From b644f85f514767c1c0297c9d8ba7dd491af392e9 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Wed, 27 Mar 2024 16:05:59 +1000 Subject: [PATCH] GSDevice: Add separate RGB/A blend factors --- pcsx2/GS/Renderers/Common/GSDevice.cpp | 5 +++ pcsx2/GS/Renderers/Common/GSDevice.h | 25 ++++++----- pcsx2/GS/Renderers/DX11/GSDevice11.cpp | 52 +++++++---------------- pcsx2/GS/Renderers/DX11/GSDevice11.h | 44 ++++++------------- pcsx2/GS/Renderers/DX12/GSDevice12.cpp | 5 ++- pcsx2/GS/Renderers/Metal/GSDeviceMTL.h | 14 +++--- pcsx2/GS/Renderers/Metal/GSDeviceMTL.mm | 8 ++-- pcsx2/GS/Renderers/OpenGL/GLState.cpp | 4 ++ pcsx2/GS/Renderers/OpenGL/GLState.h | 2 + pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp | 11 +++-- pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.h | 3 +- pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp | 5 ++- 12 files changed, 83 insertions(+), 95 deletions(-) diff --git a/pcsx2/GS/Renderers/Common/GSDevice.cpp b/pcsx2/GS/Renderers/Common/GSDevice.cpp index 6a0b4a6745..cf5e92a842 100644 --- a/pcsx2/GS/Renderers/Common/GSDevice.cpp +++ b/pcsx2/GS/Renderers/Common/GSDevice.cpp @@ -858,6 +858,11 @@ void GSDevice::CAS(GSTexture*& tex, GSVector4i& src_rect, GSVector4& src_uv, con src_uv = GSVector4(0.0f, 0.0f, 1.0f, 1.0f); } +bool GSHWDrawConfig::BlendState::IsEffective(ColorMaskSelector colormask) const +{ + return enable && ((colormask.key & 7u) || src_factor_alpha != GSDevice::CONST_ZERO || dst_factor_alpha != GSDevice::CONST_ONE); +} + // clang-format off const std::array GSDevice::m_blendMap = diff --git a/pcsx2/GS/Renderers/Common/GSDevice.h b/pcsx2/GS/Renderers/Common/GSDevice.h index 413bfea0ea..aa5ed1d57d 100644 --- a/pcsx2/GS/Renderers/Common/GSDevice.h +++ b/pcsx2/GS/Renderers/Common/GSDevice.h @@ -487,9 +487,9 @@ struct alignas(16) GSHWDrawConfig }; u8 key; }; - DepthStencilSelector(): key(0) {} - DepthStencilSelector(u8 k): key(k) {} - static DepthStencilSelector NoDepth() + constexpr DepthStencilSelector(): key(0) {} + constexpr DepthStencilSelector(u8 k): key(k) {} + static constexpr DepthStencilSelector NoDepth() { DepthStencilSelector out; out.ztst = ZTST_ALWAYS; @@ -515,8 +515,8 @@ struct alignas(16) GSHWDrawConfig }; u8 key; }; - ColorMaskSelector(): key(0xF) {} - ColorMaskSelector(u8 c): key(0) { wrgba = c; } + constexpr ColorMaskSelector(): key(0xF) {} + constexpr ColorMaskSelector(u8 c): key(0) { wrgba = c; } }; #pragma pack(pop) struct alignas(16) VSConstantBuffer @@ -616,14 +616,14 @@ struct alignas(16) GSHWDrawConfig u8 op : 6; u8 src_factor : 4; u8 dst_factor : 4; - u8 src_alpha_factor : 4; - u8 dst_alpha_factor : 4; + u8 src_factor_alpha : 4; + u8 dst_factor_alpha : 4; u8 constant; }; u32 key; }; - BlendState(): key(0) {} - BlendState(bool enable_, u8 src_factor_, u8 dst_factor_, u8 op_, + constexpr BlendState(): key(0) {} + constexpr BlendState(bool enable_, u8 src_factor_, u8 dst_factor_, u8 op_, u8 src_alpha_factor_, u8 dst_alpha_factor_, bool constant_enable_, u8 constant_) : key(0) { @@ -632,10 +632,13 @@ struct alignas(16) GSHWDrawConfig src_factor = src_factor_; dst_factor = dst_factor_; op = op_; - src_alpha_factor = src_alpha_factor_; - dst_alpha_factor = dst_alpha_factor_; + src_factor_alpha = src_alpha_factor_; + dst_factor_alpha = dst_alpha_factor_; constant = constant_; } + + // Blending has no effect if RGB is masked. + bool IsEffective(ColorMaskSelector colormask) const; }; enum class DestinationAlphaMode : u8 { diff --git a/pcsx2/GS/Renderers/DX11/GSDevice11.cpp b/pcsx2/GS/Renderers/DX11/GSDevice11.cpp index 71f285659e..1f56b716d7 100644 --- a/pcsx2/GS/Renderers/DX11/GSDevice11.cpp +++ b/pcsx2/GS/Renderers/DX11/GSDevice11.cpp @@ -1830,7 +1830,7 @@ void GSDevice11::SetupOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, u8 OMSetDepthStencilState(i->second.get(), 1); - auto j = std::as_const(m_om_bs).find(bsel); + auto j = std::as_const(m_om_bs).find(bsel.key); if (j == m_om_bs.end()) { @@ -1838,7 +1838,7 @@ void GSDevice11::SetupOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, u8 memset(&bd, 0, sizeof(bd)); - if (bsel.blend_enable && (bsel.wrgba & 0x7)) + if (bsel.blend.IsEffective(bsel.colormask)) { // clang-format off static constexpr std::array s_d3d11_blend_factors = { { @@ -1853,27 +1853,27 @@ void GSDevice11::SetupOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, u8 // clang-format on bd.RenderTarget[0].BlendEnable = TRUE; - bd.RenderTarget[0].BlendOp = s_d3d11_blend_ops[bsel.blend_op]; - bd.RenderTarget[0].SrcBlend = s_d3d11_blend_factors[bsel.blend_src_factor]; - bd.RenderTarget[0].DestBlend = s_d3d11_blend_factors[bsel.blend_dst_factor]; + bd.RenderTarget[0].BlendOp = s_d3d11_blend_ops[bsel.blend.op]; + bd.RenderTarget[0].SrcBlend = s_d3d11_blend_factors[bsel.blend.src_factor]; + bd.RenderTarget[0].DestBlend = s_d3d11_blend_factors[bsel.blend.dst_factor]; bd.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; - bd.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; - bd.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO; + bd.RenderTarget[0].SrcBlendAlpha = s_d3d11_blend_factors[bsel.blend.src_factor_alpha]; + bd.RenderTarget[0].DestBlendAlpha = s_d3d11_blend_factors[bsel.blend.dst_factor_alpha]; } - if (bsel.wr) + if (bsel.colormask.wr) bd.RenderTarget[0].RenderTargetWriteMask |= D3D11_COLOR_WRITE_ENABLE_RED; - if (bsel.wg) + if (bsel.colormask.wg) bd.RenderTarget[0].RenderTargetWriteMask |= D3D11_COLOR_WRITE_ENABLE_GREEN; - if (bsel.wb) + if (bsel.colormask.wb) bd.RenderTarget[0].RenderTargetWriteMask |= D3D11_COLOR_WRITE_ENABLE_BLUE; - if (bsel.wa) + if (bsel.colormask.wa) bd.RenderTarget[0].RenderTargetWriteMask |= D3D11_COLOR_WRITE_ENABLE_ALPHA; wil::com_ptr_nothrow bs; m_dev->CreateBlendState(&bd, bs.put()); - j = m_om_bs.try_emplace(bsel, std::move(bs)).first; + j = m_om_bs.try_emplace(bsel.key, std::move(bs)).first; } OMSetBlendState(j->second.get(), afix); @@ -2448,21 +2448,6 @@ D3D_SHADER_MACRO* GSDevice11::ShaderMacro::GetPtr() return (D3D_SHADER_MACRO*)mout.data(); } -static GSDevice11::OMBlendSelector convertSel(GSHWDrawConfig::ColorMaskSelector cm, GSHWDrawConfig::BlendState blend) -{ - GSDevice11::OMBlendSelector out; - out.wrgba = cm.wrgba; - if (blend.enable) - { - out.blend_enable = true; - out.blend_src_factor = blend.src_factor; - out.blend_dst_factor = blend.dst_factor; - out.blend_op = blend.op; - } - - return out; -} - /// Checks that we weren't sent things we declared we don't support /// Clears things we don't support that can be quietly disabled static void preprocessSel(GSDevice11::PSSelector& sel) @@ -2596,13 +2581,8 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config) { OMDepthStencilSelector dss = config.depth; dss.zwe = 0; - OMBlendSelector blend; - blend.wrgba = 0; - blend.wr = 1; - blend.blend_enable = 1; - blend.blend_src_factor = CONST_ONE; - blend.blend_dst_factor = CONST_ONE; - blend.blend_op = 3; // MIN + const OMBlendSelector blend(GSHWDrawConfig::ColorMaskSelector(1), + GSHWDrawConfig::BlendState(true, CONST_ONE, CONST_ONE, 3 /* MIN */, CONST_ONE, CONST_ZERO, false, 0)); SetupOM(dss, blend, 0); OMSetRenderTargets(primid_tex, config.ds, &config.scissor); DrawIndexedPrimitive(); @@ -2613,7 +2593,7 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config) PSSetShaderResource(3, primid_tex); } - SetupOM(config.depth, convertSel(config.colormask, config.blend), config.blend.constant); + SetupOM(config.depth, OMBlendSelector(config.colormask, config.blend), config.blend.constant); OMSetRenderTargets(hdr_rt ? hdr_rt : config.rt, config.ds, &config.scissor); DrawIndexedPrimitive(); @@ -2631,7 +2611,7 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config) SetupPS(config.alpha_second_pass.ps, nullptr, config.sampler); } - SetupOM(config.alpha_second_pass.depth, convertSel(config.alpha_second_pass.colormask, config.blend), config.blend.constant); + SetupOM(config.alpha_second_pass.depth, OMBlendSelector(config.alpha_second_pass.colormask, config.blend), config.blend.constant); DrawIndexedPrimitive(); } diff --git a/pcsx2/GS/Renderers/DX11/GSDevice11.h b/pcsx2/GS/Renderers/DX11/GSDevice11.h index 78e97c3e2a..02f766aac3 100644 --- a/pcsx2/GS/Renderers/DX11/GSDevice11.h +++ b/pcsx2/GS/Renderers/DX11/GSDevice11.h @@ -29,43 +29,25 @@ public: using PSSamplerSelector = GSHWDrawConfig::SamplerSelector; using OMDepthStencilSelector = GSHWDrawConfig::DepthStencilSelector; -#pragma pack(push, 1) - struct OMBlendSelector + union OMBlendSelector { - union + struct { - struct - { - // Color mask - u32 wr : 1; - u32 wg : 1; - u32 wb : 1; - u32 wa : 1; - // Alpha blending - u32 blend_enable : 1; - u32 blend_op : 2; - u32 blend_src_factor : 4; - u32 blend_dst_factor : 4; - }; - - struct - { - // Color mask - u32 wrgba : 4; - }; - - u32 key; + GSHWDrawConfig::ColorMaskSelector colormask; + u8 pad[3]; + GSHWDrawConfig::BlendState blend; }; + u64 key; - operator u32() { return key & 0x7fff; } - - OMBlendSelector() - : key(0) + constexpr OMBlendSelector() : key(0) {} + constexpr OMBlendSelector(GSHWDrawConfig::ColorMaskSelector colormask_, GSHWDrawConfig::BlendState blend_) { + key = 0; + colormask = colormask_; + blend = blend_; } }; - -#pragma pack(pop) + static_assert(sizeof(OMBlendSelector) == sizeof(u64)); class ShaderMacro { @@ -255,7 +237,7 @@ private: wil::com_ptr_nothrow m_ps_cb; std::unordered_map> m_ps_ss; std::unordered_map> m_om_dss; - std::unordered_map> m_om_bs; + std::unordered_map> m_om_bs; wil::com_ptr_nothrow m_rs; GSHWDrawConfig::VSConstantBuffer m_vs_cb_cache; diff --git a/pcsx2/GS/Renderers/DX12/GSDevice12.cpp b/pcsx2/GS/Renderers/DX12/GSDevice12.cpp index d98a07dfc5..dbe3ec0576 100644 --- a/pcsx2/GS/Renderers/DX12/GSDevice12.cpp +++ b/pcsx2/GS/Renderers/DX12/GSDevice12.cpp @@ -2880,7 +2880,7 @@ GSDevice12::ComPtr GSDevice12::CreateTFXPipeline(const Pipe GSHWDrawConfig::BlendState pbs{p.bs}; GSHWDrawConfig::PSSelector pps{p.ps}; - if ((p.cms.wrgba & 0x7) == 0) + if (!p.bs.IsEffective(p.cms)) { // disable blending when colours are masked pbs = {}; @@ -2966,7 +2966,8 @@ GSDevice12::ComPtr GSDevice12::CreateTFXPipeline(const Pipe // clang-format on gpb.SetBlendState(0, true, d3d_blend_factors[pbs.src_factor], d3d_blend_factors[pbs.dst_factor], - d3d_blend_ops[pbs.op], D3D12_BLEND_ONE, D3D12_BLEND_ZERO, D3D12_BLEND_OP_ADD, p.cms.wrgba); + d3d_blend_ops[pbs.op], d3d_blend_factors[pbs.src_factor_alpha], d3d_blend_factors[pbs.dst_factor_alpha], + D3D12_BLEND_OP_ADD, p.cms.wrgba); } else { diff --git a/pcsx2/GS/Renderers/Metal/GSDeviceMTL.h b/pcsx2/GS/Renderers/Metal/GSDeviceMTL.h index a34bc51a74..f99cd9b7c1 100644 --- a/pcsx2/GS/Renderers/Metal/GSDeviceMTL.h +++ b/pcsx2/GS/Renderers/Metal/GSDeviceMTL.h @@ -36,18 +36,19 @@ struct PipelineSelectorExtrasMTL u8 writemask : 4; GSDevice::BlendFactor src_factor : 4; GSDevice::BlendFactor dst_factor : 4; + GSDevice::BlendFactor src_factor_alpha : 4; + GSDevice::BlendFactor dst_factor_alpha : 4; GSDevice::BlendOp blend_op : 2; bool blend_enable : 1; bool has_depth : 1; bool has_stencil : 1; }; - u8 _key[3]; + u32 fullkey; }; - u32 fullkey() { return _key[0] | (_key[1] << 8) | (_key[2] << 16); } - PipelineSelectorExtrasMTL(): _key{} {} + PipelineSelectorExtrasMTL(): fullkey(0) {} PipelineSelectorExtrasMTL(GSHWDrawConfig::BlendState blend, GSTexture* rt, GSHWDrawConfig::ColorMaskSelector cms, bool has_depth, bool has_stencil) - : _key{} + : fullkey(0) { this->rt = rt ? rt->GetFormat() : GSTexture::Format::Invalid; MTLColorWriteMask mask = MTLColorWriteMaskNone; @@ -59,6 +60,8 @@ struct PipelineSelectorExtrasMTL this->src_factor = static_cast(blend.src_factor); this->dst_factor = static_cast(blend.dst_factor); this->blend_op = static_cast(blend.op); + this->src_factor_alpha = static_cast(blend.src_factor_alpha); + this->dst_factor_alpha = static_cast(blend.dst_factor_alpha); this->blend_enable = blend.enable; this->has_depth = has_depth; this->has_stencil = has_stencil; @@ -69,6 +72,7 @@ struct PipelineSelectorMTL GSHWDrawConfig::PSSelector ps; PipelineSelectorExtrasMTL extras; GSHWDrawConfig::VSSelector vs; + u8 pad[7]; PipelineSelectorMTL() { memset(this, 0, sizeof(*this)); @@ -95,7 +99,7 @@ struct PipelineSelectorMTL } }; -static_assert(sizeof(PipelineSelectorMTL) == 16); +static_assert(sizeof(PipelineSelectorMTL) == 24); template <> struct std::hash diff --git a/pcsx2/GS/Renderers/Metal/GSDeviceMTL.mm b/pcsx2/GS/Renderers/Metal/GSDeviceMTL.mm index ff9f555b35..252d18cce4 100644 --- a/pcsx2/GS/Renderers/Metal/GSDeviceMTL.mm +++ b/pcsx2/GS/Renderers/Metal/GSDeviceMTL.mm @@ -1749,8 +1749,6 @@ static MTLBlendOperation ConvertBlendOp(GSDevice::BlendOp generic) } } -static constexpr MTLColorWriteMask MTLColorWriteMaskRGB = MTLColorWriteMaskRed | MTLColorWriteMaskGreen | MTLColorWriteMaskBlue; - static GSMTLExpandType ConvertVSExpand(GSHWDrawConfig::VSExpand generic) { switch (generic) @@ -1874,14 +1872,16 @@ void GSDeviceMTL::MRESetHWPipelineState(GSHWDrawConfig::VSSelector vssel, GSHWDr color.destinationRGBBlendFactor = MTLBlendFactorOne; color.writeMask = MTLColorWriteMaskRed; } - else if (extras.blend_enable && (extras.writemask & MTLColorWriteMaskRGB)) + else if (blend.IsEffective(cms)) { color.blendingEnabled = YES; color.rgbBlendOperation = ConvertBlendOp(extras.blend_op); color.sourceRGBBlendFactor = ConvertBlendFactor(extras.src_factor); color.destinationRGBBlendFactor = ConvertBlendFactor(extras.dst_factor); + color.sourceAlphaBlendFactor = ConvertBlendFactor(extras.src_factor_alpha); + color.destinationAlphaBlendFactor = ConvertBlendFactor(extras.dst_factor_alpha); } - NSString* pname = [NSString stringWithFormat:@"HW Render %x.%x.%llx.%x", vssel_mtl.key, pssel.key_hi, pssel.key_lo, extras.fullkey()]; + NSString* pname = [NSString stringWithFormat:@"HW Render %x.%x.%llx.%x", vssel_mtl.key, pssel.key_hi, pssel.key_lo, extras.fullkey]; auto pipeline = MakePipeline(pdesc, vs, ps, pname); [m_current_render.encoder setRenderPipelineState:pipeline]; diff --git a/pcsx2/GS/Renderers/OpenGL/GLState.cpp b/pcsx2/GS/Renderers/OpenGL/GLState.cpp index 0851aa3ccd..ba8c4883b6 100644 --- a/pcsx2/GS/Renderers/OpenGL/GLState.cpp +++ b/pcsx2/GS/Renderers/OpenGL/GLState.cpp @@ -19,6 +19,8 @@ namespace GLState u16 eq_RGB; u16 f_sRGB; u16 f_dRGB; + u16 f_sA; + u16 f_dA; u8 bf; u8 wrgba; @@ -48,6 +50,8 @@ namespace GLState eq_RGB = GL_FUNC_ADD; f_sRGB = GL_ONE; f_dRGB = GL_ZERO; + f_sA = GL_ONE; + f_dA = GL_ZERO; bf = 0; wrgba = 0xF; diff --git a/pcsx2/GS/Renderers/OpenGL/GLState.h b/pcsx2/GS/Renderers/OpenGL/GLState.h index 7c43292fe2..6a717beffe 100644 --- a/pcsx2/GS/Renderers/OpenGL/GLState.h +++ b/pcsx2/GS/Renderers/OpenGL/GLState.h @@ -23,6 +23,8 @@ namespace GLState extern u16 eq_RGB; extern u16 f_sRGB; extern u16 f_dRGB; + extern u16 f_sA; + extern u16 f_dA; extern u8 bf; extern u8 wrgba; diff --git a/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp b/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp index 7bacd47913..32f775864f 100644 --- a/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp +++ b/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp @@ -2208,7 +2208,8 @@ void GSDeviceOGL::OMUnbindTexture(GSTextureOGL* tex) OMAttachDs(); } -void GSDeviceOGL::OMSetBlendState(bool enable, GLenum src_factor, GLenum dst_factor, GLenum op, bool is_constant, u8 constant) +void GSDeviceOGL::OMSetBlendState(bool enable, GLenum src_factor, GLenum dst_factor, GLenum op, + GLenum src_factor_alpha, GLenum dst_factor_alpha, bool is_constant, u8 constant) { if (enable) { @@ -2231,11 +2232,14 @@ void GSDeviceOGL::OMSetBlendState(bool enable, GLenum src_factor, GLenum dst_fac glBlendEquationSeparate(op, GL_FUNC_ADD); } - if (GLState::f_sRGB != src_factor || GLState::f_dRGB != dst_factor) + if (GLState::f_sRGB != src_factor || GLState::f_dRGB != dst_factor || + GLState::f_sA != src_factor_alpha || GLState::f_dA != dst_factor_alpha) { GLState::f_sRGB = src_factor; GLState::f_dRGB = dst_factor; - glBlendFuncSeparate(src_factor, dst_factor, GL_ONE, GL_ZERO); + GLState::f_sA = src_factor_alpha; + GLState::f_dA = dst_factor_alpha; + glBlendFuncSeparate(src_factor, dst_factor, src_factor_alpha, dst_factor_alpha); } } else @@ -2530,6 +2534,7 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config) OMSetBlendState(config.blend.enable, s_gl_blend_factors[config.blend.src_factor], s_gl_blend_factors[config.blend.dst_factor], s_gl_blend_ops[config.blend.op], + s_gl_blend_factors[config.blend.src_factor_alpha], s_gl_blend_factors[config.blend.dst_factor_alpha], config.blend.constant_enable, config.blend.constant); // avoid changing framebuffer just to switch from rt+depth to rt and vice versa diff --git a/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.h b/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.h index 3126107052..93ee279eee 100644 --- a/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.h +++ b/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.h @@ -343,7 +343,8 @@ public: void ClearSamplerCache() override; void OMSetDepthStencilState(GSDepthStencilOGL* dss); - void OMSetBlendState(bool enable = false, GLenum src_factor = GL_ONE, GLenum dst_factor = GL_ZERO, GLenum op = GL_FUNC_ADD, bool is_constant = false, u8 constant = 0); + void OMSetBlendState(bool enable = false, GLenum src_factor = GL_ONE, GLenum dst_factor = GL_ZERO, GLenum op = GL_FUNC_ADD, + GLenum src_factor_alpha = GL_ONE, GLenum dst_factor_alpha = GL_ZERO, bool is_constant = false, u8 constant = 0); void OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVector4i* scissor = nullptr); void OMSetColorMaskState(OMColorMaskSelector sel = OMColorMaskSelector()); void OMUnbindTexture(GSTextureOGL* tex); diff --git a/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp b/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp index e68689666d..fa68a327ae 100644 --- a/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp +++ b/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp @@ -4850,7 +4850,7 @@ VkPipeline GSDeviceVK::CreateTFXPipeline(const PipelineSelector& p) GSHWDrawConfig::BlendState pbs{p.bs}; GSHWDrawConfig::PSSelector pps{p.ps}; - if ((p.cms.wrgba & 0x7) == 0) + if (!p.bs.IsEffective(p.cms)) { // disable blending when colours are masked pbs = {}; @@ -4942,7 +4942,8 @@ VkPipeline GSDeviceVK::CreateTFXPipeline(const PipelineSelector& p) // clang-format on gpb.SetBlendAttachment(0, true, vk_blend_factors[pbs.src_factor], vk_blend_factors[pbs.dst_factor], - vk_blend_ops[pbs.op], VK_BLEND_FACTOR_ONE, VK_BLEND_FACTOR_ZERO, VK_BLEND_OP_ADD, p.cms.wrgba); + vk_blend_ops[pbs.op], vk_blend_factors[pbs.src_factor_alpha], vk_blend_factors[pbs.dst_factor_alpha], + VK_BLEND_OP_ADD, p.cms.wrgba); } else {