• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright (c) 2015-2019 The Khronos Group Inc.
2  * Copyright (c) 2015-2019 Valve Corporation
3  * Copyright (c) 2015-2019 LunarG, Inc.
4  * Copyright (C) 2015-2019 Google Inc.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  * Author: Chris Forbes <chrisf@ijw.co.nz>
19  * Author: Dave Houlton <daveh@lunarg.com>
20  */
21 
22 #include <cinttypes>
23 #include <cassert>
24 #include <chrono>
25 #include <vector>
26 #include <unordered_map>
27 #include <string>
28 #include <sstream>
29 #include <SPIRV/spirv.hpp>
30 #include "vk_loader_platform.h"
31 #include "vk_enum_string_helper.h"
32 #include "vk_layer_data.h"
33 #include "vk_layer_extension_utils.h"
34 #include "vk_layer_utils.h"
35 #include "chassis.h"
36 #include "core_validation.h"
37 #include "shader_validation.h"
38 #include "spirv-tools/libspirv.h"
39 #include "xxhash.h"
40 
add(uint32_t decoration,uint32_t value)41 void decoration_set::add(uint32_t decoration, uint32_t value) {
42     switch (decoration) {
43         case spv::DecorationLocation:
44             flags |= location_bit;
45             location = value;
46             break;
47         case spv::DecorationPatch:
48             flags |= patch_bit;
49             break;
50         case spv::DecorationRelaxedPrecision:
51             flags |= relaxed_precision_bit;
52             break;
53         case spv::DecorationBlock:
54             flags |= block_bit;
55             break;
56         case spv::DecorationBufferBlock:
57             flags |= buffer_block_bit;
58             break;
59         case spv::DecorationComponent:
60             flags |= component_bit;
61             component = value;
62             break;
63         case spv::DecorationInputAttachmentIndex:
64             flags |= input_attachment_index_bit;
65             input_attachment_index = value;
66             break;
67         case spv::DecorationDescriptorSet:
68             flags |= descriptor_set_bit;
69             descriptor_set = value;
70             break;
71         case spv::DecorationBinding:
72             flags |= binding_bit;
73             binding = value;
74             break;
75         case spv::DecorationNonWritable:
76             flags |= nonwritable_bit;
77             break;
78         case spv::DecorationBuiltIn:
79             flags |= builtin_bit;
80             builtin = value;
81             break;
82     }
83 }
84 
85 enum FORMAT_TYPE {
86     FORMAT_TYPE_FLOAT = 1,  // UNORM, SNORM, FLOAT, USCALED, SSCALED, SRGB -- anything we consider float in the shader
87     FORMAT_TYPE_SINT = 2,
88     FORMAT_TYPE_UINT = 4,
89 };
90 
91 typedef std::pair<unsigned, unsigned> location_t;
92 
93 struct shader_stage_attributes {
94     char const *const name;
95     bool arrayed_input;
96     bool arrayed_output;
97     VkShaderStageFlags stage;
98 };
99 
100 static shader_stage_attributes shader_stage_attribs[] = {
101     {"vertex shader", false, false, VK_SHADER_STAGE_VERTEX_BIT},
102     {"tessellation control shader", true, true, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT},
103     {"tessellation evaluation shader", true, false, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT},
104     {"geometry shader", true, false, VK_SHADER_STAGE_GEOMETRY_BIT},
105     {"fragment shader", false, false, VK_SHADER_STAGE_FRAGMENT_BIT},
106 };
107 
108 unsigned ExecutionModelToShaderStageFlagBits(unsigned mode);
109 
110 // SPIRV utility functions
BuildDefIndex()111 void SHADER_MODULE_STATE::BuildDefIndex() {
112     for (auto insn : *this) {
113         switch (insn.opcode()) {
114             // Types
115             case spv::OpTypeVoid:
116             case spv::OpTypeBool:
117             case spv::OpTypeInt:
118             case spv::OpTypeFloat:
119             case spv::OpTypeVector:
120             case spv::OpTypeMatrix:
121             case spv::OpTypeImage:
122             case spv::OpTypeSampler:
123             case spv::OpTypeSampledImage:
124             case spv::OpTypeArray:
125             case spv::OpTypeRuntimeArray:
126             case spv::OpTypeStruct:
127             case spv::OpTypeOpaque:
128             case spv::OpTypePointer:
129             case spv::OpTypeFunction:
130             case spv::OpTypeEvent:
131             case spv::OpTypeDeviceEvent:
132             case spv::OpTypeReserveId:
133             case spv::OpTypeQueue:
134             case spv::OpTypePipe:
135             case spv::OpTypeAccelerationStructureNV:
136             case spv::OpTypeCooperativeMatrixNV:
137                 def_index[insn.word(1)] = insn.offset();
138                 break;
139 
140                 // Fixed constants
141             case spv::OpConstantTrue:
142             case spv::OpConstantFalse:
143             case spv::OpConstant:
144             case spv::OpConstantComposite:
145             case spv::OpConstantSampler:
146             case spv::OpConstantNull:
147                 def_index[insn.word(2)] = insn.offset();
148                 break;
149 
150                 // Specialization constants
151             case spv::OpSpecConstantTrue:
152             case spv::OpSpecConstantFalse:
153             case spv::OpSpecConstant:
154             case spv::OpSpecConstantComposite:
155             case spv::OpSpecConstantOp:
156                 def_index[insn.word(2)] = insn.offset();
157                 break;
158 
159                 // Variables
160             case spv::OpVariable:
161                 def_index[insn.word(2)] = insn.offset();
162                 break;
163 
164                 // Functions
165             case spv::OpFunction:
166                 def_index[insn.word(2)] = insn.offset();
167                 break;
168 
169                 // Decorations
170             case spv::OpDecorate: {
171                 auto targetId = insn.word(1);
172                 decorations[targetId].add(insn.word(2), insn.len() > 3u ? insn.word(3) : 0u);
173             } break;
174             case spv::OpGroupDecorate: {
175                 auto const &src = decorations[insn.word(1)];
176                 for (auto i = 2u; i < insn.len(); i++) decorations[insn.word(i)].merge(src);
177             } break;
178 
179                 // Entry points ... add to the entrypoint table
180             case spv::OpEntryPoint: {
181                 // Entry points do not have an id (the id is the function id) and thus need their own table
182                 auto entrypoint_name = (char const *)&insn.word(3);
183                 auto execution_model = insn.word(1);
184                 auto entrypoint_stage = ExecutionModelToShaderStageFlagBits(execution_model);
185                 entry_points.emplace(entrypoint_name, EntryPoint{insn.offset(), entrypoint_stage});
186                 break;
187             }
188 
189             default:
190                 // We don't care about any other defs for now.
191                 break;
192         }
193     }
194 }
195 
ExecutionModelToShaderStageFlagBits(unsigned mode)196 unsigned ExecutionModelToShaderStageFlagBits(unsigned mode) {
197     switch (mode) {
198         case spv::ExecutionModelVertex:
199             return VK_SHADER_STAGE_VERTEX_BIT;
200         case spv::ExecutionModelTessellationControl:
201             return VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT;
202         case spv::ExecutionModelTessellationEvaluation:
203             return VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
204         case spv::ExecutionModelGeometry:
205             return VK_SHADER_STAGE_GEOMETRY_BIT;
206         case spv::ExecutionModelFragment:
207             return VK_SHADER_STAGE_FRAGMENT_BIT;
208         case spv::ExecutionModelGLCompute:
209             return VK_SHADER_STAGE_COMPUTE_BIT;
210         case spv::ExecutionModelRayGenerationNV:
211             return VK_SHADER_STAGE_RAYGEN_BIT_NV;
212         case spv::ExecutionModelAnyHitNV:
213             return VK_SHADER_STAGE_ANY_HIT_BIT_NV;
214         case spv::ExecutionModelClosestHitNV:
215             return VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV;
216         case spv::ExecutionModelMissNV:
217             return VK_SHADER_STAGE_MISS_BIT_NV;
218         case spv::ExecutionModelIntersectionNV:
219             return VK_SHADER_STAGE_INTERSECTION_BIT_NV;
220         case spv::ExecutionModelCallableNV:
221             return VK_SHADER_STAGE_CALLABLE_BIT_NV;
222         case spv::ExecutionModelTaskNV:
223             return VK_SHADER_STAGE_TASK_BIT_NV;
224         case spv::ExecutionModelMeshNV:
225             return VK_SHADER_STAGE_MESH_BIT_NV;
226         default:
227             return 0;
228     }
229 }
230 
FindEntrypoint(SHADER_MODULE_STATE const * src,char const * name,VkShaderStageFlagBits stageBits)231 static spirv_inst_iter FindEntrypoint(SHADER_MODULE_STATE const *src, char const *name, VkShaderStageFlagBits stageBits) {
232     auto range = src->entry_points.equal_range(name);
233     for (auto it = range.first; it != range.second; ++it) {
234         if (it->second.stage == stageBits) {
235             return src->at(it->second.offset);
236         }
237     }
238     return src->end();
239 }
240 
StorageClassName(unsigned sc)241 static char const *StorageClassName(unsigned sc) {
242     switch (sc) {
243         case spv::StorageClassInput:
244             return "input";
245         case spv::StorageClassOutput:
246             return "output";
247         case spv::StorageClassUniformConstant:
248             return "const uniform";
249         case spv::StorageClassUniform:
250             return "uniform";
251         case spv::StorageClassWorkgroup:
252             return "workgroup local";
253         case spv::StorageClassCrossWorkgroup:
254             return "workgroup global";
255         case spv::StorageClassPrivate:
256             return "private global";
257         case spv::StorageClassFunction:
258             return "function";
259         case spv::StorageClassGeneric:
260             return "generic";
261         case spv::StorageClassAtomicCounter:
262             return "atomic counter";
263         case spv::StorageClassImage:
264             return "image";
265         case spv::StorageClassPushConstant:
266             return "push constant";
267         case spv::StorageClassStorageBuffer:
268             return "storage buffer";
269         default:
270             return "unknown";
271     }
272 }
273 
274 // Get the value of an integral constant
GetConstantValue(SHADER_MODULE_STATE const * src,unsigned id)275 unsigned GetConstantValue(SHADER_MODULE_STATE const *src, unsigned id) {
276     auto value = src->get_def(id);
277     assert(value != src->end());
278 
279     if (value.opcode() != spv::OpConstant) {
280         // TODO: Either ensure that the specialization transform is already performed on a module we're
281         //       considering here, OR -- specialize on the fly now.
282         return 1;
283     }
284 
285     return value.word(3);
286 }
287 
DescribeTypeInner(std::ostringstream & ss,SHADER_MODULE_STATE const * src,unsigned type)288 static void DescribeTypeInner(std::ostringstream &ss, SHADER_MODULE_STATE const *src, unsigned type) {
289     auto insn = src->get_def(type);
290     assert(insn != src->end());
291 
292     switch (insn.opcode()) {
293         case spv::OpTypeBool:
294             ss << "bool";
295             break;
296         case spv::OpTypeInt:
297             ss << (insn.word(3) ? 's' : 'u') << "int" << insn.word(2);
298             break;
299         case spv::OpTypeFloat:
300             ss << "float" << insn.word(2);
301             break;
302         case spv::OpTypeVector:
303             ss << "vec" << insn.word(3) << " of ";
304             DescribeTypeInner(ss, src, insn.word(2));
305             break;
306         case spv::OpTypeMatrix:
307             ss << "mat" << insn.word(3) << " of ";
308             DescribeTypeInner(ss, src, insn.word(2));
309             break;
310         case spv::OpTypeArray:
311             ss << "arr[" << GetConstantValue(src, insn.word(3)) << "] of ";
312             DescribeTypeInner(ss, src, insn.word(2));
313             break;
314         case spv::OpTypeRuntimeArray:
315             ss << "runtime arr[] of ";
316             DescribeTypeInner(ss, src, insn.word(2));
317             break;
318         case spv::OpTypePointer:
319             ss << "ptr to " << StorageClassName(insn.word(2)) << " ";
320             DescribeTypeInner(ss, src, insn.word(3));
321             break;
322         case spv::OpTypeStruct: {
323             ss << "struct of (";
324             for (unsigned i = 2; i < insn.len(); i++) {
325                 DescribeTypeInner(ss, src, insn.word(i));
326                 if (i == insn.len() - 1) {
327                     ss << ")";
328                 } else {
329                     ss << ", ";
330                 }
331             }
332             break;
333         }
334         case spv::OpTypeSampler:
335             ss << "sampler";
336             break;
337         case spv::OpTypeSampledImage:
338             ss << "sampler+";
339             DescribeTypeInner(ss, src, insn.word(2));
340             break;
341         case spv::OpTypeImage:
342             ss << "image(dim=" << insn.word(3) << ", sampled=" << insn.word(7) << ")";
343             break;
344         case spv::OpTypeAccelerationStructureNV:
345             ss << "accelerationStruture";
346             break;
347         default:
348             ss << "oddtype";
349             break;
350     }
351 }
352 
DescribeType(SHADER_MODULE_STATE const * src,unsigned type)353 static std::string DescribeType(SHADER_MODULE_STATE const *src, unsigned type) {
354     std::ostringstream ss;
355     DescribeTypeInner(ss, src, type);
356     return ss.str();
357 }
358 
IsNarrowNumericType(spirv_inst_iter type)359 static bool IsNarrowNumericType(spirv_inst_iter type) {
360     if (type.opcode() != spv::OpTypeInt && type.opcode() != spv::OpTypeFloat) return false;
361     return type.word(2) < 64;
362 }
363 
TypesMatch(SHADER_MODULE_STATE const * a,SHADER_MODULE_STATE const * b,unsigned a_type,unsigned b_type,bool a_arrayed,bool b_arrayed,bool relaxed)364 static bool TypesMatch(SHADER_MODULE_STATE const *a, SHADER_MODULE_STATE const *b, unsigned a_type, unsigned b_type, bool a_arrayed,
365                        bool b_arrayed, bool relaxed) {
366     // Walk two type trees together, and complain about differences
367     auto a_insn = a->get_def(a_type);
368     auto b_insn = b->get_def(b_type);
369     assert(a_insn != a->end());
370     assert(b_insn != b->end());
371 
372     // Ignore runtime-sized arrays-- they cannot appear in these interfaces.
373 
374     if (a_arrayed && a_insn.opcode() == spv::OpTypeArray) {
375         return TypesMatch(a, b, a_insn.word(2), b_type, false, b_arrayed, relaxed);
376     }
377 
378     if (b_arrayed && b_insn.opcode() == spv::OpTypeArray) {
379         // We probably just found the extra level of arrayness in b_type: compare the type inside it to a_type
380         return TypesMatch(a, b, a_type, b_insn.word(2), a_arrayed, false, relaxed);
381     }
382 
383     if (a_insn.opcode() == spv::OpTypeVector && relaxed && IsNarrowNumericType(b_insn)) {
384         return TypesMatch(a, b, a_insn.word(2), b_type, a_arrayed, b_arrayed, false);
385     }
386 
387     if (a_insn.opcode() != b_insn.opcode()) {
388         return false;
389     }
390 
391     if (a_insn.opcode() == spv::OpTypePointer) {
392         // Match on pointee type. storage class is expected to differ
393         return TypesMatch(a, b, a_insn.word(3), b_insn.word(3), a_arrayed, b_arrayed, relaxed);
394     }
395 
396     if (a_arrayed || b_arrayed) {
397         // If we havent resolved array-of-verts by here, we're not going to.
398         return false;
399     }
400 
401     switch (a_insn.opcode()) {
402         case spv::OpTypeBool:
403             return true;
404         case spv::OpTypeInt:
405             // Match on width, signedness
406             return a_insn.word(2) == b_insn.word(2) && a_insn.word(3) == b_insn.word(3);
407         case spv::OpTypeFloat:
408             // Match on width
409             return a_insn.word(2) == b_insn.word(2);
410         case spv::OpTypeVector:
411             // Match on element type, count.
412             if (!TypesMatch(a, b, a_insn.word(2), b_insn.word(2), a_arrayed, b_arrayed, false)) return false;
413             if (relaxed && IsNarrowNumericType(a->get_def(a_insn.word(2)))) {
414                 return a_insn.word(3) >= b_insn.word(3);
415             } else {
416                 return a_insn.word(3) == b_insn.word(3);
417             }
418         case spv::OpTypeMatrix:
419             // Match on element type, count.
420             return TypesMatch(a, b, a_insn.word(2), b_insn.word(2), a_arrayed, b_arrayed, false) &&
421                    a_insn.word(3) == b_insn.word(3);
422         case spv::OpTypeArray:
423             // Match on element type, count. these all have the same layout. we don't get here if b_arrayed. This differs from
424             // vector & matrix types in that the array size is the id of a constant instruction, * not a literal within OpTypeArray
425             return TypesMatch(a, b, a_insn.word(2), b_insn.word(2), a_arrayed, b_arrayed, false) &&
426                    GetConstantValue(a, a_insn.word(3)) == GetConstantValue(b, b_insn.word(3));
427         case spv::OpTypeStruct:
428             // Match on all element types
429             {
430                 if (a_insn.len() != b_insn.len()) {
431                     return false;  // Structs cannot match if member counts differ
432                 }
433 
434                 for (unsigned i = 2; i < a_insn.len(); i++) {
435                     if (!TypesMatch(a, b, a_insn.word(i), b_insn.word(i), a_arrayed, b_arrayed, false)) {
436                         return false;
437                     }
438                 }
439 
440                 return true;
441             }
442         default:
443             // Remaining types are CLisms, or may not appear in the interfaces we are interested in. Just claim no match.
444             return false;
445     }
446 }
447 
ValueOrDefault(std::unordered_map<unsigned,unsigned> const & map,unsigned id,unsigned def)448 static unsigned ValueOrDefault(std::unordered_map<unsigned, unsigned> const &map, unsigned id, unsigned def) {
449     auto it = map.find(id);
450     if (it == map.end())
451         return def;
452     else
453         return it->second;
454 }
455 
GetLocationsConsumedByType(SHADER_MODULE_STATE const * src,unsigned type,bool strip_array_level)456 static unsigned GetLocationsConsumedByType(SHADER_MODULE_STATE const *src, unsigned type, bool strip_array_level) {
457     auto insn = src->get_def(type);
458     assert(insn != src->end());
459 
460     switch (insn.opcode()) {
461         case spv::OpTypePointer:
462             // See through the ptr -- this is only ever at the toplevel for graphics shaders we're never actually passing
463             // pointers around.
464             return GetLocationsConsumedByType(src, insn.word(3), strip_array_level);
465         case spv::OpTypeArray:
466             if (strip_array_level) {
467                 return GetLocationsConsumedByType(src, insn.word(2), false);
468             } else {
469                 return GetConstantValue(src, insn.word(3)) * GetLocationsConsumedByType(src, insn.word(2), false);
470             }
471         case spv::OpTypeMatrix:
472             // Num locations is the dimension * element size
473             return insn.word(3) * GetLocationsConsumedByType(src, insn.word(2), false);
474         case spv::OpTypeVector: {
475             auto scalar_type = src->get_def(insn.word(2));
476             auto bit_width =
477                 (scalar_type.opcode() == spv::OpTypeInt || scalar_type.opcode() == spv::OpTypeFloat) ? scalar_type.word(2) : 32;
478 
479             // Locations are 128-bit wide; 3- and 4-component vectors of 64 bit types require two.
480             return (bit_width * insn.word(3) + 127) / 128;
481         }
482         default:
483             // Everything else is just 1.
484             return 1;
485 
486             // TODO: extend to handle 64bit scalar types, whose vectors may need multiple locations.
487     }
488 }
489 
GetComponentsConsumedByType(SHADER_MODULE_STATE const * src,unsigned type,bool strip_array_level)490 static unsigned GetComponentsConsumedByType(SHADER_MODULE_STATE const *src, unsigned type, bool strip_array_level) {
491     auto insn = src->get_def(type);
492     assert(insn != src->end());
493 
494     switch (insn.opcode()) {
495         case spv::OpTypePointer:
496             // See through the ptr -- this is only ever at the toplevel for graphics shaders we're never actually passing
497             // pointers around.
498             return GetComponentsConsumedByType(src, insn.word(3), strip_array_level);
499         case spv::OpTypeStruct: {
500             uint32_t sum = 0;
501             for (uint32_t i = 2; i < insn.len(); i++) {  // i=2 to skip word(0) and word(1)=ID of struct
502                 sum += GetComponentsConsumedByType(src, insn.word(i), false);
503             }
504             return sum;
505         }
506         case spv::OpTypeArray:
507             if (strip_array_level) {
508                 return GetComponentsConsumedByType(src, insn.word(2), false);
509             } else {
510                 return GetConstantValue(src, insn.word(3)) * GetComponentsConsumedByType(src, insn.word(2), false);
511             }
512         case spv::OpTypeMatrix:
513             // Num locations is the dimension * element size
514             return insn.word(3) * GetComponentsConsumedByType(src, insn.word(2), false);
515         case spv::OpTypeVector: {
516             auto scalar_type = src->get_def(insn.word(2));
517             auto bit_width =
518                 (scalar_type.opcode() == spv::OpTypeInt || scalar_type.opcode() == spv::OpTypeFloat) ? scalar_type.word(2) : 32;
519             // One component is 32-bit
520             return (bit_width * insn.word(3) + 31) / 32;
521         }
522         case spv::OpTypeFloat: {
523             auto bit_width = insn.word(2);
524             return (bit_width + 31) / 32;
525         }
526         case spv::OpTypeInt: {
527             auto bit_width = insn.word(2);
528             return (bit_width + 31) / 32;
529         }
530         case spv::OpConstant:
531             return GetComponentsConsumedByType(src, insn.word(1), false);
532         default:
533             return 0;
534     }
535 }
536 
GetLocationsConsumedByFormat(VkFormat format)537 static unsigned GetLocationsConsumedByFormat(VkFormat format) {
538     switch (format) {
539         case VK_FORMAT_R64G64B64A64_SFLOAT:
540         case VK_FORMAT_R64G64B64A64_SINT:
541         case VK_FORMAT_R64G64B64A64_UINT:
542         case VK_FORMAT_R64G64B64_SFLOAT:
543         case VK_FORMAT_R64G64B64_SINT:
544         case VK_FORMAT_R64G64B64_UINT:
545             return 2;
546         default:
547             return 1;
548     }
549 }
550 
GetFormatType(VkFormat fmt)551 static unsigned GetFormatType(VkFormat fmt) {
552     if (FormatIsSInt(fmt)) return FORMAT_TYPE_SINT;
553     if (FormatIsUInt(fmt)) return FORMAT_TYPE_UINT;
554     if (FormatIsDepthAndStencil(fmt)) return FORMAT_TYPE_FLOAT | FORMAT_TYPE_UINT;
555     if (fmt == VK_FORMAT_UNDEFINED) return 0;
556     // everything else -- UNORM/SNORM/FLOAT/USCALED/SSCALED is all float in the shader.
557     return FORMAT_TYPE_FLOAT;
558 }
559 
560 // characterizes a SPIR-V type appearing in an interface to a FF stage, for comparison to a VkFormat's characterization above.
561 // also used for input attachments, as we statically know their format.
GetFundamentalType(SHADER_MODULE_STATE const * src,unsigned type)562 static unsigned GetFundamentalType(SHADER_MODULE_STATE const *src, unsigned type) {
563     auto insn = src->get_def(type);
564     assert(insn != src->end());
565 
566     switch (insn.opcode()) {
567         case spv::OpTypeInt:
568             return insn.word(3) ? FORMAT_TYPE_SINT : FORMAT_TYPE_UINT;
569         case spv::OpTypeFloat:
570             return FORMAT_TYPE_FLOAT;
571         case spv::OpTypeVector:
572         case spv::OpTypeMatrix:
573         case spv::OpTypeArray:
574         case spv::OpTypeRuntimeArray:
575         case spv::OpTypeImage:
576             return GetFundamentalType(src, insn.word(2));
577         case spv::OpTypePointer:
578             return GetFundamentalType(src, insn.word(3));
579 
580         default:
581             return 0;
582     }
583 }
584 
GetShaderStageId(VkShaderStageFlagBits stage)585 static uint32_t GetShaderStageId(VkShaderStageFlagBits stage) {
586     uint32_t bit_pos = uint32_t(u_ffs(stage));
587     return bit_pos - 1;
588 }
589 
GetStructType(SHADER_MODULE_STATE const * src,spirv_inst_iter def,bool is_array_of_verts)590 static spirv_inst_iter GetStructType(SHADER_MODULE_STATE const *src, spirv_inst_iter def, bool is_array_of_verts) {
591     while (true) {
592         if (def.opcode() == spv::OpTypePointer) {
593             def = src->get_def(def.word(3));
594         } else if (def.opcode() == spv::OpTypeArray && is_array_of_verts) {
595             def = src->get_def(def.word(2));
596             is_array_of_verts = false;
597         } else if (def.opcode() == spv::OpTypeStruct) {
598             return def;
599         } else {
600             return src->end();
601         }
602     }
603 }
604 
CollectInterfaceBlockMembers(SHADER_MODULE_STATE const * src,std::map<location_t,interface_var> * out,bool is_array_of_verts,uint32_t id,uint32_t type_id,bool is_patch,int)605 static bool CollectInterfaceBlockMembers(SHADER_MODULE_STATE const *src, std::map<location_t, interface_var> *out,
606                                          bool is_array_of_verts, uint32_t id, uint32_t type_id, bool is_patch,
607                                          int /*first_location*/) {
608     // Walk down the type_id presented, trying to determine whether it's actually an interface block.
609     auto type = GetStructType(src, src->get_def(type_id), is_array_of_verts && !is_patch);
610     if (type == src->end() || !(src->get_decorations(type.word(1)).flags & decoration_set::block_bit)) {
611         // This isn't an interface block.
612         return false;
613     }
614 
615     std::unordered_map<unsigned, unsigned> member_components;
616     std::unordered_map<unsigned, unsigned> member_relaxed_precision;
617     std::unordered_map<unsigned, unsigned> member_patch;
618 
619     // Walk all the OpMemberDecorate for type's result id -- first pass, collect components.
620     for (auto insn : *src) {
621         if (insn.opcode() == spv::OpMemberDecorate && insn.word(1) == type.word(1)) {
622             unsigned member_index = insn.word(2);
623 
624             if (insn.word(3) == spv::DecorationComponent) {
625                 unsigned component = insn.word(4);
626                 member_components[member_index] = component;
627             }
628 
629             if (insn.word(3) == spv::DecorationRelaxedPrecision) {
630                 member_relaxed_precision[member_index] = 1;
631             }
632 
633             if (insn.word(3) == spv::DecorationPatch) {
634                 member_patch[member_index] = 1;
635             }
636         }
637     }
638 
639     // TODO: correctly handle location assignment from outside
640 
641     // Second pass -- produce the output, from Location decorations
642     for (auto insn : *src) {
643         if (insn.opcode() == spv::OpMemberDecorate && insn.word(1) == type.word(1)) {
644             unsigned member_index = insn.word(2);
645             unsigned member_type_id = type.word(2 + member_index);
646 
647             if (insn.word(3) == spv::DecorationLocation) {
648                 unsigned location = insn.word(4);
649                 unsigned num_locations = GetLocationsConsumedByType(src, member_type_id, false);
650                 auto component_it = member_components.find(member_index);
651                 unsigned component = component_it == member_components.end() ? 0 : component_it->second;
652                 bool is_relaxed_precision = member_relaxed_precision.find(member_index) != member_relaxed_precision.end();
653                 bool member_is_patch = is_patch || member_patch.count(member_index) > 0;
654 
655                 for (unsigned int offset = 0; offset < num_locations; offset++) {
656                     interface_var v = {};
657                     v.id = id;
658                     // TODO: member index in interface_var too?
659                     v.type_id = member_type_id;
660                     v.offset = offset;
661                     v.is_patch = member_is_patch;
662                     v.is_block_member = true;
663                     v.is_relaxed_precision = is_relaxed_precision;
664                     (*out)[std::make_pair(location + offset, component)] = v;
665                 }
666             }
667         }
668     }
669 
670     return true;
671 }
672 
FindEntrypointInterfaces(spirv_inst_iter entrypoint)673 static std::vector<uint32_t> FindEntrypointInterfaces(spirv_inst_iter entrypoint) {
674     assert(entrypoint.opcode() == spv::OpEntryPoint);
675 
676     std::vector<uint32_t> interfaces;
677     // Find the end of the entrypoint's name string. additional zero bytes follow the actual null terminator, to fill out the
678     // rest of the word - so we only need to look at the last byte in the word to determine which word contains the terminator.
679     uint32_t word = 3;
680     while (entrypoint.word(word) & 0xff000000u) {
681         ++word;
682     }
683     ++word;
684 
685     for (; word < entrypoint.len(); word++) interfaces.push_back(entrypoint.word(word));
686 
687     return interfaces;
688 }
689 
CollectInterfaceByLocation(SHADER_MODULE_STATE const * src,spirv_inst_iter entrypoint,spv::StorageClass sinterface,bool is_array_of_verts)690 static std::map<location_t, interface_var> CollectInterfaceByLocation(SHADER_MODULE_STATE const *src, spirv_inst_iter entrypoint,
691                                                                       spv::StorageClass sinterface, bool is_array_of_verts) {
692     // TODO: handle index=1 dual source outputs from FS -- two vars will have the same location, and we DON'T want to clobber.
693 
694     std::map<location_t, interface_var> out;
695 
696     for (uint32_t iid : FindEntrypointInterfaces(entrypoint)) {
697         auto insn = src->get_def(iid);
698         assert(insn != src->end());
699         assert(insn.opcode() == spv::OpVariable);
700 
701         if (insn.word(3) == static_cast<uint32_t>(sinterface)) {
702             auto d = src->get_decorations(iid);
703             unsigned id = insn.word(2);
704             unsigned type = insn.word(1);
705 
706             int location = d.location;
707             int builtin = d.builtin;
708             unsigned component = d.component;
709             bool is_patch = (d.flags & decoration_set::patch_bit) != 0;
710             bool is_relaxed_precision = (d.flags & decoration_set::relaxed_precision_bit) != 0;
711 
712             if (builtin != -1)
713                 continue;
714             else if (!CollectInterfaceBlockMembers(src, &out, is_array_of_verts, id, type, is_patch, location)) {
715                 // A user-defined interface variable, with a location. Where a variable occupied multiple locations, emit
716                 // one result for each.
717                 unsigned num_locations = GetLocationsConsumedByType(src, type, is_array_of_verts && !is_patch);
718                 for (unsigned int offset = 0; offset < num_locations; offset++) {
719                     interface_var v = {};
720                     v.id = id;
721                     v.type_id = type;
722                     v.offset = offset;
723                     v.is_patch = is_patch;
724                     v.is_relaxed_precision = is_relaxed_precision;
725                     out[std::make_pair(location + offset, component)] = v;
726                 }
727             }
728         }
729     }
730 
731     return out;
732 }
733 
CollectBuiltinBlockMembers(SHADER_MODULE_STATE const * src,spirv_inst_iter entrypoint,uint32_t storageClass)734 static std::vector<uint32_t> CollectBuiltinBlockMembers(SHADER_MODULE_STATE const *src, spirv_inst_iter entrypoint,
735                                                         uint32_t storageClass) {
736     std::vector<uint32_t> variables;
737     std::vector<uint32_t> builtinStructMembers;
738     std::vector<uint32_t> builtinDecorations;
739 
740     for (auto insn : *src) {
741         switch (insn.opcode()) {
742             // Find all built-in member decorations
743             case spv::OpMemberDecorate:
744                 if (insn.word(3) == spv::DecorationBuiltIn) {
745                     builtinStructMembers.push_back(insn.word(1));
746                 }
747                 break;
748             // Find all built-in decorations
749             case spv::OpDecorate:
750                 switch (insn.word(2)) {
751                     case spv::DecorationBlock: {
752                         uint32_t blockID = insn.word(1);
753                         for (auto builtInBlockID : builtinStructMembers) {
754                             // Check if one of the members of the block are built-in -> the block is built-in
755                             if (blockID == builtInBlockID) {
756                                 builtinDecorations.push_back(blockID);
757                                 break;
758                             }
759                         }
760                         break;
761                     }
762                     case spv::DecorationBuiltIn:
763                         builtinDecorations.push_back(insn.word(1));
764                         break;
765                     default:
766                         break;
767                 }
768                 break;
769             default:
770                 break;
771         }
772     }
773 
774     // Find all interface variables belonging to the entrypoint and matching the storage class
775     for (uint32_t id : FindEntrypointInterfaces(entrypoint)) {
776         auto def = src->get_def(id);
777         assert(def != src->end());
778         assert(def.opcode() == spv::OpVariable);
779 
780         if (def.word(3) == storageClass) variables.push_back(def.word(1));
781     }
782 
783     // Find all members belonging to the builtin block selected
784     std::vector<uint32_t> builtinBlockMembers;
785     for (auto &var : variables) {
786         auto def = src->get_def(src->get_def(var).word(3));
787 
788         // It could be an array of IO blocks. The element type should be the struct defining the block contents
789         if (def.opcode() == spv::OpTypeArray) def = src->get_def(def.word(2));
790 
791         // Now find all members belonging to the struct defining the IO block
792         if (def.opcode() == spv::OpTypeStruct) {
793             for (auto builtInID : builtinDecorations) {
794                 if (builtInID == def.word(1)) {
795                     for (int i = 2; i < (int)def.len(); i++)
796                         builtinBlockMembers.push_back(spv::BuiltInMax);  // Start with undefined builtin for each struct member.
797                                                                          // These shouldn't be left after replacing.
798                     for (auto insn : *src) {
799                         if (insn.opcode() == spv::OpMemberDecorate && insn.word(1) == builtInID &&
800                             insn.word(3) == spv::DecorationBuiltIn) {
801                             auto structIndex = insn.word(2);
802                             assert(structIndex < builtinBlockMembers.size());
803                             builtinBlockMembers[structIndex] = insn.word(4);
804                         }
805                     }
806                 }
807             }
808         }
809     }
810 
811     return builtinBlockMembers;
812 }
813 
CollectInterfaceByInputAttachmentIndex(SHADER_MODULE_STATE const * src,std::unordered_set<uint32_t> const & accessible_ids)814 static std::vector<std::pair<uint32_t, interface_var>> CollectInterfaceByInputAttachmentIndex(
815     SHADER_MODULE_STATE const *src, std::unordered_set<uint32_t> const &accessible_ids) {
816     std::vector<std::pair<uint32_t, interface_var>> out;
817 
818     for (auto insn : *src) {
819         if (insn.opcode() == spv::OpDecorate) {
820             if (insn.word(2) == spv::DecorationInputAttachmentIndex) {
821                 auto attachment_index = insn.word(3);
822                 auto id = insn.word(1);
823 
824                 if (accessible_ids.count(id)) {
825                     auto def = src->get_def(id);
826                     assert(def != src->end());
827 
828                     if (def.opcode() == spv::OpVariable && insn.word(3) == spv::StorageClassUniformConstant) {
829                         auto num_locations = GetLocationsConsumedByType(src, def.word(1), false);
830                         for (unsigned int offset = 0; offset < num_locations; offset++) {
831                             interface_var v = {};
832                             v.id = id;
833                             v.type_id = def.word(1);
834                             v.offset = offset;
835                             out.emplace_back(attachment_index + offset, v);
836                         }
837                     }
838                 }
839             }
840         }
841     }
842 
843     return out;
844 }
845 
IsWritableDescriptorType(SHADER_MODULE_STATE const * module,uint32_t type_id,bool is_storage_buffer)846 static bool IsWritableDescriptorType(SHADER_MODULE_STATE const *module, uint32_t type_id, bool is_storage_buffer) {
847     auto type = module->get_def(type_id);
848 
849     // Strip off any array or ptrs. Where we remove array levels, adjust the  descriptor count for each dimension.
850     while (type.opcode() == spv::OpTypeArray || type.opcode() == spv::OpTypePointer || type.opcode() == spv::OpTypeRuntimeArray) {
851         if (type.opcode() == spv::OpTypeArray || type.opcode() == spv::OpTypeRuntimeArray) {
852             type = module->get_def(type.word(2));  // Element type
853         } else {
854             type = module->get_def(type.word(3));  // Pointee type
855         }
856     }
857 
858     switch (type.opcode()) {
859         case spv::OpTypeImage: {
860             auto dim = type.word(3);
861             auto sampled = type.word(7);
862             return sampled == 2 && dim != spv::DimSubpassData;
863         }
864 
865         case spv::OpTypeStruct: {
866             std::unordered_set<unsigned> nonwritable_members;
867             if (module->get_decorations(type.word(1)).flags & decoration_set::buffer_block_bit) is_storage_buffer = true;
868             for (auto insn : *module) {
869                 if (insn.opcode() == spv::OpMemberDecorate && insn.word(1) == type.word(1) &&
870                     insn.word(3) == spv::DecorationNonWritable) {
871                     nonwritable_members.insert(insn.word(2));
872                 }
873             }
874 
875             // A buffer is writable if it's either flavor of storage buffer, and has any member not decorated
876             // as nonwritable.
877             return is_storage_buffer && nonwritable_members.size() != type.len() - 2;
878         }
879     }
880 
881     return false;
882 }
883 
CollectInterfaceByDescriptorSlot(debug_report_data const * report_data,SHADER_MODULE_STATE const * src,std::unordered_set<uint32_t> const & accessible_ids,bool * has_writable_descriptor)884 static std::vector<std::pair<descriptor_slot_t, interface_var>> CollectInterfaceByDescriptorSlot(
885     debug_report_data const *report_data, SHADER_MODULE_STATE const *src, std::unordered_set<uint32_t> const &accessible_ids,
886     bool *has_writable_descriptor) {
887     std::vector<std::pair<descriptor_slot_t, interface_var>> out;
888 
889     for (auto id : accessible_ids) {
890         auto insn = src->get_def(id);
891         assert(insn != src->end());
892 
893         if (insn.opcode() == spv::OpVariable &&
894             (insn.word(3) == spv::StorageClassUniform || insn.word(3) == spv::StorageClassUniformConstant ||
895              insn.word(3) == spv::StorageClassStorageBuffer)) {
896             auto d = src->get_decorations(insn.word(2));
897             unsigned set = d.descriptor_set;
898             unsigned binding = d.binding;
899 
900             interface_var v = {};
901             v.id = insn.word(2);
902             v.type_id = insn.word(1);
903             out.emplace_back(std::make_pair(set, binding), v);
904 
905             if (!(d.flags & decoration_set::nonwritable_bit) &&
906                 IsWritableDescriptorType(src, insn.word(1), insn.word(3) == spv::StorageClassStorageBuffer)) {
907                 *has_writable_descriptor = true;
908             }
909         }
910     }
911 
912     return out;
913 }
914 
ValidateViConsistency(debug_report_data const * report_data,VkPipelineVertexInputStateCreateInfo const * vi)915 static bool ValidateViConsistency(debug_report_data const *report_data, VkPipelineVertexInputStateCreateInfo const *vi) {
916     // Walk the binding descriptions, which describe the step rate and stride of each vertex buffer.  Each binding should
917     // be specified only once.
918     std::unordered_map<uint32_t, VkVertexInputBindingDescription const *> bindings;
919     bool skip = false;
920 
921     for (unsigned i = 0; i < vi->vertexBindingDescriptionCount; i++) {
922         auto desc = &vi->pVertexBindingDescriptions[i];
923         auto &binding = bindings[desc->binding];
924         if (binding) {
925             // TODO: "VUID-VkGraphicsPipelineCreateInfo-pStages-00742" perhaps?
926             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
927                             kVUID_Core_Shader_InconsistentVi, "Duplicate vertex input binding descriptions for binding %d",
928                             desc->binding);
929         } else {
930             binding = desc;
931         }
932     }
933 
934     return skip;
935 }
936 
ValidateViAgainstVsInputs(debug_report_data const * report_data,VkPipelineVertexInputStateCreateInfo const * vi,SHADER_MODULE_STATE const * vs,spirv_inst_iter entrypoint)937 static bool ValidateViAgainstVsInputs(debug_report_data const *report_data, VkPipelineVertexInputStateCreateInfo const *vi,
938                                       SHADER_MODULE_STATE const *vs, spirv_inst_iter entrypoint) {
939     bool skip = false;
940 
941     auto inputs = CollectInterfaceByLocation(vs, entrypoint, spv::StorageClassInput, false);
942 
943     // Build index by location
944     std::map<uint32_t, VkVertexInputAttributeDescription const *> attribs;
945     if (vi) {
946         for (unsigned i = 0; i < vi->vertexAttributeDescriptionCount; i++) {
947             auto num_locations = GetLocationsConsumedByFormat(vi->pVertexAttributeDescriptions[i].format);
948             for (auto j = 0u; j < num_locations; j++) {
949                 attribs[vi->pVertexAttributeDescriptions[i].location + j] = &vi->pVertexAttributeDescriptions[i];
950             }
951         }
952     }
953 
954     auto it_a = attribs.begin();
955     auto it_b = inputs.begin();
956     bool used = false;
957 
958     while ((attribs.size() > 0 && it_a != attribs.end()) || (inputs.size() > 0 && it_b != inputs.end())) {
959         bool a_at_end = attribs.size() == 0 || it_a == attribs.end();
960         bool b_at_end = inputs.size() == 0 || it_b == inputs.end();
961         auto a_first = a_at_end ? 0 : it_a->first;
962         auto b_first = b_at_end ? 0 : it_b->first.first;
963 
964         if (!a_at_end && (b_at_end || a_first < b_first)) {
965             if (!used &&
966                 log_msg(report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT,
967                         HandleToUint64(vs->vk_shader_module), kVUID_Core_Shader_OutputNotConsumed,
968                         "Vertex attribute at location %d not consumed by vertex shader", a_first)) {
969                 skip = true;
970             }
971             used = false;
972             it_a++;
973         } else if (!b_at_end && (a_at_end || b_first < a_first)) {
974             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT,
975                             HandleToUint64(vs->vk_shader_module), kVUID_Core_Shader_InputNotProduced,
976                             "Vertex shader consumes input at location %d but not provided", b_first);
977             it_b++;
978         } else {
979             unsigned attrib_type = GetFormatType(it_a->second->format);
980             unsigned input_type = GetFundamentalType(vs, it_b->second.type_id);
981 
982             // Type checking
983             if (!(attrib_type & input_type)) {
984                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT,
985                                 HandleToUint64(vs->vk_shader_module), kVUID_Core_Shader_InterfaceTypeMismatch,
986                                 "Attribute type of `%s` at location %d does not match vertex shader input type of `%s`",
987                                 string_VkFormat(it_a->second->format), a_first, DescribeType(vs, it_b->second.type_id).c_str());
988             }
989 
990             // OK!
991             used = true;
992             it_b++;
993         }
994     }
995 
996     return skip;
997 }
998 
ValidateFsOutputsAgainstRenderPass(debug_report_data const * report_data,SHADER_MODULE_STATE const * fs,spirv_inst_iter entrypoint,PIPELINE_STATE const * pipeline,uint32_t subpass_index)999 static bool ValidateFsOutputsAgainstRenderPass(debug_report_data const *report_data, SHADER_MODULE_STATE const *fs,
1000                                                spirv_inst_iter entrypoint, PIPELINE_STATE const *pipeline, uint32_t subpass_index) {
1001     auto rpci = pipeline->rp_state->createInfo.ptr();
1002 
1003     std::map<uint32_t, VkFormat> color_attachments;
1004     auto subpass = rpci->pSubpasses[subpass_index];
1005     for (auto i = 0u; i < subpass.colorAttachmentCount; ++i) {
1006         uint32_t attachment = subpass.pColorAttachments[i].attachment;
1007         if (attachment == VK_ATTACHMENT_UNUSED) continue;
1008         if (rpci->pAttachments[attachment].format != VK_FORMAT_UNDEFINED) {
1009             color_attachments[i] = rpci->pAttachments[attachment].format;
1010         }
1011     }
1012 
1013     bool skip = false;
1014 
1015     // TODO: dual source blend index (spv::DecIndex, zero if not provided)
1016 
1017     auto outputs = CollectInterfaceByLocation(fs, entrypoint, spv::StorageClassOutput, false);
1018 
1019     auto it_a = outputs.begin();
1020     auto it_b = color_attachments.begin();
1021     bool used = false;
1022     bool alphaToCoverageEnabled = pipeline->graphicsPipelineCI.pMultisampleState != NULL &&
1023                                   pipeline->graphicsPipelineCI.pMultisampleState->alphaToCoverageEnable == VK_TRUE;
1024     bool locationZeroHasAlpha = false;
1025 
1026     // Walk attachment list and outputs together
1027 
1028     while ((outputs.size() > 0 && it_a != outputs.end()) || (color_attachments.size() > 0 && it_b != color_attachments.end())) {
1029         bool a_at_end = outputs.size() == 0 || it_a == outputs.end();
1030         bool b_at_end = color_attachments.size() == 0 || it_b == color_attachments.end();
1031 
1032         if (!a_at_end && it_a->first.first == 0 && fs->get_def(it_a->second.type_id) != fs->end() &&
1033             GetComponentsConsumedByType(fs, it_a->second.type_id, false) == 4)
1034             locationZeroHasAlpha = true;
1035 
1036         if (!a_at_end && (b_at_end || it_a->first.first < it_b->first)) {
1037             if (!alphaToCoverageEnabled || it_a->first.first != 0) {
1038                 skip |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT,
1039                                 HandleToUint64(fs->vk_shader_module), kVUID_Core_Shader_OutputNotConsumed,
1040                                 "fragment shader writes to output location %d with no matching attachment", it_a->first.first);
1041             }
1042             it_a++;
1043         } else if (!b_at_end && (a_at_end || it_a->first.first > it_b->first)) {
1044             // Only complain if there are unmasked channels for this attachment. If the writemask is 0, it's acceptable for the
1045             // shader to not produce a matching output.
1046             if (!used) {
1047                 if (pipeline->attachments[it_b->first].colorWriteMask != 0) {
1048                     skip |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT,
1049                                     HandleToUint64(fs->vk_shader_module), kVUID_Core_Shader_InputNotProduced,
1050                                     "Attachment %d not written by fragment shader; undefined values will be written to attachment",
1051                                     it_b->first);
1052                 }
1053             }
1054             used = false;
1055             it_b++;
1056         } else {
1057             unsigned output_type = GetFundamentalType(fs, it_a->second.type_id);
1058             unsigned att_type = GetFormatType(it_b->second);
1059 
1060             // Type checking
1061             if (!(output_type & att_type)) {
1062                 skip |= log_msg(
1063                     report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT,
1064                     HandleToUint64(fs->vk_shader_module), kVUID_Core_Shader_InterfaceTypeMismatch,
1065                     "Attachment %d of type `%s` does not match fragment shader output type of `%s`; resulting values are undefined",
1066                     it_b->first, string_VkFormat(it_b->second), DescribeType(fs, it_a->second.type_id).c_str());
1067             }
1068 
1069             // OK!
1070             it_a++;
1071             used = true;
1072         }
1073     }
1074 
1075     if (alphaToCoverageEnabled && !locationZeroHasAlpha) {
1076         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT,
1077                         HandleToUint64(fs->vk_shader_module), kVUID_Core_Shader_NoAlphaAtLocation0WithAlphaToCoverage,
1078                         "fragment shader doesn't declare alpha output at location 0 even though alpha to coverage is enabled.");
1079     }
1080 
1081     return skip;
1082 }
1083 
1084 // For PointSize analysis we need to know if the variable decorated with the PointSize built-in was actually written to.
1085 // This function examines instructions in the static call tree for a write to this variable.
IsPointSizeWritten(SHADER_MODULE_STATE const * src,spirv_inst_iter builtin_instr,spirv_inst_iter entrypoint)1086 static bool IsPointSizeWritten(SHADER_MODULE_STATE const *src, spirv_inst_iter builtin_instr, spirv_inst_iter entrypoint) {
1087     auto type = builtin_instr.opcode();
1088     uint32_t target_id = builtin_instr.word(1);
1089     bool init_complete = false;
1090 
1091     if (type == spv::OpMemberDecorate) {
1092         // Built-in is part of a structure -- examine instructions up to first function body to get initial IDs
1093         auto insn = entrypoint;
1094         while (!init_complete && (insn.opcode() != spv::OpFunction)) {
1095             switch (insn.opcode()) {
1096                 case spv::OpTypePointer:
1097                     if ((insn.word(3) == target_id) && (insn.word(2) == spv::StorageClassOutput)) {
1098                         target_id = insn.word(1);
1099                     }
1100                     break;
1101                 case spv::OpVariable:
1102                     if (insn.word(1) == target_id) {
1103                         target_id = insn.word(2);
1104                         init_complete = true;
1105                     }
1106                     break;
1107             }
1108             insn++;
1109         }
1110     }
1111 
1112     if (!init_complete && (type == spv::OpMemberDecorate)) return false;
1113 
1114     bool found_write = false;
1115     std::unordered_set<uint32_t> worklist;
1116     worklist.insert(entrypoint.word(2));
1117 
1118     // Follow instructions in call graph looking for writes to target
1119     while (!worklist.empty() && !found_write) {
1120         auto id_iter = worklist.begin();
1121         auto id = *id_iter;
1122         worklist.erase(id_iter);
1123 
1124         auto insn = src->get_def(id);
1125         if (insn == src->end()) {
1126             continue;
1127         }
1128 
1129         if (insn.opcode() == spv::OpFunction) {
1130             // Scan body of function looking for other function calls or items in our ID chain
1131             while (++insn, insn.opcode() != spv::OpFunctionEnd) {
1132                 switch (insn.opcode()) {
1133                     case spv::OpAccessChain:
1134                         if (insn.word(3) == target_id) {
1135                             if (type == spv::OpMemberDecorate) {
1136                                 auto value = GetConstantValue(src, insn.word(4));
1137                                 if (value == builtin_instr.word(2)) {
1138                                     target_id = insn.word(2);
1139                                 }
1140                             } else {
1141                                 target_id = insn.word(2);
1142                             }
1143                         }
1144                         break;
1145                     case spv::OpStore:
1146                         if (insn.word(1) == target_id) {
1147                             found_write = true;
1148                         }
1149                         break;
1150                     case spv::OpFunctionCall:
1151                         worklist.insert(insn.word(3));
1152                         break;
1153                 }
1154             }
1155         }
1156     }
1157     return found_write;
1158 }
1159 
1160 // For some analyses, we need to know about all ids referenced by the static call tree of a particular entrypoint. This is
1161 // important for identifying the set of shader resources actually used by an entrypoint, for example.
1162 // Note: we only explore parts of the image which might actually contain ids we care about for the above analyses.
1163 //  - NOT the shader input/output interfaces.
1164 //
1165 // TODO: The set of interesting opcodes here was determined by eyeballing the SPIRV spec. It might be worth
1166 // converting parts of this to be generated from the machine-readable spec instead.
MarkAccessibleIds(SHADER_MODULE_STATE const * src,spirv_inst_iter entrypoint)1167 static std::unordered_set<uint32_t> MarkAccessibleIds(SHADER_MODULE_STATE const *src, spirv_inst_iter entrypoint) {
1168     std::unordered_set<uint32_t> ids;
1169     std::unordered_set<uint32_t> worklist;
1170     worklist.insert(entrypoint.word(2));
1171 
1172     while (!worklist.empty()) {
1173         auto id_iter = worklist.begin();
1174         auto id = *id_iter;
1175         worklist.erase(id_iter);
1176 
1177         auto insn = src->get_def(id);
1178         if (insn == src->end()) {
1179             // ID is something we didn't collect in BuildDefIndex. that's OK -- we'll stumble across all kinds of things here
1180             // that we may not care about.
1181             continue;
1182         }
1183 
1184         // Try to add to the output set
1185         if (!ids.insert(id).second) {
1186             continue;  // If we already saw this id, we don't want to walk it again.
1187         }
1188 
1189         switch (insn.opcode()) {
1190             case spv::OpFunction:
1191                 // Scan whole body of the function, enlisting anything interesting
1192                 while (++insn, insn.opcode() != spv::OpFunctionEnd) {
1193                     switch (insn.opcode()) {
1194                         case spv::OpLoad:
1195                         case spv::OpAtomicLoad:
1196                         case spv::OpAtomicExchange:
1197                         case spv::OpAtomicCompareExchange:
1198                         case spv::OpAtomicCompareExchangeWeak:
1199                         case spv::OpAtomicIIncrement:
1200                         case spv::OpAtomicIDecrement:
1201                         case spv::OpAtomicIAdd:
1202                         case spv::OpAtomicISub:
1203                         case spv::OpAtomicSMin:
1204                         case spv::OpAtomicUMin:
1205                         case spv::OpAtomicSMax:
1206                         case spv::OpAtomicUMax:
1207                         case spv::OpAtomicAnd:
1208                         case spv::OpAtomicOr:
1209                         case spv::OpAtomicXor:
1210                             worklist.insert(insn.word(3));  // ptr
1211                             break;
1212                         case spv::OpStore:
1213                         case spv::OpAtomicStore:
1214                             worklist.insert(insn.word(1));  // ptr
1215                             break;
1216                         case spv::OpAccessChain:
1217                         case spv::OpInBoundsAccessChain:
1218                             worklist.insert(insn.word(3));  // base ptr
1219                             break;
1220                         case spv::OpSampledImage:
1221                         case spv::OpImageSampleImplicitLod:
1222                         case spv::OpImageSampleExplicitLod:
1223                         case spv::OpImageSampleDrefImplicitLod:
1224                         case spv::OpImageSampleDrefExplicitLod:
1225                         case spv::OpImageSampleProjImplicitLod:
1226                         case spv::OpImageSampleProjExplicitLod:
1227                         case spv::OpImageSampleProjDrefImplicitLod:
1228                         case spv::OpImageSampleProjDrefExplicitLod:
1229                         case spv::OpImageFetch:
1230                         case spv::OpImageGather:
1231                         case spv::OpImageDrefGather:
1232                         case spv::OpImageRead:
1233                         case spv::OpImage:
1234                         case spv::OpImageQueryFormat:
1235                         case spv::OpImageQueryOrder:
1236                         case spv::OpImageQuerySizeLod:
1237                         case spv::OpImageQuerySize:
1238                         case spv::OpImageQueryLod:
1239                         case spv::OpImageQueryLevels:
1240                         case spv::OpImageQuerySamples:
1241                         case spv::OpImageSparseSampleImplicitLod:
1242                         case spv::OpImageSparseSampleExplicitLod:
1243                         case spv::OpImageSparseSampleDrefImplicitLod:
1244                         case spv::OpImageSparseSampleDrefExplicitLod:
1245                         case spv::OpImageSparseSampleProjImplicitLod:
1246                         case spv::OpImageSparseSampleProjExplicitLod:
1247                         case spv::OpImageSparseSampleProjDrefImplicitLod:
1248                         case spv::OpImageSparseSampleProjDrefExplicitLod:
1249                         case spv::OpImageSparseFetch:
1250                         case spv::OpImageSparseGather:
1251                         case spv::OpImageSparseDrefGather:
1252                         case spv::OpImageTexelPointer:
1253                             worklist.insert(insn.word(3));  // Image or sampled image
1254                             break;
1255                         case spv::OpImageWrite:
1256                             worklist.insert(insn.word(1));  // Image -- different operand order to above
1257                             break;
1258                         case spv::OpFunctionCall:
1259                             for (uint32_t i = 3; i < insn.len(); i++) {
1260                                 worklist.insert(insn.word(i));  // fn itself, and all args
1261                             }
1262                             break;
1263 
1264                         case spv::OpExtInst:
1265                             for (uint32_t i = 5; i < insn.len(); i++) {
1266                                 worklist.insert(insn.word(i));  // Operands to ext inst
1267                             }
1268                             break;
1269                     }
1270                 }
1271                 break;
1272         }
1273     }
1274 
1275     return ids;
1276 }
1277 
ValidatePushConstantBlockAgainstPipeline(debug_report_data const * report_data,std::vector<VkPushConstantRange> const * push_constant_ranges,SHADER_MODULE_STATE const * src,spirv_inst_iter type,VkShaderStageFlagBits stage)1278 static bool ValidatePushConstantBlockAgainstPipeline(debug_report_data const *report_data,
1279                                                      std::vector<VkPushConstantRange> const *push_constant_ranges,
1280                                                      SHADER_MODULE_STATE const *src, spirv_inst_iter type,
1281                                                      VkShaderStageFlagBits stage) {
1282     bool skip = false;
1283 
1284     // Strip off ptrs etc
1285     type = GetStructType(src, type, false);
1286     assert(type != src->end());
1287 
1288     // Validate directly off the offsets. this isn't quite correct for arrays and matrices, but is a good first step.
1289     // TODO: arrays, matrices, weird sizes
1290     for (auto insn : *src) {
1291         if (insn.opcode() == spv::OpMemberDecorate && insn.word(1) == type.word(1)) {
1292             if (insn.word(3) == spv::DecorationOffset) {
1293                 unsigned offset = insn.word(4);
1294                 auto size = 4;  // Bytes; TODO: calculate this based on the type
1295 
1296                 bool found_range = false;
1297                 for (auto const &range : *push_constant_ranges) {
1298                     if (range.offset <= offset && range.offset + range.size >= offset + size) {
1299                         found_range = true;
1300 
1301                         if ((range.stageFlags & stage) == 0) {
1302                             skip |=
1303                                 log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
1304                                         kVUID_Core_Shader_PushConstantNotAccessibleFromStage,
1305                                         "Push constant range covering variable starting at offset %u not accessible from stage %s",
1306                                         offset, string_VkShaderStageFlagBits(stage));
1307                         }
1308 
1309                         break;
1310                     }
1311                 }
1312 
1313                 if (!found_range) {
1314                     skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
1315                                     kVUID_Core_Shader_PushConstantOutOfRange,
1316                                     "Push constant range covering variable starting at offset %u not declared in layout", offset);
1317                 }
1318             }
1319         }
1320     }
1321 
1322     return skip;
1323 }
1324 
ValidatePushConstantUsage(debug_report_data const * report_data,std::vector<VkPushConstantRange> const * push_constant_ranges,SHADER_MODULE_STATE const * src,std::unordered_set<uint32_t> accessible_ids,VkShaderStageFlagBits stage)1325 static bool ValidatePushConstantUsage(debug_report_data const *report_data,
1326                                       std::vector<VkPushConstantRange> const *push_constant_ranges, SHADER_MODULE_STATE const *src,
1327                                       std::unordered_set<uint32_t> accessible_ids, VkShaderStageFlagBits stage) {
1328     bool skip = false;
1329 
1330     for (auto id : accessible_ids) {
1331         auto def_insn = src->get_def(id);
1332         if (def_insn.opcode() == spv::OpVariable && def_insn.word(3) == spv::StorageClassPushConstant) {
1333             skip |= ValidatePushConstantBlockAgainstPipeline(report_data, push_constant_ranges, src, src->get_def(def_insn.word(1)),
1334                                                              stage);
1335         }
1336     }
1337 
1338     return skip;
1339 }
1340 
1341 // Validate that data for each specialization entry is fully contained within the buffer.
ValidateSpecializationOffsets(debug_report_data const * report_data,VkPipelineShaderStageCreateInfo const * info)1342 static bool ValidateSpecializationOffsets(debug_report_data const *report_data, VkPipelineShaderStageCreateInfo const *info) {
1343     bool skip = false;
1344 
1345     VkSpecializationInfo const *spec = info->pSpecializationInfo;
1346 
1347     if (spec) {
1348         for (auto i = 0u; i < spec->mapEntryCount; i++) {
1349             // TODO: This is a good place for "VUID-VkSpecializationInfo-offset-00773".
1350             if (spec->pMapEntries[i].offset + spec->pMapEntries[i].size > spec->dataSize) {
1351                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 0,
1352                                 "VUID-VkSpecializationInfo-pMapEntries-00774",
1353                                 "Specialization entry %u (for constant id %u) references memory outside provided specialization "
1354                                 "data (bytes %u.." PRINTF_SIZE_T_SPECIFIER "; " PRINTF_SIZE_T_SPECIFIER " bytes provided)..",
1355                                 i, spec->pMapEntries[i].constantID, spec->pMapEntries[i].offset,
1356                                 spec->pMapEntries[i].offset + spec->pMapEntries[i].size - 1, spec->dataSize);
1357             }
1358         }
1359     }
1360 
1361     return skip;
1362 }
1363 
1364 // TODO (jbolz): Can this return a const reference?
TypeToDescriptorTypeSet(SHADER_MODULE_STATE const * module,uint32_t type_id,unsigned & descriptor_count)1365 static std::set<uint32_t> TypeToDescriptorTypeSet(SHADER_MODULE_STATE const *module, uint32_t type_id, unsigned &descriptor_count) {
1366     auto type = module->get_def(type_id);
1367     bool is_storage_buffer = false;
1368     descriptor_count = 1;
1369     std::set<uint32_t> ret;
1370 
1371     // Strip off any array or ptrs. Where we remove array levels, adjust the  descriptor count for each dimension.
1372     while (type.opcode() == spv::OpTypeArray || type.opcode() == spv::OpTypePointer || type.opcode() == spv::OpTypeRuntimeArray) {
1373         if (type.opcode() == spv::OpTypeRuntimeArray) {
1374             descriptor_count = 0;
1375             type = module->get_def(type.word(2));
1376         } else if (type.opcode() == spv::OpTypeArray) {
1377             descriptor_count *= GetConstantValue(module, type.word(3));
1378             type = module->get_def(type.word(2));
1379         } else {
1380             if (type.word(2) == spv::StorageClassStorageBuffer) {
1381                 is_storage_buffer = true;
1382             }
1383             type = module->get_def(type.word(3));
1384         }
1385     }
1386 
1387     switch (type.opcode()) {
1388         case spv::OpTypeStruct: {
1389             for (auto insn : *module) {
1390                 if (insn.opcode() == spv::OpDecorate && insn.word(1) == type.word(1)) {
1391                     if (insn.word(2) == spv::DecorationBlock) {
1392                         if (is_storage_buffer) {
1393                             ret.insert(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
1394                             ret.insert(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC);
1395                             return ret;
1396                         } else {
1397                             ret.insert(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
1398                             ret.insert(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC);
1399                             ret.insert(VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT);
1400                             return ret;
1401                         }
1402                     } else if (insn.word(2) == spv::DecorationBufferBlock) {
1403                         ret.insert(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
1404                         ret.insert(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC);
1405                         return ret;
1406                     }
1407                 }
1408             }
1409 
1410             // Invalid
1411             return ret;
1412         }
1413 
1414         case spv::OpTypeSampler:
1415             ret.insert(VK_DESCRIPTOR_TYPE_SAMPLER);
1416             ret.insert(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
1417             return ret;
1418 
1419         case spv::OpTypeSampledImage: {
1420             // Slight relaxation for some GLSL historical madness: samplerBuffer doesn't really have a sampler, and a texel
1421             // buffer descriptor doesn't really provide one. Allow this slight mismatch.
1422             auto image_type = module->get_def(type.word(2));
1423             auto dim = image_type.word(3);
1424             auto sampled = image_type.word(7);
1425             if (dim == spv::DimBuffer && sampled == 1) {
1426                 ret.insert(VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER);
1427                 return ret;
1428             }
1429         }
1430             ret.insert(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
1431             return ret;
1432 
1433         case spv::OpTypeImage: {
1434             // Many descriptor types backing image types-- depends on dimension and whether the image will be used with a sampler.
1435             // SPIRV for Vulkan requires that sampled be 1 or 2 -- leaving the decision to runtime is unacceptable.
1436             auto dim = type.word(3);
1437             auto sampled = type.word(7);
1438 
1439             if (dim == spv::DimSubpassData) {
1440                 ret.insert(VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT);
1441                 return ret;
1442             } else if (dim == spv::DimBuffer) {
1443                 if (sampled == 1) {
1444                     ret.insert(VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER);
1445                     return ret;
1446                 } else {
1447                     ret.insert(VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER);
1448                     return ret;
1449                 }
1450             } else if (sampled == 1) {
1451                 ret.insert(VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE);
1452                 ret.insert(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
1453                 return ret;
1454             } else {
1455                 ret.insert(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE);
1456                 return ret;
1457             }
1458         }
1459         case spv::OpTypeAccelerationStructureNV:
1460             ret.insert(VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV);
1461             return ret;
1462 
1463             // We shouldn't really see any other junk types -- but if we do, they're a mismatch.
1464         default:
1465             return ret;  // Matches nothing
1466     }
1467 }
1468 
string_descriptorTypes(const std::set<uint32_t> & descriptor_types)1469 static std::string string_descriptorTypes(const std::set<uint32_t> &descriptor_types) {
1470     std::stringstream ss;
1471     for (auto it = descriptor_types.begin(); it != descriptor_types.end(); ++it) {
1472         if (ss.tellp()) ss << ", ";
1473         ss << string_VkDescriptorType(VkDescriptorType(*it));
1474     }
1475     return ss.str();
1476 }
1477 
RequirePropertyFlag(debug_report_data const * report_data,VkBool32 check,char const * flag,char const * structure)1478 static bool RequirePropertyFlag(debug_report_data const *report_data, VkBool32 check, char const *flag, char const *structure) {
1479     if (!check) {
1480         if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
1481                     kVUID_Core_Shader_ExceedDeviceLimit, "Shader requires flag %s set in %s but it is not set on the device", flag,
1482                     structure)) {
1483             return true;
1484         }
1485     }
1486 
1487     return false;
1488 }
1489 
RequireFeature(debug_report_data const * report_data,VkBool32 feature,char const * feature_name)1490 static bool RequireFeature(debug_report_data const *report_data, VkBool32 feature, char const *feature_name) {
1491     if (!feature) {
1492         if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
1493                     kVUID_Core_Shader_FeatureNotEnabled, "Shader requires %s but is not enabled on the device", feature_name)) {
1494             return true;
1495         }
1496     }
1497 
1498     return false;
1499 }
1500 
RequireExtension(debug_report_data const * report_data,bool extension,char const * extension_name)1501 static bool RequireExtension(debug_report_data const *report_data, bool extension, char const *extension_name) {
1502     if (!extension) {
1503         if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
1504                     kVUID_Core_Shader_FeatureNotEnabled, "Shader requires extension %s but is not enabled on the device",
1505                     extension_name)) {
1506             return true;
1507         }
1508     }
1509 
1510     return false;
1511 }
1512 
ValidateShaderCapabilities(SHADER_MODULE_STATE const * src,VkShaderStageFlagBits stage) const1513 bool CoreChecks::ValidateShaderCapabilities(SHADER_MODULE_STATE const *src, VkShaderStageFlagBits stage) const {
1514     bool skip = false;
1515 
1516     struct FeaturePointer {
1517         // Callable object to test if this feature is enabled in the given aggregate feature struct
1518         const std::function<VkBool32(const DeviceFeatures &)> IsEnabled;
1519 
1520         // Test if feature pointer is populated
1521         explicit operator bool() const { return static_cast<bool>(IsEnabled); }
1522 
1523         // Default and nullptr constructor to create an empty FeaturePointer
1524         FeaturePointer() : IsEnabled(nullptr) {}
1525         FeaturePointer(std::nullptr_t ptr) : IsEnabled(nullptr) {}
1526 
1527         // Constructors to populate FeaturePointer based on given pointer to member
1528         FeaturePointer(VkBool32 VkPhysicalDeviceFeatures::*ptr)
1529             : IsEnabled([=](const DeviceFeatures &features) { return features.core.*ptr; }) {}
1530         FeaturePointer(VkBool32 VkPhysicalDeviceDescriptorIndexingFeaturesEXT::*ptr)
1531             : IsEnabled([=](const DeviceFeatures &features) { return features.descriptor_indexing.*ptr; }) {}
1532         FeaturePointer(VkBool32 VkPhysicalDevice8BitStorageFeaturesKHR::*ptr)
1533             : IsEnabled([=](const DeviceFeatures &features) { return features.eight_bit_storage.*ptr; }) {}
1534         FeaturePointer(VkBool32 VkPhysicalDeviceTransformFeedbackFeaturesEXT::*ptr)
1535             : IsEnabled([=](const DeviceFeatures &features) { return features.transform_feedback_features.*ptr; }) {}
1536         FeaturePointer(VkBool32 VkPhysicalDeviceFloat16Int8FeaturesKHR::*ptr)
1537             : IsEnabled([=](const DeviceFeatures &features) { return features.float16_int8.*ptr; }) {}
1538         FeaturePointer(VkBool32 VkPhysicalDeviceScalarBlockLayoutFeaturesEXT::*ptr)
1539             : IsEnabled([=](const DeviceFeatures &features) { return features.scalar_block_layout_features.*ptr; }) {}
1540         FeaturePointer(VkBool32 VkPhysicalDeviceCooperativeMatrixFeaturesNV::*ptr)
1541             : IsEnabled([=](const DeviceFeatures &features) { return features.cooperative_matrix_features.*ptr; }) {}
1542         FeaturePointer(VkBool32 VkPhysicalDeviceFloatControlsPropertiesKHR::*ptr)
1543             : IsEnabled([=](const DeviceFeatures &features) { return features.float_controls.*ptr; }) {}
1544         FeaturePointer(VkBool32 VkPhysicalDeviceUniformBufferStandardLayoutFeaturesKHR::*ptr)
1545             : IsEnabled([=](const DeviceFeatures &features) { return features.uniform_buffer_standard_layout.*ptr; }) {}
1546         FeaturePointer(VkBool32 VkPhysicalDeviceComputeShaderDerivativesFeaturesNV::*ptr)
1547             : IsEnabled([=](const DeviceFeatures &features) { return features.compute_shader_derivatives_features.*ptr; }) {}
1548         FeaturePointer(VkBool32 VkPhysicalDeviceFragmentShaderBarycentricFeaturesNV::*ptr)
1549             : IsEnabled([=](const DeviceFeatures &features) { return features.fragment_shader_barycentric_features.*ptr; }) {}
1550         FeaturePointer(VkBool32 VkPhysicalDeviceShaderImageFootprintFeaturesNV::*ptr)
1551             : IsEnabled([=](const DeviceFeatures &features) { return features.shader_image_footprint_features.*ptr; }) {}
1552         FeaturePointer(VkBool32 VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT::*ptr)
1553             : IsEnabled([=](const DeviceFeatures &features) { return features.fragment_shader_interlock_features.*ptr; }) {}
1554         FeaturePointer(VkBool32 VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT::*ptr)
1555             : IsEnabled([=](const DeviceFeatures &features) { return features.demote_to_helper_invocation_features.*ptr; }) {}
1556     };
1557 
1558     struct CapabilityInfo {
1559         char const *name;
1560         FeaturePointer feature;
1561         bool DeviceExtensions::*extension;
1562     };
1563 
1564     // clang-format off
1565     static const std::unordered_multimap<uint32_t, CapabilityInfo> capabilities = {
1566         // Capabilities always supported by a Vulkan 1.0 implementation -- no
1567         // feature bits.
1568         {spv::CapabilityMatrix, {nullptr}},
1569         {spv::CapabilityShader, {nullptr}},
1570         {spv::CapabilityInputAttachment, {nullptr}},
1571         {spv::CapabilitySampled1D, {nullptr}},
1572         {spv::CapabilityImage1D, {nullptr}},
1573         {spv::CapabilitySampledBuffer, {nullptr}},
1574         {spv::CapabilityStorageImageExtendedFormats, {nullptr}},
1575         {spv::CapabilityImageQuery, {nullptr}},
1576         {spv::CapabilityDerivativeControl, {nullptr}},
1577 
1578         // Capabilities that are optionally supported, but require a feature to
1579         // be enabled on the device
1580         {spv::CapabilityGeometry, {"VkPhysicalDeviceFeatures::geometryShader", &VkPhysicalDeviceFeatures::geometryShader}},
1581         {spv::CapabilityTessellation, {"VkPhysicalDeviceFeatures::tessellationShader", &VkPhysicalDeviceFeatures::tessellationShader}},
1582         {spv::CapabilityFloat64, {"VkPhysicalDeviceFeatures::shaderFloat64", &VkPhysicalDeviceFeatures::shaderFloat64}},
1583         {spv::CapabilityInt64, {"VkPhysicalDeviceFeatures::shaderInt64", &VkPhysicalDeviceFeatures::shaderInt64}},
1584         {spv::CapabilityTessellationPointSize, {"VkPhysicalDeviceFeatures::shaderTessellationAndGeometryPointSize", &VkPhysicalDeviceFeatures::shaderTessellationAndGeometryPointSize}},
1585         {spv::CapabilityGeometryPointSize, {"VkPhysicalDeviceFeatures::shaderTessellationAndGeometryPointSize", &VkPhysicalDeviceFeatures::shaderTessellationAndGeometryPointSize}},
1586         {spv::CapabilityImageGatherExtended, {"VkPhysicalDeviceFeatures::shaderImageGatherExtended", &VkPhysicalDeviceFeatures::shaderImageGatherExtended}},
1587         {spv::CapabilityStorageImageMultisample, {"VkPhysicalDeviceFeatures::shaderStorageImageMultisample", &VkPhysicalDeviceFeatures::shaderStorageImageMultisample}},
1588         {spv::CapabilityUniformBufferArrayDynamicIndexing, {"VkPhysicalDeviceFeatures::shaderUniformBufferArrayDynamicIndexing", &VkPhysicalDeviceFeatures::shaderUniformBufferArrayDynamicIndexing}},
1589         {spv::CapabilitySampledImageArrayDynamicIndexing, {"VkPhysicalDeviceFeatures::shaderSampledImageArrayDynamicIndexing", &VkPhysicalDeviceFeatures::shaderSampledImageArrayDynamicIndexing}},
1590         {spv::CapabilityStorageBufferArrayDynamicIndexing, {"VkPhysicalDeviceFeatures::shaderStorageBufferArrayDynamicIndexing", &VkPhysicalDeviceFeatures::shaderStorageBufferArrayDynamicIndexing}},
1591         {spv::CapabilityStorageImageArrayDynamicIndexing, {"VkPhysicalDeviceFeatures::shaderStorageImageArrayDynamicIndexing", &VkPhysicalDeviceFeatures::shaderStorageBufferArrayDynamicIndexing}},
1592         {spv::CapabilityClipDistance, {"VkPhysicalDeviceFeatures::shaderClipDistance", &VkPhysicalDeviceFeatures::shaderClipDistance}},
1593         {spv::CapabilityCullDistance, {"VkPhysicalDeviceFeatures::shaderCullDistance", &VkPhysicalDeviceFeatures::shaderCullDistance}},
1594         {spv::CapabilityImageCubeArray, {"VkPhysicalDeviceFeatures::imageCubeArray", &VkPhysicalDeviceFeatures::imageCubeArray}},
1595         {spv::CapabilitySampleRateShading, {"VkPhysicalDeviceFeatures::sampleRateShading", &VkPhysicalDeviceFeatures::sampleRateShading}},
1596         {spv::CapabilitySparseResidency, {"VkPhysicalDeviceFeatures::shaderResourceResidency", &VkPhysicalDeviceFeatures::shaderResourceResidency}},
1597         {spv::CapabilityMinLod, {"VkPhysicalDeviceFeatures::shaderResourceMinLod", &VkPhysicalDeviceFeatures::shaderResourceMinLod}},
1598         {spv::CapabilitySampledCubeArray, {"VkPhysicalDeviceFeatures::imageCubeArray", &VkPhysicalDeviceFeatures::imageCubeArray}},
1599         {spv::CapabilityImageMSArray, {"VkPhysicalDeviceFeatures::shaderStorageImageMultisample", &VkPhysicalDeviceFeatures::shaderStorageImageMultisample}},
1600         {spv::CapabilityInterpolationFunction, {"VkPhysicalDeviceFeatures::sampleRateShading", &VkPhysicalDeviceFeatures::sampleRateShading}},
1601         {spv::CapabilityStorageImageReadWithoutFormat, {"VkPhysicalDeviceFeatures::shaderStorageImageReadWithoutFormat", &VkPhysicalDeviceFeatures::shaderStorageImageReadWithoutFormat}},
1602         {spv::CapabilityStorageImageWriteWithoutFormat, {"VkPhysicalDeviceFeatures::shaderStorageImageWriteWithoutFormat", &VkPhysicalDeviceFeatures::shaderStorageImageWriteWithoutFormat}},
1603         {spv::CapabilityMultiViewport, {"VkPhysicalDeviceFeatures::multiViewport", &VkPhysicalDeviceFeatures::multiViewport}},
1604 
1605         {spv::CapabilityShaderNonUniformEXT, {VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME, nullptr, &DeviceExtensions::vk_ext_descriptor_indexing}},
1606         {spv::CapabilityRuntimeDescriptorArrayEXT, {"VkPhysicalDeviceDescriptorIndexingFeaturesEXT::runtimeDescriptorArray", &VkPhysicalDeviceDescriptorIndexingFeaturesEXT::runtimeDescriptorArray}},
1607         {spv::CapabilityInputAttachmentArrayDynamicIndexingEXT, {"VkPhysicalDeviceDescriptorIndexingFeaturesEXT::shaderInputAttachmentArrayDynamicIndexing", &VkPhysicalDeviceDescriptorIndexingFeaturesEXT::shaderInputAttachmentArrayDynamicIndexing}},
1608         {spv::CapabilityUniformTexelBufferArrayDynamicIndexingEXT, {"VkPhysicalDeviceDescriptorIndexingFeaturesEXT::shaderUniformTexelBufferArrayDynamicIndexing", &VkPhysicalDeviceDescriptorIndexingFeaturesEXT::shaderUniformTexelBufferArrayDynamicIndexing}},
1609         {spv::CapabilityStorageTexelBufferArrayDynamicIndexingEXT, {"VkPhysicalDeviceDescriptorIndexingFeaturesEXT::shaderStorageTexelBufferArrayDynamicIndexing", &VkPhysicalDeviceDescriptorIndexingFeaturesEXT::shaderStorageTexelBufferArrayDynamicIndexing}},
1610         {spv::CapabilityUniformBufferArrayNonUniformIndexingEXT, {"VkPhysicalDeviceDescriptorIndexingFeaturesEXT::shaderUniformBufferArrayNonUniformIndexing", &VkPhysicalDeviceDescriptorIndexingFeaturesEXT::shaderUniformBufferArrayNonUniformIndexing}},
1611         {spv::CapabilitySampledImageArrayNonUniformIndexingEXT, {"VkPhysicalDeviceDescriptorIndexingFeaturesEXT::shaderSampledImageArrayNonUniformIndexing", &VkPhysicalDeviceDescriptorIndexingFeaturesEXT::shaderSampledImageArrayNonUniformIndexing}},
1612         {spv::CapabilityStorageBufferArrayNonUniformIndexingEXT, {"VkPhysicalDeviceDescriptorIndexingFeaturesEXT::shaderStorageBufferArrayNonUniformIndexing", &VkPhysicalDeviceDescriptorIndexingFeaturesEXT::shaderStorageBufferArrayNonUniformIndexing}},
1613         {spv::CapabilityStorageImageArrayNonUniformIndexingEXT, {"VkPhysicalDeviceDescriptorIndexingFeaturesEXT::shaderStorageImageArrayNonUniformIndexing", &VkPhysicalDeviceDescriptorIndexingFeaturesEXT::shaderStorageImageArrayNonUniformIndexing}},
1614         {spv::CapabilityInputAttachmentArrayNonUniformIndexingEXT, {"VkPhysicalDeviceDescriptorIndexingFeaturesEXT::shaderInputAttachmentArrayNonUniformIndexing", &VkPhysicalDeviceDescriptorIndexingFeaturesEXT::shaderInputAttachmentArrayNonUniformIndexing}},
1615         {spv::CapabilityUniformTexelBufferArrayNonUniformIndexingEXT, {"VkPhysicalDeviceDescriptorIndexingFeaturesEXT::shaderUniformTexelBufferArrayNonUniformIndexing", &VkPhysicalDeviceDescriptorIndexingFeaturesEXT::shaderUniformTexelBufferArrayNonUniformIndexing}},
1616         {spv::CapabilityStorageTexelBufferArrayNonUniformIndexingEXT, {"VkPhysicalDeviceDescriptorIndexingFeaturesEXT::shaderStorageTexelBufferArrayNonUniformIndexing", &VkPhysicalDeviceDescriptorIndexingFeaturesEXT::shaderStorageTexelBufferArrayNonUniformIndexing}},
1617 
1618         // Capabilities that require an extension
1619         {spv::CapabilityDrawParameters, {VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME, nullptr, &DeviceExtensions::vk_khr_shader_draw_parameters}},
1620         {spv::CapabilityGeometryShaderPassthroughNV, {VK_NV_GEOMETRY_SHADER_PASSTHROUGH_EXTENSION_NAME, nullptr, &DeviceExtensions::vk_nv_geometry_shader_passthrough}},
1621         {spv::CapabilitySampleMaskOverrideCoverageNV, {VK_NV_SAMPLE_MASK_OVERRIDE_COVERAGE_EXTENSION_NAME, nullptr, &DeviceExtensions::vk_nv_sample_mask_override_coverage}},
1622         {spv::CapabilityShaderViewportIndexLayerEXT, {VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME, nullptr, &DeviceExtensions::vk_ext_shader_viewport_index_layer}},
1623         {spv::CapabilityShaderViewportIndexLayerNV, {VK_NV_VIEWPORT_ARRAY2_EXTENSION_NAME, nullptr, &DeviceExtensions::vk_nv_viewport_array2}},
1624         {spv::CapabilityShaderViewportMaskNV, {VK_NV_VIEWPORT_ARRAY2_EXTENSION_NAME, nullptr, &DeviceExtensions::vk_nv_viewport_array2}},
1625         {spv::CapabilitySubgroupBallotKHR, {VK_EXT_SHADER_SUBGROUP_BALLOT_EXTENSION_NAME, nullptr, &DeviceExtensions::vk_ext_shader_subgroup_ballot }},
1626         {spv::CapabilitySubgroupVoteKHR, {VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME, nullptr, &DeviceExtensions::vk_ext_shader_subgroup_vote }},
1627         {spv::CapabilityGroupNonUniformPartitionedNV, {VK_NV_SHADER_SUBGROUP_PARTITIONED_EXTENSION_NAME, nullptr, &DeviceExtensions::vk_nv_shader_subgroup_partitioned}},
1628         {spv::CapabilityInt64Atomics, {VK_KHR_SHADER_ATOMIC_INT64_EXTENSION_NAME, nullptr, &DeviceExtensions::vk_khr_shader_atomic_int64 }},
1629 
1630         {spv::CapabilityComputeDerivativeGroupQuadsNV, {"VkPhysicalDeviceComputeShaderDerivativesFeaturesNV::computeDerivativeGroupQuads", &VkPhysicalDeviceComputeShaderDerivativesFeaturesNV::computeDerivativeGroupQuads, &DeviceExtensions::vk_nv_compute_shader_derivatives}},
1631         {spv::CapabilityComputeDerivativeGroupLinearNV, {"VkPhysicalDeviceComputeShaderDerivativesFeaturesNV::computeDerivativeGroupLinear", &VkPhysicalDeviceComputeShaderDerivativesFeaturesNV::computeDerivativeGroupLinear, &DeviceExtensions::vk_nv_compute_shader_derivatives}},
1632         {spv::CapabilityFragmentBarycentricNV, {"VkPhysicalDeviceFragmentShaderBarycentricFeaturesNV::fragmentShaderBarycentric", &VkPhysicalDeviceFragmentShaderBarycentricFeaturesNV::fragmentShaderBarycentric, &DeviceExtensions::vk_nv_fragment_shader_barycentric}},
1633 
1634         {spv::CapabilityStorageBuffer8BitAccess, {"VkPhysicalDevice8BitStorageFeaturesKHR::storageBuffer8BitAccess", &VkPhysicalDevice8BitStorageFeaturesKHR::storageBuffer8BitAccess, &DeviceExtensions::vk_khr_8bit_storage}},
1635         {spv::CapabilityUniformAndStorageBuffer8BitAccess, {"VkPhysicalDevice8BitStorageFeaturesKHR::uniformAndStorageBuffer8BitAccess", &VkPhysicalDevice8BitStorageFeaturesKHR::uniformAndStorageBuffer8BitAccess, &DeviceExtensions::vk_khr_8bit_storage}},
1636         {spv::CapabilityStoragePushConstant8, {"VkPhysicalDevice8BitStorageFeaturesKHR::storagePushConstant8", &VkPhysicalDevice8BitStorageFeaturesKHR::storagePushConstant8, &DeviceExtensions::vk_khr_8bit_storage}},
1637 
1638         {spv::CapabilityTransformFeedback, { "VkPhysicalDeviceTransformFeedbackFeaturesEXT::transformFeedback", &VkPhysicalDeviceTransformFeedbackFeaturesEXT::transformFeedback, &DeviceExtensions::vk_ext_transform_feedback}},
1639         {spv::CapabilityGeometryStreams, { "VkPhysicalDeviceTransformFeedbackFeaturesEXT::geometryStreams", &VkPhysicalDeviceTransformFeedbackFeaturesEXT::geometryStreams, &DeviceExtensions::vk_ext_transform_feedback}},
1640 
1641         {spv::CapabilityFloat16, {"VkPhysicalDeviceFloat16Int8FeaturesKHR::shaderFloat16", &VkPhysicalDeviceFloat16Int8FeaturesKHR::shaderFloat16, &DeviceExtensions::vk_khr_shader_float16_int8}},
1642         {spv::CapabilityInt8, {"VkPhysicalDeviceFloat16Int8FeaturesKHR::shaderInt8", &VkPhysicalDeviceFloat16Int8FeaturesKHR::shaderInt8, &DeviceExtensions::vk_khr_shader_float16_int8}},
1643 
1644         {spv::CapabilityImageFootprintNV, {"VkPhysicalDeviceShaderImageFootprintFeaturesNV::imageFootprint", &VkPhysicalDeviceShaderImageFootprintFeaturesNV::imageFootprint, &DeviceExtensions::vk_nv_shader_image_footprint}},
1645 
1646         {spv::CapabilityCooperativeMatrixNV, {"VkPhysicalDeviceCooperativeMatrixFeaturesNV::cooperativeMatrix", &VkPhysicalDeviceCooperativeMatrixFeaturesNV::cooperativeMatrix, &DeviceExtensions::vk_nv_cooperative_matrix}},
1647 
1648         {spv::CapabilitySignedZeroInfNanPreserve, {"VkPhysicalDeviceFloatControlsPropertiesKHR::shaderSignedZeroInfNanPreserveFloat16", &VkPhysicalDeviceFloatControlsPropertiesKHR::shaderSignedZeroInfNanPreserveFloat16, &DeviceExtensions::vk_khr_shader_float_controls}},
1649         {spv::CapabilitySignedZeroInfNanPreserve, {"VkPhysicalDeviceFloatControlsPropertiesKHR::shaderSignedZeroInfNanPreserveFloat32", &VkPhysicalDeviceFloatControlsPropertiesKHR::shaderSignedZeroInfNanPreserveFloat32, &DeviceExtensions::vk_khr_shader_float_controls}},
1650         {spv::CapabilitySignedZeroInfNanPreserve, {"VkPhysicalDeviceFloatControlsPropertiesKHR::shaderSignedZeroInfNanPreserveFloat64", &VkPhysicalDeviceFloatControlsPropertiesKHR::shaderSignedZeroInfNanPreserveFloat64, &DeviceExtensions::vk_khr_shader_float_controls}},
1651         {spv::CapabilityDenormPreserve, {"VkPhysicalDeviceFloatControlsPropertiesKHR::shaderDenormPreserveFloat16", &VkPhysicalDeviceFloatControlsPropertiesKHR::shaderDenormPreserveFloat16, &DeviceExtensions::vk_khr_shader_float_controls}},
1652         {spv::CapabilityDenormPreserve, {"VkPhysicalDeviceFloatControlsPropertiesKHR::shaderDenormPreserveFloat32", &VkPhysicalDeviceFloatControlsPropertiesKHR::shaderDenormPreserveFloat32, &DeviceExtensions::vk_khr_shader_float_controls}},
1653         {spv::CapabilityDenormPreserve, {"VkPhysicalDeviceFloatControlsPropertiesKHR::shaderDenormPreserveFloat64", &VkPhysicalDeviceFloatControlsPropertiesKHR::shaderDenormPreserveFloat64, &DeviceExtensions::vk_khr_shader_float_controls}},
1654         {spv::CapabilityDenormFlushToZero, {"VkPhysicalDeviceFloatControlsPropertiesKHR::shaderDenormFlushToZeroFloat16", &VkPhysicalDeviceFloatControlsPropertiesKHR::shaderDenormFlushToZeroFloat16, &DeviceExtensions::vk_khr_shader_float_controls}},
1655         {spv::CapabilityDenormFlushToZero, {"VkPhysicalDeviceFloatControlsPropertiesKHR::shaderDenormFlushToZeroFloat32", &VkPhysicalDeviceFloatControlsPropertiesKHR::shaderDenormFlushToZeroFloat32, &DeviceExtensions::vk_khr_shader_float_controls}},
1656         {spv::CapabilityDenormFlushToZero, {"VkPhysicalDeviceFloatControlsPropertiesKHR::shaderDenormFlushToZeroFloat64", &VkPhysicalDeviceFloatControlsPropertiesKHR::shaderDenormFlushToZeroFloat64, &DeviceExtensions::vk_khr_shader_float_controls}},
1657         {spv::CapabilityRoundingModeRTE, {"VkPhysicalDeviceFloatControlsPropertiesKHR::shaderRoundingModeRTEFloat16", &VkPhysicalDeviceFloatControlsPropertiesKHR::shaderRoundingModeRTEFloat16, &DeviceExtensions::vk_khr_shader_float_controls}},
1658         {spv::CapabilityRoundingModeRTE, {"VkPhysicalDeviceFloatControlsPropertiesKHR::shaderRoundingModeRTEFloat32", &VkPhysicalDeviceFloatControlsPropertiesKHR::shaderRoundingModeRTEFloat32, &DeviceExtensions::vk_khr_shader_float_controls}},
1659         {spv::CapabilityRoundingModeRTE, {"VkPhysicalDeviceFloatControlsPropertiesKHR::shaderRoundingModeRTEFloat64", &VkPhysicalDeviceFloatControlsPropertiesKHR::shaderRoundingModeRTEFloat64, &DeviceExtensions::vk_khr_shader_float_controls}},
1660         {spv::CapabilityRoundingModeRTZ, {"VkPhysicalDeviceFloatControlsPropertiesKHR::shaderRoundingModeRTZFloat16", &VkPhysicalDeviceFloatControlsPropertiesKHR::shaderRoundingModeRTZFloat16, &DeviceExtensions::vk_khr_shader_float_controls}},
1661         {spv::CapabilityRoundingModeRTZ, {"VkPhysicalDeviceFloatControlsPropertiesKHR::shaderRoundingModeRTZFloat32", &VkPhysicalDeviceFloatControlsPropertiesKHR::shaderRoundingModeRTZFloat32, &DeviceExtensions::vk_khr_shader_float_controls}},
1662         {spv::CapabilityRoundingModeRTZ, {"VkPhysicalDeviceFloatControlsPropertiesKHR::shaderRoundingModeRTZFloat64", &VkPhysicalDeviceFloatControlsPropertiesKHR::shaderRoundingModeRTZFloat64, &DeviceExtensions::vk_khr_shader_float_controls}},
1663 
1664         {spv::CapabilityFragmentShaderSampleInterlockEXT,       {"VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT::fragmentShaderSampleInterlock",       &VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT::fragmentShaderSampleInterlock,         &DeviceExtensions::vk_ext_fragment_shader_interlock}},
1665         {spv::CapabilityFragmentShaderPixelInterlockEXT,        {"VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT::fragmentShaderPixelInterlock",        &VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT::fragmentShaderPixelInterlock,          &DeviceExtensions::vk_ext_fragment_shader_interlock}},
1666         {spv::CapabilityFragmentShaderShadingRateInterlockEXT,  {"VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT::fragmentShaderShadingRateInterlock",  &VkPhysicalDeviceFragmentShaderInterlockFeaturesEXT::fragmentShaderShadingRateInterlock,    &DeviceExtensions::vk_ext_fragment_shader_interlock}},
1667         {spv::CapabilityDemoteToHelperInvocationEXT,       {"VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT::shaderDemoteToHelperInvocation",       &VkPhysicalDeviceShaderDemoteToHelperInvocationFeaturesEXT::shaderDemoteToHelperInvocation,         &DeviceExtensions::vk_ext_shader_demote_to_helper_invocation}},
1668     };
1669     // clang-format on
1670 
1671     for (auto insn : *src) {
1672         if (insn.opcode() == spv::OpCapability) {
1673             size_t n = capabilities.count(insn.word(1));
1674             if (1 == n) {  // key occurs exactly once
1675                 auto it = capabilities.find(insn.word(1));
1676                 if (it != capabilities.end()) {
1677                     if (it->second.feature) {
1678                         skip |= RequireFeature(report_data, it->second.feature.IsEnabled(enabled_features), it->second.name);
1679                     }
1680                     if (it->second.extension) {
1681                         skip |= RequireExtension(report_data, device_extensions.*(it->second.extension), it->second.name);
1682                     }
1683                 }
1684             } else if (1 < n) {  // key occurs multiple times, at least one must be enabled
1685                 bool needs_feature = false, has_feature = false;
1686                 bool needs_ext = false, has_ext = false;
1687                 std::string feature_names = "(one of) [ ";
1688                 std::string extension_names = feature_names;
1689                 auto caps = capabilities.equal_range(insn.word(1));
1690                 for (auto it = caps.first; it != caps.second; ++it) {
1691                     if (it->second.feature) {
1692                         needs_feature = true;
1693                         has_feature = has_feature || it->second.feature.IsEnabled(enabled_features);
1694                         feature_names += it->second.name;
1695                         feature_names += " ";
1696                     }
1697                     if (it->second.extension) {
1698                         needs_ext = true;
1699                         has_ext = has_ext || device_extensions.*(it->second.extension);
1700                         extension_names += it->second.name;
1701                         extension_names += " ";
1702                     }
1703                 }
1704                 if (needs_feature) {
1705                     feature_names += "]";
1706                     skip |= RequireFeature(report_data, has_feature, feature_names.c_str());
1707                 }
1708                 if (needs_ext) {
1709                     extension_names += "]";
1710                     skip |= RequireExtension(report_data, has_ext, extension_names.c_str());
1711                 }
1712             } else {  // Do group non-uniform checks
1713                 const VkSubgroupFeatureFlags supportedOperations = phys_dev_ext_props.subgroup_props.supportedOperations;
1714                 const VkSubgroupFeatureFlags supportedStages = phys_dev_ext_props.subgroup_props.supportedStages;
1715 
1716                 switch (insn.word(1)) {
1717                     default:
1718                         break;
1719                     case spv::CapabilityGroupNonUniform:
1720                     case spv::CapabilityGroupNonUniformVote:
1721                     case spv::CapabilityGroupNonUniformArithmetic:
1722                     case spv::CapabilityGroupNonUniformBallot:
1723                     case spv::CapabilityGroupNonUniformShuffle:
1724                     case spv::CapabilityGroupNonUniformShuffleRelative:
1725                     case spv::CapabilityGroupNonUniformClustered:
1726                     case spv::CapabilityGroupNonUniformQuad:
1727                     case spv::CapabilityGroupNonUniformPartitionedNV:
1728                         RequirePropertyFlag(report_data, supportedStages & stage, string_VkShaderStageFlagBits(stage),
1729                                             "VkPhysicalDeviceSubgroupProperties::supportedStages");
1730                         break;
1731                 }
1732 
1733                 switch (insn.word(1)) {
1734                     default:
1735                         break;
1736                     case spv::CapabilityGroupNonUniform:
1737                         RequirePropertyFlag(report_data, supportedOperations & VK_SUBGROUP_FEATURE_BASIC_BIT,
1738                                             "VK_SUBGROUP_FEATURE_BASIC_BIT",
1739                                             "VkPhysicalDeviceSubgroupProperties::supportedOperations");
1740                         break;
1741                     case spv::CapabilityGroupNonUniformVote:
1742                         RequirePropertyFlag(report_data, supportedOperations & VK_SUBGROUP_FEATURE_VOTE_BIT,
1743                                             "VK_SUBGROUP_FEATURE_VOTE_BIT",
1744                                             "VkPhysicalDeviceSubgroupProperties::supportedOperations");
1745                         break;
1746                     case spv::CapabilityGroupNonUniformArithmetic:
1747                         RequirePropertyFlag(report_data, supportedOperations & VK_SUBGROUP_FEATURE_ARITHMETIC_BIT,
1748                                             "VK_SUBGROUP_FEATURE_ARITHMETIC_BIT",
1749                                             "VkPhysicalDeviceSubgroupProperties::supportedOperations");
1750                         break;
1751                     case spv::CapabilityGroupNonUniformBallot:
1752                         RequirePropertyFlag(report_data, supportedOperations & VK_SUBGROUP_FEATURE_BALLOT_BIT,
1753                                             "VK_SUBGROUP_FEATURE_BALLOT_BIT",
1754                                             "VkPhysicalDeviceSubgroupProperties::supportedOperations");
1755                         break;
1756                     case spv::CapabilityGroupNonUniformShuffle:
1757                         RequirePropertyFlag(report_data, supportedOperations & VK_SUBGROUP_FEATURE_SHUFFLE_BIT,
1758                                             "VK_SUBGROUP_FEATURE_SHUFFLE_BIT",
1759                                             "VkPhysicalDeviceSubgroupProperties::supportedOperations");
1760                         break;
1761                     case spv::CapabilityGroupNonUniformShuffleRelative:
1762                         RequirePropertyFlag(report_data, supportedOperations & VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT,
1763                                             "VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT",
1764                                             "VkPhysicalDeviceSubgroupProperties::supportedOperations");
1765                         break;
1766                     case spv::CapabilityGroupNonUniformClustered:
1767                         RequirePropertyFlag(report_data, supportedOperations & VK_SUBGROUP_FEATURE_CLUSTERED_BIT,
1768                                             "VK_SUBGROUP_FEATURE_CLUSTERED_BIT",
1769                                             "VkPhysicalDeviceSubgroupProperties::supportedOperations");
1770                         break;
1771                     case spv::CapabilityGroupNonUniformQuad:
1772                         RequirePropertyFlag(report_data, supportedOperations & VK_SUBGROUP_FEATURE_QUAD_BIT,
1773                                             "VK_SUBGROUP_FEATURE_QUAD_BIT",
1774                                             "VkPhysicalDeviceSubgroupProperties::supportedOperations");
1775                         break;
1776                     case spv::CapabilityGroupNonUniformPartitionedNV:
1777                         RequirePropertyFlag(report_data, supportedOperations & VK_SUBGROUP_FEATURE_PARTITIONED_BIT_NV,
1778                                             "VK_SUBGROUP_FEATURE_PARTITIONED_BIT_NV",
1779                                             "VkPhysicalDeviceSubgroupProperties::supportedOperations");
1780                         break;
1781                 }
1782             }
1783         }
1784     }
1785 
1786     return skip;
1787 }
1788 
ValidateShaderStageWritableDescriptor(VkShaderStageFlagBits stage,bool has_writable_descriptor) const1789 bool CoreChecks::ValidateShaderStageWritableDescriptor(VkShaderStageFlagBits stage, bool has_writable_descriptor) const {
1790     bool skip = false;
1791 
1792     if (has_writable_descriptor) {
1793         switch (stage) {
1794             case VK_SHADER_STAGE_COMPUTE_BIT:
1795             case VK_SHADER_STAGE_RAYGEN_BIT_NV:
1796             case VK_SHADER_STAGE_ANY_HIT_BIT_NV:
1797             case VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV:
1798             case VK_SHADER_STAGE_MISS_BIT_NV:
1799             case VK_SHADER_STAGE_INTERSECTION_BIT_NV:
1800             case VK_SHADER_STAGE_CALLABLE_BIT_NV:
1801             case VK_SHADER_STAGE_TASK_BIT_NV:
1802             case VK_SHADER_STAGE_MESH_BIT_NV:
1803                 /* No feature requirements for writes and atomics from compute
1804                  * raytracing, or mesh stages */
1805                 break;
1806             case VK_SHADER_STAGE_FRAGMENT_BIT:
1807                 skip |= RequireFeature(report_data, enabled_features.core.fragmentStoresAndAtomics, "fragmentStoresAndAtomics");
1808                 break;
1809             default:
1810                 skip |= RequireFeature(report_data, enabled_features.core.vertexPipelineStoresAndAtomics,
1811                                        "vertexPipelineStoresAndAtomics");
1812                 break;
1813         }
1814     }
1815 
1816     return skip;
1817 }
1818 
ValidateShaderStageGroupNonUniform(SHADER_MODULE_STATE const * module,VkShaderStageFlagBits stage,std::unordered_set<uint32_t> const & accessible_ids) const1819 bool CoreChecks::ValidateShaderStageGroupNonUniform(SHADER_MODULE_STATE const *module, VkShaderStageFlagBits stage,
1820                                                     std::unordered_set<uint32_t> const &accessible_ids) const {
1821     bool skip = false;
1822 
1823     auto const subgroup_props = phys_dev_ext_props.subgroup_props;
1824 
1825     for (uint32_t id : accessible_ids) {
1826         auto inst = module->get_def(id);
1827 
1828         // Check the quad operations.
1829         switch (inst.opcode()) {
1830             default:
1831                 break;
1832             case spv::OpGroupNonUniformQuadBroadcast:
1833             case spv::OpGroupNonUniformQuadSwap:
1834                 if ((stage != VK_SHADER_STAGE_FRAGMENT_BIT) && (stage != VK_SHADER_STAGE_COMPUTE_BIT)) {
1835                     skip |= RequireFeature(report_data, subgroup_props.quadOperationsInAllStages,
1836                                            "VkPhysicalDeviceSubgroupProperties::quadOperationsInAllStages");
1837                 }
1838                 break;
1839         }
1840     }
1841 
1842     return skip;
1843 }
1844 
ValidateShaderStageInputOutputLimits(SHADER_MODULE_STATE const * src,VkPipelineShaderStageCreateInfo const * pStage,const PIPELINE_STATE * pipeline,spirv_inst_iter entrypoint) const1845 bool CoreChecks::ValidateShaderStageInputOutputLimits(SHADER_MODULE_STATE const *src, VkPipelineShaderStageCreateInfo const *pStage,
1846                                                       const PIPELINE_STATE *pipeline, spirv_inst_iter entrypoint) const {
1847     if (pStage->stage == VK_SHADER_STAGE_COMPUTE_BIT || pStage->stage == VK_SHADER_STAGE_ALL_GRAPHICS ||
1848         pStage->stage == VK_SHADER_STAGE_ALL) {
1849         return false;
1850     }
1851 
1852     bool skip = false;
1853     auto const &limits = phys_dev_props.limits;
1854 
1855     std::set<uint32_t> patchIDs;
1856     struct Variable {
1857         uint32_t baseTypePtrID;
1858         uint32_t ID;
1859         uint32_t storageClass;
1860     };
1861     std::vector<Variable> variables;
1862 
1863     uint32_t numVertices = 0;
1864 
1865     for (auto insn : *src) {
1866         switch (insn.opcode()) {
1867             // Find all Patch decorations
1868             case spv::OpDecorate:
1869                 switch (insn.word(2)) {
1870                     case spv::DecorationPatch: {
1871                         patchIDs.insert(insn.word(1));
1872                         break;
1873                     }
1874                     default:
1875                         break;
1876                 }
1877                 break;
1878             // Find all input and output variables
1879             case spv::OpVariable: {
1880                 Variable var = {};
1881                 var.storageClass = insn.word(3);
1882                 if (var.storageClass == spv::StorageClassInput || var.storageClass == spv::StorageClassOutput) {
1883                     var.baseTypePtrID = insn.word(1);
1884                     var.ID = insn.word(2);
1885                     variables.push_back(var);
1886                 }
1887                 break;
1888             }
1889             case spv::OpExecutionMode:
1890                 if (insn.word(1) == entrypoint.word(2)) {
1891                     switch (insn.word(2)) {
1892                         default:
1893                             break;
1894                         case spv::ExecutionModeOutputVertices:
1895                             numVertices = insn.word(3);
1896                             break;
1897                     }
1898                 }
1899                 break;
1900             default:
1901                 break;
1902         }
1903     }
1904 
1905     bool strip_output_array_level =
1906         (pStage->stage == VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT || pStage->stage == VK_SHADER_STAGE_MESH_BIT_NV);
1907     bool strip_input_array_level =
1908         (pStage->stage == VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT ||
1909          pStage->stage == VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT || pStage->stage == VK_SHADER_STAGE_GEOMETRY_BIT);
1910 
1911     uint32_t numCompIn = 0, numCompOut = 0;
1912     for (auto &var : variables) {
1913         // Check if the variable is a patch. Patches can also be members of blocks,
1914         // but if they are then the top-level arrayness has already been stripped
1915         // by the time GetComponentsConsumedByType gets to it.
1916         bool isPatch = patchIDs.find(var.ID) != patchIDs.end();
1917 
1918         if (var.storageClass == spv::StorageClassInput) {
1919             numCompIn += GetComponentsConsumedByType(src, var.baseTypePtrID, strip_input_array_level && !isPatch);
1920         } else {  // var.storageClass == spv::StorageClassOutput
1921             numCompOut += GetComponentsConsumedByType(src, var.baseTypePtrID, strip_output_array_level && !isPatch);
1922         }
1923     }
1924 
1925     switch (pStage->stage) {
1926         case VK_SHADER_STAGE_VERTEX_BIT:
1927             if (numCompOut > limits.maxVertexOutputComponents) {
1928                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
1929                                 HandleToUint64(pipeline->pipeline), kVUID_Core_Shader_ExceedDeviceLimit,
1930                                 "Invalid Pipeline CreateInfo State: Vertex shader exceeds "
1931                                 "VkPhysicalDeviceLimits::maxVertexOutputComponents of %u "
1932                                 "components by %u components",
1933                                 limits.maxVertexOutputComponents, numCompOut - limits.maxVertexOutputComponents);
1934             }
1935             break;
1936 
1937         case VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT:
1938             if (numCompIn > limits.maxTessellationControlPerVertexInputComponents) {
1939                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
1940                                 HandleToUint64(pipeline->pipeline), kVUID_Core_Shader_ExceedDeviceLimit,
1941                                 "Invalid Pipeline CreateInfo State: Tessellation control shader exceeds "
1942                                 "VkPhysicalDeviceLimits::maxTessellationControlPerVertexInputComponents of %u "
1943                                 "components by %u components",
1944                                 limits.maxTessellationControlPerVertexInputComponents,
1945                                 numCompIn - limits.maxTessellationControlPerVertexInputComponents);
1946             }
1947             if (numCompOut > limits.maxTessellationControlPerVertexOutputComponents) {
1948                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
1949                                 HandleToUint64(pipeline->pipeline), kVUID_Core_Shader_ExceedDeviceLimit,
1950                                 "Invalid Pipeline CreateInfo State: Tessellation control shader exceeds "
1951                                 "VkPhysicalDeviceLimits::maxTessellationControlPerVertexOutputComponents of %u "
1952                                 "components by %u components",
1953                                 limits.maxTessellationControlPerVertexOutputComponents,
1954                                 numCompOut - limits.maxTessellationControlPerVertexOutputComponents);
1955             }
1956             break;
1957 
1958         case VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT:
1959             if (numCompIn > limits.maxTessellationEvaluationInputComponents) {
1960                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
1961                                 HandleToUint64(pipeline->pipeline), kVUID_Core_Shader_ExceedDeviceLimit,
1962                                 "Invalid Pipeline CreateInfo State: Tessellation evaluation shader exceeds "
1963                                 "VkPhysicalDeviceLimits::maxTessellationEvaluationInputComponents of %u "
1964                                 "components by %u components",
1965                                 limits.maxTessellationEvaluationInputComponents,
1966                                 numCompIn - limits.maxTessellationEvaluationInputComponents);
1967             }
1968             if (numCompOut > limits.maxTessellationEvaluationOutputComponents) {
1969                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
1970                                 HandleToUint64(pipeline->pipeline), kVUID_Core_Shader_ExceedDeviceLimit,
1971                                 "Invalid Pipeline CreateInfo State: Tessellation evaluation shader exceeds "
1972                                 "VkPhysicalDeviceLimits::maxTessellationEvaluationOutputComponents of %u "
1973                                 "components by %u components",
1974                                 limits.maxTessellationEvaluationOutputComponents,
1975                                 numCompOut - limits.maxTessellationEvaluationOutputComponents);
1976             }
1977             break;
1978 
1979         case VK_SHADER_STAGE_GEOMETRY_BIT:
1980             if (numCompIn > limits.maxGeometryInputComponents) {
1981                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
1982                                 HandleToUint64(pipeline->pipeline), kVUID_Core_Shader_ExceedDeviceLimit,
1983                                 "Invalid Pipeline CreateInfo State: Geometry shader exceeds "
1984                                 "VkPhysicalDeviceLimits::maxGeometryInputComponents of %u "
1985                                 "components by %u components",
1986                                 limits.maxGeometryInputComponents, numCompIn - limits.maxGeometryInputComponents);
1987             }
1988             if (numCompOut > limits.maxGeometryOutputComponents) {
1989                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
1990                                 HandleToUint64(pipeline->pipeline), kVUID_Core_Shader_ExceedDeviceLimit,
1991                                 "Invalid Pipeline CreateInfo State: Geometry shader exceeds "
1992                                 "VkPhysicalDeviceLimits::maxGeometryOutputComponents of %u "
1993                                 "components by %u components",
1994                                 limits.maxGeometryOutputComponents, numCompOut - limits.maxGeometryOutputComponents);
1995             }
1996             if (numCompOut * numVertices > limits.maxGeometryTotalOutputComponents) {
1997                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
1998                                 HandleToUint64(pipeline->pipeline), kVUID_Core_Shader_ExceedDeviceLimit,
1999                                 "Invalid Pipeline CreateInfo State: Geometry shader exceeds "
2000                                 "VkPhysicalDeviceLimits::maxGeometryTotalOutputComponents of %u "
2001                                 "components by %u components",
2002                                 limits.maxGeometryTotalOutputComponents,
2003                                 numCompOut * numVertices - limits.maxGeometryTotalOutputComponents);
2004             }
2005             break;
2006 
2007         case VK_SHADER_STAGE_FRAGMENT_BIT:
2008             if (numCompIn > limits.maxFragmentInputComponents) {
2009                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2010                                 HandleToUint64(pipeline->pipeline), kVUID_Core_Shader_ExceedDeviceLimit,
2011                                 "Invalid Pipeline CreateInfo State: Fragment shader exceeds "
2012                                 "VkPhysicalDeviceLimits::maxFragmentInputComponents of %u "
2013                                 "components by %u components",
2014                                 limits.maxFragmentInputComponents, numCompIn - limits.maxFragmentInputComponents);
2015             }
2016             break;
2017 
2018         case VK_SHADER_STAGE_RAYGEN_BIT_NV:
2019         case VK_SHADER_STAGE_ANY_HIT_BIT_NV:
2020         case VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV:
2021         case VK_SHADER_STAGE_MISS_BIT_NV:
2022         case VK_SHADER_STAGE_INTERSECTION_BIT_NV:
2023         case VK_SHADER_STAGE_CALLABLE_BIT_NV:
2024         case VK_SHADER_STAGE_TASK_BIT_NV:
2025         case VK_SHADER_STAGE_MESH_BIT_NV:
2026             break;
2027 
2028         default:
2029             assert(false);  // This should never happen
2030     }
2031     return skip;
2032 }
2033 
2034 // copy the specialization constant value into buf, if it is present
GetSpecConstantValue(VkPipelineShaderStageCreateInfo const * pStage,uint32_t spec_id,void * buf)2035 void GetSpecConstantValue(VkPipelineShaderStageCreateInfo const *pStage, uint32_t spec_id, void *buf) {
2036     VkSpecializationInfo const *spec = pStage->pSpecializationInfo;
2037 
2038     if (spec && spec_id < spec->mapEntryCount) {
2039         memcpy(buf, (uint8_t *)spec->pData + spec->pMapEntries[spec_id].offset, spec->pMapEntries[spec_id].size);
2040     }
2041 }
2042 
2043 // Fill in value with the constant or specialization constant value, if available.
2044 // Returns true if the value has been accurately filled out.
GetIntConstantValue(spirv_inst_iter insn,SHADER_MODULE_STATE const * src,VkPipelineShaderStageCreateInfo const * pStage,const std::unordered_map<uint32_t,uint32_t> & id_to_spec_id,uint32_t * value)2045 static bool GetIntConstantValue(spirv_inst_iter insn, SHADER_MODULE_STATE const *src, VkPipelineShaderStageCreateInfo const *pStage,
2046                                 const std::unordered_map<uint32_t, uint32_t> &id_to_spec_id, uint32_t *value) {
2047     auto type_id = src->get_def(insn.word(1));
2048     if (type_id.opcode() != spv::OpTypeInt || type_id.word(2) != 32) {
2049         return false;
2050     }
2051     switch (insn.opcode()) {
2052         case spv::OpSpecConstant:
2053             *value = insn.word(3);
2054             GetSpecConstantValue(pStage, id_to_spec_id.at(insn.word(2)), value);
2055             return true;
2056         case spv::OpConstant:
2057             *value = insn.word(3);
2058             return true;
2059         default:
2060             return false;
2061     }
2062 }
2063 
2064 // Map SPIR-V type to VK_COMPONENT_TYPE enum
GetComponentType(spirv_inst_iter insn,SHADER_MODULE_STATE const * src)2065 VkComponentTypeNV GetComponentType(spirv_inst_iter insn, SHADER_MODULE_STATE const *src) {
2066     switch (insn.opcode()) {
2067         case spv::OpTypeInt:
2068             switch (insn.word(2)) {
2069                 case 8:
2070                     return insn.word(3) != 0 ? VK_COMPONENT_TYPE_SINT8_NV : VK_COMPONENT_TYPE_UINT8_NV;
2071                 case 16:
2072                     return insn.word(3) != 0 ? VK_COMPONENT_TYPE_SINT16_NV : VK_COMPONENT_TYPE_UINT16_NV;
2073                 case 32:
2074                     return insn.word(3) != 0 ? VK_COMPONENT_TYPE_SINT32_NV : VK_COMPONENT_TYPE_UINT32_NV;
2075                 case 64:
2076                     return insn.word(3) != 0 ? VK_COMPONENT_TYPE_SINT64_NV : VK_COMPONENT_TYPE_UINT64_NV;
2077                 default:
2078                     return VK_COMPONENT_TYPE_MAX_ENUM_NV;
2079             }
2080         case spv::OpTypeFloat:
2081             switch (insn.word(2)) {
2082                 case 16:
2083                     return VK_COMPONENT_TYPE_FLOAT16_NV;
2084                 case 32:
2085                     return VK_COMPONENT_TYPE_FLOAT32_NV;
2086                 case 64:
2087                     return VK_COMPONENT_TYPE_FLOAT64_NV;
2088                 default:
2089                     return VK_COMPONENT_TYPE_MAX_ENUM_NV;
2090             }
2091         default:
2092             return VK_COMPONENT_TYPE_MAX_ENUM_NV;
2093     }
2094 }
2095 
2096 // Validate SPV_NV_cooperative_matrix behavior that can't be statically validated
2097 // in SPIRV-Tools (e.g. due to specialization constant usage).
ValidateCooperativeMatrix(SHADER_MODULE_STATE const * src,VkPipelineShaderStageCreateInfo const * pStage,const PIPELINE_STATE * pipeline) const2098 bool CoreChecks::ValidateCooperativeMatrix(SHADER_MODULE_STATE const *src, VkPipelineShaderStageCreateInfo const *pStage,
2099                                            const PIPELINE_STATE *pipeline) const {
2100     bool skip = false;
2101 
2102     // Map SPIR-V result ID to specialization constant id (SpecId decoration value)
2103     std::unordered_map<uint32_t, uint32_t> id_to_spec_id;
2104     // Map SPIR-V result ID to the ID of its type.
2105     std::unordered_map<uint32_t, uint32_t> id_to_type_id;
2106 
2107     struct CoopMatType {
2108         uint32_t scope, rows, cols;
2109         VkComponentTypeNV component_type;
2110         bool all_constant;
2111 
2112         CoopMatType() : scope(0), rows(0), cols(0), component_type(VK_COMPONENT_TYPE_MAX_ENUM_NV), all_constant(false) {}
2113 
2114         void Init(uint32_t id, SHADER_MODULE_STATE const *src, VkPipelineShaderStageCreateInfo const *pStage,
2115                   const std::unordered_map<uint32_t, uint32_t> &id_to_spec_id) {
2116             spirv_inst_iter insn = src->get_def(id);
2117             uint32_t component_type_id = insn.word(2);
2118             uint32_t scope_id = insn.word(3);
2119             uint32_t rows_id = insn.word(4);
2120             uint32_t cols_id = insn.word(5);
2121             auto component_type_iter = src->get_def(component_type_id);
2122             auto scope_iter = src->get_def(scope_id);
2123             auto rows_iter = src->get_def(rows_id);
2124             auto cols_iter = src->get_def(cols_id);
2125 
2126             all_constant = true;
2127             if (!GetIntConstantValue(scope_iter, src, pStage, id_to_spec_id, &scope)) {
2128                 all_constant = false;
2129             }
2130             if (!GetIntConstantValue(rows_iter, src, pStage, id_to_spec_id, &rows)) {
2131                 all_constant = false;
2132             }
2133             if (!GetIntConstantValue(cols_iter, src, pStage, id_to_spec_id, &cols)) {
2134                 all_constant = false;
2135             }
2136             component_type = GetComponentType(component_type_iter, src);
2137         }
2138     };
2139 
2140     bool seen_coopmat_capability = false;
2141 
2142     for (auto insn : *src) {
2143         // Whitelist instructions whose result can be a cooperative matrix type, and
2144         // keep track of their types. It would be nice if SPIRV-Headers generated code
2145         // to identify which instructions have a result type and result id. Lacking that,
2146         // this whitelist is based on the set of instructions that
2147         // SPV_NV_cooperative_matrix says can be used with cooperative matrix types.
2148         switch (insn.opcode()) {
2149             case spv::OpLoad:
2150             case spv::OpCooperativeMatrixLoadNV:
2151             case spv::OpCooperativeMatrixMulAddNV:
2152             case spv::OpSNegate:
2153             case spv::OpFNegate:
2154             case spv::OpIAdd:
2155             case spv::OpFAdd:
2156             case spv::OpISub:
2157             case spv::OpFSub:
2158             case spv::OpFDiv:
2159             case spv::OpSDiv:
2160             case spv::OpUDiv:
2161             case spv::OpMatrixTimesScalar:
2162             case spv::OpConstantComposite:
2163             case spv::OpCompositeConstruct:
2164             case spv::OpConvertFToU:
2165             case spv::OpConvertFToS:
2166             case spv::OpConvertSToF:
2167             case spv::OpConvertUToF:
2168             case spv::OpUConvert:
2169             case spv::OpSConvert:
2170             case spv::OpFConvert:
2171                 id_to_type_id[insn.word(2)] = insn.word(1);
2172                 break;
2173             default:
2174                 break;
2175         }
2176 
2177         switch (insn.opcode()) {
2178             case spv::OpDecorate:
2179                 if (insn.word(2) == spv::DecorationSpecId) {
2180                     id_to_spec_id[insn.word(1)] = insn.word(3);
2181                 }
2182                 break;
2183             case spv::OpCapability:
2184                 if (insn.word(1) == spv::CapabilityCooperativeMatrixNV) {
2185                     seen_coopmat_capability = true;
2186 
2187                     if (!(pStage->stage & phys_dev_ext_props.cooperative_matrix_props.cooperativeMatrixSupportedStages)) {
2188                         skip |=
2189                             log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2190                                     HandleToUint64(pipeline->pipeline), kVUID_Core_Shader_CooperativeMatrixSupportedStages,
2191                                     "OpTypeCooperativeMatrixNV used in shader stage not in cooperativeMatrixSupportedStages (= %u)",
2192                                     phys_dev_ext_props.cooperative_matrix_props.cooperativeMatrixSupportedStages);
2193                     }
2194                 }
2195                 break;
2196             case spv::OpMemoryModel:
2197                 // If the capability isn't enabled, don't bother with the rest of this function.
2198                 // OpMemoryModel is the first required instruction after all OpCapability instructions.
2199                 if (!seen_coopmat_capability) {
2200                     return skip;
2201                 }
2202                 break;
2203             case spv::OpTypeCooperativeMatrixNV: {
2204                 CoopMatType M;
2205                 M.Init(insn.word(1), src, pStage, id_to_spec_id);
2206 
2207                 if (M.all_constant) {
2208                     // Validate that the type parameters are all supported for one of the
2209                     // operands of a cooperative matrix property.
2210                     bool valid = false;
2211                     for (unsigned i = 0; i < cooperative_matrix_properties.size(); ++i) {
2212                         if (cooperative_matrix_properties[i].AType == M.component_type &&
2213                             cooperative_matrix_properties[i].MSize == M.rows && cooperative_matrix_properties[i].KSize == M.cols &&
2214                             cooperative_matrix_properties[i].scope == M.scope) {
2215                             valid = true;
2216                             break;
2217                         }
2218                         if (cooperative_matrix_properties[i].BType == M.component_type &&
2219                             cooperative_matrix_properties[i].KSize == M.rows && cooperative_matrix_properties[i].NSize == M.cols &&
2220                             cooperative_matrix_properties[i].scope == M.scope) {
2221                             valid = true;
2222                             break;
2223                         }
2224                         if (cooperative_matrix_properties[i].CType == M.component_type &&
2225                             cooperative_matrix_properties[i].MSize == M.rows && cooperative_matrix_properties[i].NSize == M.cols &&
2226                             cooperative_matrix_properties[i].scope == M.scope) {
2227                             valid = true;
2228                             break;
2229                         }
2230                         if (cooperative_matrix_properties[i].DType == M.component_type &&
2231                             cooperative_matrix_properties[i].MSize == M.rows && cooperative_matrix_properties[i].NSize == M.cols &&
2232                             cooperative_matrix_properties[i].scope == M.scope) {
2233                             valid = true;
2234                             break;
2235                         }
2236                     }
2237                     if (!valid) {
2238                         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2239                                         HandleToUint64(pipeline->pipeline), kVUID_Core_Shader_CooperativeMatrixType,
2240                                         "OpTypeCooperativeMatrixNV (result id = %u) operands don't match a supported matrix type",
2241                                         insn.word(1));
2242                     }
2243                 }
2244                 break;
2245             }
2246             case spv::OpCooperativeMatrixMulAddNV: {
2247                 CoopMatType A, B, C, D;
2248                 if (id_to_type_id.find(insn.word(2)) == id_to_type_id.end() ||
2249                     id_to_type_id.find(insn.word(3)) == id_to_type_id.end() ||
2250                     id_to_type_id.find(insn.word(4)) == id_to_type_id.end() ||
2251                     id_to_type_id.find(insn.word(5)) == id_to_type_id.end()) {
2252                     // Couldn't find type of matrix
2253                     assert(false);
2254                     break;
2255                 }
2256                 D.Init(id_to_type_id[insn.word(2)], src, pStage, id_to_spec_id);
2257                 A.Init(id_to_type_id[insn.word(3)], src, pStage, id_to_spec_id);
2258                 B.Init(id_to_type_id[insn.word(4)], src, pStage, id_to_spec_id);
2259                 C.Init(id_to_type_id[insn.word(5)], src, pStage, id_to_spec_id);
2260 
2261                 if (A.all_constant && B.all_constant && C.all_constant && D.all_constant) {
2262                     // Validate that the type parameters are all supported for the same
2263                     // cooperative matrix property.
2264                     bool valid = false;
2265                     for (unsigned i = 0; i < cooperative_matrix_properties.size(); ++i) {
2266                         if (cooperative_matrix_properties[i].AType == A.component_type &&
2267                             cooperative_matrix_properties[i].MSize == A.rows && cooperative_matrix_properties[i].KSize == A.cols &&
2268                             cooperative_matrix_properties[i].scope == A.scope &&
2269 
2270                             cooperative_matrix_properties[i].BType == B.component_type &&
2271                             cooperative_matrix_properties[i].KSize == B.rows && cooperative_matrix_properties[i].NSize == B.cols &&
2272                             cooperative_matrix_properties[i].scope == B.scope &&
2273 
2274                             cooperative_matrix_properties[i].CType == C.component_type &&
2275                             cooperative_matrix_properties[i].MSize == C.rows && cooperative_matrix_properties[i].NSize == C.cols &&
2276                             cooperative_matrix_properties[i].scope == C.scope &&
2277 
2278                             cooperative_matrix_properties[i].DType == D.component_type &&
2279                             cooperative_matrix_properties[i].MSize == D.rows && cooperative_matrix_properties[i].NSize == D.cols &&
2280                             cooperative_matrix_properties[i].scope == D.scope) {
2281                             valid = true;
2282                             break;
2283                         }
2284                     }
2285                     if (!valid) {
2286                         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2287                                         HandleToUint64(pipeline->pipeline), kVUID_Core_Shader_CooperativeMatrixMulAdd,
2288                                         "OpCooperativeMatrixMulAddNV (result id = %u) operands don't match a supported matrix "
2289                                         "VkCooperativeMatrixPropertiesNV",
2290                                         insn.word(2));
2291                     }
2292                 }
2293                 break;
2294             }
2295             default:
2296                 break;
2297         }
2298     }
2299 
2300     return skip;
2301 }
2302 
ValidateExecutionModes(SHADER_MODULE_STATE const * src,spirv_inst_iter entrypoint) const2303 bool CoreChecks::ValidateExecutionModes(SHADER_MODULE_STATE const *src, spirv_inst_iter entrypoint) const {
2304     auto entrypoint_id = entrypoint.word(2);
2305 
2306     // The first denorm execution mode encountered, along with its bit width.
2307     // Used to check if SeparateDenormSettings is respected.
2308     std::pair<spv::ExecutionMode, uint32_t> first_denorm_execution_mode = std::make_pair(spv::ExecutionModeMax, 0);
2309 
2310     // The first rounding mode encountered, along with its bit width.
2311     // Used to check if SeparateRoundingModeSettings is respected.
2312     std::pair<spv::ExecutionMode, uint32_t> first_rounding_mode = std::make_pair(spv::ExecutionModeMax, 0);
2313 
2314     bool skip = false;
2315 
2316     uint32_t verticesOut = 0;
2317     uint32_t invocations = 0;
2318 
2319     for (auto insn : *src) {
2320         if (insn.opcode() == spv::OpExecutionMode && insn.word(1) == entrypoint_id) {
2321             auto mode = insn.word(2);
2322             switch (mode) {
2323                 case spv::ExecutionModeSignedZeroInfNanPreserve: {
2324                     auto bit_width = insn.word(3);
2325                     if ((bit_width == 16 && !enabled_features.float_controls.shaderSignedZeroInfNanPreserveFloat16) ||
2326                         (bit_width == 32 && !enabled_features.float_controls.shaderSignedZeroInfNanPreserveFloat32) ||
2327                         (bit_width == 64 && !enabled_features.float_controls.shaderSignedZeroInfNanPreserveFloat64)) {
2328                         skip |=
2329                             log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
2330                                     kVUID_Core_Shader_FeatureNotEnabled,
2331                                     "Shader requires SignedZeroInfNanPreserve for bit width %d but it is not enabled on the device",
2332                                     bit_width);
2333                     }
2334                     break;
2335                 }
2336 
2337                 case spv::ExecutionModeDenormPreserve: {
2338                     auto bit_width = insn.word(3);
2339                     if ((bit_width == 16 && !enabled_features.float_controls.shaderDenormPreserveFloat16) ||
2340                         (bit_width == 32 && !enabled_features.float_controls.shaderDenormPreserveFloat32) ||
2341                         (bit_width == 64 && !enabled_features.float_controls.shaderDenormPreserveFloat64)) {
2342                         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
2343                                         kVUID_Core_Shader_FeatureNotEnabled,
2344                                         "Shader requires DenormPreserve for bit width %d but it is not enabled on the device",
2345                                         bit_width);
2346                     }
2347 
2348                     if (first_denorm_execution_mode.first == spv::ExecutionModeMax) {
2349                         // Register the first denorm execution mode found
2350                         first_denorm_execution_mode = std::make_pair(static_cast<spv::ExecutionMode>(mode), bit_width);
2351                     } else if (first_denorm_execution_mode.first != mode && first_denorm_execution_mode.second != bit_width) {
2352                         switch (enabled_features.float_controls.denormBehaviorIndependence) {
2353                             case VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_32_BIT_ONLY_KHR:
2354                                 if (first_rounding_mode.second != 32 && bit_width != 32) {
2355                                     skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
2356                                                     VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, kVUID_Core_Shader_FeatureNotEnabled,
2357                                                     "Shader uses different denorm execution modes for 16 and 64-bit but "
2358                                                     "denormBehaviorIndependence is "
2359                                                     "VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_32_BIT_ONLY_KHR on the device");
2360                                 }
2361                                 break;
2362 
2363                             case VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL_KHR:
2364                                 break;
2365 
2366                             case VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE_KHR:
2367                                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
2368                                                 0, kVUID_Core_Shader_FeatureNotEnabled,
2369                                                 "Shader uses different denorm execution modes for different bit widths but "
2370                                                 "denormBehaviorIndependence is "
2371                                                 "VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE_KHR on the device");
2372                                 break;
2373 
2374                             default:
2375                                 break;
2376                         }
2377                     }
2378                     break;
2379                 }
2380 
2381                 case spv::ExecutionModeDenormFlushToZero: {
2382                     auto bit_width = insn.word(3);
2383                     if ((bit_width == 16 && !enabled_features.float_controls.shaderDenormFlushToZeroFloat16) ||
2384                         (bit_width == 32 && !enabled_features.float_controls.shaderDenormFlushToZeroFloat32) ||
2385                         (bit_width == 64 && !enabled_features.float_controls.shaderDenormFlushToZeroFloat64)) {
2386                         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
2387                                         kVUID_Core_Shader_FeatureNotEnabled,
2388                                         "Shader requires DenormFlushToZero for bit width %d but it is not enabled on the device",
2389                                         bit_width);
2390                     }
2391 
2392                     if (first_denorm_execution_mode.first == spv::ExecutionModeMax) {
2393                         // Register the first denorm execution mode found
2394                         first_denorm_execution_mode = std::make_pair(static_cast<spv::ExecutionMode>(mode), bit_width);
2395                     } else if (first_denorm_execution_mode.first != mode && first_denorm_execution_mode.second != bit_width) {
2396                         switch (enabled_features.float_controls.denormBehaviorIndependence) {
2397                             case VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_32_BIT_ONLY_KHR:
2398                                 if (first_rounding_mode.second != 32 && bit_width != 32) {
2399                                     skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
2400                                                     VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, kVUID_Core_Shader_FeatureNotEnabled,
2401                                                     "Shader uses different denorm execution modes for 16 and 64-bit but "
2402                                                     "denormBehaviorIndependence is "
2403                                                     "VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_32_BIT_ONLY_KHR on the device");
2404                                 }
2405                                 break;
2406 
2407                             case VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL_KHR:
2408                                 break;
2409 
2410                             case VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE_KHR:
2411                                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
2412                                                 0, kVUID_Core_Shader_FeatureNotEnabled,
2413                                                 "Shader uses different denorm execution modes for different bit widths but "
2414                                                 "denormBehaviorIndependence is "
2415                                                 "VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE_KHR on the device");
2416                                 break;
2417 
2418                             default:
2419                                 break;
2420                         }
2421                     }
2422                     break;
2423                 }
2424 
2425                 case spv::ExecutionModeRoundingModeRTE: {
2426                     auto bit_width = insn.word(3);
2427                     if ((bit_width == 16 && !enabled_features.float_controls.shaderRoundingModeRTEFloat16) ||
2428                         (bit_width == 32 && !enabled_features.float_controls.shaderRoundingModeRTEFloat32) ||
2429                         (bit_width == 64 && !enabled_features.float_controls.shaderRoundingModeRTEFloat64)) {
2430                         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
2431                                         kVUID_Core_Shader_FeatureNotEnabled,
2432                                         "Shader requires RoundingModeRTE for bit width %d but it is not enabled on the device",
2433                                         bit_width);
2434                     }
2435 
2436                     if (first_rounding_mode.first == spv::ExecutionModeMax) {
2437                         // Register the first rounding mode found
2438                         first_rounding_mode = std::make_pair(static_cast<spv::ExecutionMode>(mode), bit_width);
2439                     } else if (first_rounding_mode.first != mode && first_rounding_mode.second != bit_width) {
2440                         switch (enabled_features.float_controls.roundingModeIndependence) {
2441                             case VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_32_BIT_ONLY_KHR:
2442                                 if (first_rounding_mode.second != 32 && bit_width != 32) {
2443                                     skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
2444                                                     VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, kVUID_Core_Shader_FeatureNotEnabled,
2445                                                     "Shader uses different rounding modes for 16 and 64-bit but "
2446                                                     "roundingModeIndependence is "
2447                                                     "VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_32_BIT_ONLY_KHR on the device");
2448                                 }
2449                                 break;
2450 
2451                             case VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL_KHR:
2452                                 break;
2453 
2454                             case VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE_KHR:
2455                                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
2456                                                 0, kVUID_Core_Shader_FeatureNotEnabled,
2457                                                 "Shader uses different rounding modes for different bit widths but "
2458                                                 "roundingModeIndependence is "
2459                                                 "VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE_KHR on the device");
2460                                 break;
2461 
2462                             default:
2463                                 break;
2464                         }
2465                     }
2466                     break;
2467                 }
2468 
2469                 case spv::ExecutionModeRoundingModeRTZ: {
2470                     auto bit_width = insn.word(3);
2471                     if ((bit_width == 16 && !enabled_features.float_controls.shaderRoundingModeRTZFloat16) ||
2472                         (bit_width == 32 && !enabled_features.float_controls.shaderRoundingModeRTZFloat32) ||
2473                         (bit_width == 64 && !enabled_features.float_controls.shaderRoundingModeRTZFloat64)) {
2474                         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
2475                                         kVUID_Core_Shader_FeatureNotEnabled,
2476                                         "Shader requires RoundingModeRTZ for bit width %d but it is not enabled on the device",
2477                                         bit_width);
2478                     }
2479 
2480                     if (first_rounding_mode.first == spv::ExecutionModeMax) {
2481                         // Register the first rounding mode found
2482                         first_rounding_mode = std::make_pair(static_cast<spv::ExecutionMode>(mode), bit_width);
2483                     } else if (first_rounding_mode.first != mode && first_rounding_mode.second != bit_width) {
2484                         switch (enabled_features.float_controls.roundingModeIndependence) {
2485                             case VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_32_BIT_ONLY_KHR:
2486                                 if (first_rounding_mode.second != 32 && bit_width != 32) {
2487                                     skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT,
2488                                                     VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, kVUID_Core_Shader_FeatureNotEnabled,
2489                                                     "Shader uses different rounding modes for 16 and 64-bit but "
2490                                                     "roundingModeIndependence is "
2491                                                     "VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_32_BIT_ONLY_KHR on the device");
2492                                 }
2493                                 break;
2494 
2495                             case VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL_KHR:
2496                                 break;
2497 
2498                             case VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE_KHR:
2499                                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
2500                                                 0, kVUID_Core_Shader_FeatureNotEnabled,
2501                                                 "Shader uses different rounding modes for different bit widths but "
2502                                                 "roundingModeIndependence is "
2503                                                 "VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_NONE_KHR on the device");
2504                                 break;
2505 
2506                             default:
2507                                 break;
2508                         }
2509                     }
2510                     break;
2511                 }
2512 
2513                 case spv::ExecutionModeOutputVertices: {
2514                     verticesOut = insn.word(3);
2515                     break;
2516                 }
2517 
2518                 case spv::ExecutionModeInvocations: {
2519                     invocations = insn.word(3);
2520                     break;
2521                 }
2522             }
2523         }
2524     }
2525 
2526     if (entrypoint.word(1) == spv::ExecutionModelGeometry) {
2527         if (verticesOut == 0 || verticesOut > phys_dev_props.limits.maxGeometryOutputVertices) {
2528             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
2529                             "VUID-VkPipelineShaderStageCreateInfo-stage-00714",
2530                             "Geometry shader entry point must have an OpExecutionMode instruction that "
2531                             "specifies a maximum output vertex count that is greater than 0 and less "
2532                             "than or equal to maxGeometryOutputVertices. "
2533                             "OutputVertices=%d, maxGeometryOutputVertices=%d",
2534                             verticesOut, phys_dev_props.limits.maxGeometryOutputVertices);
2535         }
2536 
2537         if (invocations == 0 || invocations > phys_dev_props.limits.maxGeometryShaderInvocations) {
2538             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
2539                             "VUID-VkPipelineShaderStageCreateInfo-stage-00715",
2540                             "Geometry shader entry point must have an OpExecutionMode instruction that "
2541                             "specifies an invocation count that is greater than 0 and less "
2542                             "than or equal to maxGeometryShaderInvocations. "
2543                             "Invocations=%d, maxGeometryShaderInvocations=%d",
2544                             invocations, phys_dev_props.limits.maxGeometryShaderInvocations);
2545         }
2546     }
2547     return skip;
2548 }
2549 
DescriptorTypeToReqs(SHADER_MODULE_STATE const * module,uint32_t type_id)2550 static uint32_t DescriptorTypeToReqs(SHADER_MODULE_STATE const *module, uint32_t type_id) {
2551     auto type = module->get_def(type_id);
2552 
2553     while (true) {
2554         switch (type.opcode()) {
2555             case spv::OpTypeArray:
2556             case spv::OpTypeRuntimeArray:
2557             case spv::OpTypeSampledImage:
2558                 type = module->get_def(type.word(2));
2559                 break;
2560             case spv::OpTypePointer:
2561                 type = module->get_def(type.word(3));
2562                 break;
2563             case spv::OpTypeImage: {
2564                 auto dim = type.word(3);
2565                 auto arrayed = type.word(5);
2566                 auto msaa = type.word(6);
2567 
2568                 uint32_t bits = 0;
2569                 switch (GetFundamentalType(module, type.word(2))) {
2570                     case FORMAT_TYPE_FLOAT:
2571                         bits = DESCRIPTOR_REQ_COMPONENT_TYPE_FLOAT;
2572                         break;
2573                     case FORMAT_TYPE_UINT:
2574                         bits = DESCRIPTOR_REQ_COMPONENT_TYPE_UINT;
2575                         break;
2576                     case FORMAT_TYPE_SINT:
2577                         bits = DESCRIPTOR_REQ_COMPONENT_TYPE_SINT;
2578                         break;
2579                     default:
2580                         break;
2581                 }
2582 
2583                 switch (dim) {
2584                     case spv::Dim1D:
2585                         bits |= arrayed ? DESCRIPTOR_REQ_VIEW_TYPE_1D_ARRAY : DESCRIPTOR_REQ_VIEW_TYPE_1D;
2586                         return bits;
2587                     case spv::Dim2D:
2588                         bits |= msaa ? DESCRIPTOR_REQ_MULTI_SAMPLE : DESCRIPTOR_REQ_SINGLE_SAMPLE;
2589                         bits |= arrayed ? DESCRIPTOR_REQ_VIEW_TYPE_2D_ARRAY : DESCRIPTOR_REQ_VIEW_TYPE_2D;
2590                         return bits;
2591                     case spv::Dim3D:
2592                         bits |= DESCRIPTOR_REQ_VIEW_TYPE_3D;
2593                         return bits;
2594                     case spv::DimCube:
2595                         bits |= arrayed ? DESCRIPTOR_REQ_VIEW_TYPE_CUBE_ARRAY : DESCRIPTOR_REQ_VIEW_TYPE_CUBE;
2596                         return bits;
2597                     case spv::DimSubpassData:
2598                         bits |= msaa ? DESCRIPTOR_REQ_MULTI_SAMPLE : DESCRIPTOR_REQ_SINGLE_SAMPLE;
2599                         return bits;
2600                     default:  // buffer, etc.
2601                         return bits;
2602                 }
2603             }
2604             default:
2605                 return 0;
2606         }
2607     }
2608 }
2609 
2610 // For given pipelineLayout verify that the set_layout_node at slot.first
2611 //  has the requested binding at slot.second and return ptr to that binding
GetDescriptorBinding(PIPELINE_LAYOUT_STATE const * pipelineLayout,descriptor_slot_t slot)2612 static VkDescriptorSetLayoutBinding const *GetDescriptorBinding(PIPELINE_LAYOUT_STATE const *pipelineLayout,
2613                                                                 descriptor_slot_t slot) {
2614     if (!pipelineLayout) return nullptr;
2615 
2616     if (slot.first >= pipelineLayout->set_layouts.size()) return nullptr;
2617 
2618     return pipelineLayout->set_layouts[slot.first]->GetDescriptorSetLayoutBindingPtrFromBinding(slot.second);
2619 }
2620 
FindLocalSize(SHADER_MODULE_STATE const * src,uint32_t & local_size_x,uint32_t & local_size_y,uint32_t & local_size_z)2621 static bool FindLocalSize(SHADER_MODULE_STATE const *src, uint32_t &local_size_x, uint32_t &local_size_y, uint32_t &local_size_z) {
2622     for (auto insn : *src) {
2623         if (insn.opcode() == spv::OpEntryPoint) {
2624             auto executionModel = insn.word(1);
2625             auto entrypointStageBits = ExecutionModelToShaderStageFlagBits(executionModel);
2626             if (entrypointStageBits == VK_SHADER_STAGE_COMPUTE_BIT) {
2627                 auto entrypoint_id = insn.word(2);
2628                 for (auto insn1 : *src) {
2629                     if (insn1.opcode() == spv::OpExecutionMode && insn1.word(1) == entrypoint_id &&
2630                         insn1.word(2) == spv::ExecutionModeLocalSize) {
2631                         local_size_x = insn1.word(3);
2632                         local_size_y = insn1.word(4);
2633                         local_size_z = insn1.word(5);
2634                         return true;
2635                     }
2636                 }
2637             }
2638         }
2639     }
2640     return false;
2641 }
2642 
ProcessExecutionModes(SHADER_MODULE_STATE const * src,const spirv_inst_iter & entrypoint,PIPELINE_STATE * pipeline)2643 static void ProcessExecutionModes(SHADER_MODULE_STATE const *src, const spirv_inst_iter &entrypoint, PIPELINE_STATE *pipeline) {
2644     auto entrypoint_id = entrypoint.word(2);
2645     bool is_point_mode = false;
2646 
2647     for (auto insn : *src) {
2648         if (insn.opcode() == spv::OpExecutionMode && insn.word(1) == entrypoint_id) {
2649             switch (insn.word(2)) {
2650                 case spv::ExecutionModePointMode:
2651                     // In tessellation shaders, PointMode is separate and trumps the tessellation topology.
2652                     is_point_mode = true;
2653                     break;
2654 
2655                 case spv::ExecutionModeOutputPoints:
2656                     pipeline->topology_at_rasterizer = VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
2657                     break;
2658 
2659                 case spv::ExecutionModeIsolines:
2660                 case spv::ExecutionModeOutputLineStrip:
2661                     pipeline->topology_at_rasterizer = VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
2662                     break;
2663 
2664                 case spv::ExecutionModeTriangles:
2665                 case spv::ExecutionModeQuads:
2666                 case spv::ExecutionModeOutputTriangleStrip:
2667                     pipeline->topology_at_rasterizer = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
2668                     break;
2669             }
2670         }
2671     }
2672 
2673     if (is_point_mode) pipeline->topology_at_rasterizer = VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
2674 }
2675 
2676 // If PointList topology is specified in the pipeline, verify that a shader geometry stage writes PointSize
2677 //    o If there is only a vertex shader : gl_PointSize must be written when using points
2678 //    o If there is a geometry or tessellation shader:
2679 //        - If shaderTessellationAndGeometryPointSize feature is enabled:
2680 //            * gl_PointSize must be written in the final geometry stage
2681 //        - If shaderTessellationAndGeometryPointSize feature is disabled:
2682 //            * gl_PointSize must NOT be written and a default of 1.0 is assumed
ValidatePointListShaderState(const PIPELINE_STATE * pipeline,SHADER_MODULE_STATE const * src,spirv_inst_iter entrypoint,VkShaderStageFlagBits stage) const2683 bool CoreChecks::ValidatePointListShaderState(const PIPELINE_STATE *pipeline, SHADER_MODULE_STATE const *src,
2684                                               spirv_inst_iter entrypoint, VkShaderStageFlagBits stage) const {
2685     if (pipeline->topology_at_rasterizer != VK_PRIMITIVE_TOPOLOGY_POINT_LIST) {
2686         return false;
2687     }
2688 
2689     bool pointsize_written = false;
2690     bool skip = false;
2691 
2692     // Search for PointSize built-in decorations
2693     std::vector<uint32_t> pointsize_builtin_offsets;
2694     spirv_inst_iter insn = entrypoint;
2695     while (!pointsize_written && (insn.opcode() != spv::OpFunction)) {
2696         if (insn.opcode() == spv::OpMemberDecorate) {
2697             if (insn.word(3) == spv::DecorationBuiltIn) {
2698                 if (insn.word(4) == spv::BuiltInPointSize) {
2699                     pointsize_written = IsPointSizeWritten(src, insn, entrypoint);
2700                 }
2701             }
2702         } else if (insn.opcode() == spv::OpDecorate) {
2703             if (insn.word(2) == spv::DecorationBuiltIn) {
2704                 if (insn.word(3) == spv::BuiltInPointSize) {
2705                     pointsize_written = IsPointSizeWritten(src, insn, entrypoint);
2706                 }
2707             }
2708         }
2709 
2710         insn++;
2711     }
2712 
2713     if ((stage == VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT || stage == VK_SHADER_STAGE_GEOMETRY_BIT) &&
2714         !enabled_features.core.shaderTessellationAndGeometryPointSize) {
2715         if (pointsize_written) {
2716             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2717                             HandleToUint64(pipeline->pipeline), kVUID_Core_Shader_PointSizeBuiltInOverSpecified,
2718                             "Pipeline topology is set to POINT_LIST and geometry or tessellation shaders write PointSize which "
2719                             "is prohibited when the shaderTessellationAndGeometryPointSize feature is not enabled.");
2720         }
2721     } else if (!pointsize_written) {
2722         skip |=
2723             log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT,
2724                     HandleToUint64(pipeline->pipeline), kVUID_Core_Shader_MissingPointSizeBuiltIn,
2725                     "Pipeline topology is set to POINT_LIST, but PointSize is not written to in the shader corresponding to %s.",
2726                     string_VkShaderStageFlagBits(stage));
2727     }
2728     return skip;
2729 }
RecordPipelineShaderStage(VkPipelineShaderStageCreateInfo const * pStage,PIPELINE_STATE * pipeline,PIPELINE_STATE::StageState * stage_state)2730 void ValidationStateTracker::RecordPipelineShaderStage(VkPipelineShaderStageCreateInfo const *pStage, PIPELINE_STATE *pipeline,
2731                                                        PIPELINE_STATE::StageState *stage_state) {
2732     // Validation shouldn't rely on anything in stage state being valid if the spirv isn't
2733     auto module = GetShaderModuleState(pStage->module);
2734     if (!module->has_valid_spirv) return;
2735 
2736     // Validation shouldn't rely on anything in stage state being valid if the entrypoint isn't present
2737     auto entrypoint = FindEntrypoint(module, pStage->pName, pStage->stage);
2738     if (entrypoint == module->end()) return;
2739 
2740     // Mark accessible ids
2741     stage_state->accessible_ids = MarkAccessibleIds(module, entrypoint);
2742     ProcessExecutionModes(module, entrypoint, pipeline);
2743 
2744     stage_state->descriptor_uses =
2745         CollectInterfaceByDescriptorSlot(report_data, module, stage_state->accessible_ids, &stage_state->has_writable_descriptor);
2746     // Capture descriptor uses for the pipeline
2747     for (auto use : stage_state->descriptor_uses) {
2748         // While validating shaders capture which slots are used by the pipeline
2749         auto &reqs = pipeline->active_slots[use.first.first][use.first.second];
2750         reqs = descriptor_req(reqs | DescriptorTypeToReqs(module, use.second.type_id));
2751     }
2752 }
2753 
ValidatePipelineShaderStage(VkPipelineShaderStageCreateInfo const * pStage,const PIPELINE_STATE * pipeline,const PIPELINE_STATE::StageState & stage_state,const SHADER_MODULE_STATE * module,const spirv_inst_iter & entrypoint,bool check_point_size) const2754 bool CoreChecks::ValidatePipelineShaderStage(VkPipelineShaderStageCreateInfo const *pStage, const PIPELINE_STATE *pipeline,
2755                                              const PIPELINE_STATE::StageState &stage_state, const SHADER_MODULE_STATE *module,
2756                                              const spirv_inst_iter &entrypoint, bool check_point_size) const {
2757     bool skip = false;
2758 
2759     // Check the module
2760     if (!module->has_valid_spirv) {
2761         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
2762                         "VUID-VkPipelineShaderStageCreateInfo-module-parameter", "%s does not contain valid spirv for stage %s.",
2763                         report_data->FormatHandle(module->vk_shader_module).c_str(), string_VkShaderStageFlagBits(pStage->stage));
2764     }
2765 
2766     // Check the entrypoint
2767     if (entrypoint == module->end()) {
2768         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
2769                         "VUID-VkPipelineShaderStageCreateInfo-pName-00707", "No entrypoint found named `%s` for stage %s..",
2770                         pStage->pName, string_VkShaderStageFlagBits(pStage->stage));
2771     }
2772     if (skip) return true;  // no point continuing beyond here, any analysis is just going to be garbage.
2773 
2774     // Mark accessible ids
2775     auto &accessible_ids = stage_state.accessible_ids;
2776 
2777     // Validate descriptor set layout against what the entrypoint actually uses
2778     bool has_writable_descriptor = stage_state.has_writable_descriptor;
2779     auto &descriptor_uses = stage_state.descriptor_uses;
2780 
2781     // Validate shader capabilities against enabled device features
2782     skip |= ValidateShaderCapabilities(module, pStage->stage);
2783     skip |= ValidateShaderStageWritableDescriptor(pStage->stage, has_writable_descriptor);
2784     skip |= ValidateShaderStageInputOutputLimits(module, pStage, pipeline, entrypoint);
2785     skip |= ValidateShaderStageGroupNonUniform(module, pStage->stage, accessible_ids);
2786     skip |= ValidateExecutionModes(module, entrypoint);
2787     skip |= ValidateSpecializationOffsets(report_data, pStage);
2788     skip |= ValidatePushConstantUsage(report_data, pipeline->pipeline_layout.push_constant_ranges.get(), module, accessible_ids,
2789                                       pStage->stage);
2790     if (check_point_size && !pipeline->graphicsPipelineCI.pRasterizationState->rasterizerDiscardEnable) {
2791         skip |= ValidatePointListShaderState(pipeline, module, entrypoint, pStage->stage);
2792     }
2793     skip |= ValidateCooperativeMatrix(module, pStage, pipeline);
2794 
2795     // Validate descriptor use
2796     for (auto use : descriptor_uses) {
2797         // Verify given pipelineLayout has requested setLayout with requested binding
2798         const auto &binding = GetDescriptorBinding(&pipeline->pipeline_layout, use.first);
2799         unsigned required_descriptor_count;
2800         std::set<uint32_t> descriptor_types = TypeToDescriptorTypeSet(module, use.second.type_id, required_descriptor_count);
2801 
2802         if (!binding) {
2803             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
2804                             kVUID_Core_Shader_MissingDescriptor,
2805                             "Shader uses descriptor slot %u.%u (expected `%s`) but not declared in pipeline layout",
2806                             use.first.first, use.first.second, string_descriptorTypes(descriptor_types).c_str());
2807         } else if (~binding->stageFlags & pStage->stage) {
2808             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 0,
2809                             kVUID_Core_Shader_DescriptorNotAccessibleFromStage,
2810                             "Shader uses descriptor slot %u.%u but descriptor not accessible from stage %s", use.first.first,
2811                             use.first.second, string_VkShaderStageFlagBits(pStage->stage));
2812         } else if (descriptor_types.find(binding->descriptorType) == descriptor_types.end()) {
2813             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
2814                             kVUID_Core_Shader_DescriptorTypeMismatch,
2815                             "Type mismatch on descriptor slot %u.%u (expected `%s`) but descriptor of type %s", use.first.first,
2816                             use.first.second, string_descriptorTypes(descriptor_types).c_str(),
2817                             string_VkDescriptorType(binding->descriptorType));
2818         } else if (binding->descriptorCount < required_descriptor_count) {
2819             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
2820                             kVUID_Core_Shader_DescriptorTypeMismatch,
2821                             "Shader expects at least %u descriptors for binding %u.%u but only %u provided",
2822                             required_descriptor_count, use.first.first, use.first.second, binding->descriptorCount);
2823         }
2824     }
2825 
2826     // Validate use of input attachments against subpass structure
2827     if (pStage->stage == VK_SHADER_STAGE_FRAGMENT_BIT) {
2828         auto input_attachment_uses = CollectInterfaceByInputAttachmentIndex(module, accessible_ids);
2829 
2830         auto rpci = pipeline->rp_state->createInfo.ptr();
2831         auto subpass = pipeline->graphicsPipelineCI.subpass;
2832 
2833         for (auto use : input_attachment_uses) {
2834             auto input_attachments = rpci->pSubpasses[subpass].pInputAttachments;
2835             auto index = (input_attachments && use.first < rpci->pSubpasses[subpass].inputAttachmentCount)
2836                              ? input_attachments[use.first].attachment
2837                              : VK_ATTACHMENT_UNUSED;
2838 
2839             if (index == VK_ATTACHMENT_UNUSED) {
2840                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
2841                                 kVUID_Core_Shader_MissingInputAttachment,
2842                                 "Shader consumes input attachment index %d but not provided in subpass", use.first);
2843             } else if (!(GetFormatType(rpci->pAttachments[index].format) & GetFundamentalType(module, use.second.type_id))) {
2844                 skip |=
2845                     log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
2846                             kVUID_Core_Shader_InputAttachmentTypeMismatch,
2847                             "Subpass input attachment %u format of %s does not match type used in shader `%s`", use.first,
2848                             string_VkFormat(rpci->pAttachments[index].format), DescribeType(module, use.second.type_id).c_str());
2849             }
2850         }
2851     }
2852     if (pStage->stage == VK_SHADER_STAGE_COMPUTE_BIT) {
2853         skip |= ValidateComputeWorkGroupSizes(module);
2854     }
2855     return skip;
2856 }
2857 
ValidateInterfaceBetweenStages(debug_report_data const * report_data,SHADER_MODULE_STATE const * producer,spirv_inst_iter producer_entrypoint,shader_stage_attributes const * producer_stage,SHADER_MODULE_STATE const * consumer,spirv_inst_iter consumer_entrypoint,shader_stage_attributes const * consumer_stage)2858 static bool ValidateInterfaceBetweenStages(debug_report_data const *report_data, SHADER_MODULE_STATE const *producer,
2859                                            spirv_inst_iter producer_entrypoint, shader_stage_attributes const *producer_stage,
2860                                            SHADER_MODULE_STATE const *consumer, spirv_inst_iter consumer_entrypoint,
2861                                            shader_stage_attributes const *consumer_stage) {
2862     bool skip = false;
2863 
2864     auto outputs =
2865         CollectInterfaceByLocation(producer, producer_entrypoint, spv::StorageClassOutput, producer_stage->arrayed_output);
2866     auto inputs = CollectInterfaceByLocation(consumer, consumer_entrypoint, spv::StorageClassInput, consumer_stage->arrayed_input);
2867 
2868     auto a_it = outputs.begin();
2869     auto b_it = inputs.begin();
2870 
2871     // Maps sorted by key (location); walk them together to find mismatches
2872     while ((outputs.size() > 0 && a_it != outputs.end()) || (inputs.size() && b_it != inputs.end())) {
2873         bool a_at_end = outputs.size() == 0 || a_it == outputs.end();
2874         bool b_at_end = inputs.size() == 0 || b_it == inputs.end();
2875         auto a_first = a_at_end ? std::make_pair(0u, 0u) : a_it->first;
2876         auto b_first = b_at_end ? std::make_pair(0u, 0u) : b_it->first;
2877 
2878         if (b_at_end || ((!a_at_end) && (a_first < b_first))) {
2879             skip |= log_msg(report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT,
2880                             HandleToUint64(producer->vk_shader_module), kVUID_Core_Shader_OutputNotConsumed,
2881                             "%s writes to output location %u.%u which is not consumed by %s", producer_stage->name, a_first.first,
2882                             a_first.second, consumer_stage->name);
2883             a_it++;
2884         } else if (a_at_end || a_first > b_first) {
2885             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT,
2886                             HandleToUint64(consumer->vk_shader_module), kVUID_Core_Shader_InputNotProduced,
2887                             "%s consumes input location %u.%u which is not written by %s", consumer_stage->name, b_first.first,
2888                             b_first.second, producer_stage->name);
2889             b_it++;
2890         } else {
2891             // subtleties of arrayed interfaces:
2892             // - if is_patch, then the member is not arrayed, even though the interface may be.
2893             // - if is_block_member, then the extra array level of an arrayed interface is not
2894             //   expressed in the member type -- it's expressed in the block type.
2895             if (!TypesMatch(producer, consumer, a_it->second.type_id, b_it->second.type_id,
2896                             producer_stage->arrayed_output && !a_it->second.is_patch && !a_it->second.is_block_member,
2897                             consumer_stage->arrayed_input && !b_it->second.is_patch && !b_it->second.is_block_member, true)) {
2898                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT,
2899                                 HandleToUint64(producer->vk_shader_module), kVUID_Core_Shader_InterfaceTypeMismatch,
2900                                 "Type mismatch on location %u.%u: '%s' vs '%s'", a_first.first, a_first.second,
2901                                 DescribeType(producer, a_it->second.type_id).c_str(),
2902                                 DescribeType(consumer, b_it->second.type_id).c_str());
2903             }
2904             if (a_it->second.is_patch != b_it->second.is_patch) {
2905                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT,
2906                                 HandleToUint64(producer->vk_shader_module), kVUID_Core_Shader_InterfaceTypeMismatch,
2907                                 "Decoration mismatch on location %u.%u: is per-%s in %s stage but per-%s in %s stage",
2908                                 a_first.first, a_first.second, a_it->second.is_patch ? "patch" : "vertex", producer_stage->name,
2909                                 b_it->second.is_patch ? "patch" : "vertex", consumer_stage->name);
2910             }
2911             if (a_it->second.is_relaxed_precision != b_it->second.is_relaxed_precision) {
2912                 skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT,
2913                                 HandleToUint64(producer->vk_shader_module), kVUID_Core_Shader_InterfaceTypeMismatch,
2914                                 "Decoration mismatch on location %u.%u: %s and %s stages differ in precision", a_first.first,
2915                                 a_first.second, producer_stage->name, consumer_stage->name);
2916             }
2917             a_it++;
2918             b_it++;
2919         }
2920     }
2921 
2922     if (consumer_stage->stage != VK_SHADER_STAGE_FRAGMENT_BIT) {
2923         auto builtins_producer = CollectBuiltinBlockMembers(producer, producer_entrypoint, spv::StorageClassOutput);
2924         auto builtins_consumer = CollectBuiltinBlockMembers(consumer, consumer_entrypoint, spv::StorageClassInput);
2925 
2926         if (!builtins_producer.empty() && !builtins_consumer.empty()) {
2927             if (builtins_producer.size() != builtins_consumer.size()) {
2928                 skip |=
2929                     log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT,
2930                             HandleToUint64(producer->vk_shader_module), kVUID_Core_Shader_InterfaceTypeMismatch,
2931                             "Number of elements inside builtin block differ between stages (%s %d vs %s %d).", producer_stage->name,
2932                             (int)builtins_producer.size(), consumer_stage->name, (int)builtins_consumer.size());
2933             } else {
2934                 auto it_producer = builtins_producer.begin();
2935                 auto it_consumer = builtins_consumer.begin();
2936                 while (it_producer != builtins_producer.end() && it_consumer != builtins_consumer.end()) {
2937                     if (*it_producer != *it_consumer) {
2938                         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT,
2939                                         HandleToUint64(producer->vk_shader_module), kVUID_Core_Shader_InterfaceTypeMismatch,
2940                                         "Builtin variable inside block doesn't match between %s and %s.", producer_stage->name,
2941                                         consumer_stage->name);
2942                         break;
2943                     }
2944                     it_producer++;
2945                     it_consumer++;
2946                 }
2947             }
2948         }
2949     }
2950 
2951     return skip;
2952 }
2953 
DetermineFinalGeomStage(const PIPELINE_STATE * pipeline,const VkGraphicsPipelineCreateInfo * pCreateInfo)2954 static inline uint32_t DetermineFinalGeomStage(const PIPELINE_STATE *pipeline, const VkGraphicsPipelineCreateInfo *pCreateInfo) {
2955     uint32_t stage_mask = 0;
2956     if (pipeline->topology_at_rasterizer == VK_PRIMITIVE_TOPOLOGY_POINT_LIST) {
2957         for (uint32_t i = 0; i < pCreateInfo->stageCount; i++) {
2958             stage_mask |= pCreateInfo->pStages[i].stage;
2959         }
2960         // Determine which shader in which PointSize should be written (the final geometry stage)
2961         if (stage_mask & VK_SHADER_STAGE_MESH_BIT_NV) {
2962             stage_mask = VK_SHADER_STAGE_MESH_BIT_NV;
2963         } else if (stage_mask & VK_SHADER_STAGE_GEOMETRY_BIT) {
2964             stage_mask = VK_SHADER_STAGE_GEOMETRY_BIT;
2965         } else if (stage_mask & VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) {
2966             stage_mask = VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT;
2967         } else if (stage_mask & VK_SHADER_STAGE_VERTEX_BIT) {
2968             stage_mask = VK_SHADER_STAGE_VERTEX_BIT;
2969         }
2970     }
2971     return stage_mask;
2972 }
2973 
2974 // Validate that the shaders used by the given pipeline and store the active_slots
2975 //  that are actually used by the pipeline into pPipeline->active_slots
ValidateGraphicsPipelineShaderState(const PIPELINE_STATE * pipeline) const2976 bool CoreChecks::ValidateGraphicsPipelineShaderState(const PIPELINE_STATE *pipeline) const {
2977     auto pCreateInfo = pipeline->graphicsPipelineCI.ptr();
2978     int vertex_stage = GetShaderStageId(VK_SHADER_STAGE_VERTEX_BIT);
2979     int fragment_stage = GetShaderStageId(VK_SHADER_STAGE_FRAGMENT_BIT);
2980 
2981     const SHADER_MODULE_STATE *shaders[32];
2982     memset(shaders, 0, sizeof(shaders));
2983     spirv_inst_iter entrypoints[32];
2984     memset(entrypoints, 0, sizeof(entrypoints));
2985     bool skip = false;
2986 
2987     uint32_t pointlist_stage_mask = DetermineFinalGeomStage(pipeline, pCreateInfo);
2988 
2989     for (uint32_t i = 0; i < pCreateInfo->stageCount; i++) {
2990         auto pStage = &pCreateInfo->pStages[i];
2991         auto stage_id = GetShaderStageId(pStage->stage);
2992         shaders[stage_id] = GetShaderModuleState(pStage->module);
2993         entrypoints[stage_id] = FindEntrypoint(shaders[stage_id], pStage->pName, pStage->stage);
2994         skip |= ValidatePipelineShaderStage(pStage, pipeline, pipeline->stage_state[i], shaders[stage_id], entrypoints[stage_id],
2995 
2996                                             (pointlist_stage_mask == pStage->stage));
2997     }
2998 
2999     // if the shader stages are no good individually, cross-stage validation is pointless.
3000     if (skip) return true;
3001 
3002     auto vi = pCreateInfo->pVertexInputState;
3003 
3004     if (vi) {
3005         skip |= ValidateViConsistency(report_data, vi);
3006     }
3007 
3008     if (shaders[vertex_stage] && shaders[vertex_stage]->has_valid_spirv) {
3009         skip |= ValidateViAgainstVsInputs(report_data, vi, shaders[vertex_stage], entrypoints[vertex_stage]);
3010     }
3011 
3012     int producer = GetShaderStageId(VK_SHADER_STAGE_VERTEX_BIT);
3013     int consumer = GetShaderStageId(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT);
3014 
3015     while (!shaders[producer] && producer != fragment_stage) {
3016         producer++;
3017         consumer++;
3018     }
3019 
3020     for (; producer != fragment_stage && consumer <= fragment_stage; consumer++) {
3021         assert(shaders[producer]);
3022         if (shaders[consumer]) {
3023             if (shaders[consumer]->has_valid_spirv && shaders[producer]->has_valid_spirv) {
3024                 skip |= ValidateInterfaceBetweenStages(report_data, shaders[producer], entrypoints[producer],
3025                                                        &shader_stage_attribs[producer], shaders[consumer], entrypoints[consumer],
3026                                                        &shader_stage_attribs[consumer]);
3027             }
3028 
3029             producer = consumer;
3030         }
3031     }
3032 
3033     if (shaders[fragment_stage] && shaders[fragment_stage]->has_valid_spirv) {
3034         skip |= ValidateFsOutputsAgainstRenderPass(report_data, shaders[fragment_stage], entrypoints[fragment_stage], pipeline,
3035                                                    pCreateInfo->subpass);
3036     }
3037 
3038     return skip;
3039 }
3040 
ValidateComputePipeline(PIPELINE_STATE * pipeline) const3041 bool CoreChecks::ValidateComputePipeline(PIPELINE_STATE *pipeline) const {
3042     const auto &stage = *pipeline->computePipelineCI.stage.ptr();
3043 
3044     const SHADER_MODULE_STATE *module = GetShaderModuleState(stage.module);
3045     const spirv_inst_iter entrypoint = FindEntrypoint(module, stage.pName, stage.stage);
3046 
3047     return ValidatePipelineShaderStage(&stage, pipeline, pipeline->stage_state[0], module, entrypoint, false);
3048 }
3049 
ValidateRayTracingPipelineNV(PIPELINE_STATE * pipeline) const3050 bool CoreChecks::ValidateRayTracingPipelineNV(PIPELINE_STATE *pipeline) const {
3051     bool skip = false;
3052     for (uint32_t stage_index = 0; stage_index < pipeline->raytracingPipelineCI.stageCount; stage_index++) {
3053         const auto &stage = pipeline->raytracingPipelineCI.ptr()->pStages[stage_index];
3054 
3055         const SHADER_MODULE_STATE *module = GetShaderModuleState(stage.module);
3056         const spirv_inst_iter entrypoint = FindEntrypoint(module, stage.pName, stage.stage);
3057 
3058         skip |= ValidatePipelineShaderStage(&stage, pipeline, pipeline->stage_state[stage_index], module, entrypoint, false);
3059     }
3060     return skip;
3061 }
3062 
MakeShaderHash(VkShaderModuleCreateInfo const * smci)3063 uint32_t ValidationCache::MakeShaderHash(VkShaderModuleCreateInfo const *smci) { return XXH32(smci->pCode, smci->codeSize, 0); }
3064 
GetValidationCacheInfo(VkShaderModuleCreateInfo const * pCreateInfo)3065 static ValidationCache *GetValidationCacheInfo(VkShaderModuleCreateInfo const *pCreateInfo) {
3066     const auto validation_cache_ci = lvl_find_in_chain<VkShaderModuleValidationCacheCreateInfoEXT>(pCreateInfo->pNext);
3067     if (validation_cache_ci) {
3068         return CastFromHandle<ValidationCache *>(validation_cache_ci->validationCache);
3069     }
3070     return nullptr;
3071 }
3072 
PreCallValidateCreateShaderModule(VkDevice device,const VkShaderModuleCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkShaderModule * pShaderModule)3073 bool CoreChecks::PreCallValidateCreateShaderModule(VkDevice device, const VkShaderModuleCreateInfo *pCreateInfo,
3074                                                    const VkAllocationCallbacks *pAllocator, VkShaderModule *pShaderModule) {
3075     bool skip = false;
3076     spv_result_t spv_valid = SPV_SUCCESS;
3077 
3078     if (disabled.shader_validation) {
3079         return false;
3080     }
3081 
3082     auto have_glsl_shader = device_extensions.vk_nv_glsl_shader;
3083 
3084     if (!have_glsl_shader && (pCreateInfo->codeSize % 4)) {
3085         skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
3086                         "VUID-VkShaderModuleCreateInfo-pCode-01376",
3087                         "SPIR-V module not valid: Codesize must be a multiple of 4 but is " PRINTF_SIZE_T_SPECIFIER ".",
3088                         pCreateInfo->codeSize);
3089     } else {
3090         auto cache = GetValidationCacheInfo(pCreateInfo);
3091         uint32_t hash = 0;
3092         if (cache) {
3093             hash = ValidationCache::MakeShaderHash(pCreateInfo);
3094             if (cache->Contains(hash)) return false;
3095         }
3096 
3097         // Use SPIRV-Tools validator to try and catch any issues with the module itself
3098         spv_target_env spirv_environment = SPV_ENV_VULKAN_1_0;
3099         if (api_version >= VK_API_VERSION_1_1) {
3100             spirv_environment = SPV_ENV_VULKAN_1_1;
3101         }
3102         spv_context ctx = spvContextCreate(spirv_environment);
3103         spv_const_binary_t binary{pCreateInfo->pCode, pCreateInfo->codeSize / sizeof(uint32_t)};
3104         spv_diagnostic diag = nullptr;
3105         spv_validator_options options = spvValidatorOptionsCreate();
3106         if (device_extensions.vk_khr_relaxed_block_layout) {
3107             spvValidatorOptionsSetRelaxBlockLayout(options, true);
3108         }
3109         if (device_extensions.vk_khr_uniform_buffer_standard_layout &&
3110             enabled_features.uniform_buffer_standard_layout.uniformBufferStandardLayout == VK_TRUE) {
3111             spvValidatorOptionsSetUniformBufferStandardLayout(options, true);
3112         }
3113         if (device_extensions.vk_ext_scalar_block_layout &&
3114             enabled_features.scalar_block_layout_features.scalarBlockLayout == VK_TRUE) {
3115             spvValidatorOptionsSetScalarBlockLayout(options, true);
3116         }
3117         spv_valid = spvValidateWithOptions(ctx, options, &binary, &diag);
3118         if (spv_valid != SPV_SUCCESS) {
3119             if (!have_glsl_shader || (pCreateInfo->pCode[0] == spv::MagicNumber)) {
3120                 skip |=
3121                     log_msg(report_data, spv_valid == SPV_WARNING ? VK_DEBUG_REPORT_WARNING_BIT_EXT : VK_DEBUG_REPORT_ERROR_BIT_EXT,
3122                             VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, kVUID_Core_Shader_InconsistentSpirv,
3123                             "SPIR-V module not valid: %s", diag && diag->error ? diag->error : "(no error text)");
3124             }
3125         } else {
3126             if (cache) {
3127                 cache->Insert(hash);
3128             }
3129         }
3130 
3131         spvValidatorOptionsDestroy(options);
3132         spvDiagnosticDestroy(diag);
3133         spvContextDestroy(ctx);
3134     }
3135 
3136     return skip;
3137 }
3138 
PreCallRecordCreateShaderModule(VkDevice device,const VkShaderModuleCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkShaderModule * pShaderModule,void * csm_state_data)3139 void CoreChecks::PreCallRecordCreateShaderModule(VkDevice device, const VkShaderModuleCreateInfo *pCreateInfo,
3140                                                  const VkAllocationCallbacks *pAllocator, VkShaderModule *pShaderModule,
3141                                                  void *csm_state_data) {
3142     create_shader_module_api_state *csm_state = reinterpret_cast<create_shader_module_api_state *>(csm_state_data);
3143     if (enabled.gpu_validation) {
3144         GpuPreCallCreateShaderModule(pCreateInfo, pAllocator, pShaderModule, &csm_state->unique_shader_id,
3145                                      &csm_state->instrumented_create_info, &csm_state->instrumented_pgm);
3146     }
3147 }
3148 
PostCallRecordCreateShaderModule(VkDevice device,const VkShaderModuleCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkShaderModule * pShaderModule,VkResult result,void * csm_state_data)3149 void ValidationStateTracker::PostCallRecordCreateShaderModule(VkDevice device, const VkShaderModuleCreateInfo *pCreateInfo,
3150                                                               const VkAllocationCallbacks *pAllocator,
3151                                                               VkShaderModule *pShaderModule, VkResult result,
3152                                                               void *csm_state_data) {
3153     if (VK_SUCCESS != result) return;
3154     create_shader_module_api_state *csm_state = reinterpret_cast<create_shader_module_api_state *>(csm_state_data);
3155 
3156     spv_target_env spirv_environment = ((api_version >= VK_API_VERSION_1_1) ? SPV_ENV_VULKAN_1_1 : SPV_ENV_VULKAN_1_0);
3157     bool is_spirv = (pCreateInfo->pCode[0] == spv::MagicNumber);
3158     std::unique_ptr<SHADER_MODULE_STATE> new_shader_module(
3159         is_spirv ? new SHADER_MODULE_STATE(pCreateInfo, *pShaderModule, spirv_environment, csm_state->unique_shader_id)
3160                  : new SHADER_MODULE_STATE());
3161     shaderModuleMap[*pShaderModule] = std::move(new_shader_module);
3162 }
3163 
ValidateComputeWorkGroupSizes(const SHADER_MODULE_STATE * shader) const3164 bool CoreChecks::ValidateComputeWorkGroupSizes(const SHADER_MODULE_STATE *shader) const {
3165     bool skip = false;
3166     uint32_t local_size_x = 0;
3167     uint32_t local_size_y = 0;
3168     uint32_t local_size_z = 0;
3169     if (FindLocalSize(shader, local_size_x, local_size_y, local_size_z)) {
3170         if (local_size_x > phys_dev_props.limits.maxComputeWorkGroupSize[0]) {
3171             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT,
3172                             HandleToUint64(shader->vk_shader_module), "UNASSIGNED-features-limits-maxComputeWorkGroupSize",
3173                             "%s local_size_x (%" PRIu32 ") exceeds device limit maxComputeWorkGroupSize[0] (%" PRIu32 ").",
3174                             report_data->FormatHandle(shader->vk_shader_module).c_str(), local_size_x,
3175                             phys_dev_props.limits.maxComputeWorkGroupSize[0]);
3176         }
3177         if (local_size_y > phys_dev_props.limits.maxComputeWorkGroupSize[1]) {
3178             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT,
3179                             HandleToUint64(shader->vk_shader_module), "UNASSIGNED-features-limits-maxComputeWorkGroupSize",
3180                             "%s local_size_y (%" PRIu32 ") exceeds device limit maxComputeWorkGroupSize[1] (%" PRIu32 ").",
3181                             report_data->FormatHandle(shader->vk_shader_module).c_str(), local_size_x,
3182                             phys_dev_props.limits.maxComputeWorkGroupSize[1]);
3183         }
3184         if (local_size_z > phys_dev_props.limits.maxComputeWorkGroupSize[2]) {
3185             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT,
3186                             HandleToUint64(shader->vk_shader_module), "UNASSIGNED-features-limits-maxComputeWorkGroupSize",
3187                             "%s local_size_z (%" PRIu32 ") exceeds device limit maxComputeWorkGroupSize[2] (%" PRIu32 ").",
3188                             report_data->FormatHandle(shader->vk_shader_module).c_str(), local_size_x,
3189                             phys_dev_props.limits.maxComputeWorkGroupSize[2]);
3190         }
3191 
3192         uint32_t limit = phys_dev_props.limits.maxComputeWorkGroupInvocations;
3193         uint64_t invocations = local_size_x * local_size_y;
3194         // Prevent overflow.
3195         bool fail = false;
3196         if (invocations > UINT32_MAX || invocations > limit) {
3197             fail = true;
3198         }
3199         if (!fail) {
3200             invocations *= local_size_z;
3201             if (invocations > UINT32_MAX || invocations > limit) {
3202                 fail = true;
3203             }
3204         }
3205         if (fail) {
3206             skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT,
3207                             HandleToUint64(shader->vk_shader_module), "UNASSIGNED-features-limits-maxComputeWorkGroupInvocations",
3208                             "%s local_size (%" PRIu32 ", %" PRIu32 ", %" PRIu32
3209                             ") exceeds device limit maxComputeWorkGroupInvocations (%" PRIu32 ").",
3210                             report_data->FormatHandle(shader->vk_shader_module).c_str(), local_size_x, local_size_y, local_size_z,
3211                             limit);
3212         }
3213     }
3214     return skip;
3215 }
3216