From 63420c0cd7f2533f204b6f6b0632f2dac7ef6c8d Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Sun, 31 Jul 2022 00:24:16 +0200 Subject: [PATCH] [dxvk] Introduce DxvkGraphicsPipelineShaderState And factor out a bunch of related code. --- src/dxvk/dxvk_graphics.cpp | 193 ++++++++++++++++++++------------- src/dxvk/dxvk_graphics.h | 47 ++++++-- src/dxvk/dxvk_graphics_state.h | 10 ++ 3 files changed, 164 insertions(+), 86 deletions(-) diff --git a/src/dxvk/dxvk_graphics.cpp b/src/dxvk/dxvk_graphics.cpp index 6ab86914..9fb31ab7 100644 --- a/src/dxvk/dxvk_graphics.cpp +++ b/src/dxvk/dxvk_graphics.cpp @@ -601,6 +601,112 @@ namespace dxvk { } + DxvkGraphicsPipelineShaderState::DxvkGraphicsPipelineShaderState() { + + } + + + DxvkGraphicsPipelineShaderState::DxvkGraphicsPipelineShaderState( + const DxvkGraphicsPipelineShaders& shaders, + const DxvkGraphicsPipelineStateInfo& state) + : vsInfo (getCreateInfo(shaders, shaders.vs, state)), + tcsInfo (getCreateInfo(shaders, shaders.tcs, state)), + tesInfo (getCreateInfo(shaders, shaders.tes, state)), + gsInfo (getCreateInfo(shaders, shaders.gs, state)), + fsInfo (getCreateInfo(shaders, shaders.fs, state)) { + + } + + + bool DxvkGraphicsPipelineShaderState::eq(const DxvkGraphicsPipelineShaderState& other) const { + return vsInfo.eq(other.vsInfo) + && tcsInfo.eq(other.tcsInfo) + && tesInfo.eq(other.tesInfo) + && gsInfo.eq(other.gsInfo) + && fsInfo.eq(other.fsInfo); + } + + + size_t DxvkGraphicsPipelineShaderState::hash() const { + DxvkHashState hash; + hash.add(vsInfo.hash()); + hash.add(tcsInfo.hash()); + hash.add(tesInfo.hash()); + hash.add(gsInfo.hash()); + hash.add(fsInfo.hash()); + return hash; + } + + + DxvkShaderModuleCreateInfo DxvkGraphicsPipelineShaderState::getCreateInfo( + const DxvkGraphicsPipelineShaders& shaders, + const Rc& shader, + const DxvkGraphicsPipelineStateInfo& state) { + DxvkShaderModuleCreateInfo info; + + if (shader == nullptr) + return info; + + // Fix up fragment shader outputs for dual-source blending + const DxvkShaderCreateInfo& shaderInfo = shader->info(); + + if (shaderInfo.stage == VK_SHADER_STAGE_FRAGMENT_BIT) { + info.fsDualSrcBlend = state.useDualSourceBlending(); + + for (uint32_t i = 0; i < MaxNumRenderTargets; i++) { + if ((shaderInfo.outputMask & (1u << i)) && state.writesRenderTarget(i)) + info.rtSwizzles[i] = state.omSwizzle[i].mapping(); + } + } + + // Deal with undefined shader inputs + uint32_t consumedInputs = shaderInfo.inputMask; + uint32_t providedInputs = 0; + + if (shaderInfo.stage == VK_SHADER_STAGE_VERTEX_BIT) { + for (uint32_t i = 0; i < state.il.attributeCount(); i++) + providedInputs |= 1u << state.ilAttributes[i].location(); + } else if (shaderInfo.stage != VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) { + auto prevStage = getPrevStageShader(shaders, shaderInfo.stage); + providedInputs = prevStage->info().outputMask; + } else { + // Technically not correct, but this + // would need a lot of extra care + providedInputs = consumedInputs; + } + + info.undefinedInputs = (providedInputs & consumedInputs) ^ consumedInputs; + return info; + } + + + Rc DxvkGraphicsPipelineShaderState::getPrevStageShader( + const DxvkGraphicsPipelineShaders& shaders, + const VkShaderStageFlagBits stage) { + if (stage == VK_SHADER_STAGE_VERTEX_BIT) + return nullptr; + + if (stage == VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) + return shaders.tcs; + + Rc result = shaders.vs; + + if (stage == VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) + return result; + + if (shaders.tes != nullptr) + result = shaders.tes; + + if (stage == VK_SHADER_STAGE_GEOMETRY_BIT) + return result; + + if (shaders.gs != nullptr) + result = shaders.gs; + + return result; + } + + DxvkPipelineSpecConstantState::DxvkPipelineSpecConstantState() { } @@ -888,7 +994,8 @@ namespace dxvk { // Remapping fragment shader outputs would require spec constants for (uint32_t i = 0; i < MaxNumRenderTargets; i++) { - if (writesRenderTarget(state, i) && !util::isIdentityMapping(state.omSwizzle[i].mapping())) + if ((m_fsOut & (1u << i)) && state.writesRenderTarget(i) + && !util::isIdentityMapping(state.omSwizzle[i].mapping())) return false; } @@ -978,6 +1085,7 @@ namespace dxvk { } // Set up pipeline state + DxvkGraphicsPipelineShaderState shState(m_shaders, state); DxvkGraphicsPipelineVertexInputState viState(m_device, state, m_shaders.vs.ptr()); DxvkGraphicsPipelinePreRasterizationState prState(m_device, state, m_shaders.gs.ptr()); DxvkGraphicsPipelineFragmentShaderState fsState(m_device, state); @@ -993,16 +1101,16 @@ namespace dxvk { if (m_shaders.fs != nullptr) stageInfo.addStage(VK_SHADER_STAGE_FRAGMENT_BIT, m_fsLibrary->getModuleIdentifier(), &scState.scInfo); } else { - stageInfo.addStage(VK_SHADER_STAGE_VERTEX_BIT, getShaderCode(m_shaders.vs, state), &scState.scInfo); + stageInfo.addStage(VK_SHADER_STAGE_VERTEX_BIT, getShaderCode(m_shaders.vs, shState.vsInfo), &scState.scInfo); if (m_shaders.tcs != nullptr) - stageInfo.addStage(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, getShaderCode(m_shaders.tcs, state), &scState.scInfo); + stageInfo.addStage(VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT, getShaderCode(m_shaders.tcs, shState.tcsInfo), &scState.scInfo); if (m_shaders.tes != nullptr) - stageInfo.addStage(VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, getShaderCode(m_shaders.tes, state), &scState.scInfo); + stageInfo.addStage(VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT, getShaderCode(m_shaders.tes, shState.tesInfo), &scState.scInfo); if (m_shaders.gs != nullptr) - stageInfo.addStage(VK_SHADER_STAGE_GEOMETRY_BIT, getShaderCode(m_shaders.gs, state), &scState.scInfo); + stageInfo.addStage(VK_SHADER_STAGE_GEOMETRY_BIT, getShaderCode(m_shaders.gs, shState.gsInfo), &scState.scInfo); if (m_shaders.fs != nullptr) - stageInfo.addStage(VK_SHADER_STAGE_FRAGMENT_BIT, getShaderCode(m_shaders.fs, state), &scState.scInfo); + stageInfo.addStage(VK_SHADER_STAGE_FRAGMENT_BIT, getShaderCode(m_shaders.fs, shState.fsInfo), &scState.scInfo); } VkPipelineDynamicStateCreateInfo dyInfo = { VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO }; @@ -1053,82 +1161,11 @@ namespace dxvk { SpirvCodeBuffer DxvkGraphicsPipeline::getShaderCode( const Rc& shader, - const DxvkGraphicsPipelineStateInfo& state) const { - auto vk = m_device->vkd(); - - const DxvkShaderCreateInfo& shaderInfo = shader->info(); - DxvkShaderModuleCreateInfo info; - - // Fix up fragment shader outputs for dual-source blending - if (shaderInfo.stage == VK_SHADER_STAGE_FRAGMENT_BIT) { - info.fsDualSrcBlend = state.useDualSourceBlending(); - - for (uint32_t i = 0; i < MaxNumRenderTargets; i++) { - if (writesRenderTarget(state, i)) - info.rtSwizzles[i] = state.omSwizzle[i].mapping(); - } - } - - // Deal with undefined shader inputs - uint32_t consumedInputs = shaderInfo.inputMask; - uint32_t providedInputs = 0; - - if (shaderInfo.stage == VK_SHADER_STAGE_VERTEX_BIT) { - for (uint32_t i = 0; i < state.il.attributeCount(); i++) - providedInputs |= 1u << state.ilAttributes[i].location(); - } else if (shaderInfo.stage != VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) { - auto prevStage = getPrevStageShader(shaderInfo.stage); - providedInputs = prevStage->info().outputMask; - } else { - // Technically not correct, but this - // would need a lot of extra care - providedInputs = consumedInputs; - } - - info.undefinedInputs = (providedInputs & consumedInputs) ^ consumedInputs; + const DxvkShaderModuleCreateInfo& info) const { return shader->getCode(m_bindings, info); } - Rc DxvkGraphicsPipeline::getPrevStageShader(VkShaderStageFlagBits stage) const { - if (stage == VK_SHADER_STAGE_VERTEX_BIT) - return nullptr; - - if (stage == VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT) - return m_shaders.tcs; - - Rc result = m_shaders.vs; - - if (stage == VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT) - return result; - - if (m_shaders.tes != nullptr) - result = m_shaders.tes; - - if (stage == VK_SHADER_STAGE_GEOMETRY_BIT) - return result; - - if (m_shaders.gs != nullptr) - result = m_shaders.gs; - - return result; - } - - - bool DxvkGraphicsPipeline::writesRenderTarget( - const DxvkGraphicsPipelineStateInfo& state, - uint32_t target) const { - if (!(m_fsOut & (1u << target))) - return false; - - if (!state.omBlend[target].colorWriteMask()) - return false; - - VkFormat rtFormat = state.rt.getColorFormat(target); - return rtFormat != VK_FORMAT_UNDEFINED; - } - - uint32_t DxvkGraphicsPipeline::computeSpecConstantMask() const { uint32_t mask = m_shaders.vs->getSpecConstantMask(); diff --git a/src/dxvk/dxvk_graphics.h b/src/dxvk/dxvk_graphics.h index 614633c8..11f033b3 100644 --- a/src/dxvk/dxvk_graphics.h +++ b/src/dxvk/dxvk_graphics.h @@ -19,6 +19,8 @@ namespace dxvk { class DxvkStateCache; class DxvkPipelineManager; class DxvkPipelineWorkers; + + struct DxvkGraphicsPipelineShaders; struct DxvkPipelineStats; /** @@ -187,6 +189,42 @@ namespace dxvk { }; + /** + * \brief Shader create info state for graphics pipelines + * + * Can only be used when all pipeline state is known. + */ + struct DxvkGraphicsPipelineShaderState { + DxvkGraphicsPipelineShaderState(); + + DxvkGraphicsPipelineShaderState( + const DxvkGraphicsPipelineShaders& shaders, + const DxvkGraphicsPipelineStateInfo& state); + + DxvkShaderModuleCreateInfo vsInfo; + DxvkShaderModuleCreateInfo tcsInfo; + DxvkShaderModuleCreateInfo tesInfo; + DxvkShaderModuleCreateInfo gsInfo; + DxvkShaderModuleCreateInfo fsInfo; + + bool eq(const DxvkGraphicsPipelineShaderState& other) const; + + size_t hash() const; + + private: + + DxvkShaderModuleCreateInfo getCreateInfo( + const DxvkGraphicsPipelineShaders& shaders, + const Rc& shader, + const DxvkGraphicsPipelineStateInfo& state); + + Rc getPrevStageShader( + const DxvkGraphicsPipelineShaders& shaders, + const VkShaderStageFlagBits stage); + + }; + + /** * \brief Specialization constant state for pipelines * @@ -475,15 +513,8 @@ namespace dxvk { SpirvCodeBuffer getShaderCode( const Rc& shader, - const DxvkGraphicsPipelineStateInfo& state) const; + const DxvkShaderModuleCreateInfo& info) const; - Rc getPrevStageShader( - VkShaderStageFlagBits stage) const; - - bool writesRenderTarget( - const DxvkGraphicsPipelineStateInfo& state, - uint32_t target) const; - uint32_t computeSpecConstantMask() const; bool validatePipelineState( diff --git a/src/dxvk/dxvk_graphics_state.h b/src/dxvk/dxvk_graphics_state.h index 133e0d68..49f081a3 100644 --- a/src/dxvk/dxvk_graphics_state.h +++ b/src/dxvk/dxvk_graphics_state.h @@ -769,6 +769,16 @@ namespace dxvk { util::isDualSourceBlendFactor(omBlend[0].dstAlphaBlendFactor())); } + bool writesRenderTarget( + uint32_t target) const { + if (!omBlend[target].colorWriteMask()) + return false; + + VkFormat rtFormat = rt.getColorFormat(target); + return rtFormat != VK_FORMAT_UNDEFINED; + } + + DxvkIaInfo ia; DxvkIlInfo il; DxvkRsInfo rs;