@@ -222,198 +222,6 @@ bool CoreChecks::ValidatePushConstantUsage(const spirv::Module& module_state, co
222222 return skip;
223223}
224224
225- struct ShaderResourceType {
226- // All possible VkDescriptorSet
227- vvl::unordered_set<uint32_t > descriptor_type_set;
228- // Way to print out extra useful information
229- bool is_buffer_block{false };
230-
231- bool HasType (VkDescriptorType type) { return descriptor_type_set.find (type) != descriptor_type_set.end (); }
232-
233- std::string Describe (bool hints) {
234- std::ostringstream ss;
235- for (auto it = descriptor_type_set.begin (); it != descriptor_type_set.end (); ++it) {
236- if (ss.tellp ()) ss << " or " ;
237- ss << string_VkDescriptorType (VkDescriptorType (*it));
238- }
239-
240- // Currently this is used for 2 checks
241- // - When there is no binding found at all
242- // - When it is found, but the mismatch, here we want to help give hints
243- if (hints) {
244- ss << " \n Info on SPIR-V mapping for each type:" ;
245- if (descriptor_type_set.count (VK_DESCRIPTOR_TYPE_SAMPLER)) {
246- ss << " \n - VK_DESCRIPTOR_TYPE_SAMPLER is an OpTypeSampler with UniformConstant" ;
247- }
248- if (descriptor_type_set.count (VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)) {
249- ss << " \n - VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER is an OpTypeSampledImage that consumes both a OpTypeSampler "
250- " and OpTypeImage in UniformConstant" ;
251- }
252- if (descriptor_type_set.count (VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE)) {
253- ss << " \n - VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE is an OpTypeImage, with Sampled = 1, in UniformConstant" ;
254- }
255- if (descriptor_type_set.count (VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)) {
256- ss << " \n - VK_DESCRIPTOR_TYPE_STORAGE_IMAGE is an OpTypeImage, with Sampled = 2, in UniformConstant" ;
257- }
258- if (descriptor_type_set.count (VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER)) {
259- ss << " \n - VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER is an OpTypeImage, with Sampled = 1 and Dim = Buffer, in "
260- " UniformConstant" ;
261- }
262- if (descriptor_type_set.count (VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER)) {
263- ss << " \n - VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER is an OpTypeImage, with Sampled = 2 and Dim = Buffer, in "
264- " UniformConstant" ;
265- }
266- if (descriptor_type_set.count (VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER)) {
267- ss << " \n - VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER/VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK is an OpTypeStruct as "
268- " Uniform" ;
269- }
270- if (descriptor_type_set.count (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)) {
271- ss << " \n - VK_DESCRIPTOR_TYPE_STORAGE_BUFFER is an OpTypeStruct as " ;
272- if (is_buffer_block) {
273- ss << " Uniform, with BufferBlock (Vulkan 1.0 didn't have a dedicated StorageBuffer storage class, more info at "
274- " https://docs.vulkan.org/guide/latest/extensions/"
275- " shader_features.html#VK_KHR_storage_buffer_storage_class)" ;
276- } else {
277- ss << " StorageBuffer" ;
278- }
279- }
280- if (descriptor_type_set.count (VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT)) {
281- ss << " \n - VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT is an OpTypeImage, with Sampled = 2 and Dim = SubpassData, in "
282- " UniformConstant" ;
283- }
284- if (descriptor_type_set.count (VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR)) {
285- ss << " \n - VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR is an OpTypeAccelerationStructureKHR in UniformConstant" ;
286- }
287- if (descriptor_type_set.count (VK_DESCRIPTOR_TYPE_PARTITIONED_ACCELERATION_STRUCTURE_NV)) {
288- ss << " \n - VK_DESCRIPTOR_TYPE_PARTITIONED_ACCELERATION_STRUCTURE_NV is an OpTypeAccelerationStructureKHR in "
289- " UniformConstant" ;
290- }
291- if (descriptor_type_set.count (VK_DESCRIPTOR_TYPE_TENSOR_ARM)) {
292- ss << " \n - VK_DESCRIPTOR_TYPE_TENSOR_ARM is an OpTypeTensorARM in UniformConstant" ;
293- }
294- ss << " \n Full list of mappings can be found at "
295- " https://docs.vulkan.org/spec/latest/chapters/interfaces.html#interfaces-resources-storage-class-correspondence" ;
296- }
297- return ss.str ();
298- }
299- };
300-
301- // This function is matching the VkDescriptorType to the SPIR-V.
302- // We return back a set, because things like a Uniform in SPIR-V could be one of many possible matching VkDescriptorType.
303- // https://docs.vulkan.org/spec/latest/chapters/interfaces.html#interfaces-resources-storage-class-correspondence
304- static void TypeToDescriptorTypeSet (const spirv::Module& module_state, uint32_t type_id, uint32_t data_type_id,
305- ShaderResourceType& out_data) {
306- const spirv::Instruction* type = module_state.FindDef (type_id);
307- assert (type->Opcode () == spv::OpTypePointer || type->Opcode () == spv::OpTypeUntypedPointerKHR);
308- bool is_storage_buffer = type->StorageClass () == spv::StorageClassStorageBuffer;
309-
310- if (data_type_id != 0 ) {
311- type = module_state.FindDef (data_type_id);
312- }
313-
314- // Strip off any array or ptrs. Where we remove array levels, adjust the descriptor count for each dimension.
315- while (type->IsArray () || type->Opcode () == spv::OpTypePointer) {
316- if (type->Opcode () == spv::OpTypeRuntimeArray) {
317- type = module_state.FindDef (type->Word (2 ));
318- } else if (type->Opcode () == spv::OpTypeArray) {
319- type = module_state.FindDef (type->Word (2 ));
320- } else {
321- if (type->StorageClass () == spv::StorageClassStorageBuffer) {
322- is_storage_buffer = true ;
323- }
324- type = module_state.FindDef (type->Word (3 ));
325- }
326- }
327-
328- switch (type->Opcode ()) {
329- case spv::OpTypeStruct: {
330- for (const spirv::Instruction* insn : module_state.static_data_ .decoration_inst ) {
331- if (insn->Word (1 ) == type->ResultId ()) {
332- if (insn->Word (2 ) == spv::DecorationBlock) {
333- if (is_storage_buffer) {
334- out_data.descriptor_type_set .insert (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
335- out_data.descriptor_type_set .insert (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC);
336- } else {
337- out_data.descriptor_type_set .insert (VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER);
338- out_data.descriptor_type_set .insert (VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC);
339- out_data.descriptor_type_set .insert (VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK);
340- }
341- } else if (insn->Word (2 ) == spv::DecorationBufferBlock) {
342- out_data.is_buffer_block = true ;
343- out_data.descriptor_type_set .insert (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER);
344- out_data.descriptor_type_set .insert (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC);
345- }
346- break ;
347- }
348- }
349- return ;
350- }
351-
352- case spv::OpTypeSampler:
353- out_data.descriptor_type_set .insert (VK_DESCRIPTOR_TYPE_SAMPLER);
354- out_data.descriptor_type_set .insert (VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
355- return ;
356-
357- case spv::OpTypeSampledImage: {
358- // Slight relaxation for some GLSL historical madness: samplerBuffer doesn't really have a sampler, and a texel
359- // buffer descriptor doesn't really provide one. Allow this slight mismatch.
360- const spirv::Instruction* image_type = module_state.FindDef (type->Word (2 ));
361- auto dim = image_type->Word (3 );
362- auto sampled = image_type->Word (7 );
363- if (dim == spv::DimBuffer && sampled == 1 ) {
364- out_data.descriptor_type_set .insert (VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER);
365- } else {
366- out_data.descriptor_type_set .insert (VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
367- }
368- return ;
369- }
370- case spv::OpTypeImage: {
371- // Many descriptor types backing image types-- depends on dimension and whether the image will be used with a sampler.
372- // SPIRV for Vulkan requires that sampled be 1 or 2 -- leaving the decision to runtime is unacceptable.
373- auto dim = type->Word (3 );
374- auto sampled = type->Word (7 );
375-
376- if (dim == spv::DimSubpassData) {
377- out_data.descriptor_type_set .insert (VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT);
378- } else if (dim == spv::DimBuffer) {
379- if (sampled == 1 ) {
380- out_data.descriptor_type_set .insert (VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER);
381- } else {
382- out_data.descriptor_type_set .insert (VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER);
383- }
384- } else if (sampled == 1 ) {
385- out_data.descriptor_type_set .insert (VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE);
386- out_data.descriptor_type_set .insert (VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
387- } else {
388- out_data.descriptor_type_set .insert (VK_DESCRIPTOR_TYPE_STORAGE_IMAGE);
389- }
390- return ;
391- }
392-
393- // The OpType are alias, but the Descriptor Types are different
394- case spv::OpTypeAccelerationStructureKHR:
395- // Only KHR or NV base acceleration structure is selected
396- if (module_state.HasCapability (spv::CapabilityRayTracingNV)) {
397- out_data.descriptor_type_set .insert (VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV);
398- } else {
399- out_data.descriptor_type_set .insert (VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR);
400- }
401- // Additionally allow PTLAS if shader uses cluster acceleration structure features
402- if (module_state.HasCapability (spv::CapabilityRayTracingClusterAccelerationStructureNV)) {
403- out_data.descriptor_type_set .insert (VK_DESCRIPTOR_TYPE_PARTITIONED_ACCELERATION_STRUCTURE_NV);
404- }
405- return ;
406- case spv::OpTypeTensorARM: {
407- out_data.descriptor_type_set .insert (VK_DESCRIPTOR_TYPE_TENSOR_ARM);
408- return ;
409- }
410-
411- default :
412- // We shouldn't really see any other junk types -- but if we do, they're a mismatch.
413- return ; // Matches nothing
414- }
415- }
416-
417225// Map SPIR-V type to VK_COMPONENT_TYPE enum
418226VkComponentTypeKHR GetComponentType (const spirv::Instruction* insn, bool is_signed_int) {
419227 if (insn->Opcode () == spv::OpTypeInt) {
@@ -1620,27 +1428,14 @@ bool CoreChecks::ValidateShaderInterfaceVariable(const spirv::Module& module_sta
16201428 // If the variable is a struct, all members must contain NonWritable
16211429 if (!variable.type_struct_info ||
16221430 !variable.type_struct_info ->decorations .AllMemberHave (spirv::DecorationSet::nonwritable_bit)) {
1623- auto print_type = [variable]() {
1624- if (variable.is_storage_image ) {
1625- return " VK_DESCRIPTOR_TYPE_STORAGE_IMAGE" ;
1626- } else if (variable.is_storage_texel_buffer ) {
1627- return " VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER" ;
1628- } else if (variable.is_storage_buffer ) {
1629- return " VK_DESCRIPTOR_TYPE_STORAGE_BUFFER" ;
1630- } else if (variable.is_storage_tensor ) {
1631- return " VK_DESCRIPTOR_TYPE_TENSOR_ARM" ;
1632- } else {
1633- return " Unknown VkDescriptorType" ;
1634- }
1635- };
1636-
16371431 switch (variable.stage ) {
16381432 case VK_SHADER_STAGE_FRAGMENT_BIT:
16391433 if (!enabled_features.fragmentStoresAndAtomics ) {
16401434 skip |= LogError (" VUID-RuntimeSpirv-NonWritable-06340" , module_state.handle (), loc,
16411435 " shader %s uses descriptor %s (type %s) which is not "
16421436 " marked with NonWritable, but fragmentStoresAndAtomics was not enabled." ,
1643- entrypoint.Describe ().c_str (), variable.DescribeDescriptor ().c_str (), print_type ());
1437+ entrypoint.Describe ().c_str (), variable.DescribeDescriptor ().c_str (),
1438+ string_VkDescriptorType (variable.GetPotentialDescriptorType ()));
16441439 }
16451440 break ;
16461441 case VK_SHADER_STAGE_VERTEX_BIT:
@@ -1651,7 +1446,8 @@ bool CoreChecks::ValidateShaderInterfaceVariable(const spirv::Module& module_sta
16511446 skip |= LogError (" VUID-RuntimeSpirv-NonWritable-06341" , module_state.handle (), loc,
16521447 " shader %s uses descriptor %s (type %s) which is not marked with NonWritable, but "
16531448 " vertexPipelineStoresAndAtomics was not enabled." ,
1654- entrypoint.Describe ().c_str (), variable.DescribeDescriptor ().c_str (), print_type ());
1449+ entrypoint.Describe ().c_str (), variable.DescribeDescriptor ().c_str (),
1450+ string_VkDescriptorType (variable.GetPotentialDescriptorType ()));
16551451 }
16561452 break ;
16571453 default :
@@ -1687,6 +1483,83 @@ bool CoreChecks::ValidateShaderInterfaceVariable(const spirv::Module& module_sta
16871483 return skip;
16881484}
16891485
1486+ struct ShaderResourceType {
1487+ const spirv::ResourceInterfaceVariable& resource_variable;
1488+ const vvl::unordered_set<VkDescriptorType> descriptor_type_set;
1489+
1490+ explicit ShaderResourceType (const spirv::ResourceInterfaceVariable& variable)
1491+ : resource_variable(variable), descriptor_type_set(variable.GetAllDescriptorTypes()) {}
1492+
1493+ bool HasType (VkDescriptorType type) { return descriptor_type_set.find (type) != descriptor_type_set.end (); }
1494+
1495+ std::string Describe (bool hints) {
1496+ std::ostringstream ss;
1497+ for (auto it = descriptor_type_set.begin (); it != descriptor_type_set.end (); ++it) {
1498+ if (ss.tellp ()) ss << " or " ;
1499+ ss << string_VkDescriptorType (VkDescriptorType (*it));
1500+ }
1501+
1502+ // Currently this is used for 2 checks
1503+ // - When there is no binding found at all
1504+ // - When it is found, but the mismatch, here we want to help give hints
1505+ if (hints) {
1506+ ss << " \n Info on SPIR-V mapping for each type:" ;
1507+ if (descriptor_type_set.count (VK_DESCRIPTOR_TYPE_SAMPLER)) {
1508+ ss << " \n - VK_DESCRIPTOR_TYPE_SAMPLER is an OpTypeSampler with UniformConstant" ;
1509+ }
1510+ if (descriptor_type_set.count (VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER)) {
1511+ ss << " \n - VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER is an OpTypeSampledImage that consumes both a OpTypeSampler "
1512+ " and OpTypeImage in UniformConstant" ;
1513+ }
1514+ if (descriptor_type_set.count (VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE)) {
1515+ ss << " \n - VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE is an OpTypeImage, with Sampled = 1, in UniformConstant" ;
1516+ }
1517+ if (descriptor_type_set.count (VK_DESCRIPTOR_TYPE_STORAGE_IMAGE)) {
1518+ ss << " \n - VK_DESCRIPTOR_TYPE_STORAGE_IMAGE is an OpTypeImage, with Sampled = 2, in UniformConstant" ;
1519+ }
1520+ if (descriptor_type_set.count (VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER)) {
1521+ ss << " \n - VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER is an OpTypeImage, with Sampled = 1 and Dim = Buffer, in "
1522+ " UniformConstant" ;
1523+ }
1524+ if (descriptor_type_set.count (VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER)) {
1525+ ss << " \n - VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER is an OpTypeImage, with Sampled = 2 and Dim = Buffer, in "
1526+ " UniformConstant" ;
1527+ }
1528+ if (descriptor_type_set.count (VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER)) {
1529+ ss << " \n - VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER/VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK is an OpTypeStruct as "
1530+ " Uniform" ;
1531+ }
1532+ if (descriptor_type_set.count (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER)) {
1533+ ss << " \n - VK_DESCRIPTOR_TYPE_STORAGE_BUFFER is an OpTypeStruct as " ;
1534+ if (resource_variable.is_buffer_block ) {
1535+ ss << " Uniform, with BufferBlock (Vulkan 1.0 didn't have a dedicated StorageBuffer storage class, more info at "
1536+ " https://docs.vulkan.org/guide/latest/extensions/"
1537+ " shader_features.html#VK_KHR_storage_buffer_storage_class)" ;
1538+ } else {
1539+ ss << " StorageBuffer" ;
1540+ }
1541+ }
1542+ if (descriptor_type_set.count (VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT)) {
1543+ ss << " \n - VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT is an OpTypeImage, with Sampled = 2 and Dim = SubpassData, in "
1544+ " UniformConstant" ;
1545+ }
1546+ if (descriptor_type_set.count (VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR)) {
1547+ ss << " \n - VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR is an OpTypeAccelerationStructureKHR in UniformConstant" ;
1548+ }
1549+ if (descriptor_type_set.count (VK_DESCRIPTOR_TYPE_PARTITIONED_ACCELERATION_STRUCTURE_NV)) {
1550+ ss << " \n - VK_DESCRIPTOR_TYPE_PARTITIONED_ACCELERATION_STRUCTURE_NV is an OpTypeAccelerationStructureKHR in "
1551+ " UniformConstant" ;
1552+ }
1553+ if (descriptor_type_set.count (VK_DESCRIPTOR_TYPE_TENSOR_ARM)) {
1554+ ss << " \n - VK_DESCRIPTOR_TYPE_TENSOR_ARM is an OpTypeTensorARM in UniformConstant" ;
1555+ }
1556+ ss << " \n Full list of mappings can be found at "
1557+ " https://docs.vulkan.org/spec/latest/chapters/interfaces.html#interfaces-resources-storage-class-correspondence" ;
1558+ }
1559+ return ss.str ();
1560+ }
1561+ };
1562+
16901563bool CoreChecks::ValidateShaderInterfaceVariableDSL (const spirv::Module& module_state, const spirv::EntryPoint& entrypoint,
16911564 const ShaderStageState& stage_state,
16921565 const spirv::ResourceInterfaceVariable& variable, const Location& loc) const {
@@ -1717,9 +1590,7 @@ bool CoreChecks::ValidateShaderInterfaceVariableDSL(const spirv::Module& module_
17171590 return ss.str ();
17181591 };
17191592
1720- // Pass as reference to not copy the unordered_set on a return
1721- ShaderResourceType resource_type;
1722- TypeToDescriptorTypeSet (module_state, variable.type_id , variable.data_type_id , resource_type);
1593+ ShaderResourceType resource_type (variable);
17231594
17241595 // If no binding nothing left to validate
17251596 if (!binding) {
0 commit comments