Skip to content

Commit cd99896

Browse files
layers: Fix false positive for vertex input with no Location
1 parent 63c493e commit cd99896

5 files changed

Lines changed: 225 additions & 17 deletions

File tree

layers/core_checks/cc_pipeline_graphics.cpp

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,11 @@
2525
#include <vulkan/vk_enum_string_helper.h>
2626
#include <vulkan/utility/vk_format_utils.h>
2727
#include <vulkan/vulkan_core.h>
28+
#include "containers/custom_containers.h"
2829
#include "core_checks/cc_state_tracker.h"
2930
#include "error_message/logging.h"
3031
#include "state_tracker/last_bound_state.h"
32+
#include "utils/assert_utils.h"
3133
#include "utils/math_utils.h"
3234
#include "utils/vk_struct_compare.h"
3335
#include "core_validation.h"
@@ -3403,7 +3405,7 @@ bool CoreChecks::ValidateDrawPipeline(const LastBound &last_bound_state, const v
34033405
}
34043406

34053407
skip |= ValidateDrawPipelineFramebuffer(cb_state, pipeline, vuid);
3406-
skip |= ValidateDrawPipelineVertexBinding(cb_state, pipeline, vuid);
3408+
skip |= ValidateDrawPipelineVertexBinding(cb_state, last_bound_state, pipeline, vuid);
34073409
skip |= ValidateDrawPipelineFragmentDensityMapLayered(cb_state, pipeline, *rp_state, vuid);
34083410
skip |= ValidateDrawPipelineRasterizationState(last_bound_state, pipeline, vuid);
34093411

@@ -4213,10 +4215,18 @@ bool CoreChecks::ValidateDrawPipelineFragmentDensityMapLayered(const vvl::Comman
42134215
return skip;
42144216
}
42154217

