From bfa2ad4da2cb80365fa1afdacc720864715caf7a Mon Sep 17 00:00:00 2001 From: spencer-lunarg Date: Fri, 19 Jul 2024 16:04:14 -0400 Subject: [PATCH] layers: Add VK_EXT_depth_clamp_control --- layers/core_checks/cc_cmd_buffer_dynamic.cpp | 15 ++++++ layers/core_checks/core_validation.h | 3 ++ layers/drawdispatch/drawdispatch_vuids.cpp | 15 ++++++ layers/drawdispatch/drawdispatch_vuids.h | 1 + layers/state_tracker/cmd_buffer_state.h | 2 + layers/state_tracker/pipeline_state.cpp | 13 +++++ layers/state_tracker/pipeline_state.h | 1 + layers/state_tracker/state_tracker.cpp | 9 ++++ layers/state_tracker/state_tracker.h | 3 ++ layers/stateless/sl_cmd_buffer_dynamic.cpp | 16 ++++++ layers/stateless/sl_pipeline.cpp | 40 +++++++++++++++ layers/stateless/stateless_validation.h | 4 ++ .../vulkan/generated/dynamic_state_helper.cpp | 10 ++++ .../generated/stateless_validation_helper.cpp | 1 + scripts/generators/dynamic_state_generator.py | 11 ++++ .../stateless_validation_helper_generator.py | 1 + tests/device_profiles/max_profile.json | 4 ++ tests/unit/dynamic_state.cpp | 36 +++++++++++++ tests/unit/dynamic_state_positive.cpp | 38 +++++++++++--- tests/unit/pipeline.cpp | 51 +++++++++++++++++++ tests/unit/pipeline_positive.cpp | 46 +++++++++++++++++ 21 files changed, 312 insertions(+), 8 deletions(-) diff --git a/layers/core_checks/cc_cmd_buffer_dynamic.cpp b/layers/core_checks/cc_cmd_buffer_dynamic.cpp index e05534c91dd..bcf307f3e0e 100644 --- a/layers/core_checks/cc_cmd_buffer_dynamic.cpp +++ b/layers/core_checks/cc_cmd_buffer_dynamic.cpp @@ -122,6 +122,9 @@ bool CoreChecks::ValidateDynamicStateIsSet(const LastBound& last_bound_state, co case CB_DYNAMIC_STATE_DEPTH_CLIP_NEGATIVE_ONE_TO_ONE_EXT: vuid_str = vuid.dynamic_depth_clip_negative_one_to_one_07639; break; + case CB_DYNAMIC_STATE_DEPTH_CLAMP_RANGE_EXT: + vuid_str = vuid.dynamic_depth_clamp_control_09650; + break; case CB_DYNAMIC_STATE_DEPTH_CLIP_ENABLE_EXT: vuid_str = vuid.dynamic_depth_clip_enable_07633; break; @@ -279,6 +282,11 @@ bool CoreChecks::ValidateGraphicsDynamicStateSetStatus(const LastBound& last_bou skip |= ValidateDynamicStateIsSet(last_bound_state, state_status_cb, CB_DYNAMIC_STATE_DEPTH_CLIP_NEGATIVE_ONE_TO_ONE_EXT, vuid); } + if (enabled_features.depthClampControl) { + if (last_bound_state.IsDepthClampEnable()) { + skip |= ValidateDynamicStateIsSet(last_bound_state, state_status_cb, CB_DYNAMIC_STATE_DEPTH_CLAMP_RANGE_EXT, vuid); + } + } if (enabled_features.depthClamp) { skip |= ValidateDynamicStateIsSet(last_bound_state, state_status_cb, CB_DYNAMIC_STATE_DEPTH_CLAMP_ENABLE_EXT, vuid); } @@ -2267,6 +2275,13 @@ bool CoreChecks::PreCallValidateCmdSetDepthClampEnableEXT(VkCommandBuffer comman return skip; } +bool CoreChecks::PreCallValidateCmdSetDepthClampRangeEXT(VkCommandBuffer commandBuffer, VkDepthClampModeEXT depthClampMode, + const VkDepthClampRangeEXT* pDepthClampRange, + const ErrorObject& error_obj) const { + auto cb_state = GetRead(commandBuffer); + return ValidateCmd(*cb_state, error_obj.location); +} + bool CoreChecks::PreCallValidateCmdSetPolygonModeEXT(VkCommandBuffer commandBuffer, VkPolygonMode polygonMode, const ErrorObject& error_obj) const { auto cb_state = GetRead(commandBuffer); diff --git a/layers/core_checks/core_validation.h b/layers/core_checks/core_validation.h index e3e33fb46d9..f3f0f5d027d 100644 --- a/layers/core_checks/core_validation.h +++ b/layers/core_checks/core_validation.h @@ -2283,6 +2283,9 @@ class CoreChecks : public ValidationStateTracker { const ErrorObject& error_obj) const override; bool PreCallValidateCmdSetDepthClampEnableEXT(VkCommandBuffer commandBuffer, VkBool32 depthClampEnable, const ErrorObject& error_obj) const override; + bool PreCallValidateCmdSetDepthClampRangeEXT(VkCommandBuffer commandBuffer, VkDepthClampModeEXT depthClampMode, + const VkDepthClampRangeEXT* pDepthClampRange, + const ErrorObject& error_obj) const override; bool PreCallValidateCmdSetPolygonModeEXT(VkCommandBuffer commandBuffer, VkPolygonMode polygonMode, const ErrorObject& error_obj) const override; bool PreCallValidateCmdSetRasterizationSamplesEXT(VkCommandBuffer commandBuffer, VkSampleCountFlagBits rasterizationSamples, diff --git a/layers/drawdispatch/drawdispatch_vuids.cpp b/layers/drawdispatch/drawdispatch_vuids.cpp index 8d12b196c06..cc4838ca92a 100644 --- a/layers/drawdispatch/drawdispatch_vuids.cpp +++ b/layers/drawdispatch/drawdispatch_vuids.cpp @@ -153,6 +153,7 @@ struct DispatchVuidsCmdDraw : DrawDispatchVuid { dynamic_shading_rate_image_enable_07647 = "VUID-vkCmdDraw-None-07647"; dynamic_representative_fragment_test_enable_07648 = "VUID-vkCmdDraw-None-07648"; dynamic_coverage_reduction_mode_07649 = "VUID-vkCmdDraw-None-07649"; + dynamic_depth_clamp_control_09650 = "VUID-vkCmdDraw-None-09650"; dynamic_viewport_07831 = "VUID-vkCmdDraw-None-07831"; dynamic_scissor_07832 = "VUID-vkCmdDraw-None-07832"; dynamic_depth_bias_07834 = "VUID-vkCmdDraw-None-07834"; @@ -423,6 +424,7 @@ struct DispatchVuidsCmdDrawMultiEXT : DrawDispatchVuid { dynamic_shading_rate_image_enable_07647 = "VUID-vkCmdDrawMultiEXT-None-07647"; dynamic_representative_fragment_test_enable_07648 = "VUID-vkCmdDrawMultiEXT-None-07648"; dynamic_coverage_reduction_mode_07649 = "VUID-vkCmdDrawMultiEXT-None-07649"; + dynamic_depth_clamp_control_09650 = "VUID-vkCmdDrawMultiEXT-None-09650"; dynamic_viewport_07831 = "VUID-vkCmdDrawMultiEXT-None-07831"; dynamic_scissor_07832 = "VUID-vkCmdDrawMultiEXT-None-07832"; dynamic_depth_bias_07834 = "VUID-vkCmdDrawMultiEXT-None-07834"; @@ -694,6 +696,7 @@ struct DispatchVuidsCmdDrawIndexed : DrawDispatchVuid { dynamic_shading_rate_image_enable_07647 = "VUID-vkCmdDrawIndexed-None-07647"; dynamic_representative_fragment_test_enable_07648 = "VUID-vkCmdDrawIndexed-None-07648"; dynamic_coverage_reduction_mode_07649 = "VUID-vkCmdDrawIndexed-None-07649"; + dynamic_depth_clamp_control_09650 = "VUID-vkCmdDrawIndexed-None-09650"; dynamic_viewport_07831 = "VUID-vkCmdDrawIndexed-None-07831"; dynamic_scissor_07832 = "VUID-vkCmdDrawIndexed-None-07832"; dynamic_depth_bias_07834 = "VUID-vkCmdDrawIndexed-None-07834"; @@ -965,6 +968,7 @@ struct DispatchVuidsCmdDrawMultiIndexedEXT : DrawDispatchVuid { dynamic_shading_rate_image_enable_07647 = "VUID-vkCmdDrawMultiIndexedEXT-None-07647"; dynamic_representative_fragment_test_enable_07648 = "VUID-vkCmdDrawMultiIndexedEXT-None-07648"; dynamic_coverage_reduction_mode_07649 = "VUID-vkCmdDrawMultiIndexedEXT-None-07649"; + dynamic_depth_clamp_control_09650 = "VUID-vkCmdDrawMultiIndexedEXT-None-09650"; dynamic_viewport_07831 = "VUID-vkCmdDrawMultiIndexedEXT-None-07831"; dynamic_scissor_07832 = "VUID-vkCmdDrawMultiIndexedEXT-None-07832"; dynamic_depth_bias_07834 = "VUID-vkCmdDrawMultiIndexedEXT-None-07834"; @@ -1236,6 +1240,7 @@ struct DispatchVuidsCmdDrawIndirect : DrawDispatchVuid { dynamic_shading_rate_image_enable_07647 = "VUID-vkCmdDrawIndirect-None-07647"; dynamic_representative_fragment_test_enable_07648 = "VUID-vkCmdDrawIndirect-None-07648"; dynamic_coverage_reduction_mode_07649 = "VUID-vkCmdDrawIndirect-None-07649"; + dynamic_depth_clamp_control_09650 = "VUID-vkCmdDrawIndirect-None-09650"; dynamic_viewport_07831 = "VUID-vkCmdDrawIndirect-None-07831"; dynamic_scissor_07832 = "VUID-vkCmdDrawIndirect-None-07832"; dynamic_depth_bias_07834 = "VUID-vkCmdDrawIndirect-None-07834"; @@ -1506,6 +1511,7 @@ struct DispatchVuidsCmdDrawIndexedIndirect : DrawDispatchVuid { dynamic_shading_rate_image_enable_07647 = "VUID-vkCmdDrawIndexedIndirect-None-07647"; dynamic_representative_fragment_test_enable_07648 = "VUID-vkCmdDrawIndexedIndirect-None-07648"; dynamic_coverage_reduction_mode_07649 = "VUID-vkCmdDrawIndexedIndirect-None-07649"; + dynamic_depth_clamp_control_09650 = "VUID-vkCmdDrawIndexedIndirect-None-09650"; dynamic_viewport_07831 = "VUID-vkCmdDrawIndexedIndirect-None-07831"; dynamic_scissor_07832 = "VUID-vkCmdDrawIndexedIndirect-None-07832"; dynamic_depth_bias_07834 = "VUID-vkCmdDrawIndexedIndirect-None-07834"; @@ -1875,6 +1881,7 @@ struct DispatchVuidsCmdDrawIndirectCount : DrawDispatchVuid { dynamic_shading_rate_image_enable_07647 = "VUID-vkCmdDrawIndirectCount-None-07647"; dynamic_representative_fragment_test_enable_07648 = "VUID-vkCmdDrawIndirectCount-None-07648"; dynamic_coverage_reduction_mode_07649 = "VUID-vkCmdDrawIndirectCount-None-07649"; + dynamic_depth_clamp_control_09650 = "VUID-vkCmdDrawIndirectCount-None-09650"; dynamic_viewport_07831 = "VUID-vkCmdDrawIndirectCount-None-07831"; dynamic_scissor_07832 = "VUID-vkCmdDrawIndirectCount-None-07832"; dynamic_depth_bias_07834 = "VUID-vkCmdDrawIndirectCount-None-07834"; @@ -2148,6 +2155,7 @@ struct DispatchVuidsCmdDrawIndexedIndirectCount : DrawDispatchVuid { dynamic_shading_rate_image_enable_07647 = "VUID-vkCmdDrawIndexedIndirectCount-None-07647"; dynamic_representative_fragment_test_enable_07648 = "VUID-vkCmdDrawIndexedIndirectCount-None-07648"; dynamic_coverage_reduction_mode_07649 = "VUID-vkCmdDrawIndexedIndirectCount-None-07649"; + dynamic_depth_clamp_control_09650 = "VUID-vkCmdDrawIndexedIndirectCount-None-09650"; dynamic_viewport_07831 = "VUID-vkCmdDrawIndexedIndirectCount-None-07831"; dynamic_scissor_07832 = "VUID-vkCmdDrawIndexedIndirectCount-None-07832"; dynamic_depth_bias_07834 = "VUID-vkCmdDrawIndexedIndirectCount-None-07834"; @@ -2600,6 +2608,7 @@ struct DispatchVuidsCmdDrawMeshTasksNV: DrawDispatchVuid { dynamic_shading_rate_image_enable_07647 = "VUID-vkCmdDrawMeshTasksNV-None-07647"; dynamic_representative_fragment_test_enable_07648 = "VUID-vkCmdDrawMeshTasksNV-None-07648"; dynamic_coverage_reduction_mode_07649 = "VUID-vkCmdDrawMeshTasksNV-None-07649"; + dynamic_depth_clamp_control_09650 = "VUID-vkCmdDrawMeshTasksNV-None-09650"; dynamic_viewport_07831 = "VUID-vkCmdDrawMeshTasksNV-None-07831"; dynamic_scissor_07832 = "VUID-vkCmdDrawMeshTasksNV-None-07832"; dynamic_depth_bias_07834 = "VUID-vkCmdDrawMeshTasksNV-None-07834"; @@ -2856,6 +2865,7 @@ struct DispatchVuidsCmdDrawMeshTasksIndirectNV: DrawDispatchVuid { dynamic_shading_rate_image_enable_07647 = "VUID-vkCmdDrawMeshTasksIndirectNV-None-07647"; dynamic_representative_fragment_test_enable_07648 = "VUID-vkCmdDrawMeshTasksIndirectNV-None-07648"; dynamic_coverage_reduction_mode_07649 = "VUID-vkCmdDrawMeshTasksIndirectNV-None-07649"; + dynamic_depth_clamp_control_09650 = "VUID-vkCmdDrawMeshTasksIndirectNV-None-09650"; dynamic_viewport_07831 = "VUID-vkCmdDrawMeshTasksIndirectNV-None-07831"; dynamic_scissor_07832 = "VUID-vkCmdDrawMeshTasksIndirectNV-None-07832"; dynamic_depth_bias_07834 = "VUID-vkCmdDrawMeshTasksIndirectNV-None-07834"; @@ -3115,6 +3125,7 @@ struct DispatchVuidsCmdDrawMeshTasksIndirectCountNV : DrawDispatchVuid { dynamic_shading_rate_image_enable_07647 = "VUID-vkCmdDrawMeshTasksIndirectCountNV-None-07647"; dynamic_representative_fragment_test_enable_07648 = "VUID-vkCmdDrawMeshTasksIndirectCountNV-None-07648"; dynamic_coverage_reduction_mode_07649 = "VUID-vkCmdDrawMeshTasksIndirectCountNV-None-07649"; + dynamic_depth_clamp_control_09650 = "VUID-vkCmdDrawMeshTasksIndirectCountNV-None-09650"; dynamic_viewport_07831 = "VUID-vkCmdDrawMeshTasksIndirectCountNV-None-07831"; dynamic_scissor_07832 = "VUID-vkCmdDrawMeshTasksIndirectCountNV-None-07832"; dynamic_depth_bias_07834 = "VUID-vkCmdDrawMeshTasksIndirectCountNV-None-07834"; @@ -3368,6 +3379,7 @@ struct DispatchVuidsCmdDrawMeshTasksEXT: DrawDispatchVuid { dynamic_shading_rate_image_enable_07647 = "VUID-vkCmdDrawMeshTasksEXT-None-07647"; dynamic_representative_fragment_test_enable_07648 = "VUID-vkCmdDrawMeshTasksEXT-None-07648"; dynamic_coverage_reduction_mode_07649 = "VUID-vkCmdDrawMeshTasksEXT-None-07649"; + dynamic_depth_clamp_control_09650 = "VUID-vkCmdDrawMeshTasksEXT-None-09650"; dynamic_viewport_07831 = "VUID-vkCmdDrawMeshTasksEXT-None-07831"; dynamic_scissor_07832 = "VUID-vkCmdDrawMeshTasksEXT-None-07832"; dynamic_depth_bias_07834 = "VUID-vkCmdDrawMeshTasksEXT-None-07834"; @@ -3624,6 +3636,7 @@ struct DispatchVuidsCmdDrawMeshTasksIndirectEXT: DrawDispatchVuid { dynamic_shading_rate_image_enable_07647 = "VUID-vkCmdDrawMeshTasksIndirectEXT-None-07647"; dynamic_representative_fragment_test_enable_07648 = "VUID-vkCmdDrawMeshTasksIndirectEXT-None-07648"; dynamic_coverage_reduction_mode_07649 = "VUID-vkCmdDrawMeshTasksIndirectEXT-None-07649"; + dynamic_depth_clamp_control_09650 = "VUID-vkCmdDraw-None-09650"; dynamic_viewport_07831 = "VUID-vkCmdDrawMeshTasksIndirectEXT-None-07831"; dynamic_scissor_07832 = "VUID-vkCmdDrawMeshTasksIndirectEXT-None-07832"; dynamic_depth_bias_07834 = "VUID-vkCmdDrawMeshTasksIndirectEXT-None-07834"; @@ -3883,6 +3896,7 @@ struct DispatchVuidsCmdDrawMeshTasksIndirectCountEXT : DrawDispatchVuid { dynamic_shading_rate_image_enable_07647 = "VUID-vkCmdDrawMeshTasksIndirectCountEXT-None-07647"; dynamic_representative_fragment_test_enable_07648 = "VUID-vkCmdDrawMeshTasksIndirectCountEXT-None-07648"; dynamic_coverage_reduction_mode_07649 = "VUID-vkCmdDrawMeshTasksIndirectCountEXT-None-07649"; + dynamic_depth_clamp_control_09650 = "VUID-vkCmdDraw-None-09650"; dynamic_viewport_07831 = "VUID-vkCmdDrawMeshTasksIndirectCountEXT-None-07831"; dynamic_scissor_07832 = "VUID-vkCmdDrawMeshTasksIndirectCountEXT-None-07832"; dynamic_depth_bias_07834 = "VUID-vkCmdDrawMeshTasksIndirectCountEXT-None-07834"; @@ -4149,6 +4163,7 @@ struct DispatchVuidsCmdDrawIndirectByteCountEXT: DrawDispatchVuid { dynamic_shading_rate_image_enable_07647 = "VUID-vkCmdDrawIndirectByteCountEXT-None-07647"; dynamic_representative_fragment_test_enable_07648 = "VUID-vkCmdDrawIndirectByteCountEXT-None-07648"; dynamic_coverage_reduction_mode_07649 = "VUID-vkCmdDrawIndirectByteCountEXT-None-07649"; + dynamic_depth_clamp_control_09650 = "VUID-vkCmdDraw-None-09650"; dynamic_viewport_07831 = "VUID-vkCmdDrawIndirectByteCountEXT-None-07831"; dynamic_scissor_07832 = "VUID-vkCmdDrawIndirectByteCountEXT-None-07832"; dynamic_depth_bias_07834 = "VUID-vkCmdDrawIndirectByteCountEXT-None-07834"; diff --git a/layers/drawdispatch/drawdispatch_vuids.h b/layers/drawdispatch/drawdispatch_vuids.h index 63e28a685c7..f2668c03f71 100644 --- a/layers/drawdispatch/drawdispatch_vuids.h +++ b/layers/drawdispatch/drawdispatch_vuids.h @@ -170,6 +170,7 @@ struct DrawDispatchVuid { const char* dynamic_shading_rate_image_enable_07647 = kVUIDUndefined; const char* dynamic_representative_fragment_test_enable_07648 = kVUIDUndefined; const char* dynamic_coverage_reduction_mode_07649 = kVUIDUndefined; + const char* dynamic_depth_clamp_control_09650 = kVUIDUndefined; const char* dynamic_viewport_07831 = kVUIDUndefined; const char* dynamic_scissor_07832 = kVUIDUndefined; const char* dynamic_depth_bias_07834 = kVUIDUndefined; diff --git a/layers/state_tracker/cmd_buffer_state.h b/layers/state_tracker/cmd_buffer_state.h index 09300c6db08..a514ff5525b 100644 --- a/layers/state_tracker/cmd_buffer_state.h +++ b/layers/state_tracker/cmd_buffer_state.h @@ -262,6 +262,8 @@ class CommandBuffer : public RefcountedStateObject { bool rasterizer_discard_enable; // VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE bool depth_bias_enable = false; + // VK_DYNAMIC_STATE_DEPTH_CLAMP_ENABLE_EXT + bool depth_clamp_enable = false; // VK_DYNAMIC_STATE_ALPHA_TO_COVERAGE_ENABLE_EXT bool alpha_to_coverage_enable; // VK_DYNAMIC_STATE_LOGIC_OP_ENABLE_EXT diff --git a/layers/state_tracker/pipeline_state.cpp b/layers/state_tracker/pipeline_state.cpp index 83de3ca9609..a1d74d17b99 100644 --- a/layers/state_tracker/pipeline_state.cpp +++ b/layers/state_tracker/pipeline_state.cpp @@ -899,6 +899,19 @@ bool LastBound::IsDepthBiasEnable() const { return false; } +bool LastBound::IsDepthClampEnable() const { + if (!pipeline_state || pipeline_state->IsDynamic(CB_DYNAMIC_STATE_DEPTH_CLAMP_ENABLE_EXT)) { + if (cb_state.IsDynamicStateSet(CB_DYNAMIC_STATE_DEPTH_CLAMP_ENABLE_EXT)) { + return cb_state.dynamic_state_value.depth_clamp_enable; + } + } else { + if (pipeline_state->RasterizationState()) { + return pipeline_state->RasterizationState()->depthClampEnable; + } + } + return false; +} + bool LastBound::IsStencilTestEnable() const { if (!pipeline_state || pipeline_state->IsDynamic(CB_DYNAMIC_STATE_STENCIL_TEST_ENABLE)) { if (cb_state.IsDynamicStateSet(CB_DYNAMIC_STATE_STENCIL_TEST_ENABLE)) { diff --git a/layers/state_tracker/pipeline_state.h b/layers/state_tracker/pipeline_state.h index be6bd282834..eecae08c52b 100644 --- a/layers/state_tracker/pipeline_state.h +++ b/layers/state_tracker/pipeline_state.h @@ -709,6 +709,7 @@ struct LastBound { bool IsDepthBoundTestEnable() const; bool IsDepthWriteEnable() const; bool IsDepthBiasEnable() const; + bool IsDepthClampEnable() const; bool IsStencilTestEnable() const; VkStencilOpState GetStencilOpStateFront() const; VkStencilOpState GetStencilOpStateBack() const; diff --git a/layers/state_tracker/state_tracker.cpp b/layers/state_tracker/state_tracker.cpp index a88b4c14915..2bd913ae7b8 100644 --- a/layers/state_tracker/state_tracker.cpp +++ b/layers/state_tracker/state_tracker.cpp @@ -5335,6 +5335,15 @@ void ValidationStateTracker::PostCallRecordCmdSetDepthClampEnableEXT(VkCommandBu const RecordObject &record_obj) { auto cb_state = GetWrite(commandBuffer); cb_state->RecordStateCmd(record_obj.location.function, CB_DYNAMIC_STATE_DEPTH_CLAMP_ENABLE_EXT); + cb_state->dynamic_state_value.depth_clamp_enable = depthClampEnable; +} + +void ValidationStateTracker::PostCallRecordCmdSetDepthClampRangeEXT(VkCommandBuffer commandBuffer, + VkDepthClampModeEXT depthClampMode, + const VkDepthClampRangeEXT *pDepthClampRange, + const RecordObject &record_obj) { + auto cb_state = GetWrite(commandBuffer); + cb_state->RecordStateCmd(record_obj.location.function, CB_DYNAMIC_STATE_DEPTH_CLAMP_RANGE_EXT); } void ValidationStateTracker::PostCallRecordCmdSetPolygonModeEXT(VkCommandBuffer commandBuffer, VkPolygonMode polygonMode, diff --git a/layers/state_tracker/state_tracker.h b/layers/state_tracker/state_tracker.h index 818ad47cacb..5896c66fa37 100644 --- a/layers/state_tracker/state_tracker.h +++ b/layers/state_tracker/state_tracker.h @@ -1301,6 +1301,9 @@ class ValidationStateTracker : public ValidationObject { const RecordObject& record_obj) override; void PostCallRecordCmdSetDepthClampEnableEXT(VkCommandBuffer commandBuffer, VkBool32 depthClampEnable, const RecordObject& record_obj) override; + void PostCallRecordCmdSetDepthClampRangeEXT(VkCommandBuffer commandBuffer, VkDepthClampModeEXT depthClampMode, + const VkDepthClampRangeEXT* pDepthClampRange, + const RecordObject& record_obj) override; void PostCallRecordCmdSetPolygonModeEXT(VkCommandBuffer commandBuffer, VkPolygonMode polygonMode, const RecordObject& record_obj) override; void PostCallRecordCmdSetRasterizationSamplesEXT(VkCommandBuffer commandBuffer, VkSampleCountFlagBits rasterizationSamples, diff --git a/layers/stateless/sl_cmd_buffer_dynamic.cpp b/layers/stateless/sl_cmd_buffer_dynamic.cpp index f4a226ce932..afa0029c156 100644 --- a/layers/stateless/sl_cmd_buffer_dynamic.cpp +++ b/layers/stateless/sl_cmd_buffer_dynamic.cpp @@ -498,6 +498,22 @@ bool StatelessValidation::manual_PreCallValidateCmdSetViewport(VkCommandBuffer c return skip; } +bool StatelessValidation::manual_PreCallValidateCmdSetDepthClampRangeEXT(VkCommandBuffer commandBuffer, + VkDepthClampModeEXT depthClampMode, + const VkDepthClampRangeEXT *pDepthClampRange, + const ErrorObject &error_obj) const { + bool skip = false; + if (depthClampMode == VK_DEPTH_CLAMP_MODE_USER_DEFINED_RANGE_EXT) { + if (!pDepthClampRange) { + skip |= LogError("VUID-vkCmdSetDepthClampRangeEXT-pDepthClampRange-09647", device, + error_obj.location.dot(Field::pDepthClampRange), "is NULL."); + } else { + skip |= ValidateDepthClampRange(*pDepthClampRange, error_obj.location.dot(Field::pDepthClampRange)); + } + } + return skip; +} + bool StatelessValidation::manual_PreCallValidateCmdSetScissor(VkCommandBuffer commandBuffer, uint32_t firstScissor, uint32_t scissorCount, const VkRect2D *pScissors, const ErrorObject &error_obj) const { diff --git a/layers/stateless/sl_pipeline.cpp b/layers/stateless/sl_pipeline.cpp index 7feee10ee79..0e9d2c140f3 100644 --- a/layers/stateless/sl_pipeline.cpp +++ b/layers/stateless/sl_pipeline.cpp @@ -694,6 +694,8 @@ bool StatelessValidation::manual_PreCallValidateCreateGraphicsPipelines( vku::FindStructInPNextChain(viewport_state.pNext); const auto *depth_clip_control_struct = vku::FindStructInPNextChain(viewport_state.pNext); + const auto *depth_clamp_control_struct = + vku::FindStructInPNextChain(viewport_state.pNext); if (!enabled_features.multiViewport) { if (exclusive_scissor_struct && (exclusive_scissor_struct->exclusiveScissorCount != 0 && @@ -933,6 +935,21 @@ bool StatelessValidation::manual_PreCallValidateCreateGraphicsPipelines( } } + const bool has_dynamic_depth_clamp_range = vvl::Contains(dynamic_state_map, VK_DYNAMIC_STATE_DEPTH_CLAMP_RANGE_EXT); + if (!has_dynamic_depth_clamp_range && depth_clamp_control_struct && + depth_clamp_control_struct->depthClampMode == VK_DEPTH_CLAMP_MODE_USER_DEFINED_RANGE_EXT) { + if (!depth_clamp_control_struct->pDepthClampRange) { + skip |= LogError( + "VUID-VkPipelineViewportDepthClampControlCreateInfoEXT-pDepthClampRange-09646", device, + viewport_loc.pNext(Struct::VkPipelineViewportDepthClampControlCreateInfoEXT, Field::pDepthClampRange), + "is NULL."); + } else { + skip |= ValidateDepthClampRange( + *depth_clamp_control_struct->pDepthClampRange, + viewport_loc.pNext(Struct::VkPipelineViewportDepthClampControlCreateInfoEXT, Field::pDepthClampRange)); + } + } + if (depth_clip_control_struct) { if (depth_clip_control_struct->negativeOneToOne && !enabled_features.depthClipControl) { skip |= LogError( @@ -1315,6 +1332,29 @@ bool StatelessValidation::manual_PreCallValidateCreateComputePipelines(VkDevice return skip; } +bool StatelessValidation::ValidateDepthClampRange(const VkDepthClampRangeEXT &depth_clamp_range, const Location &loc) const { + bool skip = false; + if (depth_clamp_range.minDepthClamp > depth_clamp_range.maxDepthClamp) { + skip |= + LogError("VUID-VkDepthClampRangeEXT-pDepthClampRange-00999", device, loc.dot(Field::minDepthClamp), + "(%f) is greater than maxDepthClamp (%f).", depth_clamp_range.minDepthClamp, depth_clamp_range.maxDepthClamp); + } + + if (!IsExtEnabled(device_extensions.vk_ext_depth_range_unrestricted)) { + if (depth_clamp_range.minDepthClamp < 0.0) { + skip |= LogError("VUID-VkDepthClampRangeEXT-pDepthClampRange-09648", device, loc.dot(Field::minDepth), + "(%f) is below 0.0 (and VK_EXT_depth_range_unrestricted is not enabled).", + depth_clamp_range.minDepthClamp); + } + if (depth_clamp_range.maxDepthClamp > 1.0) { + skip |= LogError("VUID-VkDepthClampRangeEXT-pDepthClampRange-09649", device, loc.dot(Field::maxDepthClamp), + "(%f) is above 1.0 (and VK_EXT_depth_range_unrestricted is not enabled).", + depth_clamp_range.maxDepthClamp); + } + } + return skip; +} + bool StatelessValidation::manual_PreCallValidateMergePipelineCaches(VkDevice device, VkPipelineCache dstCache, uint32_t srcCacheCount, const VkPipelineCache *pSrcCaches, const ErrorObject &error_obj) const { diff --git a/layers/stateless/stateless_validation.h b/layers/stateless/stateless_validation.h index 10b2bff4036..f31552a5bf8 100644 --- a/layers/stateless/stateless_validation.h +++ b/layers/stateless/stateless_validation.h @@ -826,6 +826,9 @@ class StatelessValidation : public ValidationObject { bool manual_PreCallValidateCmdSetViewportWScalingNV(VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewportWScalingNV *pViewportWScalings, const ErrorObject &error_obj) const; + bool manual_PreCallValidateCmdSetDepthClampRangeEXT(VkCommandBuffer commandBuffer, VkDepthClampModeEXT depthClampMode, + const VkDepthClampRangeEXT *pDepthClampRange, + const ErrorObject &error_obj) const; bool manual_PreCallValidateCreateShadersEXT(VkDevice device, uint32_t createInfoCount, const VkShaderCreateInfoEXT *pCreateInfos, const VkAllocationCallbacks *pAllocator, @@ -1085,6 +1088,7 @@ class StatelessValidation : public ValidationObject { VkBaseOutStructure *pPipelineProperties, const ErrorObject &error_obj) const; + bool ValidateDepthClampRange(const VkDepthClampRangeEXT &depth_clamp_range, const Location &loc) const; bool manual_PreCallValidateCmdClearColorImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout, const VkClearColorValue *pColor, uint32_t rangeCount, const VkImageSubresourceRange *pRanges, const ErrorObject &error_obj) const; diff --git a/layers/vulkan/generated/dynamic_state_helper.cpp b/layers/vulkan/generated/dynamic_state_helper.cpp index 166c7e1e539..5ae14e23aad 100644 --- a/layers/vulkan/generated/dynamic_state_helper.cpp +++ b/layers/vulkan/generated/dynamic_state_helper.cpp @@ -584,6 +584,9 @@ std::string DescribeDynamicStateCommand(CBDynamicState dynamic_state) { case CB_DYNAMIC_STATE_RAY_TRACING_PIPELINE_STACK_SIZE_KHR: func = vvl::Func::vkCmdSetRayTracingPipelineStackSizeKHR; break; + case CB_DYNAMIC_STATE_DEPTH_CLAMP_RANGE_EXT: + func = vvl::Func::vkCmdSetDepthClampRangeEXT; + break; default: ss << "(Unknown Dynamic State) "; } @@ -895,6 +898,13 @@ std::string DescribeDynamicStateDependency(CBDynamicState dynamic_state, const v "coverageModulationTableEnable was VK_TRUE in the last bound graphics pipeline.\n"; } break; + case CB_DYNAMIC_STATE_DEPTH_CLAMP_RANGE_EXT: + if (!pipeline || pipeline->IsDynamic(CB_DYNAMIC_STATE_DEPTH_CLAMP_ENABLE_EXT)) { + ss << "vkCmdSetDepthClampEnableEXT last set depthClampEnable to VK_TRUE.\n"; + } else { + ss << "VkPipelineRasterizationStateCreateInfo::depthClampEnable was VK_TRUE in the last bound graphics pipeline.\n"; + } + break; default: break; // not all state will be dependent on other state } diff --git a/layers/vulkan/generated/stateless_validation_helper.cpp b/layers/vulkan/generated/stateless_validation_helper.cpp index 4b10d68575b..31c39c41324 100644 --- a/layers/vulkan/generated/stateless_validation_helper.cpp +++ b/layers/vulkan/generated/stateless_validation_helper.cpp @@ -25955,6 +25955,7 @@ bool StatelessValidation::PreCallValidateCmdSetDepthClampRangeEXT(VkCommandBuffe [[maybe_unused]] const Location pDepthClampRange_loc = loc.dot(Field::pDepthClampRange); // No xml-driven validation } + if (!skip) skip |= manual_PreCallValidateCmdSetDepthClampRangeEXT(commandBuffer, depthClampMode, pDepthClampRange, error_obj); return skip; } diff --git a/scripts/generators/dynamic_state_generator.py b/scripts/generators/dynamic_state_generator.py index 8249f8efe33..0f5a599ddf3 100644 --- a/scripts/generators/dynamic_state_generator.py +++ b/scripts/generators/dynamic_state_generator.py @@ -268,6 +268,10 @@ "VK_DYNAMIC_STATE_RAY_TRACING_PIPELINE_STACK_SIZE_KHR" : { "command" : ["vkCmdSetRayTracingPipelineStackSizeKHR"], }, + "VK_DYNAMIC_STATE_DEPTH_CLAMP_RANGE_EXT" : { + "command" : ["vkCmdSetDepthClampRangeEXT"], + "dependency" : ["depthClampEnable"] + }, } # @@ -494,6 +498,13 @@ def generateSource(self): } else { ss << "VkPipelineRasterizationStateCreateInfo::depthTestEnable was VK_TRUE in the last bound graphics pipeline.\\n"; }''') + if 'depthClampEnable' in dependency: + out.append(''' + if (!pipeline || pipeline->IsDynamic(CB_DYNAMIC_STATE_DEPTH_CLAMP_ENABLE_EXT)) { + ss << "vkCmdSetDepthClampEnableEXT last set depthClampEnable to VK_TRUE.\\n"; + } else { + ss << "VkPipelineRasterizationStateCreateInfo::depthClampEnable was VK_TRUE in the last bound graphics pipeline.\\n"; + }''') if 'logicOpEnable' in dependency: out.append(''' if (!pipeline || pipeline->IsDynamic(CB_DYNAMIC_STATE_LOGIC_OP_ENABLE_EXT)) { diff --git a/scripts/generators/stateless_validation_helper_generator.py b/scripts/generators/stateless_validation_helper_generator.py index 68c45fb3e24..03ff9de7867 100644 --- a/scripts/generators/stateless_validation_helper_generator.py +++ b/scripts/generators/stateless_validation_helper_generator.py @@ -118,6 +118,7 @@ def __init__(self, 'vkSetDebugUtilsObjectNameEXT', 'vkSetDebugUtilsObjectTagEXT', 'vkCmdSetViewportWScalingNV', + 'vkCmdSetDepthClampRangeEXT', 'vkAcquireNextImageKHR', 'vkAcquireNextImage2KHR', 'vkCmdBindTransformFeedbackBuffersEXT', diff --git a/tests/device_profiles/max_profile.json b/tests/device_profiles/max_profile.json index 6226cff0804..af49123bef7 100644 --- a/tests/device_profiles/max_profile.json +++ b/tests/device_profiles/max_profile.json @@ -791,6 +791,9 @@ "VkPhysicalDeviceDepthClampZeroOneFeaturesEXT": { "depthClampZeroOne": true }, + "VkPhysicalDeviceDepthClampControlFeaturesEXT": { + "depthClampControl": true + }, "VkPhysicalDeviceAddressBindingReportFeaturesEXT": { "reportAddressBinding": true }, @@ -1883,6 +1886,7 @@ "VK_EXT_debug_report": 1, "VK_EXT_debug_utils": 1, "VK_EXT_depth_bias_control": 1, + "VK_EXT_depth_clamp_control": 1, "VK_EXT_depth_clamp_zero_one": 1, "VK_EXT_depth_clip_control": 1, "VK_EXT_depth_clip_enable": 1, diff --git a/tests/unit/dynamic_state.cpp b/tests/unit/dynamic_state.cpp index 32e9d6b73f5..a6b01b1e0f7 100644 --- a/tests/unit/dynamic_state.cpp +++ b/tests/unit/dynamic_state.cpp @@ -6047,3 +6047,39 @@ TEST_F(NegativeDynamicState, DrawNotSetDepthCompareOp) { m_commandBuffer->EndRenderPass(); m_commandBuffer->end(); } + +TEST_F(NegativeDynamicState, DepthClampControl) { + AddRequiredExtensions(VK_EXT_DEPTH_CLAMP_CONTROL_EXTENSION_NAME); + AddRequiredFeature(vkt::Feature::depthClampControl); + RETURN_IF_SKIP(Init()); + InitRenderTarget(); + + CreatePipelineHelper pipe(*this); + pipe.AddDynamicState(VK_DYNAMIC_STATE_DEPTH_CLAMP_RANGE_EXT); + pipe.rs_state_ci_.depthClampEnable = VK_TRUE; + pipe.CreateGraphicsPipeline(); + + m_command_buffer.begin(); + m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); + vk::CmdBindPipeline(m_command_buffer.handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.Handle()); + m_errorMonitor->SetDesiredError("VUID-vkCmdDraw-None-09650"); + vk::CmdDraw(m_command_buffer.handle(), 3u, 1u, 0u, 0u); + m_errorMonitor->VerifyFound(); + m_command_buffer.EndRenderPass(); + m_command_buffer.end(); +} + +TEST_F(NegativeDynamicState, DepthClampControlNullStruct) { + AddRequiredExtensions(VK_EXT_DEPTH_CLAMP_CONTROL_EXTENSION_NAME); + AddRequiredFeature(vkt::Feature::depthClampControl); + RETURN_IF_SKIP(Init()); + InitRenderTarget(); + + m_command_buffer.begin(); + m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); + m_errorMonitor->SetDesiredError("VUID-vkCmdSetDepthClampRangeEXT-pDepthClampRange-09647"); + vk::CmdSetDepthClampRangeEXT(m_command_buffer.handle(), VK_DEPTH_CLAMP_MODE_USER_DEFINED_RANGE_EXT, nullptr); + m_errorMonitor->VerifyFound(); + m_command_buffer.EndRenderPass(); + m_command_buffer.end(); +} \ No newline at end of file diff --git a/tests/unit/dynamic_state_positive.cpp b/tests/unit/dynamic_state_positive.cpp index 21409ba957f..b6e376d76eb 100644 --- a/tests/unit/dynamic_state_positive.cpp +++ b/tests/unit/dynamic_state_positive.cpp @@ -1367,12 +1367,34 @@ TEST_F(PositiveDynamicState, DynamicSampleLocationsRasterizationSamplesMismatch) pipe.AddDynamicState(VK_DYNAMIC_STATE_RASTERIZATION_SAMPLES_EXT); pipe.CreateGraphicsPipeline(); - m_commandBuffer->begin(); - m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo); - vk::CmdSetSampleLocationsEnableEXT(m_commandBuffer->handle(), VK_FALSE); - vk::CmdSetRasterizationSamplesEXT(m_commandBuffer->handle(), VK_SAMPLE_COUNT_1_BIT); - vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.Handle()); - vk::CmdDraw(m_commandBuffer->handle(), 3u, 1u, 0u, 0u); - m_commandBuffer->EndRenderPass(); - m_commandBuffer->end(); + m_command_buffer.begin(); + m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); + vk::CmdSetSampleLocationsEnableEXT(m_command_buffer.handle(), VK_FALSE); + vk::CmdSetRasterizationSamplesEXT(m_command_buffer.handle(), VK_SAMPLE_COUNT_1_BIT); + vk::CmdBindPipeline(m_command_buffer.handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.Handle()); + vk::CmdDraw(m_command_buffer.handle(), 3u, 1u, 0u, 0u); + m_command_buffer.EndRenderPass(); + m_command_buffer.end(); } + +TEST_F(PositiveDynamicState, DepthClampControl) { + AddRequiredExtensions(VK_EXT_DEPTH_CLAMP_CONTROL_EXTENSION_NAME); + AddRequiredFeature(vkt::Feature::depthClampControl); + RETURN_IF_SKIP(Init()); + InitRenderTarget(); + + CreatePipelineHelper pipe(*this); + pipe.AddDynamicState(VK_DYNAMIC_STATE_DEPTH_CLAMP_RANGE_EXT); + pipe.CreateGraphicsPipeline(); + + m_command_buffer.begin(); + m_command_buffer.BeginRenderPass(m_renderPassBeginInfo); + vk::CmdBindPipeline(m_command_buffer.handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.Handle()); + VkDepthClampRangeEXT clamp_range = {0.0f, 1.0f}; + vk::CmdSetDepthClampRangeEXT(m_command_buffer.handle(), VK_DEPTH_CLAMP_MODE_USER_DEFINED_RANGE_EXT, &clamp_range); + vk::CmdDraw(m_command_buffer.handle(), 3u, 1u, 0u, 0u); + vk::CmdSetDepthClampRangeEXT(m_command_buffer.handle(), VK_DEPTH_CLAMP_MODE_VIEWPORT_RANGE_EXT, nullptr); + vk::CmdDraw(m_command_buffer.handle(), 3u, 1u, 0u, 0u); + m_command_buffer.EndRenderPass(); + m_command_buffer.end(); +} \ No newline at end of file diff --git a/tests/unit/pipeline.cpp b/tests/unit/pipeline.cpp index 2ecc7df318e..212d9dedd1f 100644 --- a/tests/unit/pipeline.cpp +++ b/tests/unit/pipeline.cpp @@ -3649,3 +3649,54 @@ TEST_F(NegativePipeline, NoRasterizationStateDynamicRendering) { pipe.CreateGraphicsPipeline(); m_errorMonitor->VerifyFound(); } + +TEST_F(NegativePipeline, DepthClampControlMinMax) { + AddRequiredExtensions(VK_EXT_DEPTH_CLAMP_CONTROL_EXTENSION_NAME); + AddRequiredFeature(vkt::Feature::depthClampControl); + RETURN_IF_SKIP(Init()); + InitRenderTarget(); + + VkDepthClampRangeEXT clamp_range = {0.5f, 0.4f}; + VkPipelineViewportDepthClampControlCreateInfoEXT clamp_control = vku::InitStructHelper(); + clamp_control.depthClampMode = VK_DEPTH_CLAMP_MODE_USER_DEFINED_RANGE_EXT; + clamp_control.pDepthClampRange = &clamp_range; + CreatePipelineHelper pipe(*this); + pipe.vp_state_ci_.pNext = &clamp_control; + m_errorMonitor->SetDesiredError("VUID-VkDepthClampRangeEXT-pDepthClampRange-00999"); + pipe.CreateGraphicsPipeline(); + m_errorMonitor->VerifyFound(); +} + +TEST_F(NegativePipeline, DepthClampControlUnrestricted) { + AddRequiredExtensions(VK_EXT_DEPTH_CLAMP_CONTROL_EXTENSION_NAME); + AddRequiredFeature(vkt::Feature::depthClampControl); + RETURN_IF_SKIP(Init()); + InitRenderTarget(); + + VkDepthClampRangeEXT clamp_range = {-0.5f, 1.5f}; + VkPipelineViewportDepthClampControlCreateInfoEXT clamp_control = vku::InitStructHelper(); + clamp_control.depthClampMode = VK_DEPTH_CLAMP_MODE_USER_DEFINED_RANGE_EXT; + clamp_control.pDepthClampRange = &clamp_range; + CreatePipelineHelper pipe(*this); + pipe.vp_state_ci_.pNext = &clamp_control; + m_errorMonitor->SetDesiredError("VUID-VkDepthClampRangeEXT-pDepthClampRange-09648"); + m_errorMonitor->SetDesiredError("VUID-VkDepthClampRangeEXT-pDepthClampRange-09649"); + pipe.CreateGraphicsPipeline(); + m_errorMonitor->VerifyFound(); +} + +TEST_F(NegativePipeline, DepthClampControlUserDefined) { + AddRequiredExtensions(VK_EXT_DEPTH_CLAMP_CONTROL_EXTENSION_NAME); + AddRequiredFeature(vkt::Feature::depthClampControl); + RETURN_IF_SKIP(Init()); + InitRenderTarget(); + + VkPipelineViewportDepthClampControlCreateInfoEXT clamp_control = vku::InitStructHelper(); + clamp_control.depthClampMode = VK_DEPTH_CLAMP_MODE_USER_DEFINED_RANGE_EXT; + clamp_control.pDepthClampRange = nullptr; + CreatePipelineHelper pipe(*this); + pipe.vp_state_ci_.pNext = &clamp_control; + m_errorMonitor->SetDesiredError("VUID-VkPipelineViewportDepthClampControlCreateInfoEXT-pDepthClampRange-09646"); + pipe.CreateGraphicsPipeline(); + m_errorMonitor->VerifyFound(); +} \ No newline at end of file diff --git a/tests/unit/pipeline_positive.cpp b/tests/unit/pipeline_positive.cpp index 33504712be0..a78ab892498 100644 --- a/tests/unit/pipeline_positive.cpp +++ b/tests/unit/pipeline_positive.cpp @@ -1890,3 +1890,49 @@ TEST_F(PositivePipeline, PipelineMissingFeaturesDynamic) { pipe.gp_ci_.renderPass = rp.Handle(); pipe.CreateGraphicsPipeline(); } + +TEST_F(PositivePipeline, DepthClampControl) { + AddRequiredExtensions(VK_EXT_DEPTH_CLAMP_CONTROL_EXTENSION_NAME); + AddRequiredFeature(vkt::Feature::depthClampControl); + RETURN_IF_SKIP(Init()); + InitRenderTarget(); + + VkDepthClampRangeEXT clamp_range = {0.0f, 1.0f}; + VkPipelineViewportDepthClampControlCreateInfoEXT clamp_control = vku::InitStructHelper(); + clamp_control.depthClampMode = VK_DEPTH_CLAMP_MODE_USER_DEFINED_RANGE_EXT; + clamp_control.pDepthClampRange = &clamp_range; + CreatePipelineHelper pipe(*this); + pipe.vp_state_ci_.pNext = &clamp_control; + pipe.CreateGraphicsPipeline(); +} + +TEST_F(PositivePipeline, DepthClampControlUnrestricted) { + AddRequiredExtensions(VK_EXT_DEPTH_RANGE_UNRESTRICTED_EXTENSION_NAME); + AddRequiredExtensions(VK_EXT_DEPTH_CLAMP_CONTROL_EXTENSION_NAME); + AddRequiredFeature(vkt::Feature::depthClampControl); + RETURN_IF_SKIP(Init()); + InitRenderTarget(); + + VkDepthClampRangeEXT clamp_range = {-0.5f, 1.5f}; + VkPipelineViewportDepthClampControlCreateInfoEXT clamp_control = vku::InitStructHelper(); + clamp_control.depthClampMode = VK_DEPTH_CLAMP_MODE_USER_DEFINED_RANGE_EXT; + clamp_control.pDepthClampRange = &clamp_range; + CreatePipelineHelper pipe(*this); + pipe.vp_state_ci_.pNext = &clamp_control; + pipe.CreateGraphicsPipeline(); + m_errorMonitor->VerifyFound(); +} + +TEST_F(PositivePipeline, DepthClampControlNullRange) { + AddRequiredExtensions(VK_EXT_DEPTH_CLAMP_CONTROL_EXTENSION_NAME); + AddRequiredFeature(vkt::Feature::depthClampControl); + RETURN_IF_SKIP(Init()); + InitRenderTarget(); + + VkPipelineViewportDepthClampControlCreateInfoEXT clamp_control = vku::InitStructHelper(); + clamp_control.depthClampMode = VK_DEPTH_CLAMP_MODE_VIEWPORT_RANGE_EXT; + clamp_control.pDepthClampRange = nullptr; + CreatePipelineHelper pipe(*this); + pipe.vp_state_ci_.pNext = &clamp_control; + pipe.CreateGraphicsPipeline(); +} \ No newline at end of file