Add RP normalisation option

This commit is contained in:
baldurk
2025-02-13 18:31:58 +00:00
parent 34d4cd51ef
commit b02dbdc1b5
4 changed files with 229 additions and 127 deletions
+2
View File
@@ -1051,6 +1051,8 @@ private:
void AddImplicitResolveResourceUsage(uint32_t subpass = 0);
rdcarray<VkImageMemoryBarrier> GetImplicitRenderPassBarriers(uint32_t subpass = 0);
rdcstr MakeRenderPassOpString(bool store);
void ApplyRPStoreDiscards(VkCommandBuffer commandBuffer, VkRect2D renderArea,
ResourceId currentRP, const rdcarray<ResourceId> &attachments);
void ApplyRPLoadDiscards(VkCommandBuffer commandBuffer, VkRect2D renderArea);
RDCDriver GetFrameCaptureDriver() { return RDCDriver::Vulkan; }
+2 -1
View File
@@ -2376,7 +2376,8 @@ void VulkanDebugManager::FillWithDiscardPattern(VkCommandBuffer cmd, DiscardType
: (VkAccessFlags)VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dstimBarrier.dstAccessMask = VK_ACCESS_ALL_WRITE_BITS | VK_ACCESS_ALL_READ_BITS;
DoPipelineBarrier(cmd, 1, &dstimBarrier);
if(curLayout != VK_IMAGE_LAYOUT_UNDEFINED)
DoPipelineBarrier(cmd, 1, &dstimBarrier);
m_pDriver->GetCmdRenderState().BindPipeline(m_pDriver, cmd, VulkanRenderState::BindInitial,
false);
+157 -84
View File
@@ -30,6 +30,7 @@
RDOC_DEBUG_CONFIG(
bool, Vulkan_Debug_VerboseCommandRecording, false,
"Add verbose logging around recording and submission of command buffers in vulkan.");
RDOC_EXTERN_CONFIG(bool, Vulkan_Hack_DisableRPRobustness);
static rdcstr ToHumanStr(const VkAttachmentLoadOp &el)
{
@@ -768,6 +769,64 @@ void WrappedVulkan::ApplyRPLoadDiscards(VkCommandBuffer commandBuffer, VkRect2D
}
}
void WrappedVulkan::ApplyRPStoreDiscards(VkCommandBuffer commandBuffer, VkRect2D renderArea,
ResourceId currentRP,
const rdcarray<ResourceId> &attachments)
{
const VulkanCreationInfo::RenderPass &rpinfo = m_CreationInfo.m_RenderPass[currentRP];
for(size_t i = 0; i < attachments.size(); i++)
{
if(!rpinfo.attachments[i].used)
continue;
const VulkanCreationInfo::ImageView &viewInfo = m_CreationInfo.m_ImageView[attachments[i]];
VkImage image = GetResourceManager()->GetCurrentHandle<VkImage>(viewInfo.image);
VkImageLayout layout = rpinfo.attachments[i].finalLayout;
if(Vulkan_Hack_DisableRPRobustness())
layout = VK_IMAGE_LAYOUT_UNDEFINED;
if(IsStencilFormat(viewInfo.format))
{
// check to see if stencil and depth store ops are different and apply them
// individually here
const bool depthDontCareStore =
(rpinfo.attachments[i].storeOp == VK_ATTACHMENT_STORE_OP_DONT_CARE);
const bool stencilDontCareStore =
(rpinfo.attachments[i].stencilStoreOp == VK_ATTACHMENT_STORE_OP_DONT_CARE);
// if they're both don't care then we can do a simple discard clear
if(depthDontCareStore && stencilDontCareStore)
{
GetDebugManager()->FillWithDiscardPattern(commandBuffer, DiscardType::RenderPassStore,
image, layout, viewInfo.range, renderArea);
}
else
{
// otherwise only don't care the appropriate aspects
VkImageSubresourceRange range = viewInfo.range;
range.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
if(depthDontCareStore && (viewInfo.range.aspectMask & range.aspectMask) != 0)
GetDebugManager()->FillWithDiscardPattern(commandBuffer, DiscardType::RenderPassStore,
image, layout, range, renderArea);
range.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
if(stencilDontCareStore && (viewInfo.range.aspectMask & range.aspectMask) != 0)
GetDebugManager()->FillWithDiscardPattern(commandBuffer, DiscardType::RenderPassStore,
image, layout, range, renderArea);
}
}
else if(rpinfo.attachments[i].storeOp == VK_ATTACHMENT_STORE_OP_DONT_CARE)
{
GetDebugManager()->FillWithDiscardPattern(commandBuffer, DiscardType::RenderPassStore, image,
layout, viewInfo.range, renderArea);
}
}
}
// Command pool functions
template <typename SerialiserType>
@@ -2274,58 +2333,7 @@ bool WrappedVulkan::Serialise_vkCmdEndRenderPass(SerialiserType &ser, VkCommandB
if(m_ReplayOptions.optimisation != ReplayOptimisationLevel::Fastest &&
!m_FeedbackRPs.contains(currentRP))
{
const VulkanCreationInfo::RenderPass &rpinfo = m_CreationInfo.m_RenderPass[currentRP];
for(size_t i = 0; i < attachments.size(); i++)
{
if(!rpinfo.attachments[i].used)
continue;
const VulkanCreationInfo::ImageView &viewInfo =
m_CreationInfo.m_ImageView[attachments[i]];
VkImage image = GetResourceManager()->GetCurrentHandle<VkImage>(viewInfo.image);
if(IsStencilFormat(viewInfo.format))
{
// check to see if stencil and depth store ops are different and apply them
// individually here
const bool depthDontCareStore =
(rpinfo.attachments[i].storeOp == VK_ATTACHMENT_STORE_OP_DONT_CARE);
const bool stencilDontCareStore =
(rpinfo.attachments[i].stencilStoreOp == VK_ATTACHMENT_STORE_OP_DONT_CARE);
// if they're both don't care then we can do a simple discard clear
if(depthDontCareStore && stencilDontCareStore)
{
GetDebugManager()->FillWithDiscardPattern(
commandBuffer, DiscardType::RenderPassStore, image,
rpinfo.attachments[i].finalLayout, viewInfo.range, renderArea);
}
else
{
// otherwise only don't care the appropriate aspects
VkImageSubresourceRange range = viewInfo.range;
range.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
if(depthDontCareStore && (viewInfo.range.aspectMask & range.aspectMask) != 0)
GetDebugManager()->FillWithDiscardPattern(
commandBuffer, DiscardType::RenderPassStore, image,
rpinfo.attachments[i].finalLayout, range, renderArea);
range.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
if(stencilDontCareStore && (viewInfo.range.aspectMask & range.aspectMask) != 0)
GetDebugManager()->FillWithDiscardPattern(
commandBuffer, DiscardType::RenderPassStore, image,
rpinfo.attachments[i].finalLayout, range, renderArea);
}
}
else if(rpinfo.attachments[i].storeOp == VK_ATTACHMENT_STORE_OP_DONT_CARE)
{
GetDebugManager()->FillWithDiscardPattern(commandBuffer, DiscardType::RenderPassStore,
image, rpinfo.attachments[i].finalLayout,
viewInfo.range, renderArea);
}
}
ApplyRPStoreDiscards(commandBuffer, renderArea, currentRP, attachments);
}
GetResourceManager()->RecordBarriers(m_BakedCmdBufferInfo[m_LastCmdBufferID].imageStates,
@@ -2339,6 +2347,14 @@ bool WrappedVulkan::Serialise_vkCmdEndRenderPass(SerialiserType &ser, VkCommandB
m_BakedCmdBufferInfo[m_LastCmdBufferID].renderPassOpen = false;
m_BakedCmdBufferInfo[m_LastCmdBufferID].endBarriers.append(GetImplicitRenderPassBarriers(~0U));
ResourceId currentRP = GetCmdRenderState().GetRenderPass();
if(Vulkan_Hack_DisableRPRobustness() && !m_FeedbackRPs.contains(currentRP))
{
ApplyRPStoreDiscards(commandBuffer, GetCmdRenderState().renderArea, currentRP,
GetCmdRenderState().GetFramebufferAttachments());
}
}
}
else
@@ -2942,7 +2958,6 @@ bool WrappedVulkan::Serialise_vkCmdEndRenderPass2(SerialiserType &ser, VkCommand
rdcarray<ResourceId> attachments;
VkRect2D renderArea;
const VulkanCreationInfo::RenderPass &rpinfo = m_CreationInfo.m_RenderPass[currentRP];
{
VulkanRenderState &renderstate = GetCmdRenderState();
@@ -2968,20 +2983,7 @@ bool WrappedVulkan::Serialise_vkCmdEndRenderPass2(SerialiserType &ser, VkCommand
if(m_ReplayOptions.optimisation != ReplayOptimisationLevel::Fastest &&
!m_FeedbackRPs.contains(currentRP))
{
for(size_t i = 0; i < attachments.size(); i++)
{
const VulkanCreationInfo::ImageView &viewInfo =
m_CreationInfo.m_ImageView[attachments[i]];
VkImage image = GetResourceManager()->GetCurrentHandle<VkImage>(viewInfo.image);
if(rpinfo.attachments[i].storeOp == VK_ATTACHMENT_STORE_OP_DONT_CARE &&
rpinfo.attachments[i].used)
{
GetDebugManager()->FillWithDiscardPattern(commandBuffer, DiscardType::RenderPassStore,
image, rpinfo.attachments[i].finalLayout,
viewInfo.range, renderArea);
}
}
ApplyRPStoreDiscards(commandBuffer, renderArea, currentRP, attachments);
}
GetResourceManager()->RecordBarriers(m_BakedCmdBufferInfo[m_LastCmdBufferID].imageStates,
@@ -3010,6 +3012,13 @@ bool WrappedVulkan::Serialise_vkCmdEndRenderPass2(SerialiserType &ser, VkCommand
stateOffsets[i] = fragmentDensityOffsetStruct->pFragmentDensityOffsets[i];
}
}
ResourceId currentRP = GetCmdRenderState().GetRenderPass();
if(Vulkan_Hack_DisableRPRobustness() && !m_FeedbackRPs.contains(currentRP))
{
ApplyRPStoreDiscards(commandBuffer, GetCmdRenderState().renderArea, currentRP,
GetCmdRenderState().GetFramebufferAttachments());
}
}
}
else
@@ -7305,24 +7314,36 @@ bool WrappedVulkan::Serialise_vkCmdBeginRendering(SerialiserType &ser, VkCommand
// effects of that are never user-visible.
if(m_ReplayOptions.optimisation != ReplayOptimisationLevel::Fastest)
{
for(uint32_t i = 0; i < unwrappedInfo->colorAttachmentCount + 2; i++)
if(Vulkan_Hack_DisableRPRobustness())
{
VkRenderingAttachmentInfo *att =
(VkRenderingAttachmentInfo *)unwrappedInfo->pColorAttachments + i;
static bool warned = false;
if(i == unwrappedInfo->colorAttachmentCount)
att = (VkRenderingAttachmentInfo *)unwrappedInfo->pDepthAttachment;
else if(i == unwrappedInfo->colorAttachmentCount + 1)
att = (VkRenderingAttachmentInfo *)unwrappedInfo->pStencilAttachment;
if(!warned)
RDCWARN("RP attachment normalisation not applied!");
if(!att)
continue;
warned = true;
}
else
{
for(uint32_t i = 0; i < unwrappedInfo->colorAttachmentCount + 2; i++)
{
VkRenderingAttachmentInfo *att =
(VkRenderingAttachmentInfo *)unwrappedInfo->pColorAttachments + i;
if(att->storeOp != VK_ATTACHMENT_STORE_OP_NONE)
att->storeOp = VK_ATTACHMENT_STORE_OP_STORE;
if(i == unwrappedInfo->colorAttachmentCount)
att = (VkRenderingAttachmentInfo *)unwrappedInfo->pDepthAttachment;
else if(i == unwrappedInfo->colorAttachmentCount + 1)
att = (VkRenderingAttachmentInfo *)unwrappedInfo->pStencilAttachment;
if(att->loadOp == VK_ATTACHMENT_LOAD_OP_DONT_CARE)
att->loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
if(!att)
continue;
if(att->storeOp != VK_ATTACHMENT_STORE_OP_NONE)
att->storeOp = VK_ATTACHMENT_STORE_OP_STORE;
if(att->loadOp == VK_ATTACHMENT_LOAD_OP_DONT_CARE)
att->loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
}
}
}
@@ -7550,14 +7571,14 @@ bool WrappedVulkan::Serialise_vkCmdEndRendering(SerialiserType &ser, VkCommandBu
if(IsActiveReplaying(m_State))
{
VulkanRenderState &renderstate = GetCmdRenderState();
bool suspending = (renderstate.dynamicRendering.flags & VK_RENDERING_SUSPENDING_BIT) != 0;
if(InRerecordRange(m_LastCmdBufferID))
{
commandBuffer = RerecordCmdBuf(m_LastCmdBufferID);
VulkanRenderState &renderstate = GetCmdRenderState();
bool suspending = (renderstate.dynamicRendering.flags & VK_RENDERING_SUSPENDING_BIT) != 0;
if(ShouldUpdateRenderpassActive(m_LastCmdBufferID, true))
{
m_BakedCmdBufferInfo[m_LastCmdBufferID].renderPassOpen = false;
@@ -7648,6 +7669,58 @@ bool WrappedVulkan::Serialise_vkCmdEndRendering(SerialiserType &ser, VkCommandBu
ObjDisp(commandBuffer)->CmdEndRendering(Unwrap(commandBuffer));
m_BakedCmdBufferInfo[m_LastCmdBufferID].renderPassOpen = false;
// only do discards when not suspending!
if(Vulkan_Hack_DisableRPRobustness() && !suspending)
{
rdcarray<VkRenderingAttachmentInfo> dynAtts = renderstate.dynamicRendering.color;
dynAtts.push_back(renderstate.dynamicRendering.depth);
size_t depthIdx = dynAtts.size() - 1;
size_t stencilIdx = ~0U;
VkImageAspectFlags depthAspects = VK_IMAGE_ASPECT_DEPTH_BIT;
// if we have different images attached, or different store ops, treat stencil separately
if(renderstate.dynamicRendering.stencil.imageView != VK_NULL_HANDLE &&
(renderstate.dynamicRendering.depth.imageView !=
renderstate.dynamicRendering.stencil.imageView ||
renderstate.dynamicRendering.depth.storeOp !=
renderstate.dynamicRendering.stencil.storeOp))
{
dynAtts.push_back(renderstate.dynamicRendering.stencil);
stencilIdx = dynAtts.size() - 1;
}
// otherwise if the same image is bound and the storeOp is the same then include it
else if(renderstate.dynamicRendering.stencil.imageView != VK_NULL_HANDLE)
{
depthAspects |= VK_IMAGE_ASPECT_STENCIL_BIT;
}
for(size_t i = 0; i < dynAtts.size(); i++)
{
if(dynAtts[i].imageView == VK_NULL_HANDLE)
continue;
const VulkanCreationInfo::ImageView &viewInfo =
m_CreationInfo.m_ImageView[GetResID(dynAtts[i].imageView)];
VkImage image = GetResourceManager()->GetCurrentHandle<VkImage>(viewInfo.image);
if(dynAtts[i].storeOp == VK_ATTACHMENT_STORE_OP_DONT_CARE)
{
VkImageSubresourceRange range = viewInfo.range;
if(i == depthIdx)
range.aspectMask = depthAspects;
if(i == stencilIdx)
range.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
GetDebugManager()->FillWithDiscardPattern(commandBuffer, DiscardType::RenderPassStore,
image, VK_IMAGE_LAYOUT_UNDEFINED, range,
renderstate.renderArea);
}
}
}
}
}
else
@@ -24,6 +24,11 @@
#include "../vk_core.h"
#include "../vk_debug.h"
#include "core/settings.h"
RDOC_CONFIG(
bool, Vulkan_Hack_DisableRPNormalisation, false,
"Disable default behaviour to normalise renderpasses to be more consistent and debuggable.");
static void PatchSeparateStencil(VkAttachmentDescription &att, const VkAttachmentReference *ref)
{
@@ -1041,28 +1046,35 @@ bool WrappedVulkan::Serialise_vkCreateRenderPass(SerialiserType &ser, VkDevice d
VkAttachmentDescription *att = (VkAttachmentDescription *)CreateInfo.pAttachments;
for(uint32_t i = 0; i < CreateInfo.attachmentCount; i++)
{
if(att[i].storeOp != VK_ATTACHMENT_STORE_OP_NONE)
att[i].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
if(att[i].stencilStoreOp != VK_ATTACHMENT_STORE_OP_NONE)
att[i].stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
if(m_ReplayOptions.optimisation != ReplayOptimisationLevel::Fastest)
if(Vulkan_Hack_DisableRPNormalisation())
{
if(att[i].loadOp == VK_ATTACHMENT_LOAD_OP_DONT_CARE)
att[i].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
if(att[i].stencilLoadOp == VK_ATTACHMENT_LOAD_OP_DONT_CARE)
att[i].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
RDCWARN("RP attachment normalisation not applied!");
}
else
{
if(att[i].storeOp != VK_ATTACHMENT_STORE_OP_NONE)
att[i].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
if(att[i].stencilStoreOp != VK_ATTACHMENT_STORE_OP_NONE)
att[i].stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
if(att[i].loadOp == VK_ATTACHMENT_LOAD_OP_LOAD &&
att[i].initialLayout == VK_IMAGE_LAYOUT_UNDEFINED)
if(m_ReplayOptions.optimisation != ReplayOptimisationLevel::Fastest)
{
att[i].initialLayout = VK_IMAGE_LAYOUT_GENERAL;
}
if(att[i].loadOp == VK_ATTACHMENT_LOAD_OP_DONT_CARE)
att[i].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
if(att[i].stencilLoadOp == VK_ATTACHMENT_LOAD_OP_DONT_CARE)
att[i].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
if(att[i].stencilLoadOp == VK_ATTACHMENT_LOAD_OP_LOAD &&
att[i].initialLayout == VK_IMAGE_LAYOUT_UNDEFINED)
{
att[i].initialLayout = VK_IMAGE_LAYOUT_GENERAL;
if(att[i].loadOp == VK_ATTACHMENT_LOAD_OP_LOAD &&
att[i].initialLayout == VK_IMAGE_LAYOUT_UNDEFINED)
{
att[i].initialLayout = VK_IMAGE_LAYOUT_GENERAL;
}
if(att[i].stencilLoadOp == VK_ATTACHMENT_LOAD_OP_LOAD &&
att[i].initialLayout == VK_IMAGE_LAYOUT_UNDEFINED)
{
att[i].initialLayout = VK_IMAGE_LAYOUT_GENERAL;
}
}
}
@@ -1124,6 +1136,21 @@ bool WrappedVulkan::Serialise_vkCreateRenderPass(SerialiserType &ser, VkDevice d
att[i].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
if(att[i].stencilLoadOp != VK_ATTACHMENT_LOAD_OP_NONE)
att[i].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
if(Vulkan_Hack_DisableRPNormalisation())
{
if((att[i].loadOp == VK_ATTACHMENT_LOAD_OP_LOAD ||
att[i].stencilLoadOp == VK_ATTACHMENT_LOAD_OP_LOAD) &&
att[i].initialLayout == VK_IMAGE_LAYOUT_UNDEFINED)
{
att[i].initialLayout = VK_IMAGE_LAYOUT_GENERAL;
}
if(att[i].storeOp != VK_ATTACHMENT_STORE_OP_NONE)
att[i].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
if(att[i].stencilStoreOp != VK_ATTACHMENT_STORE_OP_NONE)
att[i].stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
}
}
VkRenderPassCreateInfo loadInfo = CreateInfo;
@@ -1295,36 +1322,35 @@ bool WrappedVulkan::Serialise_vkCreateRenderPass2(SerialiserType &ser, VkDevice
VkAttachmentDescription2 *att = (VkAttachmentDescription2 *)CreateInfo.pAttachments;
for(uint32_t i = 0; i < CreateInfo.attachmentCount; i++)
{
if(att[i].storeOp != VK_ATTACHMENT_STORE_OP_NONE)
att[i].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
if(att[i].stencilStoreOp != VK_ATTACHMENT_STORE_OP_NONE)
att[i].stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
if(m_ReplayOptions.optimisation != ReplayOptimisationLevel::Fastest)
if(Vulkan_Hack_DisableRPNormalisation())
{
if(att[i].loadOp == VK_ATTACHMENT_LOAD_OP_DONT_CARE)
att[i].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
if(att[i].stencilLoadOp == VK_ATTACHMENT_LOAD_OP_DONT_CARE)
att[i].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
RDCWARN("RP attachment normalisation not applied!");
}
if(m_ReplayOptions.optimisation != ReplayOptimisationLevel::Fastest)
else
{
if(att[i].loadOp == VK_ATTACHMENT_LOAD_OP_DONT_CARE)
att[i].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
if(att[i].stencilLoadOp == VK_ATTACHMENT_LOAD_OP_DONT_CARE)
att[i].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
if(att[i].storeOp != VK_ATTACHMENT_STORE_OP_NONE)
att[i].storeOp = VK_ATTACHMENT_STORE_OP_STORE;
if(att[i].stencilStoreOp != VK_ATTACHMENT_STORE_OP_NONE)
att[i].stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE;
if(att[i].loadOp == VK_ATTACHMENT_LOAD_OP_LOAD &&
att[i].initialLayout == VK_IMAGE_LAYOUT_UNDEFINED)
if(m_ReplayOptions.optimisation != ReplayOptimisationLevel::Fastest)
{
att[i].initialLayout = VK_IMAGE_LAYOUT_GENERAL;
}
if(att[i].loadOp == VK_ATTACHMENT_LOAD_OP_DONT_CARE)
att[i].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
if(att[i].stencilLoadOp == VK_ATTACHMENT_LOAD_OP_DONT_CARE)
att[i].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
if(att[i].stencilLoadOp == VK_ATTACHMENT_LOAD_OP_LOAD &&
att[i].initialLayout == VK_IMAGE_LAYOUT_UNDEFINED)
{
att[i].initialLayout = VK_IMAGE_LAYOUT_GENERAL;
if(att[i].loadOp == VK_ATTACHMENT_LOAD_OP_LOAD &&
att[i].initialLayout == VK_IMAGE_LAYOUT_UNDEFINED)
{
att[i].initialLayout = VK_IMAGE_LAYOUT_GENERAL;
}
if(att[i].stencilLoadOp == VK_ATTACHMENT_LOAD_OP_LOAD &&
att[i].initialLayout == VK_IMAGE_LAYOUT_UNDEFINED)
{
att[i].initialLayout = VK_IMAGE_LAYOUT_GENERAL;
}
}
}