#include "dxvk_framebuffer.h" namespace dxvk { DxvkFramebuffer::DxvkFramebuffer( const Rc& vkd, const Rc& renderPass, const DxvkRenderTargets& renderTargets, const DxvkFramebufferSize& defaultSize) : m_vkd (vkd), m_renderPass (renderPass), m_renderTargets (renderTargets), m_renderSize (computeRenderSize(defaultSize)) { std::array views; for (uint32_t i = 0; i < MaxNumRenderTargets; i++) { if (m_renderTargets.color[i].view != nullptr) { 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[m_attachmentCount] = m_renderTargets.depth.view->handle(); m_attachments[m_attachmentCount] = &m_renderTargets.depth; m_attachmentCount += 1; } VkFramebufferCreateInfo info; info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; info.pNext = nullptr; info.flags = 0; info.renderPass = m_renderPass->getDefaultHandle(); info.attachmentCount = m_attachmentCount; info.pAttachments = views.data(); info.width = m_renderSize.width; info.height = m_renderSize.height; info.layers = m_renderSize.layers; if (m_vkd->vkCreateFramebuffer(m_vkd->device(), &info, nullptr, &m_handle) != VK_SUCCESS) Logger::err("DxvkFramebuffer: Failed to create framebuffer object"); } DxvkFramebuffer::~DxvkFramebuffer() { m_vkd->vkDestroyFramebuffer(m_vkd->device(), m_handle, nullptr); } int32_t DxvkFramebuffer::findAttachment(const Rc& view) const { for (uint32_t i = 0; i < m_attachmentCount; i++) { if (m_attachments[i]->view == view) return int32_t(i); } return -1; } bool DxvkFramebuffer::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; } DxvkRenderPassFormat DxvkFramebuffer::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 DxvkFramebuffer::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 DxvkFramebuffer::computeRenderTargetSize( const Rc& renderTarget) const { auto extent = renderTarget->mipLevelExtent(0); auto layers = renderTarget->info().numLayers; return DxvkFramebufferSize { extent.width, extent.height, layers }; } }