diff --git a/src/d3d11/d3d11_context.cpp b/src/d3d11/d3d11_context.cpp index a8b1d53c..9aff8553 100644 --- a/src/d3d11/d3d11_context.cpp +++ b/src/d3d11/d3d11_context.cpp @@ -2591,20 +2591,20 @@ namespace dxvk { // target bindings are updated. Set up the attachments. for (UINT i = 0; i < m_state.om.renderTargetViews.size(); i++) { if (m_state.om.renderTargetViews.at(i) != nullptr) { - attachments.color[i] = { + attachments.setColorTarget(i, m_state.om.renderTargetViews.at(i)->GetImageView(), - m_state.om.renderTargetViews.at(i)->GetRenderLayout() }; + m_state.om.renderTargetViews.at(i)->GetRenderLayout()); } } if (m_state.om.depthStencilView != nullptr) { - attachments.depth = { + attachments.setDepthTarget( m_state.om.depthStencilView->GetImageView(), - m_state.om.depthStencilView->GetRenderLayout() }; + m_state.om.depthStencilView->GetRenderLayout()); } // Create and bind the framebuffer object to the context - EmitCs([cAttachments = std::move(attachments)] (DxvkContext* ctx) { + EmitCs([cAttachments = attachments] (DxvkContext* ctx) { ctx->bindRenderTargets(cAttachments); }); } diff --git a/src/dxgi/dxgi_presenter.cpp b/src/dxgi/dxgi_presenter.cpp index 116ea212..21afa4a7 100644 --- a/src/dxgi/dxgi_presenter.cpp +++ b/src/dxgi/dxgi_presenter.cpp @@ -169,27 +169,26 @@ namespace dxvk { VK_FORMAT_UNDEFINED); } - auto swapSemas = m_swapchain->getSemaphorePair(); - auto swapImage = m_swapchain->getImageView(swapSemas.acquireSync); + const DxvkSwapSemaphores sem = m_swapchain->getSemaphorePair(); - DxvkRenderTargets renderTargets; - renderTargets.color[0].view = swapImage; - renderTargets.color[0].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - m_context->bindRenderTargets(renderTargets); + auto framebuffer = m_swapchain->getFramebuffer(sem.acquireSync); + auto framebufferSize = framebuffer->size(); + + m_context->bindFramebuffer(framebuffer); VkViewport viewport; viewport.x = 0.0f; viewport.y = 0.0f; - viewport.width = float(swapImage->imageInfo().extent.width); - viewport.height = float(swapImage->imageInfo().extent.height); + viewport.width = static_cast(framebufferSize.width); + viewport.height = static_cast(framebufferSize.height); viewport.minDepth = 0.0f; viewport.maxDepth = 1.0f; VkRect2D scissor; scissor.offset.x = 0; scissor.offset.y = 0; - scissor.extent.width = swapImage->imageInfo().extent.width; - scissor.extent.height = swapImage->imageInfo().extent.height; + scissor.extent.width = framebufferSize.width; + scissor.extent.height = framebufferSize.height; m_context->setViewports(1, &viewport, &scissor); @@ -215,11 +214,9 @@ namespace dxvk { m_device->submitCommandList( m_context->endRecording(), - swapSemas.acquireSync, - swapSemas.presentSync); + sem.acquireSync, sem.presentSync); - m_swapchain->present( - swapSemas.presentSync); + m_swapchain->present(sem.presentSync); } diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index e6ccc783..76ec620d 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -85,17 +85,31 @@ namespace dxvk { } + void DxvkContext::bindFramebuffer(const Rc& fb) { + if (m_state.om.framebuffer != fb) { + this->spillRenderPass(); + + if (fb != nullptr) { + m_state.gp.state.msSampleCount = fb->sampleCount(); + m_state.gp.state.omRenderPass = fb->renderPass(); + + m_flags.set(DxvkContextFlag::GpDirtyPipelineState); + } + + m_state.om.framebuffer = fb; + } + + m_state.om.renderTargets = fb != nullptr + ? fb->renderTargets() + : DxvkRenderTargets(); + m_flags.clr(DxvkContextFlag::GpDirtyFramebuffer); + } + + void DxvkContext::bindRenderTargets(const DxvkRenderTargets& targets) { m_state.om.renderTargets = targets; - // TODO execute pending clears - - // Set up default render pass ops - this->resetRenderPassOps( - m_state.om.renderTargets, - m_state.om.renderPassOps); - - if (m_state.om.framebuffer == nullptr || !m_state.om.framebuffer->hasTargets(targets)) { + if (m_state.om.framebuffer == nullptr || !m_state.om.framebuffer->renderTargets().matches(targets)) { // Create a new framebuffer object next // time we start rendering something m_flags.set(DxvkContextFlag::GpDirtyFramebuffer); @@ -389,36 +403,27 @@ namespace dxvk { // Check whether the render target view is an attachment // of the current framebuffer. If not, we need to create // a temporary framebuffer. - int32_t attachmentIndex = -1; + uint32_t attachmentIndex = MaxNumRenderTargets; if (m_state.om.framebuffer != nullptr) attachmentIndex = m_state.om.framebuffer->findAttachment(imageView); - if (attachmentIndex < 0) { + if (attachmentIndex == MaxNumRenderTargets) { this->spillRenderPass(); - DxvkAttachmentOps op; - op.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; - op.loadLayout = imageView->imageInfo().layout; - op.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - op.storeLayout = imageView->imageInfo().layout; - // Set up and bind a temporary framebuffer DxvkRenderTargets attachments; - DxvkRenderPassOps ops; if (clearAspects & VK_IMAGE_ASPECT_COLOR_BIT) { - attachments.color[0].view = imageView; - attachments.color[0].layout = imageView->pickLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - ops.colorOps[0] = op; + attachments.setColorTarget(0, imageView, + imageView->pickLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)); } else { - attachments.depth.view = imageView; - attachments.depth.layout = imageView->pickLayout(VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); - ops.depthOps = op; + attachments.setDepthTarget(imageView, + imageView->pickLayout(VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)); } this->renderPassBindFramebuffer( - m_device->createFramebuffer(attachments), ops); + m_device->createFramebuffer(attachments)); } else { // Make sure that the currently bound // framebuffer can be rendered to @@ -431,7 +436,7 @@ namespace dxvk { clearInfo.colorAttachment = attachmentIndex; clearInfo.clearValue = clearValue; - if (attachmentIndex < 0) + if (attachmentIndex == MaxNumRenderTargets) clearInfo.colorAttachment = 0; m_cmd->cmdClearAttachments( @@ -439,7 +444,7 @@ namespace dxvk { // If we used a temporary framebuffer, we'll have to unbind it // again in order to not disturb subsequent rendering commands. - if (attachmentIndex < 0) + if (attachmentIndex == MaxNumRenderTargets) this->renderPassUnbindFramebuffer(); } @@ -1515,23 +1520,12 @@ namespace dxvk { if (!m_flags.test(DxvkContextFlag::GpRenderPassBound) && (m_state.om.framebuffer != nullptr)) { m_flags.set(DxvkContextFlag::GpRenderPassBound); - - this->renderPassBindFramebuffer( - m_state.om.framebuffer, - m_state.om.renderPassOps); - - // Don't discard image contents if we have - // to spill the current render pass - this->resetRenderPassOps( - m_state.om.renderTargets, - m_state.om.renderPassOps); + this->renderPassBindFramebuffer(m_state.om.framebuffer); } } void DxvkContext::spillRenderPass() { - // TODO execute pending clears - if (m_flags.test(DxvkContextFlag::GpRenderPassBound)) { m_flags.clr(DxvkContextFlag::GpRenderPassBound); this->renderPassUnbindFramebuffer(); @@ -1539,9 +1533,7 @@ namespace dxvk { } - void DxvkContext::renderPassBindFramebuffer( - const Rc& framebuffer, - const DxvkRenderPassOps& ops) { + void DxvkContext::renderPassBindFramebuffer(const Rc& framebuffer) { const DxvkFramebufferSize fbSize = framebuffer->size(); VkRect2D renderArea; @@ -1551,7 +1543,7 @@ namespace dxvk { VkRenderPassBeginInfo info; info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; info.pNext = nullptr; - info.renderPass = framebuffer->getRenderPassHandle(ops); + info.renderPass = framebuffer->renderPass(); info.framebuffer = framebuffer->handle(); info.renderArea = renderArea; info.clearValueCount = 0; @@ -1569,31 +1561,6 @@ namespace dxvk { } - void DxvkContext::resetRenderPassOps( - const DxvkRenderTargets& renderTargets, - DxvkRenderPassOps& renderPassOps) { - renderPassOps.depthOps = renderTargets.depth.view != nullptr - ? DxvkAttachmentOps { - VK_ATTACHMENT_LOAD_OP_LOAD, renderTargets.depth.view->imageInfo().layout, - VK_ATTACHMENT_STORE_OP_STORE, renderTargets.depth.view->imageInfo().layout } - : DxvkAttachmentOps { }; - - for (uint32_t i = 0; i < MaxNumRenderTargets; i++) { - renderPassOps.colorOps[i] = renderTargets.color[i].view != nullptr - ? DxvkAttachmentOps { - VK_ATTACHMENT_LOAD_OP_LOAD, renderTargets.color[i].view->imageInfo().layout, - VK_ATTACHMENT_STORE_OP_STORE, renderTargets.color[i].view->imageInfo().layout } - : DxvkAttachmentOps { }; - } - - // TODO provide a sane alternative for this - if (renderPassOps.colorOps[0].loadLayout == VK_IMAGE_LAYOUT_PRESENT_SRC_KHR) { - renderPassOps.colorOps[0].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - renderPassOps.colorOps[0].loadLayout = VK_IMAGE_LAYOUT_UNDEFINED; - } - } - - void DxvkContext::unbindComputePipeline() { m_flags.set( DxvkContextFlag::CpDirtyPipeline, @@ -1753,7 +1720,7 @@ namespace dxvk { DxvkAttachment depthAttachment; if (bindPoint == VK_PIPELINE_BIND_POINT_GRAPHICS && m_state.om.framebuffer != nullptr) - depthAttachment = m_state.om.framebuffer->getDepthTarget(); + depthAttachment = m_state.om.framebuffer->renderTargets().getDepthTarget(); for (uint32_t i = 0; i < layout->bindingCount(); i++) { const auto& binding = layout->binding(i); @@ -1865,8 +1832,8 @@ namespace dxvk { auto fb = m_device->createFramebuffer(m_state.om.renderTargets); - m_state.gp.state.msSampleCount = fb->getSampleCount(); - m_state.gp.state.omRenderPass = fb->getDefaultRenderPassHandle(); + m_state.gp.state.msSampleCount = fb->sampleCount(); + m_state.gp.state.omRenderPass = fb->renderPass(); m_state.om.framebuffer = fb; m_flags.set(DxvkContextFlag::GpDirtyPipelineState); diff --git a/src/dxvk/dxvk_context.h b/src/dxvk/dxvk_context.h index e3743fa7..81f9a460 100644 --- a/src/dxvk/dxvk_context.h +++ b/src/dxvk/dxvk_context.h @@ -71,6 +71,13 @@ namespace dxvk { void endQuery( const DxvkQueryRevision& query); + /** + * \brief Sets framebuffer + * \param [in] fb Framebuffer + */ + void bindFramebuffer( + const Rc& fb); + /** * \brief Sets render targets * @@ -643,15 +650,9 @@ namespace dxvk { void spillRenderPass(); void renderPassBindFramebuffer( - const Rc& framebuffer, - const DxvkRenderPassOps& ops); - + const Rc& framebuffer); void renderPassUnbindFramebuffer(); - void resetRenderPassOps( - const DxvkRenderTargets& renderTargets, - DxvkRenderPassOps& renderPassOps); - void unbindComputePipeline(); void updateComputePipeline(); diff --git a/src/dxvk/dxvk_context_state.h b/src/dxvk/dxvk_context_state.h index 5516e362..59692883 100644 --- a/src/dxvk/dxvk_context_state.h +++ b/src/dxvk/dxvk_context_state.h @@ -54,10 +54,7 @@ namespace dxvk { struct DxvkOutputMergerState { - std::array clearValue; - DxvkRenderTargets renderTargets; - DxvkRenderPassOps renderPassOps; Rc framebuffer = nullptr; DxvkBlendConstants blendConstants = { 0.0f, 0.0f, 0.0f, 0.0f }; diff --git a/src/dxvk/dxvk_device.cpp b/src/dxvk/dxvk_device.cpp index 72aaa4b2..c961d638 100644 --- a/src/dxvk/dxvk_device.cpp +++ b/src/dxvk/dxvk_device.cpp @@ -117,11 +117,11 @@ namespace dxvk { m_properties.limits.maxFramebufferHeight, m_properties.limits.maxFramebufferLayers }; - auto renderPassFormat = DxvkFramebuffer::getRenderPassFormat(renderTargets); - auto renderPassObject = m_renderPassPool->getRenderPass(renderPassFormat); + auto format = renderTargets.renderPassFormat(); + auto renderPass = m_renderPassPool->getRenderPass(format); return new DxvkFramebuffer(m_vkd, - renderPassObject, renderTargets, defaultSize); + renderPass, renderTargets, defaultSize); } diff --git a/src/dxvk/dxvk_framebuffer.cpp b/src/dxvk/dxvk_framebuffer.cpp index 46865662..1128de2c 100644 --- a/src/dxvk/dxvk_framebuffer.cpp +++ b/src/dxvk/dxvk_framebuffer.cpp @@ -2,117 +2,142 @@ 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; - - uint32_t viewId = 0; + DxvkRenderTargets:: DxvkRenderTargets() { } + DxvkRenderTargets::~DxvkRenderTargets() { } + + + DxvkRenderPassFormat DxvkRenderTargets::renderPassFormat() const { + DxvkRenderPassFormat result; 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; + if (m_colorTargets.at(i).view != nullptr) { + result.setColorFormat(i, DxvkRenderTargetFormat { + 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_renderTargets.depth.view != nullptr) { - views[viewId] = m_renderTargets.depth.view->handle(); - m_attachments[viewId] = &m_renderTargets.depth; - viewId += 1; + if (m_depthTarget.view != nullptr) { + result.setDepthFormat(DxvkRenderTargetFormat { + 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); } - VkFramebufferCreateInfo info; - info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - info.pNext = nullptr; - info.flags = 0; - info.renderPass = m_renderPass->getDefaultHandle(); - info.attachmentCount = viewId; - 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"); + return result; } - 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); - } + uint32_t DxvkRenderTargets::getAttachments(VkImageView* viewHandles) const { + uint32_t numViews = 0; - 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; + if (m_depthTarget.view != nullptr) + viewHandles[numViews++] = m_depthTarget.view->handle(); 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 (m_colorTargets.at(i).view != nullptr) + viewHandles[numViews++] = m_colorTargets.at(i).view->handle(); } - 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; + return numViews; } - DxvkFramebufferSize DxvkFramebuffer::computeRenderSize( + DxvkFramebufferSize DxvkRenderTargets::getImageSize( const DxvkFramebufferSize& defaultSize) const { - if (m_renderTargets.depth.view != nullptr) - return this->computeRenderTargetSize(m_renderTargets.depth.view); + if (m_depthTarget.view != nullptr) + return this->renderTargetSize(m_depthTarget.view); for (uint32_t i = 0; i < MaxNumRenderTargets; i++) { - if (m_renderTargets.color[i].view != nullptr) - return this->computeRenderTargetSize(m_renderTargets.color[i].view); + if (m_colorTargets.at(i).view != nullptr) + return this->renderTargetSize(m_colorTargets.at(i).view); } return defaultSize; } - DxvkFramebufferSize DxvkFramebuffer::computeRenderTargetSize( + bool DxvkRenderTargets::hasAttachments() const { + bool result = m_depthTarget.view != nullptr; + + for (uint32_t i = 0; (i < MaxNumRenderTargets) && !result; i++) + result |= m_colorTargets.at(i).view != nullptr; + + return result; + } + + + bool DxvkRenderTargets::matches(const DxvkRenderTargets& other) const { + bool equal = m_depthTarget.view == other.m_depthTarget.view + && m_depthTarget.layout == other.m_depthTarget.layout; + + for (uint32_t i = 0; i < MaxNumRenderTargets && equal; i++) { + equal &= m_colorTargets.at(i).view == other.m_colorTargets.at(i).view + && m_colorTargets.at(i).layout == other.m_colorTargets.at(i).layout; + } + + return equal; + } + + + DxvkFramebufferSize DxvkRenderTargets::renderTargetSize( 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, + const Rc& renderPass, + const DxvkRenderTargets& renderTargets, + const DxvkFramebufferSize& defaultSize) + : m_vkd (vkd), + m_renderPass (renderPass), + m_renderTargets (renderTargets), + m_framebufferSize (renderTargets.getImageSize(defaultSize)) { + std::array views; + uint32_t viewCount = renderTargets.getAttachments(views.data()); + + VkFramebufferCreateInfo info; + info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + info.pNext = nullptr; + info.flags = 0; + info.renderPass = renderPass->handle(); + info.attachmentCount = viewCount; + info.pAttachments = views.data(); + info.width = m_framebufferSize.width; + info.height = m_framebufferSize.height; + info.layers = m_framebufferSize.layers; + + if (m_vkd->vkCreateFramebuffer(m_vkd->device(), &info, nullptr, &m_framebuffer) != VK_SUCCESS) + throw DxvkError("DxvkFramebuffer: Failed to create framebuffer object"); + } + + + DxvkFramebuffer::~DxvkFramebuffer() { + m_vkd->vkDestroyFramebuffer( + 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 592b6d96..b5edad79 100644 --- a/src/dxvk/dxvk_framebuffer.h +++ b/src/dxvk/dxvk_framebuffer.h @@ -19,12 +19,6 @@ namespace dxvk { }; - /** - * \brief Framebuffer attachment - * - * Stores an attachment, as well as the image layout - * that will be used for rendering to the attachment. - */ struct DxvkAttachment { Rc view = nullptr; VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED; @@ -32,23 +26,127 @@ namespace dxvk { /** - * \brief Render targets + * \brief Render target description * - * Stores all depth-stencil and color - * attachments attached to a framebuffer. + * Stores render targets for a framebuffer object + * and provides methods to query the render pass + * format. Note that all render target views must + * have the same size and number of array layers. */ - struct DxvkRenderTargets { - DxvkAttachment depth; - DxvkAttachment color[MaxNumRenderTargets]; + class DxvkRenderTargets { + + public: + + DxvkRenderTargets(); + ~DxvkRenderTargets(); + + /** + * \brief Retrieves color target + * + * \param [in] id Color attachment ID + * \returns Render target view + */ + DxvkAttachment getColorTarget(uint32_t id) const { + return m_colorTargets.at(id); + } + + /** + * \brief Retrieves depth-stencil target + * \returns Depth-stencil target view + */ + DxvkAttachment getDepthTarget() const { + return m_depthTarget; + } + + /** + * \brief Sets color target + * + * \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, + 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, + VkImageLayout layout) { + m_depthTarget = { view, layout }; + } + + /** + * \brief Render pass format + * + * Computes the render pass format based on + * the color and depth-stencil attachments. + * \returns Render pass format + */ + DxvkRenderPassFormat renderPassFormat() const; + + /** + * \brief Creates attachment list + * + * \param [out] viewHandles Attachment handles + * \returns Framebuffer attachment count + */ + uint32_t getAttachments(VkImageView* viewHandles) const; + + /** + * \brief Framebuffer size + * + * The width, height and layer count of the + * attached render targets. + * \param [in] defaultSize Size to use when + * there are no framebuffer attachments. + * \returns Framebuffer size + */ + DxvkFramebufferSize getImageSize( + const DxvkFramebufferSize& defaultSize) const; + + /** + * \brief Checks whether any attachments are defined + * \returns \c false if no attachments are defined + */ + bool hasAttachments() const; + + /** + * \brief Compares two sets of render targets + * + * Checks whether two sets of render targets + * are identical, including the image layout. + * \param [in] other Render target set to compare to + * \returns \c true if the render targets are the same + */ + bool matches(const DxvkRenderTargets& other) const; + + private: + + std::array m_colorTargets; + DxvkAttachment m_depthTarget; + + DxvkFramebufferSize renderTargetSize( + const Rc& renderTarget) const; + }; /** - * \brief Framebuffer + * \brief DXVK framebuffer * * A framebuffer either stores a set of image views * that will be used as render targets, or in case - * no render targets are attached, fixed dimensions. + * no render targets are being used, fixed viewport + * dimensions. */ class DxvkFramebuffer : public DxvkResource { @@ -59,7 +157,6 @@ namespace dxvk { const Rc& renderPass, const DxvkRenderTargets& renderTargets, const DxvkFramebufferSize& defaultSize); - ~DxvkFramebuffer(); /** @@ -67,7 +164,15 @@ namespace dxvk { * \returns Framebuffer handle */ VkFramebuffer handle() const { - return m_handle; + return m_framebuffer; + } + + /** + * \brief Render pass handle + * \returns Render pass handle + */ + VkRenderPass renderPass() const { + return m_renderPass->handle(); } /** @@ -75,124 +180,45 @@ namespace dxvk { * \returns Framebuffer size */ DxvkFramebufferSize size() const { - return m_renderSize; + return m_framebufferSize; + } + + /** + * \brief Render target info + * \returns Render target info + */ + const DxvkRenderTargets& renderTargets() const { + return m_renderTargets; } /** * \brief Sample count * \returns Sample count */ - VkSampleCountFlagBits getSampleCount() const { - return m_renderPass->getSampleCount(); + VkSampleCountFlagBits sampleCount() const { + return m_renderPass->sampleCount(); } /** - * \brief Retrieves default render pass handle + * \brief Retrieves index of a given attachment * - * Retrieves the render pass handle that was used - * to create the Vulkan framebuffer object with, - * and that should be used to create pipelines. - * \returns The default render pass handle + * \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. */ - VkRenderPass getDefaultRenderPassHandle() const { - return m_renderPass->getDefaultHandle(); - } - - /** - * \brief Retrieves render pass handle - * - * Retrieves a render pass handle that can - * be used to begin a render pass instance. - * \param [in] ops Render pass ops - * \returns The render pass handle - */ - VkRenderPass getRenderPassHandle(const DxvkRenderPassOps& ops) const { - return m_renderPass->getHandle(ops); - } - - /** - * \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 Retrieves attachment by index - * - * \param [in] id Framebuffer attachment ID - * \returns The framebuffer attachment - */ - const DxvkAttachment& getAttachment(uint32_t id) const { - return *m_attachments[id]; - } - - /** - * \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 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); + uint32_t findAttachment( + const Rc& view) const; private: - const Rc m_vkd; - const Rc m_renderPass; - const DxvkRenderTargets m_renderTargets; - const DxvkFramebufferSize m_renderSize; + Rc m_vkd; + Rc m_renderPass; - uint32_t m_attachmentCount = 0; - std::array m_attachments; + DxvkRenderTargets m_renderTargets; + DxvkFramebufferSize m_framebufferSize = { 0, 0, 0 }; - VkFramebuffer m_handle = VK_NULL_HANDLE; - - DxvkFramebufferSize computeRenderSize( - const DxvkFramebufferSize& defaultSize) const; - - DxvkFramebufferSize computeRenderTargetSize( - const Rc& renderTarget) const; + VkFramebuffer m_framebuffer = VK_NULL_HANDLE; }; diff --git a/src/dxvk/dxvk_renderpass.cpp b/src/dxvk/dxvk_renderpass.cpp index e24109c4..e93f46de 100644 --- a/src/dxvk/dxvk_renderpass.cpp +++ b/src/dxvk/dxvk_renderpass.cpp @@ -4,56 +4,29 @@ namespace dxvk { + bool DxvkRenderPassFormat::matchesFormat(const DxvkRenderPassFormat& other) const { + bool equal = m_samples == other.m_samples; + + 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; + + 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; + } + + return equal; + } + + DxvkRenderPass::DxvkRenderPass( - const Rc& vkd, - const DxvkRenderPassFormat& fmt) - : m_vkd(vkd), m_format(fmt), - m_default(createRenderPass(DxvkRenderPassOps())) { - - } - - - DxvkRenderPass::~DxvkRenderPass() { - m_vkd->vkDestroyRenderPass(m_vkd->device(), m_default, nullptr); - - for (const auto& i : m_instances) { - m_vkd->vkDestroyRenderPass( - m_vkd->device(), i.handle, nullptr); - } - } - - - bool DxvkRenderPass::hasCompatibleFormat( - const DxvkRenderPassFormat& fmt) const { - bool eq = m_format.sampleCount == fmt.sampleCount; - - for (uint32_t i = 0; i < MaxNumRenderTargets && eq; i++) { - eq &= m_format.color[i].format == fmt.color[i].format - && m_format.color[i].layout == fmt.color[i].layout; - } - - eq &= m_format.depth.format == fmt.depth.format - && m_format.depth.layout == fmt.depth.layout; - - return eq; - } - - - VkRenderPass DxvkRenderPass::getHandle(const DxvkRenderPassOps& ops) { - std::lock_guard lock(m_mutex); - - for (const auto& i : m_instances) { - if (compareOps(i.ops, ops)) - return i.handle; - } - - VkRenderPass handle = this->createRenderPass(ops); - m_instances.push_back({ ops, handle }); - return handle; - } - - - VkRenderPass DxvkRenderPass::createRenderPass(const DxvkRenderPassOps& ops) { + const Rc& vkd, + const DxvkRenderPassFormat& fmt) + : m_vkd(vkd), m_format(fmt) { std::vector attachments; VkAttachmentReference depthRef; @@ -61,47 +34,51 @@ namespace dxvk { // Render passes may not require the previous // contents of the attachments to be preserved. + const DxvkRenderTargetFormat depthFmt = fmt.getDepthFormat(); + + if (depthFmt.format != VK_FORMAT_UNDEFINED) { + VkAttachmentDescription desc; + desc.flags = 0; + desc.format = depthFmt.format; + desc.samples = fmt.getSampleCount(); + desc.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + desc.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + desc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + desc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_STORE; + desc.initialLayout = depthFmt.initialLayout; + desc.finalLayout = depthFmt.finalLayout; + + depthRef.attachment = attachments.size(); + depthRef.layout = depthFmt.renderLayout; + + attachments.push_back(desc); + } + for (uint32_t i = 0; i < MaxNumRenderTargets; i++) { + const DxvkRenderTargetFormat colorFmt = fmt.getColorFormat(i); + colorRef[i].attachment = VK_ATTACHMENT_UNUSED; colorRef[i].layout = VK_IMAGE_LAYOUT_UNDEFINED; - if (m_format.color[i].format != VK_FORMAT_UNDEFINED) { + if (colorFmt.format != VK_FORMAT_UNDEFINED) { VkAttachmentDescription desc; desc.flags = 0; - desc.format = m_format.color[i].format; - desc.samples = m_format.sampleCount; - desc.loadOp = ops.colorOps[i].loadOp; - desc.storeOp = ops.colorOps[i].storeOp; + desc.format = colorFmt.format; + desc.samples = fmt.getSampleCount(); + desc.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; + desc.storeOp = VK_ATTACHMENT_STORE_OP_STORE; desc.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; desc.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - desc.initialLayout = ops.colorOps[i].loadLayout; - desc.finalLayout = ops.colorOps[i].storeLayout; + desc.initialLayout = colorFmt.initialLayout; + desc.finalLayout = colorFmt.finalLayout; colorRef[i].attachment = attachments.size(); - colorRef[i].layout = m_format.color[i].layout; + colorRef[i].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; attachments.push_back(desc); } } - if (m_format.depth.format != VK_FORMAT_UNDEFINED) { - VkAttachmentDescription desc; - desc.flags = 0; - desc.format = m_format.depth.format; - desc.samples = m_format.sampleCount; - desc.loadOp = ops.depthOps.loadOp; - desc.storeOp = ops.depthOps.storeOp; - desc.stencilLoadOp = ops.depthOps.loadOp; - desc.stencilStoreOp = ops.depthOps.storeOp; - desc.initialLayout = ops.depthOps.loadLayout; - desc.finalLayout = ops.depthOps.storeLayout; - - depthRef.attachment = attachments.size(); - depthRef.layout = m_format.depth.layout; - - attachments.push_back(desc); - } - VkSubpassDescription subpass; subpass.flags = 0; subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; @@ -110,14 +87,11 @@ namespace dxvk { subpass.colorAttachmentCount = colorRef.size(); subpass.pColorAttachments = colorRef.data(); subpass.pResolveAttachments = nullptr; - subpass.pDepthStencilAttachment = &depthRef; + subpass.pDepthStencilAttachment = depthFmt.format != VK_FORMAT_UNDEFINED ? &depthRef : nullptr; subpass.preserveAttachmentCount = 0; subpass.pPreserveAttachments = nullptr; - if (m_format.depth.format == VK_FORMAT_UNDEFINED) - subpass.pDepthStencilAttachment = nullptr; - - const std::array subpassDeps = {{ + std::array subpassDeps = {{ { VK_SUBPASS_EXTERNAL, 0, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | @@ -165,33 +139,14 @@ namespace dxvk { info.dependencyCount = subpassDeps.size(); info.pDependencies = subpassDeps.data(); - VkRenderPass renderPass = VK_NULL_HANDLE; - - if (m_vkd->vkCreateRenderPass(m_vkd->device(), &info, nullptr, &renderPass) != VK_SUCCESS) { - Logger::err("DxvkRenderPass: Failed to create render pass object"); - return VK_NULL_HANDLE; - } - - return renderPass; + if (m_vkd->vkCreateRenderPass(m_vkd->device(), &info, nullptr, &m_renderPass) != VK_SUCCESS) + throw DxvkError("DxvkRenderPass::DxvkRenderPass: Failed to create render pass object"); } - bool DxvkRenderPass::compareOps( - const DxvkRenderPassOps& a, - const DxvkRenderPassOps& b) { - bool eq = a.depthOps.loadOp == b.depthOps.loadOp - && a.depthOps.loadLayout == b.depthOps.loadLayout - && a.depthOps.storeOp == b.depthOps.storeOp - && a.depthOps.storeLayout == b.depthOps.storeLayout; - - for (uint32_t i = 0; i < MaxNumRenderTargets && eq; i++) { - eq &= a.colorOps[i].loadOp == b.colorOps[i].loadOp - && a.colorOps[i].loadLayout == b.colorOps[i].loadLayout - && a.colorOps[i].storeOp == b.colorOps[i].storeOp - && a.colorOps[i].storeLayout == b.colorOps[i].storeLayout; - } - - return eq; + DxvkRenderPass::~DxvkRenderPass() { + m_vkd->vkDestroyRenderPass( + m_vkd->device(), m_renderPass, nullptr); } @@ -206,17 +161,29 @@ namespace dxvk { } - Rc DxvkRenderPassPool::getRenderPass(const DxvkRenderPassFormat& fmt) { + Rc DxvkRenderPassPool::getRenderPass( + const DxvkRenderPassFormat& fmt) { std::lock_guard lock(m_mutex); - for (const auto& r : m_renderPasses) { - if (r->hasCompatibleFormat(fmt)) - return r; + Rc renderPass = nullptr; + + for (uint32_t i = 0; i < m_renderPasses.size() && renderPass == nullptr; i++) { + if (m_renderPasses[i]->matchesFormat(fmt)) + renderPass = m_renderPasses[i]; } - Rc rp = new DxvkRenderPass(m_vkd, fmt); - m_renderPasses.push_back(rp); - return rp; + if (renderPass != nullptr) + return renderPass; + + renderPass = this->createRenderPass(fmt); + m_renderPasses.push_back(renderPass); + return renderPass; + } + + + Rc DxvkRenderPassPool::createRenderPass( + const DxvkRenderPassFormat& fmt) { + return new DxvkRenderPass(m_vkd, fmt); } } \ No newline at end of file diff --git a/src/dxvk/dxvk_renderpass.h b/src/dxvk/dxvk_renderpass.h index a65c5253..0883967a 100644 --- a/src/dxvk/dxvk_renderpass.h +++ b/src/dxvk/dxvk_renderpass.h @@ -1,7 +1,7 @@ #pragma once #include -#include +#include #include "dxvk_hash.h" #include "dxvk_include.h" @@ -10,84 +10,50 @@ namespace dxvk { /** - * \brief Format and layout for a render target + * \brief Format and layout info for a sigle render target * - * Stores the image format of the attachment and - * the image layout that is used while rendering. + * Stores the format, initial layout and + * final layout of a render target. */ - struct DxvkAttachmentFormat { - VkFormat format = VK_FORMAT_UNDEFINED; - VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED; + struct DxvkRenderTargetFormat { + VkFormat format = VK_FORMAT_UNDEFINED; + VkImageLayout initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + VkImageLayout finalLayout = VK_IMAGE_LAYOUT_UNDEFINED; + VkImageLayout renderLayout = VK_IMAGE_LAYOUT_UNDEFINED; }; /** * \brief Render pass format * - * Stores the attachment formats for all depth and - * color attachments, as well as the sample count. + * Stores the formats of all render targets + * that are used by a framebuffer object. */ - struct DxvkRenderPassFormat { - VkSampleCountFlagBits sampleCount = VK_SAMPLE_COUNT_1_BIT; - DxvkAttachmentFormat depth; - DxvkAttachmentFormat color[MaxNumRenderTargets]; - }; - - - /** - * \brief Attachment transitions - * - * Stores the load/store ops and the initial - * and final layout of a single attachment. - */ - struct DxvkAttachmentOps { - VkAttachmentLoadOp loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - VkImageLayout loadLayout = VK_IMAGE_LAYOUT_UNDEFINED; - VkAttachmentStoreOp storeOp = VK_ATTACHMENT_STORE_OP_STORE; - VkImageLayout storeLayout = VK_IMAGE_LAYOUT_GENERAL; - }; - - - /** - * \brief Render pass transitions - * - * Stores transitions for all depth and color attachments. - * This is used to select a specific render pass object - * from a group of render passes with the same format. - */ - struct DxvkRenderPassOps { - DxvkAttachmentOps depthOps; - DxvkAttachmentOps colorOps[MaxNumRenderTargets]; - }; - - - /** - * \brief Render pass object - * - * Manages a set of compatible render passes, i.e. - * render passes which share the same format but - * may differ in their attachment operations. - */ - class DxvkRenderPass : public RcObject { + class DxvkRenderPassFormat { public: - DxvkRenderPass( - const Rc& vkd, - const DxvkRenderPassFormat& fmt); - - ~DxvkRenderPass(); + /** + * \brief Retrieves color target format + * + * If the color target has not been defined, + * this will return \c VK_FORMAT_UNDEFINED. + * \param [in] id Color target index + * \returns Color target format + */ + DxvkRenderTargetFormat getColorFormat(uint32_t id) const { + return m_color.at(id); + } /** - * \brief Checks whether a format is compatible + * \brief Retrieves depth-stencil format * - * Two render pass formats are considered compatible - * if all the relevant attachment formats match. - * \param [in] fmt The render pass format to check - * \returns \c true if this render pass is compatible. + * If the color target has not been defined, + * this will return \c VK_FORMAT_UNDEFINED. */ - bool hasCompatibleFormat( - const DxvkRenderPassFormat& fmt) const; + DxvkRenderTargetFormat getDepthFormat() const { + return m_depth; + } /** * \brief Retrieves sample count @@ -97,53 +63,103 @@ namespace dxvk { * \returns Sample count */ VkSampleCountFlagBits getSampleCount() const { - return m_format.sampleCount; + return m_samples; } /** - * \brief Returns handle of default render pass + * \brief Sets color target format * - * The default render pass handle should be used to - * create pipelines and framebuffer objects. It can - * \e not be used for \c vkCmdBeginRenderPass calls. - * \returns The default render pass handle + * \param [in] id Color target index + * \param [in] fmt Color target format */ - VkRenderPass getDefaultHandle() const { - return m_default; + void setColorFormat(uint32_t id, DxvkRenderTargetFormat fmt) { + m_color.at(id) = fmt; } /** - * \brief Returns handle to a specialized render pass - * - * Returns a handle to a render pass with the given - * set of parameters. This should be used for calls - * to \c vkCmdBeginRenderPass. - * \param [in] ops Attachment ops - * \returns Render pass handle + * \brief Sets depth-stencil format + * \param [in] fmt Depth-stencil format */ - VkRenderPass getHandle( - const DxvkRenderPassOps& ops); + void setDepthFormat(DxvkRenderTargetFormat fmt) { + m_depth = fmt; + } + + /** + * \brief Sets sample count + * \param [in] samples Sample count + */ + void setSampleCount(VkSampleCountFlagBits samples) { + m_samples = samples; + } + + /** + * \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 + */ + bool matchesFormat(const DxvkRenderPassFormat& other) const; private: - struct Instance { - DxvkRenderPassOps ops; - VkRenderPass handle; - }; + std::array m_color; + DxvkRenderTargetFormat m_depth; + VkSampleCountFlagBits m_samples = VK_SAMPLE_COUNT_1_BIT; - Rc m_vkd; - DxvkRenderPassFormat m_format; - VkRenderPass m_default; + }; + + + /** + * \brief DXVK render pass + * + * Render pass objects are used internally to identify render + * target formats and + */ + class DxvkRenderPass : public RcObject { - sync::Spinlock m_mutex; - std::vector m_instances; + public: - VkRenderPass createRenderPass( - const DxvkRenderPassOps& ops); + DxvkRenderPass( + const Rc& vkd, + const DxvkRenderPassFormat& fmt); + ~DxvkRenderPass(); - static bool compareOps( - const DxvkRenderPassOps& a, - const DxvkRenderPassOps& b); + /** + * \brief Render pass handle + * + * Internal use only. + * \returns Render pass handle + */ + VkRenderPass handle() const { + return m_renderPass; + } + + /** + * \brief Render pass sample count + * \returns Render pass sample count + */ + VkSampleCountFlagBits sampleCount() const { + 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; + DxvkRenderPassFormat m_format; + VkRenderPass m_renderPass; }; @@ -151,35 +167,35 @@ namespace dxvk { /** * \brief Render pass pool * - * Manages render pass objects. For each render - * pass format, a new render pass object will - * be created, but no two render pass objects - * will have the same format. + * Thread-safe class that manages the render pass + * objects that are used within an application. */ class DxvkRenderPassPool : public RcObject { public: - DxvkRenderPassPool( - const Rc& vkd); + DxvkRenderPassPool(const Rc& vkd); ~DxvkRenderPassPool(); /** * \brief Retrieves a render pass object * - * \param [in] fmt The render pass format - * \returns Matching render pass object + * \param [in] fmt Render target formats + * \returns Compatible render pass object */ Rc getRenderPass( - const DxvkRenderPassFormat& fmt); + const DxvkRenderPassFormat& fmt); private: - const Rc m_vkd; + Rc m_vkd; std::mutex m_mutex; std::vector> m_renderPasses; + Rc createRenderPass( + const DxvkRenderPassFormat& fmt); + }; } \ No newline at end of file diff --git a/src/dxvk/dxvk_swapchain.cpp b/src/dxvk/dxvk_swapchain.cpp index 36573346..23c0d2b0 100644 --- a/src/dxvk/dxvk_swapchain.cpp +++ b/src/dxvk/dxvk_swapchain.cpp @@ -34,7 +34,7 @@ namespace dxvk { } - Rc DxvkSwapchain::getImageView( + Rc DxvkSwapchain::getFramebuffer( const Rc& wakeSync) { VkResult status = this->acquireNextImage(wakeSync); @@ -136,6 +136,17 @@ namespace dxvk { if (m_vkd->vkCreateSwapchainKHR(m_vkd->device(), &swapInfo, nullptr, &m_handle) != VK_SUCCESS) throw DxvkError("DxvkSwapchain: Failed to recreate swap chain"); + // Create the render pass object + DxvkRenderPassFormat renderTargetFormat; + + renderTargetFormat.setColorFormat(0, + DxvkRenderTargetFormat { fmt.format, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_PRESENT_SRC_KHR }); + + m_renderPass = new DxvkRenderPass( + m_vkd, renderTargetFormat); + // Retrieve swap images auto swapImages = this->retrieveSwapImages(); @@ -170,8 +181,16 @@ namespace dxvk { viewInfo.numLayers = swapInfo.imageArrayLayers; for (size_t i = 0; i < swapImages.size(); i++) { - m_framebuffers.at(i) = m_device->createImageView( - new DxvkImage(m_vkd, imageInfo, swapImages.at(i)), viewInfo); + Rc image = new DxvkImage(m_vkd, imageInfo, swapImages.at(i)); + Rc iview = m_device->createImageView(image, viewInfo); + + DxvkRenderTargets renderTargets; + renderTargets.setColorTarget(0, iview, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + + m_framebuffers.at(i) = new DxvkFramebuffer( + m_vkd, m_renderPass, renderTargets, + DxvkFramebufferSize()); m_semaphoreSet.at(i).acquireSync = m_device->createSemaphore(); m_semaphoreSet.at(i).presentSync = m_device->createSemaphore(); diff --git a/src/dxvk/dxvk_swapchain.h b/src/dxvk/dxvk_swapchain.h index 97661d47..cb5ff103 100644 --- a/src/dxvk/dxvk_swapchain.h +++ b/src/dxvk/dxvk_swapchain.h @@ -53,20 +53,20 @@ namespace dxvk { * * Retrieves a set of semaphores for the acquire * and present operations. This must be called - * \e before \c getImageView. + * \e before \c getFramebuffer. * \returns Semaphore pair */ DxvkSwapSemaphores getSemaphorePair(); /** - * \brief Retrieves the image view for the current frame + * \brief Retrieves the framebuffer for the current frame * * If necessary, this will automatically recreate the - * underlying swapchain object and image view objects. + * underlying swapchain object and framebuffer objects. * \param [in] wakeSync Semaphore to signal - * \returns The image view object + * \returns The framebuffer object */ - Rc getImageView( + Rc getFramebuffer( const Rc& wakeSync); /** @@ -83,7 +83,7 @@ namespace dxvk { /** * \brief Changes swapchain properties * - * This must not be called between \ref getImageView + * This must not be called between \ref getFramebuffer * and \ref present as this method may recreate the swap * chain and framebuffer objects immediately. * \param [in] props New swapchain properties @@ -102,7 +102,8 @@ namespace dxvk { uint32_t m_imageIndex = 0; uint32_t m_frameIndex = 0; - std::vector> m_framebuffers; + Rc m_renderPass; + std::vector> m_framebuffers; std::vector m_semaphoreSet; VkResult acquireNextImage( diff --git a/src/dxvk/hud/dxvk_hud.cpp b/src/dxvk/hud/dxvk_hud.cpp index 66172a06..057427c8 100644 --- a/src/dxvk/hud/dxvk_hud.cpp +++ b/src/dxvk/hud/dxvk_hud.cpp @@ -170,8 +170,8 @@ namespace dxvk::hud { viewInfo.numLayers = 1; m_renderTargetView = m_device->createImageView(m_renderTarget, viewInfo); - m_renderTargetInfo.color[0] = { m_renderTargetView, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; + m_renderTargetInfo.setColorTarget(0, m_renderTargetView, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); }