diff --git a/renderdoc/driver/vulkan/vk_state.cpp b/renderdoc/driver/vulkan/vk_state.cpp index 77fffe448..4b295e449 100644 --- a/renderdoc/driver/vulkan/vk_state.cpp +++ b/renderdoc/driver/vulkan/vk_state.cpp @@ -275,14 +275,51 @@ void VulkanRenderState::BeginRenderPassAndApplyState(WrappedVulkan *vk, VkComman void VulkanRenderState::EndRenderPass(VkCommandBuffer cmd) { + VkRenderPassFragmentDensityMapOffsetEndInfoEXT fragmentDensityOffsetStruct = { + VK_STRUCTURE_TYPE_RENDER_PASS_FRAGMENT_DENSITY_MAP_OFFSET_END_INFO_EXT, + NULL, + (uint32_t)fragmentDensityMapOffsets.size(), + fragmentDensityMapOffsets.data(), + }; + if(dynamicRendering.active) { if(!dynamicRendering.suspended) - ObjDisp(cmd)->CmdEndRendering(Unwrap(cmd)); + { + if(fragmentDensityMapOffsets.empty()) + { + ObjDisp(cmd)->CmdEndRendering(Unwrap(cmd)); + } + else + { + VkRenderingEndInfoEXT endInfo = { + VK_STRUCTURE_TYPE_RENDERING_END_INFO_EXT, + &fragmentDensityOffsetStruct, + }; + + // the only time we can possibly have fragment offsets and be using dynamic rendering is if + // this function is available by definition, so we don't have to check for it + ObjDisp(cmd)->CmdEndRendering2EXT(Unwrap(cmd), &endInfo); + } + } } else { - ObjDisp(cmd)->CmdEndRenderPass(Unwrap(cmd)); + if(fragmentDensityMapOffsets.empty()) + { + ObjDisp(cmd)->CmdEndRenderPass(Unwrap(cmd)); + } + else + { + VkSubpassEndInfo endInfo = { + VK_STRUCTURE_TYPE_SUBPASS_END_INFO, + &fragmentDensityOffsetStruct, + }; + + // the only time we can possibly have fragment offsets and be using a normal render pass is if + // this function is available by definition, so we don't have to check for it + ObjDisp(cmd)->CmdEndRenderPass2(Unwrap(cmd), &endInfo); + } } } diff --git a/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp index a4020ff07..c3250ecad 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_cmd_funcs.cpp @@ -2186,6 +2186,8 @@ bool WrappedVulkan::Serialise_vkCmdBeginRenderPass(SerialiserType &ser, VkComman renderstate.renderArea = RenderPassBegin.renderArea; renderstate.subpassContents = contents; + renderstate.fragmentDensityMapOffsets.clear(); + const VkRenderPassAttachmentBeginInfo *attachmentsInfo = (const VkRenderPassAttachmentBeginInfo *)FindNextStruct( &RenderPassBegin, VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO); @@ -2804,6 +2806,8 @@ bool WrappedVulkan::Serialise_vkCmdBeginRenderPass2(SerialiserType &ser, renderstate.renderArea = RenderPassBegin.renderArea; renderstate.subpassContents = SubpassBegin.contents; + renderstate.fragmentDensityMapOffsets.clear(); + const VkRenderPassAttachmentBeginInfo *attachmentsInfo = (const VkRenderPassAttachmentBeginInfo *)FindNextStruct( &RenderPassBegin, VK_STRUCTURE_TYPE_RENDER_PASS_ATTACHMENT_BEGIN_INFO); @@ -7647,6 +7651,8 @@ bool WrappedVulkan::Serialise_vkCmdBeginRendering(SerialiserType &ser, VkCommand renderstate.dynamicRendering.CopyAttachmentNexts(); + renderstate.fragmentDensityMapOffsets.clear(); + const VkRenderingFragmentDensityMapAttachmentInfoEXT *fragmentDensityAttachment = (const VkRenderingFragmentDensityMapAttachmentInfoEXT *)FindNextStruct( &RenderingInfo,