From e74411704277009169a31f0bc34951b9f67be9c2 Mon Sep 17 00:00:00 2001 From: Philip Rebohle Date: Fri, 16 Nov 2018 20:00:28 +0100 Subject: [PATCH] [dxvk] Patch fragment shader for dual-source blending --- src/dxvk/dxvk_compute.cpp | 5 ++++- src/dxvk/dxvk_graphics.cpp | 29 ++++++++++++++++++++++------- src/dxvk/dxvk_graphics.h | 1 + src/dxvk/dxvk_shader.cpp | 29 +++++++++++++++++++++++------ src/dxvk/dxvk_shader.h | 15 ++++++++++++++- src/dxvk/dxvk_util.cpp | 8 ++++++++ src/dxvk/dxvk_util.h | 3 +++ 7 files changed, 75 insertions(+), 15 deletions(-) diff --git a/src/dxvk/dxvk_compute.cpp b/src/dxvk/dxvk_compute.cpp index fdc2a3cf7..69eec5c4b 100644 --- a/src/dxvk/dxvk_compute.cpp +++ b/src/dxvk/dxvk_compute.cpp @@ -36,7 +36,10 @@ namespace dxvk { slotMapping.bindingInfos(), VK_PIPELINE_BIND_POINT_COMPUTE); - m_cs = cs->createShaderModule(m_vkd, slotMapping); + DxvkShaderModuleCreateInfo moduleInfo; + moduleInfo.fsDualSrcBlend = false; + + m_cs = cs->createShaderModule(m_vkd, slotMapping, moduleInfo); } diff --git a/src/dxvk/dxvk_graphics.cpp b/src/dxvk/dxvk_graphics.cpp index 9dee8cf4a..0e30bd13b 100644 --- a/src/dxvk/dxvk_graphics.cpp +++ b/src/dxvk/dxvk_graphics.cpp @@ -61,11 +61,18 @@ namespace dxvk { slotMapping.bindingInfos(), VK_PIPELINE_BIND_POINT_GRAPHICS); - if (vs != nullptr) m_vs = vs ->createShaderModule(m_vkd, slotMapping); - if (tcs != nullptr) m_tcs = tcs->createShaderModule(m_vkd, slotMapping); - if (tes != nullptr) m_tes = tes->createShaderModule(m_vkd, slotMapping); - if (gs != nullptr) m_gs = gs ->createShaderModule(m_vkd, slotMapping); - if (fs != nullptr) m_fs = fs ->createShaderModule(m_vkd, slotMapping); + DxvkShaderModuleCreateInfo moduleInfo; + moduleInfo.fsDualSrcBlend = true; + + DxvkShaderModuleCreateInfo moduleInfoDualSrc; + moduleInfoDualSrc.fsDualSrcBlend = true; + + if (vs != nullptr) m_vs = vs ->createShaderModule(m_vkd, slotMapping, moduleInfo); + if (tcs != nullptr) m_tcs = tcs->createShaderModule(m_vkd, slotMapping, moduleInfo); + if (tes != nullptr) m_tes = tes->createShaderModule(m_vkd, slotMapping, moduleInfo); + if (gs != nullptr) m_gs = gs ->createShaderModule(m_vkd, slotMapping, moduleInfo); + if (fs != nullptr) m_fs = fs ->createShaderModule(m_vkd, slotMapping, moduleInfo); + if (fs != nullptr) m_fs2 = fs ->createShaderModule(m_vkd, slotMapping, moduleInfoDualSrc); m_vsIn = vs != nullptr ? vs->interfaceSlots().inputSlots : 0; m_fsOut = fs != nullptr ? fs->interfaceSlots().outputSlots : 0; @@ -200,12 +207,20 @@ namespace dxvk { specInfo.pData = &specData; std::vector stages; - + + bool useDualSrcBlend = state.omBlendAttachments[0].blendEnable && ( + util::isDualSourceBlendFactor(state.omBlendAttachments[0].srcColorBlendFactor) || + util::isDualSourceBlendFactor(state.omBlendAttachments[0].dstColorBlendFactor) || + util::isDualSourceBlendFactor(state.omBlendAttachments[0].srcAlphaBlendFactor) || + util::isDualSourceBlendFactor(state.omBlendAttachments[0].dstAlphaBlendFactor)); + + Rc fs = useDualSrcBlend ? m_fs2 : m_fs; + if (m_vs != nullptr) stages.push_back(m_vs->stageInfo(&specInfo)); if (m_tcs != nullptr) stages.push_back(m_tcs->stageInfo(&specInfo)); if (m_tes != nullptr) stages.push_back(m_tes->stageInfo(&specInfo)); if (m_gs != nullptr) stages.push_back(m_gs->stageInfo(&specInfo)); - if (m_fs != nullptr) stages.push_back(m_fs->stageInfo(&specInfo)); + if (fs != nullptr) stages.push_back(fs->stageInfo(&specInfo)); // Fix up color write masks using the component mappings std::array omBlendAttachments; diff --git a/src/dxvk/dxvk_graphics.h b/src/dxvk/dxvk_graphics.h index f0d7d9a55..96e5c0423 100644 --- a/src/dxvk/dxvk_graphics.h +++ b/src/dxvk/dxvk_graphics.h @@ -229,6 +229,7 @@ namespace dxvk { Rc m_tes; Rc m_gs; Rc m_fs; + Rc m_fs2; uint32_t m_vsIn = 0; uint32_t m_fsOut = 0; diff --git a/src/dxvk/dxvk_shader.cpp b/src/dxvk/dxvk_shader.cpp index ff22cc31f..21af222c1 100644 --- a/src/dxvk/dxvk_shader.cpp +++ b/src/dxvk/dxvk_shader.cpp @@ -91,11 +91,22 @@ namespace dxvk { // Gather the offsets where the binding IDs // are stored so we can quickly remap them. + uint32_t o1VarId = 0; + for (auto ins : m_code) { - if (ins.opCode() == spv::OpDecorate - && ((ins.arg(2) == spv::DecorationBinding) - || (ins.arg(2) == spv::DecorationSpecId))) - m_idOffsets.push_back(ins.offset() + 3); + if (ins.opCode() == spv::OpDecorate) { + if (ins.arg(2) == spv::DecorationBinding + || ins.arg(2) == spv::DecorationSpecId) + m_idOffsets.push_back(ins.offset() + 3); + + if (ins.arg(2) == spv::DecorationLocation && ins.arg(3) == 1) { + m_o1LocOffset = ins.offset() + 3; + o1VarId = ins.arg(1); + } + + if (ins.arg(2) == spv::DecorationIndex && ins.arg(1) == o1VarId) + m_o1IdxOffset = ins.offset() + 3; + } } } @@ -128,15 +139,21 @@ namespace dxvk { Rc DxvkShader::createShaderModule( const Rc& vkd, - const DxvkDescriptorSlotMapping& mapping) { + const DxvkDescriptorSlotMapping& mapping, + const DxvkShaderModuleCreateInfo& info) { SpirvCodeBuffer spirvCode = m_code; + uint32_t* code = spirvCode.data(); // Remap resource binding IDs - uint32_t* code = spirvCode.data(); for (uint32_t ofs : m_idOffsets) { if (code[ofs] < MaxNumResourceSlots) code[ofs] = mapping.getBindingId(code[ofs]); } + + // For dual-source blending we need to re-map + // location 1, index 0 to location 0, index 1 + if (info.fsDualSrcBlend && m_o1IdxOffset && m_o1LocOffset) + std::swap(code[m_o1IdxOffset], code[m_o1LocOffset]); return new DxvkShaderModule(vkd, this, spirvCode); } diff --git a/src/dxvk/dxvk_shader.h b/src/dxvk/dxvk_shader.h index 7f6620a86..de9bb6557 100644 --- a/src/dxvk/dxvk_shader.h +++ b/src/dxvk/dxvk_shader.h @@ -101,6 +101,14 @@ namespace dxvk { uint32_t* m_data = nullptr; }; + + + /** + * \brief Shader module create info + */ + struct DxvkShaderModuleCreateInfo { + bool fsDualSrcBlend; + }; /** @@ -162,11 +170,13 @@ namespace dxvk { * Maps the binding slot numbers * \param [in] vkd Vulkan device functions * \param [in] mapping Resource slot mapping + * \param [in] info Module create info * \returns The shader module */ Rc createShaderModule( const Rc& vkd, - const DxvkDescriptorSlotMapping& mapping); + const DxvkDescriptorSlotMapping& mapping, + const DxvkShaderModuleCreateInfo& info); /** * \brief Inter-stage interface slots @@ -242,6 +252,9 @@ namespace dxvk { DxvkShaderOptions m_options; DxvkShaderConstData m_constData; DxvkShaderKey m_key; + + size_t m_o1IdxOffset = 0; + size_t m_o1LocOffset = 0; }; diff --git a/src/dxvk/dxvk_util.cpp b/src/dxvk/dxvk_util.cpp index 603e9c942..a8782b1fb 100644 --- a/src/dxvk/dxvk_util.cpp +++ b/src/dxvk/dxvk_util.cpp @@ -149,4 +149,12 @@ namespace dxvk::util { } } + + bool isDualSourceBlendFactor(VkBlendFactor factor) { + return factor == VK_BLEND_FACTOR_SRC1_COLOR + || factor == VK_BLEND_FACTOR_SRC1_ALPHA + || factor == VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR + || factor == VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA; + } + } diff --git a/src/dxvk/dxvk_util.h b/src/dxvk/dxvk_util.h index b736fb255..73af2829b 100644 --- a/src/dxvk/dxvk_util.h +++ b/src/dxvk/dxvk_util.h @@ -212,4 +212,7 @@ namespace dxvk::util { VkComponentSwizzle component, uint32_t identity); + bool isDualSourceBlendFactor( + VkBlendFactor factor); + }