From ebfb6d18f1b71e142402abb753ba3de9a217824d Mon Sep 17 00:00:00 2001 From: spencer-lunarg Date: Thu, 12 Sep 2024 18:01:24 -0700 Subject: [PATCH] gpu: Fix instrumentation desc set binding logic This binding can disturb application binding in some circumstances Add SharedPipelineLayoutSubset tests --- layers/core_checks/cc_descriptor.cpp | 2 +- .../gpuav_cmd_validation_common.cpp | 10 +- layers/gpu/core/gpuav.h | 77 +++ layers/gpu/core/gpuav_record.cpp | 384 +++++++++++++- layers/gpu/debug_printf/debug_printf.cpp | 12 +- .../gpu_shader_instrumentor.cpp | 55 +- .../instrumentation/gpu_shader_instrumentor.h | 15 +- .../instrumentation/gpuav_instrumentation.cpp | 283 ++++++++-- .../instrumentation/gpuav_instrumentation.h | 7 +- layers/state_tracker/pipeline_state.cpp | 63 ++- layers/state_tracker/pipeline_state.h | 6 +- tests/unit/gpu_av.cpp | 24 - tests/unit/gpu_av_descriptor_indexing.cpp | 48 ++ .../gpu_av_descriptor_indexing_positive.cpp | 488 +++++++++++++++++- tests/unit/gpu_av_positive.cpp | 140 +++++ 15 files changed, 1471 insertions(+), 143 deletions(-) diff --git a/layers/core_checks/cc_descriptor.cpp b/layers/core_checks/cc_descriptor.cpp index b1bcb80443f..9c52f18e318 100644 --- a/layers/core_checks/cc_descriptor.cpp +++ b/layers/core_checks/cc_descriptor.cpp @@ -382,7 +382,7 @@ bool CoreChecks::ValidateCmdBindDescriptorSets(const vvl::CommandBuffer &cb_stat const char *vuid = is_2 ? "VUID-VkBindDescriptorSetsInfoKHR-pDescriptorSets-06563" : "VUID-vkCmdBindDescriptorSets-pDescriptorSets-06563"; skip |= LogError(vuid, objlist, set_loc, - "(%s) that does not exist, and the layout was not created " + "(%s) does not exist, and the pipeline layout was not created " "VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT.", FormatHandle(pDescriptorSets[set_idx]).c_str()); } diff --git a/layers/gpu/cmd_validation/gpuav_cmd_validation_common.cpp b/layers/gpu/cmd_validation/gpuav_cmd_validation_common.cpp index fdd536911c9..e184644fa1a 100644 --- a/layers/gpu/cmd_validation/gpuav_cmd_validation_common.cpp +++ b/layers/gpu/cmd_validation/gpuav_cmd_validation_common.cpp @@ -64,14 +64,14 @@ void RestorablePipelineState::Create(vvl::CommandBuffer &cb_state, VkPipelineBin push_constants_data_ = cb_state.push_constant_data_chunks; descriptor_sets_.reserve(last_bound.per_set.size()); - for (std::size_t i = 0; i < last_bound.per_set.size(); i++) { - const auto &bound_descriptor_set = last_bound.per_set[i].bound_descriptor_set; + for (std::size_t set_i = 0; set_i < last_bound.per_set.size(); set_i++) { + const auto &bound_descriptor_set = last_bound.per_set[set_i].bound_descriptor_set; if (bound_descriptor_set) { - descriptor_sets_.emplace_back(bound_descriptor_set->VkHandle(), static_cast(i)); + descriptor_sets_.emplace_back(bound_descriptor_set->VkHandle(), static_cast(set_i)); if (bound_descriptor_set->IsPushDescriptor()) { - push_descriptor_set_index_ = static_cast(i); + push_descriptor_set_index_ = static_cast(set_i); } - dynamic_offsets_.push_back(last_bound.per_set[i].dynamicOffsets); + dynamic_offsets_.push_back(last_bound.per_set[set_i].dynamicOffsets); } } diff --git a/layers/gpu/core/gpuav.h b/layers/gpu/core/gpuav.h index edc547aa5cb..8942c5f7d02 100644 --- a/layers/gpu/core/gpuav.h +++ b/layers/gpu/core/gpuav.h @@ -147,59 +147,114 @@ class Validator : public gpu::GpuShaderInstrumentor { const RecordObject& record_obj) final; void PreCallRecordCmdDraw(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, uint32_t firstInstance, const RecordObject& record_obj) final; + void PostCallRecordCmdDraw(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex, + uint32_t firstInstance, const RecordObject& record_obj) final; void PreCallRecordCmdDrawMultiEXT(VkCommandBuffer commandBuffer, uint32_t drawCount, const VkMultiDrawInfoEXT* pVertexInfo, uint32_t instanceCount, uint32_t firstInstance, uint32_t stride, const RecordObject& record_obj) final; + void PostCallRecordCmdDrawMultiEXT(VkCommandBuffer commandBuffer, uint32_t drawCount, const VkMultiDrawInfoEXT* pVertexInfo, + uint32_t instanceCount, uint32_t firstInstance, uint32_t stride, + const RecordObject& record_obj) final; void PreCallRecordCmdDrawIndexed(VkCommandBuffer commandBuffer, uint32_t indexCount, uint32_t instanceCount, uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance, const RecordObject& record_obj) final; + void PostCallRecordCmdDrawIndexed(VkCommandBuffer commandBuffer, uint32_t indexCount, uint32_t instanceCount, + uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance, + const RecordObject& record_obj) final; void PreCallRecordCmdDrawMultiIndexedEXT(VkCommandBuffer commandBuffer, uint32_t drawCount, const VkMultiDrawIndexedInfoEXT* pIndexInfo, uint32_t instanceCount, uint32_t firstInstance, uint32_t stride, const int32_t* pVertexOffset, const RecordObject& record_obj) final; + void PostCallRecordCmdDrawMultiIndexedEXT(VkCommandBuffer commandBuffer, uint32_t drawCount, + const VkMultiDrawIndexedInfoEXT* pIndexInfo, uint32_t instanceCount, + uint32_t firstInstance, uint32_t stride, const int32_t* pVertexOffset, + const RecordObject& record_obj) final; void PreCallRecordCmdDrawIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t count, uint32_t stride, const RecordObject& record_obj) final; + void PostCallRecordCmdDrawIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t count, + uint32_t stride, const RecordObject& record_obj) final; void PreCallRecordCmdDrawIndexedIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t count, uint32_t stride, const RecordObject& record_obj) final; + void PostCallRecordCmdDrawIndexedIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t count, + uint32_t stride, const RecordObject& record_obj) final; void PreCallRecordCmdDrawIndirectCountKHR(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride, const RecordObject& record_obj) final; + void PostCallRecordCmdDrawIndirectCountKHR(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, + VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, + uint32_t stride, const RecordObject& record_obj) final; void PreCallRecordCmdDrawIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride, const RecordObject& record_obj) final; + void PostCallRecordCmdDrawIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, + VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, + uint32_t stride, const RecordObject& record_obj) final; void PreCallRecordCmdDrawIndirectByteCountEXT(VkCommandBuffer commandBuffer, uint32_t instanceCount, uint32_t firstInstance, VkBuffer counterBuffer, VkDeviceSize counterBufferOffset, uint32_t counterOffset, uint32_t vertexStride, const RecordObject& record_obj) final; + void PostCallRecordCmdDrawIndirectByteCountEXT(VkCommandBuffer commandBuffer, uint32_t instanceCount, uint32_t firstInstance, + VkBuffer counterBuffer, VkDeviceSize counterBufferOffset, uint32_t counterOffset, + uint32_t vertexStride, const RecordObject& record_obj) final; void PreCallRecordCmdDrawIndexedIndirectCountKHR(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride, const RecordObject& record_obj) final; + void PostCallRecordCmdDrawIndexedIndirectCountKHR(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, + VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, + uint32_t stride, const RecordObject& record_obj) final; void PreCallRecordCmdDrawIndexedIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride, const RecordObject& record_obj) final; + void PostCallRecordCmdDrawIndexedIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, + VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, + uint32_t stride, const RecordObject& record_obj) final; void PreCallRecordCmdDrawMeshTasksNV(VkCommandBuffer commandBuffer, uint32_t taskCount, uint32_t firstTask, const RecordObject& record_obj) final; + void PostCallRecordCmdDrawMeshTasksNV(VkCommandBuffer commandBuffer, uint32_t taskCount, uint32_t firstTask, + const RecordObject& record_obj) final; void PreCallRecordCmdDrawMeshTasksIndirectNV(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride, const RecordObject& record_obj) final; + void PostCallRecordCmdDrawMeshTasksIndirectNV(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, + uint32_t drawCount, uint32_t stride, const RecordObject& record_obj) final; void PreCallRecordCmdDrawMeshTasksIndirectCountNV(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride, const RecordObject& record_obj) final; + void PostCallRecordCmdDrawMeshTasksIndirectCountNV(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, + VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, + uint32_t stride, const RecordObject& record_obj) final; void PreCallRecordCmdDrawMeshTasksEXT(VkCommandBuffer commandBuffer, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ, const RecordObject& record_obj) final; + void PostCallRecordCmdDrawMeshTasksEXT(VkCommandBuffer commandBuffer, uint32_t groupCountX, uint32_t groupCountY, + uint32_t groupCountZ, const RecordObject& record_obj) final; void PreCallRecordCmdDrawMeshTasksIndirectEXT(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t drawCount, uint32_t stride, const RecordObject& record_obj) final; + void PostCallRecordCmdDrawMeshTasksIndirectEXT(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, + uint32_t drawCount, uint32_t stride, const RecordObject& record_obj) final; void PreCallRecordCmdDrawMeshTasksIndirectCountEXT(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride, const RecordObject& record_obj) final; + void PostCallRecordCmdDrawMeshTasksIndirectCountEXT(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, + VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, + uint32_t stride, const RecordObject& record_obj) final; void PreCallRecordCmdDispatch(VkCommandBuffer commandBuffer, uint32_t x, uint32_t y, uint32_t z, const RecordObject& record_obj) final; + void PostCallRecordCmdDispatch(VkCommandBuffer commandBuffer, uint32_t x, uint32_t y, uint32_t z, + const RecordObject& record_obj) final; void PreCallRecordCmdDispatchIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, const RecordObject& record_obj) final; + void PostCallRecordCmdDispatchIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, + const RecordObject& record_obj) final; void PreCallRecordCmdDispatchBase(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ, const RecordObject& record_obj) final; + void PostCallRecordCmdDispatchBase(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, + uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ, + const RecordObject& record_obj) final; void PreCallRecordCmdDispatchBaseKHR(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ, const RecordObject& record_obj) final; + void PostCallRecordCmdDispatchBaseKHR(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, + uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ, + const RecordObject& record_obj) final; void PreCallRecordCmdTraceRaysNV(VkCommandBuffer commandBuffer, VkBuffer raygenShaderBindingTableBuffer, VkDeviceSize raygenShaderBindingOffset, VkBuffer missShaderBindingTableBuffer, VkDeviceSize missShaderBindingOffset, VkDeviceSize missShaderBindingStride, @@ -207,20 +262,42 @@ class Validator : public gpu::GpuShaderInstrumentor { VkDeviceSize hitShaderBindingStride, VkBuffer callableShaderBindingTableBuffer, VkDeviceSize callableShaderBindingOffset, VkDeviceSize callableShaderBindingStride, uint32_t width, uint32_t height, uint32_t depth, const RecordObject& record_obj) final; + void PostCallRecordCmdTraceRaysNV(VkCommandBuffer commandBuffer, VkBuffer raygenShaderBindingTableBuffer, + VkDeviceSize raygenShaderBindingOffset, VkBuffer missShaderBindingTableBuffer, + VkDeviceSize missShaderBindingOffset, VkDeviceSize missShaderBindingStride, + VkBuffer hitShaderBindingTableBuffer, VkDeviceSize hitShaderBindingOffset, + VkDeviceSize hitShaderBindingStride, VkBuffer callableShaderBindingTableBuffer, + VkDeviceSize callableShaderBindingOffset, VkDeviceSize callableShaderBindingStride, + uint32_t width, uint32_t height, uint32_t depth, const RecordObject& record_obj) final; + void PreCallRecordCmdTraceRaysKHR(VkCommandBuffer commandBuffer, const VkStridedDeviceAddressRegionKHR* pRaygenShaderBindingTable, const VkStridedDeviceAddressRegionKHR* pMissShaderBindingTable, const VkStridedDeviceAddressRegionKHR* pHitShaderBindingTable, const VkStridedDeviceAddressRegionKHR* pCallableShaderBindingTable, uint32_t width, uint32_t height, uint32_t depth, const RecordObject& record_obj) final; + void PostCallRecordCmdTraceRaysKHR(VkCommandBuffer commandBuffer, + const VkStridedDeviceAddressRegionKHR* pRaygenShaderBindingTable, + const VkStridedDeviceAddressRegionKHR* pMissShaderBindingTable, + const VkStridedDeviceAddressRegionKHR* pHitShaderBindingTable, + const VkStridedDeviceAddressRegionKHR* pCallableShaderBindingTable, uint32_t width, + uint32_t height, uint32_t depth, const RecordObject& record_obj) final; void PreCallRecordCmdTraceRaysIndirectKHR(VkCommandBuffer commandBuffer, const VkStridedDeviceAddressRegionKHR* pRaygenShaderBindingTable, const VkStridedDeviceAddressRegionKHR* pMissShaderBindingTable, const VkStridedDeviceAddressRegionKHR* pHitShaderBindingTable, const VkStridedDeviceAddressRegionKHR* pCallableShaderBindingTable, VkDeviceAddress indirectDeviceAddress, const RecordObject& record_obj) final; + void PostCallRecordCmdTraceRaysIndirectKHR(VkCommandBuffer commandBuffer, + const VkStridedDeviceAddressRegionKHR* pRaygenShaderBindingTable, + const VkStridedDeviceAddressRegionKHR* pMissShaderBindingTable, + const VkStridedDeviceAddressRegionKHR* pHitShaderBindingTable, + const VkStridedDeviceAddressRegionKHR* pCallableShaderBindingTable, + VkDeviceAddress indirectDeviceAddress, const RecordObject& record_obj) final; void PreCallRecordCmdTraceRaysIndirect2KHR(VkCommandBuffer commandBuffer, VkDeviceAddress indirectDeviceAddress, const RecordObject& record_obj) final; + void PostCallRecordCmdTraceRaysIndirect2KHR(VkCommandBuffer commandBuffer, VkDeviceAddress indirectDeviceAddress, + const RecordObject& record_obj) final; void PostCallRecordGetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2* pPhysicalDeviceProperties2, diff --git a/layers/gpu/core/gpuav_record.cpp b/layers/gpu/core/gpuav_record.cpp index 743bc77ca2f..8e93896d947 100644 --- a/layers/gpu/core/gpuav_record.cpp +++ b/layers/gpu/core/gpuav_record.cpp @@ -307,7 +307,20 @@ void Validator::PreCallRecordCmdDraw(VkCommandBuffer commandBuffer, uint32_t ver return; } - SetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, record_obj.location); + PreCallSetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, record_obj.location); +} + +void Validator::PostCallRecordCmdDraw(VkCommandBuffer commandBuffer, uint32_t vertexCount, uint32_t instanceCount, + uint32_t firstVertex, uint32_t firstInstance, const RecordObject &record_obj) { + BaseClass::PostCallRecordCmdDraw(commandBuffer, vertexCount, instanceCount, firstVertex, firstInstance, record_obj); + + auto cb_state = GetWrite(commandBuffer); + if (!cb_state) { + InternalError(commandBuffer, record_obj.location, "Unrecognized command buffer."); + return; + } + + PostCallSetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, record_obj.location); } void Validator::PreCallRecordCmdDrawMultiEXT(VkCommandBuffer commandBuffer, uint32_t drawCount, @@ -322,9 +335,22 @@ void Validator::PreCallRecordCmdDrawMultiEXT(VkCommandBuffer commandBuffer, uint return; } - for (uint32_t i = 0; i < drawCount; i++) { - SetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, record_obj.location); + PreCallSetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, record_obj.location); +} + +void Validator::PostCallRecordCmdDrawMultiEXT(VkCommandBuffer commandBuffer, uint32_t drawCount, + const VkMultiDrawInfoEXT *pVertexInfo, uint32_t instanceCount, uint32_t firstInstance, + uint32_t stride, const RecordObject &record_obj) { + BaseClass::PostCallRecordCmdDrawMultiEXT(commandBuffer, drawCount, pVertexInfo, instanceCount, firstInstance, stride, + record_obj); + + auto cb_state = GetWrite(commandBuffer); + if (!cb_state) { + InternalError(commandBuffer, record_obj.location, "Unrecognized command buffer."); + return; } + + PostCallSetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, record_obj.location); } void Validator::PreCallRecordCmdDrawIndexed(VkCommandBuffer commandBuffer, uint32_t indexCount, uint32_t instanceCount, @@ -337,7 +363,20 @@ void Validator::PreCallRecordCmdDrawIndexed(VkCommandBuffer commandBuffer, uint3 InternalError(commandBuffer, record_obj.location, "Unrecognized command buffer."); return; } - SetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, record_obj.location); + PreCallSetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, record_obj.location); +} + +void Validator::PostCallRecordCmdDrawIndexed(VkCommandBuffer commandBuffer, uint32_t indexCount, uint32_t instanceCount, + uint32_t firstIndex, int32_t vertexOffset, uint32_t firstInstance, + const RecordObject &record_obj) { + BaseClass::PostCallRecordCmdDrawIndexed(commandBuffer, indexCount, instanceCount, firstIndex, vertexOffset, firstInstance, + record_obj); + auto cb_state = GetWrite(commandBuffer); + if (!cb_state) { + InternalError(commandBuffer, record_obj.location, "Unrecognized command buffer."); + return; + } + PostCallSetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, record_obj.location); } void Validator::PreCallRecordCmdDrawMultiIndexedEXT(VkCommandBuffer commandBuffer, uint32_t drawCount, @@ -353,10 +392,25 @@ void Validator::PreCallRecordCmdDrawMultiIndexedEXT(VkCommandBuffer commandBuffe } for (uint32_t i = 0; i < drawCount; i++) { // #ARNO_TODO calling Setup drawCount times seems weird... - SetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, record_obj.location); + PreCallSetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, record_obj.location); } } +void Validator::PostCallRecordCmdDrawMultiIndexedEXT(VkCommandBuffer commandBuffer, uint32_t drawCount, + const VkMultiDrawIndexedInfoEXT *pIndexInfo, uint32_t instanceCount, + uint32_t firstInstance, uint32_t stride, const int32_t *pVertexOffset, + const RecordObject &record_obj) { + BaseClass::PostCallRecordCmdDrawMultiIndexedEXT(commandBuffer, drawCount, pIndexInfo, instanceCount, firstInstance, stride, + pVertexOffset, record_obj); + auto cb_state = GetWrite(commandBuffer); + if (!cb_state) { + InternalError(commandBuffer, record_obj.location, "Unrecognized command buffer."); + return; + } + + PostCallSetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, record_obj.location); +} + void Validator::PreCallRecordCmdDrawIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t count, uint32_t stride, const RecordObject &record_obj) { BaseClass::PreCallRecordCmdDrawIndirect(commandBuffer, buffer, offset, count, stride, record_obj); @@ -368,7 +422,20 @@ void Validator::PreCallRecordCmdDrawIndirect(VkCommandBuffer commandBuffer, VkBu } InsertIndirectDrawValidation(*this, record_obj.location, *cb_state, buffer, offset, count, VK_NULL_HANDLE, 0, stride); - SetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, record_obj.location); + PreCallSetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, record_obj.location); +} + +void Validator::PostCallRecordCmdDrawIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t count, + uint32_t stride, const RecordObject &record_obj) { + BaseClass::PostCallRecordCmdDrawIndirect(commandBuffer, buffer, offset, count, stride, record_obj); + + auto cb_state = GetWrite(commandBuffer); + if (!cb_state) { + InternalError(commandBuffer, record_obj.location, "Unrecognized command buffer."); + return; + } + + PostCallSetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, record_obj.location); } void Validator::PreCallRecordCmdDrawIndexedIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, @@ -382,7 +449,20 @@ void Validator::PreCallRecordCmdDrawIndexedIndirect(VkCommandBuffer commandBuffe } InsertIndirectDrawValidation(*this, record_obj.location, *cb_state, buffer, offset, count, VK_NULL_HANDLE, 0, stride); - SetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, record_obj.location); + PreCallSetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, record_obj.location); +} + +void Validator::PostCallRecordCmdDrawIndexedIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, + uint32_t count, uint32_t stride, const RecordObject &record_obj) { + BaseClass::PostCallRecordCmdDrawIndexedIndirect(commandBuffer, buffer, offset, count, stride, record_obj); + + auto cb_state = GetWrite(commandBuffer); + if (!cb_state) { + InternalError(commandBuffer, record_obj.location, "Unrecognized command buffer."); + return; + } + + PostCallSetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, record_obj.location); } void Validator::PreCallRecordCmdDrawIndirectCountKHR(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, @@ -392,6 +472,13 @@ void Validator::PreCallRecordCmdDrawIndirectCountKHR(VkCommandBuffer commandBuff record_obj); } +void Validator::PostCallRecordCmdDrawIndirectCountKHR(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, + VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, + uint32_t stride, const RecordObject &record_obj) { + PostCallRecordCmdDrawIndirectCount(commandBuffer, buffer, offset, countBuffer, countBufferOffset, maxDrawCount, stride, + record_obj); +} + void Validator::PreCallRecordCmdDrawIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride, const RecordObject &record_obj) { @@ -405,7 +492,22 @@ void Validator::PreCallRecordCmdDrawIndirectCount(VkCommandBuffer commandBuffer, } InsertIndirectDrawValidation(*this, record_obj.location, *cb_state, buffer, offset, maxDrawCount, countBuffer, countBufferOffset, stride); - SetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, record_obj.location); + PreCallSetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, record_obj.location); +} + +void Validator::PostCallRecordCmdDrawIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, + VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, + uint32_t stride, const RecordObject &record_obj) { + BaseClass::PostCallRecordCmdDrawIndirectCount(commandBuffer, buffer, offset, countBuffer, countBufferOffset, maxDrawCount, + stride, record_obj); + + auto cb_state = GetWrite(commandBuffer); + if (!cb_state) { + InternalError(commandBuffer, record_obj.location, "Unrecognized command buffer."); + return; + } + + PostCallSetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, record_obj.location); } void Validator::PreCallRecordCmdDrawIndirectByteCountEXT(VkCommandBuffer commandBuffer, uint32_t instanceCount, @@ -419,7 +521,21 @@ void Validator::PreCallRecordCmdDrawIndirectByteCountEXT(VkCommandBuffer command InternalError(commandBuffer, record_obj.location, "Unrecognized command buffer."); return; } - SetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, record_obj.location); + PreCallSetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, record_obj.location); +} + +void Validator::PostCallRecordCmdDrawIndirectByteCountEXT(VkCommandBuffer commandBuffer, uint32_t instanceCount, + uint32_t firstInstance, VkBuffer counterBuffer, + VkDeviceSize counterBufferOffset, uint32_t counterOffset, + uint32_t vertexStride, const RecordObject &record_obj) { + BaseClass::PostCallRecordCmdDrawIndirectByteCountEXT(commandBuffer, instanceCount, firstInstance, counterBuffer, + counterBufferOffset, counterOffset, vertexStride, record_obj); + auto cb_state = GetWrite(commandBuffer); + if (!cb_state) { + InternalError(commandBuffer, record_obj.location, "Unrecognized command buffer."); + return; + } + PostCallSetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, record_obj.location); } void Validator::PreCallRecordCmdDrawIndexedIndirectCountKHR(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, @@ -430,6 +546,14 @@ void Validator::PreCallRecordCmdDrawIndexedIndirectCountKHR(VkCommandBuffer comm record_obj); } +void Validator::PostCallRecordCmdDrawIndexedIndirectCountKHR(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, + VkBuffer countBuffer, VkDeviceSize countBufferOffset, + uint32_t maxDrawCount, uint32_t stride, + const RecordObject &record_obj) { + PostCallRecordCmdDrawIndexedIndirectCount(commandBuffer, buffer, offset, countBuffer, countBufferOffset, maxDrawCount, stride, + record_obj); +} + void Validator::PreCallRecordCmdDrawIndexedIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride, const RecordObject &record_obj) { @@ -443,7 +567,22 @@ void Validator::PreCallRecordCmdDrawIndexedIndirectCount(VkCommandBuffer command } InsertIndirectDrawValidation(*this, record_obj.location, *cb_state, buffer, offset, maxDrawCount, countBuffer, countBufferOffset, stride); - SetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, record_obj.location); + PreCallSetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, record_obj.location); +} + +void Validator::PostCallRecordCmdDrawIndexedIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, + VkBuffer countBuffer, VkDeviceSize countBufferOffset, + uint32_t maxDrawCount, uint32_t stride, const RecordObject &record_obj) { + BaseClass::PostCallRecordCmdDrawIndexedIndirectCount(commandBuffer, buffer, offset, countBuffer, countBufferOffset, + maxDrawCount, stride, record_obj); + + auto cb_state = GetWrite(commandBuffer); + if (!cb_state) { + InternalError(commandBuffer, record_obj.location, "Unrecognized command buffer."); + return; + } + + PostCallSetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, record_obj.location); } void Validator::PreCallRecordCmdDrawMeshTasksNV(VkCommandBuffer commandBuffer, uint32_t taskCount, uint32_t firstTask, @@ -454,7 +593,18 @@ void Validator::PreCallRecordCmdDrawMeshTasksNV(VkCommandBuffer commandBuffer, u InternalError(commandBuffer, record_obj.location, "Unrecognized command buffer."); return; } - SetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, record_obj.location); + PreCallSetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, record_obj.location); +} + +void Validator::PostCallRecordCmdDrawMeshTasksNV(VkCommandBuffer commandBuffer, uint32_t taskCount, uint32_t firstTask, + const RecordObject &record_obj) { + ValidationStateTracker::PostCallRecordCmdDrawMeshTasksNV(commandBuffer, taskCount, firstTask, record_obj); + auto cb_state = GetWrite(commandBuffer); + if (!cb_state) { + InternalError(commandBuffer, record_obj.location, "Unrecognized command buffer."); + return; + } + PostCallSetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, record_obj.location); } void Validator::PreCallRecordCmdDrawMeshTasksIndirectNV(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, @@ -467,7 +617,19 @@ void Validator::PreCallRecordCmdDrawMeshTasksIndirectNV(VkCommandBuffer commandB return; } InsertIndirectDrawValidation(*this, record_obj.location, *cb_state, buffer, offset, drawCount, VK_NULL_HANDLE, 0, stride); - SetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, record_obj.location); + PreCallSetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, record_obj.location); +} + +void Validator::PostCallRecordCmdDrawMeshTasksIndirectNV(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, + uint32_t drawCount, uint32_t stride, const RecordObject &record_obj) { + BaseClass::PostCallRecordCmdDrawMeshTasksIndirectNV(commandBuffer, buffer, offset, drawCount, stride, record_obj); + + auto cb_state = GetWrite(commandBuffer); + if (!cb_state) { + InternalError(commandBuffer, record_obj.location, "Unrecognized command buffer."); + return; + } + PostCallSetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, record_obj.location); } void Validator::PreCallRecordCmdDrawMeshTasksIndirectCountNV(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, @@ -484,7 +646,23 @@ void Validator::PreCallRecordCmdDrawMeshTasksIndirectCountNV(VkCommandBuffer com } InsertIndirectDrawValidation(*this, record_obj.location, *cb_state, buffer, offset, maxDrawCount, countBuffer, countBufferOffset, stride); - SetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, record_obj.location); + PreCallSetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, record_obj.location); +} + +void Validator::PostCallRecordCmdDrawMeshTasksIndirectCountNV(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, + VkBuffer countBuffer, VkDeviceSize countBufferOffset, + uint32_t maxDrawCount, uint32_t stride, + const RecordObject &record_obj) { + BaseClass::PostCallRecordCmdDrawMeshTasksIndirectCountNV(commandBuffer, buffer, offset, countBuffer, countBufferOffset, + maxDrawCount, stride, record_obj); + + auto cb_state = GetWrite(commandBuffer); + if (!cb_state) { + InternalError(commandBuffer, record_obj.location, "Unrecognized command buffer."); + return; + } + + PostCallSetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, record_obj.location); } void Validator::PreCallRecordCmdDrawMeshTasksEXT(VkCommandBuffer commandBuffer, uint32_t groupCountX, uint32_t groupCountY, @@ -495,7 +673,18 @@ void Validator::PreCallRecordCmdDrawMeshTasksEXT(VkCommandBuffer commandBuffer, InternalError(commandBuffer, record_obj.location, "Unrecognized command buffer."); return; } - SetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, record_obj.location); + PreCallSetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, record_obj.location); +} + +void Validator::PostCallRecordCmdDrawMeshTasksEXT(VkCommandBuffer commandBuffer, uint32_t groupCountX, uint32_t groupCountY, + uint32_t groupCountZ, const RecordObject &record_obj) { + BaseClass::PostCallRecordCmdDrawMeshTasksEXT(commandBuffer, groupCountX, groupCountY, groupCountZ, record_obj); + auto cb_state = GetWrite(commandBuffer); + if (!cb_state) { + InternalError(commandBuffer, record_obj.location, "Unrecognized command buffer."); + return; + } + PostCallSetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, record_obj.location); } void Validator::PreCallRecordCmdDrawMeshTasksIndirectEXT(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, @@ -508,7 +697,19 @@ void Validator::PreCallRecordCmdDrawMeshTasksIndirectEXT(VkCommandBuffer command return; } InsertIndirectDrawValidation(*this, record_obj.location, *cb_state, buffer, offset, drawCount, VK_NULL_HANDLE, 0, stride); - SetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, record_obj.location); + PreCallSetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, record_obj.location); +} + +void Validator::PostCallRecordCmdDrawMeshTasksIndirectEXT(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, + uint32_t drawCount, uint32_t stride, const RecordObject &record_obj) { + BaseClass::PostCallRecordCmdDrawMeshTasksIndirectEXT(commandBuffer, buffer, offset, drawCount, stride, record_obj); + + auto cb_state = GetWrite(commandBuffer); + if (!cb_state) { + InternalError(commandBuffer, record_obj.location, "Unrecognized command buffer."); + return; + } + PostCallSetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, record_obj.location); } void Validator::PreCallRecordCmdDrawMeshTasksIndirectCountEXT(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, @@ -525,7 +726,23 @@ void Validator::PreCallRecordCmdDrawMeshTasksIndirectCountEXT(VkCommandBuffer co } InsertIndirectDrawValidation(*this, record_obj.location, *cb_state, buffer, offset, maxDrawCount, countBuffer, countBufferOffset, stride); - SetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, record_obj.location); + PreCallSetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, record_obj.location); +} + +void Validator::PostCallRecordCmdDrawMeshTasksIndirectCountEXT(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, + VkBuffer countBuffer, VkDeviceSize countBufferOffset, + uint32_t maxDrawCount, uint32_t stride, + const RecordObject &record_obj) { + BaseClass::PostCallRecordCmdDrawMeshTasksIndirectCountEXT(commandBuffer, buffer, offset, countBuffer, countBufferOffset, + maxDrawCount, stride, record_obj); + + auto cb_state = GetWrite(commandBuffer); + if (!cb_state) { + InternalError(commandBuffer, record_obj.location, "Unrecognized command buffer."); + return; + } + + PostCallSetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_GRAPHICS, record_obj.location); } void Validator::PreCallRecordCmdDispatch(VkCommandBuffer commandBuffer, uint32_t x, uint32_t y, uint32_t z, @@ -537,7 +754,19 @@ void Validator::PreCallRecordCmdDispatch(VkCommandBuffer commandBuffer, uint32_t InternalError(commandBuffer, record_obj.location, "Unrecognized command buffer."); return; } - SetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_COMPUTE, record_obj.location); + PreCallSetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_COMPUTE, record_obj.location); +} + +void Validator::PostCallRecordCmdDispatch(VkCommandBuffer commandBuffer, uint32_t x, uint32_t y, uint32_t z, + const RecordObject &record_obj) { + BaseClass::PostCallRecordCmdDispatch(commandBuffer, x, y, z, record_obj); + + auto cb_state = GetWrite(commandBuffer); + if (!cb_state) { + InternalError(commandBuffer, record_obj.location, "Unrecognized command buffer."); + return; + } + PostCallSetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_COMPUTE, record_obj.location); } void Validator::PreCallRecordCmdDispatchIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, @@ -550,7 +779,20 @@ void Validator::PreCallRecordCmdDispatchIndirect(VkCommandBuffer commandBuffer, return; } InsertIndirectDispatchValidation(*this, record_obj.location, *cb_state, buffer, offset); - SetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_COMPUTE, record_obj.location); + PreCallSetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_COMPUTE, record_obj.location); +} + +void Validator::PostCallRecordCmdDispatchIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, + const RecordObject &record_obj) { + BaseClass::PostCallRecordCmdDispatchIndirect(commandBuffer, buffer, offset, record_obj); + + auto cb_state = GetWrite(commandBuffer); + if (!cb_state) { + InternalError(commandBuffer, record_obj.location, "Unrecognized command buffer."); + return; + } + + PostCallSetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_COMPUTE, record_obj.location); } void Validator::PreCallRecordCmdDispatchBase(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, @@ -564,7 +806,21 @@ void Validator::PreCallRecordCmdDispatchBase(VkCommandBuffer commandBuffer, uint InternalError(commandBuffer, record_obj.location, "Unrecognized command buffer."); return; } - SetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_COMPUTE, record_obj.location); + PreCallSetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_COMPUTE, record_obj.location); +} + +void Validator::PostCallRecordCmdDispatchBase(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, + uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ, + const RecordObject &record_obj) { + BaseClass::PostCallRecordCmdDispatchBase(commandBuffer, baseGroupX, baseGroupY, baseGroupZ, groupCountX, groupCountY, + groupCountZ, record_obj); + + auto cb_state = GetWrite(commandBuffer); + if (!cb_state) { + InternalError(commandBuffer, record_obj.location, "Unrecognized command buffer."); + return; + } + PostCallSetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_COMPUTE, record_obj.location); } void Validator::PreCallRecordCmdDispatchBaseKHR(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, @@ -574,6 +830,20 @@ void Validator::PreCallRecordCmdDispatchBaseKHR(VkCommandBuffer commandBuffer, u record_obj); } +void Validator::PostCallRecordCmdDispatchBaseKHR(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, + uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, + uint32_t groupCountZ, const RecordObject &record_obj) { + BaseClass::PostCallRecordCmdDispatchBaseKHR(commandBuffer, baseGroupX, baseGroupY, baseGroupZ, groupCountX, groupCountY, + groupCountZ, record_obj); + + auto cb_state = GetWrite(commandBuffer); + if (!cb_state) { + InternalError(commandBuffer, record_obj.location, "Unrecognized command buffer."); + return; + } + PostCallSetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_COMPUTE, record_obj.location); +} + void Validator::PreCallRecordCmdTraceRaysNV(VkCommandBuffer commandBuffer, VkBuffer raygenShaderBindingTableBuffer, VkDeviceSize raygenShaderBindingOffset, VkBuffer missShaderBindingTableBuffer, VkDeviceSize missShaderBindingOffset, VkDeviceSize missShaderBindingStride, @@ -592,7 +862,28 @@ void Validator::PreCallRecordCmdTraceRaysNV(VkCommandBuffer commandBuffer, VkBuf InternalError(commandBuffer, record_obj.location, "Unrecognized command buffer."); return; } - SetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, record_obj.location); + PreCallSetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, record_obj.location); +} + +void Validator::PostCallRecordCmdTraceRaysNV(VkCommandBuffer commandBuffer, VkBuffer raygenShaderBindingTableBuffer, + VkDeviceSize raygenShaderBindingOffset, VkBuffer missShaderBindingTableBuffer, + VkDeviceSize missShaderBindingOffset, VkDeviceSize missShaderBindingStride, + VkBuffer hitShaderBindingTableBuffer, VkDeviceSize hitShaderBindingOffset, + VkDeviceSize hitShaderBindingStride, VkBuffer callableShaderBindingTableBuffer, + VkDeviceSize callableShaderBindingOffset, VkDeviceSize callableShaderBindingStride, + uint32_t width, uint32_t height, uint32_t depth, const RecordObject &record_obj) { + BaseClass::PostCallRecordCmdTraceRaysNV(commandBuffer, raygenShaderBindingTableBuffer, raygenShaderBindingOffset, + missShaderBindingTableBuffer, missShaderBindingOffset, missShaderBindingStride, + hitShaderBindingTableBuffer, hitShaderBindingOffset, hitShaderBindingStride, + callableShaderBindingTableBuffer, callableShaderBindingOffset, + callableShaderBindingStride, width, height, depth, record_obj); + + auto cb_state = GetWrite(commandBuffer); + if (!cb_state) { + InternalError(commandBuffer, record_obj.location, "Unrecognized command buffer."); + return; + } + PostCallSetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, record_obj.location); } void Validator::PreCallRecordCmdTraceRaysKHR(VkCommandBuffer commandBuffer, @@ -609,7 +900,24 @@ void Validator::PreCallRecordCmdTraceRaysKHR(VkCommandBuffer commandBuffer, InternalError(commandBuffer, record_obj.location, "Unrecognized command buffer."); return; } - SetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, record_obj.location); + PreCallSetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, record_obj.location); +} + +void Validator::PostCallRecordCmdTraceRaysKHR(VkCommandBuffer commandBuffer, + const VkStridedDeviceAddressRegionKHR *pRaygenShaderBindingTable, + const VkStridedDeviceAddressRegionKHR *pMissShaderBindingTable, + const VkStridedDeviceAddressRegionKHR *pHitShaderBindingTable, + const VkStridedDeviceAddressRegionKHR *pCallableShaderBindingTable, uint32_t width, + uint32_t height, uint32_t depth, const RecordObject &record_obj) { + BaseClass::PostCallRecordCmdTraceRaysKHR(commandBuffer, pRaygenShaderBindingTable, pMissShaderBindingTable, + pHitShaderBindingTable, pCallableShaderBindingTable, width, height, depth, record_obj); + + auto cb_state = GetWrite(commandBuffer); + if (!cb_state) { + InternalError(commandBuffer, record_obj.location, "Unrecognized command buffer."); + return; + } + PostCallSetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, record_obj.location); } void Validator::PreCallRecordCmdTraceRaysIndirectKHR(VkCommandBuffer commandBuffer, @@ -628,7 +936,25 @@ void Validator::PreCallRecordCmdTraceRaysIndirectKHR(VkCommandBuffer commandBuff return; } InsertIndirectTraceRaysValidation(*this, record_obj.location, *cb_state, indirectDeviceAddress); - SetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, record_obj.location); + PreCallSetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, record_obj.location); +} + +void Validator::PostCallRecordCmdTraceRaysIndirectKHR(VkCommandBuffer commandBuffer, + const VkStridedDeviceAddressRegionKHR *pRaygenShaderBindingTable, + const VkStridedDeviceAddressRegionKHR *pMissShaderBindingTable, + const VkStridedDeviceAddressRegionKHR *pHitShaderBindingTable, + const VkStridedDeviceAddressRegionKHR *pCallableShaderBindingTable, + VkDeviceAddress indirectDeviceAddress, const RecordObject &record_obj) { + BaseClass::PostCallRecordCmdTraceRaysIndirectKHR(commandBuffer, pRaygenShaderBindingTable, pMissShaderBindingTable, + pHitShaderBindingTable, pCallableShaderBindingTable, indirectDeviceAddress, + record_obj); + + auto cb_state = GetWrite(commandBuffer); + if (!cb_state) { + InternalError(commandBuffer, record_obj.location, "Unrecognized command buffer."); + return; + } + PostCallSetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, record_obj.location); } void Validator::PreCallRecordCmdTraceRaysIndirect2KHR(VkCommandBuffer commandBuffer, VkDeviceAddress indirectDeviceAddress, @@ -640,7 +966,19 @@ void Validator::PreCallRecordCmdTraceRaysIndirect2KHR(VkCommandBuffer commandBuf InternalError(commandBuffer, record_obj.location, "Unrecognized command buffer."); return; } - SetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, record_obj.location); + PreCallSetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, record_obj.location); +} + +void Validator::PostCallRecordCmdTraceRaysIndirect2KHR(VkCommandBuffer commandBuffer, VkDeviceAddress indirectDeviceAddress, + const RecordObject &record_obj) { + BaseClass::PostCallRecordCmdTraceRaysIndirect2KHR(commandBuffer, indirectDeviceAddress, record_obj); + + auto cb_state = GetWrite(commandBuffer); + if (!cb_state) { + InternalError(commandBuffer, record_obj.location, "Unrecognized command buffer."); + return; + } + PostCallSetupShaderInstrumentationResources(*this, *cb_state, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, record_obj.location); } } // namespace gpuav diff --git a/layers/gpu/debug_printf/debug_printf.cpp b/layers/gpu/debug_printf/debug_printf.cpp index 7db8bf42e5c..a958da492f8 100644 --- a/layers/gpu/debug_printf/debug_printf.cpp +++ b/layers/gpu/debug_printf/debug_printf.cpp @@ -600,7 +600,7 @@ void Validator::AllocateDebugPrintfResources(const VkCommandBuffer cmd_buffer, c // VkDescriptorSet printf_desc_set = cb_state->gpu_resources_manager.GetManagedDescriptorSet(GetDebugDescriptorSetLayout()); std::vector desc_sets; VkDescriptorPool desc_pool = VK_NULL_HANDLE; - VkResult result = desc_set_manager_->GetDescriptorSets(1, &desc_pool, GetDebugDescriptorSetLayout(), &desc_sets); + VkResult result = desc_set_manager_->GetDescriptorSets(1, &desc_pool, GetInstrumentationDescriptorSetLayout(), &desc_sets); if (result != VK_SUCCESS) { InternalError(cmd_buffer, loc, "Unable to allocate descriptor sets."); return; @@ -654,15 +654,15 @@ void Validator::AllocateDebugPrintfResources(const VkCommandBuffer cmd_buffer, c const auto pipeline_layout_handle = (last_bound.desc_set_pipeline_layout) ? last_bound.desc_set_pipeline_layout : pipeline_state->PreRasterPipelineLayoutState()->VkHandle(); - if (pipeline_layout->set_layouts.size() <= desc_set_bind_index_) { - DispatchCmdBindDescriptorSets(cmd_buffer, bind_point, pipeline_layout_handle, desc_set_bind_index_, 1, desc_sets.data(), - 0, nullptr); + if (pipeline_layout->set_layouts.size() <= instrumentation_desc_set_bind_index_) { + DispatchCmdBindDescriptorSets(cmd_buffer, bind_point, pipeline_layout_handle, instrumentation_desc_set_bind_index_, 1, + desc_sets.data(), 0, nullptr); } } else { // If no pipeline layout was bound when using shader objects that don't use any descriptor set, bind the debug pipeline // layout - DispatchCmdBindDescriptorSets(cmd_buffer, bind_point, GetDebugPipelineLayout(), desc_set_bind_index_, 1, desc_sets.data(), - 0, nullptr); + DispatchCmdBindDescriptorSets(cmd_buffer, bind_point, GetInstrumentationPipelineLayout(), + instrumentation_desc_set_bind_index_, 1, desc_sets.data(), 0, nullptr); } // Record buffer and memory info in CB state tracking cb_state->buffer_infos.emplace_back(output_block, desc_sets[0], desc_pool, bind_point, cb_state->action_command_count++); diff --git a/layers/gpu/instrumentation/gpu_shader_instrumentor.cpp b/layers/gpu/instrumentation/gpu_shader_instrumentor.cpp index f2373034ae2..c4f378df184 100644 --- a/layers/gpu/instrumentation/gpu_shader_instrumentor.cpp +++ b/layers/gpu/instrumentation/gpu_shader_instrumentor.cpp @@ -267,7 +267,7 @@ void GpuShaderInstrumentor::PostCreateDevice(const VkDeviceCreateInfo *pCreateIn std::min(gpu::kMaxAdjustedBoundDescriptorSet, phys_dev_props.limits.maxBoundDescriptorSets); // If gpu_validation_reserve_binding_slot: the max slot is where we reserved // else: always use the last possible set as least likely to be used - desc_set_bind_index_ = adjusted_max_desc_sets_limit - 1; + instrumentation_desc_set_bind_index_ = adjusted_max_desc_sets_limit - 1; // We can't do anything if there is only one. // Device probably not a legit Vulkan device, since there should be at least 4. Protect ourselves. @@ -289,7 +289,7 @@ void GpuShaderInstrumentor::PostCreateDevice(const VkDeviceCreateInfo *pCreateIn static_cast(instrumentation_bindings_.size()), instrumentation_bindings_.data()}; - result = DispatchCreateDescriptorSetLayout(device, &debug_desc_layout_info, nullptr, &debug_desc_layout_); + result = DispatchCreateDescriptorSetLayout(device, &debug_desc_layout_info, nullptr, &instrumentation_desc_layout_); if (result != VK_SUCCESS) { InternalError(device, loc, "vkCreateDescriptorSetLayout failed for internal descriptor set"); Cleanup(); @@ -306,10 +306,12 @@ void GpuShaderInstrumentor::PostCreateDevice(const VkDeviceCreateInfo *pCreateIn } std::vector debug_layouts; - for (uint32_t j = 0; j < desc_set_bind_index_; ++j) { + for (uint32_t j = 0; j < instrumentation_desc_set_bind_index_; ++j) { debug_layouts.push_back(dummy_desc_layout_); } - debug_layouts.push_back(debug_desc_layout_); + // #ARNO_TODO this last push_back looks wrong + debug_layouts.push_back(instrumentation_desc_layout_); + const VkPipelineLayoutCreateInfo debug_pipeline_layout_info = {VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, nullptr, 0u, @@ -317,7 +319,7 @@ void GpuShaderInstrumentor::PostCreateDevice(const VkDeviceCreateInfo *pCreateIn debug_layouts.data(), 0u, nullptr}; - result = DispatchCreatePipelineLayout(device, &debug_pipeline_layout_info, nullptr, &debug_pipeline_layout_); + result = DispatchCreatePipelineLayout(device, &debug_pipeline_layout_info, nullptr, &instrumentation_pipeline_layout_); if (result != VK_SUCCESS) { InternalError(device, loc, "vkCreateDescriptorSetLayout failed for internal pipeline layout"); Cleanup(); @@ -326,17 +328,18 @@ void GpuShaderInstrumentor::PostCreateDevice(const VkDeviceCreateInfo *pCreateIn } void GpuShaderInstrumentor::Cleanup() { - if (debug_desc_layout_) { - DispatchDestroyDescriptorSetLayout(device, debug_desc_layout_, nullptr); - debug_desc_layout_ = VK_NULL_HANDLE; + if (instrumentation_desc_layout_) { + DispatchDestroyDescriptorSetLayout(device, instrumentation_desc_layout_, nullptr); + instrumentation_desc_layout_ = VK_NULL_HANDLE; } if (dummy_desc_layout_) { DispatchDestroyDescriptorSetLayout(device, dummy_desc_layout_, nullptr); dummy_desc_layout_ = VK_NULL_HANDLE; } - if (debug_pipeline_layout_) { - DispatchDestroyPipelineLayout(device, debug_pipeline_layout_, nullptr); - debug_pipeline_layout_ = VK_NULL_HANDLE; + + if (instrumentation_pipeline_layout_) { + DispatchDestroyPipelineLayout(device, instrumentation_pipeline_layout_, nullptr); + instrumentation_pipeline_layout_ = VK_NULL_HANDLE; } } @@ -440,10 +443,10 @@ void GpuShaderInstrumentor::PreCallRecordCreatePipelineLayout(VkDevice device, c VkPipelineLayout *pPipelineLayout, const RecordObject &record_obj, chassis::CreatePipelineLayout &chassis_state) { if (gpuav_settings.shader_instrumentation_enabled) { - if (chassis_state.modified_create_info.setLayoutCount > desc_set_bind_index_) { + if (chassis_state.modified_create_info.setLayoutCount > instrumentation_desc_set_bind_index_) { std::ostringstream strm; strm << "pCreateInfo::setLayoutCount (" << chassis_state.modified_create_info.setLayoutCount - << ") will conflicts with validation's descriptor set at slot " << desc_set_bind_index_ << ". " + << ") will conflicts with validation's descriptor set at slot " << instrumentation_desc_set_bind_index_ << ". " << "This Pipeline Layout has too many descriptor sets that will not allow GPU shader instrumentation to be setup " "for " "pipelines created with it, therefor no validation error will be repored for them by GPU-AV at " @@ -454,15 +457,15 @@ void GpuShaderInstrumentor::PreCallRecordCreatePipelineLayout(VkDevice device, c // 1. Copying the caller's descriptor set desc_layouts // 2. Fill in dummy descriptor layouts up to the max binding // 3. Fill in with the debug descriptor layout at the max binding slot - chassis_state.new_layouts.reserve(desc_set_bind_index_ + 1); + chassis_state.new_layouts.reserve(instrumentation_desc_set_bind_index_ + 1); chassis_state.new_layouts.insert(chassis_state.new_layouts.end(), &pCreateInfo->pSetLayouts[0], &pCreateInfo->pSetLayouts[pCreateInfo->setLayoutCount]); - for (uint32_t i = pCreateInfo->setLayoutCount; i < desc_set_bind_index_; ++i) { + for (uint32_t i = pCreateInfo->setLayoutCount; i < instrumentation_desc_set_bind_index_; ++i) { chassis_state.new_layouts.push_back(dummy_desc_layout_); } - chassis_state.new_layouts.push_back(debug_desc_layout_); + chassis_state.new_layouts.push_back(instrumentation_desc_layout_); chassis_state.modified_create_info.pSetLayouts = chassis_state.new_layouts.data(); - chassis_state.modified_create_info.setLayoutCount = desc_set_bind_index_ + 1; + chassis_state.modified_create_info.setLayoutCount = instrumentation_desc_set_bind_index_ + 1; } } BaseClass::PreCallRecordCreatePipelineLayout(device, pCreateInfo, pAllocator, pPipelineLayout, record_obj, chassis_state); @@ -545,10 +548,10 @@ void GpuShaderInstrumentor::PreCallRecordCreateShadersEXT(VkDevice device, uint3 VkShaderCreateInfoEXT new_create_info = pCreateInfos[i]; auto &instrumentation_data = chassis_state.instrumentations_data[i]; - if (new_create_info.setLayoutCount > desc_set_bind_index_) { + if (new_create_info.setLayoutCount > instrumentation_desc_set_bind_index_) { std::ostringstream strm; strm << "pCreateInfos[" << i << "]::setLayoutCount (" << new_create_info.setLayoutCount - << ") will conflicts with validation's descriptor set at slot " << desc_set_bind_index_ << ". " + << ") will conflicts with validation's descriptor set at slot " << instrumentation_desc_set_bind_index_ << ". " << "This Shader Object has too many descriptor sets that will not allow GPU shader instrumentation to be setup " "for VkShaderEXT created with it, therefor no validation error will be repored for them by GPU-AV at " "runtime."; @@ -558,15 +561,15 @@ void GpuShaderInstrumentor::PreCallRecordCreateShadersEXT(VkDevice device, uint3 // 1. Copying the caller's descriptor set desc_layouts // 2. Fill in dummy descriptor layouts up to the max binding // 3. Fill in with the debug descriptor layout at the max binding slot - instrumentation_data.new_layouts.reserve(desc_set_bind_index_ + 1); + instrumentation_data.new_layouts.reserve(instrumentation_desc_set_bind_index_ + 1); instrumentation_data.new_layouts.insert(instrumentation_data.new_layouts.end(), pCreateInfos[i].pSetLayouts, &pCreateInfos[i].pSetLayouts[pCreateInfos[i].setLayoutCount]); - for (uint32_t j = pCreateInfos[i].setLayoutCount; j < desc_set_bind_index_; ++j) { + for (uint32_t j = pCreateInfos[i].setLayoutCount; j < instrumentation_desc_set_bind_index_; ++j) { instrumentation_data.new_layouts.push_back(dummy_desc_layout_); } - instrumentation_data.new_layouts.push_back(debug_desc_layout_); + instrumentation_data.new_layouts.push_back(instrumentation_desc_layout_); new_create_info.pSetLayouts = instrumentation_data.new_layouts.data(); - new_create_info.setLayoutCount = desc_set_bind_index_ + 1; + new_create_info.setLayoutCount = instrumentation_desc_set_bind_index_ + 1; } PreCallRecordShaderObjectInstrumentation(new_create_info, record_obj.location.dot(vvl::Field::pCreateInfos, i), @@ -972,11 +975,11 @@ bool GpuShaderInstrumentor::NeedPipelineCreationShaderInstrumentation(vvl::Pipel // If the app requests all available sets, the pipeline layout was not modified at pipeline layout creation and the // already instrumented shaders need to be replaced with uninstrumented shaders - if (pipeline_state.active_slots.find(desc_set_bind_index_) != pipeline_state.active_slots.end()) { + if (pipeline_state.active_slots.find(instrumentation_desc_set_bind_index_) != pipeline_state.active_slots.end()) { return false; } const auto pipeline_layout = pipeline_state.PipelineLayoutState(); - if (pipeline_layout && pipeline_layout->set_layouts.size() > desc_set_bind_index_) { + if (pipeline_layout && pipeline_layout->set_layouts.size() > instrumentation_desc_set_bind_index_) { return false; } @@ -1346,7 +1349,7 @@ bool GpuShaderInstrumentor::InstrumentShader(const vvl::span &in gpu::spirv::Settings module_settings{}; // Use the unique_shader_id as a shader ID so we can look up its handle later in the shader_map. module_settings.shader_id = unique_shader_id; - module_settings.output_buffer_descriptor_set = desc_set_bind_index_; + module_settings.output_buffer_descriptor_set = instrumentation_desc_set_bind_index_; module_settings.print_debug_info = gpuav_settings.debug_print_instrumentation_info; module_settings.max_instrumented_count = gpuav_settings.debug_max_instrumented_count; module_settings.support_int64 = enabled_features.shaderInt64; diff --git a/layers/gpu/instrumentation/gpu_shader_instrumentor.h b/layers/gpu/instrumentation/gpu_shader_instrumentor.h index ac9d89415b6..a2ff31a7c76 100644 --- a/layers/gpu/instrumentation/gpu_shader_instrumentor.h +++ b/layers/gpu/instrumentation/gpu_shader_instrumentor.h @@ -210,10 +210,9 @@ class GpuShaderInstrumentor : public ValidationStateTracker { bool InstrumentShader(const vvl::span &input_spirv, uint32_t unique_shader_id, bool has_bindless_descriptors, const Location &loc, std::vector &out_instrumented_spirv); - VkDescriptorSetLayout GetDebugDescriptorSetLayout() { return debug_desc_layout_; } - public: - VkPipelineLayout GetDebugPipelineLayout() { return debug_pipeline_layout_; } + VkDescriptorSetLayout GetInstrumentationDescriptorSetLayout() { return instrumentation_desc_layout_; } + VkPipelineLayout GetInstrumentationPipelineLayout() { return instrumentation_pipeline_layout_; } // When aborting we will disconnect all future chassis calls. // If we are deep into a call stack, we can use this to return up to the chassis call. @@ -224,7 +223,9 @@ class GpuShaderInstrumentor : public ValidationStateTracker { PFN_vkSetDeviceLoaderData vk_set_device_loader_data_; std::atomic unique_shader_module_id_ = 1; // zero represents no shader module found // The descriptor slot we will be injecting our error buffer into - uint32_t desc_set_bind_index_ = 0; + uint32_t instrumentation_desc_set_bind_index_ = 0; + // This is a layout used to "pad" a pipeline layout to fill in any gaps to the selected bind index + VkDescriptorSetLayout dummy_desc_layout_ = VK_NULL_HANDLE; VmaAllocator vma_allocator_ = {}; VmaPool output_buffer_pool_ = VK_NULL_HANDLE; std::unique_ptr desc_set_manager_; @@ -239,11 +240,9 @@ class GpuShaderInstrumentor : public ValidationStateTracker { private: void Cleanup(); - // This is a layout used to "pad" a pipeline layout to fill in any gaps to the selected bind index - VkDescriptorSetLayout dummy_desc_layout_ = VK_NULL_HANDLE; // These are objects used to inject our descriptor set into the command buffer - VkDescriptorSetLayout debug_desc_layout_ = VK_NULL_HANDLE; - VkPipelineLayout debug_pipeline_layout_ = VK_NULL_HANDLE; + VkDescriptorSetLayout instrumentation_desc_layout_ = VK_NULL_HANDLE; + VkPipelineLayout instrumentation_pipeline_layout_ = VK_NULL_HANDLE; // Make sure we call the right versions of any timeline semaphore functions. bool timeline_khr_{false}; diff --git a/layers/gpu/instrumentation/gpuav_instrumentation.cpp b/layers/gpu/instrumentation/gpuav_instrumentation.cpp index 47151934cca..b9fc0b327ff 100644 --- a/layers/gpu/instrumentation/gpuav_instrumentation.cpp +++ b/layers/gpu/instrumentation/gpuav_instrumentation.cpp @@ -25,8 +25,133 @@ namespace gpuav { -void SetupShaderInstrumentationResources(Validator &gpuav, CommandBuffer &cb_state, VkPipelineBindPoint bind_point, - const Location &loc) { +enum class PipelineLayoutSource { NoPipelineLayout, LastBoundPipeline, LastBoundDescriptorSet, LastPushedConstants }; +static PipelineLayoutSource GetInstrumentionDescSetBindingPipelineLayout( + Validator &gpuav, LvlBindPoint lv_bind_point, CommandBuffer &cb_state, const LastBound &last_bound, + std::shared_ptr &out_inst_desc_set_binding_pipe_layout_state) { + // If GPL is used, it's possible the pipeline layout used at pipeline creation time is null. If CmdBindDescriptorSets has + // not been called yet (i.e., state.pipeline_null), then fall back to the layout associated with pre-raster state, + // or the last specified pipeline layout in vkCmdPushConstantRanges. + // PipelineLayoutState should be used for the purposes of determining the number of sets in the layout, but this layout + // may be a "pseudo layout" used to represent the union of pre-raster and fragment shader layouts, and therefore have a + // null handle. + if (last_bound.pipeline_state && !last_bound.pipeline_state->PreRasterPipelineLayoutState()->Destroyed()) { + out_inst_desc_set_binding_pipe_layout_state = last_bound.pipeline_state->PreRasterPipelineLayoutState(); + return PipelineLayoutSource::LastBoundPipeline; + } else if (last_bound.desc_set_pipeline_layout) { + out_inst_desc_set_binding_pipe_layout_state = gpuav.Get(last_bound.desc_set_pipeline_layout); + return PipelineLayoutSource::LastBoundDescriptorSet; + } else if (cb_state.push_constant_latest_used_layout[lv_bind_point] != VK_NULL_HANDLE) { + out_inst_desc_set_binding_pipe_layout_state = + gpuav.Get(cb_state.push_constant_latest_used_layout[lv_bind_point]); + return PipelineLayoutSource::LastPushedConstants; + } + return PipelineLayoutSource::NoPipelineLayout; +} + +// If application is using shader objects, bindings count will be computed from bound shaders +static uint32_t GetBindingsCountFromLastBoundPipeline(Validator &gpuav, VkPipelineBindPoint bind_point, CommandBuffer &cb_state, + const LastBound &last_bound) { + if (last_bound.pipeline_state && last_bound.pipeline_state->PipelineLayoutState()) { + return static_cast(last_bound.pipeline_state->PipelineLayoutState()->set_layouts.size()); + } else if (last_bound.pipeline_state && last_bound.pipeline_state->PreRasterPipelineLayoutState()) { + return static_cast(last_bound.pipeline_state->PreRasterPipelineLayoutState()->set_layouts.size()); + } + + return last_bound.GetBoundShaderObjectsSetLayoutSize(bind_point); +} + +static std::shared_ptr GetLayoutFromLastBoundPipeline(Validator &gpuav, const LastBound &last_bound) { + if (last_bound.pipeline_state && last_bound.pipeline_state->PipelineLayoutState()) { + return last_bound.pipeline_state->PipelineLayoutState(); + } else if (last_bound.pipeline_state && last_bound.pipeline_state->PreRasterPipelineLayoutState()) { + return last_bound.pipeline_state->PreRasterPipelineLayoutState(); + } + return nullptr; +} + +static VkPipelineLayout CreateInstrumentationPipelineLayout(Validator &gpuav, VkPipelineBindPoint bind_point, const Location &loc, + const LastBound &last_bound, + VkDescriptorSetLayout dummy_desc_set_layout, + VkDescriptorSetLayout instrumentation_desc_set_layout, + uint32_t inst_desc_set_binding) { + // If not using shader objects, GPU-AV should be able to retrieve a pipeline layout from last bound pipeline + VkPipelineLayoutCreateInfo pipe_layout_ci = vku::InitStructHelper(); + if (auto last_bound_pipeline_pipe_layout = GetLayoutFromLastBoundPipeline(gpuav, last_bound)) { + pipe_layout_ci.flags = last_bound_pipeline_pipe_layout->create_flags; + std::vector ranges; + if (last_bound_pipeline_pipe_layout->push_constant_ranges_layout) { + ranges.reserve(last_bound_pipeline_pipe_layout->push_constant_ranges_layout->size()); + for (const VkPushConstantRange &range : *last_bound_pipeline_pipe_layout->push_constant_ranges_layout) { + ranges.push_back(range); + } + } + pipe_layout_ci.pushConstantRangeCount = static_cast(ranges.size()); + pipe_layout_ci.pPushConstantRanges = ranges.data(); + std::vector set_layouts; + set_layouts.reserve(inst_desc_set_binding + 1); + for (const auto &set_layout : last_bound_pipeline_pipe_layout->set_layouts) { + set_layouts.push_back(set_layout->VkHandle()); + } + for (uint32_t set_i = static_cast(last_bound_pipeline_pipe_layout->set_layouts.size()); + set_i < inst_desc_set_binding; ++set_i) { + set_layouts.push_back(dummy_desc_set_layout); + } + set_layouts.push_back(instrumentation_desc_set_layout); + pipe_layout_ci.setLayoutCount = static_cast(set_layouts.size()); + pipe_layout_ci.pSetLayouts = set_layouts.data(); + VkPipelineLayout pipe_layout_handle; + VkResult result = DispatchCreatePipelineLayout(gpuav.device, &pipe_layout_ci, VK_NULL_HANDLE, &pipe_layout_handle); + if (result != VK_SUCCESS) { + gpuav.InternalError(gpuav.device, loc, "Failed to create instrumentation pipeline layout"); + return VK_NULL_HANDLE; + } + + return pipe_layout_handle; + } else { + // Application is using shader objects, compose a pipeline layout from bound shaders; + + // #ARNO_TODO set flags according to last bound descriptor set's pipe layout + const auto [set_layouts, push_constants_layouts] = last_bound.GetBoundShaderObjectsLayoutInfo(bind_point); + + if (last_bound.desc_set_pipeline_layout) { + std::shared_ptr last_bound_desc_set_pipe_layout = + gpuav.Get(last_bound.desc_set_pipeline_layout); + if (last_bound_desc_set_pipe_layout) { + pipe_layout_ci.flags = last_bound_desc_set_pipe_layout->CreateFlags(); + } + } + std::vector set_layout_handles; + if (set_layouts) { + set_layout_handles.reserve(inst_desc_set_binding + 1); + for (const auto &set_layout : *set_layouts) { + set_layout_handles.push_back(set_layout->VkHandle()); + } + for (uint32_t set_i = static_cast(set_layouts->size()); set_i < inst_desc_set_binding; ++set_i) { + set_layout_handles.push_back(dummy_desc_set_layout); + } + set_layout_handles.push_back(instrumentation_desc_set_layout); + pipe_layout_ci.setLayoutCount = static_cast(set_layout_handles.size()); + pipe_layout_ci.pSetLayouts = set_layout_handles.data(); + } + + if (push_constants_layouts) { + pipe_layout_ci.pushConstantRangeCount = static_cast(push_constants_layouts->size()); + pipe_layout_ci.pPushConstantRanges = push_constants_layouts->data(); + } + VkPipelineLayout pipe_layout_handle; + VkResult result = DispatchCreatePipelineLayout(gpuav.device, &pipe_layout_ci, VK_NULL_HANDLE, &pipe_layout_handle); + if (result != VK_SUCCESS) { + gpuav.InternalError(gpuav.device, loc, "Failed to create instrumentation pipeline layout"); + return VK_NULL_HANDLE; + } + + return pipe_layout_handle; + } +} + +void PreCallSetupShaderInstrumentationResources(Validator &gpuav, CommandBuffer &cb_state, VkPipelineBindPoint bind_point, + const Location &loc) { if (!gpuav.gpuav_settings.shader_instrumentation_enabled) { return; } @@ -36,9 +161,8 @@ void SetupShaderInstrumentationResources(Validator &gpuav, CommandBuffer &cb_sta const auto lv_bind_point = ConvertToLvlBindPoint(bind_point); auto const &last_bound = cb_state.lastBound[lv_bind_point]; - const auto *pipeline_state = last_bound.pipeline_state; - if (!pipeline_state && !last_bound.HasShaderObjects()) { + if (!last_bound.pipeline_state && !last_bound.HasShaderObjects()) { gpuav.InternalError(cb_state.VkHandle(), loc, "Neither pipeline state nor shader object states were found."); return; } @@ -151,23 +275,9 @@ void SetupShaderInstrumentationResources(Validator &gpuav, CommandBuffer &cb_sta DispatchUpdateDescriptorSets(gpuav.device, static_cast(desc_writes.size()), desc_writes.data(), 0, nullptr); } - auto pipeline_layout = pipeline_state ? pipeline_state->PipelineLayoutState() - : gpuav.Get(last_bound.desc_set_pipeline_layout); - // If GPL is used, it's possible the pipeline layout used at pipeline creation time is null. If CmdBindDescriptorSets has - // not been called yet (i.e., state.pipeline_null), then fall back to the layout associated with pre-raster state, - // or the last specified pipeline layout in vkCmdPushConstantRanges. - // PipelineLayoutState should be used for the purposes of determining the number of sets in the layout, but this layout - // may be a "pseudo layout" used to represent the union of pre-raster and fragment shader layouts, and therefore have a - // null handle. - VkPipelineLayout pipeline_layout_handle = VK_NULL_HANDLE; - if (last_bound.desc_set_pipeline_layout) { - pipeline_layout_handle = last_bound.desc_set_pipeline_layout; - } else if (pipeline_state && !pipeline_state->PreRasterPipelineLayoutState()->Destroyed()) { - pipeline_layout_handle = pipeline_state->PreRasterPipelineLayoutState()->VkHandle(); - } else if (cb_state.push_constant_latest_used_layout[lv_bind_point] != VK_NULL_HANDLE) { - pipeline_layout_handle = cb_state.push_constant_latest_used_layout[lv_bind_point]; - pipeline_layout = gpuav.Get(pipeline_layout_handle); - } + std::shared_ptr inst_binding_pipe_layout_state; + const PipelineLayoutSource inst_binding_pipe_layout_src = + GetInstrumentionDescSetBindingPipelineLayout(gpuav, lv_bind_point, cb_state, last_bound, inst_binding_pipe_layout_state); uint32_t operation_index = 0; if (bind_point == VK_PIPELINE_BIND_POINT_GRAPHICS) @@ -177,33 +287,75 @@ void SetupShaderInstrumentationResources(Validator &gpuav, CommandBuffer &cb_sta else if (bind_point == VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR) operation_index = cb_state.trace_rays_index++; + const bool uses_shader_object = last_bound.pipeline_state == nullptr; + // TODO: Using cb_state.per_command_resources.size() is kind of a hack? Worth considering passing the resource index as a // parameter const uint32_t error_logger_i = static_cast(cb_state.per_command_error_loggers.size()); const std::array dynamic_offsets = { {operation_index * gpuav.indices_buffer_alignment_, error_logger_i * gpuav.indices_buffer_alignment_}}; - if (pipeline_layout && pipeline_layout_handle != VK_NULL_HANDLE) { - // If we were unable to use the layout because it overlaps with the instrumented set, don't dispatch anything or we will - // disturb the original bound set - if (pipeline_layout->set_layouts.size() <= gpuav.desc_set_bind_index_) { - DispatchCmdBindDescriptorSets(cb_state.VkHandle(), bind_point, pipeline_layout_handle, gpuav.desc_set_bind_index_, 1, - &instrumentation_desc_set, static_cast(dynamic_offsets.size()), - dynamic_offsets.data()); + if (inst_binding_pipe_layout_state) { + if (inst_binding_pipe_layout_state->set_layouts.size() <= gpuav.instrumentation_desc_set_bind_index_) { + switch (inst_binding_pipe_layout_src) { + case PipelineLayoutSource::NoPipelineLayout: + // should not get there, because inst_desc_set_binding_pipe_layout_state is not null + assert(false); + break; + case PipelineLayoutSource::LastBoundPipeline: + DispatchCmdBindDescriptorSets(cb_state.VkHandle(), bind_point, inst_binding_pipe_layout_state->VkHandle(), + gpuav.instrumentation_desc_set_bind_index_, 1, &instrumentation_desc_set, + static_cast(dynamic_offsets.size()), dynamic_offsets.data()); + break; + case PipelineLayoutSource::LastBoundDescriptorSet: + case PipelineLayoutSource::LastPushedConstants: { + // Currently bound pipeline/set of shader objects may have bindings that are not compatible with last + // bound descriptor sets: GPU-AV may create this incompatibility by adding its empty padding descriptor sets. + // To alleviate that, since we could not get a pipeline layout from last pipeline binding (it was either + // destroyed, or never has been created if using shader objects), a pipeline layout matching bindings of last + // bound pipeline or + // last bound shader objects is created and used. + // If will also be cached: heuristic is next action command will likely need the same. + + const uint32_t bindings_counts_from_last_pipeline = + GetBindingsCountFromLastBoundPipeline(gpuav, bind_point, cb_state, last_bound); + + // If the number of binding of the currently bound pipeline's layout (or the equivalent for shader objects) is + // less that the number of bindings in the pipeline layout used to bind descriptor sets, + // GPU-AV needs to create a temporary pipeline layout matching the the currently bound pipeline's layout + // to bind the instrumentation descriptor set + if (bindings_counts_from_last_pipeline < + static_cast(inst_binding_pipe_layout_state->set_layouts.size())) { + VkPipelineLayout instrumentation_pipe_layout = CreateInstrumentationPipelineLayout( + gpuav, bind_point, loc, last_bound, gpuav.dummy_desc_layout_, + gpuav.GetInstrumentationDescriptorSetLayout(), gpuav.instrumentation_desc_set_bind_index_); + + if (instrumentation_pipe_layout != VK_NULL_HANDLE) { + DispatchCmdBindDescriptorSets(cb_state.VkHandle(), bind_point, instrumentation_pipe_layout, + gpuav.instrumentation_desc_set_bind_index_, 1, &instrumentation_desc_set, + static_cast(dynamic_offsets.size()), dynamic_offsets.data()); + DispatchDestroyPipelineLayout(gpuav.device, instrumentation_pipe_layout, nullptr); + } else { + return; + } + } else { + // No incompatibility detected, safe to use pipeline layout for last bound descriptor set/push constants. + DispatchCmdBindDescriptorSets(cb_state.VkHandle(), bind_point, inst_binding_pipe_layout_state->VkHandle(), + gpuav.instrumentation_desc_set_bind_index_, 1, &instrumentation_desc_set, + static_cast(dynamic_offsets.size()), dynamic_offsets.data()); + } + } break; + } } else { - // Cannot setup instrumentation descriptor set, abort for this command + gpuav.InternalWarning(cb_state.Handle(), loc, + "Unable to bind instrumentation descriptor set, it would override application's bound set"); return; } } else { // If no pipeline layout was bound when using shader objects that don't use any descriptor set, and no push constants, bind - // the debug pipeline layout - DispatchCmdBindDescriptorSets(cb_state.VkHandle(), bind_point, gpuav.GetDebugPipelineLayout(), gpuav.desc_set_bind_index_, - 1, &instrumentation_desc_set, static_cast(dynamic_offsets.size()), - dynamic_offsets.data()); - } - - if (pipeline_state && pipeline_layout_handle == VK_NULL_HANDLE) { - gpuav.InternalError(cb_state.Handle(), loc, "Unable to find pipeline layout to bind debug descriptor set"); - return; + // the instrumentation pipeline layout + DispatchCmdBindDescriptorSets(cb_state.VkHandle(), bind_point, gpuav.GetInstrumentationPipelineLayout(), + gpuav.instrumentation_desc_set_bind_index_, 1, &instrumentation_desc_set, + static_cast(dynamic_offsets.size()), dynamic_offsets.data()); } // It is possible to have no descriptor sets bound, for example if using push constants. @@ -211,11 +363,11 @@ void SetupShaderInstrumentationResources(Validator &gpuav, CommandBuffer &cb_sta !cb_state.di_input_buffer_list.empty() ? uint32_t(cb_state.di_input_buffer_list.size()) - 1 : vvl::kU32Max; const bool uses_robustness = (gpuav.enabled_features.robustBufferAccess || gpuav.enabled_features.robustBufferAccess2 || - (pipeline_state && pipeline_state->uses_pipeline_robustness)); + (last_bound.pipeline_state && last_bound.pipeline_state->uses_pipeline_robustness)); CommandBuffer::ErrorLoggerFunc error_logger = [loc, desc_binding_index, desc_binding_list = &cb_state.di_input_buffer_list, cb_state_handle = cb_state.VkHandle(), bind_point, operation_index, - uses_shader_object = pipeline_state == nullptr, + uses_shader_object, uses_robustness](Validator &gpuav, const uint32_t *error_record, const LogObjectList &objlist) { bool skip = false; @@ -230,6 +382,57 @@ void SetupShaderInstrumentationResources(Validator &gpuav, CommandBuffer &cb_sta cb_state.per_command_error_loggers.emplace_back(error_logger); } +void PostCallSetupShaderInstrumentationResources(Validator &gpuav, CommandBuffer &cb_state, VkPipelineBindPoint bind_point, + const Location &loc) { + if (!gpuav.gpuav_settings.shader_instrumentation_enabled) { + return; + } + + assert(bind_point == VK_PIPELINE_BIND_POINT_GRAPHICS || bind_point == VK_PIPELINE_BIND_POINT_COMPUTE || + bind_point == VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR); + + const LvlBindPoint lv_bind_point = ConvertToLvlBindPoint(bind_point); + const LastBound &last_bound = cb_state.lastBound[lv_bind_point]; + + if (!last_bound.pipeline_state && !last_bound.HasShaderObjects()) { + gpuav.InternalError(cb_state.VkHandle(), loc, "Neither pipeline state nor shader object states were found."); + return; + } + + // Only need to rebind application desc sets if they have been disturbed by GPU-AV binding its instrumentation desc set. + // - Can happen if the pipeline layout used to bind instrumentation descriptor set is not compatible with the one used by the + // app to bind the last/all the last desc set. This pipeline layout is referred to as "last_bound_desc_set_pipe_layout_state" + // hereinafter. + // => We create this incompatibility when we add our empty descriptor set. + // See PositiveGpuAVDescriptorIndexing.SharedPipelineLayoutSubsetGraphics for instance + + if (last_bound.desc_set_pipeline_layout) { + std::shared_ptr last_bound_desc_set_pipe_layout_state = + gpuav.Get(last_bound.desc_set_pipeline_layout); + if (last_bound_desc_set_pipe_layout_state) { + uint32_t bindings_count = 0; + uint32_t first_set = 0; + + if (uint32_t bindings_counts_from_last_pipeline = + GetBindingsCountFromLastBoundPipeline(gpuav, bind_point, cb_state, last_bound); + bindings_counts_from_last_pipeline < + static_cast(last_bound_desc_set_pipe_layout_state->set_layouts.size())) { + bindings_count = static_cast(last_bound_desc_set_pipe_layout_state->set_layouts.size() - + bindings_counts_from_last_pipeline); + first_set = bindings_counts_from_last_pipeline; + } + for (uint32_t set_i = 0; set_i < bindings_count; ++set_i) { + const uint32_t last_bound_set_i = set_i + first_set; + VkDescriptorSet desc_set = last_bound.per_set[last_bound_set_i].bound_descriptor_set->VkHandle(); + const std::vector &dynamic_offset = last_bound.per_set[last_bound_set_i].dynamicOffsets; + const uint32_t dynamic_offset_count = static_cast(dynamic_offset.size()); + DispatchCmdBindDescriptorSets(cb_state.VkHandle(), bind_point, last_bound_desc_set_pipe_layout_state->VkHandle(), + last_bound_set_i, 1, &desc_set, dynamic_offset_count, dynamic_offset.data()); + } + } + } +} + bool LogMessageInstBindlessDescriptor(Validator &gpuav, const uint32_t *error_record, std::string &out_error_msg, std::string &out_vuid_msg, const std::vector &descriptor_sets, const Location &loc, bool uses_shader_object, bool &out_oob_access) { diff --git a/layers/gpu/instrumentation/gpuav_instrumentation.h b/layers/gpu/instrumentation/gpuav_instrumentation.h index 4f3b3728e29..214ba8d4a73 100644 --- a/layers/gpu/instrumentation/gpuav_instrumentation.h +++ b/layers/gpu/instrumentation/gpuav_instrumentation.h @@ -23,8 +23,11 @@ namespace gpuav { struct DescSetState; -void SetupShaderInstrumentationResources(Validator& gpuav, CommandBuffer& cmd_buffer, VkPipelineBindPoint bind_point, - const Location& loc); +void PreCallSetupShaderInstrumentationResources(Validator& gpuav, CommandBuffer& cb_state, VkPipelineBindPoint bind_point, + const Location& loc); + +void PostCallSetupShaderInstrumentationResources(Validator& gpuav, CommandBuffer& cb_statee, VkPipelineBindPoint bind_point, + const Location& loc); // Return true iff a error has been found bool LogInstrumentationError(Validator& gpuav, VkCommandBuffer cmd_buffer, const LogObjectList& objlist, uint32_t operation_index, diff --git a/layers/state_tracker/pipeline_state.cpp b/layers/state_tracker/pipeline_state.cpp index 16397f73965..6b11e2e4c87 100644 --- a/layers/state_tracker/pipeline_state.cpp +++ b/layers/state_tracker/pipeline_state.cpp @@ -1155,6 +1155,13 @@ vvl::ShaderObject *LastBound::GetShaderState(ShaderObjectStage stage) const { return shader_object_states[static_cast(stage)]; } +vvl::ShaderObject *LastBound::GetShaderStateIfValid(ShaderObjectStage stage) const { + if (!shader_object_bound[static_cast(stage)]) { + return nullptr; + } + return shader_object_states[static_cast(stage)]; +} + bool LastBound::HasShaderObjects() const { for (uint32_t i = 0; i < kShaderObjectStageCount; ++i) { if (GetShader(static_cast(i)) != VK_NULL_HANDLE) { @@ -1164,12 +1171,7 @@ bool LastBound::HasShaderObjects() const { return false; } -bool LastBound::IsValidShaderBound(ShaderObjectStage stage) const { - if (!shader_object_bound[static_cast(stage)]) { - return false; - } - return shader_object_states[static_cast(stage)] != nullptr; -} +bool LastBound::IsValidShaderBound(ShaderObjectStage stage) const { return GetShaderStateIfValid(stage) != nullptr; } bool LastBound::IsValidShaderOrNullBound(ShaderObjectStage stage) const { return shader_object_bound[static_cast(stage)]; @@ -1213,6 +1215,55 @@ bool LastBound::IsAnyGraphicsShaderBound() const { IsValidShaderBound(ShaderObjectStage::MESH); } +uint32_t LastBound::GetBoundShaderObjectsSetLayoutSize(VkPipelineBindPoint bind_point) const { + if (bind_point == VK_PIPELINE_BIND_POINT_COMPUTE) { + if (vvl::ShaderObject *cs = GetShaderStateIfValid(ShaderObjectStage::COMPUTE)) { + return static_cast(cs->set_layouts.size()); + } + } else if (bind_point == VK_PIPELINE_BIND_POINT_GRAPHICS) { + // VUID-vkCmdDraw-None-08878: + // - All bound graphics shader objects must have been created with identical or identically defined push constant ranges + // VUID-vkCmdDraw-None-08879 + // - All bound graphics shader objects must have been created with identical or identically defined arrays of descriptor set + // layouts + if (vvl::ShaderObject *vs = GetShaderStateIfValid(ShaderObjectStage::VERTEX)) { + return static_cast(vs->set_layouts.size()); + } + + if (vvl::ShaderObject *ms = GetShaderStateIfValid(ShaderObjectStage::MESH)) { + return static_cast(ms->set_layouts.size()); + } + return 0; + } + assert(false); + return 0; +} + +std::pair LastBound::GetBoundShaderObjectsLayoutInfo( + VkPipelineBindPoint bind_point) const { + if (bind_point == VK_PIPELINE_BIND_POINT_COMPUTE) { + if (vvl::ShaderObject *cs = GetShaderStateIfValid(ShaderObjectStage::COMPUTE)) { + return {&cs->set_layouts, cs->push_constant_ranges}; + } + } else if (bind_point == VK_PIPELINE_BIND_POINT_GRAPHICS) { + // VUID-vkCmdDraw-None-08878: + // - All bound graphics shader objects must have been created with identical or identically defined push constant ranges + // VUID-vkCmdDraw-None-08879 + // - All bound graphics shader objects must have been created with identical or identically defined arrays of descriptor set + // layouts + if (vvl::ShaderObject *vs = GetShaderStateIfValid(ShaderObjectStage::VERTEX)) { + return {&vs->set_layouts, vs->push_constant_ranges}; + } + + if (vvl::ShaderObject *ms = GetShaderStateIfValid(ShaderObjectStage::MESH)) { + return {&ms->set_layouts, ms->push_constant_ranges}; + } + return {nullptr, nullptr}; + } + assert(false); + return {nullptr, nullptr}; +} + bool LastBound::IsBoundSetCompatible(uint32_t set, const vvl::PipelineLayout &pipeline_layout) const { if ((set >= per_set.size()) || (set >= pipeline_layout.set_compat_ids.size())) { return false; diff --git a/layers/state_tracker/pipeline_state.h b/layers/state_tracker/pipeline_state.h index 5bc6065892c..2175fff7e31 100644 --- a/layers/state_tracker/pipeline_state.h +++ b/layers/state_tracker/pipeline_state.h @@ -26,6 +26,7 @@ #include "utils/shader_utils.h" #include "state_tracker/state_tracker.h" #include "state_tracker/shader_stage_state.h" +#include "state_tracker/shader_object_state.h" // Fwd declarations -- including descriptor_set.h creates an ugly include loop namespace vvl { @@ -36,7 +37,6 @@ class Descriptor; class RenderPass; class CommandBuffer; class Pipeline; -struct ShaderObject; struct ShaderModule; } // namespace vvl @@ -729,11 +729,15 @@ struct LastBound { bool ValidShaderObjectCombination(const VkPipelineBindPoint bind_point, const DeviceFeatures &device_features) const; VkShaderEXT GetShader(ShaderObjectStage stage) const; vvl::ShaderObject *GetShaderState(ShaderObjectStage stage) const; + vvl::ShaderObject *GetShaderStateIfValid(ShaderObjectStage stage) const; bool HasShaderObjects() const; bool IsValidShaderBound(ShaderObjectStage stage) const; bool IsValidShaderOrNullBound(ShaderObjectStage stage) const; std::vector GetAllBoundGraphicsShaders(); bool IsAnyGraphicsShaderBound() const; + uint32_t GetBoundShaderObjectsSetLayoutSize(VkPipelineBindPoint bind_point) const; + std::pair GetBoundShaderObjectsLayoutInfo( + VkPipelineBindPoint bind_point) const; bool IsBoundSetCompatible(uint32_t set, const vvl::PipelineLayout &pipeline_layout) const; bool IsBoundSetCompatible(uint32_t set, const vvl::ShaderObject &shader_object_state) const; diff --git a/tests/unit/gpu_av.cpp b/tests/unit/gpu_av.cpp index 69a7e9d2f67..14fd892bb16 100644 --- a/tests/unit/gpu_av.cpp +++ b/tests/unit/gpu_av.cpp @@ -18,30 +18,6 @@ class NegativeGpuAV : public GpuAVTest {}; -TEST_F(NegativeGpuAV, DestroyedPipelineLayout) { - TEST_DESCRIPTION("Check if can catch pipeline layout not being bound"); - RETURN_IF_SKIP(InitGpuAvFramework()); - RETURN_IF_SKIP(InitState()); - InitRenderTarget(); - - // Destroy pipeline layout after creating pipeline - CreatePipelineHelper pipe(*this); - { - const vkt::PipelineLayout doomed_pipeline_layout(*m_device); - pipe.gp_ci_.layout = doomed_pipeline_layout.handle(); - pipe.CreateGraphicsPipeline(); - } - - m_commandBuffer->begin(); - vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.Handle()); - m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo); - m_errorMonitor->SetDesiredError("Unable to find pipeline layout to bind debug descriptor set"); - vk::CmdDraw(m_commandBuffer->handle(), 3, 1, 0, 0); - m_errorMonitor->VerifyFound(); - m_commandBuffer->EndRenderPass(); - m_commandBuffer->end(); -} - TEST_F(NegativeGpuAV, ValidationAbort) { TEST_DESCRIPTION("GPU validation: Verify that aborting GPU-AV is safe."); RETURN_IF_SKIP(InitGpuAvFramework()); diff --git a/tests/unit/gpu_av_descriptor_indexing.cpp b/tests/unit/gpu_av_descriptor_indexing.cpp index 41880e6a52a..4e921cd3772 100644 --- a/tests/unit/gpu_av_descriptor_indexing.cpp +++ b/tests/unit/gpu_av_descriptor_indexing.cpp @@ -2569,3 +2569,51 @@ TEST_F(NegativeGpuAVDescriptorIndexing, BindingOOB) { m_default_queue->Wait(); m_errorMonitor->VerifyFound(); } + +TEST_F(NegativeGpuAVDescriptorIndexing, DestroyedPipelineLayout) { + RETURN_IF_SKIP(InitGpuAvFramework()); + RETURN_IF_SKIP(InitState()); + InitRenderTarget(); + + static const char vertshader[] = R"glsl( + #version 450 + layout(set = 0, binding = 0) buffer StorageBuffer { uint x[]; }; + void main() { + x[1234] = 0; + } + )glsl"; + VkShaderObj vs(this, vertshader, VK_SHADER_STAGE_VERTEX_BIT); + + vkt::Buffer buffer(*m_device, 64, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + OneOffDescriptorSet descriptor_set(m_device, {{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}}); + descriptor_set.WriteDescriptorBufferInfo(0, buffer.handle(), 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); + descriptor_set.UpdateDescriptorSets(); + const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_}); + CreatePipelineHelper pipe1(*this); + pipe1.shader_stages_[0] = vs.GetStageCreateInfo(); + pipe1.gp_ci_.layout = pipeline_layout.handle(); + pipe1.CreateGraphicsPipeline(); + + // Destroy pipeline layout after creating pipeline + CreatePipelineHelper pipe2(*this); + { + const vkt::PipelineLayout doomed_pipeline_layout(*m_device); + pipe2.gp_ci_.layout = doomed_pipeline_layout.handle(); + pipe2.CreateGraphicsPipeline(); + } + + m_commandBuffer->begin(); + vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe2.Handle()); + m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo); + // We will create a fake pipeline layout underneath here + vk::CmdDraw(m_commandBuffer->handle(), 3, 1, 0, 0); + + vk::CmdBindDescriptorSets(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout.handle(), 0, 1, + &descriptor_set.set_, 0, nullptr); + vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe1.Handle()); + vk::CmdDraw(m_commandBuffer->handle(), 3, 1, 0, 0); + + m_commandBuffer->EndRenderPass(); + m_commandBuffer->end(); +} diff --git a/tests/unit/gpu_av_descriptor_indexing_positive.cpp b/tests/unit/gpu_av_descriptor_indexing_positive.cpp index a544e8bac76..268bd170d05 100644 --- a/tests/unit/gpu_av_descriptor_indexing_positive.cpp +++ b/tests/unit/gpu_av_descriptor_indexing_positive.cpp @@ -1031,4 +1031,490 @@ TEST_F(PositiveGpuAVDescriptorIndexing, PartialBoundDescriptorSSBO) { m_default_queue->Submit(*m_commandBuffer); m_default_queue->Wait(); -} \ No newline at end of file +} + +TEST_F(PositiveGpuAVDescriptorIndexing, SharedPipelineLayoutSubsetCompute) { + TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/8377"); + RETURN_IF_SKIP(InitGpuVUDescriptorIndexing()); + + VkDescriptorBindingFlags binding_flags = VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT; + VkDescriptorSetLayoutBindingFlagsCreateInfo flags_create_info = vku::InitStructHelper(); + flags_create_info.bindingCount = 1; + flags_create_info.pBindingFlags = &binding_flags; + + const VkDescriptorSetLayoutBinding binding{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}; + vkt::DescriptorSetLayout dsl2(*m_device, binding, VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT, + &flags_create_info); + vkt::DescriptorSetLayout dsl1(*m_device, binding, VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT, + &flags_create_info); + VkDescriptorSetLayout set_layouts[2] = {dsl1.handle(), dsl2.handle()}; + + VkPipelineLayoutCreateInfo pipeline_layout_ci = vku::InitStructHelper(); + pipeline_layout_ci.pSetLayouts = set_layouts; + + pipeline_layout_ci.setLayoutCount = 1; + const vkt::PipelineLayout pipeline_layout_1(*m_device, pipeline_layout_ci); + pipeline_layout_ci.setLayoutCount = 2; + const vkt::PipelineLayout pipeline_layout_2(*m_device, pipeline_layout_ci); + + char const *source_1 = R"glsl( + #version 450 + layout(set = 0, binding = 0) buffer foo_0 { int a; int b;}; + void main() { + a = b; + } + )glsl"; + char const *source_2 = R"glsl( + #version 450 + layout(set = 0, binding = 0) buffer foo_0 { int a; }; + layout(set = 1, binding = 0) buffer foo_1 { int b; }; + void main() { + a = b; + } + )glsl"; + + CreateComputePipelineHelper pipe1(*this); + pipe1.cs_ = std::make_unique(this, source_1, VK_SHADER_STAGE_COMPUTE_BIT); + pipe1.cp_ci_.layout = pipeline_layout_1.handle(); + pipe1.CreateComputePipeline(); + + CreateComputePipelineHelper pipe2(*this); + pipe2.cs_ = std::make_unique(this, source_2, VK_SHADER_STAGE_COMPUTE_BIT); + pipe2.cp_ci_.layout = pipeline_layout_2.handle(); + pipe2.CreateComputePipeline(); + + VkDescriptorPoolSize pool_size = {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 2}; + VkDescriptorPoolCreateInfo ds_pool_ci = vku::InitStructHelper(); + ds_pool_ci.flags = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT; + ds_pool_ci.maxSets = 2; + ds_pool_ci.poolSizeCount = 1; + ds_pool_ci.pPoolSizes = &pool_size; + vkt::DescriptorPool pool(*m_device, ds_pool_ci); + + VkDescriptorSetAllocateInfo allocate_info = vku::InitStructHelper(); + allocate_info.descriptorPool = pool.handle(); + allocate_info.descriptorSetCount = 2; + allocate_info.pSetLayouts = set_layouts; + + VkDescriptorSet descriptor_sets[2]; + vk::AllocateDescriptorSets(device(), &allocate_info, descriptor_sets); + + vkt::Buffer buffer(*m_device, 32, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); + VkDescriptorBufferInfo buffer_info = {buffer.handle(), 0, VK_WHOLE_SIZE}; + + VkWriteDescriptorSet descriptor_writes[2]; + descriptor_writes[0] = vku::InitStructHelper(); + descriptor_writes[0].dstSet = descriptor_sets[0]; + descriptor_writes[0].dstBinding = 0; + descriptor_writes[0].descriptorCount = 1; + descriptor_writes[0].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + descriptor_writes[0].pBufferInfo = &buffer_info; + descriptor_writes[1] = vku::InitStructHelper(); + descriptor_writes[1].dstSet = descriptor_sets[1]; + descriptor_writes[1].dstBinding = 0; + descriptor_writes[1].descriptorCount = 1; + descriptor_writes[1].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + descriptor_writes[1].pBufferInfo = &buffer_info; + vk::UpdateDescriptorSets(device(), 2, descriptor_writes, 0, nullptr); + + VkCommandBufferBeginInfo begin_info = vku::InitStructHelper(); + m_commandBuffer->begin(&begin_info); + + vk::CmdBindDescriptorSets(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout_2.handle(), 0, 2, + descriptor_sets, 0, nullptr); + + vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_COMPUTE, pipe2.Handle()); + vk::CmdDispatch(m_commandBuffer->handle(), 1, 1, 1); + + vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_COMPUTE, pipe1.Handle()); + vk::CmdDispatch(m_commandBuffer->handle(), 1, 1, 1); + + vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_COMPUTE, pipe2.Handle()); + vk::CmdDispatch(m_commandBuffer->handle(), 1, 1, 1); + + m_commandBuffer->end(); + m_default_queue->Submit(*m_commandBuffer); + m_default_queue->Wait(); +} + +TEST_F(PositiveGpuAVDescriptorIndexing, SharedPipelineLayoutSubsetGraphics) { + TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/8377"); + RETURN_IF_SKIP(InitGpuVUDescriptorIndexing()); + InitRenderTarget(); + + // Create 2 pipeline layouts. Pipeline layout 2 starts the same as pipeline layout 1, with one descriptor set, + // but one more descriptor set is added to it, for a total of 2. + // Hence, it is valid to bind all descriptor slots from pipeline layout 2, + // but use a pipeline create with pipeline layout 1 for rendering. + // BUT, + // since GPU-AV adds empty descriptor sets to pipeline layouts before adding the + // instrumentation descriptor set, it creates an incompatibility between pipeline + // layout 1 and 2 at the binding index 1: pipeline layout 1 has one empty descriptor set, + // and pipeline layout 2 as an application defined descriptor set. + // GPU-AV has to take care of this incompatibility, by picking the right pipeline layout to + // bind its instrumentation descriptor set to, and by correctly restoring disturbed application + // defined descriptor set bindings. + + VkDescriptorBindingFlags binding_flags = VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT; + VkDescriptorSetLayoutBindingFlagsCreateInfo flags_create_info = vku::InitStructHelper(); + flags_create_info.bindingCount = 1; + flags_create_info.pBindingFlags = &binding_flags; + + const VkDescriptorSetLayoutBinding binding{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}; + + vkt::DescriptorSetLayout dsl_1(*m_device, binding, VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT, + &flags_create_info); + + std::array set_layouts = {dsl_1.handle(), dsl_1.handle()}; + + VkPipelineLayoutCreateInfo pipeline_layout_ci = vku::InitStructHelper(); + pipeline_layout_ci.pSetLayouts = set_layouts.data(); + + pipeline_layout_ci.setLayoutCount = 1; + auto pipeline_layout_1 = std::make_unique(*m_device, pipeline_layout_ci); + pipeline_layout_ci.setLayoutCount = 2; + const vkt::PipelineLayout pipeline_layout_2(*m_device, pipeline_layout_ci); + + char const *vs_source_1 = R"glsl( + #version 450 + layout(set = 0, binding = 0) buffer foo_0 { int a; int b;}; + void main() { + a = b; + } + )glsl"; + char const *vs_source_2 = R"glsl( + #version 450 + layout(set = 0, binding = 0) buffer foo_0 { int a; }; + layout(set = 1, binding = 0) buffer foo_1 { int b; }; + void main() { + a = b; + } + )glsl"; + VkShaderObj vs_1(this, vs_source_1, VK_SHADER_STAGE_VERTEX_BIT); + VkShaderObj vs_2(this, vs_source_2, VK_SHADER_STAGE_VERTEX_BIT); + + CreatePipelineHelper pipe_1(*this); + pipe_1.shader_stages_ = {vs_1.GetStageCreateInfo(), pipe_1.fs_->GetStageCreateInfo()}; + pipe_1.gp_ci_.layout = pipeline_layout_1->handle(); + pipe_1.CreateGraphicsPipeline(); + pipeline_layout_1 = nullptr; + + CreatePipelineHelper pipe_2(*this); + pipe_2.shader_stages_ = {vs_2.GetStageCreateInfo(), pipe_2.fs_->GetStageCreateInfo()}; + pipe_2.gp_ci_.layout = pipeline_layout_2.handle(); + pipe_2.CreateGraphicsPipeline(); + + VkDescriptorPoolSize pool_size = {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 2}; + VkDescriptorPoolCreateInfo ds_pool_ci = vku::InitStructHelper(); + ds_pool_ci.flags = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT; + ds_pool_ci.maxSets = 2; + ds_pool_ci.poolSizeCount = 1; + ds_pool_ci.pPoolSizes = &pool_size; + vkt::DescriptorPool pool(*m_device, ds_pool_ci); + + VkDescriptorSetAllocateInfo allocate_info = vku::InitStructHelper(); + allocate_info.descriptorPool = pool.handle(); + allocate_info.descriptorSetCount = 2; + allocate_info.pSetLayouts = set_layouts.data(); + + std::array descriptor_sets{}; + vk::AllocateDescriptorSets(device(), &allocate_info, descriptor_sets.data()); + + vkt::Buffer buffer(*m_device, 32, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); + VkDescriptorBufferInfo buffer_info = {buffer.handle(), 0, VK_WHOLE_SIZE}; + + VkWriteDescriptorSet descriptor_writes[2]; + descriptor_writes[0] = vku::InitStructHelper(); + descriptor_writes[0].dstSet = descriptor_sets[0]; + descriptor_writes[0].dstBinding = 0; + descriptor_writes[0].descriptorCount = 1; + descriptor_writes[0].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + descriptor_writes[0].pBufferInfo = &buffer_info; + descriptor_writes[1] = vku::InitStructHelper(); + descriptor_writes[1].dstSet = descriptor_sets[1]; + descriptor_writes[1].dstBinding = 0; + descriptor_writes[1].descriptorCount = 1; + descriptor_writes[1].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + descriptor_writes[1].pBufferInfo = &buffer_info; + vk::UpdateDescriptorSets(device(), 2, descriptor_writes, 0, nullptr); + + VkCommandBufferBeginInfo begin_info = vku::InitStructHelper(); + m_commandBuffer->begin(&begin_info); + m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo); + + vk::CmdBindDescriptorSets(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout_2.handle(), 0, 2, + descriptor_sets.data(), 0, nullptr); + + vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe_2.Handle()); + vk::CmdDraw(m_commandBuffer->handle(), 3, 1, 0, 0); + vk::CmdDraw(m_commandBuffer->handle(), 3, 1, 0, 0); + + vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe_1.Handle()); + vk::CmdDraw(m_commandBuffer->handle(), 3, 1, 0, 0); + vk::CmdDraw(m_commandBuffer->handle(), 3, 1, 0, 0); + + vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe_2.Handle()); + vk::CmdDraw(m_commandBuffer->handle(), 3, 1, 0, 0); + vk::CmdDraw(m_commandBuffer->handle(), 3, 1, 0, 0); + + m_commandBuffer->EndRenderPass(); + m_commandBuffer->end(); + m_default_queue->Submit(*m_commandBuffer); + m_default_queue->Wait(); +} + +TEST_F(PositiveGpuAVDescriptorIndexing, SharedPipelineLayoutSubsetGraphicsGPL) { + TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/8377"); + + AddRequiredExtensions(VK_EXT_GRAPHICS_PIPELINE_LIBRARY_EXTENSION_NAME); + AddRequiredFeature(vkt::Feature::graphicsPipelineLibrary); + RETURN_IF_SKIP(InitGpuVUDescriptorIndexing()); + InitRenderTarget(); + + // Create 2 pipeline layouts. Pipeline layout 2 starts the same as pipeline layout 1, with one descriptor set, + // but one more descriptor set is added to it, for a total of 2. + // Hence, it is valid to bind all descriptor slots from pipeline layout 2, + // but use a pipeline create with pipeline layout 1 for rendering. + // BUT, + // since GPU-AV adds empty descriptor sets to pipeline layouts before adding the + // instrumentation descriptor set, it creates an incompatibility between pipeline + // layout 1 and 2 at the binding index 1: pipeline layout 1 has one empty descriptor set, + // and pipeline layout 2 as an application defined descriptor set. + // GPU-AV has to take care of this incompatibility, by picking the right pipeline layout to + // bind its instrumentation descriptor set to, and by correctly restoring disturbed application + // defined descriptor set bindings. + + VkDescriptorBindingFlags binding_flags = VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT; + VkDescriptorSetLayoutBindingFlagsCreateInfo flags_create_info = vku::InitStructHelper(); + flags_create_info.bindingCount = 1; + flags_create_info.pBindingFlags = &binding_flags; + + const VkDescriptorSetLayoutBinding binding{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}; + + vkt::DescriptorSetLayout dsl_1(*m_device, binding, VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT, + &flags_create_info); + + std::array set_layouts = {dsl_1.handle(), dsl_1.handle()}; + + VkPipelineLayoutCreateInfo pipeline_layout_ci = vku::InitStructHelper(); + pipeline_layout_ci.pSetLayouts = set_layouts.data(); + + pipeline_layout_ci.setLayoutCount = 1; + const vkt::PipelineLayout pipeline_layout_1(*m_device, pipeline_layout_ci); + pipeline_layout_ci.setLayoutCount = 2; + const vkt::PipelineLayout pipeline_layout_2(*m_device, pipeline_layout_ci); + + char const *vs_source_1 = R"glsl( + #version 450 + layout(set = 0, binding = 0) buffer foo_0 { int a; int b;}; + void main() { + a = b; + } + )glsl"; + char const *vs_source_2 = R"glsl( + #version 450 + layout(set = 0, binding = 0) buffer foo_0 { int a; }; + layout(set = 1, binding = 0) buffer foo_1 { int b; }; + void main() { + a = b; + } + )glsl"; + + vkt::SimpleGPL pipe_1(*this, pipeline_layout_1.handle(), vs_source_1); + + vkt::SimpleGPL pipe_2(*this, pipeline_layout_2.handle(), vs_source_2); + + VkDescriptorPoolSize pool_size = {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 2}; + VkDescriptorPoolCreateInfo ds_pool_ci = vku::InitStructHelper(); + ds_pool_ci.flags = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT; + ds_pool_ci.maxSets = 2; + ds_pool_ci.poolSizeCount = 1; + ds_pool_ci.pPoolSizes = &pool_size; + vkt::DescriptorPool pool(*m_device, ds_pool_ci); + + VkDescriptorSetAllocateInfo allocate_info = vku::InitStructHelper(); + allocate_info.descriptorPool = pool.handle(); + allocate_info.descriptorSetCount = 2; + allocate_info.pSetLayouts = set_layouts.data(); + + std::array descriptor_sets{}; + vk::AllocateDescriptorSets(device(), &allocate_info, descriptor_sets.data()); + + vkt::Buffer buffer(*m_device, 32, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); + VkDescriptorBufferInfo buffer_info = {buffer.handle(), 0, VK_WHOLE_SIZE}; + + VkWriteDescriptorSet descriptor_writes[2]; + descriptor_writes[0] = vku::InitStructHelper(); + descriptor_writes[0].dstSet = descriptor_sets[0]; + descriptor_writes[0].dstBinding = 0; + descriptor_writes[0].descriptorCount = 1; + descriptor_writes[0].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + descriptor_writes[0].pBufferInfo = &buffer_info; + descriptor_writes[1] = vku::InitStructHelper(); + descriptor_writes[1].dstSet = descriptor_sets[1]; + descriptor_writes[1].dstBinding = 0; + descriptor_writes[1].descriptorCount = 1; + descriptor_writes[1].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + descriptor_writes[1].pBufferInfo = &buffer_info; + vk::UpdateDescriptorSets(device(), 2, descriptor_writes, 0, nullptr); + + VkCommandBufferBeginInfo begin_info = vku::InitStructHelper(); + m_commandBuffer->begin(&begin_info); + m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo); + + vk::CmdBindDescriptorSets(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout_2.handle(), 0, 2, + descriptor_sets.data(), 0, nullptr); + + vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe_2.Handle()); + vk::CmdDraw(m_commandBuffer->handle(), 3, 1, 0, 0); + vk::CmdDraw(m_commandBuffer->handle(), 3, 1, 0, 0); + + vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe_1.Handle()); + vk::CmdDraw(m_commandBuffer->handle(), 3, 1, 0, 0); + vk::CmdDraw(m_commandBuffer->handle(), 3, 1, 0, 0); + + vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe_2.Handle()); + vk::CmdDraw(m_commandBuffer->handle(), 3, 1, 0, 0); + vk::CmdDraw(m_commandBuffer->handle(), 3, 1, 0, 0); + + m_commandBuffer->EndRenderPass(); + m_commandBuffer->end(); + m_default_queue->Submit(*m_commandBuffer); + m_default_queue->Wait(); +} + +TEST_F(PositiveGpuAVDescriptorIndexing, SharedPipelineLayoutSubsetGraphicsShaderObject) { + TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/8377"); + AddRequiredExtensions(VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME); + AddRequiredExtensions(VK_EXT_SHADER_OBJECT_EXTENSION_NAME); + AddRequiredFeature(vkt::Feature::dynamicRendering); + AddRequiredFeature(vkt::Feature::shaderObject); + RETURN_IF_SKIP(InitGpuVUDescriptorIndexing()); + InitDynamicRenderTarget(); + + // Create 2 pipeline layouts. Pipeline layout 2 starts the same as pipeline layout 1, with one descriptor set, + // but one more descriptor set is added to it, for a total of 2. + // Hence, it is valid to bind all descriptor slots from pipeline layout 2, + // but use a pipeline create with pipeline layout 1 for rendering. + // BUT, + // since GPU-AV adds empty descriptor sets to pipeline layouts before adding the + // instrumentation descriptor set, it creates an incompatibility between pipeline + // layout 1 and 2 at the binding index 1: pipeline layout 1 has one empty descriptor set, + // and pipeline layout 2 as an application defined descriptor set. + // GPU-AV has to take care of this incompatibility, by picking the right pipeline layout to + // bind its instrumentation descriptor set to, and by correctly restoring disturbed application + // defined descriptor set bindings. + + VkDescriptorBindingFlags binding_flags = VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT; + VkDescriptorSetLayoutBindingFlagsCreateInfo flags_create_info = vku::InitStructHelper(); + flags_create_info.bindingCount = 1; + flags_create_info.pBindingFlags = &binding_flags; + + const VkDescriptorSetLayoutBinding binding{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}; + + vkt::DescriptorSetLayout dsl_1(*m_device, binding, VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT, + &flags_create_info); + + std::array set_layouts = {dsl_1.handle(), dsl_1.handle()}; + + VkPipelineLayoutCreateInfo pipeline_layout_ci = vku::InitStructHelper(); + pipeline_layout_ci.pSetLayouts = set_layouts.data(); + + pipeline_layout_ci.setLayoutCount = 2; + const vkt::PipelineLayout pipeline_layout_2(*m_device, pipeline_layout_ci); + + char const *vs_source_1 = R"glsl( + #version 450 + layout(set = 0, binding = 0) buffer foo_0 { int a; int b;}; + void main() { + a = b; + } + )glsl"; + const std::vector vs_spv_1 = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, vs_source_1); + char const *vs_source_2 = R"glsl( + #version 450 + layout(set = 0, binding = 0) buffer foo_0 { int a; }; + layout(set = 1, binding = 0) buffer foo_1 { int b; }; + void main() { + a = b; + } + )glsl"; + const std::vector vs_spv_2 = GLSLToSPV(VK_SHADER_STAGE_VERTEX_BIT, vs_source_2); + + VkShaderCreateInfoEXT shader_obj_ci = vku::InitStructHelper(); + shader_obj_ci.stage = VK_SHADER_STAGE_VERTEX_BIT; + shader_obj_ci.codeType = VK_SHADER_CODE_TYPE_SPIRV_EXT; + shader_obj_ci.codeSize = vs_spv_1.size() * sizeof(uint32_t); + shader_obj_ci.pCode = vs_spv_1.data(); + shader_obj_ci.pName = "main"; + shader_obj_ci.setLayoutCount = 1u; + shader_obj_ci.pSetLayouts = set_layouts.data(); + vkt::Shader vs_1(*m_device, shader_obj_ci); + shader_obj_ci.codeSize = vs_spv_2.size() * sizeof(uint32_t); + shader_obj_ci.pCode = vs_spv_2.data(); + shader_obj_ci.setLayoutCount = 2u; + vkt::Shader vs_2(*m_device, shader_obj_ci); + + const std::array 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 std::array shaders_1 = {{vs_1.handle(), VK_NULL_HANDLE, VK_NULL_HANDLE, VK_NULL_HANDLE, VK_NULL_HANDLE}}; + const std::array shaders_2 = {{vs_2.handle(), VK_NULL_HANDLE, VK_NULL_HANDLE, VK_NULL_HANDLE, VK_NULL_HANDLE}}; + + VkDescriptorPoolSize pool_size = {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 2}; + VkDescriptorPoolCreateInfo ds_pool_ci = vku::InitStructHelper(); + ds_pool_ci.flags = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT; + ds_pool_ci.maxSets = 2; + ds_pool_ci.poolSizeCount = 1; + ds_pool_ci.pPoolSizes = &pool_size; + vkt::DescriptorPool pool(*m_device, ds_pool_ci); + + VkDescriptorSetAllocateInfo allocate_info = vku::InitStructHelper(); + allocate_info.descriptorPool = pool.handle(); + allocate_info.descriptorSetCount = 2; + allocate_info.pSetLayouts = set_layouts.data(); + + std::array descriptor_sets{}; + vk::AllocateDescriptorSets(device(), &allocate_info, descriptor_sets.data()); + + vkt::Buffer buffer(*m_device, 32, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); + VkDescriptorBufferInfo buffer_info = {buffer.handle(), 0, VK_WHOLE_SIZE}; + + VkWriteDescriptorSet descriptor_writes[2]; + descriptor_writes[0] = vku::InitStructHelper(); + descriptor_writes[0].dstSet = descriptor_sets[0]; + descriptor_writes[0].dstBinding = 0; + descriptor_writes[0].descriptorCount = 1; + descriptor_writes[0].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + descriptor_writes[0].pBufferInfo = &buffer_info; + descriptor_writes[1] = vku::InitStructHelper(); + descriptor_writes[1].dstSet = descriptor_sets[1]; + descriptor_writes[1].dstBinding = 0; + descriptor_writes[1].descriptorCount = 1; + descriptor_writes[1].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + descriptor_writes[1].pBufferInfo = &buffer_info; + vk::UpdateDescriptorSets(device(), 2, descriptor_writes, 0, nullptr); + + VkCommandBufferBeginInfo begin_info = vku::InitStructHelper(); + m_commandBuffer->begin(&begin_info); + m_commandBuffer->BeginRenderingColor(GetDynamicRenderTarget(), GetRenderTargetArea()); + + vk::CmdBindDescriptorSets(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout_2.handle(), 0, 2, + descriptor_sets.data(), 0, nullptr); + + vk::CmdBindShadersEXT(m_commandBuffer->handle(), size32(stages), stages.data(), shaders_2.data()); + SetDefaultDynamicStatesAll(m_commandBuffer->handle()); + + vk::CmdDraw(m_commandBuffer->handle(), 3, 1, 0, 0); + + vk::CmdBindShadersEXT(m_commandBuffer->handle(), size32(stages), stages.data(), shaders_1.data()); + vk::CmdDraw(m_commandBuffer->handle(), 3, 1, 0, 0); + + vk::CmdBindShadersEXT(m_commandBuffer->handle(), size32(stages), stages.data(), shaders_2.data()); + vk::CmdDraw(m_commandBuffer->handle(), 3, 1, 0, 0); + + m_commandBuffer->EndRendering(); + m_commandBuffer->end(); + m_default_queue->Submit(*m_commandBuffer); + m_default_queue->Wait(); +} diff --git a/tests/unit/gpu_av_positive.cpp b/tests/unit/gpu_av_positive.cpp index e7abbf23989..390bd682453 100644 --- a/tests/unit/gpu_av_positive.cpp +++ b/tests/unit/gpu_av_positive.cpp @@ -1730,3 +1730,143 @@ TEST_F(PositiveGpuAV, PipelineLayoutMixing) { m_default_queue->Submit(*m_commandBuffer); m_default_queue->Wait(); } + +TEST_F(PositiveGpuAV, SharedPipelineLayoutSubset) { + TEST_DESCRIPTION("https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/8377"); + RETURN_IF_SKIP(InitGpuAvFramework()); + RETURN_IF_SKIP(InitState()); + + const VkDescriptorSetLayoutBinding binding{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}; + vkt::DescriptorSetLayout dsl1(*m_device, binding); + vkt::DescriptorSetLayout dsl2(*m_device, binding); + VkDescriptorSetLayout set_layouts[2] = {dsl1.handle(), dsl2.handle()}; + + VkPipelineLayoutCreateInfo pipeline_layout_ci = vku::InitStructHelper(); + pipeline_layout_ci.pSetLayouts = set_layouts; + + pipeline_layout_ci.setLayoutCount = 1; + const vkt::PipelineLayout pipeline_layout_1(*m_device, pipeline_layout_ci); + pipeline_layout_ci.setLayoutCount = 2; + const vkt::PipelineLayout pipeline_layout_2(*m_device, pipeline_layout_ci); + + char const *cs_source = R"glsl( + #version 450 + layout(set = 0, binding = 0) buffer foo_0 { int a; int b;}; + void main() { + a = b; + } + )glsl"; + CreateComputePipelineHelper pipe(*this); + pipe.cs_ = std::make_unique(this, cs_source, VK_SHADER_STAGE_COMPUTE_BIT); + pipe.cp_ci_.layout = pipeline_layout_1.handle(); + pipe.CreateComputePipeline(); + + VkDescriptorPoolSize pool_size = {VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 2}; + VkDescriptorPoolCreateInfo ds_pool_ci = vku::InitStructHelper(); + ds_pool_ci.maxSets = 2; + ds_pool_ci.poolSizeCount = 1; + ds_pool_ci.pPoolSizes = &pool_size; + vkt::DescriptorPool pool(*m_device, ds_pool_ci); + + VkDescriptorSetAllocateInfo allocate_info = vku::InitStructHelper(); + allocate_info.descriptorPool = pool.handle(); + allocate_info.descriptorSetCount = 2; + allocate_info.pSetLayouts = set_layouts; + + VkDescriptorSet descriptor_sets[2]; + vk::AllocateDescriptorSets(device(), &allocate_info, descriptor_sets); + + vkt::Buffer buffer(*m_device, 32, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); + VkDescriptorBufferInfo buffer_info = {buffer.handle(), 0, VK_WHOLE_SIZE}; + + VkWriteDescriptorSet descriptor_writes[2]; + descriptor_writes[0] = vku::InitStructHelper(); + descriptor_writes[0].dstSet = descriptor_sets[0]; + descriptor_writes[0].dstBinding = 0; + descriptor_writes[0].descriptorCount = 1; + descriptor_writes[0].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + descriptor_writes[0].pBufferInfo = &buffer_info; + descriptor_writes[1] = vku::InitStructHelper(); + descriptor_writes[1].dstSet = descriptor_sets[1]; + descriptor_writes[1].dstBinding = 0; + descriptor_writes[1].descriptorCount = 1; + descriptor_writes[1].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + descriptor_writes[1].pBufferInfo = &buffer_info; + vk::UpdateDescriptorSets(device(), 2, descriptor_writes, 0, nullptr); + + VkCommandBufferBeginInfo begin_info = vku::InitStructHelper(); + m_commandBuffer->begin(&begin_info); + + vk::CmdBindDescriptorSets(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout_2.handle(), 0, 2, + descriptor_sets, 0, nullptr); + + vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_COMPUTE, pipe.Handle()); + vk::CmdDispatch(m_commandBuffer->handle(), 1, 1, 1); + + m_commandBuffer->end(); + m_default_queue->Submit(*m_commandBuffer); + m_default_queue->Wait(); +} + +TEST_F(PositiveGpuAV, DestroyedPipelineLayout) { + TEST_DESCRIPTION("Check if can catch pipeline layout not being bound"); + RETURN_IF_SKIP(InitGpuAvFramework()); + RETURN_IF_SKIP(InitState()); + InitRenderTarget(); + + // Destroy pipeline layout after creating pipeline + CreatePipelineHelper pipe(*this); + { + const vkt::PipelineLayout doomed_pipeline_layout(*m_device); + pipe.gp_ci_.layout = doomed_pipeline_layout.handle(); + pipe.CreateGraphicsPipeline(); + } + + m_commandBuffer->begin(); + vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.Handle()); + m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo); + vk::CmdDraw(m_commandBuffer->handle(), 3, 1, 0, 0); + m_commandBuffer->EndRenderPass(); + m_commandBuffer->end(); +} + +TEST_F(PositiveGpuAV, DestroyedPipelineLayout2) { + TEST_DESCRIPTION("Have a descriptor set that needs to be bound as well so GPU-AV can use that"); + RETURN_IF_SKIP(InitGpuAvFramework()); + RETURN_IF_SKIP(InitState()); + InitRenderTarget(); + + static const char vertshader[] = R"glsl( + #version 450 + layout(set = 0, binding = 0) buffer StorageBuffer { uint x; }; + void main() { + x = 0; + } + )glsl"; + VkShaderObj vs(this, vertshader, VK_SHADER_STAGE_VERTEX_BIT); + + vkt::Buffer buffer(*m_device, 64, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + OneOffDescriptorSet descriptor_set(m_device, {{0, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_ALL, nullptr}}); + descriptor_set.WriteDescriptorBufferInfo(0, buffer.handle(), 0, VK_WHOLE_SIZE, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER); + descriptor_set.UpdateDescriptorSets(); + const vkt::PipelineLayout pipeline_layout(*m_device, {&descriptor_set.layout_}); + + // Destroy pipeline layout after creating pipeline + CreatePipelineHelper pipe(*this); + { + const vkt::PipelineLayout doomed_pipeline_layout(*m_device, {&descriptor_set.layout_}); + pipe.shader_stages_[0] = vs.GetStageCreateInfo(); + pipe.gp_ci_.layout = doomed_pipeline_layout.handle(); + pipe.CreateGraphicsPipeline(); + } + + m_commandBuffer->begin(); + vk::CmdBindDescriptorSets(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout.handle(), 0, 1, + &descriptor_set.set_, 0, nullptr); + vk::CmdBindPipeline(m_commandBuffer->handle(), VK_PIPELINE_BIND_POINT_GRAPHICS, pipe.Handle()); + m_commandBuffer->BeginRenderPass(m_renderPassBeginInfo); + vk::CmdDraw(m_commandBuffer->handle(), 3, 1, 0, 0); + m_commandBuffer->EndRenderPass(); + m_commandBuffer->end(); +}