1// Copyright (c) 2018 Google LLC.
2// Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights
3// reserved.
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
17// Validates correctness of built-in variables.
18
19#include <array>
20#include <functional>
21#include <list>
22#include <map>
23#include <set>
24#include <sstream>
25#include <stack>
26#include <string>
27#include <vector>
28
29#include "source/opcode.h"
30#include "source/spirv_target_env.h"
31#include "source/util/bitutils.h"
32#include "source/val/instruction.h"
33#include "source/val/validate.h"
34#include "source/val/validation_state.h"
35
36namespace spvtools {
37namespace val {
38namespace {
39
40// Returns a short textual description of the id defined by the given
41// instruction.
42std::string GetIdDesc(const Instruction& inst) {
43 std::ostringstream ss;
44 ss << "ID <" << inst.id() << "> (Op" << spvOpcodeString(opcode: inst.opcode()) << ")";
45 return ss.str();
46}
47
48// Gets underlying data type which is
49// - member type if instruction is OpTypeStruct
50// (member index is taken from decoration).
51// - data type if id creates a pointer.
52// - type of the constant if instruction is OpConst or OpSpecConst.
53//
54// Fails in any other case. The function is based on built-ins allowed by
55// the Vulkan spec.
56// TODO: If non-Vulkan validation rules are added then it might need
57// to be refactored.
58spv_result_t GetUnderlyingType(ValidationState_t& _,
59 const Decoration& decoration,
60 const Instruction& inst,
61 uint32_t* underlying_type) {
62 if (decoration.struct_member_index() != Decoration::kInvalidMember) {
63 if (inst.opcode() != spv::Op::OpTypeStruct) {
64 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &inst)
65 << GetIdDesc(inst)
66 << "Attempted to get underlying data type via member index for "
67 "non-struct type.";
68 }
69 *underlying_type = inst.word(index: decoration.struct_member_index() + 2);
70 return SPV_SUCCESS;
71 }
72
73 if (inst.opcode() == spv::Op::OpTypeStruct) {
74 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &inst)
75 << GetIdDesc(inst)
76 << " did not find an member index to get underlying data type for "
77 "struct type.";
78 }
79
80 if (spvOpcodeIsConstant(opcode: inst.opcode())) {
81 *underlying_type = inst.type_id();
82 return SPV_SUCCESS;
83 }
84
85 spv::StorageClass storage_class;
86 if (!_.GetPointerTypeInfo(id: inst.type_id(), data_type: underlying_type, storage_class: &storage_class)) {
87 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &inst)
88 << GetIdDesc(inst)
89 << " is decorated with BuiltIn. BuiltIn decoration should only be "
90 "applied to struct types, variables and constants.";
91 }
92 return SPV_SUCCESS;
93}
94
95// Returns Storage Class used by the instruction if applicable.
96// Returns spv::StorageClass::Max if not.
97spv::StorageClass GetStorageClass(const Instruction& inst) {
98 switch (inst.opcode()) {
99 case spv::Op::OpTypePointer:
100 case spv::Op::OpTypeForwardPointer: {
101 return spv::StorageClass(inst.word(index: 2));
102 }
103 case spv::Op::OpVariable: {
104 return spv::StorageClass(inst.word(index: 3));
105 }
106 case spv::Op::OpGenericCastToPtrExplicit: {
107 return spv::StorageClass(inst.word(index: 4));
108 }
109 default: { break; }
110 }
111 return spv::StorageClass::Max;
112}
113
114typedef enum VUIDError_ {
115 VUIDErrorExecutionModel = 0,
116 VUIDErrorStorageClass = 1,
117 VUIDErrorType = 2,
118 VUIDErrorMax,
119} VUIDError;
120
121const static uint32_t NumVUIDBuiltins = 36;
122
123typedef struct {
124 spv::BuiltIn builtIn;
125 uint32_t vuid[VUIDErrorMax]; // execution mode, storage class, type VUIDs
126} BuiltinVUIDMapping;
127
128std::array<BuiltinVUIDMapping, NumVUIDBuiltins> builtinVUIDInfo = {{
129 // clang-format off
130 {.builtIn: spv::BuiltIn::SubgroupEqMask, .vuid: {0, 4370, 4371}},
131 {.builtIn: spv::BuiltIn::SubgroupGeMask, .vuid: {0, 4372, 4373}},
132 {.builtIn: spv::BuiltIn::SubgroupGtMask, .vuid: {0, 4374, 4375}},
133 {.builtIn: spv::BuiltIn::SubgroupLeMask, .vuid: {0, 4376, 4377}},
134 {.builtIn: spv::BuiltIn::SubgroupLtMask, .vuid: {0, 4378, 4379}},
135 {.builtIn: spv::BuiltIn::SubgroupLocalInvocationId, .vuid: {0, 4380, 4381}},
136 {.builtIn: spv::BuiltIn::SubgroupSize, .vuid: {0, 4382, 4383}},
137 {.builtIn: spv::BuiltIn::GlobalInvocationId, .vuid: {4236, 4237, 4238}},
138 {.builtIn: spv::BuiltIn::LocalInvocationId, .vuid: {4281, 4282, 4283}},
139 {.builtIn: spv::BuiltIn::NumWorkgroups, .vuid: {4296, 4297, 4298}},
140 {.builtIn: spv::BuiltIn::NumSubgroups, .vuid: {4293, 4294, 4295}},
141 {.builtIn: spv::BuiltIn::SubgroupId, .vuid: {4367, 4368, 4369}},
142 {.builtIn: spv::BuiltIn::WorkgroupId, .vuid: {4422, 4423, 4424}},
143 {.builtIn: spv::BuiltIn::HitKindKHR, .vuid: {4242, 4243, 4244}},
144 {.builtIn: spv::BuiltIn::HitTNV, .vuid: {4245, 4246, 4247}},
145 {.builtIn: spv::BuiltIn::InstanceCustomIndexKHR, .vuid: {4251, 4252, 4253}},
146 {.builtIn: spv::BuiltIn::InstanceId, .vuid: {4254, 4255, 4256}},
147 {.builtIn: spv::BuiltIn::RayGeometryIndexKHR, .vuid: {4345, 4346, 4347}},
148 {.builtIn: spv::BuiltIn::ObjectRayDirectionKHR, .vuid: {4299, 4300, 4301}},
149 {.builtIn: spv::BuiltIn::ObjectRayOriginKHR, .vuid: {4302, 4303, 4304}},
150 {.builtIn: spv::BuiltIn::ObjectToWorldKHR, .vuid: {4305, 4306, 4307}},
151 {.builtIn: spv::BuiltIn::WorldToObjectKHR, .vuid: {4434, 4435, 4436}},
152 {.builtIn: spv::BuiltIn::IncomingRayFlagsKHR, .vuid: {4248, 4249, 4250}},
153 {.builtIn: spv::BuiltIn::RayTminKHR, .vuid: {4351, 4352, 4353}},
154 {.builtIn: spv::BuiltIn::RayTmaxKHR, .vuid: {4348, 4349, 4350}},
155 {.builtIn: spv::BuiltIn::WorldRayDirectionKHR, .vuid: {4428, 4429, 4430}},
156 {.builtIn: spv::BuiltIn::WorldRayOriginKHR, .vuid: {4431, 4432, 4433}},
157 {.builtIn: spv::BuiltIn::LaunchIdKHR, .vuid: {4266, 4267, 4268}},
158 {.builtIn: spv::BuiltIn::LaunchSizeKHR, .vuid: {4269, 4270, 4271}},
159 {.builtIn: spv::BuiltIn::FragInvocationCountEXT, .vuid: {4217, 4218, 4219}},
160 {.builtIn: spv::BuiltIn::FragSizeEXT, .vuid: {4220, 4221, 4222}},
161 {.builtIn: spv::BuiltIn::FragStencilRefEXT, .vuid: {4223, 4224, 4225}},
162 {.builtIn: spv::BuiltIn::FullyCoveredEXT, .vuid: {4232, 4233, 4234}},
163 {.builtIn: spv::BuiltIn::CullMaskKHR, .vuid: {6735, 6736, 6737}},
164 {.builtIn: spv::BuiltIn::BaryCoordKHR, .vuid: {4154, 4155, 4156}},
165 {.builtIn: spv::BuiltIn::BaryCoordNoPerspKHR, .vuid: {4160, 4161, 4162}},
166 // clang-format off
167} };
168
169uint32_t GetVUIDForBuiltin(spv::BuiltIn builtIn, VUIDError type) {
170 uint32_t vuid = 0;
171 for (const auto& iter: builtinVUIDInfo) {
172 if (iter.builtIn == builtIn) {
173 assert(type < VUIDErrorMax);
174 vuid = iter.vuid[type];
175 break;
176 }
177 }
178 return vuid;
179}
180
181bool IsExecutionModelValidForRtBuiltIn(spv::BuiltIn builtin,
182 spv::ExecutionModel stage) {
183 switch (builtin) {
184 case spv::BuiltIn::HitKindKHR:
185 case spv::BuiltIn::HitTNV:
186 if (stage == spv::ExecutionModel::AnyHitKHR ||
187 stage == spv::ExecutionModel::ClosestHitKHR) {
188 return true;
189 }
190 break;
191 case spv::BuiltIn::InstanceCustomIndexKHR:
192 case spv::BuiltIn::InstanceId:
193 case spv::BuiltIn::RayGeometryIndexKHR:
194 case spv::BuiltIn::ObjectRayDirectionKHR:
195 case spv::BuiltIn::ObjectRayOriginKHR:
196 case spv::BuiltIn::ObjectToWorldKHR:
197 case spv::BuiltIn::WorldToObjectKHR:
198 switch (stage) {
199 case spv::ExecutionModel::IntersectionKHR:
200 case spv::ExecutionModel::AnyHitKHR:
201 case spv::ExecutionModel::ClosestHitKHR:
202 return true;
203 default:
204 return false;
205 }
206 break;
207 case spv::BuiltIn::IncomingRayFlagsKHR:
208 case spv::BuiltIn::RayTminKHR:
209 case spv::BuiltIn::RayTmaxKHR:
210 case spv::BuiltIn::WorldRayDirectionKHR:
211 case spv::BuiltIn::WorldRayOriginKHR:
212 case spv::BuiltIn::CullMaskKHR:
213 switch (stage) {
214 case spv::ExecutionModel::IntersectionKHR:
215 case spv::ExecutionModel::AnyHitKHR:
216 case spv::ExecutionModel::ClosestHitKHR:
217 case spv::ExecutionModel::MissKHR:
218 return true;
219 default:
220 return false;
221 }
222 break;
223 case spv::BuiltIn::LaunchIdKHR:
224 case spv::BuiltIn::LaunchSizeKHR:
225 switch (stage) {
226 case spv::ExecutionModel::RayGenerationKHR:
227 case spv::ExecutionModel::IntersectionKHR:
228 case spv::ExecutionModel::AnyHitKHR:
229 case spv::ExecutionModel::ClosestHitKHR:
230 case spv::ExecutionModel::MissKHR:
231 case spv::ExecutionModel::CallableKHR:
232 return true;
233 default:
234 return false;
235 }
236 break;
237 default:
238 break;
239 }
240 return false;
241}
242
243// Helper class managing validation of built-ins.
244// TODO: Generic functionality of this class can be moved into
245// ValidationState_t to be made available to other users.
246class BuiltInsValidator {
247 public:
248 BuiltInsValidator(ValidationState_t& vstate) : _(vstate) {}
249
250 // Run validation.
251 spv_result_t Run();
252
253 private:
254 // Goes through all decorations in the module, if decoration is BuiltIn
255 // calls ValidateSingleBuiltInAtDefinition().
256 spv_result_t ValidateBuiltInsAtDefinition();
257
258 // Validates the instruction defining an id with built-in decoration.
259 // Can be called multiple times for the same id, if multiple built-ins are
260 // specified. Seeds id_to_at_reference_checks_ with decorated ids if needed.
261 spv_result_t ValidateSingleBuiltInAtDefinition(const Decoration& decoration,
262 const Instruction& inst);
263
264 // The following section contains functions which are called when id defined
265 // by |inst| is decorated with BuiltIn |decoration|.
266 // Most functions are specific to a single built-in and have naming scheme:
267 // ValidateXYZAtDefinition. Some functions are common to multiple kinds of
268 // BuiltIn.
269 spv_result_t ValidateClipOrCullDistanceAtDefinition(
270 const Decoration& decoration, const Instruction& inst);
271 spv_result_t ValidateFragCoordAtDefinition(const Decoration& decoration,
272 const Instruction& inst);
273 spv_result_t ValidateFragDepthAtDefinition(const Decoration& decoration,
274 const Instruction& inst);
275 spv_result_t ValidateFrontFacingAtDefinition(const Decoration& decoration,
276 const Instruction& inst);
277 spv_result_t ValidateHelperInvocationAtDefinition(
278 const Decoration& decoration, const Instruction& inst);
279 spv_result_t ValidateInvocationIdAtDefinition(const Decoration& decoration,
280 const Instruction& inst);
281 spv_result_t ValidateInstanceIndexAtDefinition(const Decoration& decoration,
282 const Instruction& inst);
283 spv_result_t ValidateLayerOrViewportIndexAtDefinition(
284 const Decoration& decoration, const Instruction& inst);
285 spv_result_t ValidatePatchVerticesAtDefinition(const Decoration& decoration,
286 const Instruction& inst);
287 spv_result_t ValidatePointCoordAtDefinition(const Decoration& decoration,
288 const Instruction& inst);
289 spv_result_t ValidatePointSizeAtDefinition(const Decoration& decoration,
290 const Instruction& inst);
291 spv_result_t ValidatePositionAtDefinition(const Decoration& decoration,
292 const Instruction& inst);
293 spv_result_t ValidatePrimitiveIdAtDefinition(const Decoration& decoration,
294 const Instruction& inst);
295 spv_result_t ValidateSampleIdAtDefinition(const Decoration& decoration,
296 const Instruction& inst);
297 spv_result_t ValidateSampleMaskAtDefinition(const Decoration& decoration,
298 const Instruction& inst);
299 spv_result_t ValidateSamplePositionAtDefinition(const Decoration& decoration,
300 const Instruction& inst);
301 spv_result_t ValidateTessCoordAtDefinition(const Decoration& decoration,
302 const Instruction& inst);
303 spv_result_t ValidateTessLevelOuterAtDefinition(const Decoration& decoration,
304 const Instruction& inst);
305 spv_result_t ValidateTessLevelInnerAtDefinition(const Decoration& decoration,
306 const Instruction& inst);
307 spv_result_t ValidateVertexIndexAtDefinition(const Decoration& decoration,
308 const Instruction& inst);
309 spv_result_t ValidateVertexIdAtDefinition(const Decoration& decoration,
310 const Instruction& inst);
311 spv_result_t ValidateLocalInvocationIndexAtDefinition(
312 const Decoration& decoration, const Instruction& inst);
313 spv_result_t ValidateWorkgroupSizeAtDefinition(const Decoration& decoration,
314 const Instruction& inst);
315 spv_result_t ValidateBaseInstanceOrVertexAtDefinition(
316 const Decoration& decoration, const Instruction& inst);
317 spv_result_t ValidateDrawIndexAtDefinition(const Decoration& decoration,
318 const Instruction& inst);
319 spv_result_t ValidateViewIndexAtDefinition(const Decoration& decoration,
320 const Instruction& inst);
321 spv_result_t ValidateDeviceIndexAtDefinition(const Decoration& decoration,
322 const Instruction& inst);
323 spv_result_t ValidateFragInvocationCountAtDefinition(const Decoration& decoration,
324 const Instruction& inst);
325 spv_result_t ValidateFragSizeAtDefinition(const Decoration& decoration,
326 const Instruction& inst);
327 spv_result_t ValidateFragStencilRefAtDefinition(const Decoration& decoration,
328 const Instruction& inst);
329 spv_result_t ValidateFullyCoveredAtDefinition(const Decoration& decoration,
330 const Instruction& inst);
331 // Used for GlobalInvocationId, LocalInvocationId, NumWorkgroups, WorkgroupId.
332 spv_result_t ValidateComputeShaderI32Vec3InputAtDefinition(
333 const Decoration& decoration, const Instruction& inst);
334 spv_result_t ValidateNVSMOrARMCoreBuiltinsAtDefinition(const Decoration& decoration,
335 const Instruction& inst);
336 // Used for BaryCoord, BaryCoordNoPersp.
337 spv_result_t ValidateFragmentShaderF32Vec3InputAtDefinition(
338 const Decoration& decoration, const Instruction& inst);
339 // Used for SubgroupEqMask, SubgroupGeMask, SubgroupGtMask, SubgroupLtMask,
340 // SubgroupLeMask.
341 spv_result_t ValidateI32Vec4InputAtDefinition(const Decoration& decoration,
342 const Instruction& inst);
343 // Used for SubgroupLocalInvocationId, SubgroupSize.
344 spv_result_t ValidateI32InputAtDefinition(const Decoration& decoration,
345 const Instruction& inst);
346 // Used for SubgroupId, NumSubgroups.
347 spv_result_t ValidateComputeI32InputAtDefinition(const Decoration& decoration,
348 const Instruction& inst);
349
350 spv_result_t ValidatePrimitiveShadingRateAtDefinition(
351 const Decoration& decoration, const Instruction& inst);
352
353 spv_result_t ValidateShadingRateAtDefinition(const Decoration& decoration,
354 const Instruction& inst);
355
356 spv_result_t ValidateRayTracingBuiltinsAtDefinition(
357 const Decoration& decoration, const Instruction& inst);
358
359 // The following section contains functions which are called when id defined
360 // by |referenced_inst| is
361 // 1. referenced by |referenced_from_inst|
362 // 2. dependent on |built_in_inst| which is decorated with BuiltIn
363 // |decoration|. Most functions are specific to a single built-in and have
364 // naming scheme: ValidateXYZAtReference. Some functions are common to
365 // multiple kinds of BuiltIn.
366 spv_result_t ValidateFragCoordAtReference(
367 const Decoration& decoration, const Instruction& built_in_inst,
368 const Instruction& referenced_inst,
369 const Instruction& referenced_from_inst);
370
371 spv_result_t ValidateFragDepthAtReference(
372 const Decoration& decoration, const Instruction& built_in_inst,
373 const Instruction& referenced_inst,
374 const Instruction& referenced_from_inst);
375
376 spv_result_t ValidateFrontFacingAtReference(
377 const Decoration& decoration, const Instruction& built_in_inst,
378 const Instruction& referenced_inst,
379 const Instruction& referenced_from_inst);
380
381 spv_result_t ValidateHelperInvocationAtReference(
382 const Decoration& decoration, const Instruction& built_in_inst,
383 const Instruction& referenced_inst,
384 const Instruction& referenced_from_inst);
385
386 spv_result_t ValidateInvocationIdAtReference(
387 const Decoration& decoration, const Instruction& built_in_inst,
388 const Instruction& referenced_inst,
389 const Instruction& referenced_from_inst);
390
391 spv_result_t ValidateInstanceIndexAtReference(
392 const Decoration& decoration, const Instruction& built_in_inst,
393 const Instruction& referenced_inst,
394 const Instruction& referenced_from_inst);
395
396 spv_result_t ValidatePatchVerticesAtReference(
397 const Decoration& decoration, const Instruction& built_in_inst,
398 const Instruction& referenced_inst,
399 const Instruction& referenced_from_inst);
400
401 spv_result_t ValidatePointCoordAtReference(
402 const Decoration& decoration, const Instruction& built_in_inst,
403 const Instruction& referenced_inst,
404 const Instruction& referenced_from_inst);
405
406 spv_result_t ValidatePointSizeAtReference(
407 const Decoration& decoration, const Instruction& built_in_inst,
408 const Instruction& referenced_inst,
409 const Instruction& referenced_from_inst);
410
411 spv_result_t ValidatePositionAtReference(
412 const Decoration& decoration, const Instruction& built_in_inst,
413 const Instruction& referenced_inst,
414 const Instruction& referenced_from_inst);
415
416 spv_result_t ValidatePrimitiveIdAtReference(
417 const Decoration& decoration, const Instruction& built_in_inst,
418 const Instruction& referenced_inst,
419 const Instruction& referenced_from_inst);
420
421 spv_result_t ValidateSampleIdAtReference(
422 const Decoration& decoration, const Instruction& built_in_inst,
423 const Instruction& referenced_inst,
424 const Instruction& referenced_from_inst);
425
426 spv_result_t ValidateSampleMaskAtReference(
427 const Decoration& decoration, const Instruction& built_in_inst,
428 const Instruction& referenced_inst,
429 const Instruction& referenced_from_inst);
430
431 spv_result_t ValidateSamplePositionAtReference(
432 const Decoration& decoration, const Instruction& built_in_inst,
433 const Instruction& referenced_inst,
434 const Instruction& referenced_from_inst);
435
436 spv_result_t ValidateTessCoordAtReference(
437 const Decoration& decoration, const Instruction& built_in_inst,
438 const Instruction& referenced_inst,
439 const Instruction& referenced_from_inst);
440
441 spv_result_t ValidateTessLevelAtReference(
442 const Decoration& decoration, const Instruction& built_in_inst,
443 const Instruction& referenced_inst,
444 const Instruction& referenced_from_inst);
445
446 spv_result_t ValidateLocalInvocationIndexAtReference(
447 const Decoration& decoration, const Instruction& built_in_inst,
448 const Instruction& referenced_inst,
449 const Instruction& referenced_from_inst);
450
451 spv_result_t ValidateVertexIndexAtReference(
452 const Decoration& decoration, const Instruction& built_in_inst,
453 const Instruction& referenced_inst,
454 const Instruction& referenced_from_inst);
455
456 spv_result_t ValidateLayerOrViewportIndexAtReference(
457 const Decoration& decoration, const Instruction& built_in_inst,
458 const Instruction& referenced_inst,
459 const Instruction& referenced_from_inst);
460
461 spv_result_t ValidateWorkgroupSizeAtReference(
462 const Decoration& decoration, const Instruction& built_in_inst,
463 const Instruction& referenced_inst,
464 const Instruction& referenced_from_inst);
465
466 spv_result_t ValidateClipOrCullDistanceAtReference(
467 const Decoration& decoration, const Instruction& built_in_inst,
468 const Instruction& referenced_inst,
469 const Instruction& referenced_from_inst);
470
471 spv_result_t ValidateBaseInstanceOrVertexAtReference(
472 const Decoration& decoration, const Instruction& built_in_inst,
473 const Instruction& referenced_inst,
474 const Instruction& referenced_from_inst);
475
476 spv_result_t ValidateDrawIndexAtReference(
477 const Decoration& decoration, const Instruction& built_in_inst,
478 const Instruction& referenced_inst,
479 const Instruction& referenced_from_inst);
480
481 spv_result_t ValidateViewIndexAtReference(
482 const Decoration& decoration, const Instruction& built_in_inst,
483 const Instruction& referenced_inst,
484 const Instruction& referenced_from_inst);
485
486 spv_result_t ValidateDeviceIndexAtReference(
487 const Decoration& decoration, const Instruction& built_in_inst,
488 const Instruction& referenced_inst,
489 const Instruction& referenced_from_inst);
490
491 spv_result_t ValidateFragInvocationCountAtReference(
492 const Decoration& decoration, const Instruction& built_in_inst,
493 const Instruction& referenced_inst,
494 const Instruction& referenced_from_inst);
495
496 spv_result_t ValidateFragSizeAtReference(
497 const Decoration& decoration, const Instruction& built_in_inst,
498 const Instruction& referenced_inst,
499 const Instruction& referenced_from_inst);
500
501 spv_result_t ValidateFragStencilRefAtReference(
502 const Decoration& decoration, const Instruction& built_in_inst,
503 const Instruction& referenced_inst,
504 const Instruction& referenced_from_inst);
505
506 spv_result_t ValidateFullyCoveredAtReference(
507 const Decoration& decoration, const Instruction& built_in_inst,
508 const Instruction& referenced_inst,
509 const Instruction& referenced_from_inst);
510
511 // Used for GlobalInvocationId, LocalInvocationId, NumWorkgroups, WorkgroupId.
512 spv_result_t ValidateComputeShaderI32Vec3InputAtReference(
513 const Decoration& decoration, const Instruction& built_in_inst,
514 const Instruction& referenced_inst,
515 const Instruction& referenced_from_inst);
516
517 // Used for BaryCoord, BaryCoordNoPersp.
518 spv_result_t ValidateFragmentShaderF32Vec3InputAtReference(
519 const Decoration& decoration, const Instruction& built_in_inst,
520 const Instruction& referenced_inst,
521 const Instruction& referenced_from_inst);
522
523 // Used for SubgroupId and NumSubgroups.
524 spv_result_t ValidateComputeI32InputAtReference(
525 const Decoration& decoration, const Instruction& built_in_inst,
526 const Instruction& referenced_inst,
527 const Instruction& referenced_from_inst);
528
529 spv_result_t ValidateNVSMOrARMCoreBuiltinsAtReference(
530 const Decoration& decoration, const Instruction& built_in_inst,
531 const Instruction& referenced_inst,
532 const Instruction& referenced_from_inst);
533
534 spv_result_t ValidatePrimitiveShadingRateAtReference(
535 const Decoration& decoration, const Instruction& built_in_inst,
536 const Instruction& referenced_inst,
537 const Instruction& referenced_from_inst);
538
539 spv_result_t ValidateShadingRateAtReference(
540 const Decoration& decoration, const Instruction& built_in_inst,
541 const Instruction& referenced_inst,
542 const Instruction& referenced_from_inst);
543
544 spv_result_t ValidateRayTracingBuiltinsAtReference(
545 const Decoration& decoration, const Instruction& built_in_inst,
546 const Instruction& referenced_inst,
547 const Instruction& referenced_from_inst);
548
549 // Validates that |built_in_inst| is not (even indirectly) referenced from
550 // within a function which can be called with |execution_model|.
551 //
552 // |vuid| - Vulkan ID for the error, or a negative value if none.
553 // |comment| - text explaining why the restriction was imposed.
554 // |decoration| - BuiltIn decoration which causes the restriction.
555 // |referenced_inst| - instruction which is dependent on |built_in_inst| and
556 // defines the id which was referenced.
557 // |referenced_from_inst| - instruction which references id defined by
558 // |referenced_inst| from within a function.
559 spv_result_t ValidateNotCalledWithExecutionModel(
560 int vuid, const char* comment, spv::ExecutionModel execution_model,
561 const Decoration& decoration, const Instruction& built_in_inst,
562 const Instruction& referenced_inst,
563 const Instruction& referenced_from_inst);
564
565 // The following section contains functions which check that the decorated
566 // variable has the type specified in the function name. |diag| would be
567 // called with a corresponding error message, if validation is not successful.
568 spv_result_t ValidateBool(
569 const Decoration& decoration, const Instruction& inst,
570 const std::function<spv_result_t(const std::string& message)>& diag);
571 spv_result_t ValidateI(
572 const Decoration& decoration, const Instruction& inst,
573 const std::function<spv_result_t(const std::string& message)>& diag);
574 spv_result_t ValidateI32(
575 const Decoration& decoration, const Instruction& inst,
576 const std::function<spv_result_t(const std::string& message)>& diag);
577 spv_result_t ValidateI32Vec(
578 const Decoration& decoration, const Instruction& inst,
579 uint32_t num_components,
580 const std::function<spv_result_t(const std::string& message)>& diag);
581 spv_result_t ValidateI32Arr(
582 const Decoration& decoration, const Instruction& inst,
583 const std::function<spv_result_t(const std::string& message)>& diag);
584 spv_result_t ValidateOptionalArrayedI32(
585 const Decoration& decoration, const Instruction& inst,
586 const std::function<spv_result_t(const std::string& message)>& diag);
587 spv_result_t ValidateI32Helper(
588 const Decoration& decoration, const Instruction& inst,
589 const std::function<spv_result_t(const std::string& message)>& diag,
590 uint32_t underlying_type);
591 spv_result_t ValidateF32(
592 const Decoration& decoration, const Instruction& inst,
593 const std::function<spv_result_t(const std::string& message)>& diag);
594 spv_result_t ValidateOptionalArrayedF32(
595 const Decoration& decoration, const Instruction& inst,
596 const std::function<spv_result_t(const std::string& message)>& diag);
597 spv_result_t ValidateF32Helper(
598 const Decoration& decoration, const Instruction& inst,
599 const std::function<spv_result_t(const std::string& message)>& diag,
600 uint32_t underlying_type);
601 spv_result_t ValidateF32Vec(
602 const Decoration& decoration, const Instruction& inst,
603 uint32_t num_components,
604 const std::function<spv_result_t(const std::string& message)>& diag);
605 spv_result_t ValidateOptionalArrayedF32Vec(
606 const Decoration& decoration, const Instruction& inst,
607 uint32_t num_components,
608 const std::function<spv_result_t(const std::string& message)>& diag);
609 spv_result_t ValidateF32VecHelper(
610 const Decoration& decoration, const Instruction& inst,
611 uint32_t num_components,
612 const std::function<spv_result_t(const std::string& message)>& diag,
613 uint32_t underlying_type);
614 // If |num_components| is zero, the number of components is not checked.
615 spv_result_t ValidateF32Arr(
616 const Decoration& decoration, const Instruction& inst,
617 uint32_t num_components,
618 const std::function<spv_result_t(const std::string& message)>& diag);
619 spv_result_t ValidateOptionalArrayedF32Arr(
620 const Decoration& decoration, const Instruction& inst,
621 uint32_t num_components,
622 const std::function<spv_result_t(const std::string& message)>& diag);
623 spv_result_t ValidateF32ArrHelper(
624 const Decoration& decoration, const Instruction& inst,
625 uint32_t num_components,
626 const std::function<spv_result_t(const std::string& message)>& diag,
627 uint32_t underlying_type);
628 spv_result_t ValidateF32Mat(
629 const Decoration& decoration, const Instruction& inst,
630 uint32_t req_num_rows, uint32_t req_num_columns,
631 const std::function<spv_result_t(const std::string& message)>& diag);
632
633 // Generates strings like "Member #0 of struct ID <2>".
634 std::string GetDefinitionDesc(const Decoration& decoration,
635 const Instruction& inst) const;
636
637 // Generates strings like "ID <51> (OpTypePointer) is referencing ID <2>
638 // (OpTypeStruct) which is decorated with BuiltIn Position".
639 std::string GetReferenceDesc(
640 const Decoration& decoration, const Instruction& built_in_inst,
641 const Instruction& referenced_inst,
642 const Instruction& referenced_from_inst,
643 spv::ExecutionModel execution_model = spv::ExecutionModel::Max) const;
644
645 // Generates strings like "ID <51> (OpTypePointer) uses storage class
646 // UniformConstant".
647 std::string GetStorageClassDesc(const Instruction& inst) const;
648
649 // Updates inner working of the class. Is called sequentially for every
650 // instruction.
651 void Update(const Instruction& inst);
652
653 ValidationState_t& _;
654
655 // Mapping id -> list of rules which validate instruction referencing the
656 // id. Rules can create new rules and add them to this container.
657 // Using std::map, and not std::unordered_map to avoid iterator invalidation
658 // during rehashing.
659 std::map<uint32_t, std::list<std::function<spv_result_t(const Instruction&)>>>
660 id_to_at_reference_checks_;
661
662 // Id of the function we are currently inside. 0 if not inside a function.
663 uint32_t function_id_ = 0;
664
665 // Entry points which can (indirectly) call the current function.
666 // The pointer either points to a vector inside to function_to_entry_points_
667 // or to no_entry_points_. The pointer is guaranteed to never be null.
668 const std::vector<uint32_t> no_entry_points;
669 const std::vector<uint32_t>* entry_points_ = &no_entry_points;
670
671 // Execution models with which the current function can be called.
672 std::set<spv::ExecutionModel> execution_models_;
673};
674
675void BuiltInsValidator::Update(const Instruction& inst) {
676 const spv::Op opcode = inst.opcode();
677 if (opcode == spv::Op::OpFunction) {
678 // Entering a function.
679 assert(function_id_ == 0);
680 function_id_ = inst.id();
681 execution_models_.clear();
682 entry_points_ = &_.FunctionEntryPoints(func: function_id_);
683 // Collect execution models from all entry points from which the current
684 // function can be called.
685 for (const uint32_t entry_point : *entry_points_) {
686 if (const auto* models = _.GetExecutionModels(entry_point)) {
687 execution_models_.insert(f: models->begin(), l: models->end());
688 }
689 }
690 }
691
692 if (opcode == spv::Op::OpFunctionEnd) {
693 // Exiting a function.
694 assert(function_id_ != 0);
695 function_id_ = 0;
696 entry_points_ = &no_entry_points;
697 execution_models_.clear();
698 }
699}
700
701std::string BuiltInsValidator::GetDefinitionDesc(
702 const Decoration& decoration, const Instruction& inst) const {
703 std::ostringstream ss;
704 if (decoration.struct_member_index() != Decoration::kInvalidMember) {
705 assert(inst.opcode() == spv::Op::OpTypeStruct);
706 ss << "Member #" << decoration.struct_member_index();
707 ss << " of struct ID <" << inst.id() << ">";
708 } else {
709 ss << GetIdDesc(inst);
710 }
711 return ss.str();
712}
713
714std::string BuiltInsValidator::GetReferenceDesc(
715 const Decoration& decoration, const Instruction& built_in_inst,
716 const Instruction& referenced_inst, const Instruction& referenced_from_inst,
717 spv::ExecutionModel execution_model) const {
718 std::ostringstream ss;
719 ss << GetIdDesc(inst: referenced_from_inst) << " is referencing "
720 << GetIdDesc(inst: referenced_inst);
721 if (built_in_inst.id() != referenced_inst.id()) {
722 ss << " which is dependent on " << GetIdDesc(inst: built_in_inst);
723 }
724
725 ss << " which is decorated with BuiltIn ";
726 ss << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN,
727 operand: decoration.params()[0]);
728 if (function_id_) {
729 ss << " in function <" << function_id_ << ">";
730 if (execution_model != spv::ExecutionModel::Max) {
731 ss << " called with execution model ";
732 ss << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_EXECUTION_MODEL,
733 operand: uint32_t(execution_model));
734 }
735 }
736 ss << ".";
737 return ss.str();
738}
739
740std::string BuiltInsValidator::GetStorageClassDesc(
741 const Instruction& inst) const {
742 std::ostringstream ss;
743 ss << GetIdDesc(inst) << " uses storage class ";
744 ss << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_STORAGE_CLASS,
745 operand: uint32_t(GetStorageClass(inst)));
746 ss << ".";
747 return ss.str();
748}
749
750spv_result_t BuiltInsValidator::ValidateBool(
751 const Decoration& decoration, const Instruction& inst,
752 const std::function<spv_result_t(const std::string& message)>& diag) {
753 uint32_t underlying_type = 0;
754 if (spv_result_t error =
755 GetUnderlyingType(_, decoration, inst, underlying_type: &underlying_type)) {
756 return error;
757 }
758
759 if (!_.IsBoolScalarType(id: underlying_type)) {
760 return diag(GetDefinitionDesc(decoration, inst) + " is not a bool scalar.");
761 }
762
763 return SPV_SUCCESS;
764}
765
766spv_result_t BuiltInsValidator::ValidateI(
767 const Decoration& decoration, const Instruction& inst,
768 const std::function<spv_result_t(const std::string& message)>& diag) {
769 uint32_t underlying_type = 0;
770 if (spv_result_t error =
771 GetUnderlyingType(_, decoration, inst, underlying_type: &underlying_type)) {
772 return error;
773 }
774
775 if (!_.IsIntScalarType(id: underlying_type)) {
776 return diag(GetDefinitionDesc(decoration, inst) + " is not an int scalar.");
777 }
778
779 return SPV_SUCCESS;
780}
781
782spv_result_t BuiltInsValidator::ValidateI32(
783 const Decoration& decoration, const Instruction& inst,
784 const std::function<spv_result_t(const std::string& message)>& diag) {
785 uint32_t underlying_type = 0;
786 if (spv_result_t error =
787 GetUnderlyingType(_, decoration, inst, underlying_type: &underlying_type)) {
788 return error;
789 }
790
791 return ValidateI32Helper(decoration, inst, diag, underlying_type);
792}
793
794spv_result_t BuiltInsValidator::ValidateOptionalArrayedI32(
795 const Decoration& decoration, const Instruction& inst,
796 const std::function<spv_result_t(const std::string& message)>& diag) {
797 uint32_t underlying_type = 0;
798 if (spv_result_t error =
799 GetUnderlyingType(_, decoration, inst, underlying_type: &underlying_type)) {
800 return error;
801 }
802
803 // Strip the array, if present.
804 if (_.GetIdOpcode(id: underlying_type) == spv::Op::OpTypeArray) {
805 underlying_type = _.FindDef(id: underlying_type)->word(index: 2u);
806 }
807
808 return ValidateI32Helper(decoration, inst, diag, underlying_type);
809}
810
811spv_result_t BuiltInsValidator::ValidateI32Helper(
812 const Decoration& decoration, const Instruction& inst,
813 const std::function<spv_result_t(const std::string& message)>& diag,
814 uint32_t underlying_type) {
815 if (!_.IsIntScalarType(id: underlying_type)) {
816 return diag(GetDefinitionDesc(decoration, inst) + " is not an int scalar.");
817 }
818
819 const uint32_t bit_width = _.GetBitWidth(id: underlying_type);
820 if (bit_width != 32) {
821 std::ostringstream ss;
822 ss << GetDefinitionDesc(decoration, inst) << " has bit width " << bit_width
823 << ".";
824 return diag(ss.str());
825 }
826
827 return SPV_SUCCESS;
828}
829
830spv_result_t BuiltInsValidator::ValidateOptionalArrayedF32(
831 const Decoration& decoration, const Instruction& inst,
832 const std::function<spv_result_t(const std::string& message)>& diag) {
833 uint32_t underlying_type = 0;
834 if (spv_result_t error =
835 GetUnderlyingType(_, decoration, inst, underlying_type: &underlying_type)) {
836 return error;
837 }
838
839 // Strip the array, if present.
840 if (_.GetIdOpcode(id: underlying_type) == spv::Op::OpTypeArray) {
841 underlying_type = _.FindDef(id: underlying_type)->word(index: 2u);
842 }
843
844 return ValidateF32Helper(decoration, inst, diag, underlying_type);
845}
846
847spv_result_t BuiltInsValidator::ValidateF32(
848 const Decoration& decoration, const Instruction& inst,
849 const std::function<spv_result_t(const std::string& message)>& diag) {
850 uint32_t underlying_type = 0;
851 if (spv_result_t error =
852 GetUnderlyingType(_, decoration, inst, underlying_type: &underlying_type)) {
853 return error;
854 }
855
856 return ValidateF32Helper(decoration, inst, diag, underlying_type);
857}
858
859spv_result_t BuiltInsValidator::ValidateF32Helper(
860 const Decoration& decoration, const Instruction& inst,
861 const std::function<spv_result_t(const std::string& message)>& diag,
862 uint32_t underlying_type) {
863 if (!_.IsFloatScalarType(id: underlying_type)) {
864 return diag(GetDefinitionDesc(decoration, inst) +
865 " is not a float scalar.");
866 }
867
868 const uint32_t bit_width = _.GetBitWidth(id: underlying_type);
869 if (bit_width != 32) {
870 std::ostringstream ss;
871 ss << GetDefinitionDesc(decoration, inst) << " has bit width " << bit_width
872 << ".";
873 return diag(ss.str());
874 }
875
876 return SPV_SUCCESS;
877}
878
879spv_result_t BuiltInsValidator::ValidateI32Vec(
880 const Decoration& decoration, const Instruction& inst,
881 uint32_t num_components,
882 const std::function<spv_result_t(const std::string& message)>& diag) {
883 uint32_t underlying_type = 0;
884 if (spv_result_t error =
885 GetUnderlyingType(_, decoration, inst, underlying_type: &underlying_type)) {
886 return error;
887 }
888
889 if (!_.IsIntVectorType(id: underlying_type)) {
890 return diag(GetDefinitionDesc(decoration, inst) + " is not an int vector.");
891 }
892
893 const uint32_t actual_num_components = _.GetDimension(id: underlying_type);
894 if (_.GetDimension(id: underlying_type) != num_components) {
895 std::ostringstream ss;
896 ss << GetDefinitionDesc(decoration, inst) << " has "
897 << actual_num_components << " components.";
898 return diag(ss.str());
899 }
900
901 const uint32_t bit_width = _.GetBitWidth(id: underlying_type);
902 if (bit_width != 32) {
903 std::ostringstream ss;
904 ss << GetDefinitionDesc(decoration, inst)
905 << " has components with bit width " << bit_width << ".";
906 return diag(ss.str());
907 }
908
909 return SPV_SUCCESS;
910}
911
912spv_result_t BuiltInsValidator::ValidateOptionalArrayedF32Vec(
913 const Decoration& decoration, const Instruction& inst,
914 uint32_t num_components,
915 const std::function<spv_result_t(const std::string& message)>& diag) {
916 uint32_t underlying_type = 0;
917 if (spv_result_t error =
918 GetUnderlyingType(_, decoration, inst, underlying_type: &underlying_type)) {
919 return error;
920 }
921
922 // Strip the array, if present.
923 if (_.GetIdOpcode(id: underlying_type) == spv::Op::OpTypeArray) {
924 underlying_type = _.FindDef(id: underlying_type)->word(index: 2u);
925 }
926
927 return ValidateF32VecHelper(decoration, inst, num_components, diag,
928 underlying_type);
929}
930
931spv_result_t BuiltInsValidator::ValidateF32Vec(
932 const Decoration& decoration, const Instruction& inst,
933 uint32_t num_components,
934 const std::function<spv_result_t(const std::string& message)>& diag) {
935 uint32_t underlying_type = 0;
936 if (spv_result_t error =
937 GetUnderlyingType(_, decoration, inst, underlying_type: &underlying_type)) {
938 return error;
939 }
940
941 return ValidateF32VecHelper(decoration, inst, num_components, diag,
942 underlying_type);
943}
944
945spv_result_t BuiltInsValidator::ValidateF32VecHelper(
946 const Decoration& decoration, const Instruction& inst,
947 uint32_t num_components,
948 const std::function<spv_result_t(const std::string& message)>& diag,
949 uint32_t underlying_type) {
950 if (!_.IsFloatVectorType(id: underlying_type)) {
951 return diag(GetDefinitionDesc(decoration, inst) +
952 " is not a float vector.");
953 }
954
955 const uint32_t actual_num_components = _.GetDimension(id: underlying_type);
956 if (_.GetDimension(id: underlying_type) != num_components) {
957 std::ostringstream ss;
958 ss << GetDefinitionDesc(decoration, inst) << " has "
959 << actual_num_components << " components.";
960 return diag(ss.str());
961 }
962
963 const uint32_t bit_width = _.GetBitWidth(id: underlying_type);
964 if (bit_width != 32) {
965 std::ostringstream ss;
966 ss << GetDefinitionDesc(decoration, inst)
967 << " has components with bit width " << bit_width << ".";
968 return diag(ss.str());
969 }
970
971 return SPV_SUCCESS;
972}
973
974spv_result_t BuiltInsValidator::ValidateI32Arr(
975 const Decoration& decoration, const Instruction& inst,
976 const std::function<spv_result_t(const std::string& message)>& diag) {
977 uint32_t underlying_type = 0;
978 if (spv_result_t error =
979 GetUnderlyingType(_, decoration, inst, underlying_type: &underlying_type)) {
980 return error;
981 }
982
983 const Instruction* const type_inst = _.FindDef(id: underlying_type);
984 if (type_inst->opcode() != spv::Op::OpTypeArray) {
985 return diag(GetDefinitionDesc(decoration, inst) + " is not an array.");
986 }
987
988 const uint32_t component_type = type_inst->word(index: 2);
989 if (!_.IsIntScalarType(id: component_type)) {
990 return diag(GetDefinitionDesc(decoration, inst) +
991 " components are not int scalar.");
992 }
993
994 const uint32_t bit_width = _.GetBitWidth(id: component_type);
995 if (bit_width != 32) {
996 std::ostringstream ss;
997 ss << GetDefinitionDesc(decoration, inst)
998 << " has components with bit width " << bit_width << ".";
999 return diag(ss.str());
1000 }
1001
1002 return SPV_SUCCESS;
1003}
1004
1005spv_result_t BuiltInsValidator::ValidateF32Arr(
1006 const Decoration& decoration, const Instruction& inst,
1007 uint32_t num_components,
1008 const std::function<spv_result_t(const std::string& message)>& diag) {
1009 uint32_t underlying_type = 0;
1010 if (spv_result_t error =
1011 GetUnderlyingType(_, decoration, inst, underlying_type: &underlying_type)) {
1012 return error;
1013 }
1014
1015 return ValidateF32ArrHelper(decoration, inst, num_components, diag,
1016 underlying_type);
1017}
1018
1019spv_result_t BuiltInsValidator::ValidateOptionalArrayedF32Arr(
1020 const Decoration& decoration, const Instruction& inst,
1021 uint32_t num_components,
1022 const std::function<spv_result_t(const std::string& message)>& diag) {
1023 uint32_t underlying_type = 0;
1024 if (spv_result_t error =
1025 GetUnderlyingType(_, decoration, inst, underlying_type: &underlying_type)) {
1026 return error;
1027 }
1028
1029 // Strip an extra layer of arraying if present.
1030 if (_.GetIdOpcode(id: underlying_type) == spv::Op::OpTypeArray) {
1031 uint32_t subtype = _.FindDef(id: underlying_type)->word(index: 2u);
1032 if (_.GetIdOpcode(id: subtype) == spv::Op::OpTypeArray) {
1033 underlying_type = subtype;
1034 }
1035 }
1036
1037 return ValidateF32ArrHelper(decoration, inst, num_components, diag,
1038 underlying_type);
1039}
1040
1041spv_result_t BuiltInsValidator::ValidateF32ArrHelper(
1042 const Decoration& decoration, const Instruction& inst,
1043 uint32_t num_components,
1044 const std::function<spv_result_t(const std::string& message)>& diag,
1045 uint32_t underlying_type) {
1046 const Instruction* const type_inst = _.FindDef(id: underlying_type);
1047 if (type_inst->opcode() != spv::Op::OpTypeArray) {
1048 return diag(GetDefinitionDesc(decoration, inst) + " is not an array.");
1049 }
1050
1051 const uint32_t component_type = type_inst->word(index: 2);
1052 if (!_.IsFloatScalarType(id: component_type)) {
1053 return diag(GetDefinitionDesc(decoration, inst) +
1054 " components are not float scalar.");
1055 }
1056
1057 const uint32_t bit_width = _.GetBitWidth(id: component_type);
1058 if (bit_width != 32) {
1059 std::ostringstream ss;
1060 ss << GetDefinitionDesc(decoration, inst)
1061 << " has components with bit width " << bit_width << ".";
1062 return diag(ss.str());
1063 }
1064
1065 if (num_components != 0) {
1066 uint64_t actual_num_components = 0;
1067 if (!_.GetConstantValUint64(id: type_inst->word(index: 3), val: &actual_num_components)) {
1068 assert(0 && "Array type definition is corrupt");
1069 }
1070 if (actual_num_components != num_components) {
1071 std::ostringstream ss;
1072 ss << GetDefinitionDesc(decoration, inst) << " has "
1073 << actual_num_components << " components.";
1074 return diag(ss.str());
1075 }
1076 }
1077
1078 return SPV_SUCCESS;
1079}
1080
1081spv_result_t BuiltInsValidator::ValidateF32Mat(
1082 const Decoration& decoration, const Instruction& inst,
1083 uint32_t req_num_rows, uint32_t req_num_columns,
1084 const std::function<spv_result_t(const std::string& message)>& diag) {
1085 uint32_t underlying_type = 0;
1086 uint32_t num_rows = 0;
1087 uint32_t num_cols = 0;
1088 uint32_t col_type = 0;
1089 uint32_t component_type = 0;
1090 if (spv_result_t error =
1091 GetUnderlyingType(_, decoration, inst, underlying_type: &underlying_type)) {
1092 return error;
1093 }
1094 if (!_.GetMatrixTypeInfo(id: underlying_type, num_rows: &num_rows, num_cols: &num_cols, column_type: &col_type,
1095 component_type: &component_type) ||
1096 num_rows != req_num_rows || num_cols != req_num_columns) {
1097 std::ostringstream ss;
1098 ss << GetDefinitionDesc(decoration, inst) << " has columns " << num_cols
1099 << " and rows " << num_rows << " not equal to expected "
1100 << req_num_columns << "x" << req_num_rows << ".";
1101 return diag(ss.str());
1102 }
1103
1104 return ValidateF32VecHelper(decoration, inst, num_components: req_num_rows, diag, underlying_type: col_type);
1105}
1106
1107spv_result_t BuiltInsValidator::ValidateNotCalledWithExecutionModel(
1108 int vuid, const char* comment, spv::ExecutionModel execution_model,
1109 const Decoration& decoration, const Instruction& built_in_inst,
1110 const Instruction& referenced_inst,
1111 const Instruction& referenced_from_inst) {
1112 if (function_id_) {
1113 if (execution_models_.count(k: execution_model)) {
1114 const char* execution_model_str = _.grammar().lookupOperandName(
1115 type: SPV_OPERAND_TYPE_EXECUTION_MODEL, operand: uint32_t(execution_model));
1116 const char* built_in_str = _.grammar().lookupOperandName(
1117 type: SPV_OPERAND_TYPE_BUILT_IN, operand: decoration.params()[0]);
1118 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
1119 << (vuid < 0 ? std::string("") : _.VkErrorID(id: vuid)) << comment
1120 << " " << GetIdDesc(inst: referenced_inst) << " depends on "
1121 << GetIdDesc(inst: built_in_inst) << " which is decorated with BuiltIn "
1122 << built_in_str << "."
1123 << " Id <" << referenced_inst.id() << "> is later referenced by "
1124 << GetIdDesc(inst: referenced_from_inst) << " in function <"
1125 << function_id_ << "> which is called with execution model "
1126 << execution_model_str << ".";
1127 }
1128 } else {
1129 // Propagate this rule to all dependant ids in the global scope.
1130 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
1131 x: std::bind(f: &BuiltInsValidator::ValidateNotCalledWithExecutionModel, bound_args: this,
1132 bound_args&: vuid, bound_args&: comment, bound_args&: execution_model, bound_args: decoration, bound_args: built_in_inst,
1133 bound_args: referenced_from_inst, bound_args: std::placeholders::_1));
1134 }
1135 return SPV_SUCCESS;
1136}
1137
1138spv_result_t BuiltInsValidator::ValidateClipOrCullDistanceAtDefinition(
1139 const Decoration& decoration, const Instruction& inst) {
1140 // Seed at reference checks with this built-in.
1141 return ValidateClipOrCullDistanceAtReference(decoration, built_in_inst: inst, referenced_inst: inst, referenced_from_inst: inst);
1142}
1143
1144spv_result_t BuiltInsValidator::ValidateClipOrCullDistanceAtReference(
1145 const Decoration& decoration, const Instruction& built_in_inst,
1146 const Instruction& referenced_inst,
1147 const Instruction& referenced_from_inst) {
1148 uint32_t operand = decoration.params()[0];
1149 if (spvIsVulkanEnv(env: _.context()->target_env)) {
1150 const spv::StorageClass storage_class = GetStorageClass(inst: referenced_from_inst);
1151 if (storage_class != spv::StorageClass::Max &&
1152 storage_class != spv::StorageClass::Input &&
1153 storage_class != spv::StorageClass::Output) {
1154 uint32_t vuid = (spv::BuiltIn(decoration.params()[0]) == spv::BuiltIn::ClipDistance) ? 4190 : 4199;
1155 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
1156 << _.VkErrorID(id: vuid) << "Vulkan spec allows BuiltIn "
1157 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN,
1158 operand)
1159 << " to be only used for variables with Input or Output storage "
1160 "class. "
1161 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
1162 referenced_from_inst)
1163 << " " << GetStorageClassDesc(inst: referenced_from_inst);
1164 }
1165
1166 if (storage_class == spv::StorageClass::Input) {
1167 assert(function_id_ == 0);
1168 uint32_t vuid = (spv::BuiltIn(decoration.params()[0]) == spv::BuiltIn::ClipDistance) ? 4188 : 4197;
1169 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(x: std::bind(
1170 f: &BuiltInsValidator::ValidateNotCalledWithExecutionModel, bound_args: this, bound_args&: vuid,
1171 bound_args: "Vulkan spec doesn't allow BuiltIn ClipDistance/CullDistance to be "
1172 "used for variables with Input storage class if execution model is "
1173 "Vertex.",
1174 bound_args: spv::ExecutionModel::Vertex, bound_args: decoration, bound_args: built_in_inst,
1175 bound_args: referenced_from_inst, bound_args: std::placeholders::_1));
1176 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(x: std::bind(
1177 f: &BuiltInsValidator::ValidateNotCalledWithExecutionModel, bound_args: this, bound_args&: vuid,
1178 bound_args: "Vulkan spec doesn't allow BuiltIn ClipDistance/CullDistance to be "
1179 "used for variables with Input storage class if execution model is "
1180 "MeshNV.",
1181 bound_args: spv::ExecutionModel::MeshNV, bound_args: decoration, bound_args: built_in_inst,
1182 bound_args: referenced_from_inst, bound_args: std::placeholders::_1));
1183 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(x: std::bind(
1184 f: &BuiltInsValidator::ValidateNotCalledWithExecutionModel, bound_args: this, bound_args&: vuid,
1185 bound_args: "Vulkan spec doesn't allow BuiltIn ClipDistance/CullDistance to be "
1186 "used for variables with Input storage class if execution model is "
1187 "MeshEXT.",
1188 bound_args: spv::ExecutionModel::MeshEXT, bound_args: decoration, bound_args: built_in_inst,
1189 bound_args: referenced_from_inst, bound_args: std::placeholders::_1));
1190 }
1191
1192 if (storage_class == spv::StorageClass::Output) {
1193 assert(function_id_ == 0);
1194 uint32_t vuid = (spv::BuiltIn(decoration.params()[0]) == spv::BuiltIn::ClipDistance) ? 4189 : 4198;
1195 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(x: std::bind(
1196 f: &BuiltInsValidator::ValidateNotCalledWithExecutionModel, bound_args: this, bound_args&: vuid,
1197 bound_args: "Vulkan spec doesn't allow BuiltIn ClipDistance/CullDistance to be "
1198 "used for variables with Output storage class if execution model is "
1199 "Fragment.",
1200 bound_args: spv::ExecutionModel::Fragment, bound_args: decoration, bound_args: built_in_inst,
1201 bound_args: referenced_from_inst, bound_args: std::placeholders::_1));
1202 }
1203
1204 for (const spv::ExecutionModel execution_model : execution_models_) {
1205 switch (execution_model) {
1206 case spv::ExecutionModel::Fragment:
1207 case spv::ExecutionModel::Vertex: {
1208 if (spv_result_t error = ValidateF32Arr(
1209 decoration, inst: built_in_inst, /* Any number of components */ num_components: 0,
1210 diag: [this, &decoration, &referenced_from_inst](
1211 const std::string& message) -> spv_result_t {
1212 uint32_t vuid =
1213 (spv::BuiltIn(decoration.params()[0]) == spv::BuiltIn::ClipDistance)
1214 ? 4191
1215 : 4200;
1216 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
1217 << _.VkErrorID(id: vuid)
1218 << "According to the Vulkan spec BuiltIn "
1219 << _.grammar().lookupOperandName(
1220 type: SPV_OPERAND_TYPE_BUILT_IN,
1221 operand: decoration.params()[0])
1222 << " variable needs to be a 32-bit float array. "
1223 << message;
1224 })) {
1225 return error;
1226 }
1227 break;
1228 }
1229 case spv::ExecutionModel::TessellationControl:
1230 case spv::ExecutionModel::TessellationEvaluation:
1231 case spv::ExecutionModel::Geometry:
1232 case spv::ExecutionModel::MeshNV:
1233 case spv::ExecutionModel::MeshEXT: {
1234 if (decoration.struct_member_index() != Decoration::kInvalidMember) {
1235 // The outer level of array is applied on the variable.
1236 if (spv_result_t error = ValidateF32Arr(
1237 decoration, inst: built_in_inst, /* Any number of components */ num_components: 0,
1238 diag: [this, &decoration, &referenced_from_inst](
1239 const std::string& message) -> spv_result_t {
1240 uint32_t vuid =
1241 (spv::BuiltIn(decoration.params()[0]) == spv::BuiltIn::ClipDistance)
1242 ? 4191
1243 : 4200;
1244 return _.diag(error_code: SPV_ERROR_INVALID_DATA,
1245 inst: &referenced_from_inst)
1246 << _.VkErrorID(id: vuid)
1247 << "According to the Vulkan spec BuiltIn "
1248 << _.grammar().lookupOperandName(
1249 type: SPV_OPERAND_TYPE_BUILT_IN,
1250 operand: decoration.params()[0])
1251 << " variable needs to be a 32-bit float array. "
1252 << message;
1253 })) {
1254 return error;
1255 }
1256 } else {
1257 if (spv_result_t error = ValidateOptionalArrayedF32Arr(
1258 decoration, inst: built_in_inst, /* Any number of components */ num_components: 0,
1259 diag: [this, &decoration, &referenced_from_inst](
1260 const std::string& message) -> spv_result_t {
1261 uint32_t vuid =
1262 (spv::BuiltIn(decoration.params()[0]) == spv::BuiltIn::ClipDistance)
1263 ? 4191
1264 : 4200;
1265 return _.diag(error_code: SPV_ERROR_INVALID_DATA,
1266 inst: &referenced_from_inst)
1267 << _.VkErrorID(id: vuid)
1268 << "According to the Vulkan spec BuiltIn "
1269 << _.grammar().lookupOperandName(
1270 type: SPV_OPERAND_TYPE_BUILT_IN,
1271 operand: decoration.params()[0])
1272 << " variable needs to be a 32-bit float array. "
1273 << message;
1274 })) {
1275 return error;
1276 }
1277 }
1278 break;
1279 }
1280
1281 default: {
1282 uint32_t vuid =
1283 (spv::BuiltIn(decoration.params()[0]) == spv::BuiltIn::ClipDistance) ? 4187 : 4196;
1284 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
1285 << _.VkErrorID(id: vuid) << "Vulkan spec allows BuiltIn "
1286 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN,
1287 operand)
1288 << " to be used only with Fragment, Vertex, "
1289 "TessellationControl, TessellationEvaluation or Geometry "
1290 "execution models. "
1291 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
1292 referenced_from_inst, execution_model);
1293 }
1294 }
1295 }
1296 }
1297
1298 if (function_id_ == 0) {
1299 // Propagate this rule to all dependant ids in the global scope.
1300 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
1301 x: std::bind(f: &BuiltInsValidator::ValidateClipOrCullDistanceAtReference,
1302 bound_args: this, bound_args: decoration, bound_args: built_in_inst, bound_args: referenced_from_inst,
1303 bound_args: std::placeholders::_1));
1304 }
1305
1306 return SPV_SUCCESS;
1307}
1308
1309spv_result_t BuiltInsValidator::ValidateFragCoordAtDefinition(
1310 const Decoration& decoration, const Instruction& inst) {
1311 if (spvIsVulkanEnv(env: _.context()->target_env)) {
1312 if (spv_result_t error = ValidateF32Vec(
1313 decoration, inst, num_components: 4,
1314 diag: [this, &inst](const std::string& message) -> spv_result_t {
1315 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &inst)
1316 << _.VkErrorID(id: 4212) << "According to the "
1317 << spvLogStringForEnv(env: _.context()->target_env)
1318 << " spec BuiltIn FragCoord "
1319 "variable needs to be a 4-component 32-bit float "
1320 "vector. "
1321 << message;
1322 })) {
1323 return error;
1324 }
1325 }
1326
1327 // Seed at reference checks with this built-in.
1328 return ValidateFragCoordAtReference(decoration, built_in_inst: inst, referenced_inst: inst, referenced_from_inst: inst);
1329}
1330
1331spv_result_t BuiltInsValidator::ValidateFragCoordAtReference(
1332 const Decoration& decoration, const Instruction& built_in_inst,
1333 const Instruction& referenced_inst,
1334 const Instruction& referenced_from_inst) {
1335 if (spvIsVulkanEnv(env: _.context()->target_env)) {
1336 const spv::StorageClass storage_class = GetStorageClass(inst: referenced_from_inst);
1337 if (storage_class != spv::StorageClass::Max &&
1338 storage_class != spv::StorageClass::Input) {
1339 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
1340 << _.VkErrorID(id: 4211) << spvLogStringForEnv(env: _.context()->target_env)
1341 << " spec allows BuiltIn FragCoord to be only used for "
1342 "variables with Input storage class. "
1343 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
1344 referenced_from_inst)
1345 << " " << GetStorageClassDesc(inst: referenced_from_inst);
1346 }
1347
1348 for (const spv::ExecutionModel execution_model : execution_models_) {
1349 if (execution_model != spv::ExecutionModel::Fragment) {
1350 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
1351 << _.VkErrorID(id: 4210)
1352 << spvLogStringForEnv(env: _.context()->target_env)
1353 << " spec allows BuiltIn FragCoord to be used only with "
1354 "Fragment execution model. "
1355 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
1356 referenced_from_inst, execution_model);
1357 }
1358 }
1359 }
1360
1361 if (function_id_ == 0) {
1362 // Propagate this rule to all dependant ids in the global scope.
1363 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(x: std::bind(
1364 f: &BuiltInsValidator::ValidateFragCoordAtReference, bound_args: this, bound_args: decoration,
1365 bound_args: built_in_inst, bound_args: referenced_from_inst, bound_args: std::placeholders::_1));
1366 }
1367
1368 return SPV_SUCCESS;
1369}
1370
1371spv_result_t BuiltInsValidator::ValidateFragDepthAtDefinition(
1372 const Decoration& decoration, const Instruction& inst) {
1373 if (spvIsVulkanEnv(env: _.context()->target_env)) {
1374 if (spv_result_t error = ValidateF32(
1375 decoration, inst,
1376 diag: [this, &inst](const std::string& message) -> spv_result_t {
1377 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &inst)
1378 << _.VkErrorID(id: 4215) << "According to the "
1379 << spvLogStringForEnv(env: _.context()->target_env)
1380 << " spec BuiltIn FragDepth "
1381 "variable needs to be a 32-bit float scalar. "
1382 << message;
1383 })) {
1384 return error;
1385 }
1386 }
1387
1388 // Seed at reference checks with this built-in.
1389 return ValidateFragDepthAtReference(decoration, built_in_inst: inst, referenced_inst: inst, referenced_from_inst: inst);
1390}
1391
1392spv_result_t BuiltInsValidator::ValidateFragDepthAtReference(
1393 const Decoration& decoration, const Instruction& built_in_inst,
1394 const Instruction& referenced_inst,
1395 const Instruction& referenced_from_inst) {
1396 if (spvIsVulkanEnv(env: _.context()->target_env)) {
1397 const spv::StorageClass storage_class = GetStorageClass(inst: referenced_from_inst);
1398 if (storage_class != spv::StorageClass::Max &&
1399 storage_class != spv::StorageClass::Output) {
1400 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
1401 << _.VkErrorID(id: 4214) << spvLogStringForEnv(env: _.context()->target_env)
1402 << " spec allows BuiltIn FragDepth to be only used for "
1403 "variables with Output storage class. "
1404 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
1405 referenced_from_inst)
1406 << " " << GetStorageClassDesc(inst: referenced_from_inst);
1407 }
1408
1409 for (const spv::ExecutionModel execution_model : execution_models_) {
1410 if (execution_model != spv::ExecutionModel::Fragment) {
1411 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
1412 << _.VkErrorID(id: 4213)
1413 << spvLogStringForEnv(env: _.context()->target_env)
1414 << " spec allows BuiltIn FragDepth to be used only with "
1415 "Fragment execution model. "
1416 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
1417 referenced_from_inst, execution_model);
1418 }
1419 }
1420
1421 for (const uint32_t entry_point : *entry_points_) {
1422 // Every entry point from which this function is called needs to have
1423 // Execution Mode DepthReplacing.
1424 const auto* modes = _.GetExecutionModes(entry_point);
1425 if (!modes || !modes->count(k: spv::ExecutionMode::DepthReplacing)) {
1426 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
1427 << _.VkErrorID(id: 4216)
1428 << spvLogStringForEnv(env: _.context()->target_env)
1429 << " spec requires DepthReplacing execution mode to be "
1430 "declared when using BuiltIn FragDepth. "
1431 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
1432 referenced_from_inst);
1433 }
1434 }
1435 }
1436
1437 if (function_id_ == 0) {
1438 // Propagate this rule to all dependant ids in the global scope.
1439 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(x: std::bind(
1440 f: &BuiltInsValidator::ValidateFragDepthAtReference, bound_args: this, bound_args: decoration,
1441 bound_args: built_in_inst, bound_args: referenced_from_inst, bound_args: std::placeholders::_1));
1442 }
1443
1444 return SPV_SUCCESS;
1445}
1446
1447spv_result_t BuiltInsValidator::ValidateFrontFacingAtDefinition(
1448 const Decoration& decoration, const Instruction& inst) {
1449 if (spvIsVulkanEnv(env: _.context()->target_env)) {
1450 if (spv_result_t error = ValidateBool(
1451 decoration, inst,
1452 diag: [this, &inst](const std::string& message) -> spv_result_t {
1453 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &inst)
1454 << _.VkErrorID(id: 4231) << "According to the "
1455 << spvLogStringForEnv(env: _.context()->target_env)
1456 << " spec BuiltIn FrontFacing "
1457 "variable needs to be a bool scalar. "
1458 << message;
1459 })) {
1460 return error;
1461 }
1462 }
1463
1464 // Seed at reference checks with this built-in.
1465 return ValidateFrontFacingAtReference(decoration, built_in_inst: inst, referenced_inst: inst, referenced_from_inst: inst);
1466}
1467
1468spv_result_t BuiltInsValidator::ValidateFrontFacingAtReference(
1469 const Decoration& decoration, const Instruction& built_in_inst,
1470 const Instruction& referenced_inst,
1471 const Instruction& referenced_from_inst) {
1472 if (spvIsVulkanEnv(env: _.context()->target_env)) {
1473 const spv::StorageClass storage_class = GetStorageClass(inst: referenced_from_inst);
1474 if (storage_class != spv::StorageClass::Max &&
1475 storage_class != spv::StorageClass::Input) {
1476 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
1477 << _.VkErrorID(id: 4230) << spvLogStringForEnv(env: _.context()->target_env)
1478 << " spec allows BuiltIn FrontFacing to be only used for "
1479 "variables with Input storage class. "
1480 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
1481 referenced_from_inst)
1482 << " " << GetStorageClassDesc(inst: referenced_from_inst);
1483 }
1484
1485 for (const spv::ExecutionModel execution_model : execution_models_) {
1486 if (execution_model != spv::ExecutionModel::Fragment) {
1487 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
1488 << _.VkErrorID(id: 4229)
1489 << spvLogStringForEnv(env: _.context()->target_env)
1490 << " spec allows BuiltIn FrontFacing to be used only with "
1491 "Fragment execution model. "
1492 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
1493 referenced_from_inst, execution_model);
1494 }
1495 }
1496 }
1497
1498 if (function_id_ == 0) {
1499 // Propagate this rule to all dependant ids in the global scope.
1500 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(x: std::bind(
1501 f: &BuiltInsValidator::ValidateFrontFacingAtReference, bound_args: this, bound_args: decoration,
1502 bound_args: built_in_inst, bound_args: referenced_from_inst, bound_args: std::placeholders::_1));
1503 }
1504
1505 return SPV_SUCCESS;
1506}
1507
1508spv_result_t BuiltInsValidator::ValidateHelperInvocationAtDefinition(
1509 const Decoration& decoration, const Instruction& inst) {
1510 if (spvIsVulkanEnv(env: _.context()->target_env)) {
1511 if (spv_result_t error = ValidateBool(
1512 decoration, inst,
1513 diag: [this, &inst](const std::string& message) -> spv_result_t {
1514 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &inst)
1515 << _.VkErrorID(id: 4241)
1516 << "According to the Vulkan spec BuiltIn HelperInvocation "
1517 "variable needs to be a bool scalar. "
1518 << message;
1519 })) {
1520 return error;
1521 }
1522 }
1523
1524 // Seed at reference checks with this built-in.
1525 return ValidateHelperInvocationAtReference(decoration, built_in_inst: inst, referenced_inst: inst, referenced_from_inst: inst);
1526}
1527
1528spv_result_t BuiltInsValidator::ValidateHelperInvocationAtReference(
1529 const Decoration& decoration, const Instruction& built_in_inst,
1530 const Instruction& referenced_inst,
1531 const Instruction& referenced_from_inst) {
1532 if (spvIsVulkanEnv(env: _.context()->target_env)) {
1533 const spv::StorageClass storage_class = GetStorageClass(inst: referenced_from_inst);
1534 if (storage_class != spv::StorageClass::Max &&
1535 storage_class != spv::StorageClass::Input) {
1536 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
1537 << _.VkErrorID(id: 4240)
1538 << "Vulkan spec allows BuiltIn HelperInvocation to be only used "
1539 "for variables with Input storage class. "
1540 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
1541 referenced_from_inst)
1542 << " " << GetStorageClassDesc(inst: referenced_from_inst);
1543 }
1544
1545 for (const spv::ExecutionModel execution_model : execution_models_) {
1546 if (execution_model != spv::ExecutionModel::Fragment) {
1547 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
1548 << _.VkErrorID(id: 4239)
1549 << "Vulkan spec allows BuiltIn HelperInvocation to be used only "
1550 "with Fragment execution model. "
1551 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
1552 referenced_from_inst, execution_model);
1553 }
1554 }
1555 }
1556
1557 if (function_id_ == 0) {
1558 // Propagate this rule to all dependant ids in the global scope.
1559 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
1560 x: std::bind(f: &BuiltInsValidator::ValidateHelperInvocationAtReference, bound_args: this,
1561 bound_args: decoration, bound_args: built_in_inst, bound_args: referenced_from_inst,
1562 bound_args: std::placeholders::_1));
1563 }
1564
1565 return SPV_SUCCESS;
1566}
1567
1568spv_result_t BuiltInsValidator::ValidateInvocationIdAtDefinition(
1569 const Decoration& decoration, const Instruction& inst) {
1570 if (spvIsVulkanEnv(env: _.context()->target_env)) {
1571 if (spv_result_t error = ValidateI32(
1572 decoration, inst,
1573 diag: [this, &inst](const std::string& message) -> spv_result_t {
1574 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &inst)
1575 << _.VkErrorID(id: 4259)
1576 << "According to the Vulkan spec BuiltIn InvocationId "
1577 "variable needs to be a 32-bit int scalar. "
1578 << message;
1579 })) {
1580 return error;
1581 }
1582 }
1583
1584 // Seed at reference checks with this built-in.
1585 return ValidateInvocationIdAtReference(decoration, built_in_inst: inst, referenced_inst: inst, referenced_from_inst: inst);
1586}
1587
1588spv_result_t BuiltInsValidator::ValidateInvocationIdAtReference(
1589 const Decoration& decoration, const Instruction& built_in_inst,
1590 const Instruction& referenced_inst,
1591 const Instruction& referenced_from_inst) {
1592 if (spvIsVulkanEnv(env: _.context()->target_env)) {
1593 const spv::StorageClass storage_class = GetStorageClass(inst: referenced_from_inst);
1594 if (storage_class != spv::StorageClass::Max &&
1595 storage_class != spv::StorageClass::Input) {
1596 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
1597 << _.VkErrorID(id: 4258)
1598 << "Vulkan spec allows BuiltIn InvocationId to be only used for "
1599 "variables with Input storage class. "
1600 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
1601 referenced_from_inst)
1602 << " " << GetStorageClassDesc(inst: referenced_from_inst);
1603 }
1604
1605 for (const spv::ExecutionModel execution_model : execution_models_) {
1606 if (execution_model != spv::ExecutionModel::TessellationControl &&
1607 execution_model != spv::ExecutionModel::Geometry) {
1608 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
1609 << _.VkErrorID(id: 4257)
1610 << "Vulkan spec allows BuiltIn InvocationId to be used only "
1611 "with TessellationControl or Geometry execution models. "
1612 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
1613 referenced_from_inst, execution_model);
1614 }
1615 }
1616 }
1617
1618 if (function_id_ == 0) {
1619 // Propagate this rule to all dependant ids in the global scope.
1620 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(x: std::bind(
1621 f: &BuiltInsValidator::ValidateInvocationIdAtReference, bound_args: this, bound_args: decoration,
1622 bound_args: built_in_inst, bound_args: referenced_from_inst, bound_args: std::placeholders::_1));
1623 }
1624
1625 return SPV_SUCCESS;
1626}
1627
1628spv_result_t BuiltInsValidator::ValidateInstanceIndexAtDefinition(
1629 const Decoration& decoration, const Instruction& inst) {
1630 if (spvIsVulkanEnv(env: _.context()->target_env)) {
1631 if (spv_result_t error = ValidateI32(
1632 decoration, inst,
1633 diag: [this, &inst](const std::string& message) -> spv_result_t {
1634 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &inst)
1635 << _.VkErrorID(id: 4265) << "According to the "
1636 << spvLogStringForEnv(env: _.context()->target_env)
1637 << " spec BuiltIn InstanceIndex "
1638 "variable needs to be a 32-bit int scalar. "
1639 << message;
1640 })) {
1641 return error;
1642 }
1643 }
1644
1645 // Seed at reference checks with this built-in.
1646 return ValidateInstanceIndexAtReference(decoration, built_in_inst: inst, referenced_inst: inst, referenced_from_inst: inst);
1647}
1648
1649spv_result_t BuiltInsValidator::ValidateInstanceIndexAtReference(
1650 const Decoration& decoration, const Instruction& built_in_inst,
1651 const Instruction& referenced_inst,
1652 const Instruction& referenced_from_inst) {
1653 if (spvIsVulkanEnv(env: _.context()->target_env)) {
1654 const spv::StorageClass storage_class = GetStorageClass(inst: referenced_from_inst);
1655 if (storage_class != spv::StorageClass::Max &&
1656 storage_class != spv::StorageClass::Input) {
1657 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
1658 << _.VkErrorID(id: 4264) << spvLogStringForEnv(env: _.context()->target_env)
1659 << " spec allows BuiltIn InstanceIndex to be only used for "
1660 "variables with Input storage class. "
1661 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
1662 referenced_from_inst)
1663 << " " << GetStorageClassDesc(inst: referenced_from_inst);
1664 }
1665
1666 for (const spv::ExecutionModel execution_model : execution_models_) {
1667 if (execution_model != spv::ExecutionModel::Vertex) {
1668 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
1669 << _.VkErrorID(id: 4263)
1670 << spvLogStringForEnv(env: _.context()->target_env)
1671 << " spec allows BuiltIn InstanceIndex to be used only "
1672 "with Vertex execution model. "
1673 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
1674 referenced_from_inst, execution_model);
1675 }
1676 }
1677 }
1678
1679 if (function_id_ == 0) {
1680 // Propagate this rule to all dependant ids in the global scope.
1681 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(x: std::bind(
1682 f: &BuiltInsValidator::ValidateInstanceIndexAtReference, bound_args: this, bound_args: decoration,
1683 bound_args: built_in_inst, bound_args: referenced_from_inst, bound_args: std::placeholders::_1));
1684 }
1685
1686 return SPV_SUCCESS;
1687}
1688
1689spv_result_t BuiltInsValidator::ValidatePatchVerticesAtDefinition(
1690 const Decoration& decoration, const Instruction& inst) {
1691 if (spvIsVulkanEnv(env: _.context()->target_env)) {
1692 if (spv_result_t error = ValidateI32(
1693 decoration, inst,
1694 diag: [this, &inst](const std::string& message) -> spv_result_t {
1695 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &inst)
1696 << _.VkErrorID(id: 4310)
1697 << "According to the Vulkan spec BuiltIn PatchVertices "
1698 "variable needs to be a 32-bit int scalar. "
1699 << message;
1700 })) {
1701 return error;
1702 }
1703 }
1704
1705 // Seed at reference checks with this built-in.
1706 return ValidatePatchVerticesAtReference(decoration, built_in_inst: inst, referenced_inst: inst, referenced_from_inst: inst);
1707}
1708
1709spv_result_t BuiltInsValidator::ValidatePatchVerticesAtReference(
1710 const Decoration& decoration, const Instruction& built_in_inst,
1711 const Instruction& referenced_inst,
1712 const Instruction& referenced_from_inst) {
1713 if (spvIsVulkanEnv(env: _.context()->target_env)) {
1714 const spv::StorageClass storage_class = GetStorageClass(inst: referenced_from_inst);
1715 if (storage_class != spv::StorageClass::Max &&
1716 storage_class != spv::StorageClass::Input) {
1717 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
1718 << _.VkErrorID(id: 4309)
1719 << "Vulkan spec allows BuiltIn PatchVertices to be only used for "
1720 "variables with Input storage class. "
1721 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
1722 referenced_from_inst)
1723 << " " << GetStorageClassDesc(inst: referenced_from_inst);
1724 }
1725
1726 for (const spv::ExecutionModel execution_model : execution_models_) {
1727 if (execution_model != spv::ExecutionModel::TessellationControl &&
1728 execution_model != spv::ExecutionModel::TessellationEvaluation) {
1729 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
1730 << _.VkErrorID(id: 4308)
1731 << "Vulkan spec allows BuiltIn PatchVertices to be used only "
1732 "with TessellationControl or TessellationEvaluation "
1733 "execution models. "
1734 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
1735 referenced_from_inst, execution_model);
1736 }
1737 }
1738 }
1739
1740 if (function_id_ == 0) {
1741 // Propagate this rule to all dependant ids in the global scope.
1742 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(x: std::bind(
1743 f: &BuiltInsValidator::ValidatePatchVerticesAtReference, bound_args: this, bound_args: decoration,
1744 bound_args: built_in_inst, bound_args: referenced_from_inst, bound_args: std::placeholders::_1));
1745 }
1746
1747 return SPV_SUCCESS;
1748}
1749
1750spv_result_t BuiltInsValidator::ValidatePointCoordAtDefinition(
1751 const Decoration& decoration, const Instruction& inst) {
1752 if (spvIsVulkanEnv(env: _.context()->target_env)) {
1753 if (spv_result_t error = ValidateF32Vec(
1754 decoration, inst, num_components: 2,
1755 diag: [this, &inst](const std::string& message) -> spv_result_t {
1756 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &inst)
1757 << _.VkErrorID(id: 4313)
1758 << "According to the Vulkan spec BuiltIn PointCoord "
1759 "variable needs to be a 2-component 32-bit float "
1760 "vector. "
1761 << message;
1762 })) {
1763 return error;
1764 }
1765 }
1766
1767 // Seed at reference checks with this built-in.
1768 return ValidatePointCoordAtReference(decoration, built_in_inst: inst, referenced_inst: inst, referenced_from_inst: inst);
1769}
1770
1771spv_result_t BuiltInsValidator::ValidatePointCoordAtReference(
1772 const Decoration& decoration, const Instruction& built_in_inst,
1773 const Instruction& referenced_inst,
1774 const Instruction& referenced_from_inst) {
1775 if (spvIsVulkanEnv(env: _.context()->target_env)) {
1776 const spv::StorageClass storage_class = GetStorageClass(inst: referenced_from_inst);
1777 if (storage_class != spv::StorageClass::Max &&
1778 storage_class != spv::StorageClass::Input) {
1779 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
1780 << _.VkErrorID(id: 4312)
1781 << "Vulkan spec allows BuiltIn PointCoord to be only used for "
1782 "variables with Input storage class. "
1783 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
1784 referenced_from_inst)
1785 << " " << GetStorageClassDesc(inst: referenced_from_inst);
1786 }
1787
1788 for (const spv::ExecutionModel execution_model : execution_models_) {
1789 if (execution_model != spv::ExecutionModel::Fragment) {
1790 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
1791 << _.VkErrorID(id: 4311)
1792 << "Vulkan spec allows BuiltIn PointCoord to be used only with "
1793 "Fragment execution model. "
1794 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
1795 referenced_from_inst, execution_model);
1796 }
1797 }
1798 }
1799
1800 if (function_id_ == 0) {
1801 // Propagate this rule to all dependant ids in the global scope.
1802 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(x: std::bind(
1803 f: &BuiltInsValidator::ValidatePointCoordAtReference, bound_args: this, bound_args: decoration,
1804 bound_args: built_in_inst, bound_args: referenced_from_inst, bound_args: std::placeholders::_1));
1805 }
1806
1807 return SPV_SUCCESS;
1808}
1809
1810spv_result_t BuiltInsValidator::ValidatePointSizeAtDefinition(
1811 const Decoration& decoration, const Instruction& inst) {
1812 // Seed at reference checks with this built-in.
1813 return ValidatePointSizeAtReference(decoration, built_in_inst: inst, referenced_inst: inst, referenced_from_inst: inst);
1814}
1815
1816spv_result_t BuiltInsValidator::ValidatePointSizeAtReference(
1817 const Decoration& decoration, const Instruction& built_in_inst,
1818 const Instruction& referenced_inst,
1819 const Instruction& referenced_from_inst) {
1820 if (spvIsVulkanEnv(env: _.context()->target_env)) {
1821 const spv::StorageClass storage_class = GetStorageClass(inst: referenced_from_inst);
1822 if (storage_class != spv::StorageClass::Max &&
1823 storage_class != spv::StorageClass::Input &&
1824 storage_class != spv::StorageClass::Output) {
1825 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
1826 << _.VkErrorID(id: 4316)
1827 << "Vulkan spec allows BuiltIn PointSize to be only used for "
1828 "variables with Input or Output storage class. "
1829 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
1830 referenced_from_inst)
1831 << " " << GetStorageClassDesc(inst: referenced_from_inst);
1832 }
1833
1834 if (storage_class == spv::StorageClass::Input) {
1835 assert(function_id_ == 0);
1836 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(x: std::bind(
1837 f: &BuiltInsValidator::ValidateNotCalledWithExecutionModel, bound_args: this, bound_args: 4315,
1838 bound_args: "Vulkan spec doesn't allow BuiltIn PointSize to be used for "
1839 "variables with Input storage class if execution model is "
1840 "Vertex.",
1841 bound_args: spv::ExecutionModel::Vertex, bound_args: decoration, bound_args: built_in_inst,
1842 bound_args: referenced_from_inst, bound_args: std::placeholders::_1));
1843 }
1844
1845 for (const spv::ExecutionModel execution_model : execution_models_) {
1846 switch (execution_model) {
1847 case spv::ExecutionModel::Vertex: {
1848 if (spv_result_t error = ValidateF32(
1849 decoration, inst: built_in_inst,
1850 diag: [this, &referenced_from_inst](
1851 const std::string& message) -> spv_result_t {
1852 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
1853 << _.VkErrorID(id: 4317)
1854 << "According to the Vulkan spec BuiltIn PointSize "
1855 "variable needs to be a 32-bit float scalar. "
1856 << message;
1857 })) {
1858 return error;
1859 }
1860 break;
1861 }
1862 case spv::ExecutionModel::TessellationControl:
1863 case spv::ExecutionModel::TessellationEvaluation:
1864 case spv::ExecutionModel::Geometry:
1865 case spv::ExecutionModel::MeshNV:
1866 case spv::ExecutionModel::MeshEXT: {
1867 // PointSize can be a per-vertex variable for tessellation control,
1868 // tessellation evaluation and geometry shader stages. In such cases
1869 // variables will have an array of 32-bit floats.
1870 if (decoration.struct_member_index() != Decoration::kInvalidMember) {
1871 // The array is on the variable, so this must be a 32-bit float.
1872 if (spv_result_t error = ValidateF32(
1873 decoration, inst: built_in_inst,
1874 diag: [this, &referenced_from_inst](
1875 const std::string& message) -> spv_result_t {
1876 return _.diag(error_code: SPV_ERROR_INVALID_DATA,
1877 inst: &referenced_from_inst)
1878 << _.VkErrorID(id: 4317)
1879 << "According to the Vulkan spec BuiltIn "
1880 "PointSize variable needs to be a 32-bit "
1881 "float scalar. "
1882 << message;
1883 })) {
1884 return error;
1885 }
1886 } else {
1887 if (spv_result_t error = ValidateOptionalArrayedF32(
1888 decoration, inst: built_in_inst,
1889 diag: [this, &referenced_from_inst](
1890 const std::string& message) -> spv_result_t {
1891 return _.diag(error_code: SPV_ERROR_INVALID_DATA,
1892 inst: &referenced_from_inst)
1893 << _.VkErrorID(id: 4317)
1894 << "According to the Vulkan spec BuiltIn "
1895 "PointSize variable needs to be a 32-bit "
1896 "float scalar. "
1897 << message;
1898 })) {
1899 return error;
1900 }
1901 }
1902 break;
1903 }
1904
1905 default: {
1906 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
1907 << _.VkErrorID(id: 4314)
1908 << "Vulkan spec allows BuiltIn PointSize to be used only with "
1909 "Vertex, TessellationControl, TessellationEvaluation or "
1910 "Geometry execution models. "
1911 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
1912 referenced_from_inst, execution_model);
1913 }
1914 }
1915 }
1916 }
1917
1918 if (function_id_ == 0) {
1919 // Propagate this rule to all dependant ids in the global scope.
1920 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(x: std::bind(
1921 f: &BuiltInsValidator::ValidatePointSizeAtReference, bound_args: this, bound_args: decoration,
1922 bound_args: built_in_inst, bound_args: referenced_from_inst, bound_args: std::placeholders::_1));
1923 }
1924
1925 return SPV_SUCCESS;
1926}
1927
1928spv_result_t BuiltInsValidator::ValidatePositionAtDefinition(
1929 const Decoration& decoration, const Instruction& inst) {
1930 // Seed at reference checks with this built-in.
1931 return ValidatePositionAtReference(decoration, built_in_inst: inst, referenced_inst: inst, referenced_from_inst: inst);
1932}
1933
1934spv_result_t BuiltInsValidator::ValidatePositionAtReference(
1935 const Decoration& decoration, const Instruction& built_in_inst,
1936 const Instruction& referenced_inst,
1937 const Instruction& referenced_from_inst) {
1938 if (spvIsVulkanEnv(env: _.context()->target_env)) {
1939 const spv::StorageClass storage_class = GetStorageClass(inst: referenced_from_inst);
1940 if (storage_class != spv::StorageClass::Max &&
1941 storage_class != spv::StorageClass::Input &&
1942 storage_class != spv::StorageClass::Output) {
1943 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
1944 << _.VkErrorID(id: 4320) << "Vulkan spec allows BuiltIn Position to be only used for "
1945 "variables with Input or Output storage class. "
1946 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
1947 referenced_from_inst)
1948 << " " << GetStorageClassDesc(inst: referenced_from_inst);
1949 }
1950
1951 if (storage_class == spv::StorageClass::Input) {
1952 assert(function_id_ == 0);
1953 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(x: std::bind(
1954 f: &BuiltInsValidator::ValidateNotCalledWithExecutionModel, bound_args: this, bound_args: 4319,
1955 bound_args: "Vulkan spec doesn't allow BuiltIn Position to be used "
1956 "for variables "
1957 "with Input storage class if execution model is Vertex.",
1958 bound_args: spv::ExecutionModel::Vertex, bound_args: decoration, bound_args: built_in_inst,
1959 bound_args: referenced_from_inst, bound_args: std::placeholders::_1));
1960 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(x: std::bind(
1961 f: &BuiltInsValidator::ValidateNotCalledWithExecutionModel, bound_args: this, bound_args: 4319,
1962 bound_args: "Vulkan spec doesn't allow BuiltIn Position to be used "
1963 "for variables "
1964 "with Input storage class if execution model is MeshNV.",
1965 bound_args: spv::ExecutionModel::MeshNV, bound_args: decoration, bound_args: built_in_inst,
1966 bound_args: referenced_from_inst, bound_args: std::placeholders::_1));
1967 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(x: std::bind(
1968 f: &BuiltInsValidator::ValidateNotCalledWithExecutionModel, bound_args: this, bound_args: 4319,
1969 bound_args: "Vulkan spec doesn't allow BuiltIn Position to be used "
1970 "for variables "
1971 "with Input storage class if execution model is MeshEXT.",
1972 bound_args: spv::ExecutionModel::MeshEXT, bound_args: decoration, bound_args: built_in_inst,
1973 bound_args: referenced_from_inst, bound_args: std::placeholders::_1));
1974 }
1975
1976 for (const spv::ExecutionModel execution_model : execution_models_) {
1977 switch (execution_model) {
1978 case spv::ExecutionModel::Vertex: {
1979 if (spv_result_t error = ValidateF32Vec(
1980 decoration, inst: built_in_inst, num_components: 4,
1981 diag: [this, &referenced_from_inst](
1982 const std::string& message) -> spv_result_t {
1983 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
1984 << _.VkErrorID(id: 4321)
1985 << "According to the Vulkan spec BuiltIn Position "
1986 "variable needs to be a 4-component 32-bit float "
1987 "vector. "
1988 << message;
1989 })) {
1990 return error;
1991 }
1992 break;
1993 }
1994 case spv::ExecutionModel::Geometry:
1995 case spv::ExecutionModel::TessellationControl:
1996 case spv::ExecutionModel::TessellationEvaluation:
1997 case spv::ExecutionModel::MeshNV:
1998 case spv::ExecutionModel::MeshEXT: {
1999 // Position can be a per-vertex variable for tessellation control,
2000 // tessellation evaluation, geometry and mesh shader stages. In such
2001 // cases variables will have an array of 4-component 32-bit float
2002 // vectors.
2003 if (decoration.struct_member_index() != Decoration::kInvalidMember) {
2004 // The array is on the variable, so this must be a 4-component
2005 // 32-bit float vector.
2006 if (spv_result_t error = ValidateF32Vec(
2007 decoration, inst: built_in_inst, num_components: 4,
2008 diag: [this, &referenced_from_inst](
2009 const std::string& message) -> spv_result_t {
2010 return _.diag(error_code: SPV_ERROR_INVALID_DATA,
2011 inst: &referenced_from_inst)
2012 << _.VkErrorID(id: 4321)
2013 << "According to the Vulkan spec BuiltIn Position "
2014 "variable needs to be a 4-component 32-bit "
2015 "float vector. "
2016 << message;
2017 })) {
2018 return error;
2019 }
2020 } else {
2021 if (spv_result_t error = ValidateOptionalArrayedF32Vec(
2022 decoration, inst: built_in_inst, num_components: 4,
2023 diag: [this, &referenced_from_inst](
2024 const std::string& message) -> spv_result_t {
2025 return _.diag(error_code: SPV_ERROR_INVALID_DATA,
2026 inst: &referenced_from_inst)
2027 << _.VkErrorID(id: 4321)
2028 << "According to the Vulkan spec BuiltIn Position "
2029 "variable needs to be a 4-component 32-bit "
2030 "float vector. "
2031 << message;
2032 })) {
2033 return error;
2034 }
2035 }
2036 break;
2037 }
2038
2039 default: {
2040 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
2041 << _.VkErrorID(id: 4318)
2042 << "Vulkan spec allows BuiltIn Position to be used only "
2043 "with Vertex, TessellationControl, TessellationEvaluation"
2044 " or Geometry execution models. "
2045 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
2046 referenced_from_inst, execution_model);
2047 }
2048 }
2049 }
2050 }
2051
2052 if (function_id_ == 0) {
2053 // Propagate this rule to all dependant ids in the global scope.
2054 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(x: std::bind(
2055 f: &BuiltInsValidator::ValidatePositionAtReference, bound_args: this, bound_args: decoration,
2056 bound_args: built_in_inst, bound_args: referenced_from_inst, bound_args: std::placeholders::_1));
2057 }
2058
2059 return SPV_SUCCESS;
2060}
2061
2062spv_result_t BuiltInsValidator::ValidatePrimitiveIdAtDefinition(
2063 const Decoration& decoration, const Instruction& inst) {
2064 if (spvIsVulkanEnv(env: _.context()->target_env)) {
2065 // PrimitiveId can be a per-primitive variable for mesh shader stage.
2066 // In such cases variable will have an array of 32-bit integers.
2067 if (decoration.struct_member_index() != Decoration::kInvalidMember) {
2068 // This must be a 32-bit int scalar.
2069 if (spv_result_t error = ValidateI32(
2070 decoration, inst,
2071 diag: [this, &inst](const std::string& message) -> spv_result_t {
2072 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &inst)
2073 << _.VkErrorID(id: 4337)
2074 << "According to the Vulkan spec BuiltIn PrimitiveId "
2075 "variable needs to be a 32-bit int scalar. "
2076 << message;
2077 })) {
2078 return error;
2079 }
2080 } else {
2081 if (spv_result_t error = ValidateOptionalArrayedI32(
2082 decoration, inst,
2083 diag: [this, &inst](const std::string& message) -> spv_result_t {
2084 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &inst)
2085 << _.VkErrorID(id: 4337)
2086 << "According to the Vulkan spec BuiltIn PrimitiveId "
2087 "variable needs to be a 32-bit int scalar. "
2088 << message;
2089 })) {
2090 return error;
2091 }
2092 }
2093 }
2094
2095 // Seed at reference checks with this built-in.
2096 return ValidatePrimitiveIdAtReference(decoration, built_in_inst: inst, referenced_inst: inst, referenced_from_inst: inst);
2097}
2098
2099spv_result_t BuiltInsValidator::ValidatePrimitiveIdAtReference(
2100 const Decoration& decoration, const Instruction& built_in_inst,
2101 const Instruction& referenced_inst,
2102 const Instruction& referenced_from_inst) {
2103 if (spvIsVulkanEnv(env: _.context()->target_env)) {
2104 const spv::StorageClass storage_class = GetStorageClass(inst: referenced_from_inst);
2105 if (storage_class != spv::StorageClass::Max &&
2106 storage_class != spv::StorageClass::Input &&
2107 storage_class != spv::StorageClass::Output) {
2108 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
2109 << "Vulkan spec allows BuiltIn PrimitiveId to be only used for "
2110 "variables with Input or Output storage class. "
2111 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
2112 referenced_from_inst)
2113 << " " << GetStorageClassDesc(inst: referenced_from_inst);
2114 }
2115
2116 if (storage_class == spv::StorageClass::Output) {
2117 assert(function_id_ == 0);
2118 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(x: std::bind(
2119 f: &BuiltInsValidator::ValidateNotCalledWithExecutionModel, bound_args: this, bound_args: 4334,
2120 bound_args: "Vulkan spec doesn't allow BuiltIn PrimitiveId to be used for "
2121 "variables with Output storage class if execution model is "
2122 "TessellationControl.",
2123 bound_args: spv::ExecutionModel::TessellationControl, bound_args: decoration, bound_args: built_in_inst,
2124 bound_args: referenced_from_inst, bound_args: std::placeholders::_1));
2125 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(x: std::bind(
2126 f: &BuiltInsValidator::ValidateNotCalledWithExecutionModel, bound_args: this, bound_args: 4334,
2127 bound_args: "Vulkan spec doesn't allow BuiltIn PrimitiveId to be used for "
2128 "variables with Output storage class if execution model is "
2129 "TessellationEvaluation.",
2130 bound_args: spv::ExecutionModel::TessellationEvaluation, bound_args: decoration, bound_args: built_in_inst,
2131 bound_args: referenced_from_inst, bound_args: std::placeholders::_1));
2132 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(x: std::bind(
2133 f: &BuiltInsValidator::ValidateNotCalledWithExecutionModel, bound_args: this, bound_args: 4334,
2134 bound_args: "Vulkan spec doesn't allow BuiltIn PrimitiveId to be used for "
2135 "variables with Output storage class if execution model is "
2136 "Fragment.",
2137 bound_args: spv::ExecutionModel::Fragment, bound_args: decoration, bound_args: built_in_inst,
2138 bound_args: referenced_from_inst, bound_args: std::placeholders::_1));
2139 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(x: std::bind(
2140 f: &BuiltInsValidator::ValidateNotCalledWithExecutionModel, bound_args: this, bound_args: 4334,
2141 bound_args: "Vulkan spec doesn't allow BuiltIn PrimitiveId to be used for "
2142 "variables with Output storage class if execution model is "
2143 "IntersectionKHR.",
2144 bound_args: spv::ExecutionModel::IntersectionKHR, bound_args: decoration, bound_args: built_in_inst,
2145 bound_args: referenced_from_inst, bound_args: std::placeholders::_1));
2146 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(x: std::bind(
2147 f: &BuiltInsValidator::ValidateNotCalledWithExecutionModel, bound_args: this, bound_args: 4334,
2148 bound_args: "Vulkan spec doesn't allow BuiltIn PrimitiveId to be used for "
2149 "variables with Output storage class if execution model is "
2150 "AnyHitKHR.",
2151 bound_args: spv::ExecutionModel::AnyHitKHR, bound_args: decoration, bound_args: built_in_inst,
2152 bound_args: referenced_from_inst, bound_args: std::placeholders::_1));
2153 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(x: std::bind(
2154 f: &BuiltInsValidator::ValidateNotCalledWithExecutionModel, bound_args: this, bound_args: 4334,
2155 bound_args: "Vulkan spec doesn't allow BuiltIn PrimitiveId to be used for "
2156 "variables with Output storage class if execution model is "
2157 "ClosestHitKHR.",
2158 bound_args: spv::ExecutionModel::ClosestHitKHR, bound_args: decoration, bound_args: built_in_inst,
2159 bound_args: referenced_from_inst, bound_args: std::placeholders::_1));
2160 }
2161
2162 for (const spv::ExecutionModel execution_model : execution_models_) {
2163 switch (execution_model) {
2164 case spv::ExecutionModel::Fragment:
2165 case spv::ExecutionModel::TessellationControl:
2166 case spv::ExecutionModel::TessellationEvaluation:
2167 case spv::ExecutionModel::Geometry:
2168 case spv::ExecutionModel::MeshNV:
2169 case spv::ExecutionModel::MeshEXT:
2170 case spv::ExecutionModel::IntersectionKHR:
2171 case spv::ExecutionModel::AnyHitKHR:
2172 case spv::ExecutionModel::ClosestHitKHR: {
2173 // Ok.
2174 break;
2175 }
2176
2177 default: {
2178 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
2179 << _.VkErrorID(id: 4330)
2180 << "Vulkan spec allows BuiltIn PrimitiveId to be used only "
2181 "with Fragment, TessellationControl, "
2182 "TessellationEvaluation, Geometry, MeshNV, MeshEXT, "
2183 "IntersectionKHR, AnyHitKHR, and ClosestHitKHR execution models. "
2184 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
2185 referenced_from_inst, execution_model);
2186 }
2187 }
2188 }
2189 }
2190
2191 if (function_id_ == 0) {
2192 // Propagate this rule to all dependant ids in the global scope.
2193 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(x: std::bind(
2194 f: &BuiltInsValidator::ValidatePrimitiveIdAtReference, bound_args: this, bound_args: decoration,
2195 bound_args: built_in_inst, bound_args: referenced_from_inst, bound_args: std::placeholders::_1));
2196 }
2197
2198 return SPV_SUCCESS;
2199}
2200
2201spv_result_t BuiltInsValidator::ValidateSampleIdAtDefinition(
2202 const Decoration& decoration, const Instruction& inst) {
2203 if (spvIsVulkanEnv(env: _.context()->target_env)) {
2204 if (spv_result_t error = ValidateI32(
2205 decoration, inst,
2206 diag: [this, &inst](const std::string& message) -> spv_result_t {
2207 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &inst)
2208 << _.VkErrorID(id: 4356)
2209 << "According to the Vulkan spec BuiltIn SampleId "
2210 "variable needs to be a 32-bit int scalar. "
2211 << message;
2212 })) {
2213 return error;
2214 }
2215 }
2216
2217 // Seed at reference checks with this built-in.
2218 return ValidateSampleIdAtReference(decoration, built_in_inst: inst, referenced_inst: inst, referenced_from_inst: inst);
2219}
2220
2221spv_result_t BuiltInsValidator::ValidateSampleIdAtReference(
2222 const Decoration& decoration, const Instruction& built_in_inst,
2223 const Instruction& referenced_inst,
2224 const Instruction& referenced_from_inst) {
2225 if (spvIsVulkanEnv(env: _.context()->target_env)) {
2226 const spv::StorageClass storage_class = GetStorageClass(inst: referenced_from_inst);
2227 if (storage_class != spv::StorageClass::Max &&
2228 storage_class != spv::StorageClass::Input) {
2229 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
2230 << _.VkErrorID(id: 4355)
2231 << "Vulkan spec allows BuiltIn SampleId to be only used for "
2232 "variables with Input storage class. "
2233 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
2234 referenced_from_inst)
2235 << " " << GetStorageClassDesc(inst: referenced_from_inst);
2236 }
2237
2238 for (const spv::ExecutionModel execution_model : execution_models_) {
2239 if (execution_model != spv::ExecutionModel::Fragment) {
2240 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
2241 << _.VkErrorID(id: 4354)
2242 << "Vulkan spec allows BuiltIn SampleId to be used only with "
2243 "Fragment execution model. "
2244 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
2245 referenced_from_inst, execution_model);
2246 }
2247 }
2248 }
2249
2250 if (function_id_ == 0) {
2251 // Propagate this rule to all dependant ids in the global scope.
2252 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(x: std::bind(
2253 f: &BuiltInsValidator::ValidateSampleIdAtReference, bound_args: this, bound_args: decoration,
2254 bound_args: built_in_inst, bound_args: referenced_from_inst, bound_args: std::placeholders::_1));
2255 }
2256
2257 return SPV_SUCCESS;
2258}
2259
2260spv_result_t BuiltInsValidator::ValidateSampleMaskAtDefinition(
2261 const Decoration& decoration, const Instruction& inst) {
2262 if (spvIsVulkanEnv(env: _.context()->target_env)) {
2263 if (spv_result_t error = ValidateI32Arr(
2264 decoration, inst,
2265 diag: [this, &inst](const std::string& message) -> spv_result_t {
2266 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &inst)
2267 << _.VkErrorID(id: 4359)
2268 << "According to the Vulkan spec BuiltIn SampleMask "
2269 "variable needs to be a 32-bit int array. "
2270 << message;
2271 })) {
2272 return error;
2273 }
2274 }
2275
2276 // Seed at reference checks with this built-in.
2277 return ValidateSampleMaskAtReference(decoration, built_in_inst: inst, referenced_inst: inst, referenced_from_inst: inst);
2278}
2279
2280spv_result_t BuiltInsValidator::ValidateSampleMaskAtReference(
2281 const Decoration& decoration, const Instruction& built_in_inst,
2282 const Instruction& referenced_inst,
2283 const Instruction& referenced_from_inst) {
2284 if (spvIsVulkanEnv(env: _.context()->target_env)) {
2285 const spv::StorageClass storage_class = GetStorageClass(inst: referenced_from_inst);
2286 if (storage_class != spv::StorageClass::Max &&
2287 storage_class != spv::StorageClass::Input &&
2288 storage_class != spv::StorageClass::Output) {
2289 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
2290 << _.VkErrorID(id: 4358)
2291 << "Vulkan spec allows BuiltIn SampleMask to be only used for "
2292 "variables with Input or Output storage class. "
2293 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
2294 referenced_from_inst)
2295 << " " << GetStorageClassDesc(inst: referenced_from_inst);
2296 }
2297
2298 for (const spv::ExecutionModel execution_model : execution_models_) {
2299 if (execution_model != spv::ExecutionModel::Fragment) {
2300 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
2301 << _.VkErrorID(id: 4357)
2302 << "Vulkan spec allows BuiltIn SampleMask to be used only "
2303 "with "
2304 "Fragment execution model. "
2305 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
2306 referenced_from_inst, execution_model);
2307 }
2308 }
2309 }
2310
2311 if (function_id_ == 0) {
2312 // Propagate this rule to all dependant ids in the global scope.
2313 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(x: std::bind(
2314 f: &BuiltInsValidator::ValidateSampleMaskAtReference, bound_args: this, bound_args: decoration,
2315 bound_args: built_in_inst, bound_args: referenced_from_inst, bound_args: std::placeholders::_1));
2316 }
2317
2318 return SPV_SUCCESS;
2319}
2320
2321spv_result_t BuiltInsValidator::ValidateSamplePositionAtDefinition(
2322 const Decoration& decoration, const Instruction& inst) {
2323 if (spvIsVulkanEnv(env: _.context()->target_env)) {
2324 if (spv_result_t error = ValidateF32Vec(
2325 decoration, inst, num_components: 2,
2326 diag: [this, &inst](const std::string& message) -> spv_result_t {
2327 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &inst)
2328 << _.VkErrorID(id: 4362)
2329 << "According to the Vulkan spec BuiltIn SamplePosition "
2330 "variable needs to be a 2-component 32-bit float "
2331 "vector. "
2332 << message;
2333 })) {
2334 return error;
2335 }
2336 }
2337
2338 // Seed at reference checks with this built-in.
2339 return ValidateSamplePositionAtReference(decoration, built_in_inst: inst, referenced_inst: inst, referenced_from_inst: inst);
2340}
2341
2342spv_result_t BuiltInsValidator::ValidateSamplePositionAtReference(
2343 const Decoration& decoration, const Instruction& built_in_inst,
2344 const Instruction& referenced_inst,
2345 const Instruction& referenced_from_inst) {
2346 if (spvIsVulkanEnv(env: _.context()->target_env)) {
2347 const spv::StorageClass storage_class = GetStorageClass(inst: referenced_from_inst);
2348 if (storage_class != spv::StorageClass::Max &&
2349 storage_class != spv::StorageClass::Input) {
2350 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
2351 << _.VkErrorID(id: 4361)
2352 << "Vulkan spec allows BuiltIn SamplePosition to be only used "
2353 "for "
2354 "variables with Input storage class. "
2355 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
2356 referenced_from_inst)
2357 << " " << GetStorageClassDesc(inst: referenced_from_inst);
2358 }
2359
2360 for (const spv::ExecutionModel execution_model : execution_models_) {
2361 if (execution_model != spv::ExecutionModel::Fragment) {
2362 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
2363 << _.VkErrorID(id: 4360)
2364 << "Vulkan spec allows BuiltIn SamplePosition to be used only "
2365 "with "
2366 "Fragment execution model. "
2367 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
2368 referenced_from_inst, execution_model);
2369 }
2370 }
2371 }
2372
2373 if (function_id_ == 0) {
2374 // Propagate this rule to all dependant ids in the global scope.
2375 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(x: std::bind(
2376 f: &BuiltInsValidator::ValidateSamplePositionAtReference, bound_args: this, bound_args: decoration,
2377 bound_args: built_in_inst, bound_args: referenced_from_inst, bound_args: std::placeholders::_1));
2378 }
2379
2380 return SPV_SUCCESS;
2381}
2382
2383spv_result_t BuiltInsValidator::ValidateTessCoordAtDefinition(
2384 const Decoration& decoration, const Instruction& inst) {
2385 if (spvIsVulkanEnv(env: _.context()->target_env)) {
2386 if (spv_result_t error = ValidateF32Vec(
2387 decoration, inst, num_components: 3,
2388 diag: [this, &inst](const std::string& message) -> spv_result_t {
2389 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &inst)
2390 << _.VkErrorID(id: 4389)
2391 << "According to the Vulkan spec BuiltIn TessCoord "
2392 "variable needs to be a 3-component 32-bit float "
2393 "vector. "
2394 << message;
2395 })) {
2396 return error;
2397 }
2398 }
2399
2400 // Seed at reference checks with this built-in.
2401 return ValidateTessCoordAtReference(decoration, built_in_inst: inst, referenced_inst: inst, referenced_from_inst: inst);
2402}
2403
2404spv_result_t BuiltInsValidator::ValidateTessCoordAtReference(
2405 const Decoration& decoration, const Instruction& built_in_inst,
2406 const Instruction& referenced_inst,
2407 const Instruction& referenced_from_inst) {
2408 if (spvIsVulkanEnv(env: _.context()->target_env)) {
2409 const spv::StorageClass storage_class = GetStorageClass(inst: referenced_from_inst);
2410 if (storage_class != spv::StorageClass::Max &&
2411 storage_class != spv::StorageClass::Input) {
2412 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
2413 << _.VkErrorID(id: 4388)
2414 << "Vulkan spec allows BuiltIn TessCoord to be only used for "
2415 "variables with Input storage class. "
2416 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
2417 referenced_from_inst)
2418 << " " << GetStorageClassDesc(inst: referenced_from_inst);
2419 }
2420
2421 for (const spv::ExecutionModel execution_model : execution_models_) {
2422 if (execution_model != spv::ExecutionModel::TessellationEvaluation) {
2423 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
2424 << _.VkErrorID(id: 4387)
2425 << "Vulkan spec allows BuiltIn TessCoord to be used only with "
2426 "TessellationEvaluation execution model. "
2427 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
2428 referenced_from_inst, execution_model);
2429 }
2430 }
2431 }
2432
2433 if (function_id_ == 0) {
2434 // Propagate this rule to all dependant ids in the global scope.
2435 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(x: std::bind(
2436 f: &BuiltInsValidator::ValidateTessCoordAtReference, bound_args: this, bound_args: decoration,
2437 bound_args: built_in_inst, bound_args: referenced_from_inst, bound_args: std::placeholders::_1));
2438 }
2439
2440 return SPV_SUCCESS;
2441}
2442
2443spv_result_t BuiltInsValidator::ValidateTessLevelOuterAtDefinition(
2444 const Decoration& decoration, const Instruction& inst) {
2445 if (spvIsVulkanEnv(env: _.context()->target_env)) {
2446 if (spv_result_t error = ValidateF32Arr(
2447 decoration, inst, num_components: 4,
2448 diag: [this, &inst](const std::string& message) -> spv_result_t {
2449 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &inst)
2450 << _.VkErrorID(id: 4393)
2451 << "According to the Vulkan spec BuiltIn TessLevelOuter "
2452 "variable needs to be a 4-component 32-bit float "
2453 "array. "
2454 << message;
2455 })) {
2456 return error;
2457 }
2458 }
2459
2460 // Seed at reference checks with this built-in.
2461 return ValidateTessLevelAtReference(decoration, built_in_inst: inst, referenced_inst: inst, referenced_from_inst: inst);
2462}
2463
2464spv_result_t BuiltInsValidator::ValidateTessLevelInnerAtDefinition(
2465 const Decoration& decoration, const Instruction& inst) {
2466 if (spvIsVulkanEnv(env: _.context()->target_env)) {
2467 if (spv_result_t error = ValidateF32Arr(
2468 decoration, inst, num_components: 2,
2469 diag: [this, &inst](const std::string& message) -> spv_result_t {
2470 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &inst)
2471 << _.VkErrorID(id: 4397)
2472 << "According to the Vulkan spec BuiltIn TessLevelOuter "
2473 "variable needs to be a 2-component 32-bit float "
2474 "array. "
2475 << message;
2476 })) {
2477 return error;
2478 }
2479 }
2480
2481 // Seed at reference checks with this built-in.
2482 return ValidateTessLevelAtReference(decoration, built_in_inst: inst, referenced_inst: inst, referenced_from_inst: inst);
2483}
2484
2485spv_result_t BuiltInsValidator::ValidateTessLevelAtReference(
2486 const Decoration& decoration, const Instruction& built_in_inst,
2487 const Instruction& referenced_inst,
2488 const Instruction& referenced_from_inst) {
2489 uint32_t operand = decoration.params()[0];
2490 if (spvIsVulkanEnv(env: _.context()->target_env)) {
2491 const spv::StorageClass storage_class = GetStorageClass(inst: referenced_from_inst);
2492 if (storage_class != spv::StorageClass::Max &&
2493 storage_class != spv::StorageClass::Input &&
2494 storage_class != spv::StorageClass::Output) {
2495 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
2496 << "Vulkan spec allows BuiltIn "
2497 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN,
2498 operand)
2499 << " to be only used for variables with Input or Output storage "
2500 "class. "
2501 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
2502 referenced_from_inst)
2503 << " " << GetStorageClassDesc(inst: referenced_from_inst);
2504 }
2505
2506 if (storage_class == spv::StorageClass::Input) {
2507 assert(function_id_ == 0);
2508 uint32_t vuid = (spv::BuiltIn(decoration.params()[0]) == spv::BuiltIn::TessLevelOuter) ? 4391 : 4395;
2509 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(x: std::bind(
2510 f: &BuiltInsValidator::ValidateNotCalledWithExecutionModel, bound_args: this, bound_args&: vuid,
2511 bound_args: "Vulkan spec doesn't allow TessLevelOuter/TessLevelInner to be "
2512 "used "
2513 "for variables with Input storage class if execution model is "
2514 "TessellationControl.",
2515 bound_args: spv::ExecutionModel::TessellationControl, bound_args: decoration, bound_args: built_in_inst,
2516 bound_args: referenced_from_inst, bound_args: std::placeholders::_1));
2517 }
2518
2519 if (storage_class == spv::StorageClass::Output) {
2520 assert(function_id_ == 0);
2521 uint32_t vuid = (spv::BuiltIn(decoration.params()[0]) == spv::BuiltIn::TessLevelOuter) ? 4392 : 4396;
2522 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(x: std::bind(
2523 f: &BuiltInsValidator::ValidateNotCalledWithExecutionModel, bound_args: this, bound_args&: vuid,
2524 bound_args: "Vulkan spec doesn't allow TessLevelOuter/TessLevelInner to be "
2525 "used "
2526 "for variables with Output storage class if execution model is "
2527 "TessellationEvaluation.",
2528 bound_args: spv::ExecutionModel::TessellationEvaluation, bound_args: decoration, bound_args: built_in_inst,
2529 bound_args: referenced_from_inst, bound_args: std::placeholders::_1));
2530 }
2531
2532 for (const spv::ExecutionModel execution_model : execution_models_) {
2533 switch (execution_model) {
2534 case spv::ExecutionModel::TessellationControl:
2535 case spv::ExecutionModel::TessellationEvaluation: {
2536 // Ok.
2537 break;
2538 }
2539
2540 default: {
2541 uint32_t vuid = (spv::BuiltIn(operand) == spv::BuiltIn::TessLevelOuter) ? 4390 : 4394;
2542 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
2543 << _.VkErrorID(id: vuid) << "Vulkan spec allows BuiltIn "
2544 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN,
2545 operand)
2546 << " to be used only with TessellationControl or "
2547 "TessellationEvaluation execution models. "
2548 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
2549 referenced_from_inst, execution_model);
2550 }
2551 }
2552 }
2553 }
2554
2555 if (function_id_ == 0) {
2556 // Propagate this rule to all dependant ids in the global scope.
2557 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(x: std::bind(
2558 f: &BuiltInsValidator::ValidateTessLevelAtReference, bound_args: this, bound_args: decoration,
2559 bound_args: built_in_inst, bound_args: referenced_from_inst, bound_args: std::placeholders::_1));
2560 }
2561
2562 return SPV_SUCCESS;
2563}
2564
2565spv_result_t BuiltInsValidator::ValidateVertexIndexAtDefinition(
2566 const Decoration& decoration, const Instruction& inst) {
2567 if (spvIsVulkanEnv(env: _.context()->target_env)) {
2568 if (spv_result_t error = ValidateI32(
2569 decoration, inst,
2570 diag: [this, &inst](const std::string& message) -> spv_result_t {
2571 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &inst)
2572 << _.VkErrorID(id: 4400) << "According to the "
2573 << spvLogStringForEnv(env: _.context()->target_env)
2574 << " spec BuiltIn VertexIndex variable needs to be a "
2575 "32-bit int scalar. "
2576 << message;
2577 })) {
2578 return error;
2579 }
2580 }
2581
2582 // Seed at reference checks with this built-in.
2583 return ValidateVertexIndexAtReference(decoration, built_in_inst: inst, referenced_inst: inst, referenced_from_inst: inst);
2584}
2585
2586spv_result_t BuiltInsValidator::ValidateVertexIdAtDefinition(
2587 const Decoration& decoration, const Instruction& inst) {
2588 (void)decoration;
2589 if (spvIsVulkanEnv(env: _.context()->target_env)) {
2590 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &inst)
2591 << "Vulkan spec doesn't allow BuiltIn VertexId "
2592 "to be used.";
2593 }
2594
2595 return SPV_SUCCESS;
2596}
2597
2598spv_result_t BuiltInsValidator::ValidateLocalInvocationIndexAtDefinition(
2599 const Decoration& decoration, const Instruction& inst) {
2600 // Seed at reference checks with this built-in.
2601 return ValidateLocalInvocationIndexAtReference(decoration, built_in_inst: inst, referenced_inst: inst, referenced_from_inst: inst);
2602}
2603
2604spv_result_t BuiltInsValidator::ValidateLocalInvocationIndexAtReference(
2605 const Decoration& decoration, const Instruction& built_in_inst,
2606 const Instruction&,
2607 const Instruction& referenced_from_inst) {
2608 if (function_id_ == 0) {
2609 // Propagate this rule to all dependant ids in the global scope.
2610 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
2611 x: std::bind(f: &BuiltInsValidator::ValidateLocalInvocationIndexAtReference,
2612 bound_args: this, bound_args: decoration, bound_args: built_in_inst, bound_args: referenced_from_inst,
2613 bound_args: std::placeholders::_1));
2614 }
2615
2616 return SPV_SUCCESS;
2617}
2618
2619spv_result_t BuiltInsValidator::ValidateVertexIndexAtReference(
2620 const Decoration& decoration, const Instruction& built_in_inst,
2621 const Instruction& referenced_inst,
2622 const Instruction& referenced_from_inst) {
2623 if (spvIsVulkanEnv(env: _.context()->target_env)) {
2624 const spv::StorageClass storage_class = GetStorageClass(inst: referenced_from_inst);
2625 if (storage_class != spv::StorageClass::Max &&
2626 storage_class != spv::StorageClass::Input) {
2627 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
2628 << _.VkErrorID(id: 4399) << spvLogStringForEnv(env: _.context()->target_env)
2629 << " spec allows BuiltIn VertexIndex to be only used for "
2630 "variables with Input storage class. "
2631 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
2632 referenced_from_inst)
2633 << " " << GetStorageClassDesc(inst: referenced_from_inst);
2634 }
2635
2636 for (const spv::ExecutionModel execution_model : execution_models_) {
2637 if (execution_model != spv::ExecutionModel::Vertex) {
2638 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
2639 << _.VkErrorID(id: 4398)
2640 << spvLogStringForEnv(env: _.context()->target_env)
2641 << " spec allows BuiltIn VertexIndex to be used only with "
2642 "Vertex execution model. "
2643 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
2644 referenced_from_inst, execution_model);
2645 }
2646 }
2647 }
2648
2649 if (function_id_ == 0) {
2650 // Propagate this rule to all dependant ids in the global scope.
2651 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(x: std::bind(
2652 f: &BuiltInsValidator::ValidateVertexIndexAtReference, bound_args: this, bound_args: decoration,
2653 bound_args: built_in_inst, bound_args: referenced_from_inst, bound_args: std::placeholders::_1));
2654 }
2655
2656 return SPV_SUCCESS;
2657}
2658
2659spv_result_t BuiltInsValidator::ValidateLayerOrViewportIndexAtDefinition(
2660 const Decoration& decoration, const Instruction& inst) {
2661 if (spvIsVulkanEnv(env: _.context()->target_env)) {
2662 // This can be a per-primitive variable for mesh shader stage.
2663 // In such cases variable will have an array of 32-bit integers.
2664 if (decoration.struct_member_index() != Decoration::kInvalidMember) {
2665 // This must be a 32-bit int scalar.
2666 if (spv_result_t error = ValidateI32(
2667 decoration, inst,
2668 diag: [this, &decoration,
2669 &inst](const std::string& message) -> spv_result_t {
2670 uint32_t vuid =
2671 (spv::BuiltIn(decoration.params()[0]) == spv::BuiltIn::Layer) ? 4276 : 4408;
2672 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &inst)
2673 << _.VkErrorID(id: vuid)
2674 << "According to the Vulkan spec BuiltIn "
2675 << _.grammar().lookupOperandName(
2676 type: SPV_OPERAND_TYPE_BUILT_IN, operand: decoration.params()[0])
2677 << "variable needs to be a 32-bit int scalar. "
2678 << message;
2679 })) {
2680 return error;
2681 }
2682 } else {
2683 if (spv_result_t error = ValidateOptionalArrayedI32(
2684 decoration, inst,
2685 diag: [this, &decoration,
2686 &inst](const std::string& message) -> spv_result_t {
2687 uint32_t vuid =
2688 (spv::BuiltIn(decoration.params()[0]) == spv::BuiltIn::Layer) ? 4276 : 4408;
2689 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &inst)
2690 << _.VkErrorID(id: vuid)
2691 << "According to the Vulkan spec BuiltIn "
2692 << _.grammar().lookupOperandName(
2693 type: SPV_OPERAND_TYPE_BUILT_IN, operand: decoration.params()[0])
2694 << "variable needs to be a 32-bit int scalar. "
2695 << message;
2696 })) {
2697 return error;
2698 }
2699 }
2700 }
2701
2702 // Seed at reference checks with this built-in.
2703 return ValidateLayerOrViewportIndexAtReference(decoration, built_in_inst: inst, referenced_inst: inst, referenced_from_inst: inst);
2704}
2705
2706spv_result_t BuiltInsValidator::ValidateLayerOrViewportIndexAtReference(
2707 const Decoration& decoration, const Instruction& built_in_inst,
2708 const Instruction& referenced_inst,
2709 const Instruction& referenced_from_inst) {
2710 uint32_t operand = decoration.params()[0];
2711 if (spvIsVulkanEnv(env: _.context()->target_env)) {
2712 const spv::StorageClass storage_class = GetStorageClass(inst: referenced_from_inst);
2713 if (storage_class != spv::StorageClass::Max &&
2714 storage_class != spv::StorageClass::Input &&
2715 storage_class != spv::StorageClass::Output) {
2716 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
2717 << "Vulkan spec allows BuiltIn "
2718 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN,
2719 operand)
2720 << " to be only used for variables with Input or Output storage "
2721 "class. "
2722 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
2723 referenced_from_inst)
2724 << " " << GetStorageClassDesc(inst: referenced_from_inst);
2725 }
2726
2727 if (storage_class == spv::StorageClass::Input) {
2728 assert(function_id_ == 0);
2729 for (const auto em :
2730 {spv::ExecutionModel::Vertex, spv::ExecutionModel::TessellationEvaluation,
2731 spv::ExecutionModel::Geometry, spv::ExecutionModel::MeshNV,
2732 spv::ExecutionModel::MeshEXT}) {
2733 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
2734 x: std::bind(f: &BuiltInsValidator::ValidateNotCalledWithExecutionModel,
2735 bound_args: this, bound_args: ((spv::BuiltIn(operand) == spv::BuiltIn::Layer) ? 4274 : 4406),
2736 bound_args: "Vulkan spec doesn't allow BuiltIn Layer and "
2737 "ViewportIndex to be "
2738 "used for variables with Input storage class if "
2739 "execution model is Vertex, TessellationEvaluation, "
2740 "Geometry, MeshNV or MeshEXT.",
2741 bound_args: em, bound_args: decoration, bound_args: built_in_inst, bound_args: referenced_from_inst,
2742 bound_args: std::placeholders::_1));
2743 }
2744 }
2745
2746 if (storage_class == spv::StorageClass::Output) {
2747 assert(function_id_ == 0);
2748 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
2749 x: std::bind(f: &BuiltInsValidator::ValidateNotCalledWithExecutionModel,
2750 bound_args: this, bound_args: ((spv::BuiltIn(operand) == spv::BuiltIn::Layer) ? 4275 : 4407),
2751 bound_args: "Vulkan spec doesn't allow BuiltIn Layer and "
2752 "ViewportIndex to be "
2753 "used for variables with Output storage class if "
2754 "execution model is "
2755 "Fragment.",
2756 bound_args: spv::ExecutionModel::Fragment, bound_args: decoration, bound_args: built_in_inst,
2757 bound_args: referenced_from_inst, bound_args: std::placeholders::_1));
2758 }
2759
2760 for (const spv::ExecutionModel execution_model : execution_models_) {
2761 switch (execution_model) {
2762 case spv::ExecutionModel::Geometry:
2763 case spv::ExecutionModel::Fragment:
2764 case spv::ExecutionModel::MeshNV:
2765 case spv::ExecutionModel::MeshEXT:
2766 // Ok.
2767 break;
2768 case spv::ExecutionModel::Vertex:
2769 case spv::ExecutionModel::TessellationEvaluation: {
2770 if (!_.HasCapability(cap: spv::Capability::ShaderViewportIndexLayerEXT)) {
2771 if (spv::BuiltIn(operand) == spv::BuiltIn::ViewportIndex &&
2772 _.HasCapability(cap: spv::Capability::ShaderViewportIndex))
2773 break; // Ok
2774 if (spv::BuiltIn(operand) == spv::BuiltIn::Layer &&
2775 _.HasCapability(cap: spv::Capability::ShaderLayer))
2776 break; // Ok
2777
2778 const char* capability = "ShaderViewportIndexLayerEXT";
2779
2780 if (spv::BuiltIn(operand) == spv::BuiltIn::ViewportIndex)
2781 capability = "ShaderViewportIndexLayerEXT or ShaderViewportIndex";
2782 if (spv::BuiltIn(operand) == spv::BuiltIn::Layer)
2783 capability = "ShaderViewportIndexLayerEXT or ShaderLayer";
2784
2785 uint32_t vuid = (spv::BuiltIn(operand) == spv::BuiltIn::Layer) ? 4273 : 4405;
2786 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
2787 << _.VkErrorID(id: vuid) << "Using BuiltIn "
2788 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN,
2789 operand)
2790 << " in Vertex or Tessellation execution model requires the "
2791 << capability << " capability.";
2792 }
2793 break;
2794 }
2795 default: {
2796 uint32_t vuid = (spv::BuiltIn(operand) == spv::BuiltIn::Layer) ? 4272 : 4404;
2797 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
2798 << _.VkErrorID(id: vuid) << "Vulkan spec allows BuiltIn "
2799 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN,
2800 operand)
2801 << " to be used only with Vertex, TessellationEvaluation, "
2802 "Geometry, or Fragment execution models. "
2803 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
2804 referenced_from_inst, execution_model);
2805 }
2806 }
2807 }
2808 }
2809
2810 if (function_id_ == 0) {
2811 // Propagate this rule to all dependant ids in the global scope.
2812 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
2813 x: std::bind(f: &BuiltInsValidator::ValidateLayerOrViewportIndexAtReference,
2814 bound_args: this, bound_args: decoration, bound_args: built_in_inst, bound_args: referenced_from_inst,
2815 bound_args: std::placeholders::_1));
2816 }
2817
2818 return SPV_SUCCESS;
2819}
2820
2821spv_result_t BuiltInsValidator::ValidateFragmentShaderF32Vec3InputAtDefinition(
2822 const Decoration& decoration, const Instruction& inst) {
2823 if (spvIsVulkanEnv(env: _.context()->target_env)) {
2824 const spv::BuiltIn builtin = spv::BuiltIn(decoration.params()[0]);
2825 if (spv_result_t error = ValidateF32Vec(
2826 decoration, inst, num_components: 3,
2827 diag: [this, &inst, builtin](const std::string& message) -> spv_result_t {
2828 uint32_t vuid = GetVUIDForBuiltin(builtIn: builtin, type: VUIDErrorType);
2829 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &inst)
2830 << _.VkErrorID(id: vuid) << "According to the "
2831 << spvLogStringForEnv(env: _.context()->target_env)
2832 << " spec BuiltIn "
2833 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN,
2834 operand: uint32_t(builtin))
2835 << " variable needs to be a 3-component 32-bit float "
2836 "vector. "
2837 << message;
2838 })) {
2839 return error;
2840 }
2841 }
2842
2843 // Seed at reference checks with this built-in.
2844 return ValidateFragmentShaderF32Vec3InputAtReference(decoration, built_in_inst: inst, referenced_inst: inst,
2845 referenced_from_inst: inst);
2846}
2847
2848spv_result_t BuiltInsValidator::ValidateFragmentShaderF32Vec3InputAtReference(
2849 const Decoration& decoration, const Instruction& built_in_inst,
2850 const Instruction& referenced_inst,
2851 const Instruction& referenced_from_inst) {
2852
2853 if (spvIsVulkanEnv(env: _.context()->target_env)) {
2854 const spv::BuiltIn builtin = spv::BuiltIn(decoration.params()[0]);
2855 const spv::StorageClass storage_class = GetStorageClass(inst: referenced_from_inst);
2856 if (storage_class != spv::StorageClass::Max &&
2857 storage_class != spv::StorageClass::Input) {
2858 uint32_t vuid = GetVUIDForBuiltin(builtIn: builtin, type: VUIDErrorStorageClass);
2859 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
2860 << _.VkErrorID(id: vuid) << spvLogStringForEnv(env: _.context()->target_env)
2861 << " spec allows BuiltIn "
2862 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN, operand: uint32_t(builtin))
2863 << " to be only used for variables with Input storage class. "
2864 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
2865 referenced_from_inst)
2866 << " " << GetStorageClassDesc(inst: referenced_from_inst);
2867 }
2868
2869 for (const spv::ExecutionModel execution_model : execution_models_) {
2870 if (execution_model != spv::ExecutionModel::Fragment) {
2871 uint32_t vuid = GetVUIDForBuiltin(builtIn: builtin, type: VUIDErrorExecutionModel);
2872 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
2873 << _.VkErrorID(id: vuid)
2874 << spvLogStringForEnv(env: _.context()->target_env)
2875 << " spec allows BuiltIn "
2876 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN, operand: uint32_t(builtin))
2877 << " to be used only with Fragment execution model. "
2878 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
2879 referenced_from_inst, execution_model);
2880 }
2881 }
2882 }
2883
2884 if (function_id_ == 0) {
2885 // Propagate this rule to all dependant ids in the global scope.
2886 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(x: std::bind(
2887 f: &BuiltInsValidator::ValidateFragmentShaderF32Vec3InputAtReference, bound_args: this,
2888 bound_args: decoration, bound_args: built_in_inst, bound_args: referenced_from_inst,
2889 bound_args: std::placeholders::_1));
2890 }
2891
2892 return SPV_SUCCESS;
2893}
2894
2895spv_result_t BuiltInsValidator::ValidateComputeShaderI32Vec3InputAtDefinition(
2896 const Decoration& decoration, const Instruction& inst) {
2897 if (spvIsVulkanEnv(env: _.context()->target_env)) {
2898 const spv::BuiltIn builtin = spv::BuiltIn(decoration.params()[0]);
2899 if (spv_result_t error = ValidateI32Vec(
2900 decoration, inst, num_components: 3,
2901 diag: [this, &inst, builtin](const std::string& message) -> spv_result_t {
2902 uint32_t vuid = GetVUIDForBuiltin(builtIn: builtin, type: VUIDErrorType);
2903 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &inst)
2904 << _.VkErrorID(id: vuid) << "According to the "
2905 << spvLogStringForEnv(env: _.context()->target_env)
2906 << " spec BuiltIn "
2907 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN,
2908 operand: uint32_t(builtin))
2909 << " variable needs to be a 3-component 32-bit int "
2910 "vector. "
2911 << message;
2912 })) {
2913 return error;
2914 }
2915 }
2916
2917 // Seed at reference checks with this built-in.
2918 return ValidateComputeShaderI32Vec3InputAtReference(decoration, built_in_inst: inst, referenced_inst: inst,
2919 referenced_from_inst: inst);
2920}
2921
2922spv_result_t BuiltInsValidator::ValidateComputeShaderI32Vec3InputAtReference(
2923 const Decoration& decoration, const Instruction& built_in_inst,
2924 const Instruction& referenced_inst,
2925 const Instruction& referenced_from_inst) {
2926 if (spvIsVulkanEnv(env: _.context()->target_env)) {
2927 const spv::BuiltIn builtin = spv::BuiltIn(decoration.params()[0]);
2928 const spv::StorageClass storage_class = GetStorageClass(inst: referenced_from_inst);
2929 if (storage_class != spv::StorageClass::Max &&
2930 storage_class != spv::StorageClass::Input) {
2931 uint32_t vuid = GetVUIDForBuiltin(builtIn: builtin, type: VUIDErrorStorageClass);
2932 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
2933 << _.VkErrorID(id: vuid) << spvLogStringForEnv(env: _.context()->target_env)
2934 << " spec allows BuiltIn "
2935 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN, operand: uint32_t(builtin))
2936 << " to be only used for variables with Input storage class. "
2937 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
2938 referenced_from_inst)
2939 << " " << GetStorageClassDesc(inst: referenced_from_inst);
2940 }
2941
2942 for (const spv::ExecutionModel execution_model : execution_models_) {
2943 bool has_vulkan_model = execution_model == spv::ExecutionModel::GLCompute ||
2944 execution_model == spv::ExecutionModel::TaskNV ||
2945 execution_model == spv::ExecutionModel::MeshNV ||
2946 execution_model == spv::ExecutionModel::TaskEXT ||
2947 execution_model == spv::ExecutionModel::MeshEXT;
2948
2949 if (spvIsVulkanEnv(env: _.context()->target_env) && !has_vulkan_model) {
2950 uint32_t vuid = GetVUIDForBuiltin(builtIn: builtin, type: VUIDErrorExecutionModel);
2951 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
2952 << _.VkErrorID(id: vuid)
2953 << spvLogStringForEnv(env: _.context()->target_env)
2954 << " spec allows BuiltIn "
2955 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN, operand: uint32_t(builtin))
2956 << " to be used only with GLCompute, MeshNV, TaskNV, MeshEXT or"
2957 << " TaskEXT execution model. "
2958 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
2959 referenced_from_inst, execution_model);
2960 }
2961 }
2962 }
2963
2964 if (function_id_ == 0) {
2965 // Propagate this rule to all dependant ids in the global scope.
2966 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(x: std::bind(
2967 f: &BuiltInsValidator::ValidateComputeShaderI32Vec3InputAtReference, bound_args: this,
2968 bound_args: decoration, bound_args: built_in_inst, bound_args: referenced_from_inst,
2969 bound_args: std::placeholders::_1));
2970 }
2971
2972 return SPV_SUCCESS;
2973}
2974
2975spv_result_t BuiltInsValidator::ValidateComputeI32InputAtDefinition(
2976 const Decoration& decoration, const Instruction& inst) {
2977 if (spvIsVulkanEnv(env: _.context()->target_env)) {
2978 const spv::BuiltIn builtin = spv::BuiltIn(decoration.params()[0]);
2979 if (decoration.struct_member_index() != Decoration::kInvalidMember) {
2980 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &inst)
2981 << "BuiltIn "
2982 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN, operand: uint32_t(builtin))
2983 << " cannot be used as a member decoration ";
2984 }
2985 if (spv_result_t error = ValidateI32(
2986 decoration, inst,
2987 diag: [this, &inst, builtin](const std::string& message) -> spv_result_t {
2988 uint32_t vuid = GetVUIDForBuiltin(builtIn: builtin, type: VUIDErrorType);
2989 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &inst)
2990 << _.VkErrorID(id: vuid)
2991 << "According to the "
2992 << spvLogStringForEnv(env: _.context()->target_env)
2993 << " spec BuiltIn "
2994 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN, operand: uint32_t(builtin))
2995 << " variable needs to be a 32-bit int "
2996 "vector. "
2997 << message;
2998 })) {
2999 return error;
3000 }
3001 }
3002
3003 // Seed at reference checks with this built-in.
3004 return ValidateComputeI32InputAtReference(decoration, built_in_inst: inst, referenced_inst: inst, referenced_from_inst: inst);
3005}
3006
3007spv_result_t BuiltInsValidator::ValidateComputeI32InputAtReference(
3008 const Decoration& decoration, const Instruction& built_in_inst,
3009 const Instruction& referenced_inst,
3010 const Instruction& referenced_from_inst) {
3011 if (spvIsVulkanEnv(env: _.context()->target_env)) {
3012 const spv::BuiltIn builtin = spv::BuiltIn(decoration.params()[0]);
3013 const spv::StorageClass storage_class = GetStorageClass(inst: referenced_from_inst);
3014 if (storage_class != spv::StorageClass::Max &&
3015 storage_class != spv::StorageClass::Input) {
3016 uint32_t vuid = GetVUIDForBuiltin(builtIn: builtin, type: VUIDErrorStorageClass);
3017 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
3018 << _.VkErrorID(id: vuid)
3019 << spvLogStringForEnv(env: _.context()->target_env)
3020 << " spec allows BuiltIn "
3021 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN, operand: uint32_t(builtin))
3022 << " to be only used for variables with Input storage class. "
3023 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
3024 referenced_from_inst)
3025 << " " << GetStorageClassDesc(inst: referenced_from_inst);
3026 }
3027
3028 for (const spv::ExecutionModel execution_model : execution_models_) {
3029 bool has_vulkan_model = execution_model == spv::ExecutionModel::GLCompute ||
3030 execution_model == spv::ExecutionModel::TaskNV ||
3031 execution_model == spv::ExecutionModel::MeshNV ||
3032 execution_model == spv::ExecutionModel::TaskEXT ||
3033 execution_model == spv::ExecutionModel::MeshEXT;
3034 if (spvIsVulkanEnv(env: _.context()->target_env) && !has_vulkan_model) {
3035 uint32_t vuid = GetVUIDForBuiltin(builtIn: builtin, type: VUIDErrorExecutionModel);
3036 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
3037 << _.VkErrorID(id: vuid)
3038 << spvLogStringForEnv(env: _.context()->target_env)
3039 << " spec allows BuiltIn "
3040 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN, operand: uint32_t(builtin))
3041 << " to be used only with GLCompute, MeshNV, TaskNV, MeshEXT or "
3042 << "TaskEXT execution model. "
3043 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
3044 referenced_from_inst, execution_model);
3045 }
3046 }
3047 }
3048
3049 if (function_id_ == 0) {
3050 // Propagate this rule to all dependant ids in the global scope.
3051 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
3052 x: std::bind(f: &BuiltInsValidator::ValidateComputeI32InputAtReference, bound_args: this,
3053 bound_args: decoration, bound_args: built_in_inst, bound_args: referenced_from_inst,
3054 bound_args: std::placeholders::_1));
3055 }
3056
3057 return SPV_SUCCESS;
3058}
3059
3060spv_result_t BuiltInsValidator::ValidateI32InputAtDefinition(
3061 const Decoration& decoration, const Instruction& inst) {
3062 if (spvIsVulkanEnv(env: _.context()->target_env)) {
3063 const spv::BuiltIn builtin = spv::BuiltIn(decoration.params()[0]);
3064 if (decoration.struct_member_index() != Decoration::kInvalidMember) {
3065 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &inst)
3066 << "BuiltIn "
3067 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN, operand: uint32_t(builtin))
3068 << " cannot be used as a member decoration ";
3069 }
3070 if (spv_result_t error = ValidateI32(
3071 decoration, inst,
3072 diag: [this, &inst, builtin](const std::string& message) -> spv_result_t {
3073 uint32_t vuid = GetVUIDForBuiltin(builtIn: builtin, type: VUIDErrorType);
3074 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &inst)
3075 << _.VkErrorID(id: vuid)
3076 << "According to the "
3077 << spvLogStringForEnv(env: _.context()->target_env)
3078 << " spec BuiltIn "
3079 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN, operand: uint32_t(builtin))
3080 << " variable needs to be a 32-bit int. " << message;
3081 })) {
3082 return error;
3083 }
3084
3085 const spv::StorageClass storage_class = GetStorageClass(inst);
3086 if (storage_class != spv::StorageClass::Max &&
3087 storage_class != spv::StorageClass::Input) {
3088 uint32_t vuid = GetVUIDForBuiltin(builtIn: builtin, type: VUIDErrorStorageClass);
3089 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &inst)
3090 << _.VkErrorID(id: vuid)
3091 << spvLogStringForEnv(env: _.context()->target_env)
3092 << " spec allows BuiltIn "
3093 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN, operand: uint32_t(builtin))
3094 << " to be only used for variables with Input storage class. "
3095 << GetReferenceDesc(decoration, built_in_inst: inst, referenced_inst: inst, referenced_from_inst: inst) << " "
3096 << GetStorageClassDesc(inst);
3097 }
3098 }
3099
3100 return SPV_SUCCESS;
3101}
3102
3103spv_result_t BuiltInsValidator::ValidateI32Vec4InputAtDefinition(
3104 const Decoration& decoration, const Instruction& inst) {
3105 if (spvIsVulkanEnv(env: _.context()->target_env)) {
3106 const spv::BuiltIn builtin = spv::BuiltIn(decoration.params()[0]);
3107 if (decoration.struct_member_index() != Decoration::kInvalidMember) {
3108 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &inst)
3109 << "BuiltIn "
3110 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN, operand: uint32_t(builtin))
3111 << " cannot be used as a member decoration ";
3112 }
3113 if (spv_result_t error = ValidateI32Vec(
3114 decoration, inst, num_components: 4,
3115 diag: [this, &inst, builtin](const std::string& message) -> spv_result_t {
3116 uint32_t vuid = GetVUIDForBuiltin(builtIn: builtin, type: VUIDErrorType);
3117 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &inst)
3118 << _.VkErrorID(id: vuid)
3119 << "According to the "
3120 << spvLogStringForEnv(env: _.context()->target_env)
3121 << " spec BuiltIn "
3122 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN, operand: uint32_t(builtin))
3123 << " variable needs to be a 4-component 32-bit int "
3124 "vector. "
3125 << message;
3126 })) {
3127 return error;
3128 }
3129
3130 const spv::StorageClass storage_class = GetStorageClass(inst);
3131 if (storage_class != spv::StorageClass::Max &&
3132 storage_class != spv::StorageClass::Input) {
3133 uint32_t vuid = GetVUIDForBuiltin(builtIn: builtin, type: VUIDErrorStorageClass);
3134 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &inst)
3135 << _.VkErrorID(id: vuid)
3136 << spvLogStringForEnv(env: _.context()->target_env)
3137 << " spec allows BuiltIn "
3138 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN, operand: uint32_t(builtin))
3139 << " to be only used for variables with Input storage class. "
3140 << GetReferenceDesc(decoration, built_in_inst: inst, referenced_inst: inst, referenced_from_inst: inst) << " "
3141 << GetStorageClassDesc(inst);
3142 }
3143 }
3144
3145 return SPV_SUCCESS;
3146}
3147
3148spv_result_t BuiltInsValidator::ValidateWorkgroupSizeAtDefinition(
3149 const Decoration& decoration, const Instruction& inst) {
3150 if (spvIsVulkanEnv(env: _.context()->target_env)) {
3151 if (spvIsVulkanEnv(env: _.context()->target_env) &&
3152 !spvOpcodeIsConstant(opcode: inst.opcode())) {
3153 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &inst)
3154 << _.VkErrorID(id: 4426)
3155 << "Vulkan spec requires BuiltIn WorkgroupSize to be a "
3156 "constant. "
3157 << GetIdDesc(inst) << " is not a constant.";
3158 }
3159
3160 if (spv_result_t error = ValidateI32Vec(
3161 decoration, inst, num_components: 3,
3162 diag: [this, &inst](const std::string& message) -> spv_result_t {
3163 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &inst)
3164 << _.VkErrorID(id: 4427) << "According to the "
3165 << spvLogStringForEnv(env: _.context()->target_env)
3166 << " spec BuiltIn WorkgroupSize variable needs to be a "
3167 "3-component 32-bit int vector. "
3168 << message;
3169 })) {
3170 return error;
3171 }
3172 }
3173
3174 // Seed at reference checks with this built-in.
3175 return ValidateWorkgroupSizeAtReference(decoration, built_in_inst: inst, referenced_inst: inst, referenced_from_inst: inst);
3176}
3177
3178spv_result_t BuiltInsValidator::ValidateWorkgroupSizeAtReference(
3179 const Decoration& decoration, const Instruction& built_in_inst,
3180 const Instruction& referenced_inst,
3181 const Instruction& referenced_from_inst) {
3182 if (spvIsVulkanEnv(env: _.context()->target_env)) {
3183 for (const spv::ExecutionModel execution_model : execution_models_) {
3184 if (execution_model != spv::ExecutionModel::GLCompute &&
3185 execution_model != spv::ExecutionModel::TaskNV &&
3186 execution_model != spv::ExecutionModel::MeshNV &&
3187 execution_model != spv::ExecutionModel::TaskEXT &&
3188 execution_model != spv::ExecutionModel::MeshEXT) {
3189 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
3190 << _.VkErrorID(id: 4425)
3191 << spvLogStringForEnv(env: _.context()->target_env)
3192 << " spec allows BuiltIn "
3193 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN,
3194 operand: decoration.params()[0])
3195 << " to be used only with GLCompute, MeshNV, TaskNV, MeshEXT or "
3196 << "TaskEXT execution model. "
3197 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
3198 referenced_from_inst, execution_model);
3199 }
3200 }
3201 }
3202
3203 if (function_id_ == 0) {
3204 // Propagate this rule to all dependant ids in the global scope.
3205 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(x: std::bind(
3206 f: &BuiltInsValidator::ValidateWorkgroupSizeAtReference, bound_args: this, bound_args: decoration,
3207 bound_args: built_in_inst, bound_args: referenced_from_inst, bound_args: std::placeholders::_1));
3208 }
3209
3210 return SPV_SUCCESS;
3211}
3212
3213spv_result_t BuiltInsValidator::ValidateBaseInstanceOrVertexAtDefinition(
3214 const Decoration& decoration, const Instruction& inst) {
3215 if (spvIsVulkanEnv(env: _.context()->target_env)) {
3216 if (spv_result_t error = ValidateI32(
3217 decoration, inst,
3218 diag: [this, &inst,
3219 &decoration](const std::string& message) -> spv_result_t {
3220 uint32_t vuid = (spv::BuiltIn(decoration.params()[0]) == spv::BuiltIn::BaseInstance)
3221 ? 4183
3222 : 4186;
3223 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &inst)
3224 << _.VkErrorID(id: vuid)
3225 << "According to the Vulkan spec BuiltIn "
3226 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN,
3227 operand: decoration.params()[0])
3228 << " variable needs to be a 32-bit int scalar. "
3229 << message;
3230 })) {
3231 return error;
3232 }
3233 }
3234
3235 return ValidateBaseInstanceOrVertexAtReference(decoration, built_in_inst: inst, referenced_inst: inst, referenced_from_inst: inst);
3236}
3237
3238spv_result_t BuiltInsValidator::ValidateBaseInstanceOrVertexAtReference(
3239 const Decoration& decoration, const Instruction& built_in_inst,
3240 const Instruction& referenced_inst,
3241 const Instruction& referenced_from_inst) {
3242 uint32_t operand = decoration.params()[0];
3243 if (spvIsVulkanEnv(env: _.context()->target_env)) {
3244 const spv::StorageClass storage_class = GetStorageClass(inst: referenced_from_inst);
3245 if (storage_class != spv::StorageClass::Max &&
3246 storage_class != spv::StorageClass::Input) {
3247 uint32_t vuid = (spv::BuiltIn(operand) == spv::BuiltIn::BaseInstance) ? 4182 : 4185;
3248 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
3249 << _.VkErrorID(id: vuid) << "Vulkan spec allows BuiltIn "
3250 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN,
3251 operand)
3252 << " to be only used for variables with Input storage class. "
3253 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
3254 referenced_from_inst)
3255 << " " << GetStorageClassDesc(inst: referenced_from_inst);
3256 }
3257
3258 for (const spv::ExecutionModel execution_model : execution_models_) {
3259 if (execution_model != spv::ExecutionModel::Vertex) {
3260 uint32_t vuid = (spv::BuiltIn(operand) == spv::BuiltIn::BaseInstance) ? 4181 : 4184;
3261 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
3262 << _.VkErrorID(id: vuid) << "Vulkan spec allows BuiltIn "
3263 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN,
3264 operand)
3265 << " to be used only with Vertex execution model. "
3266 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
3267 referenced_from_inst, execution_model);
3268 }
3269 }
3270 }
3271
3272 if (function_id_ == 0) {
3273 // Propagate this rule to all dependant ids in the global scope.
3274 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
3275 x: std::bind(f: &BuiltInsValidator::ValidateBaseInstanceOrVertexAtReference,
3276 bound_args: this, bound_args: decoration, bound_args: built_in_inst, bound_args: referenced_from_inst,
3277 bound_args: std::placeholders::_1));
3278 }
3279
3280 return SPV_SUCCESS;
3281}
3282
3283spv_result_t BuiltInsValidator::ValidateDrawIndexAtDefinition(
3284 const Decoration& decoration, const Instruction& inst) {
3285 if (spvIsVulkanEnv(env: _.context()->target_env)) {
3286 if (spv_result_t error = ValidateI32(
3287 decoration, inst,
3288 diag: [this, &inst,
3289 &decoration](const std::string& message) -> spv_result_t {
3290 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &inst)
3291 << _.VkErrorID(id: 4209)
3292 << "According to the Vulkan spec BuiltIn "
3293 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN,
3294 operand: decoration.params()[0])
3295 << " variable needs to be a 32-bit int scalar. "
3296 << message;
3297 })) {
3298 return error;
3299 }
3300 }
3301
3302 return ValidateDrawIndexAtReference(decoration, built_in_inst: inst, referenced_inst: inst, referenced_from_inst: inst);
3303}
3304
3305spv_result_t BuiltInsValidator::ValidateDrawIndexAtReference(
3306 const Decoration& decoration, const Instruction& built_in_inst,
3307 const Instruction& referenced_inst,
3308 const Instruction& referenced_from_inst) {
3309 uint32_t operand = decoration.params()[0];
3310 if (spvIsVulkanEnv(env: _.context()->target_env)) {
3311 const spv::StorageClass storage_class = GetStorageClass(inst: referenced_from_inst);
3312 if (storage_class != spv::StorageClass::Max &&
3313 storage_class != spv::StorageClass::Input) {
3314 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
3315 << _.VkErrorID(id: 4208) << "Vulkan spec allows BuiltIn "
3316 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN,
3317 operand)
3318 << " to be only used for variables with Input storage class. "
3319 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
3320 referenced_from_inst)
3321 << " " << GetStorageClassDesc(inst: referenced_from_inst);
3322 }
3323
3324 for (const spv::ExecutionModel execution_model : execution_models_) {
3325 if (execution_model != spv::ExecutionModel::Vertex &&
3326 execution_model != spv::ExecutionModel::MeshNV &&
3327 execution_model != spv::ExecutionModel::TaskNV &&
3328 execution_model != spv::ExecutionModel::MeshEXT &&
3329 execution_model != spv::ExecutionModel::TaskEXT) {
3330 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
3331 << _.VkErrorID(id: 4207) << "Vulkan spec allows BuiltIn "
3332 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN,
3333 operand)
3334 << " to be used only with Vertex, MeshNV, TaskNV , MeshEXT or"
3335 << " TaskEXT execution "
3336 "model. "
3337 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
3338 referenced_from_inst, execution_model);
3339 }
3340 }
3341 }
3342
3343 if (function_id_ == 0) {
3344 // Propagate this rule to all dependant ids in the global scope.
3345 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(x: std::bind(
3346 f: &BuiltInsValidator::ValidateDrawIndexAtReference, bound_args: this, bound_args: decoration,
3347 bound_args: built_in_inst, bound_args: referenced_from_inst, bound_args: std::placeholders::_1));
3348 }
3349
3350 return SPV_SUCCESS;
3351}
3352
3353spv_result_t BuiltInsValidator::ValidateViewIndexAtDefinition(
3354 const Decoration& decoration, const Instruction& inst) {
3355 if (spvIsVulkanEnv(env: _.context()->target_env)) {
3356 if (spv_result_t error = ValidateI32(
3357 decoration, inst,
3358 diag: [this, &inst,
3359 &decoration](const std::string& message) -> spv_result_t {
3360 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &inst)
3361 << _.VkErrorID(id: 4403)
3362 << "According to the Vulkan spec BuiltIn "
3363 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN,
3364 operand: decoration.params()[0])
3365 << " variable needs to be a 32-bit int scalar. "
3366 << message;
3367 })) {
3368 return error;
3369 }
3370 }
3371
3372 return ValidateViewIndexAtReference(decoration, built_in_inst: inst, referenced_inst: inst, referenced_from_inst: inst);
3373}
3374
3375spv_result_t BuiltInsValidator::ValidateViewIndexAtReference(
3376 const Decoration& decoration, const Instruction& built_in_inst,
3377 const Instruction& referenced_inst,
3378 const Instruction& referenced_from_inst) {
3379 uint32_t operand = decoration.params()[0];
3380 if (spvIsVulkanEnv(env: _.context()->target_env)) {
3381 const spv::StorageClass storage_class = GetStorageClass(inst: referenced_from_inst);
3382 if (storage_class != spv::StorageClass::Max &&
3383 storage_class != spv::StorageClass::Input) {
3384 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
3385 << _.VkErrorID(id: 4402) << "Vulkan spec allows BuiltIn "
3386 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN,
3387 operand)
3388 << " to be only used for variables with Input storage class. "
3389 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
3390 referenced_from_inst)
3391 << " " << GetStorageClassDesc(inst: referenced_from_inst);
3392 }
3393
3394 for (const spv::ExecutionModel execution_model : execution_models_) {
3395 if (execution_model == spv::ExecutionModel::GLCompute) {
3396 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
3397 << _.VkErrorID(id: 4401) << "Vulkan spec allows BuiltIn "
3398 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN,
3399 operand)
3400 << " to be not be used with GLCompute execution model. "
3401 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
3402 referenced_from_inst, execution_model);
3403 }
3404 }
3405 }
3406
3407 if (function_id_ == 0) {
3408 // Propagate this rule to all dependant ids in the global scope.
3409 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(x: std::bind(
3410 f: &BuiltInsValidator::ValidateViewIndexAtReference, bound_args: this, bound_args: decoration,
3411 bound_args: built_in_inst, bound_args: referenced_from_inst, bound_args: std::placeholders::_1));
3412 }
3413
3414 return SPV_SUCCESS;
3415}
3416
3417spv_result_t BuiltInsValidator::ValidateDeviceIndexAtDefinition(
3418 const Decoration& decoration, const Instruction& inst) {
3419 if (spvIsVulkanEnv(env: _.context()->target_env)) {
3420 if (spv_result_t error = ValidateI32(
3421 decoration, inst,
3422 diag: [this, &inst,
3423 &decoration](const std::string& message) -> spv_result_t {
3424 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &inst)
3425 << _.VkErrorID(id: 4206)
3426 << "According to the Vulkan spec BuiltIn "
3427 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN,
3428 operand: decoration.params()[0])
3429 << " variable needs to be a 32-bit int scalar. "
3430 << message;
3431 })) {
3432 return error;
3433 }
3434 }
3435
3436 return ValidateDeviceIndexAtReference(decoration, built_in_inst: inst, referenced_inst: inst, referenced_from_inst: inst);
3437}
3438
3439spv_result_t BuiltInsValidator::ValidateDeviceIndexAtReference(
3440 const Decoration& decoration, const Instruction& built_in_inst,
3441 const Instruction& referenced_inst,
3442 const Instruction& referenced_from_inst) {
3443 uint32_t operand = decoration.params()[0];
3444 if (spvIsVulkanEnv(env: _.context()->target_env)) {
3445 const spv::StorageClass storage_class = GetStorageClass(inst: referenced_from_inst);
3446 if (storage_class != spv::StorageClass::Max &&
3447 storage_class != spv::StorageClass::Input) {
3448 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
3449 << _.VkErrorID(id: 4205) << "Vulkan spec allows BuiltIn "
3450 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN,
3451 operand)
3452 << " to be only used for variables with Input storage class. "
3453 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
3454 referenced_from_inst)
3455 << " " << GetStorageClassDesc(inst: referenced_from_inst);
3456 }
3457 }
3458
3459 if (function_id_ == 0) {
3460 // Propagate this rule to all dependant ids in the global scope.
3461 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(x: std::bind(
3462 f: &BuiltInsValidator::ValidateDeviceIndexAtReference, bound_args: this, bound_args: decoration,
3463 bound_args: built_in_inst, bound_args: referenced_from_inst, bound_args: std::placeholders::_1));
3464 }
3465
3466 return SPV_SUCCESS;
3467}
3468
3469spv_result_t BuiltInsValidator::ValidateFragInvocationCountAtDefinition(const Decoration& decoration,
3470 const Instruction& inst) {
3471
3472 if (spvIsVulkanEnv(env: _.context()->target_env)) {
3473 const spv::BuiltIn builtin = spv::BuiltIn(decoration.params()[0]);
3474 if (spv_result_t error = ValidateI32(
3475 decoration, inst,
3476 diag: [this, &inst, &builtin](const std::string& message) -> spv_result_t {
3477 uint32_t vuid = GetVUIDForBuiltin(builtIn: builtin, type: VUIDErrorType);
3478 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &inst)
3479 << _.VkErrorID(id: vuid) << "According to the "
3480 << spvLogStringForEnv(env: _.context()->target_env)
3481 << " spec BuiltIn "
3482 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN,
3483 operand: uint32_t(builtin))
3484 << " variable needs to be a 32-bit int scalar. "
3485 << message;
3486 })) {
3487 return error;
3488 }
3489 }
3490
3491 return ValidateFragInvocationCountAtReference(decoration, built_in_inst: inst, referenced_inst: inst, referenced_from_inst: inst);
3492}
3493
3494spv_result_t BuiltInsValidator::ValidateFragInvocationCountAtReference(
3495 const Decoration& decoration, const Instruction& built_in_inst,
3496 const Instruction& referenced_inst,
3497 const Instruction& referenced_from_inst) {
3498
3499 if (spvIsVulkanEnv(env: _.context()->target_env)) {
3500 const spv::BuiltIn builtin = spv::BuiltIn(decoration.params()[0]);
3501 const spv::StorageClass storage_class = GetStorageClass(inst: referenced_from_inst);
3502 if (storage_class != spv::StorageClass::Max &&
3503 storage_class != spv::StorageClass::Input) {
3504 uint32_t vuid = GetVUIDForBuiltin(builtIn: builtin, type: VUIDErrorStorageClass);
3505 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
3506 << _.VkErrorID(id: vuid) << spvLogStringForEnv(env: _.context()->target_env)
3507 << " spec allows BuiltIn "
3508 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN, operand: uint32_t(builtin))
3509 << " to be only used for variables with Input storage class. "
3510 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
3511 referenced_from_inst)
3512 << " " << GetStorageClassDesc(inst: referenced_from_inst);
3513 }
3514
3515 for (const spv::ExecutionModel execution_model : execution_models_) {
3516 if (execution_model != spv::ExecutionModel::Fragment) {
3517 uint32_t vuid = GetVUIDForBuiltin(builtIn: builtin, type: VUIDErrorExecutionModel);
3518 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
3519 << _.VkErrorID(id: vuid)
3520 << spvLogStringForEnv(env: _.context()->target_env)
3521 << " spec allows BuiltIn "
3522 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN, operand: uint32_t(builtin))
3523 << " to be used only with Fragment execution model. "
3524 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
3525 referenced_from_inst, execution_model);
3526 }
3527 }
3528 }
3529
3530 if (function_id_ == 0) {
3531 // Propagate this rule to all dependant ids in the global scope.
3532 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(x: std::bind(
3533 f: &BuiltInsValidator::ValidateFragInvocationCountAtReference, bound_args: this, bound_args: decoration,
3534 bound_args: built_in_inst, bound_args: referenced_from_inst, bound_args: std::placeholders::_1));
3535 }
3536
3537 return SPV_SUCCESS;
3538}
3539
3540spv_result_t BuiltInsValidator::ValidateFragSizeAtDefinition(const Decoration& decoration,
3541 const Instruction& inst) {
3542 if (spvIsVulkanEnv(env: _.context()->target_env)) {
3543 const spv::BuiltIn builtin = spv::BuiltIn(decoration.params()[0]);
3544 if (spv_result_t error = ValidateI32Vec(
3545 decoration, inst, num_components: 2,
3546 diag: [this, &inst, &builtin](const std::string& message) -> spv_result_t {
3547 uint32_t vuid = GetVUIDForBuiltin(builtIn: builtin, type: VUIDErrorType);
3548 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &inst)
3549 << _.VkErrorID(id: vuid) << "According to the "
3550 << spvLogStringForEnv(env: _.context()->target_env)
3551 << " spec BuiltIn "
3552 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN,
3553 operand: uint32_t(builtin))
3554 << " variable needs to be a 2-component 32-bit int vector. "
3555 << message;
3556 })) {
3557 return error;
3558 }
3559 }
3560
3561 return ValidateFragSizeAtReference(decoration, built_in_inst: inst, referenced_inst: inst, referenced_from_inst: inst);
3562}
3563
3564spv_result_t BuiltInsValidator::ValidateFragSizeAtReference(
3565 const Decoration& decoration, const Instruction& built_in_inst,
3566 const Instruction& referenced_inst,
3567 const Instruction& referenced_from_inst) {
3568
3569 if (spvIsVulkanEnv(env: _.context()->target_env)) {
3570 const spv::BuiltIn builtin = spv::BuiltIn(decoration.params()[0]);
3571 const spv::StorageClass storage_class = GetStorageClass(inst: referenced_from_inst);
3572 if (storage_class != spv::StorageClass::Max &&
3573 storage_class != spv::StorageClass::Input) {
3574 uint32_t vuid = GetVUIDForBuiltin(builtIn: builtin, type: VUIDErrorStorageClass);
3575 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
3576 << _.VkErrorID(id: vuid) << spvLogStringForEnv(env: _.context()->target_env)
3577 << " spec allows BuiltIn "
3578 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN, operand: uint32_t(builtin))
3579 << " to be only used for variables with Input storage class. "
3580 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
3581 referenced_from_inst)
3582 << " " << GetStorageClassDesc(inst: referenced_from_inst);
3583 }
3584
3585 for (const spv::ExecutionModel execution_model : execution_models_) {
3586 if (execution_model != spv::ExecutionModel::Fragment) {
3587 uint32_t vuid = GetVUIDForBuiltin(builtIn: builtin, type: VUIDErrorExecutionModel);
3588 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
3589 << _.VkErrorID(id: vuid)
3590 << spvLogStringForEnv(env: _.context()->target_env)
3591 << " spec allows BuiltIn "
3592 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN, operand: uint32_t(builtin))
3593 << " to be used only with Fragment execution model. "
3594 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
3595 referenced_from_inst, execution_model);
3596 }
3597 }
3598 }
3599
3600 if (function_id_ == 0) {
3601 // Propagate this rule to all dependant ids in the global scope.
3602 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(x: std::bind(
3603 f: &BuiltInsValidator::ValidateFragSizeAtReference, bound_args: this, bound_args: decoration,
3604 bound_args: built_in_inst, bound_args: referenced_from_inst, bound_args: std::placeholders::_1));
3605 }
3606
3607 return SPV_SUCCESS;
3608}
3609
3610spv_result_t BuiltInsValidator::ValidateFragStencilRefAtDefinition(const Decoration& decoration,
3611 const Instruction& inst) {
3612 if (spvIsVulkanEnv(env: _.context()->target_env)) {
3613 const spv::BuiltIn builtin = spv::BuiltIn(decoration.params()[0]);
3614 if (spv_result_t error = ValidateI(
3615 decoration, inst,
3616 diag: [this, &inst, &builtin](const std::string& message) -> spv_result_t {
3617 uint32_t vuid = GetVUIDForBuiltin(builtIn: builtin, type: VUIDErrorType);
3618 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &inst)
3619 << _.VkErrorID(id: vuid) << "According to the "
3620 << spvLogStringForEnv(env: _.context()->target_env)
3621 << " spec BuiltIn "
3622 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN,
3623 operand: uint32_t(builtin))
3624 << " variable needs to be a int scalar. "
3625 << message;
3626 })) {
3627 return error;
3628 }
3629 }
3630
3631 return ValidateFragStencilRefAtReference(decoration, built_in_inst: inst, referenced_inst: inst, referenced_from_inst: inst);
3632}
3633
3634spv_result_t BuiltInsValidator::ValidateFragStencilRefAtReference(
3635 const Decoration& decoration, const Instruction& built_in_inst,
3636 const Instruction& referenced_inst,
3637 const Instruction& referenced_from_inst) {
3638
3639 if (spvIsVulkanEnv(env: _.context()->target_env)) {
3640 const spv::BuiltIn builtin = spv::BuiltIn(decoration.params()[0]);
3641 const spv::StorageClass storage_class = GetStorageClass(inst: referenced_from_inst);
3642 if (storage_class != spv::StorageClass::Max &&
3643 storage_class != spv::StorageClass::Output) {
3644 uint32_t vuid = GetVUIDForBuiltin(builtIn: builtin, type: VUIDErrorStorageClass);
3645 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
3646 << _.VkErrorID(id: vuid) << spvLogStringForEnv(env: _.context()->target_env)
3647 << " spec allows BuiltIn "
3648 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN, operand: uint32_t(builtin))
3649 << " to be only used for variables with Output storage class. "
3650 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
3651 referenced_from_inst)
3652 << " " << GetStorageClassDesc(inst: referenced_from_inst);
3653 }
3654
3655 for (const spv::ExecutionModel execution_model : execution_models_) {
3656 if (execution_model != spv::ExecutionModel::Fragment) {
3657 uint32_t vuid = GetVUIDForBuiltin(builtIn: builtin, type: VUIDErrorExecutionModel);
3658 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
3659 << _.VkErrorID(id: vuid)
3660 << spvLogStringForEnv(env: _.context()->target_env)
3661 << " spec allows BuiltIn "
3662 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN, operand: uint32_t(builtin))
3663 << " to be used only with Fragment execution model. "
3664 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
3665 referenced_from_inst, execution_model);
3666 }
3667 }
3668 }
3669
3670 if (function_id_ == 0) {
3671 // Propagate this rule to all dependant ids in the global scope.
3672 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(x: std::bind(
3673 f: &BuiltInsValidator::ValidateFragStencilRefAtReference, bound_args: this, bound_args: decoration,
3674 bound_args: built_in_inst, bound_args: referenced_from_inst, bound_args: std::placeholders::_1));
3675 }
3676
3677 return SPV_SUCCESS;
3678}
3679
3680spv_result_t BuiltInsValidator::ValidateFullyCoveredAtDefinition(const Decoration& decoration,
3681 const Instruction& inst) {
3682 if (spvIsVulkanEnv(env: _.context()->target_env)) {
3683 const spv::BuiltIn builtin = spv::BuiltIn(decoration.params()[0]);
3684 if (spv_result_t error = ValidateBool(
3685 decoration, inst,
3686 diag: [this, &inst, &builtin](const std::string& message) -> spv_result_t {
3687 uint32_t vuid = GetVUIDForBuiltin(builtIn: builtin, type: VUIDErrorType);
3688 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &inst)
3689 << _.VkErrorID(id: vuid) << "According to the "
3690 << spvLogStringForEnv(env: _.context()->target_env)
3691 << " spec BuiltIn "
3692 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN,
3693 operand: uint32_t(builtin))
3694 << " variable needs to be a bool scalar. "
3695 << message;
3696 })) {
3697 return error;
3698 }
3699 }
3700
3701 return ValidateFullyCoveredAtReference(decoration, built_in_inst: inst, referenced_inst: inst, referenced_from_inst: inst);
3702}
3703
3704spv_result_t BuiltInsValidator::ValidateFullyCoveredAtReference(
3705 const Decoration& decoration, const Instruction& built_in_inst,
3706 const Instruction& referenced_inst,
3707 const Instruction& referenced_from_inst) {
3708
3709 if (spvIsVulkanEnv(env: _.context()->target_env)) {
3710 const spv::BuiltIn builtin = spv::BuiltIn(decoration.params()[0]);
3711 const spv::StorageClass storage_class = GetStorageClass(inst: referenced_from_inst);
3712 if (storage_class != spv::StorageClass::Max &&
3713 storage_class != spv::StorageClass::Input) {
3714 uint32_t vuid = GetVUIDForBuiltin(builtIn: builtin, type: VUIDErrorStorageClass);
3715 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
3716 << _.VkErrorID(id: vuid) << spvLogStringForEnv(env: _.context()->target_env)
3717 << " spec allows BuiltIn "
3718 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN, operand: uint32_t(builtin))
3719 << " to be only used for variables with Input storage class. "
3720 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
3721 referenced_from_inst)
3722 << " " << GetStorageClassDesc(inst: referenced_from_inst);
3723 }
3724
3725 for (const spv::ExecutionModel execution_model : execution_models_) {
3726 if (execution_model != spv::ExecutionModel::Fragment) {
3727 uint32_t vuid = GetVUIDForBuiltin(builtIn: builtin, type: VUIDErrorExecutionModel);
3728 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
3729 << _.VkErrorID(id: vuid)
3730 << spvLogStringForEnv(env: _.context()->target_env)
3731 << " spec allows BuiltIn "
3732 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN, operand: uint32_t(builtin))
3733 << " to be used only with Fragment execution model. "
3734 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
3735 referenced_from_inst, execution_model);
3736 }
3737 }
3738 }
3739
3740 if (function_id_ == 0) {
3741 // Propagate this rule to all dependant ids in the global scope.
3742 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(x: std::bind(
3743 f: &BuiltInsValidator::ValidateFullyCoveredAtReference, bound_args: this, bound_args: decoration,
3744 bound_args: built_in_inst, bound_args: referenced_from_inst, bound_args: std::placeholders::_1));
3745 }
3746
3747 return SPV_SUCCESS;
3748}
3749
3750spv_result_t BuiltInsValidator::ValidateNVSMOrARMCoreBuiltinsAtDefinition(
3751 const Decoration& decoration, const Instruction& inst) {
3752 if (spvIsVulkanEnv(env: _.context()->target_env)) {
3753 if (spv_result_t error = ValidateI32(
3754 decoration, inst,
3755 diag: [this, &inst,
3756 &decoration](const std::string& message) -> spv_result_t {
3757 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &inst)
3758 << "According to the "
3759 << spvLogStringForEnv(env: _.context()->target_env)
3760 << " spec BuiltIn "
3761 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN,
3762 operand: decoration.params()[0])
3763 << " variable needs to be a 32-bit int scalar. "
3764 << message;
3765 })) {
3766 return error;
3767 }
3768 }
3769
3770 // Seed at reference checks with this built-in.
3771 return ValidateNVSMOrARMCoreBuiltinsAtReference(decoration, built_in_inst: inst, referenced_inst: inst, referenced_from_inst: inst);
3772}
3773
3774spv_result_t BuiltInsValidator::ValidateNVSMOrARMCoreBuiltinsAtReference(
3775 const Decoration& decoration, const Instruction& built_in_inst,
3776 const Instruction& referenced_inst,
3777 const Instruction& referenced_from_inst) {
3778 if (spvIsVulkanEnv(env: _.context()->target_env)) {
3779 const spv::StorageClass storage_class = GetStorageClass(inst: referenced_from_inst);
3780 if (storage_class != spv::StorageClass::Max &&
3781 storage_class != spv::StorageClass::Input) {
3782 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
3783 << spvLogStringForEnv(env: _.context()->target_env)
3784 << " spec allows BuiltIn "
3785 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN,
3786 operand: decoration.params()[0])
3787 << " to be only used for "
3788 "variables with Input storage class. "
3789 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
3790 referenced_from_inst)
3791 << " " << GetStorageClassDesc(inst: referenced_from_inst);
3792 }
3793 }
3794
3795 if (function_id_ == 0) {
3796 // Propagate this rule to all dependant ids in the global scope.
3797 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(x: std::bind(
3798 f: &BuiltInsValidator::ValidateNVSMOrARMCoreBuiltinsAtReference, bound_args: this, bound_args: decoration,
3799 bound_args: built_in_inst, bound_args: referenced_from_inst, bound_args: std::placeholders::_1));
3800 }
3801
3802 return SPV_SUCCESS;
3803}
3804
3805spv_result_t BuiltInsValidator::ValidatePrimitiveShadingRateAtDefinition(
3806 const Decoration& decoration, const Instruction& inst) {
3807 if (spvIsVulkanEnv(env: _.context()->target_env)) {
3808 if (spv_result_t error = ValidateI32(
3809 decoration, inst,
3810 diag: [this, &inst,
3811 &decoration](const std::string& message) -> spv_result_t {
3812 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &inst)
3813 << _.VkErrorID(id: 4486)
3814 << "According to the Vulkan spec BuiltIn "
3815 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN,
3816 operand: decoration.params()[0])
3817 << " variable needs to be a 32-bit int scalar. "
3818 << message;
3819 })) {
3820 return error;
3821 }
3822 }
3823
3824 // Seed at reference checks with this built-in.
3825 return ValidatePrimitiveShadingRateAtReference(decoration, built_in_inst: inst, referenced_inst: inst, referenced_from_inst: inst);
3826}
3827
3828spv_result_t BuiltInsValidator::ValidatePrimitiveShadingRateAtReference(
3829 const Decoration& decoration, const Instruction& built_in_inst,
3830 const Instruction& referenced_inst,
3831 const Instruction& referenced_from_inst) {
3832 if (spvIsVulkanEnv(env: _.context()->target_env)) {
3833 const spv::StorageClass storage_class = GetStorageClass(inst: referenced_from_inst);
3834 if (storage_class != spv::StorageClass::Max &&
3835 storage_class != spv::StorageClass::Output) {
3836 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
3837 << _.VkErrorID(id: 4485) << "Vulkan spec allows BuiltIn "
3838 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN,
3839 operand: decoration.params()[0])
3840 << " to be only used for variables with Output storage class. "
3841 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
3842 referenced_from_inst)
3843 << " " << GetStorageClassDesc(inst: referenced_from_inst);
3844 }
3845
3846 for (const spv::ExecutionModel execution_model : execution_models_) {
3847 switch (execution_model) {
3848 case spv::ExecutionModel::Vertex:
3849 case spv::ExecutionModel::Geometry:
3850 case spv::ExecutionModel::MeshNV:
3851 case spv::ExecutionModel::MeshEXT:
3852 break;
3853 default: {
3854 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
3855 << _.VkErrorID(id: 4484) << "Vulkan spec allows BuiltIn "
3856 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN,
3857 operand: decoration.params()[0])
3858 << " to be used only with Vertex, Geometry, or MeshNV "
3859 "execution models. "
3860 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
3861 referenced_from_inst, execution_model);
3862 }
3863 }
3864 }
3865 }
3866
3867 if (function_id_ == 0) {
3868 // Propagate this rule to all dependant ids in the global scope.
3869 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
3870 x: std::bind(f: &BuiltInsValidator::ValidatePrimitiveShadingRateAtReference,
3871 bound_args: this, bound_args: decoration, bound_args: built_in_inst, bound_args: referenced_from_inst,
3872 bound_args: std::placeholders::_1));
3873 }
3874
3875 return SPV_SUCCESS;
3876}
3877
3878spv_result_t BuiltInsValidator::ValidateShadingRateAtDefinition(
3879 const Decoration& decoration, const Instruction& inst) {
3880 if (spvIsVulkanEnv(env: _.context()->target_env)) {
3881 if (spv_result_t error = ValidateI32(
3882 decoration, inst,
3883 diag: [this, &inst,
3884 &decoration](const std::string& message) -> spv_result_t {
3885 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &inst)
3886 << _.VkErrorID(id: 4492)
3887 << "According to the Vulkan spec BuiltIn "
3888 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN,
3889 operand: decoration.params()[0])
3890 << " variable needs to be a 32-bit int scalar. "
3891 << message;
3892 })) {
3893 return error;
3894 }
3895 }
3896
3897 // Seed at reference checks with this built-in.
3898 return ValidateShadingRateAtReference(decoration, built_in_inst: inst, referenced_inst: inst, referenced_from_inst: inst);
3899}
3900
3901spv_result_t BuiltInsValidator::ValidateShadingRateAtReference(
3902 const Decoration& decoration, const Instruction& built_in_inst,
3903 const Instruction& referenced_inst,
3904 const Instruction& referenced_from_inst) {
3905 if (spvIsVulkanEnv(env: _.context()->target_env)) {
3906 const spv::StorageClass storage_class = GetStorageClass(inst: referenced_from_inst);
3907 if (storage_class != spv::StorageClass::Max &&
3908 storage_class != spv::StorageClass::Input) {
3909 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
3910 << _.VkErrorID(id: 4491) << "Vulkan spec allows BuiltIn "
3911 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN,
3912 operand: decoration.params()[0])
3913 << " to be only used for variables with Input storage class. "
3914 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
3915 referenced_from_inst)
3916 << " " << GetStorageClassDesc(inst: referenced_from_inst);
3917 }
3918
3919 for (const spv::ExecutionModel execution_model : execution_models_) {
3920 if (execution_model != spv::ExecutionModel::Fragment) {
3921 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
3922 << _.VkErrorID(id: 4490) << "Vulkan spec allows BuiltIn "
3923 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN,
3924 operand: decoration.params()[0])
3925 << " to be used only with the Fragment execution model. "
3926 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
3927 referenced_from_inst, execution_model);
3928 }
3929 }
3930 }
3931
3932 if (function_id_ == 0) {
3933 // Propagate this rule to all dependant ids in the global scope.
3934 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(x: std::bind(
3935 f: &BuiltInsValidator::ValidateShadingRateAtReference, bound_args: this, bound_args: decoration,
3936 bound_args: built_in_inst, bound_args: referenced_from_inst, bound_args: std::placeholders::_1));
3937 }
3938
3939 return SPV_SUCCESS;
3940}
3941
3942spv_result_t BuiltInsValidator::ValidateRayTracingBuiltinsAtDefinition(
3943 const Decoration& decoration, const Instruction& inst) {
3944 if (spvIsVulkanEnv(env: _.context()->target_env)) {
3945 const spv::BuiltIn builtin = spv::BuiltIn(decoration.params()[0]);
3946 switch (builtin) {
3947 case spv::BuiltIn::HitTNV:
3948 case spv::BuiltIn::RayTminKHR:
3949 case spv::BuiltIn::RayTmaxKHR:
3950 // f32 scalar
3951 if (spv_result_t error = ValidateF32(
3952 decoration, inst,
3953 diag: [this, &inst,
3954 builtin](const std::string& message) -> spv_result_t {
3955 uint32_t vuid = GetVUIDForBuiltin(builtIn: builtin, type: VUIDErrorType);
3956 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &inst)
3957 << _.VkErrorID(id: vuid)
3958 << "According to the Vulkan spec BuiltIn "
3959 << _.grammar().lookupOperandName(
3960 type: SPV_OPERAND_TYPE_BUILT_IN, operand: uint32_t(builtin))
3961 << " variable needs to be a 32-bit float scalar. "
3962 << message;
3963 })) {
3964 return error;
3965 }
3966 break;
3967 case spv::BuiltIn::HitKindKHR:
3968 case spv::BuiltIn::InstanceCustomIndexKHR:
3969 case spv::BuiltIn::InstanceId:
3970 case spv::BuiltIn::RayGeometryIndexKHR:
3971 case spv::BuiltIn::IncomingRayFlagsKHR:
3972 case spv::BuiltIn::CullMaskKHR:
3973 // i32 scalar
3974 if (spv_result_t error = ValidateI32(
3975 decoration, inst,
3976 diag: [this, &inst,
3977 builtin](const std::string& message) -> spv_result_t {
3978 uint32_t vuid = GetVUIDForBuiltin(builtIn: builtin, type: VUIDErrorType);
3979 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &inst)
3980 << _.VkErrorID(id: vuid)
3981 << "According to the Vulkan spec BuiltIn "
3982 << _.grammar().lookupOperandName(
3983 type: SPV_OPERAND_TYPE_BUILT_IN, operand: uint32_t(builtin))
3984 << " variable needs to be a 32-bit int scalar. "
3985 << message;
3986 })) {
3987 return error;
3988 }
3989 break;
3990 case spv::BuiltIn::ObjectRayDirectionKHR:
3991 case spv::BuiltIn::ObjectRayOriginKHR:
3992 case spv::BuiltIn::WorldRayDirectionKHR:
3993 case spv::BuiltIn::WorldRayOriginKHR:
3994 // f32 vec3
3995 if (spv_result_t error = ValidateF32Vec(
3996 decoration, inst, num_components: 3,
3997 diag: [this, &inst,
3998 builtin](const std::string& message) -> spv_result_t {
3999 uint32_t vuid = GetVUIDForBuiltin(builtIn: builtin, type: VUIDErrorType);
4000 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &inst)
4001 << _.VkErrorID(id: vuid)
4002 << "According to the Vulkan spec BuiltIn "
4003 << _.grammar().lookupOperandName(
4004 type: SPV_OPERAND_TYPE_BUILT_IN, operand: uint32_t(builtin))
4005 << " variable needs to be a 3-component 32-bit float "
4006 "vector. "
4007 << message;
4008 })) {
4009 return error;
4010 }
4011 break;
4012 case spv::BuiltIn::LaunchIdKHR:
4013 case spv::BuiltIn::LaunchSizeKHR:
4014 // i32 vec3
4015 if (spv_result_t error = ValidateI32Vec(
4016 decoration, inst, num_components: 3,
4017 diag: [this, &inst,
4018 builtin](const std::string& message) -> spv_result_t {
4019 uint32_t vuid = GetVUIDForBuiltin(builtIn: builtin, type: VUIDErrorType);
4020 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &inst)
4021 << _.VkErrorID(id: vuid)
4022 << "According to the Vulkan spec BuiltIn "
4023 << _.grammar().lookupOperandName(
4024 type: SPV_OPERAND_TYPE_BUILT_IN, operand: uint32_t(builtin))
4025 << " variable needs to be a 3-component 32-bit int "
4026 "vector. "
4027 << message;
4028 })) {
4029 return error;
4030 }
4031 break;
4032 case spv::BuiltIn::ObjectToWorldKHR:
4033 case spv::BuiltIn::WorldToObjectKHR:
4034 // f32 mat4x3
4035 if (spv_result_t error = ValidateF32Mat(
4036 decoration, inst, req_num_rows: 3, req_num_columns: 4,
4037 diag: [this, &inst,
4038 builtin](const std::string& message) -> spv_result_t {
4039 uint32_t vuid = GetVUIDForBuiltin(builtIn: builtin, type: VUIDErrorType);
4040 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &inst)
4041 << _.VkErrorID(id: vuid)
4042 << "According to the Vulkan spec BuiltIn "
4043 << _.grammar().lookupOperandName(
4044 type: SPV_OPERAND_TYPE_BUILT_IN, operand: uint32_t(builtin))
4045 << " variable needs to be a matrix with"
4046 << " 4 columns of 3-component vectors of 32-bit "
4047 "floats. "
4048 << message;
4049 })) {
4050 return error;
4051 }
4052 break;
4053 default:
4054 assert(0 && "Unexpected ray tracing builtin");
4055 break;
4056 }
4057 }
4058
4059 // Seed at reference checks with this built-in.
4060 return ValidateRayTracingBuiltinsAtReference(decoration, built_in_inst: inst, referenced_inst: inst, referenced_from_inst: inst);
4061}
4062
4063spv_result_t BuiltInsValidator::ValidateRayTracingBuiltinsAtReference(
4064 const Decoration& decoration, const Instruction& built_in_inst,
4065 const Instruction& referenced_inst,
4066 const Instruction& referenced_from_inst) {
4067 if (spvIsVulkanEnv(env: _.context()->target_env)) {
4068 const spv::BuiltIn builtin = spv::BuiltIn(decoration.params()[0]);
4069 const spv::StorageClass storage_class = GetStorageClass(inst: referenced_from_inst);
4070 if (storage_class != spv::StorageClass::Max &&
4071 storage_class != spv::StorageClass::Input) {
4072 uint32_t vuid = GetVUIDForBuiltin(builtIn: builtin, type: VUIDErrorStorageClass);
4073 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
4074 << _.VkErrorID(id: vuid) << "Vulkan spec allows BuiltIn "
4075 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN,
4076 operand: decoration.params()[0])
4077 << " to be only used for variables with Input storage class. "
4078 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
4079 referenced_from_inst)
4080 << " " << GetStorageClassDesc(inst: referenced_from_inst);
4081 }
4082
4083 for (const spv::ExecutionModel execution_model : execution_models_) {
4084 if (!IsExecutionModelValidForRtBuiltIn(builtin, stage: execution_model)) {
4085 uint32_t vuid = GetVUIDForBuiltin(builtIn: builtin, type: VUIDErrorExecutionModel);
4086 return _.diag(error_code: SPV_ERROR_INVALID_DATA, inst: &referenced_from_inst)
4087 << _.VkErrorID(id: vuid) << "Vulkan spec does not allow BuiltIn "
4088 << _.grammar().lookupOperandName(type: SPV_OPERAND_TYPE_BUILT_IN,
4089 operand: decoration.params()[0])
4090 << " to be used with the execution model "
4091 << _.grammar().lookupOperandName(
4092 type: SPV_OPERAND_TYPE_EXECUTION_MODEL, operand: uint32_t(execution_model))
4093 << ".\n"
4094 << GetReferenceDesc(decoration, built_in_inst, referenced_inst,
4095 referenced_from_inst, execution_model);
4096 }
4097 }
4098 }
4099
4100 if (function_id_ == 0) {
4101 // Propagate this rule to all dependant ids in the global scope.
4102 id_to_at_reference_checks_[referenced_from_inst.id()].push_back(
4103 x: std::bind(f: &BuiltInsValidator::ValidateRayTracingBuiltinsAtReference,
4104 bound_args: this, bound_args: decoration, bound_args: built_in_inst, bound_args: referenced_from_inst,
4105 bound_args: std::placeholders::_1));
4106 }
4107
4108 return SPV_SUCCESS;
4109}
4110
4111spv_result_t BuiltInsValidator::ValidateSingleBuiltInAtDefinition(
4112 const Decoration& decoration, const Instruction& inst) {
4113 const spv::BuiltIn label = spv::BuiltIn(decoration.params()[0]);
4114
4115 if (!spvIsVulkanEnv(env: _.context()->target_env)) {
4116 // Early return. All currently implemented rules are based on Vulkan spec.
4117 //
4118 // TODO: If you are adding validation rules for environments other than
4119 // Vulkan (or general rules which are not environment independent), then
4120 // you need to modify or remove this condition. Consider also adding early
4121 // returns into BuiltIn-specific rules, so that the system doesn't spawn new
4122 // rules which don't do anything.
4123 return SPV_SUCCESS;
4124 }
4125
4126 // If you are adding a new BuiltIn enum, please register it here.
4127 // If the newly added enum has validation rules associated with it
4128 // consider leaving a TODO and/or creating an issue.
4129 switch (label) {
4130 case spv::BuiltIn::ClipDistance:
4131 case spv::BuiltIn::CullDistance: {
4132 return ValidateClipOrCullDistanceAtDefinition(decoration, inst);
4133 }
4134 case spv::BuiltIn::FragCoord: {
4135 return ValidateFragCoordAtDefinition(decoration, inst);
4136 }
4137 case spv::BuiltIn::FragDepth: {
4138 return ValidateFragDepthAtDefinition(decoration, inst);
4139 }
4140 case spv::BuiltIn::FrontFacing: {
4141 return ValidateFrontFacingAtDefinition(decoration, inst);
4142 }
4143 case spv::BuiltIn::GlobalInvocationId:
4144 case spv::BuiltIn::LocalInvocationId:
4145 case spv::BuiltIn::NumWorkgroups:
4146 case spv::BuiltIn::WorkgroupId: {
4147 return ValidateComputeShaderI32Vec3InputAtDefinition(decoration, inst);
4148 }
4149 case spv::BuiltIn::BaryCoordKHR:
4150 case spv::BuiltIn::BaryCoordNoPerspKHR: {
4151 return ValidateFragmentShaderF32Vec3InputAtDefinition(decoration, inst);
4152 }
4153 case spv::BuiltIn::HelperInvocation: {
4154 return ValidateHelperInvocationAtDefinition(decoration, inst);
4155 }
4156 case spv::BuiltIn::InvocationId: {
4157 return ValidateInvocationIdAtDefinition(decoration, inst);
4158 }
4159 case spv::BuiltIn::InstanceIndex: {
4160 return ValidateInstanceIndexAtDefinition(decoration, inst);
4161 }
4162 case spv::BuiltIn::Layer:
4163 case spv::BuiltIn::ViewportIndex: {
4164 return ValidateLayerOrViewportIndexAtDefinition(decoration, inst);
4165 }
4166 case spv::BuiltIn::PatchVertices: {
4167 return ValidatePatchVerticesAtDefinition(decoration, inst);
4168 }
4169 case spv::BuiltIn::PointCoord: {
4170 return ValidatePointCoordAtDefinition(decoration, inst);
4171 }
4172 case spv::BuiltIn::PointSize: {
4173 return ValidatePointSizeAtDefinition(decoration, inst);
4174 }
4175 case spv::BuiltIn::Position: {
4176 return ValidatePositionAtDefinition(decoration, inst);
4177 }
4178 case spv::BuiltIn::PrimitiveId: {
4179 return ValidatePrimitiveIdAtDefinition(decoration, inst);
4180 }
4181 case spv::BuiltIn::SampleId: {
4182 return ValidateSampleIdAtDefinition(decoration, inst);
4183 }
4184 case spv::BuiltIn::SampleMask: {
4185 return ValidateSampleMaskAtDefinition(decoration, inst);
4186 }
4187 case spv::BuiltIn::SamplePosition: {
4188 return ValidateSamplePositionAtDefinition(decoration, inst);
4189 }
4190 case spv::BuiltIn::SubgroupId:
4191 case spv::BuiltIn::NumSubgroups: {
4192 return ValidateComputeI32InputAtDefinition(decoration, inst);
4193 }
4194 case spv::BuiltIn::SubgroupLocalInvocationId:
4195 case spv::BuiltIn::SubgroupSize: {
4196 return ValidateI32InputAtDefinition(decoration, inst);
4197 }
4198 case spv::BuiltIn::SubgroupEqMask:
4199 case spv::BuiltIn::SubgroupGeMask:
4200 case spv::BuiltIn::SubgroupGtMask:
4201 case spv::BuiltIn::SubgroupLeMask:
4202 case spv::BuiltIn::SubgroupLtMask: {
4203 return ValidateI32Vec4InputAtDefinition(decoration, inst);
4204 }
4205 case spv::BuiltIn::TessCoord: {
4206 return ValidateTessCoordAtDefinition(decoration, inst);
4207 }
4208 case spv::BuiltIn::TessLevelOuter: {
4209 return ValidateTessLevelOuterAtDefinition(decoration, inst);
4210 }
4211 case spv::BuiltIn::TessLevelInner: {
4212 return ValidateTessLevelInnerAtDefinition(decoration, inst);
4213 }
4214 case spv::BuiltIn::VertexIndex: {
4215 return ValidateVertexIndexAtDefinition(decoration, inst);
4216 }
4217 case spv::BuiltIn::WorkgroupSize: {
4218 return ValidateWorkgroupSizeAtDefinition(decoration, inst);
4219 }
4220 case spv::BuiltIn::VertexId: {
4221 return ValidateVertexIdAtDefinition(decoration, inst);
4222 }
4223 case spv::BuiltIn::LocalInvocationIndex: {
4224 return ValidateLocalInvocationIndexAtDefinition(decoration, inst);
4225 }
4226 case spv::BuiltIn::CoreIDARM:
4227 case spv::BuiltIn::CoreCountARM:
4228 case spv::BuiltIn::CoreMaxIDARM:
4229 case spv::BuiltIn::WarpIDARM:
4230 case spv::BuiltIn::WarpMaxIDARM:
4231 case spv::BuiltIn::WarpsPerSMNV:
4232 case spv::BuiltIn::SMCountNV:
4233 case spv::BuiltIn::WarpIDNV:
4234 case spv::BuiltIn::SMIDNV: {
4235 return ValidateNVSMOrARMCoreBuiltinsAtDefinition(decoration, inst);
4236 }
4237 case spv::BuiltIn::BaseInstance:
4238 case spv::BuiltIn::BaseVertex: {
4239 return ValidateBaseInstanceOrVertexAtDefinition(decoration, inst);
4240 }
4241 case spv::BuiltIn::DrawIndex: {
4242 return ValidateDrawIndexAtDefinition(decoration, inst);
4243 }
4244 case spv::BuiltIn::ViewIndex: {
4245 return ValidateViewIndexAtDefinition(decoration, inst);
4246 }
4247 case spv::BuiltIn::DeviceIndex: {
4248 return ValidateDeviceIndexAtDefinition(decoration, inst);
4249 }
4250 case spv::BuiltIn::FragInvocationCountEXT: {
4251 // alias spv::BuiltIn::InvocationsPerPixelNV
4252 return ValidateFragInvocationCountAtDefinition(decoration, inst);
4253 }
4254 case spv::BuiltIn::FragSizeEXT: {
4255 // alias spv::BuiltIn::FragmentSizeNV
4256 return ValidateFragSizeAtDefinition(decoration, inst);
4257 }
4258 case spv::BuiltIn::FragStencilRefEXT: {
4259 return ValidateFragStencilRefAtDefinition(decoration, inst);
4260 }
4261 case spv::BuiltIn::FullyCoveredEXT:{
4262 return ValidateFullyCoveredAtDefinition(decoration, inst);
4263 }
4264 // Ray tracing builtins
4265 case spv::BuiltIn::HitKindKHR: // alias spv::BuiltIn::HitKindNV
4266 case spv::BuiltIn::HitTNV: // NOT present in KHR
4267 case spv::BuiltIn::InstanceId:
4268 case spv::BuiltIn::LaunchIdKHR: // alias spv::BuiltIn::LaunchIdNV
4269 case spv::BuiltIn::LaunchSizeKHR: // alias spv::BuiltIn::LaunchSizeNV
4270 case spv::BuiltIn::WorldRayOriginKHR: // alias spv::BuiltIn::WorldRayOriginNV
4271 case spv::BuiltIn::WorldRayDirectionKHR: // alias spv::BuiltIn::WorldRayDirectionNV
4272 case spv::BuiltIn::ObjectRayOriginKHR: // alias spv::BuiltIn::ObjectRayOriginNV
4273 case spv::BuiltIn::ObjectRayDirectionKHR: // alias
4274 // spv::BuiltIn::ObjectRayDirectionNV
4275 case spv::BuiltIn::RayTminKHR: // alias spv::BuiltIn::RayTminNV
4276 case spv::BuiltIn::RayTmaxKHR: // alias spv::BuiltIn::RayTmaxNV
4277 case spv::BuiltIn::InstanceCustomIndexKHR: // alias
4278 // spv::BuiltIn::InstanceCustomIndexNV
4279 case spv::BuiltIn::ObjectToWorldKHR: // alias spv::BuiltIn::ObjectToWorldNV
4280 case spv::BuiltIn::WorldToObjectKHR: // alias spv::BuiltIn::WorldToObjectNV
4281 case spv::BuiltIn::IncomingRayFlagsKHR: // alias spv::BuiltIn::IncomingRayFlagsNV
4282 case spv::BuiltIn::RayGeometryIndexKHR: // NOT present in NV
4283 case spv::BuiltIn::CullMaskKHR: {
4284 return ValidateRayTracingBuiltinsAtDefinition(decoration, inst);
4285 }
4286 case spv::BuiltIn::PrimitiveShadingRateKHR: {
4287 return ValidatePrimitiveShadingRateAtDefinition(decoration, inst);
4288 }
4289 case spv::BuiltIn::ShadingRateKHR: {
4290 return ValidateShadingRateAtDefinition(decoration, inst);
4291 }
4292 default:
4293 // No validation rules (for the moment).
4294 break;
4295 }
4296 return SPV_SUCCESS;
4297}
4298
4299spv_result_t BuiltInsValidator::ValidateBuiltInsAtDefinition() {
4300 for (const auto& kv : _.id_decorations()) {
4301 const uint32_t id = kv.first;
4302 const auto& decorations = kv.second;
4303 if (decorations.empty()) {
4304 continue;
4305 }
4306
4307 const Instruction* inst = _.FindDef(id);
4308 assert(inst);
4309
4310 for (const auto& decoration : kv.second) {
4311 if (decoration.dec_type() != spv::Decoration::BuiltIn) {
4312 continue;
4313 }
4314
4315 if (spv_result_t error =
4316 ValidateSingleBuiltInAtDefinition(decoration, inst: *inst)) {
4317 return error;
4318 }
4319 }
4320 }
4321
4322 return SPV_SUCCESS;
4323}
4324
4325spv_result_t BuiltInsValidator::Run() {
4326 // First pass: validate all built-ins at definition and seed
4327 // id_to_at_reference_checks_ with built-ins.
4328 if (auto error = ValidateBuiltInsAtDefinition()) {
4329 return error;
4330 }
4331
4332 if (id_to_at_reference_checks_.empty()) {
4333 // No validation tasks were seeded. Nothing else to do.
4334 return SPV_SUCCESS;
4335 }
4336
4337 // Second pass: validate every id reference in the module using
4338 // rules in id_to_at_reference_checks_.
4339 for (const Instruction& inst : _.ordered_instructions()) {
4340 Update(inst);
4341
4342 std::set<uint32_t> already_checked;
4343
4344 for (const auto& operand : inst.operands()) {
4345 if (!spvIsIdType(type: operand.type)) {
4346 // Not id.
4347 continue;
4348 }
4349
4350 const uint32_t id = inst.word(index: operand.offset);
4351 if (id == inst.id()) {
4352 // No need to check result id.
4353 continue;
4354 }
4355
4356 if (!already_checked.insert(v: id).second) {
4357 // The instruction has already referenced this id.
4358 continue;
4359 }
4360
4361 // Instruction references the id. Run all checks associated with the id
4362 // on the instruction. id_to_at_reference_checks_ can be modified in the
4363 // process, iterators are safe because it's a tree-based map.
4364 const auto it = id_to_at_reference_checks_.find(k: id);
4365 if (it != id_to_at_reference_checks_.end()) {
4366 for (const auto& check : it->second) {
4367 if (spv_result_t error = check(inst)) {
4368 return error;
4369 }
4370 }
4371 }
4372 }
4373 }
4374
4375 return SPV_SUCCESS;
4376}
4377
4378} // namespace
4379
4380// Validates correctness of built-in variables.
4381spv_result_t ValidateBuiltIns(ValidationState_t& _) {
4382 BuiltInsValidator validator(_);
4383 return validator.Run();
4384}
4385
4386} // namespace val
4387} // namespace spvtools
4388

source code of flutter_engine/third_party/vulkan-deps/spirv-tools/src/source/val/validate_builtins.cpp