Skip to content

Commit 40ecf3c

Browse files
layers: Improve 08600 error messages
1 parent 4329a7e commit 40ecf3c

8 files changed

Lines changed: 376 additions & 185 deletions

File tree

layers/core_checks/cc_descriptor.cpp

Lines changed: 93 additions & 95 deletions
Large diffs are not rendered by default.

layers/core_checks/cc_drawdispatch.cpp

Lines changed: 60 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
* limitations under the License.
1818
*/
1919

20+
#include <vulkan/vk_enum_string_helper.h>
2021
#include "drawdispatch/drawdispatch_vuids.h"
2122
#include "core_validation.h"
2223
#include "generated/vk_extension_helper.h"
@@ -27,6 +28,7 @@
2728
#include "state_tracker/shader_module.h"
2829
#include "state_tracker/cmd_buffer_state.h"
2930
#include "state_tracker/pipeline_state.h"
31+
#include "utils/vk_layer_utils.h"
3032

3133
using vvl::DrawDispatchVuid;
3234
using vvl::GetDrawDispatchVuid;
@@ -1374,12 +1376,26 @@ bool CoreChecks::ValidateActionStateDescriptorsPipeline(const LastBound &last_bo
13741376
}
13751377

13761378
// Check if the current pipeline is compatible for the maximum used set with the bound sets.
1377-
if (pipeline.descriptor_buffer_mode) return skip;
1379+
if (pipeline.descriptor_buffer_mode) {
1380+
return skip;
1381+
}
13781382

