diff --git a/src/d3d11/d3d11_blend.cpp b/src/d3d11/d3d11_blend.cpp index da24ad1d7..ac1e149ce 100644 --- a/src/d3d11/d3d11_blend.cpp +++ b/src/d3d11/d3d11_blend.cpp @@ -182,6 +182,8 @@ namespace dxvk { DecodeBlendFactor(BlendDesc.DestBlendAlpha, true), DecodeBlendOp(BlendDesc.BlendOpAlpha)); mode.setWriteMask(BlendDesc.RenderTargetWriteMask); + + mode.normalize(); return mode; } diff --git a/src/d3d9/d3d9_device.cpp b/src/d3d9/d3d9_device.cpp index 87d9a5209..3f331640f 100644 --- a/src/d3d9/d3d9_device.cpp +++ b/src/d3d9/d3d9_device.cpp @@ -6880,6 +6880,8 @@ namespace dxvk { NormalizeFactor(mode.alphaDstFactor()), mode.alphaBlendOp()); } + mode.normalize(); + ctx->setBlendMode(i, mode); } }); diff --git a/src/dxvk/dxvk_constant_state.cpp b/src/dxvk/dxvk_constant_state.cpp index e32442fd2..5159cb22b 100644 --- a/src/dxvk/dxvk_constant_state.cpp +++ b/src/dxvk/dxvk_constant_state.cpp @@ -65,4 +65,56 @@ namespace dxvk { } } + + void DxvkBlendMode::normalize() { + constexpr VkColorComponentFlags colorMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT; + constexpr VkColorComponentFlags alphaMask = VK_COLOR_COMPONENT_A_BIT; + + VkColorComponentFlags newWriteMask = writeMask(); + + if (!newWriteMask) + setBlendEnable(false); + + if (blendEnable()) { + // If alpha or color are effectively not modified given the blend + // function, set the corresponding part of the write mask to 0. + if (colorBlendOp() == VK_BLEND_OP_ADD + && colorSrcFactor() == VK_BLEND_FACTOR_ZERO + && colorDstFactor() == VK_BLEND_FACTOR_ONE) + newWriteMask &= ~colorMask; + + if (alphaBlendOp() == VK_BLEND_OP_ADD + && alphaSrcFactor() == VK_BLEND_FACTOR_ZERO + && alphaDstFactor() == VK_BLEND_FACTOR_ONE) + newWriteMask &= ~alphaMask; + + // Check whether blending is equivalent to passing through + // the source data as if blending was disabled. + bool needsBlending = false; + + if (newWriteMask & colorMask) { + needsBlending |= colorSrcFactor() != VK_BLEND_FACTOR_ONE + || colorDstFactor() != VK_BLEND_FACTOR_ZERO + || colorBlendOp() != VK_BLEND_OP_ADD; + } + + if (newWriteMask & alphaMask) { + needsBlending |= alphaSrcFactor() != VK_BLEND_FACTOR_ONE + || alphaDstFactor() != VK_BLEND_FACTOR_ZERO + || alphaBlendOp() != VK_BLEND_OP_ADD; + } + + if (!needsBlending) + setBlendEnable(false); + } + + if (!blendEnable() || !(newWriteMask & colorMask)) + setColorOp(VK_BLEND_FACTOR_ZERO, VK_BLEND_FACTOR_ZERO, VK_BLEND_OP_ADD); + + if (!blendEnable() || !(newWriteMask & alphaMask)) + setAlphaOp(VK_BLEND_FACTOR_ZERO, VK_BLEND_FACTOR_ZERO, VK_BLEND_OP_ADD); + + setWriteMask(newWriteMask); + } + } diff --git a/src/dxvk/dxvk_constant_state.h b/src/dxvk/dxvk_constant_state.h index 59872c069..9469f655b 100644 --- a/src/dxvk/dxvk_constant_state.h +++ b/src/dxvk/dxvk_constant_state.h @@ -400,6 +400,8 @@ namespace dxvk { m_writeMask = writeMask; } + void normalize(); + private: uint32_t m_enableBlending : 1;