blob: e6a069dd8d956c90ed0072283e79556e635226a9 [file] [log] [blame]
Enrico Galli3d449d22020-12-08 21:07:24 +00001// Copyright 2020 The Tint Authors.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#include "src/transform/first_index_offset.h"
16
Ben Claytoneb496d02021-02-24 15:55:24 +000017#include <memory>
Ben Clayton1d618b12021-04-09 16:19:48 +000018#include <unordered_map>
Enrico Galli3d449d22020-12-08 21:07:24 +000019#include <utility>
20
Ben Claytona6b9a8e2021-01-26 16:57:10 +000021#include "src/program_builder.h"
Antonio Maiorano5cd71b82021-04-16 19:07:51 +000022#include "src/sem/function.h"
23#include "src/sem/member_accessor_expression.h"
24#include "src/sem/struct.h"
25#include "src/sem/variable.h"
Enrico Galli3d449d22020-12-08 21:07:24 +000026
Ben Claytonb5cd10c2021-06-25 10:26:26 +000027TINT_INSTANTIATE_TYPEINFO(tint::transform::FirstIndexOffset);
Ben Clayton1d618b12021-04-09 16:19:48 +000028TINT_INSTANTIATE_TYPEINFO(tint::transform::FirstIndexOffset::BindingPoint);
Ben Clayton7732ca52021-03-02 20:51:18 +000029TINT_INSTANTIATE_TYPEINFO(tint::transform::FirstIndexOffset::Data);
Ben Claytoneb496d02021-02-24 15:55:24 +000030
Enrico Galli3d449d22020-12-08 21:07:24 +000031namespace tint {
32namespace transform {
33namespace {
34
Ben Clayton1d618b12021-04-09 16:19:48 +000035// Uniform buffer member names
36constexpr char kFirstVertexName[] = "first_vertex_index";
37constexpr char kFirstInstanceName[] = "first_instance_index";
Ben Clayton3a7bba82020-12-10 17:47:41 +000038
Enrico Galli3d449d22020-12-08 21:07:24 +000039} // namespace
40
Ben Clayton1d618b12021-04-09 16:19:48 +000041FirstIndexOffset::BindingPoint::BindingPoint() = default;
42FirstIndexOffset::BindingPoint::BindingPoint(uint32_t b, uint32_t g)
43 : binding(b), group(g) {}
44FirstIndexOffset::BindingPoint::~BindingPoint() = default;
45
Ben Claytoneb496d02021-02-24 15:55:24 +000046FirstIndexOffset::Data::Data(bool has_vtx_index,
47 bool has_inst_index,
48 uint32_t first_vtx_offset,
Ben Claytonc1f7e902021-02-25 14:11:50 +000049 uint32_t first_inst_offset)
Ben Claytoneb496d02021-02-24 15:55:24 +000050 : has_vertex_index(has_vtx_index),
51 has_instance_index(has_inst_index),
52 first_vertex_offset(first_vtx_offset),
Ben Claytonc1f7e902021-02-25 14:11:50 +000053 first_instance_offset(first_inst_offset) {}
Ben Claytoneb496d02021-02-24 15:55:24 +000054FirstIndexOffset::Data::Data(const Data&) = default;
Ben Claytoneb496d02021-02-24 15:55:24 +000055FirstIndexOffset::Data::~Data() = default;
56
Ben Clayton1d618b12021-04-09 16:19:48 +000057FirstIndexOffset::FirstIndexOffset() = default;
Enrico Galli3d449d22020-12-08 21:07:24 +000058FirstIndexOffset::~FirstIndexOffset() = default;
59
Ben Clayton800b8e32022-01-25 21:36:04 +000060bool FirstIndexOffset::ShouldRun(const Program* program, const DataMap&) const {
61 for (auto* fn : program->AST().Functions()) {
62 if (fn->PipelineStage() == ast::PipelineStage::kVertex) {
63 return true;
64 }
65 }
66 return false;
67}
68
Ben Claytonb5cd10c2021-06-25 10:26:26 +000069void FirstIndexOffset::Run(CloneContext& ctx,
70 const DataMap& inputs,
Ben Clayton12d54d72022-01-25 20:53:25 +000071 DataMap& outputs) const {
Ben Clayton1d618b12021-04-09 16:19:48 +000072 // Get the uniform buffer binding point
73 uint32_t ub_binding = binding_;
74 uint32_t ub_group = group_;
Ben Claytonb5cd10c2021-06-25 10:26:26 +000075 if (auto* binding_point = inputs.Get<BindingPoint>()) {
Ben Clayton1d618b12021-04-09 16:19:48 +000076 ub_binding = binding_point->binding;
77 ub_group = binding_point->group;
Ben Clayton3a7bba82020-12-10 17:47:41 +000078 }
Enrico Galli3d449d22020-12-08 21:07:24 +000079
Ben Clayton1d618b12021-04-09 16:19:48 +000080 // Map of builtin usages
Antonio Maiorano5cd71b82021-04-16 19:07:51 +000081 std::unordered_map<const sem::Variable*, const char*> builtin_vars;
82 std::unordered_map<const sem::StructMember*, const char*> builtin_members;
Ben Clayton1d618b12021-04-09 16:19:48 +000083
84 bool has_vertex_index = false;
85 bool has_instance_index = false;
86
87 // Traverse the AST scanning for builtin accesses via variables (includes
88 // parameters) or structure member accesses.
Ben Claytonb5cd10c2021-06-25 10:26:26 +000089 for (auto* node : ctx.src->ASTNodes().Objects()) {
Ben Clayton1d618b12021-04-09 16:19:48 +000090 if (auto* var = node->As<ast::Variable>()) {
Ben Claytona996ffb2022-02-02 23:07:11 +000091 for (auto* attr : var->attributes) {
92 if (auto* builtin_attr = attr->As<ast::BuiltinAttribute>()) {
93 ast::Builtin builtin = builtin_attr->builtin;
Ben Clayton1d618b12021-04-09 16:19:48 +000094 if (builtin == ast::Builtin::kVertexIndex) {
95 auto* sem_var = ctx.src->Sem().Get(var);
96 builtin_vars.emplace(sem_var, kFirstVertexName);
97 has_vertex_index = true;
98 }
99 if (builtin == ast::Builtin::kInstanceIndex) {
100 auto* sem_var = ctx.src->Sem().Get(var);
101 builtin_vars.emplace(sem_var, kFirstInstanceName);
102 has_instance_index = true;
Ben Clayton1e29f4b2021-01-21 16:20:40 +0000103 }
104 }
Ben Clayton1d618b12021-04-09 16:19:48 +0000105 }
106 }
107 if (auto* member = node->As<ast::StructMember>()) {
Ben Claytona996ffb2022-02-02 23:07:11 +0000108 for (auto* attr : member->attributes) {
109 if (auto* builtin_attr = attr->As<ast::BuiltinAttribute>()) {
110 ast::Builtin builtin = builtin_attr->builtin;
Ben Clayton1d618b12021-04-09 16:19:48 +0000111 if (builtin == ast::Builtin::kVertexIndex) {
112 auto* sem_mem = ctx.src->Sem().Get(member);
113 builtin_members.emplace(sem_mem, kFirstVertexName);
114 has_vertex_index = true;
115 }
116 if (builtin == ast::Builtin::kInstanceIndex) {
117 auto* sem_mem = ctx.src->Sem().Get(member);
118 builtin_members.emplace(sem_mem, kFirstInstanceName);
119 has_instance_index = true;
120 }
121 }
122 }
123 }
124 }
125
126 // Byte offsets on the uniform buffer
127 uint32_t vertex_index_offset = 0;
128 uint32_t instance_index_offset = 0;
129
130 if (has_vertex_index || has_instance_index) {
131 // Add uniform buffer members and calculate byte offsets
132 uint32_t offset = 0;
133 ast::StructMemberList members;
134 if (has_vertex_index) {
135 members.push_back(ctx.dst->Member(kFirstVertexName, ctx.dst->ty.u32()));
136 vertex_index_offset = offset;
137 offset += 4;
138 }
139 if (has_instance_index) {
140 members.push_back(ctx.dst->Member(kFirstInstanceName, ctx.dst->ty.u32()));
141 instance_index_offset = offset;
142 offset += 4;
143 }
James Priceebdfa5d2021-12-09 15:45:03 +0000144 auto* struct_ = ctx.dst->Structure(ctx.dst->Sym(), std::move(members));
Ben Clayton1d618b12021-04-09 16:19:48 +0000145
146 // Create a global to hold the uniform buffer
James Price65ae64d2021-04-29 12:59:14 +0000147 Symbol buffer_name = ctx.dst->Sym();
Ben Clayton8758f102021-06-09 14:32:14 +0000148 ctx.dst->Global(buffer_name, ctx.dst->ty.Of(struct_),
149 ast::StorageClass::kUniform, nullptr,
Ben Claytona996ffb2022-02-02 23:07:11 +0000150 ast::AttributeList{
151 ctx.dst->create<ast::BindingAttribute>(ub_binding),
152 ctx.dst->create<ast::GroupAttribute>(ub_group),
Ben Clayton1d618b12021-04-09 16:19:48 +0000153 });
154
155 // Fix up all references to the builtins with the offsets
Ben Clayton86481202021-10-19 18:38:54 +0000156 ctx.ReplaceAll(
157 [=, &ctx](const ast::Expression* expr) -> const ast::Expression* {
158 if (auto* sem = ctx.src->Sem().Get(expr)) {
159 if (auto* user = sem->As<sem::VariableUser>()) {
160 auto it = builtin_vars.find(user->Variable());
161 if (it != builtin_vars.end()) {
162 return ctx.dst->Add(
163 ctx.CloneWithoutTransform(expr),
164 ctx.dst->MemberAccessor(buffer_name, it->second));
165 }
166 }
167 if (auto* access = sem->As<sem::StructMemberAccess>()) {
168 auto it = builtin_members.find(access->Member());
169 if (it != builtin_members.end()) {
170 return ctx.dst->Add(
171 ctx.CloneWithoutTransform(expr),
172 ctx.dst->MemberAccessor(buffer_name, it->second));
173 }
174 }
Ben Clayton94811562021-04-30 10:16:45 +0000175 }
Ben Clayton86481202021-10-19 18:38:54 +0000176 // Not interested in this experssion. Just clone.
177 return nullptr;
178 });
Ben Clayton1d618b12021-04-09 16:19:48 +0000179 }
180
Ben Claytona8b20be2021-02-26 19:33:56 +0000181 ctx.Clone();
Enrico Galli3d449d22020-12-08 21:07:24 +0000182
Ben Claytonb5cd10c2021-06-25 10:26:26 +0000183 outputs.Add<Data>(has_vertex_index, has_instance_index, vertex_index_offset,
184 instance_index_offset);
Enrico Galli3d449d22020-12-08 21:07:24 +0000185}
186
187} // namespace transform
188} // namespace tint