diff --git a/src/d3d11/d3d11_context.cpp b/src/d3d11/d3d11_context.cpp index 85297697e..47f5d2f87 100644 --- a/src/d3d11/d3d11_context.cpp +++ b/src/d3d11/d3d11_context.cpp @@ -473,62 +473,35 @@ namespace dxvk { if (rtv == nullptr) return; - // Find out whether the given attachment is currently bound - // or not, and if it is, which attachment index it has. - int32_t attachmentIndex = -1; - - for (uint32_t i = 0; i < m_state.om.renderTargetViews.size(); i++) { - if (m_state.om.renderTargetViews.at(i) == rtv) - attachmentIndex = i; - } - - // Copy the clear color into a clear value structure. - // This should also work for images that don nott have - // a floating point format. const Rc view = rtv->GetImageView(); - VkClearColorValue clearValue; - std::memcpy(clearValue.float32, ColorRGBA, - sizeof(clearValue.float32)); + VkClearValue clearValue; + clearValue.color.float32[0] = ColorRGBA[0]; + clearValue.color.float32[1] = ColorRGBA[1]; + clearValue.color.float32[2] = ColorRGBA[2]; + clearValue.color.float32[3] = ColorRGBA[3]; - if (attachmentIndex >= 0) { - // Image is bound to the pipeline for rendering. We can - // use the clear function that operates on attachments. - VkClearAttachment clearInfo; - clearInfo.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - clearInfo.colorAttachment = static_cast(attachmentIndex); - clearInfo.clearValue.color = clearValue; - - // Clear the full area. On FL 9.x, only the first array - // layer will be cleared, rather than all array layers. - VkClearRect clearRect; - clearRect.rect.offset.x = 0; - clearRect.rect.offset.y = 0; - clearRect.rect.extent.width = view->mipLevelExtent(0).width; - clearRect.rect.extent.height = view->mipLevelExtent(0).height; - clearRect.baseArrayLayer = 0; - clearRect.layerCount = view->info().numLayers; - - if (m_parent->GetFeatureLevel() < D3D_FEATURE_LEVEL_10_0) - clearRect.layerCount = 1; - - EmitCs([ - cClearInfo = clearInfo, - cClearRect = clearRect - ] (DxvkContext* ctx) { - ctx->clearRenderTarget(cClearInfo, cClearRect); - }); - } else { - // Image is not bound to the pipeline. We can still clear - // it, but we'll have to use a generic clear function. - EmitCs([ - cClearValue = clearValue, - cDstView = view - ] (DxvkContext* ctx) { - ctx->clearColorImage(cDstView->image(), - cClearValue, cDstView->subresources()); - }); - } + VkClearRect clearRect; + clearRect.rect.offset.x = 0; + clearRect.rect.offset.y = 0; + clearRect.rect.extent.width = view->mipLevelExtent(0).width; + clearRect.rect.extent.height = view->mipLevelExtent(0).height; + clearRect.baseArrayLayer = 0; + clearRect.layerCount = view->info().numLayers; + + if (m_parent->GetFeatureLevel() < D3D_FEATURE_LEVEL_10_0) + clearRect.layerCount = 1; + + EmitCs([ + cClearValue = clearValue, + cClearRect = clearRect, + cImageView = view + ] (DxvkContext* ctx) { + ctx->clearRenderTarget( + cImageView, cClearRect, + VK_IMAGE_ASPECT_COLOR_BIT, + cClearValue); + }); } @@ -606,53 +579,33 @@ namespace dxvk { if (ClearFlags & D3D11_CLEAR_STENCIL) aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; - const DxvkFormatInfo* formatInfo = - imageFormatInfo(view->info().format); - aspectMask &= formatInfo->aspectMask; + aspectMask &= imageFormatInfo(view->info().format)->aspectMask; - VkClearDepthStencilValue clearValue; - clearValue.depth = Depth; - clearValue.stencil = Stencil; + VkClearValue clearValue; + clearValue.depthStencil.depth = Depth; + clearValue.depthStencil.stencil = Stencil; - if (m_state.om.depthStencilView == dsv) { - // Image is bound to the pipeline for rendering. We can - // use the clear function that operates on attachments. - VkClearAttachment clearInfo; - clearInfo.aspectMask = aspectMask; - clearInfo.colorAttachment = 0; - clearInfo.clearValue.depthStencil = clearValue; - - // Clear the full area - VkClearRect clearRect; - clearRect.rect.offset.x = 0; - clearRect.rect.offset.y = 0; - clearRect.rect.extent.width = view->mipLevelExtent(0).width; - clearRect.rect.extent.height = view->mipLevelExtent(0).height; - clearRect.baseArrayLayer = 0; - clearRect.layerCount = view->info().numLayers; - - if (m_parent->GetFeatureLevel() < D3D_FEATURE_LEVEL_10_0) - clearRect.layerCount = 1; - - EmitCs([ - cClearInfo = clearInfo, - cClearRect = clearRect - ] (DxvkContext* ctx) { - ctx->clearRenderTarget(cClearInfo, cClearRect); - }); - } else { - EmitCs([ - cClearValue = clearValue, - cDstView = view, - cAspectMask = aspectMask - ] (DxvkContext* ctx) { - VkImageSubresourceRange subresources = cDstView->subresources(); - subresources.aspectMask = cAspectMask; - - ctx->clearDepthStencilImage(cDstView->image(), - cClearValue, subresources); - }); - } + VkClearRect clearRect; + clearRect.rect.offset.x = 0; + clearRect.rect.offset.y = 0; + clearRect.rect.extent.width = view->mipLevelExtent(0).width; + clearRect.rect.extent.height = view->mipLevelExtent(0).height; + clearRect.baseArrayLayer = 0; + clearRect.layerCount = view->info().numLayers; + + if (m_parent->GetFeatureLevel() < D3D_FEATURE_LEVEL_10_0) + clearRect.layerCount = 1; + + EmitCs([ + cClearValue = clearValue, + cClearRect = clearRect, + cAspectMask = aspectMask, + cImageView = view + ] (DxvkContext* ctx) { + ctx->clearRenderTarget( + cImageView, cClearRect, + cAspectMask, cClearValue); + }); } diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index b2e7ea055..929f1bf74 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -311,15 +311,56 @@ namespace dxvk { void DxvkContext::clearRenderTarget( - const VkClearAttachment& attachment, - const VkClearRect& clearArea) { - // We only need the framebuffer to be bound. Flushing the - // entire pipeline state is not required and might actually - // cause problems if the current pipeline state is invalid. - this->renderPassBegin(); + const Rc& imageView, + const VkClearRect& clearRect, + VkImageAspectFlags clearAspects, + const VkClearValue& clearValue) { + // Check whether the render target view is an attachment + // of the current framebuffer. If not, we need to create + // a temporary framebuffer. + uint32_t attachmentIndex = MaxNumRenderTargets; + + if (m_state.om.framebuffer != nullptr) + attachmentIndex = m_state.om.framebuffer->findAttachment(imageView); + + if (attachmentIndex == MaxNumRenderTargets) { + this->renderPassEnd(); + + // Set up and bind a temporary framebuffer + DxvkRenderTargets attachments; + + if (clearAspects & VK_IMAGE_ASPECT_COLOR_BIT) { + attachments.setColorTarget(0, imageView, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + } else { + attachments.setDepthTarget(imageView, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); + } + + this->renderPassBindFramebuffer( + m_device->createFramebuffer(attachments)); + } else { + // Make sure that the currently bound + // framebuffer can be rendered to + this->renderPassBegin(); + } + + // Clear the attachment in quesion + VkClearAttachment clearInfo; + clearInfo.aspectMask = clearAspects; + clearInfo.colorAttachment = attachmentIndex; + clearInfo.clearValue = clearValue; + + if (attachmentIndex == MaxNumRenderTargets) + clearInfo.colorAttachment = 0; m_cmd->cmdClearAttachments( - 1, &attachment, 1, &clearArea); + 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 == MaxNumRenderTargets) + this->renderPassUnbindFramebuffer(); } @@ -1298,27 +1339,7 @@ namespace dxvk { if (!m_flags.test(DxvkContextFlag::GpRenderPassBound) && (m_state.om.framebuffer != nullptr)) { m_flags.set(DxvkContextFlag::GpRenderPassBound); - - const DxvkFramebufferSize fbSize - = m_state.om.framebuffer->size(); - - VkRect2D renderArea; - renderArea.offset = VkOffset2D { 0, 0 }; - renderArea.extent = VkExtent2D { fbSize.width, fbSize.height }; - - VkRenderPassBeginInfo info; - info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - info.pNext = nullptr; - info.renderPass = m_state.om.framebuffer->renderPass(); - info.framebuffer = m_state.om.framebuffer->handle(); - info.renderArea = renderArea; - info.clearValueCount = 0; - info.pClearValues = nullptr; - - m_cmd->cmdBeginRenderPass(&info, - VK_SUBPASS_CONTENTS_INLINE); - m_cmd->trackResource( - m_state.om.framebuffer); + this->renderPassBindFramebuffer(m_state.om.framebuffer); } } @@ -1326,11 +1347,38 @@ namespace dxvk { void DxvkContext::renderPassEnd() { if (m_flags.test(DxvkContextFlag::GpRenderPassBound)) { m_flags.clr(DxvkContextFlag::GpRenderPassBound); - m_cmd->cmdEndRenderPass(); + this->renderPassUnbindFramebuffer(); } } + void DxvkContext::renderPassBindFramebuffer(const Rc& framebuffer) { + const DxvkFramebufferSize fbSize = framebuffer->size(); + + VkRect2D renderArea; + renderArea.offset = VkOffset2D { 0, 0 }; + renderArea.extent = VkExtent2D { fbSize.width, fbSize.height }; + + VkRenderPassBeginInfo info; + info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + info.pNext = nullptr; + info.renderPass = framebuffer->renderPass(); + info.framebuffer = framebuffer->handle(); + info.renderArea = renderArea; + info.clearValueCount = 0; + info.pClearValues = nullptr; + + m_cmd->cmdBeginRenderPass(&info, + VK_SUBPASS_CONTENTS_INLINE); + m_cmd->trackResource(framebuffer); + } + + + void DxvkContext::renderPassUnbindFramebuffer() { + m_cmd->cmdEndRenderPass(); + } + + void DxvkContext::updateComputePipeline() { if (m_flags.test(DxvkContextFlag::CpDirtyPipeline)) { m_flags.clr(DxvkContextFlag::CpDirtyPipeline); diff --git a/src/dxvk/dxvk_context.h b/src/dxvk/dxvk_context.h index 5990a08f6..61c6b2088 100644 --- a/src/dxvk/dxvk_context.h +++ b/src/dxvk/dxvk_context.h @@ -188,12 +188,16 @@ namespace dxvk { /** * \brief Clears an active render target * - * \param [in] attachment Attachment to clear - * \param [in] clearArea Rectangular area to clear + * \param [in] imageView Render target view to clear + * \param [in] clearArea Image area to clear + * \param [in] clearAspects Image aspects to clear + * \param [in] clearValue The clear value */ void clearRenderTarget( - const VkClearAttachment& attachment, - const VkClearRect& clearArea); + const Rc& imageView, + const VkClearRect& clearRect, + VkImageAspectFlags clearAspects, + const VkClearValue& clearValue); /** * \brief Copies data from one buffer to another @@ -579,6 +583,10 @@ namespace dxvk { void renderPassBegin(); void renderPassEnd(); + void renderPassBindFramebuffer( + const Rc& framebuffer); + void renderPassUnbindFramebuffer(); + void updateComputePipeline(); void updateComputePipelineState(); diff --git a/src/dxvk/dxvk_framebuffer.cpp b/src/dxvk/dxvk_framebuffer.cpp index 9972f9b24..9a4d1d597 100644 --- a/src/dxvk/dxvk_framebuffer.cpp +++ b/src/dxvk/dxvk_framebuffer.cpp @@ -111,4 +111,18 @@ namespace dxvk { m_vkd->device(), m_framebuffer, nullptr); } + + uint32_t DxvkFramebuffer::findAttachment( + const Rc& view) const { + if (m_renderTargets.getDepthTarget().view == view) + return 0; + + for (uint32_t i = 0; i < MaxNumRenderTargets; i++) { + if (m_renderTargets.getColorTarget(i).view == view) + return i; + } + + return MaxNumRenderTargets; + } + } \ No newline at end of file diff --git a/src/dxvk/dxvk_framebuffer.h b/src/dxvk/dxvk_framebuffer.h index b91c7c80b..c0238be24 100644 --- a/src/dxvk/dxvk_framebuffer.h +++ b/src/dxvk/dxvk_framebuffer.h @@ -185,6 +185,17 @@ namespace dxvk { return m_renderPass->sampleCount(); } + /** + * \brief Retrieves index of a given attachment + * + * \param [in] view The image view to look up + * \returns The attachment index, or \c 0 for a depth-stencil + * attachment, or \c MaxNumRenderTargets if the given + * view is not a framebuffer attachment. + */ + uint32_t findAttachment( + const Rc& view) const; + private: Rc m_vkd; diff --git a/src/dxvk/hud/dxvk_hud.cpp b/src/dxvk/hud/dxvk_hud.cpp index dea244998..70977630e 100644 --- a/src/dxvk/hud/dxvk_hud.cpp +++ b/src/dxvk/hud/dxvk_hud.cpp @@ -93,13 +93,6 @@ namespace dxvk::hud { 0, 1, 0, 1 }); } - VkClearAttachment clearInfo; - clearInfo.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - clearInfo.colorAttachment = 0; - - for (uint32_t i = 0; i < 4; i++) - clearInfo.clearValue.color.float32[i] = 0.0f; - VkClearRect clearRect; clearRect.rect.offset = { 0, 0 }; clearRect.rect.extent = m_surfaceSize; @@ -107,7 +100,10 @@ namespace dxvk::hud { clearRect.layerCount = 1; m_context->bindFramebuffer(m_renderTargetFbo); - m_context->clearRenderTarget(clearInfo, clearRect); + m_context->clearRenderTarget( + m_renderTargetView, clearRect, + VK_IMAGE_ASPECT_COLOR_BIT, + VkClearValue { }); VkViewport viewport; viewport.x = 0.0f;