From b31ebbb690dece8142486d7b03b014bd2cd3ccd2 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Tue, 6 Feb 2018 17:31:23 +0100 Subject: [PATCH] [d3d11] Add support for DSV read-only flags Games need this in order to use the depth buffer as both a framebuffer attachment and a shader resource. --- src/d3d11/d3d11_context.cpp | 14 +++++-- src/d3d11/d3d11_view_dsv.h | 13 ++++++ src/d3d11/d3d11_view_rtv.h | 5 +++ src/dxvk/dxvk_context.cpp | 11 ++++- src/dxvk/dxvk_context_state.h | 2 +- src/dxvk/dxvk_framebuffer.cpp | 42 ++++++++++--------- src/dxvk/dxvk_framebuffer.h | 30 ++++++++++---- src/dxvk/dxvk_renderpass.cpp | 77 ++++++++++++----------------------- src/dxvk/dxvk_renderpass.h | 37 +++++++++-------- src/dxvk/dxvk_swapchain.cpp | 3 +- src/dxvk/dxvk_util.h | 18 ++++++++ src/dxvk/hud/dxvk_hud.cpp | 3 +- 12 files changed, 152 insertions(+), 103 deletions(-) diff --git a/src/d3d11/d3d11_context.cpp b/src/d3d11/d3d11_context.cpp index c5e8d2a5..617c4670 100644 --- a/src/d3d11/d3d11_context.cpp +++ b/src/d3d11/d3d11_context.cpp @@ -1720,12 +1720,18 @@ namespace dxvk { // target bindings are updated. Set up the attachments. if (ppRenderTargetViews != nullptr || pDepthStencilView != nullptr) { for (UINT i = 0; i < m_state.om.renderTargetViews.size(); i++) { - if (m_state.om.renderTargetViews.at(i) != nullptr) - attachments.setColorTarget(i, m_state.om.renderTargetViews.at(i)->GetImageView()); + if (m_state.om.renderTargetViews.at(i) != nullptr) { + attachments.setColorTarget(i, + m_state.om.renderTargetViews.at(i)->GetImageView(), + m_state.om.renderTargetViews.at(i)->GetRenderLayout()); + } } - if (m_state.om.depthStencilView != nullptr) - attachments.setDepthTarget(m_state.om.depthStencilView->GetImageView()); + if (m_state.om.depthStencilView != nullptr) { + attachments.setDepthTarget( + m_state.om.depthStencilView->GetImageView(), + m_state.om.depthStencilView->GetRenderLayout()); + } } // Create and bind the framebuffer object to the context diff --git a/src/d3d11/d3d11_view_dsv.h b/src/d3d11/d3d11_view_dsv.h index 2592f8cf..85d17b6a 100644 --- a/src/d3d11/d3d11_view_dsv.h +++ b/src/d3d11/d3d11_view_dsv.h @@ -45,6 +45,19 @@ namespace dxvk { return m_view; } + VkImageLayout GetRenderLayout() const { + switch (m_desc.Flags & (D3D11_DSV_READ_ONLY_DEPTH | D3D11_DSV_READ_ONLY_STENCIL)) { + default: // case 0 + return VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + case D3D11_DSV_READ_ONLY_DEPTH: + return VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR; + case D3D11_DSV_READ_ONLY_STENCIL: + return VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR; + case D3D11_DSV_READ_ONLY_DEPTH | D3D11_DSV_READ_ONLY_STENCIL: + return VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL; + } + } + private: Com m_device; diff --git a/src/d3d11/d3d11_view_rtv.h b/src/d3d11/d3d11_view_rtv.h index 14d558b7..1116f316 100644 --- a/src/d3d11/d3d11_view_rtv.h +++ b/src/d3d11/d3d11_view_rtv.h @@ -41,6 +41,11 @@ namespace dxvk { return m_view; } + VkImageLayout GetRenderLayout() const { + // Currently no reason to use anything else + return VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + } + private: Com m_device; diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index 8775c851..a6fd259b 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -1333,7 +1333,7 @@ namespace dxvk { void DxvkContext::updateShaderResources( VkPipelineBindPoint bindPoint, - const Rc& layout) { + const Rc& layout) { DxvkBindingState& bs = bindPoint == VK_PIPELINE_BIND_POINT_GRAPHICS ? m_state.gp.state.bsBindingState @@ -1371,6 +1371,15 @@ namespace dxvk { m_descInfos[i].image.imageView = res.imageView->handle(); m_descInfos[i].image.imageLayout = res.imageView->imageInfo().layout; + // TODO try to reduce the runtime overhead of all these comparisons + if (bindPoint == VK_PIPELINE_BIND_POINT_GRAPHICS) { + DxvkAttachment depthAttachment = m_state.om.framebuffer->renderTargets().getDepthTarget(); + + if (depthAttachment.view != nullptr + && depthAttachment.view->image() == res.imageView->image()) + m_descInfos[i].image.imageLayout = depthAttachment.layout; + } + m_cmd->trackResource(res.imageView); m_cmd->trackResource(res.imageView->image()); } else { diff --git a/src/dxvk/dxvk_context_state.h b/src/dxvk/dxvk_context_state.h index b0b9e7d2..9b34ce74 100644 --- a/src/dxvk/dxvk_context_state.h +++ b/src/dxvk/dxvk_context_state.h @@ -58,7 +58,7 @@ namespace dxvk { struct DxvkOutputMergerState { - Rc framebuffer; + Rc framebuffer = nullptr; DxvkBlendConstants blendConstants = { 0.0f, 0.0f, 0.0f, 0.0f }; uint32_t stencilReference = 0; diff --git a/src/dxvk/dxvk_framebuffer.cpp b/src/dxvk/dxvk_framebuffer.cpp index 84cb86d6..c06584b1 100644 --- a/src/dxvk/dxvk_framebuffer.cpp +++ b/src/dxvk/dxvk_framebuffer.cpp @@ -10,21 +10,23 @@ namespace dxvk { DxvkRenderPassFormat result; for (uint32_t i = 0; i < MaxNumRenderTargets; i++) { - if (m_colorTargets.at(i) != nullptr) { + if (m_colorTargets.at(i).view != nullptr) { result.setColorFormat(i, DxvkRenderTargetFormat { - m_colorTargets.at(i)->info().format, - m_colorTargets.at(i)->imageInfo().layout, - m_colorTargets.at(i)->imageInfo().layout }); - result.setSampleCount(m_colorTargets.at(i)->image()->info().sampleCount); + m_colorTargets.at(i).view->info().format, + m_colorTargets.at(i).view->imageInfo().layout, + m_colorTargets.at(i).view->imageInfo().layout, + m_colorTargets.at(i).layout }); + result.setSampleCount(m_colorTargets.at(i).view->imageInfo().sampleCount); } } - if (m_depthTarget != nullptr) { + if (m_depthTarget.view != nullptr) { result.setDepthFormat(DxvkRenderTargetFormat { - m_depthTarget->info().format, - m_depthTarget->imageInfo().layout, - m_depthTarget->imageInfo().layout }); - result.setSampleCount(m_depthTarget->image()->info().sampleCount); + m_depthTarget.view->info().format, + m_depthTarget.view->imageInfo().layout, + m_depthTarget.view->imageInfo().layout, + m_depthTarget.layout }); + result.setSampleCount(m_depthTarget.view->imageInfo().sampleCount); } return result; @@ -34,12 +36,12 @@ namespace dxvk { std::vector DxvkRenderTargets::getAttachments() const { std::vector result; - if (m_depthTarget != nullptr) - result.push_back(m_depthTarget->handle()); + if (m_depthTarget.view != nullptr) + result.push_back(m_depthTarget.view->handle()); for (uint32_t i = 0; i < MaxNumRenderTargets; i++) { - if (m_colorTargets.at(i) != nullptr) - result.push_back(m_colorTargets.at(i)->handle()); + if (m_colorTargets.at(i).view != nullptr) + result.push_back(m_colorTargets.at(i).view->handle()); } return result; @@ -47,12 +49,12 @@ namespace dxvk { DxvkFramebufferSize DxvkRenderTargets::getImageSize() const { - if (m_depthTarget != nullptr) - return this->renderTargetSize(m_depthTarget); + if (m_depthTarget.view != nullptr) + return this->renderTargetSize(m_depthTarget.view); for (uint32_t i = 0; i < MaxNumRenderTargets; i++) { - if (m_colorTargets.at(i) != nullptr) - return this->renderTargetSize(m_colorTargets.at(i)); + if (m_colorTargets.at(i).view != nullptr) + return this->renderTargetSize(m_colorTargets.at(i).view); } return DxvkFramebufferSize { 0, 0, 0 }; @@ -60,10 +62,10 @@ namespace dxvk { bool DxvkRenderTargets::hasAttachments() const { - bool result = m_depthTarget != nullptr; + bool result = m_depthTarget.view != nullptr; for (uint32_t i = 0; (i < MaxNumRenderTargets) && !result; i++) - result |= m_colorTargets.at(i) != nullptr; + result |= m_colorTargets.at(i).view != nullptr; return result; } diff --git a/src/dxvk/dxvk_framebuffer.h b/src/dxvk/dxvk_framebuffer.h index 4701cb30..c7f5e60e 100644 --- a/src/dxvk/dxvk_framebuffer.h +++ b/src/dxvk/dxvk_framebuffer.h @@ -19,6 +19,12 @@ namespace dxvk { }; + struct DxvkAttachment { + Rc view = nullptr; + VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED; + }; + + /** * \brief Render target description * @@ -40,7 +46,7 @@ namespace dxvk { * \param [in] id Color attachment ID * \returns Render target view */ - Rc getColorTarget(uint32_t id) const { + DxvkAttachment getColorTarget(uint32_t id) const { return m_colorTargets.at(id); } @@ -48,7 +54,7 @@ namespace dxvk { * \brief Retrieves depth-stencil target * \returns Depth-stencil target view */ - Rc getDepthTarget() const { + DxvkAttachment getDepthTarget() const { return m_depthTarget; } @@ -57,17 +63,25 @@ namespace dxvk { * * \param [in] id Color attachment ID * \param [in] view Render target view + * \param [in] layout Layout to use for rendering */ - void setColorTarget(uint32_t id, const Rc& view) { - m_colorTargets.at(id) = view; + void setColorTarget( + uint32_t id, + const Rc& view, + VkImageLayout layout) { + m_colorTargets.at(id) = { view, layout }; } /** * \brief Sets depth-stencil target + * + * \param [in] layout Layout to use for rendering * \param [in] view Depth-stencil target view */ - void setDepthTarget(const Rc& view) { - m_depthTarget = view; + void setDepthTarget( + const Rc& view, + VkImageLayout layout) { + m_depthTarget = { view, layout }; } /** @@ -102,8 +116,8 @@ namespace dxvk { private: - std::array, MaxNumRenderTargets> m_colorTargets; - Rc m_depthTarget; + std::array m_colorTargets; + DxvkAttachment m_depthTarget; DxvkFramebufferSize renderTargetSize( const Rc& renderTarget) const; diff --git a/src/dxvk/dxvk_renderpass.cpp b/src/dxvk/dxvk_renderpass.cpp index be2a4453..c4645644 100644 --- a/src/dxvk/dxvk_renderpass.cpp +++ b/src/dxvk/dxvk_renderpass.cpp @@ -1,58 +1,28 @@ +#include + #include "dxvk_renderpass.h" namespace dxvk { - bool DxvkRenderTargetFormat::operator == (const DxvkRenderTargetFormat& other) const { - return this->format == other.format - && this->initialLayout == other.initialLayout - && this->finalLayout == other.finalLayout; - } - - - bool DxvkRenderTargetFormat::operator != (const DxvkRenderTargetFormat& other) const { - return !this->operator == (other); - } - - - size_t DxvkRenderTargetFormat::hash() const { - std::hash fhash; - std::hash lhash; + bool DxvkRenderPassFormat::matchesFormat(const DxvkRenderPassFormat& other) const { + bool equal = m_samples == other.m_samples; - DxvkHashState result; - result.add(fhash(this->format)); - result.add(lhash(this->initialLayout)); - result.add(lhash(this->finalLayout)); - return result; - } - - - size_t DxvkRenderPassFormat::hash() const { - std::hash shash; + equal = m_depth.format == other.m_depth.format + && m_depth.initialLayout == other.m_depth.initialLayout + && m_depth.finalLayout == other.m_depth.finalLayout + && m_depth.renderLayout == other.m_depth.renderLayout; - DxvkHashState result; - for (uint32_t i = 0; i < MaxNumRenderTargets; i++) - result.add(m_color[i].hash()); + for (uint32_t i = 0; i < MaxNumRenderTargets && equal; i++) { + equal &= m_color[i].format == other.m_color[i].format + && m_color[i].initialLayout == other.m_color[i].initialLayout + && m_color[i].finalLayout == other.m_color[i].finalLayout + && m_color[i].renderLayout == other.m_color[i].renderLayout; + } - result.add(m_depth.hash()); - result.add(shash(m_samples)); - return result; - } - - - bool DxvkRenderPassFormat::operator == (const DxvkRenderPassFormat& other) const { - bool equal = m_depth == other.m_depth - && m_samples == other.m_samples; - for (uint32_t i = 0; i < MaxNumRenderTargets && !equal; i++) - equal = m_color[i] == other.m_color[i]; return equal; } - bool DxvkRenderPassFormat::operator != (const DxvkRenderPassFormat& other) const { - return !this->operator == (other); - } - - DxvkRenderPass::DxvkRenderPass( const Rc& vkd, const DxvkRenderPassFormat& fmt) @@ -79,7 +49,7 @@ namespace dxvk { desc.finalLayout = depthFmt.finalLayout; depthRef.attachment = attachments.size(); - depthRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + depthRef.layout = depthFmt.renderLayout; attachments.push_back(desc); } @@ -195,14 +165,19 @@ namespace dxvk { const DxvkRenderPassFormat& fmt) { std::lock_guard lock(m_mutex); - auto rp = m_renderPasses.find(fmt); + Rc renderPass = nullptr; - if (rp != m_renderPasses.end()) - return rp->second; + for (uint32_t i = 0; i < m_renderPasses.size() && renderPass == nullptr; i++) { + if (m_renderPasses[i]->matchesFormat(fmt)) + renderPass = m_renderPasses[i]; + } - auto result = this->createRenderPass(fmt); - m_renderPasses.insert(std::make_pair(fmt, result)); - return result; + if (renderPass != nullptr) + return renderPass; + + renderPass = this->createRenderPass(fmt); + m_renderPasses.push_back(renderPass); + return renderPass; } diff --git a/src/dxvk/dxvk_renderpass.h b/src/dxvk/dxvk_renderpass.h index 1b3b2bcb..0883967a 100644 --- a/src/dxvk/dxvk_renderpass.h +++ b/src/dxvk/dxvk_renderpass.h @@ -19,11 +19,7 @@ namespace dxvk { VkFormat format = VK_FORMAT_UNDEFINED; VkImageLayout initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; VkImageLayout finalLayout = VK_IMAGE_LAYOUT_UNDEFINED; - - bool operator == (const DxvkRenderTargetFormat& other) const; - bool operator != (const DxvkRenderTargetFormat& other) const; - - size_t hash() const; + VkImageLayout renderLayout = VK_IMAGE_LAYOUT_UNDEFINED; }; @@ -97,13 +93,12 @@ namespace dxvk { } /** - * \brief Computes the hash - * \returns Resulting hash + * \brief Checks whether two render pass formats are compatible + * + * \param [in] other The render pass format to compare to + * \returns \c true if the render pass formats are compatible */ - size_t hash() const; - - bool operator == (const DxvkRenderPassFormat& other) const; - bool operator != (const DxvkRenderPassFormat& other) const; + bool matchesFormat(const DxvkRenderPassFormat& other) const; private: @@ -147,6 +142,19 @@ namespace dxvk { return m_format.getSampleCount(); } + /** + * \brief Checks render pass format compatibility + * + * This render pass object can be used with compatible render + * pass formats. Two render pass formats are compatible if the + * used attachments match in image format and layout. + * \param [in] format The render pass format to test + * \returns \c true if the formats match + */ + bool matchesFormat(const DxvkRenderPassFormat& format) const { + return m_format.matchesFormat(format); + } + private: Rc m_vkd; @@ -182,11 +190,8 @@ namespace dxvk { Rc m_vkd; - std::mutex m_mutex; - std::unordered_map< - DxvkRenderPassFormat, - Rc, - DxvkHash> m_renderPasses; + std::mutex m_mutex; + std::vector> m_renderPasses; Rc createRenderPass( const DxvkRenderPassFormat& fmt); diff --git a/src/dxvk/dxvk_swapchain.cpp b/src/dxvk/dxvk_swapchain.cpp index 05b5f249..0b45d28b 100644 --- a/src/dxvk/dxvk_swapchain.cpp +++ b/src/dxvk/dxvk_swapchain.cpp @@ -179,7 +179,8 @@ namespace dxvk { Rc iview = m_device->createImageView(image, viewInfo); DxvkRenderTargets renderTargets; - renderTargets.setColorTarget(0, iview); + renderTargets.setColorTarget(0, iview, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); m_framebuffers.at(i) = new DxvkFramebuffer( m_vkd, m_renderPass, renderTargets); diff --git a/src/dxvk/dxvk_util.h b/src/dxvk/dxvk_util.h index ed0221e1..41185450 100644 --- a/src/dxvk/dxvk_util.h +++ b/src/dxvk/dxvk_util.h @@ -69,6 +69,24 @@ namespace dxvk::util { } +inline bool operator == ( + const VkImageSubresourceRange& a, + const VkImageSubresourceRange& b) { + return a.aspectMask == b.aspectMask + && a.baseMipLevel == b.baseMipLevel + && a.levelCount == b.levelCount + && a.baseArrayLayer == b.baseArrayLayer + && a.layerCount == b.layerCount; +} + + +inline bool operator != ( + const VkImageSubresourceRange& a, + const VkImageSubresourceRange& b) { + return !operator == (a, b); +} + + inline bool operator == (VkExtent3D a, VkExtent3D b) { return a.width == b.width && a.height == b.height diff --git a/src/dxvk/hud/dxvk_hud.cpp b/src/dxvk/hud/dxvk_hud.cpp index 9cfdf805..6c893fac 100644 --- a/src/dxvk/hud/dxvk_hud.cpp +++ b/src/dxvk/hud/dxvk_hud.cpp @@ -177,7 +177,8 @@ namespace dxvk::hud { m_renderTargetView = m_device->createImageView(m_renderTarget, viewInfo); DxvkRenderTargets framebufferInfo; - framebufferInfo.setColorTarget(0, m_renderTargetView); + framebufferInfo.setColorTarget(0, m_renderTargetView, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); m_renderTargetFbo = m_device->createFramebuffer(framebufferInfo); }