4216-
bool CoreChecks::ValidateDrawPipelineVertexBinding(const vvl::CommandBuffer &cb_state, const vvl::Pipeline &pipeline,
4217-
const vvl::DrawDispatchVuid &vuid) const {
4218+
bool CoreChecks::ValidateDrawPipelineVertexBinding(const vvl::CommandBuffer &cb_state, const LastBound &last_bound,
4219+
const vvl::Pipeline &pipeline, const vvl::DrawDispatchVuid &vuid) const {
42184220
bool skip = false;
4219-
if (!pipeline.vertex_input_state) return skip;
4221+
// TODO - Seems even if using mesh shaders, the vertex_input_state is non-null (but emmpty)
4222+
if (!pipeline.vertex_input_state || ((pipeline.active_shaders & VK_SHADER_STAGE_VERTEX_BIT) == 0)) {
4223+
return skip;
4224+
}
4225+
// Since we need to know if the Vertex shader actually declares/uses the Input Location, if the shader validation was disabled,
4226+
// there will no SPIR-V to reflect the information from.
4227+
if (disabled[shader_validation]) {
4228+
return skip;
4229+
}
42204230

42214231
const bool has_dynamic_descriptions = pipeline.IsDynamic(CB_DYNAMIC_STATE_VERTEX_INPUT_EXT);
42224232
const auto &vertex_bindings =
@@ -4230,14 +4240,41 @@ bool CoreChecks::ValidateDrawPipelineVertexBinding(const vvl::CommandBuffer &cb_
42304240
ss << "the last bound pipeline";
42314241
}
42324242
ss << " has pVertexBindingDescriptions[" << binding_description.index << "].binding (" << binding_description.desc.binding
4233-
<< ")";
4243+
<< ") (pointing to Locations [";
4244+
const char *separator = "";
4245+
for (const auto &location : binding_description.locations) {
4246+
ss << separator << location.first;
4247+
separator = ", ";
4248+
}
4249+
ss << "])";
42344250
return ss.str();
42354251
};
42364252

4253+
const spirv::EntryPoint *vertex_entry_point = last_bound.GetVertexEntryPoint();
4254+
ASSERT_AND_RETURN_SKIP(vertex_entry_point);
4255+
vvl::unordered_set<uint32_t> spirv_input_locations;
4256+
for (const auto &pair : vertex_entry_point->input_interface_slots) {
4257+
spirv_input_locations.emplace(pair.first.Location());
4258+
}
4259+
42374260
// It is ok to have binding descriptions not used, them and find if there is matching buffer tied to it or not
42384261
for (const auto &[binding_index, binding_description] : vertex_bindings) {
42394262
// If no attribute points to a binding, it is unused
4240-
if (binding_description.locations.empty()) continue;
4263+
if (binding_description.locations.empty()) {
4264+
continue;
4265+
}
4266+
4267+
bool shader_has_location = false;
4268+
for (const auto &location : binding_description.locations) {
4269+
if (spirv_input_locations.find(location.first) != spirv_input_locations.end()) {
4270+
shader_has_location = true;
4271+
break;
4272+
}
4273+
}
4274+
if (!shader_has_location) {
4275+
// If the Vertex shader doesn't declare the vertex input, there can be invalid/unbound bindings
4276+
continue;
4277+
}
42414278

42424279
const auto *vertex_buffer_binding = vvl::Find(cb_state.current_vertex_buffer_binding_info, binding_index);
42434280
if (!vertex_buffer_binding || !vertex_buffer_binding->bound) {

layers/core_checks/core_validation.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -638,8 +638,8 @@ class CoreChecks : public vvl::DeviceProxy {
638638
VkDeviceSize count_buffer_offset, const vvl::DrawDispatchVuid& vuid) const;
639639
bool ValidateDrawPipelineFramebuffer(const vvl::CommandBuffer& cb_state, const vvl::Pipeline& pipeline,
640640
const vvl::DrawDispatchVuid& vuid) const;
641-
bool ValidateDrawPipelineVertexBinding(const vvl::CommandBuffer& cb_state, const vvl::Pipeline& pipeline,
642-
const vvl::DrawDispatchVuid& vuid) const;
641+
bool ValidateDrawPipelineVertexBinding(const vvl::CommandBuffer& cb_state, const LastBound& last_bound,
642+
const vvl::Pipeline& pipeline, const vvl::DrawDispatchVuid& vuid) const;
643643
bool ValidateDrawPipelineFragmentDensityMapLayered(const vvl::CommandBuffer& cb_state, const vvl::Pipeline& pipeline,
644644
const vvl::RenderPass& rp_state, const vvl::DrawDispatchVuid& vuid) const;
645645
bool ValidateDrawPipelineRasterizationState(const LastBound& last_bound_state, const vvl::Pipeline& pipeline,

tests/unit/dynamic_state.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -772,6 +772,13 @@ TEST_F(NegativeDynamicState, ExtendedDynamicStateSetViewportScissor) {
772772
std::vector<VkBuffer> buffers(m_device->Physical().limits_.maxVertexInputBindings + 1ull, buffer);
773773
std::vector<VkDeviceSize> offsets(buffers.size(), 0);
774774

775+
const char *vs_source = R"glsl(
776+
#version 450
777+
layout(location=0) in vec4 x;
778+
void main(){}
779+
)glsl";
780+
VkShaderObj vs(this, vs_source, VK_SHADER_STAGE_VERTEX_BIT);
781+
775782
CreatePipelineHelper pipe(*this);
776783
pipe.AddDynamicState(VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT);
777784
pipe.AddDynamicState(VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT);
@@ -780,11 +787,12 @@ TEST_F(NegativeDynamicState, ExtendedDynamicStateSetViewportScissor) {
780787
pipe.vp_state_ci_.viewportCount = 0;
781788
pipe.vp_state_ci_.scissorCount = 0;
782789
pipe.vi_ci_.vertexBindingDescriptionCount = 1;
783-
VkVertexInputBindingDescription inputBinding = {0, sizeof(float), VK_VERTEX_INPUT_RATE_VERTEX};
784-
pipe.vi_ci_.pVertexBindingDescriptions = &inputBinding;
790+
VkVertexInputBindingDescription input_binding = {0, sizeof(float), VK_VERTEX_INPUT_RATE_VERTEX};
791+
pipe.vi_ci_.pVertexBindingDescriptions = &input_binding;
785792
pipe.vi_ci_.vertexAttributeDescriptionCount = 1;
786793
VkVertexInputAttributeDescription attribute = {0, 0, VK_FORMAT_R32_SFLOAT, 0};
787794
pipe.vi_ci_.pVertexAttributeDescriptions = &attribute;
795+
pipe.shader_stages_ = {vs.GetStageCreateInfo(), pipe.fs_->GetStageCreateInfo()};
788796
pipe.CreateGraphicsPipeline();
789797

790798
m_command_buffer.Begin();

0 commit comments

Comments
 (0)