13791383
const auto pipeline_layout = pipeline.PipelineLayoutState();
13801384
if (!pipeline.active_slots.empty() && !last_bound_state.IsBoundSetCompatible(pipeline.max_active_slot, *pipeline_layout)) {
1385+
// If they never bound any descriptors
1386+
if (!last_bound_state.desc_set_pipeline_layout) {
1387+
skip |= LogError(vuid.compatible_pipeline_08600, cb_state.GetObjectList(bind_point), vuid.loc(),
1388+
"The %s statically uses descriptor set %" PRIu32
1389+
", but because a descriptor was never bound, the pipeline layouts are not compatible.\nIf using a "
1390+
"descriptor, make sure to call one of vkCmdBindDescriptorSets, vkCmdPushDescriptorSet, "
1391+
"vkCmdSetDescriptorBufferOffset, etc for %s",
1392+
FormatHandle(pipeline).c_str(), pipeline.max_active_slot, string_VkPipelineBindPoint(bind_point));
1393+
return skip;
1394+
}
1395+
13811396
LogObjectList objlist(pipeline.Handle());
13821397
const auto layouts = pipeline.PipelineLayoutStateUnion();
1398+
// GPL can have multiple pipeline layouts used to build up a single valid compatible set
13831399
std::ostringstream pipe_layouts_log;
13841400
if (layouts.size() > 1) {
13851401
pipe_layouts_log << "a union of layouts [ ";
@@ -1391,21 +1407,17 @@ bool CoreChecks::ValidateActionStateDescriptorsPipeline(const LastBound &last_bo
13911407
} else {
13921408
pipe_layouts_log << FormatHandle(*layouts.front());
13931409
}
1394-
std::string pipeline_layout_handle_str;
1395-
if (last_bound_state.desc_set_pipeline_layout) {
1396-
pipeline_layout_handle_str = FormatHandle(last_bound_state.desc_set_pipeline_layout->Handle());
1397-
objlist.add(last_bound_state.desc_set_pipeline_layout->Handle());
1398-
} else {
1399-
pipeline_layout_handle_str = "Pipeline Layout never bound"; // < can happen when dealing with multiview
1400-
}
1410+
1411+
objlist.add(last_bound_state.desc_set_pipeline_layout->Handle());
14011412

14021413
std::string range =
14031414
pipeline.max_active_slot == 0 ? "set 0 is" : "all sets 0 to " + std::to_string(pipeline.max_active_slot) + " are";
14041415
skip |= LogError(vuid.compatible_pipeline_08600, objlist, vuid.loc(),
14051416
"The %s (created with %s) statically uses descriptor set %" PRIu32
14061417
", but %s not compatible with the pipeline layout bound with %s (%s)\n%s",
14071418
FormatHandle(pipeline).c_str(), pipe_layouts_log.str().c_str(), pipeline.max_active_slot, range.c_str(),
1408-
String(last_bound_state.desc_set_bound_command), pipeline_layout_handle_str.c_str(),
1419+
String(last_bound_state.desc_set_bound_command),
1420+
FormatHandle(last_bound_state.desc_set_pipeline_layout->Handle()).c_str(),
14091421
last_bound_state.DescribeNonCompatibleSet(pipeline.max_active_slot, *pipeline_layout).c_str());
14101422
} else {
14111423
// if the bound set is not compatible, the rest will just be extra redundant errors
@@ -1414,17 +1426,16 @@ bool CoreChecks::ValidateActionStateDescriptorsPipeline(const LastBound &last_bo
14141426
const auto ds_slot = last_bound_state.ds_slots[set_index];
14151427
if (!ds_slot.ds_state) {
14161428
skip |= LogError(vuid.compatible_pipeline_08600, cb_state.GetObjectList(bind_point), vuid.loc(),
1417-
"%s uses set #%" PRIu32
1429+
"%s uses set %" PRIu32
14181430
" but that set is not bound. (Need to use a command like vkCmdBindDescriptorSets to bind the set)",
14191431
FormatHandle(pipeline).c_str(), set_index);
1420-
} else if (!VerifySetLayoutCompatibility(*ds_slot.ds_state, pipeline_layout->set_layouts, pipeline_layout->Handle(),
1421-
set_index, error_string)) {
1422-
// Set is bound but not compatible w/ overlapping pipeline_layout from PSO
1432+
} else if (!VerifyDescriptorSetIsCompatibile(*ds_slot.ds_state, pipeline_layout->set_layouts, set_index,
1433+
error_string)) {
1434+
// Set is bound but not compatible w/ corresponding VkPipelineLayoutCreateInfo::pSetLayouts
14231435
VkDescriptorSet set_handle = ds_slot.ds_state->VkHandle();
1424-
LogObjectList objlist = cb_state.GetObjectList(bind_point);
1425-
objlist.add(set_handle);
1436+
const LogObjectList objlist(cb_state.Handle(), set_handle, pipeline.Handle(), pipeline_layout->Handle());
14261437
skip |= LogError(vuid.compatible_pipeline_08600, objlist, vuid.loc(),
1427-
"%s bound as set #%" PRIu32 " is not compatible with overlapping %s due to: %s",
1438+
"%s bound as set %" PRIu32 " is not compatible with corresponding %s\n%s",
14281439
FormatHandle(set_handle).c_str(), set_index, FormatHandle(*pipeline_layout).c_str(),
14291440
error_string.c_str());
14301441
} else { // Valid set is bound and layout compatible, validate that it's updated
@@ -1450,16 +1461,37 @@ bool CoreChecks::ValidateActionStateDescriptorsShaderObject(const LastBound &las
14501461

14511462
// Check if the current shader objects are compatible for the maximum used set with the bound sets.
14521463
for (const auto &shader_state : last_bound_state.shader_object_states) {
1453-
if (!shader_state) continue;
1464+
if (!shader_state) {
1465+
continue;
1466+
}
14541467

1455-
if (shader_state && !shader_state->active_slots.empty() &&
1468+
if (!shader_state->active_slots.empty() &&
14561469
!last_bound_state.IsBoundSetCompatible(shader_state->max_active_slot, *shader_state)) {
14571470
LogObjectList objlist(cb_state.Handle(), shader_state->Handle());
1458-
skip |= LogError(vuid.compatible_pipeline_08600, objlist, vuid.loc(),
1459-
"The %s statically uses descriptor set (index #%" PRIu32
1460-
") which is not compatible with the currently bound descriptor set's layout\n%s",
1461-
FormatHandle(shader_state->Handle()).c_str(), shader_state->max_active_slot,
1462-
last_bound_state.DescribeNonCompatibleSet(shader_state->max_active_slot, *shader_state).c_str());
1471+
1472+
if (!last_bound_state.desc_set_pipeline_layout) {
1473+
// If they never bound any descriptors
1474+
skip |= LogError(vuid.compatible_pipeline_08600, cb_state.GetObjectList(bind_point), vuid.loc(),
1475+
"The %s statically uses descriptor set %" PRIu32
1476+
", but because a descriptor was never bound, the pipeline layouts are not compatible.\nIf using "
1477+
"a descriptor, make sure to call one of vkCmdBindDescriptorSets, vkCmdPushDescriptorSet, "
1478+
"vkCmdSetDescriptorBufferOffset, etc for %s",
1479+
FormatHandle(shader_state->Handle()).c_str(), shader_state->max_active_slot,
1480+
string_VkPipelineBindPoint(bind_point));
1481+
1482+
} else {
1483+
objlist.add(last_bound_state.desc_set_pipeline_layout->Handle());
1484+
std::string range = shader_state->max_active_slot == 0
1485+
? "set 0 is"
1486+
: "all sets 0 to " + std::to_string(shader_state->max_active_slot) + " are";
1487+
skip |= LogError(vuid.compatible_pipeline_08600, objlist, vuid.loc(),
1488+
"The %s statically uses descriptor set %" PRIu32
1489+
" but %s not compatible with the pipeline layout bound with %s (%s)\n%s",
1490+
FormatHandle(shader_state->Handle()).c_str(), shader_state->max_active_slot, range.c_str(),
1491+
String(last_bound_state.desc_set_bound_command),
1492+
FormatHandle(last_bound_state.desc_set_pipeline_layout->Handle()).c_str(),
1493+
last_bound_state.DescribeNonCompatibleSet(shader_state->max_active_slot, *shader_state).c_str());
1494+
}
14631495
} else {
14641496
// if the bound set is not copmatible, the rest will just be extra redundant errors
14651497
for (const auto &[set_index, binding_req_map] : shader_state->active_slots) {
@@ -1468,15 +1500,15 @@ bool CoreChecks::ValidateActionStateDescriptorsShaderObject(const LastBound &las
14681500
if (!ds_slot.ds_state) {
14691501
const LogObjectList objlist(cb_state.Handle(), shader_state->Handle());
14701502
skip |= LogError(vuid.compatible_pipeline_08600, objlist, vuid.loc(),
1471-
"%s uses set #%" PRIu32 " but that set is not bound.",
1503+
"%s uses set %" PRIu32 " but that set is not bound.",
14721504
FormatHandle(shader_state->Handle()).c_str(), set_index);
1473-
} else if (!VerifySetLayoutCompatibility(*ds_slot.ds_state, shader_state->set_layouts, shader_state->Handle(),
1474-
set_index, error_string)) {
1475-
// Set is bound but not compatible w/ overlapping pipeline_layout from PSO
1505+
} else if (!VerifyDescriptorSetIsCompatibile(*ds_slot.ds_state, shader_state->set_layouts, set_index,
1506+
error_string)) {
1507+
// Set is bound but not compatible w/ corresponding VkShaderCreateInfoEXT::pSetLayouts
14761508
VkDescriptorSet set_handle = ds_slot.ds_state->VkHandle();
14771509
const LogObjectList objlist(cb_state.Handle(), set_handle, shader_state->Handle());
14781510
skip |= LogError(vuid.compatible_pipeline_08600, objlist, vuid.loc(),
1479-
"%s bound as set #%" PRIu32 " is not compatible with overlapping %s due to: %s",
1511+
"%s bound as set %" PRIu32 " is not compatible with corresponding %s\n%s",
14801512
FormatHandle(set_handle).c_str(), set_index, FormatHandle(shader_state->Handle()).c_str(),
14811513
error_string.c_str());
14821514
} else { // Valid set is bound and layout compatible, validate that it's updated

layers/core_checks/core_validation.h

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -742,12 +742,12 @@ class CoreChecks : public vvl::DeviceProxy {
742742

743743
bool ImmutableSamplersAreEqual(const VkDescriptorSetLayoutBinding& b1, const VkDescriptorSetLayoutBinding& b2,
744744
bool& out_exception) const;
745-
bool VerifySetLayoutCompatibility(const vvl::DescriptorSetLayout& layout_dsl,
746-
const vvl::DescriptorSetLayout& bound_dsl, std::string& error_msg) const;
747-
748-
bool VerifySetLayoutCompatibility(const vvl::DescriptorSet& descriptor_set,
749-
const std::vector<std::shared_ptr<vvl::DescriptorSetLayout const>>& set_layouts,
750-
const VulkanTypedHandle& handle, const uint32_t layoutIndex, std::string& error_msg) const;
745+
bool VerifyDescriptorSetLayoutIsCompatibile(const vvl::DescriptorSetLayout& reference_dsl,
746+
const vvl::DescriptorSetLayout& to_bind_dsl, std::string& error_msg) const;
747+
bool VerifyDescriptorSetIsCompatibile(
748+
const vvl::DescriptorSet& to_bind_descriptor_set,
749+
const std::vector<std::shared_ptr<vvl::DescriptorSetLayout const>>& descriptor_set_layouts, const uint32_t index,
750+
std::string& error_msg) const;
751751

752752
bool VerifyPipelineLayoutCompatibility(const vvl::PipelineLayout& layout_a, const vvl::PipelineLayout& layout_b,
753753
std::string& error_msg) const;
@@ -1763,11 +1763,11 @@ class CoreChecks : public vvl::DeviceProxy {
17631763
const ErrorObject& error_obj) const override;
17641764
bool PreCallValidateCmdSetStencilReference(VkCommandBuffer commandBuffer, VkStencilFaceFlags faceMask, uint32_t reference,
17651765
const ErrorObject& error_obj) const override;
1766-
bool ValidateCmdBindDescriptorSets(const vvl::CommandBuffer&, VkPipelineLayout layout, uint32_t firstSet, uint32_t setCount,
1767-
const VkDescriptorSet* pDescriptorSets, uint32_t dynamicOffsetCount,
1768-
const uint32_t* pDynamicOffsets, const Location& loc) const;
1766+
bool ValidateCmdBindDescriptorSets(const vvl::CommandBuffer&, VkPipelineLayout layout, uint32_t firstSet,
1767+
uint32_t descriptorSetCount, const VkDescriptorSet* pDescriptorSets,
1768+
uint32_t dynamicOffsetCount, const uint32_t* pDynamicOffsets, const Location& loc) const;
17691769
bool PreCallValidateCmdBindDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBindPoint pipelineBindPoint,
1770-
VkPipelineLayout layout, uint32_t firstSet, uint32_t setCount,
1770+
VkPipelineLayout layout, uint32_t firstSet, uint32_t descriptorSetCount,
17711771
const VkDescriptorSet* pDescriptorSets, uint32_t dynamicOffsetCount,
17721772
const uint32_t* pDynamicOffsets, const ErrorObject& error_obj) const override;
17731773
bool PreCallValidateCmdBindDescriptorSets2(VkCommandBuffer commandBuffer,

layers/state_tracker/cmd_buffer_state.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1316,7 +1316,7 @@ void CommandBuffer::UpdateLastBoundDescriptorSets(VkPipelineBindPoint pipeline_b
13161316

13171317
uint32_t required_size = first_set + set_count;
13181318
const uint32_t last_binding_index = required_size - 1;
1319-
assert(last_binding_index < pipeline_layout->set_compat_ids.size());
1319+
ASSERT_AND_RETURN(last_binding_index < pipeline_layout->set_compat_ids.size());
13201320

13211321
// Some useful shorthand
13221322
const auto lv_bind_point = ConvertToLvlBindPoint(pipeline_bind_point);

layers/state_tracker/last_bound_state.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -582,7 +582,9 @@ bool LastBound::IsBoundSetCompatible(uint32_t set, const vvl::ShaderObject &shad
582582
std::string LastBound::DescribeNonCompatibleSet(uint32_t set, const vvl::PipelineLayout &pipeline_layout) const {
583583
std::ostringstream ss;
584584
if (set >= ds_slots.size()) {
585-
ss << "The set (" << set << ") is out of bounds for the number of sets bound (" << ds_slots.size() << ")\n";
585+
ss << "The set (" << set << ") is out of bounds for the number of sets bound (" << ds_slots.size()
586+
<< ")\nHint: Make sure the previous calls to " << String(desc_set_bound_command)
587+
<< " has all sets bound that are needed.";
586588
} else if (set >= pipeline_layout.set_compat_ids.size()) {
587589
ss << "The set (" << set << ") is out of bounds for the number of sets in the non-compatible VkPipelineLayout ("
588590
<< pipeline_layout.set_compat_ids.size() << ")\n";
@@ -595,7 +597,9 @@ std::string LastBound::DescribeNonCompatibleSet(uint32_t set, const vvl::Pipelin
595597
std::string LastBound::DescribeNonCompatibleSet(uint32_t set, const vvl::ShaderObject &shader_object_state) const {
596598
std::ostringstream ss;
597599
if (set >= ds_slots.size()) {
598-
ss << "The set (" << set << ") is out of bounds for the number of sets bound (" << ds_slots.size() << ")\n";
600+
ss << "The set (" << set << ") is out of bounds for the number of sets bound (" << ds_slots.size()
601+
<< ")\nHint: Make sure the previous calls to " << String(desc_set_bound_command)
602+
<< " has all sets bound that are needed.";
599603
} else if (set >= shader_object_state.set_compat_ids.size()) {
600604
ss << "The set (" << set << ") is out of bounds for the number of sets in the non-compatible VkDescriptorSetLayout ("
601605
<< shader_object_state.set_compat_ids.size() << ")\n";

0 commit comments

Comments
 (0)