diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index 4a1f03eac..cbaec650c 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -567,7 +567,7 @@ namespace dxvk { // If not, we need to create a temporary framebuffer. int32_t attachmentIndex = -1; - if (m_flags.test(DxvkContextFlag::GpRenderPassBound) + if (m_state.om.framebuffer != nullptr && m_state.om.framebuffer->isFullSize(imageView)) attachmentIndex = m_state.om.framebuffer->findAttachment(imageView); @@ -580,6 +580,9 @@ namespace dxvk { // If there is overlap, we need to explicitly transition affected attachments. this->spillRenderPass(true); this->prepareImage(m_execBarriers, imageView->image(), imageView->subresources(), false); + } else if (!m_state.om.framebuffer->isWritable(attachmentIndex, clearAspects)) { + // We cannot inline clears if the clear aspects are not writable + this->spillRenderPass(true); } if (m_flags.test(DxvkContextFlag::GpRenderPassBound)) @@ -1757,6 +1760,28 @@ namespace dxvk { else if (discardAspects & VK_IMAGE_ASPECT_DEPTH_BIT) depthOp.loadOpS = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + if (!m_flags.test(DxvkContextFlag::GpRenderPassBound) && (attachmentIndex >= 0)) { + // Do not fold the clear/discard into the render pass if any of the affected aspects + // isn't writable. We can only hit this particular path when starting a render pass, + // so we can safely manipulate load layouts here. + if (!m_state.om.framebuffer->isWritable(attachmentIndex, clearAspects | discardAspects)) { + int32_t colorIndex = m_state.om.framebuffer->getColorAttachmentIndex(attachmentIndex); + VkImageLayout renderLayout = m_state.om.framebuffer->getAttachment(attachmentIndex).layout; + + if (colorIndex < 0) { + depthOp.loadLayout = m_state.om.renderPassOps.depthOps.loadLayout; + depthOp.storeLayout = renderLayout; + m_state.om.renderPassOps.depthOps.loadLayout = renderLayout; + } else { + colorOp.loadLayout = m_state.om.renderPassOps.colorOps[colorIndex].loadLayout; + colorOp.storeLayout = renderLayout; + m_state.om.renderPassOps.colorOps[colorIndex].loadLayout = renderLayout; + } + + attachmentIndex = -1; + } + } + bool is3D = imageView->imageInfo().type == VK_IMAGE_TYPE_3D; if ((clearAspects | discardAspects) == imageView->info().aspect && !is3D) { @@ -2718,6 +2743,9 @@ namespace dxvk { && m_state.om.framebuffer->isFullSize(imageView)) attachmentIndex = m_state.om.framebuffer->findAttachment(imageView); + if (attachmentIndex >= 0 && !m_state.om.framebuffer->isWritable(attachmentIndex, aspect)) + attachmentIndex = -1; + if (attachmentIndex < 0) { this->spillRenderPass(false); diff --git a/src/dxvk/dxvk_framebuffer.cpp b/src/dxvk/dxvk_framebuffer.cpp index ca2ac0c7d..6b4c44ec7 100644 --- a/src/dxvk/dxvk_framebuffer.cpp +++ b/src/dxvk/dxvk_framebuffer.cpp @@ -78,6 +78,12 @@ namespace dxvk { } + bool DxvkFramebuffer::isWritable(uint32_t attachmentIndex, VkImageAspectFlags aspects) const { + VkImageAspectFlags writableAspects = vk::getWritableAspectsForLayout(getAttachment(attachmentIndex).layout); + return (writableAspects & aspects) == aspects; + } + + DxvkRenderPassFormat DxvkFramebuffer::getRenderPassFormat(const DxvkRenderTargets& renderTargets) { DxvkRenderPassFormat format; diff --git a/src/dxvk/dxvk_framebuffer.h b/src/dxvk/dxvk_framebuffer.h index 08c311851..070efee4f 100644 --- a/src/dxvk/dxvk_framebuffer.h +++ b/src/dxvk/dxvk_framebuffer.h @@ -207,6 +207,16 @@ namespace dxvk { * the framebuffer. */ bool isFullSize(const Rc& view) const; + + /** + * \brief Checks whether an attachment is writable + * + * Needed for certain clear optimizations. + * \param [in] attachmentIndex Attachment to check + * \param [in] aspects Aspect mask to check + * \returns \c true if all aspects can be written for the given attachment + */ + bool isWritable(uint32_t attachmentIndex, VkImageAspectFlags aspects) const; /** * \brief Generatess render pass format diff --git a/src/vulkan/vulkan_util.h b/src/vulkan/vulkan_util.h index a2899d3ef..2cbd20bec 100644 --- a/src/vulkan/vulkan_util.h +++ b/src/vulkan/vulkan_util.h @@ -76,6 +76,27 @@ namespace dxvk::vk { && a.baseArrayLayer + a.layerCount >= b.baseArrayLayer + b.layerCount; } + inline VkImageAspectFlags getWritableAspectsForLayout(VkImageLayout layout) { + switch (layout) { + case VK_IMAGE_LAYOUT_GENERAL: + return VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: + return VK_IMAGE_ASPECT_COLOR_BIT; + case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: + return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL: + return VK_IMAGE_ASPECT_DEPTH_BIT; + case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL: + return VK_IMAGE_ASPECT_STENCIL_BIT; + case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL: + case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: + return 0; + default: + Logger::err(str::format("Unhandled image layout ", layout)); + return 0; + } + } + }