From 343eba693d9866f1dcc1dda07a9eaeb20162dbd1 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Sat, 2 Jul 2022 20:39:20 +0200 Subject: [PATCH] [dxvk] Use dynamic rendering for regular graphics pipelines For now, just do whatever we were previously doing for render passes, but explicitly. --- src/dxvk/dxvk_context.cpp | 225 +++++++++++++++++++++++++++++---- src/dxvk/dxvk_context.h | 8 ++ src/dxvk/dxvk_framebuffer.cpp | 21 +++ src/dxvk/dxvk_framebuffer.h | 7 + src/dxvk/dxvk_graphics.cpp | 148 +++++++++------------- src/dxvk/dxvk_graphics_state.h | 92 ++++++++++++++ 6 files changed, 389 insertions(+), 112 deletions(-) diff --git a/src/dxvk/dxvk_context.cpp b/src/dxvk/dxvk_context.cpp index 595140fb9..115f7acaa 100644 --- a/src/dxvk/dxvk_context.cpp +++ b/src/dxvk/dxvk_context.cpp @@ -1932,10 +1932,7 @@ namespace dxvk { } if (attachmentIndex < 0) { - if (m_execBarriers.isImageDirty( - imageView->image(), - imageView->imageSubresources(), - DxvkAccess::Write)) + if (m_execBarriers.isImageDirty(imageView->image(), imageView->imageSubresources(), DxvkAccess::Write)) m_execBarriers.recordCommands(m_cmd); // Set up and bind a temporary framebuffer @@ -3982,6 +3979,133 @@ namespace dxvk { } + void DxvkContext::renderPassEmitInitBarriers( + const DxvkFramebufferInfo& framebufferInfo, + const DxvkRenderPassOps& ops) { + // If any of the involved images are dirty, emit all pending barriers now. + // Otherwise, skip this step so that we can more efficiently batch barriers. + for (uint32_t i = 0; i < framebufferInfo.numAttachments(); i++) { + const auto& attachment = framebufferInfo.getAttachment(i); + + if (m_execBarriers.isImageDirty( + attachment.view->image(), + attachment.view->imageSubresources(), + DxvkAccess::Write)) { + m_execBarriers.recordCommands(m_cmd); + break; + } + } + + // Transition all images to the render layout as necessary + const auto& depthAttachment = framebufferInfo.getDepthTarget(); + + if (depthAttachment.layout != ops.depthOps.loadLayout + && depthAttachment.view != nullptr) { + VkImageAspectFlags depthAspects = depthAttachment.view->info().aspect; + + VkPipelineStageFlags depthStages = + VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | + VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; + VkAccessFlags depthAccess = 0; + + if (((depthAspects & VK_IMAGE_ASPECT_DEPTH_BIT) && ops.depthOps.loadOpD == VK_ATTACHMENT_LOAD_OP_LOAD) + || ((depthAspects & VK_IMAGE_ASPECT_STENCIL_BIT) && ops.depthOps.loadOpS == VK_ATTACHMENT_LOAD_OP_LOAD)) + depthAccess |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT; + + if (((depthAspects & VK_IMAGE_ASPECT_DEPTH_BIT) && ops.depthOps.loadOpD != VK_ATTACHMENT_LOAD_OP_LOAD) + || ((depthAspects & VK_IMAGE_ASPECT_STENCIL_BIT) && ops.depthOps.loadOpS != VK_ATTACHMENT_LOAD_OP_LOAD) + || (depthAttachment.layout != VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL)) + depthAccess |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + + if (depthAttachment.layout != VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) { + depthStages |= m_device->getShaderPipelineStages(); + depthAccess |= VK_ACCESS_SHADER_READ_BIT; + } + + m_execBarriers.accessImage( + depthAttachment.view->image(), + depthAttachment.view->imageSubresources(), + ops.depthOps.loadLayout, + depthStages, 0, + depthAttachment.layout, + depthStages, depthAccess); + } + + for (uint32_t i = 0; i < MaxNumRenderTargets; i++) { + const auto& colorAttachment = framebufferInfo.getColorTarget(i); + + if (colorAttachment.layout != ops.colorOps[i].loadLayout + && colorAttachment.view != nullptr) { + VkAccessFlags colorAccess = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + + if (ops.colorOps[i].loadOp == VK_ATTACHMENT_LOAD_OP_LOAD) + colorAccess |= VK_ACCESS_COLOR_ATTACHMENT_READ_BIT; + + m_execBarriers.accessImage( + colorAttachment.view->image(), + colorAttachment.view->imageSubresources(), + ops.colorOps[i].loadLayout, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, + colorAttachment.layout, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + colorAccess); + } + } + + // Unconditionally emit barriers here. We need to do this + // even if there are no layout transitions, since we don't + // track resource usage during render passes. + m_execBarriers.recordCommands(m_cmd); + } + + + void DxvkContext::renderPassEmitPostBarriers( + const DxvkFramebufferInfo& framebufferInfo, + const DxvkRenderPassOps& ops) { + const auto& depthAttachment = framebufferInfo.getDepthTarget(); + + if (depthAttachment.view != nullptr) { + m_execBarriers.accessImage( + depthAttachment.view->image(), + depthAttachment.view->imageSubresources(), + depthAttachment.layout, + VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | + VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | + VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, + ops.depthOps.storeLayout, + depthAttachment.view->imageInfo().stages, + depthAttachment.view->imageInfo().access); + } + + for (uint32_t i = 0; i < MaxNumRenderTargets; i++) { + const auto& colorAttachment = framebufferInfo.getColorTarget(i); + + if (colorAttachment.view != nullptr) { + m_execBarriers.accessImage( + colorAttachment.view->image(), + colorAttachment.view->imageSubresources(), + colorAttachment.layout, + VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, + VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | + VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, + ops.colorOps[i].storeLayout, + colorAttachment.view->imageInfo().stages, + colorAttachment.view->imageInfo().access); + } + } + + m_execBarriers.accessMemory( + ops.barrier.srcStages, + ops.barrier.srcAccess, + ops.barrier.dstStages, + ops.barrier.dstAccess); + + // Do not flush barriers here. This is intended since + // we pre-record them when binding the framebuffer. + } + + void DxvkContext::renderPassBindFramebuffer( const DxvkFramebufferInfo& framebufferInfo, const DxvkRenderPassOps& ops, @@ -3989,26 +4113,75 @@ namespace dxvk { const VkClearValue* clearValues) { const DxvkFramebufferSize fbSize = framebufferInfo.size(); - Rc framebuffer = this->lookupFramebuffer(framebufferInfo); + this->renderPassEmitInitBarriers(framebufferInfo, ops); + this->renderPassEmitPostBarriers(framebufferInfo, ops); - 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 = framebufferInfo.renderPass()->getHandle(ops); - info.framebuffer = framebuffer->handle(); - info.renderArea = renderArea; - info.clearValueCount = clearValueCount; - info.pClearValues = clearValues; - - m_cmd->cmdBeginRenderPass(&info, - VK_SUBPASS_CONTENTS_INLINE); - - m_cmd->trackResource(framebuffer); + uint32_t clearValueIndex = 0; + uint32_t colorInfoCount = 0; + std::array colorInfos; + + for (uint32_t i = 0; i < MaxNumRenderTargets; i++) { + const auto& colorTarget = framebufferInfo.getColorTarget(i); + colorInfos[i] = { VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR }; + + if (colorTarget.view != nullptr) { + colorInfos[i].imageView = colorTarget.view->handle(); + colorInfos[i].imageLayout = colorTarget.layout; + colorInfos[i].loadOp = ops.colorOps[i].loadOp; + colorInfos[i].storeOp = VK_ATTACHMENT_STORE_OP_STORE; + + if (ops.colorOps[i].loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR) + colorInfos[i].clearValue = clearValues[clearValueIndex]; + + clearValueIndex += 1; + colorInfoCount = i + 1; + } + } + + VkRenderingAttachmentInfoKHR depthInfo = { VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR }; + VkImageAspectFlags depthStencilAspects = 0; + + if (framebufferInfo.getDepthTarget().view != nullptr) { + const auto& depthTarget = framebufferInfo.getDepthTarget(); + depthStencilAspects = depthTarget.view->info().aspect; + depthInfo.imageView = depthTarget.view->handle(); + depthInfo.imageLayout = depthTarget.layout; + depthInfo.loadOp = ops.depthOps.loadOpD; + depthInfo.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + + if (ops.depthOps.loadOpD == VK_ATTACHMENT_LOAD_OP_CLEAR) + depthInfo.clearValue = clearValues[clearValueIndex]; + } + + VkRenderingAttachmentInfoKHR stencilInfo = depthInfo; + + if (framebufferInfo.getDepthTarget().view != nullptr) { + stencilInfo.loadOp = ops.depthOps.loadOpS; + stencilInfo.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + + if (ops.depthOps.loadOpS == VK_ATTACHMENT_LOAD_OP_CLEAR) + stencilInfo.clearValue = clearValues[clearValueIndex]; + } + + VkRenderingInfoKHR renderingInfo = { VK_STRUCTURE_TYPE_RENDERING_INFO_KHR }; + renderingInfo.renderArea.offset = VkOffset2D { 0, 0 }; + renderingInfo.renderArea.extent = VkExtent2D { fbSize.width, fbSize.height }; + renderingInfo.layerCount = fbSize.layers; + + if (colorInfoCount) { + renderingInfo.colorAttachmentCount = colorInfoCount; + renderingInfo.pColorAttachments = colorInfos.data(); + } + + if (depthStencilAspects & VK_IMAGE_ASPECT_DEPTH_BIT) + renderingInfo.pDepthAttachment = &depthInfo; + + if (depthStencilAspects & VK_IMAGE_ASPECT_STENCIL_BIT) + renderingInfo.pStencilAttachment = &stencilInfo; + + m_cmd->cmdBeginRendering(&renderingInfo); + for (uint32_t i = 0; i < framebufferInfo.numAttachments(); i++) { m_cmd->trackResource (framebufferInfo.getAttachment(i).view); m_cmd->trackResource(framebufferInfo.getAttachment(i).view->image()); @@ -4019,7 +4192,11 @@ namespace dxvk { void DxvkContext::renderPassUnbindFramebuffer() { - m_cmd->cmdEndRenderPass(); + m_cmd->cmdEndRendering(); + + // TODO Try to get rid of this for performance reasons. + // This only exists to emulate render pass barriers. + m_execBarriers.recordCommands(m_cmd); } @@ -4499,7 +4676,9 @@ namespace dxvk { DxvkFramebufferInfo fbInfo = makeFramebufferInfo(m_state.om.renderTargets); this->updateRenderTargetLayouts(fbInfo, m_state.om.framebufferInfo); + // Update relevant graphics pipeline state m_state.gp.state.ms.setSampleCount(fbInfo.getSampleCount()); + m_state.gp.state.rt = fbInfo.getRtInfo(); m_state.om.framebufferInfo = fbInfo; for (uint32_t i = 0; i < MaxNumRenderTargets; i++) { diff --git a/src/dxvk/dxvk_context.h b/src/dxvk/dxvk_context.h index de29f3c22..fb6fdddf7 100644 --- a/src/dxvk/dxvk_context.h +++ b/src/dxvk/dxvk_context.h @@ -1286,6 +1286,14 @@ namespace dxvk { void startRenderPass(); void spillRenderPass(bool suspend); + void renderPassEmitInitBarriers( + const DxvkFramebufferInfo& framebufferInfo, + const DxvkRenderPassOps& ops); + + void renderPassEmitPostBarriers( + const DxvkFramebufferInfo& framebufferInfo, + const DxvkRenderPassOps& ops); + void renderPassBindFramebuffer( const DxvkFramebufferInfo& framebufferInfo, const DxvkRenderPassOps& ops, diff --git a/src/dxvk/dxvk_framebuffer.cpp b/src/dxvk/dxvk_framebuffer.cpp index 58d07e3b0..226e3f11e 100644 --- a/src/dxvk/dxvk_framebuffer.cpp +++ b/src/dxvk/dxvk_framebuffer.cpp @@ -88,6 +88,27 @@ namespace dxvk { } + DxvkRtInfo DxvkFramebufferInfo::getRtInfo() const { + VkFormat depthStencilFormat = VK_FORMAT_UNDEFINED; + VkImageAspectFlags depthStencilReadOnlyAspects = 0; + + if (m_renderTargets.depth.view != nullptr) { + depthStencilFormat = m_renderTargets.depth.view->info().format; + depthStencilReadOnlyAspects = m_renderTargets.depth.view->formatInfo()->aspectMask + & ~vk::getWritableAspectsForLayout(m_renderTargets.depth.layout); + } + + std::array colorFormats = { }; + for (uint32_t i = 0; i < MaxNumRenderTargets; i++) { + if (m_renderTargets.color[i].view != nullptr) + colorFormats[i] = m_renderTargets.color[i].view->info().format; + } + + return DxvkRtInfo(MaxNumRenderTargets, colorFormats.data(), + depthStencilFormat, depthStencilReadOnlyAspects); + } + + DxvkRenderPassFormat DxvkFramebufferInfo::getRenderPassFormat(const DxvkRenderTargets& renderTargets) { DxvkRenderPassFormat format; diff --git a/src/dxvk/dxvk_framebuffer.h b/src/dxvk/dxvk_framebuffer.h index b55e6e5fa..c0eb8919d 100644 --- a/src/dxvk/dxvk_framebuffer.h +++ b/src/dxvk/dxvk_framebuffer.h @@ -1,6 +1,7 @@ #pragma once #include "dxvk_image.h" +#include "dxvk_graphics_state.h" #include "dxvk_renderpass.h" namespace dxvk { @@ -225,6 +226,12 @@ namespace dxvk { */ DxvkFramebufferKey key() const; + /** + * \brief Generates render target state + * \returns Render target state info + */ + DxvkRtInfo getRtInfo() const; + /** * \brief Generatess render pass format * diff --git a/src/dxvk/dxvk_graphics.cpp b/src/dxvk/dxvk_graphics.cpp index b611059a4..e1644d103 100644 --- a/src/dxvk/dxvk_graphics.cpp +++ b/src/dxvk/dxvk_graphics.cpp @@ -120,9 +120,6 @@ namespace dxvk { this->logPipelineState(LogLevel::Debug, state); } - // Render pass format and image layouts - DxvkRenderPassFormat passFormat = renderPass->format(); - // Set up dynamic states as needed std::array dynamicStates; uint32_t dynamicStateCount = 0; @@ -180,29 +177,41 @@ namespace dxvk { if (fsm) stages.push_back(fsm.stageInfo(&specInfo)); // Fix up color write masks using the component mappings - std::array omBlendAttachments; + VkImageAspectFlags rtReadOnlyAspects = state.rt.getDepthStencilReadOnlyAspects(); + VkFormat rtDepthFormat = state.rt.getDepthStencilFormat(); + auto rtDepthFormatInfo = imageFormatInfo(rtDepthFormat); + + std::array omBlendAttachments = { }; + std::array rtColorFormats; + uint32_t rtColorFormatCount = 0; const VkColorComponentFlags fullMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; for (uint32_t i = 0; i < MaxNumRenderTargets; i++) { - auto formatInfo = imageFormatInfo(passFormat.color[i].format); - omBlendAttachments[i] = state.omBlend[i].state(); + rtColorFormats[i] = state.rt.getColorFormat(i); - if (!(m_fsOut & (1 << i)) || !formatInfo) { - omBlendAttachments[i].colorWriteMask = 0; - } else { - if (omBlendAttachments[i].colorWriteMask != fullMask) { - omBlendAttachments[i].colorWriteMask = util::remapComponentMask( - state.omBlend[i].colorWriteMask(), state.omSwizzle[i].mapping()); - } + if (rtColorFormats[i]) { + rtColorFormatCount = i + 1; - omBlendAttachments[i].colorWriteMask &= formatInfo->componentMask; + auto formatInfo = imageFormatInfo(rtColorFormats[i]); + omBlendAttachments[i] = state.omBlend[i].state(); - if (omBlendAttachments[i].colorWriteMask == formatInfo->componentMask) { - omBlendAttachments[i].colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT - | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + if (!(m_fsOut & (1 << i)) || !formatInfo) { + omBlendAttachments[i].colorWriteMask = 0; + } else { + if (omBlendAttachments[i].colorWriteMask != fullMask) { + omBlendAttachments[i].colorWriteMask = util::remapComponentMask( + state.omBlend[i].colorWriteMask(), state.omSwizzle[i].mapping()); + } + + omBlendAttachments[i].colorWriteMask &= formatInfo->componentMask; + + if (omBlendAttachments[i].colorWriteMask == formatInfo->componentMask) { + omBlendAttachments[i].colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT + | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + } } } } @@ -241,16 +250,11 @@ namespace dxvk { viAttribs[i].binding = viBindingMap[state.ilAttributes[i].binding()]; } - VkPipelineVertexInputDivisorStateCreateInfoEXT viDivisorInfo; - viDivisorInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT; - viDivisorInfo.pNext = nullptr; + VkPipelineVertexInputDivisorStateCreateInfoEXT viDivisorInfo = { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT }; viDivisorInfo.vertexBindingDivisorCount = viDivisorCount; viDivisorInfo.pVertexBindingDivisors = viDivisorDesc.data(); - VkPipelineVertexInputStateCreateInfo viInfo; - viInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; - viInfo.pNext = &viDivisorInfo; - viInfo.flags = 0; + VkPipelineVertexInputStateCreateInfo viInfo = { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, &viDivisorInfo }; viInfo.vertexBindingDescriptionCount = state.il.bindingCount(); viInfo.pVertexBindingDescriptions = viBindings.data(); viInfo.vertexAttributeDescriptionCount = state.il.attributeCount(); @@ -263,60 +267,34 @@ namespace dxvk { if (!m_pipeMgr->m_device->features().extVertexAttributeDivisor.vertexAttributeInstanceRateDivisor) viInfo.pNext = viDivisorInfo.pNext; - VkPipelineInputAssemblyStateCreateInfo iaInfo; - iaInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; - iaInfo.pNext = nullptr; - iaInfo.flags = 0; + VkPipelineInputAssemblyStateCreateInfo iaInfo = { VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO }; iaInfo.topology = state.ia.primitiveTopology(); iaInfo.primitiveRestartEnable = state.ia.primitiveRestart(); - VkPipelineTessellationStateCreateInfo tsInfo; - tsInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO; - tsInfo.pNext = nullptr; - tsInfo.flags = 0; + VkPipelineTessellationStateCreateInfo tsInfo = { VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO }; tsInfo.patchControlPoints = state.ia.patchVertexCount(); - VkPipelineViewportStateCreateInfo vpInfo; - vpInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; - vpInfo.pNext = nullptr; - vpInfo.flags = 0; + VkPipelineViewportStateCreateInfo vpInfo = { VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO }; vpInfo.viewportCount = state.rs.viewportCount(); - vpInfo.pViewports = nullptr; vpInfo.scissorCount = state.rs.viewportCount(); - vpInfo.pScissors = nullptr; - VkPipelineRasterizationConservativeStateCreateInfoEXT conservativeInfo; - conservativeInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_CONSERVATIVE_STATE_CREATE_INFO_EXT; - conservativeInfo.pNext = nullptr; - conservativeInfo.flags = 0; + VkPipelineRasterizationConservativeStateCreateInfoEXT conservativeInfo = { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_CONSERVATIVE_STATE_CREATE_INFO_EXT }; conservativeInfo.conservativeRasterizationMode = state.rs.conservativeMode(); conservativeInfo.extraPrimitiveOverestimationSize = 0.0f; - VkPipelineRasterizationStateStreamCreateInfoEXT xfbStreamInfo; - xfbStreamInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_STREAM_CREATE_INFO_EXT; - xfbStreamInfo.pNext = nullptr; - xfbStreamInfo.flags = 0; + VkPipelineRasterizationStateStreamCreateInfoEXT xfbStreamInfo = { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_STREAM_CREATE_INFO_EXT }; xfbStreamInfo.rasterizationStream = uint32_t(rasterizedStream); - VkPipelineRasterizationDepthClipStateCreateInfoEXT rsDepthClipInfo; - rsDepthClipInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_DEPTH_CLIP_STATE_CREATE_INFO_EXT; - rsDepthClipInfo.pNext = nullptr; - rsDepthClipInfo.flags = 0; + VkPipelineRasterizationDepthClipStateCreateInfoEXT rsDepthClipInfo = { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_DEPTH_CLIP_STATE_CREATE_INFO_EXT }; rsDepthClipInfo.depthClipEnable = state.rs.depthClipEnable(); - VkPipelineRasterizationStateCreateInfo rsInfo; - rsInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; - rsInfo.pNext = nullptr; - rsInfo.flags = 0; + VkPipelineRasterizationStateCreateInfo rsInfo = { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO }; rsInfo.depthClampEnable = VK_TRUE; rsInfo.rasterizerDiscardEnable = rasterizedStream < 0; rsInfo.polygonMode = state.rs.polygonMode(); rsInfo.cullMode = state.rs.cullMode(); rsInfo.frontFace = state.rs.frontFace(); rsInfo.depthBiasEnable = state.rs.depthBiasEnable(); - rsInfo.depthBiasConstantFactor= 0.0f; - rsInfo.depthBiasClamp = 0.0f; - rsInfo.depthBiasSlopeFactor = 0.0f; rsInfo.lineWidth = 1.0f; if (rasterizedStream > 0) @@ -332,10 +310,7 @@ namespace dxvk { uint32_t sampleMask = state.ms.sampleMask(); - VkPipelineMultisampleStateCreateInfo msInfo; - msInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; - msInfo.pNext = nullptr; - msInfo.flags = 0; + VkPipelineMultisampleStateCreateInfo msInfo = { VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO }; msInfo.rasterizationSamples = sampleCount; msInfo.sampleShadingEnable = m_common.msSampleShadingEnable; msInfo.minSampleShading = m_common.msSampleShadingFactor; @@ -343,43 +318,41 @@ namespace dxvk { msInfo.alphaToCoverageEnable = state.ms.enableAlphaToCoverage(); msInfo.alphaToOneEnable = VK_FALSE; - VkPipelineDepthStencilStateCreateInfo dsInfo; - dsInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; - dsInfo.pNext = nullptr; - dsInfo.flags = 0; + VkPipelineDepthStencilStateCreateInfo dsInfo = { VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO }; dsInfo.depthTestEnable = state.ds.enableDepthTest(); - dsInfo.depthWriteEnable = state.ds.enableDepthWrite() && !util::isDepthReadOnlyLayout(passFormat.depth.layout); + dsInfo.depthWriteEnable = state.ds.enableDepthWrite() && !(rtReadOnlyAspects & VK_IMAGE_ASPECT_DEPTH_BIT); dsInfo.depthCompareOp = state.ds.depthCompareOp(); dsInfo.depthBoundsTestEnable = state.ds.enableDepthBoundsTest(); dsInfo.stencilTestEnable = state.ds.enableStencilTest(); dsInfo.front = state.dsFront.state(); dsInfo.back = state.dsBack.state(); - dsInfo.minDepthBounds = 0.0f; - dsInfo.maxDepthBounds = 1.0f; - VkPipelineColorBlendStateCreateInfo cbInfo; - cbInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; - cbInfo.pNext = nullptr; - cbInfo.flags = 0; + VkPipelineColorBlendStateCreateInfo cbInfo = { VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO }; cbInfo.logicOpEnable = state.om.enableLogicOp(); cbInfo.logicOp = state.om.logicOp(); - cbInfo.attachmentCount = DxvkLimits::MaxNumRenderTargets; + cbInfo.attachmentCount = rtColorFormatCount; cbInfo.pAttachments = omBlendAttachments.data(); - for (uint32_t i = 0; i < 4; i++) - cbInfo.blendConstants[i] = 0.0f; - - VkPipelineDynamicStateCreateInfo dyInfo; - dyInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; - dyInfo.pNext = nullptr; - dyInfo.flags = 0; + VkPipelineDynamicStateCreateInfo dyInfo = { VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO }; dyInfo.dynamicStateCount = dynamicStateCount; dyInfo.pDynamicStates = dynamicStates.data(); - - VkGraphicsPipelineCreateInfo info; - info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; - info.pNext = nullptr; - info.flags = 0; + + VkPipelineRenderingCreateInfoKHR rtInfo = { VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR }; + + if (rtColorFormatCount) { + rtInfo.colorAttachmentCount = rtColorFormatCount; + rtInfo.pColorAttachmentFormats = rtColorFormats.data(); + } + + if (rtDepthFormat) { + if (rtDepthFormatInfo->aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) + rtInfo.depthAttachmentFormat = rtDepthFormat; + + if (rtDepthFormatInfo->aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) + rtInfo.stencilAttachmentFormat = rtDepthFormat; + } + + VkGraphicsPipelineCreateInfo info = { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, &rtInfo }; info.stageCount = stages.size(); info.pStages = stages.data(); info.pVertexInputState = &viInfo; @@ -392,12 +365,9 @@ namespace dxvk { info.pColorBlendState = &cbInfo; info.pDynamicState = &dyInfo; info.layout = m_bindings->getPipelineLayout(); - info.renderPass = renderPass->getDefaultHandle(); - info.subpass = 0; - info.basePipelineHandle = VK_NULL_HANDLE; info.basePipelineIndex = -1; - if (tsInfo.patchControlPoints == 0) + if (!tsInfo.patchControlPoints) info.pTessellationState = nullptr; // Time pipeline compilation for debugging purposes diff --git a/src/dxvk/dxvk_graphics_state.h b/src/dxvk/dxvk_graphics_state.h index 0044b4053..2c8ae023e 100644 --- a/src/dxvk/dxvk_graphics_state.h +++ b/src/dxvk/dxvk_graphics_state.h @@ -477,6 +477,97 @@ namespace dxvk { }; + /** + * \brief Packed render target formats + * + * Compact representation of depth-stencil and color attachments, + * as well as the read-only mask for the depth-stencil attachment, + * which needs to be known at pipeline compile time. + */ + class DxvkRtInfo { + + public: + + DxvkRtInfo() = default; + + DxvkRtInfo( + uint32_t colorFormatCount, + const VkFormat* colorFormats, + VkFormat depthStencilFormat, + VkImageAspectFlags depthStencilReadOnlyAspects) + : m_packedData(0ull) { + m_packedData |= encodeDepthStencilFormat(depthStencilFormat); + m_packedData |= encodeDepthStencilAspects(depthStencilReadOnlyAspects); + + for (uint32_t i = 0; i < colorFormatCount; i++) + m_packedData |= encodeColorFormat(colorFormats[i], i); + } + + VkFormat getColorFormat(uint32_t index) const { + return decodeColorFormat(m_packedData, index); + } + + VkFormat getDepthStencilFormat() const { + return decodeDepthStencilFormat(m_packedData); + } + + VkImageAspectFlags getDepthStencilReadOnlyAspects() const { + return decodeDepthStencilAspects(m_packedData); + } + + private: + + uint64_t m_packedData; + + static uint64_t encodeDepthStencilAspects(VkImageAspectFlags aspects) { + return uint64_t(aspects) << 61; + } + + static uint64_t encodeDepthStencilFormat(VkFormat format) { + return format + ? (uint64_t(format) - uint64_t(VK_FORMAT_E5B9G9R9_UFLOAT_PACK32)) << 56 + : (uint64_t(0)); + } + + static uint64_t encodeColorFormat(VkFormat format, uint32_t index) { + uint64_t value = uint64_t(format); + + if (value >= uint64_t(VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT)) { + value -= uint64_t(VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT); + value += uint64_t(VK_FORMAT_E5B9G9R9_UFLOAT_PACK32) + 1; + } else if (value > uint64_t(VK_FORMAT_E5B9G9R9_UFLOAT_PACK32)) { + value = 0; + } + + return value << (7 * index); + } + + static VkImageAspectFlags decodeDepthStencilAspects(uint64_t value) { + return VkImageAspectFlags((value >> 61) & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)); + } + + static VkFormat decodeDepthStencilFormat(uint64_t value) { + value = (value >> 56) & 0x1F; + + return value + ? VkFormat(value + uint64_t(VK_FORMAT_E5B9G9R9_UFLOAT_PACK32)) + : VkFormat(VK_FORMAT_UNDEFINED); + } + + static VkFormat decodeColorFormat(uint64_t value, uint32_t index) { + value = (value >> (7 * index)) & 0x7F; + + if (value > uint64_t(VK_FORMAT_E5B9G9R9_UFLOAT_PACK32)) { + value -= uint64_t(VK_FORMAT_E5B9G9R9_UFLOAT_PACK32) + 1ull; + value += uint64_t(VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT); + } + + return VkFormat(value); + } + + }; + + /** * \brief Packed attachment blend mode * @@ -685,6 +776,7 @@ namespace dxvk { DxvkMsInfo ms; DxvkDsInfo ds; DxvkOmInfo om; + DxvkRtInfo rt; DxvkScInfo sc; DxvkDsStencilOp dsFront; DxvkDsStencilOp dsBack;