Skip to content

Commit b8e9784

Browse files
layers: Add helper functions to get DescriptorType
1 parent d12550f commit b8e9784

4 files changed

Lines changed: 153 additions & 236 deletions

File tree

layers/core_checks/cc_spirv.cpp

Lines changed: 82 additions & 211 deletions
Original file line numberDiff line numberDiff line change
@@ -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 << "\nInfo 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 << "\nFull 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
418226
VkComponentTypeKHR 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 << "\nInfo 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 << "\nFull 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+
16901563
bool 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

Comments
 (0)