From 1075990dbe3e08022b82a5c89fd72547085e7c31 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Thu, 26 Apr 2018 14:47:55 +0200 Subject: [PATCH] [dxvk] Apply render target bindings at draw time This should help reduce the number of redundant render pass spills, especially in games which use deferred contexts for rendering. This optimization mostly helps in GPU-bound scenarios. --- src/dxvk/dxvk_context.cpp | 37 ++++++++++++++++++++++++++--------- src/dxvk/dxvk_context.h | 4 +--- src/dxvk/dxvk_context_state.h | 2 ++ 3 files changed, 31 insertions(+), 12 deletions(-) diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index 2908b710..66e50fd9 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -98,19 +98,18 @@ namespace dxvk { m_state.om.framebuffer = fb; } + + m_state.om.renderTargets = fb != nullptr + ? fb->renderTargets() + : DxvkRenderTargets(); + m_flags.clr(DxvkContextFlag::GpDirtyFramebuffer); } void DxvkContext::bindRenderTargets(const DxvkRenderTargets& targets) { - bool sameAsCurr = m_state.om.framebuffer != nullptr - && m_state.om.framebuffer->renderTargets().matches(targets); - - if (!sameAsCurr) { - Rc fb = targets.hasAttachments() - ? m_device->createFramebuffer(targets) - : nullptr; - - this->bindFramebuffer(fb); + if (m_state.om.framebuffer == nullptr || !m_state.om.framebuffer->renderTargets().matches(targets)) { + m_state.om.renderTargets = targets; + m_flags.set(DxvkContextFlag::GpDirtyFramebuffer); } } @@ -392,6 +391,8 @@ namespace dxvk { const VkClearRect& clearRect, VkImageAspectFlags clearAspects, const VkClearValue& clearValue) { + this->updateFramebuffer(); + // Check whether the render target view is an attachment // of the current framebuffer. If not, we need to create // a temporary framebuffer. @@ -1798,6 +1799,23 @@ namespace dxvk { } + void DxvkContext::updateFramebuffer() { + if (m_flags.test(DxvkContextFlag::GpDirtyFramebuffer)) { + m_flags.clr(DxvkContextFlag::GpDirtyFramebuffer); + + this->spillRenderPass(); + + auto fb = m_device->createFramebuffer(m_state.om.renderTargets); + + m_state.gp.state.msSampleCount = fb->sampleCount(); + m_state.gp.state.omRenderPass = fb->renderPass(); + m_state.om.framebuffer = fb; + + m_flags.set(DxvkContextFlag::GpDirtyPipelineState); + } + } + + void DxvkContext::updateIndexBufferBinding() { if (m_flags.test(DxvkContextFlag::GpDirtyIndexBuffer)) { m_flags.clr(DxvkContextFlag::GpDirtyIndexBuffer); @@ -1881,6 +1899,7 @@ namespace dxvk { void DxvkContext::commitGraphicsState() { + this->updateFramebuffer(); this->startRenderPass(); this->updateGraphicsPipeline(); this->updateIndexBufferBinding(); diff --git a/src/dxvk/dxvk_context.h b/src/dxvk/dxvk_context.h index df9b5b27..f4aed2ce 100644 --- a/src/dxvk/dxvk_context.h +++ b/src/dxvk/dxvk_context.h @@ -662,9 +662,7 @@ namespace dxvk { const DxvkBindingState& bindingState, const Rc& layout); - void updateViewports(); - void updateBlendConstants(); - void updateStencilReference(); + void updateFramebuffer(); void updateIndexBufferBinding(); void updateVertexBufferBindings(); diff --git a/src/dxvk/dxvk_context_state.h b/src/dxvk/dxvk_context_state.h index 0ebc1b31..59692883 100644 --- a/src/dxvk/dxvk_context_state.h +++ b/src/dxvk/dxvk_context_state.h @@ -22,6 +22,7 @@ namespace dxvk { */ enum class DxvkContextFlag : uint64_t { GpRenderPassBound, ///< Render pass is currently bound + GpDirtyFramebuffer, ///< Framebuffer binding is out of date GpDirtyPipeline, ///< Graphics pipeline binding is out of date GpDirtyPipelineState, ///< Graphics pipeline needs to be recompiled GpDirtyResources, ///< Graphics pipeline resource bindings are out of date @@ -53,6 +54,7 @@ namespace dxvk { struct DxvkOutputMergerState { + DxvkRenderTargets renderTargets; Rc framebuffer = nullptr; DxvkBlendConstants blendConstants = { 0.0f, 0.0f, 0.0f, 0.0f };