diff --git a/src/dxvk/dxvk_framebuffer.cpp b/src/dxvk/dxvk_framebuffer.cpp index 2184f3f6..856e9d33 100644 --- a/src/dxvk/dxvk_framebuffer.cpp +++ b/src/dxvk/dxvk_framebuffer.cpp @@ -2,6 +2,129 @@ namespace dxvk { + DxvkFramebufferInfo::DxvkFramebufferInfo() { + + } + + + DxvkFramebufferInfo::DxvkFramebufferInfo( + const DxvkRenderTargets& renderTargets, + const DxvkFramebufferSize& defaultSize, + DxvkRenderPass* renderPass) + : m_renderTargets (renderTargets), + m_renderSize (computeRenderSize(defaultSize)), + m_renderPass (renderPass) { + + for (uint32_t i = 0; i < MaxNumRenderTargets; i++) { + if (m_renderTargets.color[i].view != nullptr) { + m_attachments[m_attachmentCount++] = i; + m_sampleCount = m_renderTargets.color[i].view->imageInfo().sampleCount; + } + } + + if (m_renderTargets.depth.view != nullptr) { + m_attachments[m_attachmentCount++] = -1; + m_sampleCount = m_renderTargets.depth.view->imageInfo().sampleCount; + } + } + + + DxvkFramebufferInfo::~DxvkFramebufferInfo() { + + } + + + int32_t DxvkFramebufferInfo::findAttachment(const Rc& view) const { + for (uint32_t i = 0; i < m_attachmentCount; i++) { + if (getAttachment(i).view->matchesView(view)) + return int32_t(i); + } + + return -1; + } + + + bool DxvkFramebufferInfo::hasTargets(const DxvkRenderTargets& renderTargets) { + bool eq = m_renderTargets.depth.view == renderTargets.depth.view + && m_renderTargets.depth.layout == renderTargets.depth.layout; + + for (uint32_t i = 0; i < MaxNumRenderTargets && eq; i++) { + eq &= m_renderTargets.color[i].view == renderTargets.color[i].view + && m_renderTargets.color[i].layout == renderTargets.color[i].layout; + } + + return eq; + } + + + bool DxvkFramebufferInfo::isFullSize(const Rc& view) const { + return m_renderSize.width == view->mipLevelExtent(0).width + && m_renderSize.height == view->mipLevelExtent(0).height + && m_renderSize.layers == view->info().numLayers; + } + + + bool DxvkFramebufferInfo::isWritable(uint32_t attachmentIndex, VkImageAspectFlags aspects) const { + VkImageAspectFlags writableAspects = vk::getWritableAspectsForLayout(getAttachment(attachmentIndex).layout); + return (writableAspects & aspects) == aspects; + } + + + DxvkRenderPassFormat DxvkFramebufferInfo::getRenderPassFormat(const DxvkRenderTargets& renderTargets) { + DxvkRenderPassFormat format; + + for (uint32_t i = 0; i < MaxNumRenderTargets; i++) { + if (renderTargets.color[i].view != nullptr) { + format.sampleCount = renderTargets.color[i].view->imageInfo().sampleCount; + format.color[i].format = renderTargets.color[i].view->info().format; + format.color[i].layout = renderTargets.color[i].layout; + } + } + + if (renderTargets.depth.view != nullptr) { + format.sampleCount = renderTargets.depth.view->imageInfo().sampleCount; + format.depth.format = renderTargets.depth.view->info().format; + format.depth.layout = renderTargets.depth.layout; + } + + return format; + } + + + DxvkFramebufferSize DxvkFramebufferInfo::computeRenderSize( + const DxvkFramebufferSize& defaultSize) const { + // Some games bind render targets of a different size and + // expect it to work, so we'll compute the minimum size + DxvkFramebufferSize minSize = defaultSize; + + if (m_renderTargets.depth.view != nullptr) { + DxvkFramebufferSize depthSize = this->computeRenderTargetSize(m_renderTargets.depth.view); + minSize.width = std::min(minSize.width, depthSize.width); + minSize.height = std::min(minSize.height, depthSize.height); + minSize.layers = std::min(minSize.layers, depthSize.layers); + } + + for (uint32_t i = 0; i < MaxNumRenderTargets; i++) { + if (m_renderTargets.color[i].view != nullptr) { + DxvkFramebufferSize colorSize = this->computeRenderTargetSize(m_renderTargets.color[i].view); + minSize.width = std::min(minSize.width, colorSize.width); + minSize.height = std::min(minSize.height, colorSize.height); + minSize.layers = std::min(minSize.layers, colorSize.layers); + } + } + + return minSize; + } + + + DxvkFramebufferSize DxvkFramebufferInfo::computeRenderTargetSize( + const Rc& renderTarget) const { + auto extent = renderTarget->mipLevelExtent(0); + auto layers = renderTarget->info().numLayers; + return DxvkFramebufferSize { extent.width, extent.height, layers }; + } + + DxvkFramebuffer::DxvkFramebuffer( const Rc& vkd, DxvkRenderPass* renderPass, diff --git a/src/dxvk/dxvk_framebuffer.h b/src/dxvk/dxvk_framebuffer.h index 070efee4..77f744db 100644 --- a/src/dxvk/dxvk_framebuffer.h +++ b/src/dxvk/dxvk_framebuffer.h @@ -50,8 +50,171 @@ namespace dxvk { VkImageLayout color[MaxNumRenderTargets]; VkImageLayout depth; }; - - + + + /** + * \brief Framebuffer info + * + * Stores metadata about the current framebuffer, + * without actually creating a framebuffer object. + */ + class DxvkFramebufferInfo { + + public: + + DxvkFramebufferInfo(); + + DxvkFramebufferInfo( + const DxvkRenderTargets& renderTargets, + const DxvkFramebufferSize& defaultSize, + DxvkRenderPass* renderPass); + + ~DxvkFramebufferInfo(); + + /** + * \brief Framebuffer size + * \returns Framebuffer size + */ + DxvkFramebufferSize size() const { + return m_renderSize; + } + + /** + * \brief Render pass + * \returns Render pass + */ + DxvkRenderPass* renderPass() const { + return m_renderPass; + } + + /** + * \brief Framebuffer sample count + * + * Returns the sample count of the color + * and depth-stencil attachments, or 0 if + * there are no attachments. + * \returns Sample count + */ + VkSampleCountFlags getSampleCount() const { + return m_sampleCount; + } + + /** + * \brief Depth-stencil target + * \returns Depth-stencil target + */ + const DxvkAttachment& getDepthTarget() const { + return m_renderTargets.depth; + } + + /** + * \brief Color target + * + * \param [in] id Target Index + * \returns The color target + */ + const DxvkAttachment& getColorTarget(uint32_t id) const { + return m_renderTargets.color[id]; + } + + /** + * \brief Number of framebuffer attachment + * \returns Total attachment count + */ + uint32_t numAttachments() const { + return m_attachmentCount; + } + + /** + * \brief Queries color attachment index of a given attachment + * \returns The index, or -1 if the given attachment is the depth attachment + */ + const int32_t getColorAttachmentIndex(uint32_t id) const { + return m_attachments[id]; + } + + /** + * \brief Retrieves attachment by index + * + * \param [in] id Framebuffer attachment ID + * \returns The framebuffer attachment + */ + const DxvkAttachment& getAttachment(uint32_t id) const { + int32_t idx = getColorAttachmentIndex(id); + return idx < 0 ? m_renderTargets.depth : m_renderTargets.color[idx]; + } + + /** + * \brief Finds attachment index by view + * + * Color attachments start at 0 + * \param [in] view Image view + * \returns Attachment index + */ + int32_t findAttachment(const Rc& view) const; + + /** + * \brief Checks whether the framebuffer's targets match + * + * \param [in] renderTargets Render targets to check + * \returns \c true if the render targets are the same + * as the ones used for this framebuffer object. + */ + bool hasTargets(const DxvkRenderTargets& renderTargets); + + /** + * \brief Checks whether view and framebuffer sizes match + * + * Tests whether the size of the framebuffer is the same + * as the size of one of its views. This may be \c false + * when mixing attachments with mismatched dimensions. + * \param [in] view Image view to test + * \returns \c true if \c view has the same size as + * 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 + * + * This render pass format can be used to + * look up a compatible render pass. + * \param [in] renderTargets Render targets + * \returns The render pass format + */ + static DxvkRenderPassFormat getRenderPassFormat( + const DxvkRenderTargets& renderTargets); + + private: + + DxvkRenderTargets m_renderTargets; + DxvkFramebufferSize m_renderSize = { 0u, 0u, 0u }; + VkSampleCountFlags m_sampleCount = 0; + DxvkRenderPass* m_renderPass; + + uint32_t m_attachmentCount = 0; + std::array m_attachments; + + DxvkFramebufferSize computeRenderSize( + const DxvkFramebufferSize& defaultSize) const; + + DxvkFramebufferSize computeRenderTargetSize( + const Rc& renderTarget) const; + + }; + + + /** * \brief Framebuffer *