From 074b46ecc8c77ca1f9f92874fdc89e9c614b4f97 Mon Sep 17 00:00:00 2001 From: Shahbaz Youssefi Date: Mon, 21 Oct 2024 23:17:51 -0400 Subject: [PATCH] Support VK_KHR_dynamic_rendering_local_read Fixes #3341 --- .../VulkanPipelineStateViewer.cpp | 96 +++++++++++- renderdoc/api/replay/vk_pipestate.h | 24 +++ renderdoc/driver/vulkan/extension_support.md | 3 +- renderdoc/driver/vulkan/vk_common.h | 8 + renderdoc/driver/vulkan/vk_core.cpp | 8 + renderdoc/driver/vulkan/vk_core.h | 9 ++ renderdoc/driver/vulkan/vk_hookset_defs.h | 8 + renderdoc/driver/vulkan/vk_info.cpp | 108 +++++++++++++ renderdoc/driver/vulkan/vk_info.h | 44 ++++++ renderdoc/driver/vulkan/vk_next_chains.cpp | 102 +++++++++++- renderdoc/driver/vulkan/vk_overlay.cpp | 26 +++ renderdoc/driver/vulkan/vk_pixelhistory.cpp | 26 ++- renderdoc/driver/vulkan/vk_replay.cpp | 13 +- renderdoc/driver/vulkan/vk_serialise.cpp | 71 ++++++++- renderdoc/driver/vulkan/vk_state.cpp | 10 ++ renderdoc/driver/vulkan/vk_state.h | 4 + renderdoc/driver/vulkan/vk_stringise.cpp | 4 +- .../driver/vulkan/wrappers/vk_cmd_funcs.cpp | 24 +++ .../vulkan/wrappers/vk_device_funcs.cpp | 8 + .../vulkan/wrappers/vk_dynamic_funcs.cpp | 148 ++++++++++++++++++ renderdoc/replay/renderdoc_serialise.inl | 12 +- 21 files changed, 730 insertions(+), 26 deletions(-) diff --git a/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.cpp b/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.cpp index 9d20ca834a..2d8200ebb7 100644 --- a/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.cpp +++ b/qrenderdoc/Windows/PipelineState/VulkanPipelineStateViewer.cpp @@ -41,6 +41,8 @@ Q_DECLARE_METATYPE(CombinedSamplerData); namespace { +constexpr uint32_t VK_ATTACHMENT_UNUSED = ~0U; + QString getTextureRenderSamples(const TextureDescription *tex, const VKPipe::RenderPass &renderpass) { const uint32_t texSamples = tex ? tex->msSamp : 1; @@ -2614,12 +2616,32 @@ void VulkanPipelineStateViewer::setState() { slotname = QFormatStr("Color %1").arg(a.localIdx); + // With dynamic rendering, the API references the framebuffer index everywhere, for + // example when specifying blend state for attachments or with vkCmdClearAttachments. As + // such, RenderDoc shows the same index in Color attachments (i.e. fbIdx == localIdx) to + // avoid confusion, even when VK_KHR_dynamic_rendering_local_read maps these attachments + // to different "locations" used by the shader. In that case, the mapped location is + // shown besides the attachment index. + uint32_t location = a.localIdx; + if(a.fbIdx < rp.colorAttachmentLocations.count()) + { + location = rp.colorAttachmentLocations[a.fbIdx]; + if(location == VK_ATTACHMENT_UNUSED) + { + slotname += QFormatStr(" [disabled]"); + } + else + { + slotname += QFormatStr(" [location %1]").arg(location); + } + } + if(state.fragmentShader.reflection != NULL) { const rdcarray &outSig = state.fragmentShader.reflection->outputSignature; for(int s = 0; s < outSig.count(); s++) { - if(outSig[s].regIndex == (uint32_t)a.localIdx && + if(outSig[s].regIndex == location && (outSig[s].systemValue == ShaderBuiltin::Undefined || outSig[s].systemValue == ShaderBuiltin::ColorOutput)) { @@ -2819,6 +2841,22 @@ void VulkanPipelineStateViewer::setState() if(showNode(usedSlot, /*filledSlot*/ true)) { + QString writemask = QFormatStr("%1%2%3%4") + .arg((blend.writeMask & 0x1) == 0 ? lit("_") : lit("R")) + .arg((blend.writeMask & 0x2) == 0 ? lit("_") : lit("G")) + .arg((blend.writeMask & 0x4) == 0 ? lit("_") : lit("B")) + .arg((blend.writeMask & 0x8) == 0 ? lit("_") : lit("A")); + + // With VK_KHR_dynamic_rendering_local_read, if a color attachment is mapped to + // VK_ATTACHMENT_UNUSED, it is implicitly disabled. The Slot name in the "Render Pass" + // pane already tags the attachment with [disabled], so the write mask is simply set to + // ____ here. + if(i < rp.colorAttachmentLocations.count() && + rp.colorAttachmentLocations[i] == VK_ATTACHMENT_UNUSED) + { + writemask = lit("____"); + } + RDTreeWidgetItem *node = new RDTreeWidgetItem( {i, blend.enabled ? tr("True") : tr("False"), @@ -2828,11 +2866,7 @@ void VulkanPipelineStateViewer::setState() ToQStr(blend.alphaBlend.source), ToQStr(blend.alphaBlend.destination), ToQStr(blend.alphaBlend.operation), - QFormatStr("%1%2%3%4") - .arg((blend.writeMask & 0x1) == 0 ? lit("_") : lit("R")) - .arg((blend.writeMask & 0x2) == 0 ? lit("_") : lit("G")) - .arg((blend.writeMask & 0x4) == 0 ? lit("_") : lit("B")) - .arg((blend.writeMask & 0x8) == 0 ? lit("_") : lit("A"))}); + writemask}); if(!usedSlot) setInactiveRow(node); @@ -4188,6 +4222,40 @@ void VulkanPipelineStateViewer::exportHTML(QXmlStreamWriter &xml, const VKPipe:: xml.writeEndElement(); } + if(!pass.renderpass.colorAttachmentLocations.isEmpty()) + { + QList locations; + + for(int i = 0; i < pass.renderpass.colorAttachmentLocations.count(); i++) + locations.push_back({pass.renderpass.colorAttachmentLocations[i]}); + + m_Common.exportHTMLTable(xml, + { + tr("Color Attachment Location"), + }, + locations); + + xml.writeStartElement(lit("p")); + xml.writeEndElement(); + } + + if(!pass.renderpass.colorAttachmentInputIndices.isEmpty()) + { + QList inputIndices; + + for(int i = 0; i < pass.renderpass.colorAttachmentInputIndices.count(); i++) + inputIndices.push_back({pass.renderpass.colorAttachmentInputIndices[i]}); + + m_Common.exportHTMLTable(xml, + { + tr("Color Attachment Input Index"), + }, + inputIndices); + + xml.writeStartElement(lit("p")); + xml.writeEndElement(); + } + if(!pass.renderpass.resolveAttachments.isEmpty()) { QList resolves; @@ -4213,6 +4281,22 @@ void VulkanPipelineStateViewer::exportHTML(QXmlStreamWriter &xml, const VKPipe:: xml.writeEndElement(); } + if(!pass.renderpass.isDepthInputAttachmentIndexImplicit) + { + xml.writeStartElement(lit("p")); + xml.writeCharacters( + tr("Depth Input Attachment Index: %1").arg(pass.renderpass.depthInputAttachmentIndex)); + xml.writeEndElement(); + } + + if(!pass.renderpass.isStencilInputAttachmentIndexImplicit) + { + xml.writeStartElement(lit("p")); + xml.writeCharacters( + tr("Stencil Input Attachment Index: %1").arg(pass.renderpass.stencilInputAttachmentIndex)); + xml.writeEndElement(); + } + if(pass.renderpass.depthstencilResolveAttachment >= 0) { xml.writeStartElement(lit("p")); diff --git a/renderdoc/api/replay/vk_pipestate.h b/renderdoc/api/replay/vk_pipestate.h index a3d58df5c1..08f3e1b04b 100644 --- a/renderdoc/api/replay/vk_pipestate.h +++ b/renderdoc/api/replay/vk_pipestate.h @@ -859,6 +859,30 @@ samples used to render this subpass. If the subpass is not internally multisampled, tileOnlyMSAASampleCount is set to 0. )"); uint32_t tileOnlyMSAASampleCount = 0; + + DOCUMENT(R"(The color index->location mapping set up by dynamic rendering local read. + +:type: List[int] +)"); + rdcarray colorAttachmentLocations; + + DOCUMENT(R"(The color index->input index mapping set up by dynamic rendering local read. + +:type: List[int] +)"); + rdcarray colorAttachmentInputIndices; + + DOCUMENT("Whether or not depth input attachment index is implicit (dynamic rendering)."); + bool isDepthInputAttachmentIndexImplicit = true; + + DOCUMENT("Whether or not stencil input attachment index is implicit (dynamic rendering)."); + bool isStencilInputAttachmentIndexImplicit = true; + + DOCUMENT("Depth input attachment index if explicit (dynamic rendering)."); + uint32_t depthInputAttachmentIndex = 0x1234ABCD; + + DOCUMENT("Stencil input attachment index if explicit (dynamic rendering)."); + uint32_t stencilInputAttachmentIndex = 0x1234ABCD; }; DOCUMENT("Describes a framebuffer object and its attachments."); diff --git a/renderdoc/driver/vulkan/extension_support.md b/renderdoc/driver/vulkan/extension_support.md index 4d71649a5b..5b61e39ea3 100644 --- a/renderdoc/driver/vulkan/extension_support.md +++ b/renderdoc/driver/vulkan/extension_support.md @@ -144,6 +144,7 @@ Maintainers can update this file by updating vk.xml in this folder and running ` * `VK_KHR_draw_indirect_count` * `VK_KHR_driver_properties` * `VK_KHR_dynamic_rendering` +* `VK_KHR_dynamic_rendering_local_read` * `VK_KHR_external_fence_capabilities` * `VK_KHR_external_fence_fd` * `VK_KHR_external_fence_win32` @@ -241,9 +242,9 @@ KHR extensions will definitely be implemented at some point, though KHR extensio ## KHR Extensions * `VK_KHR_cooperative_matrix` -* `VK_KHR_dynamic_rendering_local_read` * `VK_KHR_maintenance5` * `VK_KHR_maintenance6` +* `VK_KHR_maintenance7` * `VK_KHR_map_memory2` * `VK_KHR_shader_expect_assume` * `VK_KHR_shader_float_controls2` diff --git a/renderdoc/driver/vulkan/vk_common.h b/renderdoc/driver/vulkan/vk_common.h index be5e7551b0..26e3b502a7 100644 --- a/renderdoc/driver/vulkan/vk_common.h +++ b/renderdoc/driver/vulkan/vk_common.h @@ -1053,6 +1053,8 @@ enum class VulkanChunk : uint32_t vkCmdSetVertexInputEXT, vkCmdBeginRendering, vkCmdEndRendering, + vkCmdSetRenderingAttachmentLocationsKHR, + vkCmdSetRenderingInputAttachmentIndicesKHR, vkCmdSetFragmentShadingRateKHR, vkSetDeviceMemoryPriorityEXT, vkCmdSetAttachmentFeedbackLoopEnableEXT, @@ -1335,6 +1337,7 @@ DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceDescriptorIndexingProperties) DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceDiscardRectanglePropertiesEXT); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceDriverProperties); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceDynamicRenderingFeatures); +DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceDynamicRenderingLocalReadFeaturesKHR); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceExtendedDynamicState2FeaturesEXT); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceExtendedDynamicState3FeaturesEXT); DECLARE_REFLECTION_STRUCT(VkPhysicalDeviceExtendedDynamicState3PropertiesEXT); @@ -1519,8 +1522,10 @@ DECLARE_REFLECTION_STRUCT(VkRayTracingShaderGroupCreateInfoKHR); DECLARE_REFLECTION_STRUCT(VkRefreshCycleDurationGOOGLE); DECLARE_REFLECTION_STRUCT(VkReleaseSwapchainImagesInfoEXT); DECLARE_REFLECTION_STRUCT(VkRenderingAttachmentInfo); +DECLARE_REFLECTION_STRUCT(VkRenderingAttachmentLocationInfoKHR); DECLARE_REFLECTION_STRUCT(VkRenderingFragmentDensityMapAttachmentInfoEXT); DECLARE_REFLECTION_STRUCT(VkRenderingFragmentShadingRateAttachmentInfoKHR); +DECLARE_REFLECTION_STRUCT(VkRenderingInputAttachmentIndexInfoKHR); DECLARE_REFLECTION_STRUCT(VkRenderingInfo); DECLARE_REFLECTION_STRUCT(VkRenderPassAttachmentBeginInfo); DECLARE_REFLECTION_STRUCT(VkRenderPassBeginInfo); @@ -1775,6 +1780,7 @@ DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceDescriptorIndexingProperties) DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceDiscardRectanglePropertiesEXT); DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceDriverProperties); DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceDynamicRenderingFeatures); +DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceDynamicRenderingLocalReadFeaturesKHR); DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceExtendedDynamicState2FeaturesEXT); DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceExtendedDynamicState3FeaturesEXT); DECLARE_DESERIALISE_TYPE(VkPhysicalDeviceExtendedDynamicState3PropertiesEXT); @@ -1957,8 +1963,10 @@ DECLARE_DESERIALISE_TYPE(VkRayTracingPipelineInterfaceCreateInfoKHR); DECLARE_DESERIALISE_TYPE(VkRayTracingShaderGroupCreateInfoKHR); DECLARE_DESERIALISE_TYPE(VkReleaseSwapchainImagesInfoEXT); DECLARE_DESERIALISE_TYPE(VkRenderingAttachmentInfo); +DECLARE_DESERIALISE_TYPE(VkRenderingAttachmentLocationInfoKHR); DECLARE_DESERIALISE_TYPE(VkRenderingFragmentDensityMapAttachmentInfoEXT); DECLARE_DESERIALISE_TYPE(VkRenderingFragmentShadingRateAttachmentInfoKHR); +DECLARE_DESERIALISE_TYPE(VkRenderingInputAttachmentIndexInfoKHR); DECLARE_DESERIALISE_TYPE(VkRenderingInfo); DECLARE_DESERIALISE_TYPE(VkRenderPassAttachmentBeginInfo); DECLARE_DESERIALISE_TYPE(VkRenderPassBeginInfo); diff --git a/renderdoc/driver/vulkan/vk_core.cpp b/renderdoc/driver/vulkan/vk_core.cpp index bdeef59443..d320fdbb95 100644 --- a/renderdoc/driver/vulkan/vk_core.cpp +++ b/renderdoc/driver/vulkan/vk_core.cpp @@ -1490,6 +1490,10 @@ static const VkExtensionProperties supportedExtensions[] = { VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME, VK_KHR_DYNAMIC_RENDERING_SPEC_VERSION, }, + { + VK_KHR_DYNAMIC_RENDERING_LOCAL_READ_EXTENSION_NAME, + VK_KHR_DYNAMIC_RENDERING_LOCAL_READ_SPEC_VERSION, + }, { VK_KHR_EXTERNAL_FENCE_EXTENSION_NAME, VK_KHR_EXTERNAL_FENCE_SPEC_VERSION, @@ -4230,6 +4234,10 @@ bool WrappedVulkan::ProcessChunk(ReadSerialiser &ser, VulkanChunk chunk) case VulkanChunk::vkCmdBeginRendering: return Serialise_vkCmdBeginRendering(ser, VK_NULL_HANDLE, NULL); case VulkanChunk::vkCmdEndRendering: return Serialise_vkCmdEndRendering(ser, VK_NULL_HANDLE); + case VulkanChunk::vkCmdSetRenderingAttachmentLocationsKHR: + return Serialise_vkCmdSetRenderingAttachmentLocationsKHR(ser, VK_NULL_HANDLE, NULL); + case VulkanChunk::vkCmdSetRenderingInputAttachmentIndicesKHR: + return Serialise_vkCmdSetRenderingInputAttachmentIndicesKHR(ser, VK_NULL_HANDLE, NULL); case VulkanChunk::vkCmdSetFragmentShadingRateKHR: return Serialise_vkCmdSetFragmentShadingRateKHR(ser, VK_NULL_HANDLE, NULL, NULL); diff --git a/renderdoc/driver/vulkan/vk_core.h b/renderdoc/driver/vulkan/vk_core.h index 7c37efbb7e..a72ea88a62 100644 --- a/renderdoc/driver/vulkan/vk_core.h +++ b/renderdoc/driver/vulkan/vk_core.h @@ -2787,6 +2787,15 @@ class WrappedVulkan : public IFrameCapturer IMPLEMENT_FUNCTION_SERIALISED(void, vkCmdEndRendering, VkCommandBuffer commandBuffer); + // VK_KHR_dynamic_rendering_local_read + + IMPLEMENT_FUNCTION_SERIALISED(void, vkCmdSetRenderingAttachmentLocationsKHR, + VkCommandBuffer commandBuffer, + const VkRenderingAttachmentLocationInfoKHR *pLocationInfo); + IMPLEMENT_FUNCTION_SERIALISED(void, vkCmdSetRenderingInputAttachmentIndicesKHR, + VkCommandBuffer commandBuffer, + const VkRenderingInputAttachmentIndexInfoKHR *pLocationInfo); + // VK_KHR_fragment_shading_rate IMPLEMENT_FUNCTION_SERIALISED(void, vkCmdSetFragmentShadingRateKHR, VkCommandBuffer commandBuffer, diff --git a/renderdoc/driver/vulkan/vk_hookset_defs.h b/renderdoc/driver/vulkan/vk_hookset_defs.h index a964af88d0..c283d52a2d 100644 --- a/renderdoc/driver/vulkan/vk_hookset_defs.h +++ b/renderdoc/driver/vulkan/vk_hookset_defs.h @@ -522,6 +522,7 @@ DeclExt(EXT_multisampled_render_to_single_sampled); \ DeclExt(EXT_vertex_input_dynamic_state); \ DeclExt(KHR_dynamic_rendering); \ + DeclExt(KHR_dynamic_rendering_local_read); \ DeclExt(KHR_fragment_shading_rate); \ DeclExt(EXT_attachment_feedback_loop_layout); \ DeclExt(EXT_pageable_device_local_memory); \ @@ -651,6 +652,7 @@ CheckExt(EXT_multisampled_render_to_single_sampled, VKXX); \ CheckExt(EXT_vertex_input_dynamic_state, VKXX); \ CheckExt(KHR_dynamic_rendering, VK13); \ + CheckExt(KHR_dynamic_rendering_local_read, VKXX); \ CheckExt(KHR_fragment_shading_rate, VKXX); \ CheckExt(EXT_attachment_feedback_loop_layout, VKXX); \ CheckExt(EXT_pageable_device_local_memory, VKXX); \ @@ -941,6 +943,8 @@ HookInitExtension(EXT_vertex_input_dynamic_state || EXT_shader_object, CmdSetVertexInputEXT); \ HookInitPromotedExtension(KHR_dynamic_rendering, CmdBeginRendering, KHR); \ HookInitPromotedExtension(KHR_dynamic_rendering, CmdEndRendering, KHR); \ + HookInitExtension(KHR_dynamic_rendering_local_read, CmdSetRenderingAttachmentLocationsKHR); \ + HookInitExtension(KHR_dynamic_rendering_local_read, CmdSetRenderingInputAttachmentIndicesKHR); \ HookInitExtension(KHR_fragment_shading_rate, CmdSetFragmentShadingRateKHR); \ HookInitExtension(EXT_pageable_device_local_memory, SetDeviceMemoryPriorityEXT); \ HookInitExtension(EXT_swapchain_maintenance1, ReleaseSwapchainImagesEXT); \ @@ -1743,6 +1747,10 @@ HookDefine2(void, vkCmdBeginRendering, VkCommandBuffer, commandBuffer, const VkRenderingInfo *, \ pRenderingInfo); \ HookDefine1(void, vkCmdEndRendering, VkCommandBuffer, commandBuffer); \ + HookDefine2(void, vkCmdSetRenderingAttachmentLocationsKHR, VkCommandBuffer, commandBuffer, \ + const VkRenderingAttachmentLocationInfoKHR *, pLocationInfo); \ + HookDefine2(void, vkCmdSetRenderingInputAttachmentIndicesKHR, VkCommandBuffer, commandBuffer, \ + const VkRenderingInputAttachmentIndexInfoKHR *, pInputAttachmentIndexInfo); \ HookDefine3(void, vkCmdSetFragmentShadingRateKHR, VkCommandBuffer, commandBuffer, \ const VkExtent2D *, pFragmentSize, const VkFragmentShadingRateCombinerOpKHR *, \ combinerOps); \ diff --git a/renderdoc/driver/vulkan/vk_info.cpp b/renderdoc/driver/vulkan/vk_info.cpp index 02896c56c9..8c92befd01 100644 --- a/renderdoc/driver/vulkan/vk_info.cpp +++ b/renderdoc/driver/vulkan/vk_info.cpp @@ -1109,6 +1109,14 @@ void VulkanCreationInfo::Pipeline::Init(VulkanResourceManager *resourceMan, stencilFormat = VK_FORMAT_UNDEFINED; } + const VkRenderingAttachmentLocationInfoKHR *dynAttachmentLocations = + (const VkRenderingAttachmentLocationInfoKHR *)FindNextStruct( + pCreateInfo, VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_LOCATION_INFO_KHR); + const VkRenderingInputAttachmentIndexInfoKHR *dynInputAttachmentIndex = + (const VkRenderingInputAttachmentIndexInfoKHR *)FindNextStruct( + pCreateInfo, VK_STRUCTURE_TYPE_RENDERING_INPUT_ATTACHMENT_INDEX_INFO_KHR); + dynamicRenderingLocalRead.Init(dynAttachmentLocations, dynInputAttachmentIndex); + RDCEraseEl(dynamicStates); if(pCreateInfo->pDynamicState) { @@ -1645,6 +1653,8 @@ void VulkanCreationInfo::Pipeline::Init(VulkanResourceManager *resourceMan, shadingRateCombiners[0] = pipeInfo.shadingRateCombiners[0]; shadingRateCombiners[1] = pipeInfo.shadingRateCombiners[1]; + dynamicRenderingLocalRead.CopyInputIndices(pipeInfo.dynamicRenderingLocalRead); + flags |= pipeInfo.flags; } @@ -1674,6 +1684,8 @@ void VulkanCreationInfo::Pipeline::Init(VulkanResourceManager *resourceMan, depthFormat = pipeInfo.depthFormat; stencilFormat = pipeInfo.stencilFormat; + dynamicRenderingLocalRead.CopyLocations(pipeInfo.dynamicRenderingLocalRead); + flags |= pipeInfo.flags; } } @@ -2985,3 +2997,99 @@ void DescUpdateTemplate::Apply(const void *pData, DescUpdateTemplateApplication application.writes.push_back(write); } } + +void DynamicRenderingLocalRead::Init(const VkRenderingAttachmentLocationInfoKHR *attachmentLocations, + const VkRenderingInputAttachmentIndexInfoKHR *inputAttachmentIndex) +{ + if(attachmentLocations != nullptr) + { + UpdateLocations(*attachmentLocations); + } + if(inputAttachmentIndex != nullptr) + { + UpdateInputIndices(*inputAttachmentIndex); + } +} + +void DynamicRenderingLocalRead::UpdateLocations( + const VkRenderingAttachmentLocationInfoKHR &attachmentLocations) +{ + // If nullptr is given, an identity mapping is assumed. This is indicated by an empty + // array. This works out because not providing VkRenderingAttachmentLocationInfoKHR has the + // same meaning. + if(attachmentLocations.pColorAttachmentLocations == nullptr) + { + colorAttachmentLocations.clear(); + } + else + { + colorAttachmentLocations.assign(attachmentLocations.pColorAttachmentLocations, + attachmentLocations.colorAttachmentCount); + } +} + +void DynamicRenderingLocalRead::UpdateInputIndices( + const VkRenderingInputAttachmentIndexInfoKHR &inputAttachmentIndex) +{ + // If nullptr is given, an identity mapping is assumed. This is indicated by an empty + // array. This works out because not providing VkRenderingInputAttachmentIndexInfoKHR has the + // same meaning. + if(inputAttachmentIndex.pColorAttachmentInputIndices == nullptr) + { + colorAttachmentInputIndices.clear(); + } + else + { + colorAttachmentInputIndices.assign(inputAttachmentIndex.pColorAttachmentInputIndices, + inputAttachmentIndex.colorAttachmentCount); + } + isDepthInputAttachmentIndexImplicit = inputAttachmentIndex.pDepthInputAttachmentIndex == nullptr; + isStencilInputAttachmentIndexImplicit = + inputAttachmentIndex.pStencilInputAttachmentIndex == nullptr; + if(!isDepthInputAttachmentIndexImplicit) + { + depthInputAttachmentIndex = *inputAttachmentIndex.pDepthInputAttachmentIndex; + } + if(!isStencilInputAttachmentIndexImplicit) + { + stencilInputAttachmentIndex = *inputAttachmentIndex.pStencilInputAttachmentIndex; + } +} + +void DynamicRenderingLocalRead::CopyLocations(const DynamicRenderingLocalRead &from) +{ + colorAttachmentLocations = from.colorAttachmentLocations; +} + +void DynamicRenderingLocalRead::CopyInputIndices(const DynamicRenderingLocalRead &from) +{ + colorAttachmentInputIndices = from.colorAttachmentInputIndices; + isDepthInputAttachmentIndexImplicit = from.isDepthInputAttachmentIndexImplicit; + isStencilInputAttachmentIndexImplicit = from.isStencilInputAttachmentIndexImplicit; + depthInputAttachmentIndex = from.depthInputAttachmentIndex; + stencilInputAttachmentIndex = from.stencilInputAttachmentIndex; +} + +void DynamicRenderingLocalRead::SetLocations(VkCommandBuffer cmd) +{ + VkRenderingAttachmentLocationInfoKHR attachmentLocations = {}; + attachmentLocations.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_LOCATION_INFO_KHR; + attachmentLocations.colorAttachmentCount = colorAttachmentLocations.count(); + attachmentLocations.pColorAttachmentLocations = colorAttachmentLocations.data(); + + ObjDisp(cmd)->CmdSetRenderingAttachmentLocationsKHR(Unwrap(cmd), &attachmentLocations); +} + +void DynamicRenderingLocalRead::SetInputIndices(VkCommandBuffer cmd) +{ + VkRenderingInputAttachmentIndexInfoKHR inputIndices = {}; + inputIndices.sType = VK_STRUCTURE_TYPE_RENDERING_INPUT_ATTACHMENT_INDEX_INFO_KHR; + inputIndices.colorAttachmentCount = colorAttachmentInputIndices.count(); + inputIndices.pColorAttachmentInputIndices = colorAttachmentInputIndices.data(); + inputIndices.pDepthInputAttachmentIndex = + isDepthInputAttachmentIndexImplicit ? nullptr : &depthInputAttachmentIndex; + inputIndices.pStencilInputAttachmentIndex = + isStencilInputAttachmentIndexImplicit ? nullptr : &stencilInputAttachmentIndex; + + ObjDisp(cmd)->CmdSetRenderingInputAttachmentIndicesKHR(Unwrap(cmd), &inputIndices); +} diff --git a/renderdoc/driver/vulkan/vk_info.h b/renderdoc/driver/vulkan/vk_info.h index 9c446f235c..96c44d34c8 100644 --- a/renderdoc/driver/vulkan/vk_info.h +++ b/renderdoc/driver/vulkan/vk_info.h @@ -183,6 +183,47 @@ struct DescUpdateTemplate rdcarray updates; }; +struct DynamicRenderingLocalRead +{ + void Init(const VkRenderingAttachmentLocationInfoKHR *attachmentLocations, + const VkRenderingInputAttachmentIndexInfoKHR *inputAttachmentIndex); + + void UpdateLocations(const VkRenderingAttachmentLocationInfoKHR &attachmentLocations); + void UpdateInputIndices(const VkRenderingInputAttachmentIndexInfoKHR &inputAttachmentIndex); + + void CopyLocations(const DynamicRenderingLocalRead &from); + void CopyInputIndices(const DynamicRenderingLocalRead &from); + + bool AreLocationsNonDefault() { return !colorAttachmentLocations.isEmpty(); } + bool AreInputIndicesNonDefault() + { + return !colorAttachmentInputIndices.isEmpty() || !isDepthInputAttachmentIndexImplicit || + !isStencilInputAttachmentIndexImplicit; + } + + void SetLocations(VkCommandBuffer cmd); + void SetInputIndices(VkCommandBuffer cmd); + + // VkRenderingAttachmentLocationInfoKHR + // Notes: + // - If the array is empty, it indicates an identity mapping. + // - If an element is VK_ATTACHMENT_UNUSED, writes to it are disabled (as if the color + // attachment is masked) + rdcarray colorAttachmentLocations; + + // VkRenderingInputAttachmentIndexInfoKHR + // Notes: + // - The depth/stencil indices are only set if the is..Implicit flag is false. By default, the + // depth/stencil indices are assumed to be implicit (no input_attachment_index decoration + // needed in the shader). + // - If an element is VK_ATTACHMENT_UNUSED, it won't be used as input attachment. + rdcarray colorAttachmentInputIndices; + bool isDepthInputAttachmentIndexImplicit = true; + bool isStencilInputAttachmentIndexImplicit = true; + uint32_t depthInputAttachmentIndex = 0x1234ABCD; + uint32_t stencilInputAttachmentIndex = 0x1234ABCD; +}; + struct VulkanCreationInfo { struct ShaderModuleReflectionKey @@ -288,6 +329,9 @@ struct VulkanCreationInfo VkFormat depthFormat; VkFormat stencilFormat; + // VkRenderingAttachmentLocationInfoKHR and VkRenderingInputAttachmentIndexInfoKHR + DynamicRenderingLocalRead dynamicRenderingLocalRead; + // a variant of the pipeline that uses subpass 0, used for when we are replaying in isolation. // See loadRPs in the RenderPass info VkPipeline subpass0pipe; diff --git a/renderdoc/driver/vulkan/vk_next_chains.cpp b/renderdoc/driver/vulkan/vk_next_chains.cpp index dd05904255..7f12a6de52 100644 --- a/renderdoc/driver/vulkan/vk_next_chains.cpp +++ b/renderdoc/driver/vulkan/vk_next_chains.cpp @@ -272,6 +272,8 @@ static void AppendModifiedChainedStruct(byte *&tempMem, VkStruct *outputStruct, VkPhysicalDeviceDriverProperties); \ COPY_STRUCT(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES, \ VkPhysicalDeviceDynamicRenderingFeatures) \ + COPY_STRUCT(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_LOCAL_READ_FEATURES_KHR, \ + VkPhysicalDeviceDynamicRenderingLocalReadFeaturesKHR) \ COPY_STRUCT(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT, \ VkPhysicalDeviceExtendedDynamicStateFeaturesEXT); \ COPY_STRUCT(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_2_FEATURES_EXT, \ @@ -998,7 +1000,6 @@ static void AppendModifiedChainedStruct(byte *&tempMem, VkStruct *outputStruct, case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEVICE_MEMORY_REPORT_FEATURES_EXT: \ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DIAGNOSTICS_CONFIG_FEATURES_NV: \ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRM_PROPERTIES_EXT: \ - case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_LOCAL_READ_FEATURES_KHR: \ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_UNUSED_ATTACHMENTS_FEATURES_EXT: \ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXCLUSIVE_SCISSOR_FEATURES_NV: \ case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_SPARSE_ADDRESS_SPACE_FEATURES_NV: \ @@ -1140,8 +1141,6 @@ static void AppendModifiedChainedStruct(byte *&tempMem, VkStruct *outputStruct, case VK_STRUCTURE_TYPE_RENDER_PASS_SUBPASS_FEEDBACK_CREATE_INFO_EXT: \ case VK_STRUCTURE_TYPE_RENDER_PASS_TRANSFORM_BEGIN_INFO_QCOM: \ case VK_STRUCTURE_TYPE_RENDERING_AREA_INFO_KHR: \ - case VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_LOCATION_INFO_KHR: \ - case VK_STRUCTURE_TYPE_RENDERING_INPUT_ATTACHMENT_INDEX_INFO_KHR: \ case VK_STRUCTURE_TYPE_SAMPLER_BLOCK_MATCH_WINDOW_CREATE_INFO_QCOM: \ case VK_STRUCTURE_TYPE_SAMPLER_CAPTURE_DESCRIPTOR_DATA_INFO_EXT: \ case VK_STRUCTURE_TYPE_SAMPLER_CUBIC_WEIGHTS_CREATE_INFO_QCOM: \ @@ -1593,6 +1592,30 @@ size_t GetNextPatchSize(const void *pNext) memSize += info->attachmentCount * sizeof(VkImageView); break; } + case VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_LOCATION_INFO_KHR: + { + memSize += sizeof(VkRenderingAttachmentLocationInfoKHR); + + VkRenderingAttachmentLocationInfoKHR *info = (VkRenderingAttachmentLocationInfoKHR *)next; + memSize += info->colorAttachmentCount * sizeof(uint32_t); + break; + } + case VK_STRUCTURE_TYPE_RENDERING_INPUT_ATTACHMENT_INDEX_INFO_KHR: + { + memSize += sizeof(VkRenderingInputAttachmentIndexInfoKHR); + + VkRenderingInputAttachmentIndexInfoKHR *info = (VkRenderingInputAttachmentIndexInfoKHR *)next; + memSize += info->colorAttachmentCount * sizeof(uint32_t); + if(info->pDepthInputAttachmentIndex) + { + memSize += sizeof(*info->pDepthInputAttachmentIndex); + } + if(info->pStencilInputAttachmentIndex) + { + memSize += sizeof(*info->pStencilInputAttachmentIndex); + } + break; + } case VK_STRUCTURE_TYPE_RESOLVE_IMAGE_INFO_2: { memSize += sizeof(VkResolveImageInfo2); @@ -2711,6 +2734,71 @@ void UnwrapNextChain(CaptureState state, const char *structName, byte *&tempMem, break; } + case VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_LOCATION_INFO_KHR: + { + const VkRenderingAttachmentLocationInfoKHR *in = + (const VkRenderingAttachmentLocationInfoKHR *)nextInput; + VkRenderingAttachmentLocationInfoKHR *out = (VkRenderingAttachmentLocationInfoKHR *)tempMem; + + // append immediately so tempMem is incremented + AppendModifiedChainedStruct(tempMem, out, nextChainTail); + + // allocate unwrapped array + uint32_t *outLocations = (uint32_t *)tempMem; + tempMem += sizeof(uint32_t) * in->colorAttachmentCount; + + *out = *in; + + out->pColorAttachmentLocations = outLocations; + for(uint32_t i = 0; i < in->colorAttachmentCount; i++) + { + outLocations[i] = in->pColorAttachmentLocations[i]; + } + + break; + } + case VK_STRUCTURE_TYPE_RENDERING_INPUT_ATTACHMENT_INDEX_INFO_KHR: + { + const VkRenderingInputAttachmentIndexInfoKHR *in = + (const VkRenderingInputAttachmentIndexInfoKHR *)nextInput; + VkRenderingInputAttachmentIndexInfoKHR *out = + (VkRenderingInputAttachmentIndexInfoKHR *)tempMem; + + // append immediately so tempMem is incremented + AppendModifiedChainedStruct(tempMem, out, nextChainTail); + + // allocate unwrapped array + uint32_t *outColorIndices = (uint32_t *)tempMem; + tempMem += sizeof(uint32_t) * in->colorAttachmentCount; + + *out = *in; + + out->pColorAttachmentInputIndices = outColorIndices; + for(uint32_t i = 0; i < in->colorAttachmentCount; i++) + { + outColorIndices[i] = in->pColorAttachmentInputIndices[i]; + } + + if(in->pDepthInputAttachmentIndex) + { + uint32_t *depthIndex = (uint32_t *)tempMem; + out->pDepthInputAttachmentIndex = depthIndex; + tempMem += sizeof(uint32_t); + + *depthIndex = *in->pDepthInputAttachmentIndex; + } + + if(in->pStencilInputAttachmentIndex) + { + uint32_t *stencilIndex = (uint32_t *)tempMem; + out->pStencilInputAttachmentIndex = stencilIndex; + tempMem += sizeof(uint32_t); + + *stencilIndex = *in->pStencilInputAttachmentIndex; + } + + break; + } case VK_STRUCTURE_TYPE_RESOLVE_IMAGE_INFO_2: { const VkResolveImageInfo2 *in = (const VkResolveImageInfo2 *)nextInput; @@ -3255,6 +3343,14 @@ void CopyNextChainForPatching(const char *structName, byte *&tempMem, VkBaseInSt CopyNextChainedStruct(sizeof(VkRenderPassAttachmentBeginInfo), tempMem, nextInput, nextChainTail); break; + case VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_LOCATION_INFO_KHR: + CopyNextChainedStruct(sizeof(VkRenderingAttachmentLocationInfoKHR), tempMem, nextInput, + nextChainTail); + break; + case VK_STRUCTURE_TYPE_RENDERING_INPUT_ATTACHMENT_INDEX_INFO_KHR: + CopyNextChainedStruct(sizeof(VkRenderingInputAttachmentIndexInfoKHR), tempMem, nextInput, + nextChainTail); + break; case VK_STRUCTURE_TYPE_RESOLVE_IMAGE_INFO_2: CopyNextChainedStruct(sizeof(VkResolveImageInfo2), tempMem, nextInput, nextChainTail); break; diff --git a/renderdoc/driver/vulkan/vk_overlay.cpp b/renderdoc/driver/vulkan/vk_overlay.cpp index 2a256c7e1f..6f0b3323f5 100644 --- a/renderdoc/driver/vulkan/vk_overlay.cpp +++ b/renderdoc/driver/vulkan/vk_overlay.cpp @@ -325,6 +325,21 @@ struct VulkanQuadOverdrawCallback : public VulkanActionCallback pipestate.BindShaderObjects(m_pDriver, cmd, VulkanRenderState::BindGraphics); else pipestate.BindPipeline(m_pDriver, cmd, VulkanRenderState::BindGraphics, false); + + // Reset the attachment mapping, if any + if(m_PrevState.dynamicRendering.localRead.AreLocationsNonDefault()) + { + VkRenderingAttachmentLocationInfoKHR attachmentLocations = {}; + attachmentLocations.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_LOCATION_INFO_KHR; + m_pDriver->vkCmdSetRenderingAttachmentLocationsKHR(cmd, &attachmentLocations); + } + if(m_PrevState.dynamicRendering.localRead.AreInputIndicesNonDefault()) + { + VkRenderingInputAttachmentIndexInfoKHR inputIndices = {}; + inputIndices.sType = VK_STRUCTURE_TYPE_RENDERING_INPUT_ATTACHMENT_INDEX_INFO_KHR; + + m_pDriver->vkCmdSetRenderingInputAttachmentIndicesKHR(cmd, &inputIndices); + } } } @@ -344,6 +359,17 @@ struct VulkanQuadOverdrawCallback : public VulkanActionCallback m_pDriver->GetCmdRenderState().BindPipeline(m_pDriver, cmd, VulkanRenderState::BindGraphics, false); + // Restore the attachment mappings, if any. + if(m_PrevState.dynamicRendering.localRead.AreLocationsNonDefault()) + { + m_PrevState.dynamicRendering.localRead.SetLocations(cmd); + } + + if(m_PrevState.dynamicRendering.localRead.AreInputIndicesNonDefault()) + { + m_PrevState.dynamicRendering.localRead.SetInputIndices(cmd); + } + return true; } diff --git a/renderdoc/driver/vulkan/vk_pixelhistory.cpp b/renderdoc/driver/vulkan/vk_pixelhistory.cpp index 57063d92d2..1995d2191b 100644 --- a/renderdoc/driver/vulkan/vk_pixelhistory.cpp +++ b/renderdoc/driver/vulkan/vk_pixelhistory.cpp @@ -3218,11 +3218,13 @@ struct VulkanPixelHistoryPerFragmentCallback : VulkanPixelHistoryCallback for(uint32_t i = 0; i < 2; i++) { uint32_t storeOffset = (fragsProcessed + f) * sizeof(PerFragmentInfo); + bool isPrimitiveIDPipe = i == 0; - VkMarkerRegion region(cmd, StringFormat::Fmt("Getting %s for %u", - i == 0 ? "primitive ID" : "shader output", eid)); + VkMarkerRegion region( + cmd, StringFormat::Fmt("Getting %s for %u", + isPrimitiveIDPipe ? "primitive ID" : "shader output", eid)); - if(i == 0 && !m_pDriver->GetDeviceEnabledFeatures().geometryShader) + if(isPrimitiveIDPipe && !m_pDriver->GetDeviceEnabledFeatures().geometryShader) { // without geometryShader, can't read primitive ID in pixel shader VkMarkerRegion::Set("Can't get primitive ID without geometryShader feature", cmd); @@ -3303,7 +3305,7 @@ struct VulkanPixelHistoryPerFragmentCallback : VulkanPixelHistoryCallback state.shaderObjects[(uint32_t)ShaderStage::Fragment] = shadsIter[i]; // set dynamic state - if(i == 0) + if(isPrimitiveIDPipe) { // first pass - fragment shader which outputs primitive ID state.depthTestEnable = false; @@ -3317,6 +3319,13 @@ struct VulkanPixelHistoryPerFragmentCallback : VulkanPixelHistoryCallback } } + // The primitive ID shader always writes to location 0, so make sure that's not remapped + // with VK_KHR_dynamic_rendering_local_read. + if(isPrimitiveIDPipe && prevState.dynamicRendering.localRead.AreLocationsNonDefault()) + { + state.dynamicRendering.localRead = DynamicRenderingLocalRead{}; + } + m_pDriver->GetCmdRenderState().BeginRenderPassAndApplyState( m_pDriver, cmd, VulkanRenderState::BindGraphics, false); @@ -3329,7 +3338,13 @@ struct VulkanPixelHistoryPerFragmentCallback : VulkanPixelHistoryCallback m_pDriver->ReplayDraw(cmd, *action); state.EndRenderPass(cmd); - if(i == 1) + // Restore location mapping for the other pipelines. + if(isPrimitiveIDPipe && prevState.dynamicRendering.localRead.AreLocationsNonDefault()) + { + state.dynamicRendering.localRead = prevState.dynamicRendering.localRead; + } + + if(!isPrimitiveIDPipe) { storeOffset += offsetof(struct PerFragmentInfo, shaderOut); if(depthEnabled) @@ -3707,7 +3722,6 @@ struct VulkanPixelHistoryPerFragmentCallback : VulkanPixelHistoryCallback else { pipes.primitiveIdPipe = VK_NULL_HANDLE; - RDCWARN("Can't get primitive ID at event %u due to lack of geometry shader support", eid); } return pipes; diff --git a/renderdoc/driver/vulkan/vk_replay.cpp b/renderdoc/driver/vulkan/vk_replay.cpp index ba50801c28..b8669ccf38 100644 --- a/renderdoc/driver/vulkan/vk_replay.cpp +++ b/renderdoc/driver/vulkan/vk_replay.cpp @@ -1786,7 +1786,7 @@ void VulkanReplay::SavePipelineState(uint32_t eventId) rpState.resourceId = ResourceId(); rpState.subpass = 0; rpState.fragmentDensityOffsets.clear(); - rpState.tileOnlyMSAASampleCount = 0; + rpState.tileOnlyMSAASampleCount = dyn.tileOnlyMSAASampleCount; fbState.resourceId = ResourceId(); // dynamic rendering does not provide a framebuffer dimension, it's implicit from the image @@ -1942,6 +1942,17 @@ void VulkanReplay::SavePipelineState(uint32_t eventId) if(dyn.viewMask & (1 << v)) rpState.multiviews.push_back(v); } + + ret.currentPass.renderpass.colorAttachmentLocations = dyn.localRead.colorAttachmentLocations; + ret.currentPass.renderpass.colorAttachmentInputIndices = + dyn.localRead.colorAttachmentInputIndices; + ret.currentPass.renderpass.isDepthInputAttachmentIndexImplicit = + dyn.localRead.isDepthInputAttachmentIndexImplicit; + ret.currentPass.renderpass.isStencilInputAttachmentIndexImplicit = + dyn.localRead.isStencilInputAttachmentIndexImplicit; + ret.currentPass.renderpass.depthInputAttachmentIndex = dyn.localRead.depthInputAttachmentIndex; + ret.currentPass.renderpass.stencilInputAttachmentIndex = + dyn.localRead.stencilInputAttachmentIndex; } else if(state.GetRenderPass() != ResourceId()) { diff --git a/renderdoc/driver/vulkan/vk_serialise.cpp b/renderdoc/driver/vulkan/vk_serialise.cpp index 2559a8c537..848a7c5966 100644 --- a/renderdoc/driver/vulkan/vk_serialise.cpp +++ b/renderdoc/driver/vulkan/vk_serialise.cpp @@ -1089,6 +1089,14 @@ SERIALISE_VK_HANDLES(); PNEXT_STRUCT(VK_STRUCTURE_TYPE_RENDERING_FRAGMENT_SHADING_RATE_ATTACHMENT_INFO_KHR, \ VkRenderingFragmentShadingRateAttachmentInfoKHR) \ \ + /* VK_KHR_dynamic_rendering_local_read */ \ + PNEXT_STRUCT(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_LOCAL_READ_FEATURES_KHR, \ + VkPhysicalDeviceDynamicRenderingLocalReadFeaturesKHR) \ + PNEXT_STRUCT(VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_LOCATION_INFO_KHR, \ + VkRenderingAttachmentLocationInfoKHR) \ + PNEXT_STRUCT(VK_STRUCTURE_TYPE_RENDERING_INPUT_ATTACHMENT_INDEX_INFO_KHR, \ + VkRenderingInputAttachmentIndexInfoKHR) \ + \ /* VK_KHR_external_fence_capabilities */ \ PNEXT_STRUCT(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO, \ VkPhysicalDeviceExternalFenceInfo) \ @@ -1717,11 +1725,6 @@ SERIALISE_VK_HANDLES(); PNEXT_UNSUPPORTED(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_PROPERTIES_KHR) \ PNEXT_UNSUPPORTED(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_COOPERATIVE_MATRIX_FEATURES_KHR) \ \ - /* VK_KHR_dynamic_rendering_local_read */ \ - PNEXT_UNSUPPORTED(VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_LOCAL_READ_FEATURES_KHR) \ - PNEXT_UNSUPPORTED(VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_LOCATION_INFO_KHR) \ - PNEXT_UNSUPPORTED(VK_STRUCTURE_TYPE_RENDERING_INPUT_ATTACHMENT_INDEX_INFO_KHR) \ - \ /* VK_KHR_map_memory2 */ \ PNEXT_UNSUPPORTED(VK_STRUCTURE_TYPE_MEMORY_MAP_INFO_KHR) \ PNEXT_UNSUPPORTED(VK_STRUCTURE_TYPE_MEMORY_UNMAP_INFO_KHR) \ @@ -9182,6 +9185,22 @@ void Deserialise(const VkPhysicalDeviceDynamicRenderingFeatures &el) DeserialiseNext(el.pNext); } +template +void DoSerialise(SerialiserType &ser, VkPhysicalDeviceDynamicRenderingLocalReadFeaturesKHR &el) +{ + RDCASSERT(ser.IsReading() || + el.sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_LOCAL_READ_FEATURES_KHR); + SerialiseNext(ser, el.sType, el.pNext); + + SERIALISE_MEMBER(dynamicRenderingLocalRead); +} + +template <> +void Deserialise(const VkPhysicalDeviceDynamicRenderingLocalReadFeaturesKHR &el) +{ + DeserialiseNext(el.pNext); +} + template void DoSerialise(SerialiserType &ser, VkRenderingFragmentDensityMapAttachmentInfoEXT &el) { @@ -9328,6 +9347,45 @@ void Deserialise(const VkRenderingInfo &el) delete el.pStencilAttachment; } +template +void DoSerialise(SerialiserType &ser, VkRenderingAttachmentLocationInfoKHR &el) +{ + RDCASSERT(ser.IsReading() || el.sType == VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_LOCATION_INFO_KHR); + SerialiseNext(ser, el.sType, el.pNext); + + SERIALISE_MEMBER(colorAttachmentCount).Important(); + SERIALISE_MEMBER_ARRAY(pColorAttachmentLocations, colorAttachmentCount); +} + +template <> +void Deserialise(const VkRenderingAttachmentLocationInfoKHR &el) +{ + DeserialiseNext(el.pNext); + delete[] el.pColorAttachmentLocations; +} + +template +void DoSerialise(SerialiserType &ser, VkRenderingInputAttachmentIndexInfoKHR &el) +{ + RDCASSERT(ser.IsReading() || + el.sType == VK_STRUCTURE_TYPE_RENDERING_INPUT_ATTACHMENT_INDEX_INFO_KHR); + SerialiseNext(ser, el.sType, el.pNext); + + SERIALISE_MEMBER(colorAttachmentCount).Important(); + SERIALISE_MEMBER_ARRAY(pColorAttachmentInputIndices, colorAttachmentCount); + SERIALISE_MEMBER_OPT(pDepthInputAttachmentIndex); + SERIALISE_MEMBER_OPT(pStencilInputAttachmentIndex); +} + +template <> +void Deserialise(const VkRenderingInputAttachmentIndexInfoKHR &el) +{ + DeserialiseNext(el.pNext); + delete[] el.pColorAttachmentInputIndices; + delete el.pDepthInputAttachmentIndex; + delete el.pStencilInputAttachmentIndex; +} + template void DoSerialise(SerialiserType &ser, VkPhysicalDeviceExternalFenceInfo &el) { @@ -12585,6 +12643,7 @@ INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceDescriptorIndexingProperties) INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceDiscardRectanglePropertiesEXT); INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceDriverProperties); INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceDynamicRenderingFeatures); +INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceDynamicRenderingLocalReadFeaturesKHR); INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceExtendedDynamicState2FeaturesEXT); INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceExtendedDynamicState3FeaturesEXT); INSTANTIATE_SERIALISE_TYPE(VkPhysicalDeviceExtendedDynamicState3PropertiesEXT); @@ -12769,6 +12828,8 @@ INSTANTIATE_SERIALISE_TYPE(VkRenderingAttachmentInfo); INSTANTIATE_SERIALISE_TYPE(VkRenderingFragmentDensityMapAttachmentInfoEXT); INSTANTIATE_SERIALISE_TYPE(VkRenderingFragmentShadingRateAttachmentInfoKHR); INSTANTIATE_SERIALISE_TYPE(VkRenderingInfo); +INSTANTIATE_SERIALISE_TYPE(VkRenderingAttachmentLocationInfoKHR); +INSTANTIATE_SERIALISE_TYPE(VkRenderingInputAttachmentIndexInfoKHR); INSTANTIATE_SERIALISE_TYPE(VkRenderPassAttachmentBeginInfo); INSTANTIATE_SERIALISE_TYPE(VkRenderPassBeginInfo); INSTANTIATE_SERIALISE_TYPE(VkRenderPassCreateInfo); diff --git a/renderdoc/driver/vulkan/vk_state.cpp b/renderdoc/driver/vulkan/vk_state.cpp index 5116f7be1b..9ed7b42154 100644 --- a/renderdoc/driver/vulkan/vk_state.cpp +++ b/renderdoc/driver/vulkan/vk_state.cpp @@ -230,6 +230,16 @@ void VulkanRenderState::BeginRenderPassAndApplyState(WrappedVulkan *vk, VkComman ObjDisp(cmd)->CmdBeginConditionalRenderingEXT(Unwrap(cmd), &beginInfo); } + + if(dynamicRendering.localRead.AreLocationsNonDefault()) + { + dynamicRendering.localRead.SetLocations(cmd); + } + + if(dynamicRendering.localRead.AreInputIndicesNonDefault()) + { + dynamicRendering.localRead.SetInputIndices(cmd); + } } void VulkanRenderState::EndRenderPass(VkCommandBuffer cmd) diff --git a/renderdoc/driver/vulkan/vk_state.h b/renderdoc/driver/vulkan/vk_state.h index b8417b6405..a26a5e8f02 100644 --- a/renderdoc/driver/vulkan/vk_state.h +++ b/renderdoc/driver/vulkan/vk_state.h @@ -25,6 +25,7 @@ #pragma once #include "vk_common.h" +#include "vk_info.h" struct VulkanCreationInfo; class VulkanResourceManager; @@ -289,6 +290,9 @@ struct VulkanRenderState bool tileOnlyMSAAEnable = false; VkSampleCountFlagBits tileOnlyMSAASampleCount = VK_SAMPLE_COUNT_1_BIT; + + // VK_KHR_dynamic_rendering_local_read + DynamicRenderingLocalRead localRead; } dynamicRendering; // fdm offset diff --git a/renderdoc/driver/vulkan/vk_stringise.cpp b/renderdoc/driver/vulkan/vk_stringise.cpp index a231bbd215..23a4ae07e7 100644 --- a/renderdoc/driver/vulkan/vk_stringise.cpp +++ b/renderdoc/driver/vulkan/vk_stringise.cpp @@ -28,7 +28,7 @@ template <> rdcstr DoStringise(const VulkanChunk &el) { - RDCCOMPILE_ASSERT((uint32_t)VulkanChunk::Max == 1213, "Chunks changed without updating names"); + RDCCOMPILE_ASSERT((uint32_t)VulkanChunk::Max == 1215, "Chunks changed without updating names"); BEGIN_ENUM_STRINGISE(VulkanChunk) { @@ -207,6 +207,8 @@ rdcstr DoStringise(const VulkanChunk &el) STRINGISE_ENUM_CLASS(vkCmdSetVertexInputEXT) STRINGISE_ENUM_CLASS(vkCmdBeginRendering) STRINGISE_ENUM_CLASS(vkCmdEndRendering) + STRINGISE_ENUM_CLASS(vkCmdSetRenderingAttachmentLocationsKHR) + STRINGISE_ENUM_CLASS(vkCmdSetRenderingInputAttachmentIndicesKHR) STRINGISE_ENUM_CLASS(vkCmdSetFragmentShadingRateKHR) STRINGISE_ENUM_CLASS(vkSetDeviceMemoryPriorityEXT) STRINGISE_ENUM_CLASS(vkCmdSetAttachmentFeedbackLoopEnableEXT) diff --git a/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp index e8918619af..f5b65d24b5 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp @@ -1258,6 +1258,17 @@ bool WrappedVulkan::Serialise_vkBeginCommandBuffer(SerialiserType &ser, VkComman BeginInfo.pInheritanceInfo->subpass; // framebuffer is not useful here since it may be incomplete (imageless) and it's // optional, so we should just treat it as never present. + + const VkRenderingAttachmentLocationInfoKHR *dynAttachmentLocations = + (const VkRenderingAttachmentLocationInfoKHR *)FindNextStruct( + BeginInfo.pInheritanceInfo, + VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_LOCATION_INFO_KHR); + const VkRenderingInputAttachmentIndexInfoKHR *dynInputAttachmentIndex = + (const VkRenderingInputAttachmentIndexInfoKHR *)FindNextStruct( + BeginInfo.pInheritanceInfo, + VK_STRUCTURE_TYPE_RENDERING_INPUT_ATTACHMENT_INDEX_INFO_KHR); + m_BakedCmdBufferInfo[BakedCommandBuffer].state.dynamicRendering.localRead.Init( + dynAttachmentLocations, dynInputAttachmentIndex); } ObjDisp(cmd)->BeginCommandBuffer(Unwrap(cmd), &unwrappedBeginInfo); @@ -1344,6 +1355,19 @@ bool WrappedVulkan::Serialise_vkBeginCommandBuffer(SerialiserType &ser, VkComman uint32_t(m_StructuredFile->chunks.size() - 1); } + if(AllocateInfo.level == VK_COMMAND_BUFFER_LEVEL_SECONDARY) + { + const VkRenderingAttachmentLocationInfoKHR *dynAttachmentLocations = + (const VkRenderingAttachmentLocationInfoKHR *)FindNextStruct( + BeginInfo.pInheritanceInfo, VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_LOCATION_INFO_KHR); + const VkRenderingInputAttachmentIndexInfoKHR *dynInputAttachmentIndex = + (const VkRenderingInputAttachmentIndexInfoKHR *)FindNextStruct( + BeginInfo.pInheritanceInfo, + VK_STRUCTURE_TYPE_RENDERING_INPUT_ATTACHMENT_INDEX_INFO_KHR); + m_BakedCmdBufferInfo[BakedCommandBuffer].state.dynamicRendering.localRead.Init( + dynAttachmentLocations, dynInputAttachmentIndex); + } + ObjDisp(device)->BeginCommandBuffer(Unwrap(cmd), &unwrappedBeginInfo); } } diff --git a/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp index 82ba365f87..e2e1e56812 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp @@ -3093,6 +3093,14 @@ bool WrappedVulkan::Serialise_vkCreateDevice(SerialiserType &ser, VkPhysicalDevi } END_PHYS_EXT_CHECK(); + BEGIN_PHYS_EXT_CHECK( + VkPhysicalDeviceDynamicRenderingLocalReadFeaturesKHR, + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_LOCAL_READ_FEATURES_KHR); + { + CHECK_PHYS_EXT_FEATURE(dynamicRenderingLocalRead); + } + END_PHYS_EXT_CHECK(); + BEGIN_PHYS_EXT_CHECK(VkPhysicalDevice4444FormatsFeaturesEXT, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_4444_FORMATS_FEATURES_EXT); { diff --git a/renderdoc/driver/vulkan/wrappers/vk_dynamic_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_dynamic_funcs.cpp index 10c59da139..c1d8df5323 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_dynamic_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_dynamic_funcs.cpp @@ -3566,6 +3566,147 @@ void WrappedVulkan::vkCmdSetRayTracingPipelineStackSizeKHR(VkCommandBuffer comma } } +template +bool WrappedVulkan::Serialise_vkCmdSetRenderingAttachmentLocationsKHR( + SerialiserType &ser, VkCommandBuffer commandBuffer, + const VkRenderingAttachmentLocationInfoKHR *pLocationInfo) +{ + SERIALISE_ELEMENT(commandBuffer); + SERIALISE_ELEMENT_LOCAL(locationInfo, *pLocationInfo).Named("pLocationInfo"_lit).Important(); + + Serialise_DebugMessages(ser); + + SERIALISE_CHECK_READ_ERRORS(); + + if(IsReplayingAndReading()) + { + m_LastCmdBufferID = GetResourceManager()->GetOriginalID(GetResID(commandBuffer)); + + if(IsActiveReplaying(m_State)) + { + if(InRerecordRange(m_LastCmdBufferID)) + { + commandBuffer = RerecordCmdBuf(m_LastCmdBufferID); + + { + VulkanRenderState &renderstate = GetCmdRenderState(); + + renderstate.dynamicRendering.localRead.UpdateLocations(locationInfo); + } + } + else + { + commandBuffer = VK_NULL_HANDLE; + } + } + else + { + m_BakedCmdBufferInfo[m_LastCmdBufferID].state.dynamicRendering.localRead.UpdateLocations( + locationInfo); + } + + if(commandBuffer != VK_NULL_HANDLE) + ObjDisp(commandBuffer)->CmdSetRenderingAttachmentLocationsKHR(Unwrap(commandBuffer), &locationInfo); + } + + return true; +} + +void WrappedVulkan::vkCmdSetRenderingAttachmentLocationsKHR( + VkCommandBuffer commandBuffer, const VkRenderingAttachmentLocationInfoKHR *pLocationInfo) +{ + SCOPED_DBG_SINK(); + + SERIALISE_TIME_CALL( + ObjDisp(commandBuffer) + ->CmdSetRenderingAttachmentLocationsKHR(Unwrap(commandBuffer), pLocationInfo)); + + if(IsCaptureMode(m_State)) + { + VkResourceRecord *record = GetRecord(commandBuffer); + + CACHE_THREAD_SERIALISER(); + + SCOPED_SERIALISE_CHUNK(VulkanChunk::vkCmdSetRenderingAttachmentLocationsKHR); + Serialise_vkCmdSetRenderingAttachmentLocationsKHR(ser, commandBuffer, pLocationInfo); + + record->AddChunk(scope.Get(&record->cmdInfo->alloc)); + } +} + +template +bool WrappedVulkan::Serialise_vkCmdSetRenderingInputAttachmentIndicesKHR( + SerialiserType &ser, VkCommandBuffer commandBuffer, + const VkRenderingInputAttachmentIndexInfoKHR *pInputAttachmentIndexInfo) +{ + SERIALISE_ELEMENT(commandBuffer); + SERIALISE_ELEMENT_LOCAL(inputAttachmentIndex, *pInputAttachmentIndexInfo) + .Named("pInputAttachmentIndexInfo"_lit) + .Important(); + + Serialise_DebugMessages(ser); + + SERIALISE_CHECK_READ_ERRORS(); + + if(IsReplayingAndReading()) + { + m_LastCmdBufferID = GetResourceManager()->GetOriginalID(GetResID(commandBuffer)); + + if(IsActiveReplaying(m_State)) + { + if(InRerecordRange(m_LastCmdBufferID)) + { + commandBuffer = RerecordCmdBuf(m_LastCmdBufferID); + + { + VulkanRenderState &renderstate = GetCmdRenderState(); + + renderstate.dynamicRendering.localRead.UpdateInputIndices(inputAttachmentIndex); + } + } + else + { + commandBuffer = VK_NULL_HANDLE; + } + } + else + { + m_BakedCmdBufferInfo[m_LastCmdBufferID].state.dynamicRendering.localRead.UpdateInputIndices( + inputAttachmentIndex); + } + + if(commandBuffer != VK_NULL_HANDLE) + ObjDisp(commandBuffer) + ->CmdSetRenderingInputAttachmentIndicesKHR(Unwrap(commandBuffer), &inputAttachmentIndex); + } + + return true; +} + +void WrappedVulkan::vkCmdSetRenderingInputAttachmentIndicesKHR( + VkCommandBuffer commandBuffer, + const VkRenderingInputAttachmentIndexInfoKHR *pInputAttachmentIndexInfo) +{ + SCOPED_DBG_SINK(); + + SERIALISE_TIME_CALL(ObjDisp(commandBuffer) + ->CmdSetRenderingInputAttachmentIndicesKHR(Unwrap(commandBuffer), + pInputAttachmentIndexInfo)); + + if(IsCaptureMode(m_State)) + { + VkResourceRecord *record = GetRecord(commandBuffer); + + CACHE_THREAD_SERIALISER(); + + SCOPED_SERIALISE_CHUNK(VulkanChunk::vkCmdSetRenderingInputAttachmentIndicesKHR); + Serialise_vkCmdSetRenderingInputAttachmentIndicesKHR(ser, commandBuffer, + pInputAttachmentIndexInfo); + + record->AddChunk(scope.Get(&record->cmdInfo->alloc)); + } +} + INSTANTIATE_FUNCTION_SERIALISED(void, vkCmdSetViewport, VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount, const VkViewport *pViewports); @@ -3707,3 +3848,10 @@ INSTANTIATE_FUNCTION_SERIALISED(void, vkCmdSetTessellationDomainOriginEXT, VkTessellationDomainOrigin domainOrigin); INSTANTIATE_FUNCTION_SERIALISED(void, vkCmdSetRayTracingPipelineStackSizeKHR, VkCommandBuffer commandBuffer, uint32_t pipelineStackSize) + +INSTANTIATE_FUNCTION_SERIALISED(void, vkCmdSetRenderingAttachmentLocationsKHR, + VkCommandBuffer commandBuffer, + const VkRenderingAttachmentLocationInfoKHR *pLocationInfo); +INSTANTIATE_FUNCTION_SERIALISED( + void, vkCmdSetRenderingInputAttachmentIndicesKHR, VkCommandBuffer commandBuffer, + const VkRenderingInputAttachmentIndexInfoKHR *pInputAttachmentIndexInfo); diff --git a/renderdoc/replay/renderdoc_serialise.inl b/renderdoc/replay/renderdoc_serialise.inl index ac4a279a20..03a9b9cd0e 100644 --- a/renderdoc/replay/renderdoc_serialise.inl +++ b/renderdoc/replay/renderdoc_serialise.inl @@ -2182,8 +2182,14 @@ void DoSerialise(SerialiserType &ser, VKPipe::RenderPass &el) SERIALISE_MEMBER(multiviews); SERIALISE_MEMBER(fragmentDensityOffsets); SERIALISE_MEMBER(tileOnlyMSAASampleCount); + SERIALISE_MEMBER(colorAttachmentLocations); + SERIALISE_MEMBER(colorAttachmentInputIndices); + SERIALISE_MEMBER(isDepthInputAttachmentIndexImplicit); + SERIALISE_MEMBER(isStencilInputAttachmentIndexImplicit); + SERIALISE_MEMBER(depthInputAttachmentIndex); + SERIALISE_MEMBER(stencilInputAttachmentIndex); - SIZE_CHECK(168); + SIZE_CHECK(232); } template @@ -2219,7 +2225,7 @@ void DoSerialise(SerialiserType &ser, VKPipe::CurrentPass &el) SERIALISE_MEMBER(depthFeedbackAllowed); SERIALISE_MEMBER(stencilFeedbackAllowed); - SIZE_CHECK(240); + SIZE_CHECK(304); } template @@ -2289,7 +2295,7 @@ void DoSerialise(SerialiserType &ser, VKPipe::State &el) SERIALISE_MEMBER(conditionalRendering); - SIZE_CHECK(1808); + SIZE_CHECK(1872); } #pragma endregion Vulkan pipeline state