Improve error messages for pipeline/descriptor mismatches
We were emitting type trees here, which are ridiculously large for
SSBOs, etc.
diff --git a/layers/shader_validation.cpp b/layers/shader_validation.cpp
index 7b2f411..e5baa7a 100644
--- a/layers/shader_validation.cpp
+++ b/layers/shader_validation.cpp
@@ -1084,8 +1084,7 @@
return skip;
}
-static bool DescriptorTypeMatch(shader_module const *module, uint32_t type_id, VkDescriptorType descriptor_type,
- unsigned &descriptor_count) {
+static uint32_t TypeToDescriptorTypeBits(shader_module const *module, uint32_t type_id, unsigned &descriptor_count) {
auto type = module->get_def(type_id);
bool is_storage_buffer = false;
descriptor_count = 1;
@@ -1112,36 +1111,34 @@
if (insn.opcode() == spv::OpDecorate && insn.word(1) == type.word(1)) {
if (insn.word(2) == spv::DecorationBlock) {
if (is_storage_buffer) {
- return descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER ||
- descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC;
+ return (1 << VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) | (1 << VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC);
} else {
- return descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER ||
- descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
+ return (1 << VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) | (1 << VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC);
}
} else if (insn.word(2) == spv::DecorationBufferBlock) {
- return descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER ||
- descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC;
+ return (1 << VK_DESCRIPTOR_TYPE_STORAGE_BUFFER) | (1 << VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC);
}
}
}
// Invalid
- return false;
+ return 0;
}
case spv::OpTypeSampler:
- return descriptor_type == VK_DESCRIPTOR_TYPE_SAMPLER || descriptor_type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+ return (1 << VK_DESCRIPTOR_TYPE_SAMPLER) | (1 << VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
- case spv::OpTypeSampledImage:
- if (descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER) {
- // Slight relaxation for some GLSL historical madness: samplerBuffer doesn't really have a sampler, and a texel
- // buffer descriptor doesn't really provide one. Allow this slight mismatch.
- auto image_type = module->get_def(type.word(2));
- auto dim = image_type.word(3);
- auto sampled = image_type.word(7);
- return dim == spv::DimBuffer && sampled == 1;
+ case spv::OpTypeSampledImage: {
+ // Slight relaxation for some GLSL historical madness: samplerBuffer doesn't really have a sampler, and a texel
+ // buffer descriptor doesn't really provide one. Allow this slight mismatch.
+ auto image_type = module->get_def(type.word(2));
+ auto dim = image_type.word(3);
+ auto sampled = image_type.word(7);
+ if (dim == spv::DimBuffer && sampled == 1) {
+ return 1 << VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
}
- return descriptor_type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+ }
+ return 1 << VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
case spv::OpTypeImage: {
// Many descriptor types backing image types-- depends on dimension and whether the image will be used with a sampler.
@@ -1150,27 +1147,37 @@
auto sampled = type.word(7);
if (dim == spv::DimSubpassData) {
- return descriptor_type == VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT;
+ return 1 << VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT;
} else if (dim == spv::DimBuffer) {
if (sampled == 1) {
- return descriptor_type == VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
+ return 1 << VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER;
} else {
- return descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
+ return 1 << VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER;
}
} else if (sampled == 1) {
- return descriptor_type == VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE ||
- descriptor_type == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
+ return (1 << VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE) | (1 << VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER);
} else {
- return descriptor_type == VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
+ return 1 << VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
}
}
// We shouldn't really see any other junk types -- but if we do, they're a mismatch.
default:
- return false; // Mismatch
+ return 0; // Matches nothing
}
}
+static std::string string_descriptorTypeBits(uint32_t bits) {
+ std::stringstream ss;
+ for (int i = 0; i < 32; i++) {
+ if (bits & (1 << i)) {
+ if (ss.tellp()) ss << ", ";
+ ss << string_VkDescriptorType(VkDescriptorType(i));
+ }
+ }
+ return ss.str();
+}
+
static bool RequireFeature(debug_report_data const *report_data, VkBool32 feature, char const *feature_name) {
if (!feature) {
if (log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
@@ -1488,30 +1495,29 @@
// Verify given pipelineLayout has requested setLayout with requested binding
const auto &binding = GetDescriptorBinding(&pipeline->pipeline_layout, use.first);
unsigned required_descriptor_count;
+ uint32_t descriptor_type_bits = TypeToDescriptorTypeBits(module, use.second.type_id, required_descriptor_count);
if (!binding) {
skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
kVUID_Core_Shader_MissingDescriptor,
- "Shader uses descriptor slot %u.%u (used as type `%s`) but not declared in pipeline layout",
- use.first.first, use.first.second, DescribeType(module, use.second.type_id).c_str());
+ "Shader uses descriptor slot %u.%u (expected `%s`) but not declared in pipeline layout",
+ use.first.first, use.first.second, string_descriptorTypeBits(descriptor_type_bits).c_str());
} else if (~binding->stageFlags & pStage->stage) {
skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, 0,
kVUID_Core_Shader_DescriptorNotAccessibleFromStage,
- "Shader uses descriptor slot %u.%u (used as type `%s`) but descriptor not accessible from stage %s",
- use.first.first, use.first.second, DescribeType(module, use.second.type_id).c_str(),
- string_VkShaderStageFlagBits(pStage->stage));
- } else if (!DescriptorTypeMatch(module, use.second.type_id, binding->descriptorType, required_descriptor_count)) {
+ "Shader uses descriptor slot %u.%u but descriptor not accessible from stage %s", use.first.first,
+ use.first.second, string_VkShaderStageFlagBits(pStage->stage));
+ } else if (!(descriptor_type_bits & (1 << binding->descriptorType))) {
skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
kVUID_Core_Shader_DescriptorTypeMismatch,
- "Type mismatch on descriptor slot %u.%u (used as type `%s`) but descriptor of type %s", use.first.first,
- use.first.second, DescribeType(module, use.second.type_id).c_str(),
+ "Type mismatch on descriptor slot %u.%u (expected `%s`) but descriptor of type %s", use.first.first,
+ use.first.second, string_descriptorTypeBits(descriptor_type_bits).c_str(),
string_VkDescriptorType(binding->descriptorType));
} else if (binding->descriptorCount < required_descriptor_count) {
skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
kVUID_Core_Shader_DescriptorTypeMismatch,
- "Shader expects at least %u descriptors for binding %u.%u (used as type `%s`) but only %u provided",
- required_descriptor_count, use.first.first, use.first.second,
- DescribeType(module, use.second.type_id).c_str(), binding->descriptorCount);
+ "Shader expects at least %u descriptors for binding %u.%u but only %u provided",
+ required_descriptor_count, use.first.first, use.first.second, binding->descriptorCount);
}
}
diff --git a/tests/layer_validation_tests.cpp b/tests/layer_validation_tests.cpp
index a7afe35..21e3e63 100644
--- a/tests/layer_validation_tests.cpp
+++ b/tests/layer_validation_tests.cpp
@@ -17441,7 +17441,7 @@
ASSERT_NO_FATAL_FAILURE(Init());
ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
- const char *descriptor_type_mismatch_message = "Type mismatch on descriptor slot 0.0 (used as type ";
+ const char *descriptor_type_mismatch_message = "Type mismatch on descriptor slot 0.0 ";
OneOffDescriptorSet ds(m_device, {
{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr},
@@ -17487,7 +17487,7 @@
ASSERT_NO_FATAL_FAILURE(Init());
ASSERT_NO_FATAL_FAILURE(InitRenderTarget());
- const char *descriptor_not_accessible_message = "Shader uses descriptor slot 0.0 (used as type ";
+ const char *descriptor_not_accessible_message = "Shader uses descriptor slot 0.0 ";
OneOffDescriptorSet ds(m_device, {
{0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT /*!*/, nullptr},