blob: adafe3acb8bdf2ac1d5010a6a1b67c8c288ceb53 [file] [log] [blame]
Ryan Harrisondbc13af2022-02-21 15:19:07 +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/tint/inspector/inspector.h"
16
17#include <limits>
18#include <utility>
19
20#include "src/tint/ast/bool_literal_expression.h"
21#include "src/tint/ast/call_expression.h"
22#include "src/tint/ast/float_literal_expression.h"
23#include "src/tint/ast/id_attribute.h"
Ben Claytonce31d182023-02-09 10:34:14 +000024#include "src/tint/ast/identifier.h"
Ben Clayton72876c12022-06-29 10:58:41 +000025#include "src/tint/ast/int_literal_expression.h"
Ryan Harrisondbc13af2022-02-21 15:19:07 +000026#include "src/tint/ast/interpolate_attribute.h"
27#include "src/tint/ast/location_attribute.h"
28#include "src/tint/ast/module.h"
Ben Clayton72876c12022-06-29 10:58:41 +000029#include "src/tint/ast/override.h"
30#include "src/tint/ast/var.h"
Ben Clayton4d3ff972023-02-21 17:33:54 +000031#include "src/tint/builtin/builtin_value.h"
dan sinclaire4039c72023-02-17 21:58:59 +000032#include "src/tint/builtin/extension.h"
Ben Claytonf0b4dbb2023-02-21 21:05:28 +000033#include "src/tint/builtin/interpolation_sampling.h"
34#include "src/tint/builtin/interpolation_type.h"
Ben Clayton4d3ff972023-02-21 17:33:54 +000035#include "src/tint/sem/builtin_enum_expression.h"
Ryan Harrisondbc13af2022-02-21 15:19:07 +000036#include "src/tint/sem/call.h"
Ryan Harrisondbc13af2022-02-21 15:19:07 +000037#include "src/tint/sem/function.h"
Ben Clayton7f2b8cd2022-05-18 22:41:48 +000038#include "src/tint/sem/module.h"
Ryan Harrisondbc13af2022-02-21 15:19:07 +000039#include "src/tint/sem/statement.h"
Ryan Harrisondbc13af2022-02-21 15:19:07 +000040#include "src/tint/sem/struct.h"
Ryan Harrisondbc13af2022-02-21 15:19:07 +000041#include "src/tint/sem/variable.h"
Ben Clayton23946b32023-03-09 16:50:19 +000042#include "src/tint/switch.h"
dan sinclair946858a2022-12-08 22:21:24 +000043#include "src/tint/type/array.h"
dan sinclaird37ecf92022-12-08 16:39:59 +000044#include "src/tint/type/bool.h"
dan sinclair4595fb72022-12-08 14:14:10 +000045#include "src/tint/type/depth_multisampled_texture.h"
46#include "src/tint/type/depth_texture.h"
47#include "src/tint/type/external_texture.h"
dan sinclaird37ecf92022-12-08 16:39:59 +000048#include "src/tint/type/f16.h"
49#include "src/tint/type/f32.h"
50#include "src/tint/type/i32.h"
dan sinclair0e780da2022-12-08 22:21:24 +000051#include "src/tint/type/matrix.h"
dan sinclair4595fb72022-12-08 14:14:10 +000052#include "src/tint/type/multisampled_texture.h"
53#include "src/tint/type/sampled_texture.h"
54#include "src/tint/type/storage_texture.h"
dan sinclaird37ecf92022-12-08 16:39:59 +000055#include "src/tint/type/u32.h"
dan sinclair0e780da2022-12-08 22:21:24 +000056#include "src/tint/type/vector.h"
dan sinclaird37ecf92022-12-08 16:39:59 +000057#include "src/tint/type/void.h"
Ryan Harrisondbc13af2022-02-21 15:19:07 +000058#include "src/tint/utils/math.h"
Ben Clayton48085842022-07-26 22:51:36 +000059#include "src/tint/utils/string.h"
Ryan Harrisondbc13af2022-02-21 15:19:07 +000060#include "src/tint/utils/unique_vector.h"
61
dan sinclairaba5a212022-04-07 17:59:54 +000062namespace tint::inspector {
Ryan Harrisondbc13af2022-02-21 15:19:07 +000063
64namespace {
65
66void AppendResourceBindings(std::vector<ResourceBinding>* dest,
67 const std::vector<ResourceBinding>& orig) {
dan sinclair41e4d9a2022-05-01 14:40:55 +000068 TINT_ASSERT(Inspector, dest);
69 if (!dest) {
70 return;
71 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +000072
dan sinclair41e4d9a2022-05-01 14:40:55 +000073 dest->reserve(dest->size() + orig.size());
74 dest->insert(dest->end(), orig.begin(), orig.end());
Ryan Harrisondbc13af2022-02-21 15:19:07 +000075}
76
dan sinclair5f764d82022-12-08 00:32:27 +000077std::tuple<ComponentType, CompositionType> CalculateComponentAndComposition(
78 const type::Type* type) {
Zhaoming Jiang6198bea2022-12-07 04:33:24 +000079 // entry point in/out variables must of numeric scalar or vector types.
80 TINT_ASSERT(Inspector, type->is_numeric_scalar_or_vector());
81
82 ComponentType componentType = Switch(
dan sinclair5f764d82022-12-08 00:32:27 +000083 type::Type::DeepestElementOf(type), //
dan sinclaird37ecf92022-12-08 16:39:59 +000084 [&](const type::F32*) { return ComponentType::kF32; },
85 [&](const type::F16*) { return ComponentType::kF16; },
86 [&](const type::I32*) { return ComponentType::kI32; },
87 [&](const type::U32*) { return ComponentType::kU32; },
Zhaoming Jiang6198bea2022-12-07 04:33:24 +000088 [&](Default) {
89 tint::diag::List diagnostics;
90 TINT_UNREACHABLE(Inspector, diagnostics) << "unhandled component type";
91 return ComponentType::kUnknown;
92 });
93
94 CompositionType compositionType;
dan sinclair0e780da2022-12-08 22:21:24 +000095 if (auto* vec = type->As<type::Vector>()) {
Zhaoming Jiang6198bea2022-12-07 04:33:24 +000096 switch (vec->Width()) {
97 case 2: {
98 compositionType = CompositionType::kVec2;
99 break;
100 }
101 case 3: {
102 compositionType = CompositionType::kVec3;
103 break;
104 }
105 case 4: {
106 compositionType = CompositionType::kVec4;
107 break;
108 }
109 default: {
110 tint::diag::List diagnostics;
111 TINT_UNREACHABLE(Inspector, diagnostics) << "unhandled composition type";
112 compositionType = CompositionType::kUnknown;
113 break;
114 }
dan sinclair41e4d9a2022-05-01 14:40:55 +0000115 }
Zhaoming Jiang6198bea2022-12-07 04:33:24 +0000116 } else {
117 compositionType = CompositionType::kScalar;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000118 }
Zhaoming Jiang6198bea2022-12-07 04:33:24 +0000119
120 return {componentType, compositionType};
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000121}
122
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000123} // namespace
124
125Inspector::Inspector(const Program* program) : program_(program) {}
126
127Inspector::~Inspector() = default;
128
shrekshao145337f2022-09-07 20:09:54 +0000129EntryPoint Inspector::GetEntryPoint(const tint::ast::Function* func) {
130 EntryPoint entry_point;
131 TINT_ASSERT(Inspector, func != nullptr);
132 TINT_ASSERT(Inspector, func->IsEntryPoint());
133
134 auto* sem = program_->Sem().Get(func);
135
dan sinclaird026e132023-04-18 19:38:25 +0000136 entry_point.name = func->name->symbol.Name();
137 entry_point.remapped_name = func->name->symbol.Name();
shrekshao145337f2022-09-07 20:09:54 +0000138
139 switch (func->PipelineStage()) {
140 case ast::PipelineStage::kCompute: {
141 entry_point.stage = PipelineStage::kCompute;
142
143 auto wgsize = sem->WorkgroupSize();
Ben Clayton490d9882022-09-21 21:05:45 +0000144 if (wgsize[0].has_value() && wgsize[1].has_value() && wgsize[2].has_value()) {
145 entry_point.workgroup_size = {wgsize[0].value(), wgsize[1].value(),
146 wgsize[2].value()};
shrekshao145337f2022-09-07 20:09:54 +0000147 }
148 break;
149 }
150 case ast::PipelineStage::kFragment: {
151 entry_point.stage = PipelineStage::kFragment;
152 break;
153 }
154 case ast::PipelineStage::kVertex: {
155 entry_point.stage = PipelineStage::kVertex;
156 break;
157 }
158 default: {
159 TINT_UNREACHABLE(Inspector, diagnostics_)
160 << "invalid pipeline stage for entry point '" << entry_point.name << "'";
161 break;
162 }
163 }
164
165 for (auto* param : sem->Parameters()) {
dan sinclaird026e132023-04-18 19:38:25 +0000166 AddEntryPointInOutVariables(param->Declaration()->name->symbol.Name(), param->Type(),
167 param->Declaration()->attributes, param->Location(),
168 entry_point.input_variables);
shrekshao145337f2022-09-07 20:09:54 +0000169
170 entry_point.input_position_used |= ContainsBuiltin(
dan sinclair63925792023-02-17 21:56:35 +0000171 builtin::BuiltinValue::kPosition, param->Type(), param->Declaration()->attributes);
shrekshao145337f2022-09-07 20:09:54 +0000172 entry_point.front_facing_used |= ContainsBuiltin(
dan sinclair63925792023-02-17 21:56:35 +0000173 builtin::BuiltinValue::kFrontFacing, param->Type(), param->Declaration()->attributes);
shrekshao145337f2022-09-07 20:09:54 +0000174 entry_point.sample_index_used |= ContainsBuiltin(
dan sinclair63925792023-02-17 21:56:35 +0000175 builtin::BuiltinValue::kSampleIndex, param->Type(), param->Declaration()->attributes);
shrekshao145337f2022-09-07 20:09:54 +0000176 entry_point.input_sample_mask_used |= ContainsBuiltin(
dan sinclair63925792023-02-17 21:56:35 +0000177 builtin::BuiltinValue::kSampleMask, param->Type(), param->Declaration()->attributes);
shrekshao145337f2022-09-07 20:09:54 +0000178 entry_point.num_workgroups_used |= ContainsBuiltin(
dan sinclair63925792023-02-17 21:56:35 +0000179 builtin::BuiltinValue::kNumWorkgroups, param->Type(), param->Declaration()->attributes);
shrekshao145337f2022-09-07 20:09:54 +0000180 }
181
dan sinclaird37ecf92022-12-08 16:39:59 +0000182 if (!sem->ReturnType()->Is<type::Void>()) {
shrekshao145337f2022-09-07 20:09:54 +0000183 AddEntryPointInOutVariables("<retval>", sem->ReturnType(), func->return_type_attributes,
dan sinclairf9eeed62022-09-07 22:25:24 +0000184 sem->ReturnLocation(), entry_point.output_variables);
shrekshao145337f2022-09-07 20:09:54 +0000185
186 entry_point.output_sample_mask_used = ContainsBuiltin(
dan sinclair63925792023-02-17 21:56:35 +0000187 builtin::BuiltinValue::kSampleMask, sem->ReturnType(), func->return_type_attributes);
Corentin Wallez8d3d4f62022-10-11 09:52:59 +0000188 entry_point.frag_depth_used = ContainsBuiltin(
dan sinclair63925792023-02-17 21:56:35 +0000189 builtin::BuiltinValue::kFragDepth, sem->ReturnType(), func->return_type_attributes);
shrekshao145337f2022-09-07 20:09:54 +0000190 }
191
192 for (auto* var : sem->TransitivelyReferencedGlobals()) {
193 auto* decl = var->Declaration();
194
dan sinclaird026e132023-04-18 19:38:25 +0000195 auto name = decl->name->symbol.Name();
shrekshao145337f2022-09-07 20:09:54 +0000196
197 auto* global = var->As<sem::GlobalVariable>();
198 if (global && global->Declaration()->Is<ast::Override>()) {
199 Override override;
200 override.name = name;
201 override.id = global->OverrideId();
202 auto* type = var->Type();
203 TINT_ASSERT(Inspector, type->is_scalar());
204 if (type->is_bool_scalar_or_vector()) {
205 override.type = Override::Type::kBool;
206 } else if (type->is_float_scalar()) {
Zhaoming Jiang6af073c2023-03-20 10:32:45 +0000207 if (type->Is<type::F16>()) {
208 override.type = Override::Type::kFloat16;
209 } else {
210 override.type = Override::Type::kFloat32;
211 }
shrekshao145337f2022-09-07 20:09:54 +0000212 } else if (type->is_signed_integer_scalar()) {
213 override.type = Override::Type::kInt32;
214 } else if (type->is_unsigned_integer_scalar()) {
215 override.type = Override::Type::kUint32;
216 } else {
217 TINT_UNREACHABLE(Inspector, diagnostics_);
218 }
219
dan sinclair6e77b472022-10-20 13:38:28 +0000220 override.is_initialized = global->Declaration()->initializer;
shrekshao145337f2022-09-07 20:09:54 +0000221 override.is_id_specified =
222 ast::HasAttribute<ast::IdAttribute>(global->Declaration()->attributes);
223
224 entry_point.overrides.push_back(override);
225 }
226 }
227
228 return entry_point;
229}
230
231EntryPoint Inspector::GetEntryPoint(const std::string& entry_point_name) {
232 auto* func = FindEntryPointByName(entry_point_name);
233 if (!func) {
234 return EntryPoint();
235 }
236 return GetEntryPoint(func);
237}
238
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000239std::vector<EntryPoint> Inspector::GetEntryPoints() {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000240 std::vector<EntryPoint> result;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000241
dan sinclair41e4d9a2022-05-01 14:40:55 +0000242 for (auto* func : program_->AST().Functions()) {
243 if (!func->IsEntryPoint()) {
244 continue;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000245 }
246
shrekshao145337f2022-09-07 20:09:54 +0000247 result.push_back(GetEntryPoint(func));
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000248 }
249
dan sinclair41e4d9a2022-05-01 14:40:55 +0000250 return result;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000251}
252
Ben Clayton9a6acc42022-07-27 20:50:40 +0000253std::map<OverrideId, Scalar> Inspector::GetOverrideDefaultValues() {
254 std::map<OverrideId, Scalar> result;
dan sinclair41e4d9a2022-05-01 14:40:55 +0000255 for (auto* var : program_->AST().GlobalVariables()) {
256 auto* global = program_->Sem().Get<sem::GlobalVariable>(var);
Ben Claytondcdf66e2022-06-17 12:48:51 +0000257 if (!global || !global->Declaration()->Is<ast::Override>()) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000258 continue;
259 }
260
Ben Clayton9a6acc42022-07-27 20:50:40 +0000261 // If there are conflicting defintions for an override id, that is invalid
dan sinclair41e4d9a2022-05-01 14:40:55 +0000262 // WGSL, so the resolver should catch it. Thus here the inspector just
Ben Clayton9a6acc42022-07-27 20:50:40 +0000263 // assumes all definitions of the override id are the same, so only needs
264 // to find the first reference to override id.
265 OverrideId override_id = global->OverrideId();
266 if (result.find(override_id) != result.end()) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000267 continue;
268 }
269
dan sinclair6e77b472022-10-20 13:38:28 +0000270 if (global->Initializer()) {
271 if (auto* value = global->Initializer()->ConstantValue()) {
Ben Claytonaecf1a22022-10-14 12:09:59 +0000272 result[override_id] = Switch(
273 value->Type(), //
dan sinclair5addefb2022-12-14 20:46:32 +0000274 [&](const type::I32*) { return Scalar(value->ValueAs<i32>()); },
275 [&](const type::U32*) { return Scalar(value->ValueAs<u32>()); },
276 [&](const type::F32*) { return Scalar(value->ValueAs<f32>()); },
Zhaoming Jiang6af073c2023-03-20 10:32:45 +0000277 [&](const type::F16*) {
278 // Default value of f16 override is also stored as float scalar.
279 return Scalar(static_cast<float>(value->ValueAs<f16>()));
280 },
dan sinclair5addefb2022-12-14 20:46:32 +0000281 [&](const type::Bool*) { return Scalar(value->ValueAs<bool>()); });
Ben Claytonaecf1a22022-10-14 12:09:59 +0000282 continue;
Ben Clayton8822e292022-05-04 22:18:49 +0000283 }
dan sinclair41e4d9a2022-05-01 14:40:55 +0000284 }
285
Ben Claytonaecf1a22022-10-14 12:09:59 +0000286 // No const-expression initializer for the override
Ben Clayton9a6acc42022-07-27 20:50:40 +0000287 result[override_id] = Scalar();
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000288 }
289
dan sinclair41e4d9a2022-05-01 14:40:55 +0000290 return result;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000291}
292
Ben Clayton9a6acc42022-07-27 20:50:40 +0000293std::map<std::string, OverrideId> Inspector::GetNamedOverrideIds() {
294 std::map<std::string, OverrideId> result;
dan sinclair41e4d9a2022-05-01 14:40:55 +0000295 for (auto* var : program_->AST().GlobalVariables()) {
296 auto* global = program_->Sem().Get<sem::GlobalVariable>(var);
Ben Claytondcdf66e2022-06-17 12:48:51 +0000297 if (global && global->Declaration()->Is<ast::Override>()) {
dan sinclaird026e132023-04-18 19:38:25 +0000298 auto name = var->name->symbol.Name();
Ben Clayton9a6acc42022-07-27 20:50:40 +0000299 result[name] = global->OverrideId();
dan sinclair41e4d9a2022-05-01 14:40:55 +0000300 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000301 }
dan sinclair41e4d9a2022-05-01 14:40:55 +0000302 return result;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000303}
304
305uint32_t Inspector::GetStorageSize(const std::string& entry_point) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000306 auto* func = FindEntryPointByName(entry_point);
307 if (!func) {
308 return 0;
309 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000310
dan sinclair41e4d9a2022-05-01 14:40:55 +0000311 size_t size = 0;
312 auto* func_sem = program_->Sem().Get(func);
313 for (auto& ruv : func_sem->TransitivelyReferencedUniformVariables()) {
314 size += ruv.first->Type()->UnwrapRef()->Size();
315 }
316 for (auto& rsv : func_sem->TransitivelyReferencedStorageBufferVariables()) {
317 size += rsv.first->Type()->UnwrapRef()->Size();
318 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000319
dan sinclair41e4d9a2022-05-01 14:40:55 +0000320 if (static_cast<uint64_t>(size) > static_cast<uint64_t>(std::numeric_limits<uint32_t>::max())) {
321 return std::numeric_limits<uint32_t>::max();
322 }
323 return static_cast<uint32_t>(size);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000324}
325
dan sinclair41e4d9a2022-05-01 14:40:55 +0000326std::vector<ResourceBinding> Inspector::GetResourceBindings(const std::string& entry_point) {
327 auto* func = FindEntryPointByName(entry_point);
328 if (!func) {
329 return {};
330 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000331
dan sinclair41e4d9a2022-05-01 14:40:55 +0000332 std::vector<ResourceBinding> result;
333 for (auto fn : {
334 &Inspector::GetUniformBufferResourceBindings,
335 &Inspector::GetStorageBufferResourceBindings,
336 &Inspector::GetReadOnlyStorageBufferResourceBindings,
337 &Inspector::GetSamplerResourceBindings,
338 &Inspector::GetComparisonSamplerResourceBindings,
339 &Inspector::GetSampledTextureResourceBindings,
340 &Inspector::GetMultisampledTextureResourceBindings,
341 &Inspector::GetWriteOnlyStorageTextureResourceBindings,
342 &Inspector::GetDepthTextureResourceBindings,
343 &Inspector::GetDepthMultisampledTextureResourceBindings,
344 &Inspector::GetExternalTextureResourceBindings,
345 }) {
346 AppendResourceBindings(&result, (this->*fn)(entry_point));
347 }
348 return result;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000349}
350
351std::vector<ResourceBinding> Inspector::GetUniformBufferResourceBindings(
352 const std::string& entry_point) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000353 auto* func = FindEntryPointByName(entry_point);
354 if (!func) {
355 return {};
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000356 }
357
dan sinclair41e4d9a2022-05-01 14:40:55 +0000358 std::vector<ResourceBinding> result;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000359
dan sinclair41e4d9a2022-05-01 14:40:55 +0000360 auto* func_sem = program_->Sem().Get(func);
361 for (auto& ruv : func_sem->TransitivelyReferencedUniformVariables()) {
362 auto* var = ruv.first;
363 auto binding_info = ruv.second;
364
365 auto* unwrapped_type = var->Type()->UnwrapRef();
366
367 ResourceBinding entry;
368 entry.resource_type = ResourceBinding::ResourceType::kUniformBuffer;
dan sinclairacdf6e12022-08-24 15:47:25 +0000369 entry.bind_group = binding_info.group;
370 entry.binding = binding_info.binding;
dan sinclair41e4d9a2022-05-01 14:40:55 +0000371 entry.size = unwrapped_type->Size();
372 entry.size_no_padding = entry.size;
373 if (auto* str = unwrapped_type->As<sem::Struct>()) {
374 entry.size_no_padding = str->SizeNoPadding();
375 } else {
376 entry.size_no_padding = entry.size;
377 }
378
379 result.push_back(entry);
380 }
381
382 return result;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000383}
384
385std::vector<ResourceBinding> Inspector::GetStorageBufferResourceBindings(
386 const std::string& entry_point) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000387 return GetStorageBufferResourceBindingsImpl(entry_point, false);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000388}
389
dan sinclair41e4d9a2022-05-01 14:40:55 +0000390std::vector<ResourceBinding> Inspector::GetReadOnlyStorageBufferResourceBindings(
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000391 const std::string& entry_point) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000392 return GetStorageBufferResourceBindingsImpl(entry_point, true);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000393}
394
dan sinclair41e4d9a2022-05-01 14:40:55 +0000395std::vector<ResourceBinding> Inspector::GetSamplerResourceBindings(const std::string& entry_point) {
396 auto* func = FindEntryPointByName(entry_point);
397 if (!func) {
398 return {};
399 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000400
dan sinclair41e4d9a2022-05-01 14:40:55 +0000401 std::vector<ResourceBinding> result;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000402
dan sinclair41e4d9a2022-05-01 14:40:55 +0000403 auto* func_sem = program_->Sem().Get(func);
404 for (auto& rs : func_sem->TransitivelyReferencedSamplerVariables()) {
405 auto binding_info = rs.second;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000406
dan sinclair41e4d9a2022-05-01 14:40:55 +0000407 ResourceBinding entry;
408 entry.resource_type = ResourceBinding::ResourceType::kSampler;
dan sinclairacdf6e12022-08-24 15:47:25 +0000409 entry.bind_group = binding_info.group;
410 entry.binding = binding_info.binding;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000411
dan sinclair41e4d9a2022-05-01 14:40:55 +0000412 result.push_back(entry);
413 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000414
dan sinclair41e4d9a2022-05-01 14:40:55 +0000415 return result;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000416}
417
418std::vector<ResourceBinding> Inspector::GetComparisonSamplerResourceBindings(
419 const std::string& entry_point) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000420 auto* func = FindEntryPointByName(entry_point);
421 if (!func) {
422 return {};
423 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000424
dan sinclair41e4d9a2022-05-01 14:40:55 +0000425 std::vector<ResourceBinding> result;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000426
dan sinclair41e4d9a2022-05-01 14:40:55 +0000427 auto* func_sem = program_->Sem().Get(func);
428 for (auto& rcs : func_sem->TransitivelyReferencedComparisonSamplerVariables()) {
429 auto binding_info = rcs.second;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000430
dan sinclair41e4d9a2022-05-01 14:40:55 +0000431 ResourceBinding entry;
432 entry.resource_type = ResourceBinding::ResourceType::kComparisonSampler;
dan sinclairacdf6e12022-08-24 15:47:25 +0000433 entry.bind_group = binding_info.group;
434 entry.binding = binding_info.binding;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000435
dan sinclair41e4d9a2022-05-01 14:40:55 +0000436 result.push_back(entry);
437 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000438
dan sinclair41e4d9a2022-05-01 14:40:55 +0000439 return result;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000440}
441
442std::vector<ResourceBinding> Inspector::GetSampledTextureResourceBindings(
443 const std::string& entry_point) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000444 return GetSampledTextureResourceBindingsImpl(entry_point, false);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000445}
446
447std::vector<ResourceBinding> Inspector::GetMultisampledTextureResourceBindings(
448 const std::string& entry_point) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000449 return GetSampledTextureResourceBindingsImpl(entry_point, true);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000450}
451
dan sinclair41e4d9a2022-05-01 14:40:55 +0000452std::vector<ResourceBinding> Inspector::GetWriteOnlyStorageTextureResourceBindings(
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000453 const std::string& entry_point) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000454 return GetStorageTextureResourceBindingsImpl(entry_point);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000455}
456
457std::vector<ResourceBinding> Inspector::GetTextureResourceBindings(
458 const std::string& entry_point,
dan sinclair12fa3032023-04-19 23:52:33 +0000459 const tint::utils::TypeInfo* texture_type,
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000460 ResourceBinding::ResourceType resource_type) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000461 auto* func = FindEntryPointByName(entry_point);
462 if (!func) {
463 return {};
464 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000465
dan sinclair41e4d9a2022-05-01 14:40:55 +0000466 std::vector<ResourceBinding> result;
467 auto* func_sem = program_->Sem().Get(func);
468 for (auto& ref : func_sem->TransitivelyReferencedVariablesOfType(texture_type)) {
469 auto* var = ref.first;
470 auto binding_info = ref.second;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000471
dan sinclair41e4d9a2022-05-01 14:40:55 +0000472 ResourceBinding entry;
473 entry.resource_type = resource_type;
dan sinclairacdf6e12022-08-24 15:47:25 +0000474 entry.bind_group = binding_info.group;
475 entry.binding = binding_info.binding;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000476
dan sinclair4595fb72022-12-08 14:14:10 +0000477 auto* tex = var->Type()->UnwrapRef()->As<type::Texture>();
dan sinclair41e4d9a2022-05-01 14:40:55 +0000478 entry.dim = TypeTextureDimensionToResourceBindingTextureDimension(tex->dim());
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000479
dan sinclair41e4d9a2022-05-01 14:40:55 +0000480 result.push_back(entry);
481 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000482
dan sinclair41e4d9a2022-05-01 14:40:55 +0000483 return result;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000484}
485
486std::vector<ResourceBinding> Inspector::GetDepthTextureResourceBindings(
487 const std::string& entry_point) {
dan sinclair12fa3032023-04-19 23:52:33 +0000488 return GetTextureResourceBindings(entry_point, &utils::TypeInfo::Of<type::DepthTexture>(),
dan sinclair41e4d9a2022-05-01 14:40:55 +0000489 ResourceBinding::ResourceType::kDepthTexture);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000490}
491
dan sinclair41e4d9a2022-05-01 14:40:55 +0000492std::vector<ResourceBinding> Inspector::GetDepthMultisampledTextureResourceBindings(
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000493 const std::string& entry_point) {
dan sinclair12fa3032023-04-19 23:52:33 +0000494 return GetTextureResourceBindings(entry_point,
495 &utils::TypeInfo::Of<type::DepthMultisampledTexture>(),
dan sinclair41e4d9a2022-05-01 14:40:55 +0000496 ResourceBinding::ResourceType::kDepthMultisampledTexture);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000497}
498
499std::vector<ResourceBinding> Inspector::GetExternalTextureResourceBindings(
500 const std::string& entry_point) {
dan sinclair12fa3032023-04-19 23:52:33 +0000501 return GetTextureResourceBindings(entry_point, &utils::TypeInfo::Of<type::ExternalTexture>(),
dan sinclair41e4d9a2022-05-01 14:40:55 +0000502 ResourceBinding::ResourceType::kExternalTexture);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000503}
504
dan sinclair2f689a72023-02-21 21:54:48 +0000505utils::VectorRef<SamplerTexturePair> Inspector::GetSamplerTextureUses(
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000506 const std::string& entry_point) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000507 auto* func = FindEntryPointByName(entry_point);
508 if (!func) {
509 return {};
510 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000511
dan sinclair41e4d9a2022-05-01 14:40:55 +0000512 GenerateSamplerTargets();
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000513
dan sinclair41e4d9a2022-05-01 14:40:55 +0000514 auto it = sampler_targets_->find(entry_point);
515 if (it == sampler_targets_->end()) {
516 return {};
517 }
518 return it->second;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000519}
520
dan sinclair2f689a72023-02-21 21:54:48 +0000521std::vector<SamplerTexturePair> Inspector::GetSamplerTextureUses(
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000522 const std::string& entry_point,
523 const sem::BindingPoint& placeholder) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000524 auto* func = FindEntryPointByName(entry_point);
525 if (!func) {
526 return {};
527 }
528 auto* func_sem = program_->Sem().Get(func);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000529
dan sinclair2f689a72023-02-21 21:54:48 +0000530 std::vector<SamplerTexturePair> new_pairs;
dan sinclair41e4d9a2022-05-01 14:40:55 +0000531 for (auto pair : func_sem->TextureSamplerPairs()) {
532 auto* texture = pair.first->As<sem::GlobalVariable>();
533 auto* sampler = pair.second ? pair.second->As<sem::GlobalVariable>() : nullptr;
534 SamplerTexturePair new_pair;
Ben Clayton5f4847c2023-04-19 13:24:27 +0000535 new_pair.sampler_binding_point = sampler ? *sampler->BindingPoint() : placeholder;
536 new_pair.texture_binding_point = *texture->BindingPoint();
dan sinclair41e4d9a2022-05-01 14:40:55 +0000537 new_pairs.push_back(new_pair);
538 }
539 return new_pairs;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000540}
541
542uint32_t Inspector::GetWorkgroupStorageSize(const std::string& entry_point) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000543 auto* func = FindEntryPointByName(entry_point);
544 if (!func) {
545 return 0;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000546 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000547
dan sinclair41e4d9a2022-05-01 14:40:55 +0000548 uint32_t total_size = 0;
549 auto* func_sem = program_->Sem().Get(func);
550 for (const sem::Variable* var : func_sem->TransitivelyReferencedGlobals()) {
dan sinclair2a651632023-02-19 04:03:55 +0000551 if (var->AddressSpace() == builtin::AddressSpace::kWorkgroup) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000552 auto* ty = var->Type()->UnwrapRef();
553 uint32_t align = ty->Align();
554 uint32_t size = ty->Size();
555
556 // This essentially matches std430 layout rules from GLSL, which are in
557 // turn specified as an upper bound for Vulkan layout sizing. Since D3D
558 // and Metal are even less specific, we assume Vulkan behavior as a
559 // good-enough approximation everywhere.
560 total_size += utils::RoundUp(align, size);
561 }
562 }
563
564 return total_size;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000565}
566
Zhaoming Jiang7098d3d2022-04-27 02:27:52 +0000567std::vector<std::string> Inspector::GetUsedExtensionNames() {
Ben Clayton7f2b8cd2022-05-18 22:41:48 +0000568 auto& extensions = program_->Sem().Module()->Extensions();
569 std::vector<std::string> out;
Ben Claytondce63f52022-08-17 18:07:20 +0000570 out.reserve(extensions.Length());
Ben Clayton7f2b8cd2022-05-18 22:41:48 +0000571 for (auto ext : extensions) {
Ben Clayton48085842022-07-26 22:51:36 +0000572 out.push_back(utils::ToString(ext));
dan sinclair41e4d9a2022-05-01 14:40:55 +0000573 }
Ben Clayton7f2b8cd2022-05-18 22:41:48 +0000574 return out;
Zhaoming Jiang7098d3d2022-04-27 02:27:52 +0000575}
576
577std::vector<std::pair<std::string, Source>> Inspector::GetEnableDirectives() {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000578 std::vector<std::pair<std::string, Source>> result;
Zhaoming Jiang7098d3d2022-04-27 02:27:52 +0000579
dan sinclair41e4d9a2022-05-01 14:40:55 +0000580 // Ast nodes for enable directive are stored within global declarations list
581 auto global_decls = program_->AST().GlobalDeclarations();
Ben Claytone23283f2022-05-03 16:06:23 +0000582 for (auto* node : global_decls) {
Ben Clayton8f80d992023-03-15 05:06:57 +0000583 if (auto* enable = node->As<ast::Enable>()) {
584 for (auto* ext : enable->extensions) {
585 result.push_back({utils::ToString(ext->name), ext->source});
586 }
dan sinclair41e4d9a2022-05-01 14:40:55 +0000587 }
Zhaoming Jiang7098d3d2022-04-27 02:27:52 +0000588 }
Zhaoming Jiang7098d3d2022-04-27 02:27:52 +0000589
dan sinclair41e4d9a2022-05-01 14:40:55 +0000590 return result;
Zhaoming Jiang7098d3d2022-04-27 02:27:52 +0000591}
592
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000593const ast::Function* Inspector::FindEntryPointByName(const std::string& name) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000594 auto* func = program_->AST().Functions().Find(program_->Symbols().Get(name));
595 if (!func) {
596 diagnostics_.add_error(diag::System::Inspector, name + " was not found!");
597 return nullptr;
598 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000599
dan sinclair41e4d9a2022-05-01 14:40:55 +0000600 if (!func->IsEntryPoint()) {
601 diagnostics_.add_error(diag::System::Inspector, name + " is not an entry point!");
602 return nullptr;
603 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000604
dan sinclair41e4d9a2022-05-01 14:40:55 +0000605 return func;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000606}
607
dan sinclair41e4d9a2022-05-01 14:40:55 +0000608void Inspector::AddEntryPointInOutVariables(std::string name,
dan sinclair5f764d82022-12-08 00:32:27 +0000609 const type::Type* type,
Ben Clayton783b1692022-08-02 17:03:35 +0000610 utils::VectorRef<const ast::Attribute*> attributes,
dan sinclairf9eeed62022-09-07 22:25:24 +0000611 std::optional<uint32_t> location,
dan sinclair41e4d9a2022-05-01 14:40:55 +0000612 std::vector<StageVariable>& variables) const {
613 // Skip builtins.
614 if (ast::HasAttribute<ast::BuiltinAttribute>(attributes)) {
615 return;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000616 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000617
dan sinclair41e4d9a2022-05-01 14:40:55 +0000618 auto* unwrapped_type = type->UnwrapRef();
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000619
dan sinclair41e4d9a2022-05-01 14:40:55 +0000620 if (auto* struct_ty = unwrapped_type->As<sem::Struct>()) {
621 // Recurse into members.
622 for (auto* member : struct_ty->Members()) {
dan sinclaird026e132023-04-18 19:38:25 +0000623 AddEntryPointInOutVariables(name + "." + member->Name().Name(), member->Type(),
Ben Clayton576ba1c2023-04-27 17:58:25 +0000624 member->Declaration()->attributes,
625 member->Attributes().location, variables);
dan sinclair41e4d9a2022-05-01 14:40:55 +0000626 }
627 return;
628 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000629
dan sinclair41e4d9a2022-05-01 14:40:55 +0000630 // Base case: add the variable.
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000631
dan sinclair41e4d9a2022-05-01 14:40:55 +0000632 StageVariable stage_variable;
633 stage_variable.name = name;
634 std::tie(stage_variable.component_type, stage_variable.composition_type) =
635 CalculateComponentAndComposition(type);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000636
dan sinclairf9eeed62022-09-07 22:25:24 +0000637 TINT_ASSERT(Inspector, location.has_value());
dan sinclair41e4d9a2022-05-01 14:40:55 +0000638 stage_variable.has_location_attribute = true;
dan sinclairf9eeed62022-09-07 22:25:24 +0000639 stage_variable.location_attribute = location.value();
dan sinclair41e4d9a2022-05-01 14:40:55 +0000640
641 std::tie(stage_variable.interpolation_type, stage_variable.interpolation_sampling) =
642 CalculateInterpolationData(type, attributes);
643
644 variables.push_back(stage_variable);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000645}
646
dan sinclair63925792023-02-17 21:56:35 +0000647bool Inspector::ContainsBuiltin(builtin::BuiltinValue builtin,
dan sinclair5f764d82022-12-08 00:32:27 +0000648 const type::Type* type,
Ben Clayton783b1692022-08-02 17:03:35 +0000649 utils::VectorRef<const ast::Attribute*> attributes) const {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000650 auto* unwrapped_type = type->UnwrapRef();
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000651
dan sinclair41e4d9a2022-05-01 14:40:55 +0000652 if (auto* struct_ty = unwrapped_type->As<sem::Struct>()) {
653 // Recurse into members.
654 for (auto* member : struct_ty->Members()) {
655 if (ContainsBuiltin(builtin, member->Type(), member->Declaration()->attributes)) {
656 return true;
657 }
658 }
659 return false;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000660 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000661
dan sinclair41e4d9a2022-05-01 14:40:55 +0000662 // Base case: check for builtin
663 auto* builtin_declaration = ast::GetAttribute<ast::BuiltinAttribute>(attributes);
Ben Clayton4d3ff972023-02-21 17:33:54 +0000664 if (!builtin_declaration) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000665 return false;
666 }
Ben Clayton4d3ff972023-02-21 17:33:54 +0000667 return program_->Sem().Get(builtin_declaration)->Value() == builtin;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000668}
669
670std::vector<ResourceBinding> Inspector::GetStorageBufferResourceBindingsImpl(
671 const std::string& entry_point,
672 bool read_only) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000673 auto* func = FindEntryPointByName(entry_point);
674 if (!func) {
675 return {};
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000676 }
677
dan sinclair41e4d9a2022-05-01 14:40:55 +0000678 auto* func_sem = program_->Sem().Get(func);
679 std::vector<ResourceBinding> result;
680 for (auto& rsv : func_sem->TransitivelyReferencedStorageBufferVariables()) {
681 auto* var = rsv.first;
682 auto binding_info = rsv.second;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000683
dan sinclairb6cc4cb2023-02-19 04:01:29 +0000684 if (read_only != (var->Access() == builtin::Access::kRead)) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000685 continue;
686 }
687
688 auto* unwrapped_type = var->Type()->UnwrapRef();
689
690 ResourceBinding entry;
691 entry.resource_type = read_only ? ResourceBinding::ResourceType::kReadOnlyStorageBuffer
692 : ResourceBinding::ResourceType::kStorageBuffer;
dan sinclairacdf6e12022-08-24 15:47:25 +0000693 entry.bind_group = binding_info.group;
694 entry.binding = binding_info.binding;
dan sinclair41e4d9a2022-05-01 14:40:55 +0000695 entry.size = unwrapped_type->Size();
696 if (auto* str = unwrapped_type->As<sem::Struct>()) {
697 entry.size_no_padding = str->SizeNoPadding();
698 } else {
699 entry.size_no_padding = entry.size;
700 }
701
702 result.push_back(entry);
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000703 }
704
dan sinclair41e4d9a2022-05-01 14:40:55 +0000705 return result;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000706}
707
708std::vector<ResourceBinding> Inspector::GetSampledTextureResourceBindingsImpl(
709 const std::string& entry_point,
710 bool multisampled_only) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000711 auto* func = FindEntryPointByName(entry_point);
712 if (!func) {
713 return {};
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000714 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000715
dan sinclair41e4d9a2022-05-01 14:40:55 +0000716 std::vector<ResourceBinding> result;
717 auto* func_sem = program_->Sem().Get(func);
718 auto referenced_variables = multisampled_only
719 ? func_sem->TransitivelyReferencedMultisampledTextureVariables()
720 : func_sem->TransitivelyReferencedSampledTextureVariables();
721 for (auto& ref : referenced_variables) {
722 auto* var = ref.first;
723 auto binding_info = ref.second;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000724
dan sinclair41e4d9a2022-05-01 14:40:55 +0000725 ResourceBinding entry;
726 entry.resource_type = multisampled_only
727 ? ResourceBinding::ResourceType::kMultisampledTexture
728 : ResourceBinding::ResourceType::kSampledTexture;
dan sinclairacdf6e12022-08-24 15:47:25 +0000729 entry.bind_group = binding_info.group;
730 entry.binding = binding_info.binding;
dan sinclair41e4d9a2022-05-01 14:40:55 +0000731
dan sinclair4595fb72022-12-08 14:14:10 +0000732 auto* texture_type = var->Type()->UnwrapRef()->As<type::Texture>();
dan sinclair41e4d9a2022-05-01 14:40:55 +0000733 entry.dim = TypeTextureDimensionToResourceBindingTextureDimension(texture_type->dim());
734
dan sinclair5f764d82022-12-08 00:32:27 +0000735 const type::Type* base_type = nullptr;
dan sinclair41e4d9a2022-05-01 14:40:55 +0000736 if (multisampled_only) {
dan sinclair4595fb72022-12-08 14:14:10 +0000737 base_type = texture_type->As<type::MultisampledTexture>()->type();
dan sinclair41e4d9a2022-05-01 14:40:55 +0000738 } else {
dan sinclair4595fb72022-12-08 14:14:10 +0000739 base_type = texture_type->As<type::SampledTexture>()->type();
dan sinclair41e4d9a2022-05-01 14:40:55 +0000740 }
741 entry.sampled_kind = BaseTypeToSampledKind(base_type);
742
743 result.push_back(entry);
744 }
745
746 return result;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000747}
748
749std::vector<ResourceBinding> Inspector::GetStorageTextureResourceBindingsImpl(
750 const std::string& entry_point) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000751 auto* func = FindEntryPointByName(entry_point);
752 if (!func) {
753 return {};
754 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000755
dan sinclair41e4d9a2022-05-01 14:40:55 +0000756 auto* func_sem = program_->Sem().Get(func);
757 std::vector<ResourceBinding> result;
dan sinclair4595fb72022-12-08 14:14:10 +0000758 for (auto& ref : func_sem->TransitivelyReferencedVariablesOfType<type::StorageTexture>()) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000759 auto* var = ref.first;
760 auto binding_info = ref.second;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000761
dan sinclair4595fb72022-12-08 14:14:10 +0000762 auto* texture_type = var->Type()->UnwrapRef()->As<type::StorageTexture>();
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000763
dan sinclair41e4d9a2022-05-01 14:40:55 +0000764 ResourceBinding entry;
765 entry.resource_type = ResourceBinding::ResourceType::kWriteOnlyStorageTexture;
dan sinclairacdf6e12022-08-24 15:47:25 +0000766 entry.bind_group = binding_info.group;
767 entry.binding = binding_info.binding;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000768
dan sinclair41e4d9a2022-05-01 14:40:55 +0000769 entry.dim = TypeTextureDimensionToResourceBindingTextureDimension(texture_type->dim());
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000770
dan sinclair41e4d9a2022-05-01 14:40:55 +0000771 auto* base_type = texture_type->type();
772 entry.sampled_kind = BaseTypeToSampledKind(base_type);
773 entry.image_format =
774 TypeTexelFormatToResourceBindingTexelFormat(texture_type->texel_format());
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000775
dan sinclair41e4d9a2022-05-01 14:40:55 +0000776 result.push_back(entry);
777 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000778
dan sinclair41e4d9a2022-05-01 14:40:55 +0000779 return result;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000780}
781
782void Inspector::GenerateSamplerTargets() {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000783 // Do not re-generate, since |program_| should not change during the lifetime
784 // of the inspector.
785 if (sampler_targets_ != nullptr) {
786 return;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000787 }
788
dan sinclair41e4d9a2022-05-01 14:40:55 +0000789 sampler_targets_ = std::make_unique<
dan sinclair2f689a72023-02-21 21:54:48 +0000790 std::unordered_map<std::string, utils::UniqueVector<SamplerTexturePair, 4>>>();
dan sinclair41e4d9a2022-05-01 14:40:55 +0000791
792 auto& sem = program_->Sem();
793
794 for (auto* node : program_->ASTNodes().Objects()) {
795 auto* c = node->As<ast::CallExpression>();
796 if (!c) {
797 continue;
798 }
799
Ben Claytone5a67ac2022-05-19 21:50:59 +0000800 auto* call = sem.Get(c)->UnwrapMaterialize()->As<sem::Call>();
dan sinclair41e4d9a2022-05-01 14:40:55 +0000801 if (!call) {
802 continue;
803 }
804
805 auto* i = call->Target()->As<sem::Builtin>();
806 if (!i) {
807 continue;
808 }
809
810 const auto& signature = i->Signature();
811 int sampler_index = signature.IndexOf(sem::ParameterUsage::kSampler);
812 if (sampler_index == -1) {
813 continue;
814 }
815
816 int texture_index = signature.IndexOf(sem::ParameterUsage::kTexture);
817 if (texture_index == -1) {
818 continue;
819 }
820
821 auto* call_func = call->Stmt()->Function();
822 std::vector<const sem::Function*> entry_points;
823 if (call_func->Declaration()->IsEntryPoint()) {
824 entry_points = {call_func};
825 } else {
826 entry_points = call_func->AncestorEntryPoints();
827 }
828
829 if (entry_points.empty()) {
830 continue;
831 }
832
dan sinclair3a2a2792022-06-29 14:38:15 +0000833 auto* t = c->args[static_cast<size_t>(texture_index)];
834 auto* s = c->args[static_cast<size_t>(sampler_index)];
dan sinclair41e4d9a2022-05-01 14:40:55 +0000835
Ben Clayton490d9882022-09-21 21:05:45 +0000836 GetOriginatingResources(std::array<const ast::Expression*, 2>{t, s},
837 [&](std::array<const sem::GlobalVariable*, 2> globals) {
Ben Clayton5f4847c2023-04-19 13:24:27 +0000838 auto texture_binding_point = *globals[0]->BindingPoint();
839 auto sampler_binding_point = *globals[1]->BindingPoint();
dan sinclair41e4d9a2022-05-01 14:40:55 +0000840
Ben Clayton490d9882022-09-21 21:05:45 +0000841 for (auto* entry_point : entry_points) {
dan sinclaird026e132023-04-18 19:38:25 +0000842 const auto& ep_name =
843 entry_point->Declaration()->name->symbol.Name();
Ben Clayton490d9882022-09-21 21:05:45 +0000844 (*sampler_targets_)[ep_name].Add(
845 {sampler_binding_point, texture_binding_point});
846 }
847 });
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000848 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000849}
850
Ben Claytonf0b4dbb2023-02-21 21:05:28 +0000851std::tuple<InterpolationType, InterpolationSampling> Inspector::CalculateInterpolationData(
852 const type::Type* type,
853 utils::VectorRef<const ast::Attribute*> attributes) const {
854 auto* interpolation_attribute = ast::GetAttribute<ast::InterpolateAttribute>(attributes);
855 if (type->is_integer_scalar_or_vector()) {
856 return {InterpolationType::kFlat, InterpolationSampling::kNone};
857 }
858
859 if (!interpolation_attribute) {
860 return {InterpolationType::kPerspective, InterpolationSampling::kCenter};
861 }
862
863 auto& sem = program_->Sem();
864
865 auto ast_interpolation_type = sem.Get<sem::BuiltinEnumExpression<builtin::InterpolationType>>(
866 interpolation_attribute->type)
867 ->Value();
868
869 auto ast_sampling_type = builtin::InterpolationSampling::kUndefined;
870 if (interpolation_attribute->sampling) {
871 ast_sampling_type = sem.Get<sem::BuiltinEnumExpression<builtin::InterpolationSampling>>(
872 interpolation_attribute->sampling)
873 ->Value();
874 }
875
876 if (ast_interpolation_type != builtin::InterpolationType::kFlat &&
877 ast_sampling_type == builtin::InterpolationSampling::kUndefined) {
878 ast_sampling_type = builtin::InterpolationSampling::kCenter;
879 }
880
881 auto interpolation_type = InterpolationType::kUnknown;
882 switch (ast_interpolation_type) {
883 case builtin::InterpolationType::kPerspective:
884 interpolation_type = InterpolationType::kPerspective;
885 break;
886 case builtin::InterpolationType::kLinear:
887 interpolation_type = InterpolationType::kLinear;
888 break;
889 case builtin::InterpolationType::kFlat:
890 interpolation_type = InterpolationType::kFlat;
891 break;
892 case builtin::InterpolationType::kUndefined:
893 break;
894 }
895
896 auto sampling_type = InterpolationSampling::kUnknown;
897 switch (ast_sampling_type) {
898 case builtin::InterpolationSampling::kUndefined:
899 sampling_type = InterpolationSampling::kNone;
900 break;
901 case builtin::InterpolationSampling::kCenter:
902 sampling_type = InterpolationSampling::kCenter;
903 break;
904 case builtin::InterpolationSampling::kCentroid:
905 sampling_type = InterpolationSampling::kCentroid;
906 break;
907 case builtin::InterpolationSampling::kSample:
908 sampling_type = InterpolationSampling::kSample;
909 break;
910 }
911
912 return {interpolation_type, sampling_type};
913}
914
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000915template <size_t N, typename F>
dan sinclair41e4d9a2022-05-01 14:40:55 +0000916void Inspector::GetOriginatingResources(std::array<const ast::Expression*, N> exprs, F&& callback) {
Ben Clayton884f9522023-01-12 22:52:57 +0000917 if (TINT_UNLIKELY(!program_->IsValid())) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000918 TINT_ICE(Inspector, diagnostics_)
919 << "attempting to get originating resources in invalid program";
James Pricee6d7ea72022-04-22 17:40:33 +0000920 return;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000921 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000922
dan sinclair41e4d9a2022-05-01 14:40:55 +0000923 auto& sem = program_->Sem();
924
925 std::array<const sem::GlobalVariable*, N> globals{};
926 std::array<const sem::Parameter*, N> parameters{};
Ben Claytondce63f52022-08-17 18:07:20 +0000927 utils::UniqueVector<const ast::CallExpression*, 8> callsites;
dan sinclair41e4d9a2022-05-01 14:40:55 +0000928
929 for (size_t i = 0; i < N; i++) {
Ben Clayton0b4a2f12023-02-05 22:59:40 +0000930 const sem::Variable* root_ident = sem.GetVal(exprs[i])->RootIdentifier();
James Pricea7cd3ae2022-11-09 12:16:56 +0000931 if (auto* global = root_ident->As<sem::GlobalVariable>()) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000932 globals[i] = global;
James Pricea7cd3ae2022-11-09 12:16:56 +0000933 } else if (auto* param = root_ident->As<sem::Parameter>()) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000934 auto* func = tint::As<sem::Function>(param->Owner());
935 if (func->CallSites().empty()) {
936 // One or more of the expressions is a parameter, but this function
937 // is not called. Ignore.
938 return;
939 }
940 for (auto* call : func->CallSites()) {
Ben Claytondce63f52022-08-17 18:07:20 +0000941 callsites.Add(call->Declaration());
dan sinclair41e4d9a2022-05-01 14:40:55 +0000942 }
943 parameters[i] = param;
944 } else {
945 TINT_ICE(Inspector, diagnostics_)
946 << "cannot resolve originating resource with expression type "
947 << exprs[i]->TypeInfo().name;
948 return;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000949 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000950 }
dan sinclair41e4d9a2022-05-01 14:40:55 +0000951
Ben Claytondce63f52022-08-17 18:07:20 +0000952 if (callsites.Length()) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000953 for (auto* call_expr : callsites) {
954 // Make a copy of the expressions for this callsite
955 std::array<const ast::Expression*, N> call_exprs = exprs;
956 // Patch all the parameter expressions with their argument
957 for (size_t i = 0; i < N; i++) {
958 if (auto* param = parameters[i]) {
959 call_exprs[i] = call_expr->args[param->Index()];
960 }
961 }
962 // Now call GetOriginatingResources() with from the callsite
963 GetOriginatingResources(call_exprs, callback);
964 }
965 } else {
966 // All the expressions resolved to globals
967 callback(globals);
968 }
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000969}
970
dan sinclairaba5a212022-04-07 17:59:54 +0000971} // namespace tint::inspector