From e46bf78f31e9b0d10ba632715d524255c296cdc5 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Sun, 21 Feb 2021 01:36:46 +0100 Subject: [PATCH] [dxvk] Implement discardImageView Built on top of the deferred clear logic. --- src/dxvk/dxvk_context.cpp | 79 ++++++++++++++++++++++------------- src/dxvk/dxvk_context.h | 19 +++++---- src/dxvk/dxvk_context_state.h | 1 + 3 files changed, 63 insertions(+), 36 deletions(-) diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index b7a895dd..018e50e2 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -583,7 +583,7 @@ namespace dxvk { } if (m_flags.test(DxvkContextFlag::GpRenderPassBound)) - this->performClear(imageView, attachmentIndex, clearAspects, clearValue); + this->performClear(imageView, attachmentIndex, 0, clearAspects, clearValue); else this->deferClear(imageView, clearAspects, clearValue); } @@ -1224,22 +1224,18 @@ namespace dxvk { } - void DxvkContext::discardImage( - const Rc& image, - VkImageSubresourceRange subresources) { - this->spillRenderPass(false); + void DxvkContext::discardImageView( + const Rc& imageView, + VkImageAspectFlags discardAspects) { + VkImageUsageFlags viewUsage = imageView->info().usage; - if (m_execBarriers.isImageDirty(image, subresources, DxvkAccess::Write)) - m_execBarriers.recordCommands(m_cmd); - - m_execBarriers.accessImage(image, subresources, - VK_IMAGE_LAYOUT_UNDEFINED, - image->info().stages, 0, - image->info().layout, - image->info().stages, - image->info().access); - - m_cmd->trackResource(image); + // Ignore non-render target views since there's likely no good use case for + // discarding those. Also, force reinitialization even if the image is bound + // as a render target, which may have niche use cases for depth buffers. + if (viewUsage & (VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) { + this->spillRenderPass(true); + this->deferDiscard(imageView, discardAspects); + } } @@ -1728,6 +1724,7 @@ namespace dxvk { void DxvkContext::performClear( const Rc& imageView, int32_t attachmentIndex, + VkImageAspectFlags discardAspects, VkImageAspectFlags clearAspects, VkClearValue clearValue) { DxvkColorAttachmentOps colorOp; @@ -1743,16 +1740,22 @@ namespace dxvk { if (clearAspects & VK_IMAGE_ASPECT_COLOR_BIT) colorOp.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + else if (discardAspects & VK_IMAGE_ASPECT_COLOR_BIT) + colorOp.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; if (clearAspects & VK_IMAGE_ASPECT_DEPTH_BIT) depthOp.loadOpD = VK_ATTACHMENT_LOAD_OP_CLEAR; + else if (discardAspects & VK_IMAGE_ASPECT_DEPTH_BIT) + depthOp.loadOpD = VK_ATTACHMENT_LOAD_OP_DONT_CARE; if (clearAspects & VK_IMAGE_ASPECT_STENCIL_BIT) depthOp.loadOpS = VK_ATTACHMENT_LOAD_OP_CLEAR; - + else if (discardAspects & VK_IMAGE_ASPECT_DEPTH_BIT) + depthOp.loadOpS = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + bool is3D = imageView->imageInfo().type == VK_IMAGE_TYPE_3D; - if (clearAspects == imageView->info().aspect && !is3D) { + if ((clearAspects | discardAspects) == imageView->info().aspect && !is3D) { colorOp.loadLayout = VK_IMAGE_LAYOUT_UNDEFINED; depthOp.loadLayout = VK_IMAGE_LAYOUT_UNDEFINED; } @@ -1815,32 +1818,33 @@ namespace dxvk { clearRect.baseArrayLayer = 0; clearRect.layerCount = imageView->info().numLayers; - m_cmd->cmdClearAttachments(1, &clearInfo, 1, &clearRect); + if (clearAspects) + m_cmd->cmdClearAttachments(1, &clearInfo, 1, &clearRect); } else { - // Perform the clear when starting the render pass - if (clearAspects & VK_IMAGE_ASPECT_COLOR_BIT) { + // Perform the operation when starting the next render pass + if ((clearAspects | discardAspects) & VK_IMAGE_ASPECT_COLOR_BIT) { uint32_t colorIndex = m_state.om.framebuffer->getColorAttachmentIndex(attachmentIndex); m_state.om.renderPassOps.colorOps[colorIndex].loadOp = colorOp.loadOp; - if (m_state.om.renderPassOps.colorOps[colorIndex].loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR && !is3D) + if (m_state.om.renderPassOps.colorOps[colorIndex].loadOp != VK_ATTACHMENT_LOAD_OP_LOAD && !is3D) m_state.om.renderPassOps.colorOps[colorIndex].loadLayout = VK_IMAGE_LAYOUT_UNDEFINED; m_state.om.clearValues[attachmentIndex].color = clearValue.color; } - if (clearAspects & VK_IMAGE_ASPECT_DEPTH_BIT) { + if ((clearAspects | discardAspects) & VK_IMAGE_ASPECT_DEPTH_BIT) { m_state.om.renderPassOps.depthOps.loadOpD = depthOp.loadOpD; m_state.om.clearValues[attachmentIndex].depthStencil.depth = clearValue.depthStencil.depth; } - if (clearAspects & VK_IMAGE_ASPECT_STENCIL_BIT) { + if ((clearAspects | discardAspects) & VK_IMAGE_ASPECT_STENCIL_BIT) { m_state.om.renderPassOps.depthOps.loadOpS = depthOp.loadOpS; m_state.om.clearValues[attachmentIndex].depthStencil.stencil = clearValue.depthStencil.stencil; } - if (clearAspects & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { - if (m_state.om.renderPassOps.depthOps.loadOpD == VK_ATTACHMENT_LOAD_OP_CLEAR - && m_state.om.renderPassOps.depthOps.loadOpS == VK_ATTACHMENT_LOAD_OP_CLEAR) + if ((clearAspects | discardAspects) & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { + if (m_state.om.renderPassOps.depthOps.loadOpD != VK_ATTACHMENT_LOAD_OP_LOAD + && m_state.om.renderPassOps.depthOps.loadOpS != VK_ATTACHMENT_LOAD_OP_LOAD) m_state.om.renderPassOps.depthOps.loadLayout = VK_IMAGE_LAYOUT_UNDEFINED; } } @@ -1853,6 +1857,7 @@ namespace dxvk { VkClearValue clearValue) { for (auto& entry : m_deferredClears) { if (entry.imageView == imageView) { + entry.discardAspects &= ~clearAspects; entry.clearAspects |= clearAspects; if (clearAspects & VK_IMAGE_ASPECT_COLOR_BIT) @@ -1866,7 +1871,22 @@ namespace dxvk { } } - m_deferredClears.push_back({ imageView, clearAspects, clearValue }); + m_deferredClears.push_back({ imageView, 0, clearAspects, clearValue }); + } + + + void DxvkContext::deferDiscard( + const Rc& imageView, + VkImageAspectFlags discardAspects) { + for (auto& entry : m_deferredClears) { + if (entry.imageView == imageView) { + entry.discardAspects |= discardAspects; + entry.clearAspects &= ~discardAspects; + return; + } + } + + m_deferredClears.push_back({ imageView, discardAspects }); } @@ -1878,7 +1898,8 @@ namespace dxvk { if (useRenderPass && m_state.om.framebuffer->isFullSize(clear.imageView)) attachmentIndex = m_state.om.framebuffer->findAttachment(clear.imageView); - this->performClear(clear.imageView, attachmentIndex, clear.clearAspects, clear.clearValue); + this->performClear(clear.imageView, attachmentIndex, + clear.discardAspects, clear.clearAspects, clear.clearValue); } m_deferredClears.clear(); diff --git a/src/dxvk/dxvk_context.h b/src/dxvk/dxvk_context.h index 324b43a5..36c37112 100644 --- a/src/dxvk/dxvk_context.h +++ b/src/dxvk/dxvk_context.h @@ -474,18 +474,18 @@ namespace dxvk { const Rc& buffer); /** - * \brief Discards image subresources + * \brief Discards contents of an image view * * Discards the current contents of the image * and performs a fast layout transition. This * may improve performance in some cases. - * \param [in] image The image to discard - * \param [in] subresources Image subresources + * \param [in] imageView View to discard + * \param [in] discardAspects Image aspects to discard */ - void discardImage( - const Rc& image, - VkImageSubresourceRange subresources); - + void discardImageView( + const Rc& imageView, + VkImageAspectFlags discardAspects); + /** * \brief Starts compute jobs * @@ -1090,6 +1090,7 @@ namespace dxvk { void performClear( const Rc& imageView, int32_t attachmentIndex, + VkImageAspectFlags discardAspects, VkImageAspectFlags clearAspects, VkClearValue clearValue); @@ -1098,6 +1099,10 @@ namespace dxvk { VkImageAspectFlags clearAspects, VkClearValue clearValue); + void deferDiscard( + const Rc& imageView, + VkImageAspectFlags discardAspects); + void flushClears( bool useRenderPass); diff --git a/src/dxvk/dxvk_context_state.h b/src/dxvk/dxvk_context_state.h index 5ddaa780..f3fb1bf6 100644 --- a/src/dxvk/dxvk_context_state.h +++ b/src/dxvk/dxvk_context_state.h @@ -145,6 +145,7 @@ namespace dxvk { struct DxvkDeferredClear { Rc imageView; + VkImageAspectFlags discardAspects; VkImageAspectFlags clearAspects; VkClearValue clearValue; };