diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index e6ccc783..9e0f58cb 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -29,7 +29,8 @@ namespace dxvk { // undefined, so we have to bind and set up everything // before any draw or dispatch command is recorded. m_flags.clr( - DxvkContextFlag::GpRenderPassBound); + DxvkContextFlag::GpRenderPassBound, + DxvkContextFlag::GpClearRenderTargets); m_flags.set( DxvkContextFlag::GpDirtyPipeline, @@ -88,7 +89,9 @@ namespace dxvk { void DxvkContext::bindRenderTargets(const DxvkRenderTargets& targets) { m_state.om.renderTargets = targets; - // TODO execute pending clears + // If necessary, perform clears on the active render targets + if (m_flags.test(DxvkContextFlag::GpClearRenderTargets)) + this->startRenderPass(); // Set up default render pass ops this->resetRenderPassOps( @@ -398,8 +401,8 @@ namespace dxvk { this->spillRenderPass(); DxvkAttachmentOps op; - op.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; - op.loadLayout = imageView->imageInfo().layout; + op.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + op.loadLayout = VK_IMAGE_LAYOUT_UNDEFINED; op.storeOp = VK_ATTACHMENT_STORE_OP_STORE; op.storeLayout = imageView->imageInfo().layout; @@ -418,29 +421,33 @@ namespace dxvk { } this->renderPassBindFramebuffer( - m_device->createFramebuffer(attachments), ops); - } else { - // Make sure that the currently bound - // framebuffer can be rendered to - this->startRenderPass(); - } - - // Clear the attachment in quesion - VkClearAttachment clearInfo; - clearInfo.aspectMask = clearAspects; - clearInfo.colorAttachment = attachmentIndex; - clearInfo.clearValue = clearValue; - - if (attachmentIndex < 0) - clearInfo.colorAttachment = 0; - - m_cmd->cmdClearAttachments( - 1, &clearInfo, 1, &clearRect); - - // If we used a temporary framebuffer, we'll have to unbind it - // again in order to not disturb subsequent rendering commands. - if (attachmentIndex < 0) + m_device->createFramebuffer(attachments), + ops, 1, &clearValue); this->renderPassUnbindFramebuffer(); + } else if (m_flags.test(DxvkContextFlag::GpRenderPassBound)) { + // Clear the attachment in quesion. For color images, + // the attachment index for the current subpass is + // equal to the render pass attachment index. + VkClearAttachment clearInfo; + clearInfo.aspectMask = clearAspects; + clearInfo.colorAttachment = attachmentIndex; + clearInfo.clearValue = clearValue; + + m_cmd->cmdClearAttachments( + 1, &clearInfo, 1, &clearRect); + } else { + // Perform the clear when starting the render pass + if (clearAspects & VK_IMAGE_ASPECT_COLOR_BIT) { + m_state.om.renderPassOps.colorOps[attachmentIndex].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + m_state.om.renderPassOps.colorOps[attachmentIndex].loadLayout = VK_IMAGE_LAYOUT_UNDEFINED; + } else { + m_state.om.renderPassOps.depthOps.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + m_state.om.renderPassOps.depthOps.loadLayout = VK_IMAGE_LAYOUT_UNDEFINED; + } + + m_state.om.clearValues[attachmentIndex] = clearValue; + m_flags.set(DxvkContextFlag::GpClearRenderTargets); + } } @@ -1515,10 +1522,13 @@ namespace dxvk { if (!m_flags.test(DxvkContextFlag::GpRenderPassBound) && (m_state.om.framebuffer != nullptr)) { m_flags.set(DxvkContextFlag::GpRenderPassBound); + m_flags.clr(DxvkContextFlag::GpClearRenderTargets); this->renderPassBindFramebuffer( m_state.om.framebuffer, - m_state.om.renderPassOps); + m_state.om.renderPassOps, + m_state.om.clearValues.size(), + m_state.om.clearValues.data()); // Don't discard image contents if we have // to spill the current render pass @@ -1530,7 +1540,8 @@ namespace dxvk { void DxvkContext::spillRenderPass() { - // TODO execute pending clears + if (m_flags.test(DxvkContextFlag::GpClearRenderTargets)) + this->startRenderPass(); if (m_flags.test(DxvkContextFlag::GpRenderPassBound)) { m_flags.clr(DxvkContextFlag::GpRenderPassBound); @@ -1541,7 +1552,9 @@ namespace dxvk { void DxvkContext::renderPassBindFramebuffer( const Rc& framebuffer, - const DxvkRenderPassOps& ops) { + const DxvkRenderPassOps& ops, + uint32_t clearValueCount, + const VkClearValue* clearValues) { const DxvkFramebufferSize fbSize = framebuffer->size(); VkRect2D renderArea; @@ -1554,8 +1567,8 @@ namespace dxvk { info.renderPass = framebuffer->getRenderPassHandle(ops); info.framebuffer = framebuffer->handle(); info.renderArea = renderArea; - info.clearValueCount = 0; - info.pClearValues = nullptr; + info.clearValueCount = clearValueCount; + info.pClearValues = clearValues; m_cmd->cmdBeginRenderPass(&info, VK_SUBPASS_CONTENTS_INLINE); diff --git a/src/dxvk/dxvk_context.h b/src/dxvk/dxvk_context.h index e3743fa7..7528f935 100644 --- a/src/dxvk/dxvk_context.h +++ b/src/dxvk/dxvk_context.h @@ -644,7 +644,9 @@ namespace dxvk { void renderPassBindFramebuffer( const Rc& framebuffer, - const DxvkRenderPassOps& ops); + const DxvkRenderPassOps& ops, + uint32_t clearValueCount, + const VkClearValue* clearValues); void renderPassUnbindFramebuffer(); diff --git a/src/dxvk/dxvk_context_state.h b/src/dxvk/dxvk_context_state.h index 5516e362..9d7677cb 100644 --- a/src/dxvk/dxvk_context_state.h +++ b/src/dxvk/dxvk_context_state.h @@ -16,12 +16,13 @@ namespace dxvk { /** * \brief Graphics pipeline state flags * - * Stores some information on which state of the - * graphics pipeline has changed and/or needs to - * be updated. + * Stores some information on which state + * of the graphics and compute pipelines + * has changed and/or needs to be updated. */ enum class DxvkContextFlag : uint64_t { GpRenderPassBound, ///< Render pass is currently bound + GpClearRenderTargets, ///< Render targets need to be cleared GpDirtyFramebuffer, ///< Framebuffer binding is out of date GpDirtyPipeline, ///< Graphics pipeline binding is out of date GpDirtyPipelineState, ///< Graphics pipeline needs to be recompiled @@ -54,7 +55,7 @@ namespace dxvk { struct DxvkOutputMergerState { - std::array clearValue; + std::array clearValues = { }; DxvkRenderTargets renderTargets; DxvkRenderPassOps renderPassOps; diff --git a/src/dxvk/dxvk_framebuffer.cpp b/src/dxvk/dxvk_framebuffer.cpp index 46865662..77d0ddd6 100644 --- a/src/dxvk/dxvk_framebuffer.cpp +++ b/src/dxvk/dxvk_framebuffer.cpp @@ -13,20 +13,18 @@ namespace dxvk { m_renderSize (computeRenderSize(defaultSize)) { std::array views; - uint32_t viewId = 0; - for (uint32_t i = 0; i < MaxNumRenderTargets; i++) { if (m_renderTargets.color[i].view != nullptr) { - views[viewId] = m_renderTargets.color[i].view->handle(); - m_attachments[viewId] = &m_renderTargets.color[i]; - viewId += 1; + views[m_attachmentCount] = m_renderTargets.color[i].view->handle(); + m_attachments[m_attachmentCount] = &m_renderTargets.color[i]; + m_attachmentCount += 1; } } if (m_renderTargets.depth.view != nullptr) { - views[viewId] = m_renderTargets.depth.view->handle(); - m_attachments[viewId] = &m_renderTargets.depth; - viewId += 1; + views[m_attachmentCount] = m_renderTargets.depth.view->handle(); + m_attachments[m_attachmentCount] = &m_renderTargets.depth; + m_attachmentCount += 1; } VkFramebufferCreateInfo info; @@ -34,7 +32,7 @@ namespace dxvk { info.pNext = nullptr; info.flags = 0; info.renderPass = m_renderPass->getDefaultHandle(); - info.attachmentCount = viewId; + info.attachmentCount = m_attachmentCount; info.pAttachments = views.data(); info.width = m_renderSize.width; info.height = m_renderSize.height;