diff --git a/layers/core_checks/cc_cmd_buffer_dynamic.cpp b/layers/core_checks/cc_cmd_buffer_dynamic.cpp index e05534c91dd..779cd626eec 100644 --- a/layers/core_checks/cc_cmd_buffer_dynamic.cpp +++ b/layers/core_checks/cc_cmd_buffer_dynamic.cpp @@ -191,6 +191,9 @@ bool CoreChecks::ValidateDynamicStateIsSet(const LastBound& last_bound_state, co case CB_DYNAMIC_STATE_VIEWPORT_W_SCALING_NV: vuid_str = vuid.set_clip_space_w_scaling_04138; break; + case CB_DYNAMIC_STATE_PATCH_CONTROL_POINTS_EXT: + vuid_str = vuid.patch_control_points_04875; + break; default: assert(false); break; @@ -212,8 +215,8 @@ bool CoreChecks::ValidateGraphicsDynamicStateSetStatus(const LastBound& last_bou const bool vertex_shader_bound = has_pipeline || last_bound_state.IsValidShaderBound(ShaderObjectStage::VERTEX); const bool fragment_shader_bound = has_pipeline || last_bound_state.IsValidShaderBound(ShaderObjectStage::FRAGMENT); const bool geom_shader_bound = has_pipeline || last_bound_state.IsValidShaderBound(ShaderObjectStage::GEOMETRY); - const bool tessev_shader_bound = - has_pipeline || last_bound_state.IsValidShaderBound(ShaderObjectStage::TESSELLATION_EVALUATION); + const bool tesc_shader_bound = has_pipeline || last_bound_state.IsValidShaderBound(ShaderObjectStage::TESSELLATION_CONTROL); + const bool tese_shader_bound = has_pipeline || last_bound_state.IsValidShaderBound(ShaderObjectStage::TESSELLATION_EVALUATION); // build the mask of what has been set in the Pipeline, but yet to be set in the Command Buffer, // for Shader Object, everything is dynamic don't need a mask @@ -377,10 +380,21 @@ bool CoreChecks::ValidateGraphicsDynamicStateSetStatus(const LastBound& last_bou skip |= ValidateDynamicStateIsSet(last_bound_state, state_status_cb, CB_DYNAMIC_STATE_VERTEX_INPUT_EXT, vuid); } - if (tessev_shader_bound) { + if (tese_shader_bound) { skip |= ValidateDynamicStateIsSet(last_bound_state, state_status_cb, CB_DYNAMIC_STATE_TESSELLATION_DOMAIN_ORIGIN_EXT, vuid); } + if (tesc_shader_bound) { + // Don't call GetPrimitiveTopology() because want to view the Topology from the dynamic state for ShaderObjects + const VkPrimitiveTopology topology = + (!last_bound_state.pipeline_state || last_bound_state.pipeline_state->IsDynamic(CB_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY)) + ? cb_state.dynamic_state_value.primitive_topology + : last_bound_state.pipeline_state->topology_at_rasterizer; + if (topology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST) { + skip |= ValidateDynamicStateIsSet(last_bound_state, state_status_cb, CB_DYNAMIC_STATE_PATCH_CONTROL_POINTS_EXT, vuid); + } + } + if (geom_shader_bound) { if (enabled_features.geometryStreams) { skip |= ValidateDynamicStateIsSet(last_bound_state, state_status_cb, CB_DYNAMIC_STATE_RASTERIZATION_STREAM_EXT, vuid); @@ -454,12 +468,6 @@ bool CoreChecks::ValidateGraphicsDynamicStatePipelineSetStatus(const LastBound& // build the mask of what has been set in the Pipeline, but yet to be set in the Command Buffer const CBDynamicFlags state_status_cb = ~((cb_state.dynamic_state_status.cb ^ pipeline.dynamic_state) & pipeline.dynamic_state); - // VK_EXT_extended_dynamic_state2 - { - skip |= ValidateDynamicStateIsSet(state_status_cb, CB_DYNAMIC_STATE_PATCH_CONTROL_POINTS_EXT, cb_state, objlist, loc, - vuid.patch_control_points_04875); - } - // VK_EXT_extended_dynamic_state3 { skip |= ValidateDynamicStateIsSet(state_status_cb, CB_DYNAMIC_STATE_COLOR_BLEND_EQUATION_EXT, cb_state, objlist, loc, @@ -1492,10 +1500,6 @@ bool CoreChecks::ValidateDrawDynamicStateShaderObject(const LastBound& last_boun vuid.set_line_width_08617); } - if (tessev_shader_bound) { - skip |= ValidateDynamicStateIsSet(cb_state.dynamic_state_status.cb, CB_DYNAMIC_STATE_PATCH_CONTROL_POINTS_EXT, cb_state, - objlist, loc, vuid.patch_control_points_04875); - } if ((tessev_shader_bound && tess_shader_line_topology) || (geom_shader_bound && geom_shader_line_topology)) { skip |= ValidateDynamicStateIsSet(cb_state.dynamic_state_status.cb, CB_DYNAMIC_STATE_LINE_WIDTH, cb_state, objlist, loc, vuid.set_line_width_08619); diff --git a/layers/state_tracker/pipeline_state.cpp b/layers/state_tracker/pipeline_state.cpp index d9ccc9dab84..755e48741bc 100644 --- a/layers/state_tracker/pipeline_state.cpp +++ b/layers/state_tracker/pipeline_state.cpp @@ -1009,9 +1009,7 @@ bool LastBound::IsColorWriteEnabled(uint32_t i) const { } VkPrimitiveTopology LastBound::GetPrimitiveTopology() const { - if (!pipeline_state) { - return GetShaderState(ShaderObjectStage::VERTEX)->GetTopology(); - } else if (pipeline_state->IsDynamic(CB_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY)) { + if (!pipeline_state || pipeline_state->IsDynamic(CB_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY)) { return cb_state.dynamic_state_value.primitive_topology; } else { return pipeline_state->topology_at_rasterizer; diff --git a/tests/unit/shader_object.cpp b/tests/unit/shader_object.cpp index fc695c901f4..e51f7699117 100644 --- a/tests/unit/shader_object.cpp +++ b/tests/unit/shader_object.cpp @@ -3348,6 +3348,7 @@ TEST_F(NegativeShaderObject, MissingCmdSetPatchControlPointsEXT) { const VkShaderEXT shaders[] = {vertShader.handle(), tescShader.handle(), teseShader.handle(), VK_NULL_HANDLE, fragShader.handle()}; vk::CmdBindShadersEXT(m_commandBuffer->handle(), 5u, stages, shaders); + vk::CmdSetPrimitiveTopologyEXT(m_commandBuffer->handle(), VK_PRIMITIVE_TOPOLOGY_PATCH_LIST); vk::CmdDraw(m_commandBuffer->handle(), 4, 1, 0, 0); m_commandBuffer->EndRendering(); m_commandBuffer->end(); diff --git a/tests/unit/shader_object_positive.cpp b/tests/unit/shader_object_positive.cpp index d121be14274..bdc46170a63 100644 --- a/tests/unit/shader_object_positive.cpp +++ b/tests/unit/shader_object_positive.cpp @@ -1632,3 +1632,37 @@ TEST_F(PositiveShaderObject, DrawWithVertGeomFragShaderObjects) { m_commandBuffer->EndRendering(); m_commandBuffer->end(); } + +TEST_F(PositiveShaderObject, MissingCmdSetPatchControlPointsEXT) { + RETURN_IF_SKIP(InitBasicShaderObject()); + VkPhysicalDeviceFeatures features; + GetPhysicalDeviceFeatures(&features); + if (features.tessellationShader == VK_FALSE) { + GTEST_SKIP() << "tessellationShader not supported."; + } + InitDynamicRenderTarget(); + + const vkt::Shader vertShader(*m_device, VK_SHADER_STAGE_VERTEX_BIT, GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, kVertexMinimalGlsl)); + const vkt::Shader tescShader(*m_device, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, + GLSLToSPV(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, kTessellationControlMinimalGlsl)); + const vkt::Shader teseShader(*m_device, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, + GLSLToSPV(VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, kTessellationEvalMinimalGlsl)); + const vkt::Shader fragShader(*m_device, VK_SHADER_STAGE_FRAGMENT_BIT, + GLSLToSPV(VK_SHADER_STAGE_FRAGMENT_BIT, kFragmentMinimalGlsl)); + m_commandBuffer->begin(); + m_commandBuffer->BeginRenderingColor(GetDynamicRenderTarget(), GetRenderTargetArea()); + SetDefaultDynamicStatesExclude({VK_DYNAMIC_STATE_PATCH_CONTROL_POINTS_EXT}); + const VkShaderStageFlagBits stages[] = {VK_SHADER_STAGE_VERTEX_BIT, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, + VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, VK_SHADER_STAGE_GEOMETRY_BIT, + VK_SHADER_STAGE_FRAGMENT_BIT}; + const VkShaderEXT shaders[] = {vertShader.handle(), tescShader.handle(), teseShader.handle(), VK_NULL_HANDLE, + fragShader.handle()}; + vk::CmdBindShadersEXT(m_commandBuffer->handle(), 5u, stages, shaders); + // valid because this is not VK_PRIMITIVE_TOPOLOGY_PATCH_LIST + vk::CmdSetPrimitiveTopologyEXT(m_commandBuffer->handle(), VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST); + vk::CmdDraw(m_commandBuffer->handle(), 4, 1, 0, 0); + m_commandBuffer->EndRendering(); + m_commandBuffer->end(); + + m_errorMonitor->VerifyFound(); +} \ No newline at end of file