From 6b32e000973faaff3b4a282c8934426e346022c8 Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Sun, 20 Mar 2022 17:28:18 +1000 Subject: [PATCH] GS: Make factors part of blend state Instead of using the blend map indices. --- pcsx2/GS/Renderers/Common/GSDevice.cpp | 14 +--- pcsx2/GS/Renderers/Common/GSDevice.h | 99 ++++++++++++++--------- pcsx2/GS/Renderers/DX11/GSDevice11.cpp | 43 +++------- pcsx2/GS/Renderers/DX11/GSDevice11.h | 12 ++- pcsx2/GS/Renderers/DX11/GSTextureFX11.cpp | 29 ++++--- pcsx2/GS/Renderers/HW/GSRendererNew.cpp | 89 ++++++++++---------- pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp | 90 ++++++++------------- pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.h | 6 +- pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp | 86 +++++--------------- pcsx2/GS/Renderers/Vulkan/GSDeviceVK.h | 3 +- 10 files changed, 195 insertions(+), 276 deletions(-) diff --git a/pcsx2/GS/Renderers/Common/GSDevice.cpp b/pcsx2/GS/Renderers/Common/GSDevice.cpp index e14af5e528..237a3ef69a 100644 --- a/pcsx2/GS/Renderers/Common/GSDevice.cpp +++ b/pcsx2/GS/Renderers/Common/GSDevice.cpp @@ -498,18 +498,9 @@ GSAdapter::GSAdapter(const DXGI_ADAPTER_DESC1& desc_dxgi) // TODO #endif -HWBlend GSDevice::GetBlend(size_t index, bool replace_dual_src) -{ - HWBlend blend = m_blendMap[index]; - blend.op = ConvertBlendEnum(blend.op); - blend.src = ConvertBlendEnum(replace_dual_src ? m_replaceDualSrcBlendMap[blend.src] : blend.src); - blend.dst = ConvertBlendEnum(replace_dual_src ? m_replaceDualSrcBlendMap[blend.dst] : blend.dst); - return blend; -} - // clang-format off -const std::array GSDevice::m_replaceDualSrcBlendMap = +const std::array GSDevice::m_replaceDualSrcBlendMap = {{ SRC_COLOR, // SRC_COLOR INV_SRC_COLOR, // INV_SRC_COLOR @@ -529,7 +520,7 @@ const std::array GSDevice::m_replaceDualSrcBlendMap = CONST_ZERO // CONST_ZERO }}; -const std::array GSDevice::m_blendMap = +const std::array GSDevice::m_blendMap = {{ { BLEND_NO_REC , OP_ADD , CONST_ONE , CONST_ZERO} , // 0000: (Cs - Cs)*As + Cs ==> Cs { BLEND_CD , OP_ADD , CONST_ZERO , CONST_ONE} , // 0001: (Cs - Cs)*As + Cd ==> Cd @@ -612,5 +603,4 @@ const std::array GSDevice::m_blendMap = { BLEND_NO_REC , OP_ADD , CONST_ONE , CONST_ZERO} , // 2220: (0 - 0)*F + Cs ==> Cs { BLEND_CD , OP_ADD , CONST_ZERO , CONST_ONE} , // 2221: (0 - 0)*F + Cd ==> Cd { BLEND_NO_REC , OP_ADD , CONST_ZERO , CONST_ZERO} , // 2222: (0 - 0)*F + 0 ==> 0 - { 0 , OP_ADD , SRC_ALPHA , INV_SRC_ALPHA} , // extra for merge operation }}; diff --git a/pcsx2/GS/Renderers/Common/GSDevice.h b/pcsx2/GS/Renderers/Common/GSDevice.h index 8a944711f2..9fa33eee7d 100644 --- a/pcsx2/GS/Renderers/Common/GSDevice.h +++ b/pcsx2/GS/Renderers/Common/GSDevice.h @@ -128,12 +128,14 @@ enum HWBlendFlags BLEND_C_CLR3 = 0x800, // Multiply Cs by (255/128) to compensate for wrong Ad/255 value, should be Ad/128 BLEND_NO_REC = 0x1000, // Doesn't require sampling of the RT as a texture BLEND_ACCU = 0x2000, // Allow to use a mix of SW and HW blending to keep the best of the 2 worlds + BLEND_DSB = 0x4000, // Blend equation uses dual-source outputs (SRC_ALPHA1/INV_SRC_ALPHA1). }; // Determines the HW blend function for DX11/OGL struct HWBlend { - u16 flags, op, src, dst; + u16 flags; + u8 op, src, dst; }; struct alignas(16) GSHWDrawConfig @@ -483,25 +485,25 @@ struct alignas(16) GSHWDrawConfig { struct { - u8 index; - u8 factor; - bool is_constant : 1; - bool is_accumulation : 1; - bool is_mixed_hw_sw : 1; - bool replace_dual_src: 1; + u8 enable : 1; + u8 constant_enable : 1; + u8 op : 6; + u8 src_factor; + u8 dst_factor; + u8 constant; }; u32 key; }; BlendState(): key(0) {} - BlendState(u8 index, u8 factor, bool is_constant, bool is_accumulation, bool is_mixed_hw_sw, bool replace_dual_src) + BlendState(bool enable_, u8 src_factor_, u8 dst_factor_, u8 op_, bool constant_enable_, u8 constant_) : key(0) { - this->index = index; - this->factor = factor; - this->is_constant = is_constant; - this->is_accumulation = is_accumulation; - this->is_mixed_hw_sw = is_mixed_hw_sw; - this->replace_dual_src = replace_dual_src; + enable = enable_; + constant_enable = constant_enable_; + src_factor = src_factor_; + dst_factor = dst_factor_; + op = op_; + constant = constant_; } }; enum class DestinationAlphaMode : u8 @@ -563,6 +565,7 @@ struct alignas(16) GSHWDrawConfig class GSDevice : public GSAlignedClass<32> { public: + // clang-format off struct FeatureSupport { bool broken_point_sampler : 1; ///< Issue with AMD cards, see tfx shader for details @@ -582,28 +585,30 @@ public: memset(this, 0, sizeof(*this)); } }; + // clang-format on -private: - FastList m_pool; - static const std::array m_blendMap; - static const std::array m_replaceDualSrcBlendMap; - -protected: - enum : u16 + // clang-format off + enum : u8 { // HW blend factors - SRC_COLOR, INV_SRC_COLOR, DST_COLOR, INV_DST_COLOR, - SRC1_COLOR, INV_SRC1_COLOR, SRC_ALPHA, INV_SRC_ALPHA, - DST_ALPHA, INV_DST_ALPHA, SRC1_ALPHA, INV_SRC1_ALPHA, - CONST_COLOR, INV_CONST_COLOR, CONST_ONE, CONST_ZERO, - + SRC_COLOR, INV_SRC_COLOR, DST_COLOR, INV_DST_COLOR, + SRC1_COLOR, INV_SRC1_COLOR, SRC_ALPHA, INV_SRC_ALPHA, + DST_ALPHA, INV_DST_ALPHA, SRC1_ALPHA, INV_SRC1_ALPHA, + CONST_COLOR, INV_CONST_COLOR, CONST_ONE, CONST_ZERO, + }; + enum : u8 + { // HW blend operations OP_ADD, OP_SUBTRACT, OP_REV_SUBTRACT }; + // clang-format on - static const int m_NO_BLEND = 0; - static const int m_MERGE_BLEND = m_blendMap.size() - 1; +private: + FastList m_pool; + static const std::array m_blendMap; + static const std::array m_replaceDualSrcBlendMap; +protected: static constexpr u32 MAX_POOLED_TEXTURES = 300; HostDisplay* m_display; @@ -632,7 +637,6 @@ protected: virtual void DoFXAA(GSTexture* sTex, GSTexture* dTex) {} virtual void DoShadeBoost(GSTexture* sTex, GSTexture* dTex) {} virtual void DoExternalFX(GSTexture* sTex, GSTexture* dTex) {} - virtual u16 ConvertBlendEnum(u16 generic) = 0; // Convert blend factors/ops from the generic enum to DX11/OGl specific. public: GSDevice(); @@ -641,12 +645,6 @@ public: __fi HostDisplay* GetDisplay() const { return m_display; } __fi unsigned int GetFrameNumber() const { return m_frame; } - __fi static constexpr bool IsDualSourceBlendFactor(u16 factor) - { - return (factor == GSDevice::SRC1_ALPHA || factor == GSDevice::INV_SRC1_ALPHA - /*|| factor == GSDevice::SRC1_COLOR || factor == GSDevice::INV_SRC1_COLOR*/); // not used - } - void Recycle(GSTexture* t); enum @@ -737,11 +735,34 @@ public: virtual void PrintMemoryUsage(); - // Convert the GS blend equations to HW specific blend factors/ops + __fi static constexpr bool IsDualSourceBlendFactor(u8 factor) + { + return (factor == SRC1_ALPHA || factor == INV_SRC1_ALPHA + /*|| factor == SRC1_COLOR || factor == INV_SRC1_COLOR*/); // not used + } + __fi static constexpr bool IsConstantBlendFactor(u16 factor) + { + return (factor == CONST_COLOR || factor == INV_CONST_COLOR); + } + + // Convert the GS blend equations to HW blend factors/ops // Index is computed as ((((A * 3 + B) * 3) + C) * 3) + D. A, B, C, D taken from ALPHA register. - HWBlend GetBlend(size_t index, bool replace_dual_src); - __fi HWBlend GetUnconvertedBlend(size_t index) { return m_blendMap[index]; } - __fi u16 GetBlendFlags(size_t index) const { return m_blendMap[index].flags; } + __ri static HWBlend GetBlend(u32 index, bool replace_dual_src) + { + HWBlend ret = m_blendMap[index]; + if (replace_dual_src) + { + ret.src = m_replaceDualSrcBlendMap[ret.src]; + ret.dst = m_replaceDualSrcBlendMap[ret.dst]; + } + return ret; + } + __ri static u16 GetBlendFlags(u32 index) { return m_blendMap[index].flags; } + __fi static bool IsDualSourceBlend(u32 index) + { + return (IsDualSourceBlendFactor(m_blendMap[index].src) || + IsDualSourceBlendFactor(m_blendMap[index].dst)); + } }; struct GSAdapter diff --git a/pcsx2/GS/Renderers/DX11/GSDevice11.cpp b/pcsx2/GS/Renderers/DX11/GSDevice11.cpp index a5c16b262a..3306655d41 100644 --- a/pcsx2/GS/Renderers/DX11/GSDevice11.cpp +++ b/pcsx2/GS/Renderers/DX11/GSDevice11.cpp @@ -1251,10 +1251,14 @@ static GSDevice11::OMBlendSelector convertSel(GSHWDrawConfig::ColorMaskSelector { GSDevice11::OMBlendSelector out; out.wrgba = cm.wrgba; - out.abe = blend.index != 0; - out.blend_index = blend.index; - out.accu_blend = blend.is_accumulation; - out.blend_mix = blend.is_mixed_hw_sw; + 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; } @@ -1348,7 +1352,7 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config) PSSetShaderResource(0, rt_copy); } - SetupOM(config.depth, convertSel(config.colormask, config.blend), config.blend.factor); + SetupOM(config.depth, convertSel(config.colormask, config.blend), config.blend.constant); SetupVS(config.vs, &config.cb_vs); SetupGS(config.gs); SetupPS(config.ps, &config.cb_ps, config.sampler); @@ -1369,7 +1373,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.factor); + SetupOM(config.alpha_second_pass.depth, convertSel(config.alpha_second_pass.colormask, config.blend), config.blend.constant); DrawIndexedPrimitive(); } @@ -1388,30 +1392,3 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config) Recycle(hdr_rt); } } - -u16 GSDevice11::ConvertBlendEnum(u16 generic) -{ - switch (generic) - { - case SRC_COLOR: return D3D11_BLEND_SRC_COLOR; - case INV_SRC_COLOR: return D3D11_BLEND_INV_SRC_COLOR; - case DST_COLOR: return D3D11_BLEND_DEST_COLOR; - case INV_DST_COLOR: return D3D11_BLEND_INV_DEST_COLOR; - case SRC1_COLOR: return D3D11_BLEND_SRC1_COLOR; - case INV_SRC1_COLOR: return D3D11_BLEND_INV_SRC1_COLOR; - case SRC_ALPHA: return D3D11_BLEND_SRC_ALPHA; - case INV_SRC_ALPHA: return D3D11_BLEND_INV_SRC_ALPHA; - case DST_ALPHA: return D3D11_BLEND_DEST_ALPHA; - case INV_DST_ALPHA: return D3D11_BLEND_INV_DEST_ALPHA; - case SRC1_ALPHA: return D3D11_BLEND_SRC1_ALPHA; - case INV_SRC1_ALPHA: return D3D11_BLEND_INV_SRC1_ALPHA; - case CONST_COLOR: return D3D11_BLEND_BLEND_FACTOR; - case INV_CONST_COLOR: return D3D11_BLEND_INV_BLEND_FACTOR; - case CONST_ONE: return D3D11_BLEND_ONE; - case CONST_ZERO: return D3D11_BLEND_ZERO; - case OP_ADD: return D3D11_BLEND_OP_ADD; - case OP_SUBTRACT: return D3D11_BLEND_OP_SUBTRACT; - case OP_REV_SUBTRACT: return D3D11_BLEND_OP_REV_SUBTRACT; - default: ASSERT(0); return 0; - } -} diff --git a/pcsx2/GS/Renderers/DX11/GSDevice11.h b/pcsx2/GS/Renderers/DX11/GSDevice11.h index 97c8e5fa9f..ed024f0f6e 100644 --- a/pcsx2/GS/Renderers/DX11/GSDevice11.h +++ b/pcsx2/GS/Renderers/DX11/GSDevice11.h @@ -51,10 +51,10 @@ public: u32 wb : 1; u32 wa : 1; // Alpha blending - u32 blend_index : 7; - u32 abe : 1; - u32 accu_blend : 1; - u32 blend_mix : 1; + u32 blend_enable : 1; + u32 blend_op : 2; + u32 blend_src_factor : 4; + u32 blend_dst_factor : 4; }; struct @@ -66,7 +66,7 @@ public: u32 key; }; - operator u32() { return key & 0x3fff; } + operator u32() { return key & 0x7fff; } OMBlendSelector() : key(0) @@ -127,8 +127,6 @@ private: void DoShadeBoost(GSTexture* sTex, GSTexture* dTex) final; void DoExternalFX(GSTexture* sTex, GSTexture* dTex) final; - u16 ConvertBlendEnum(u16 generic) final; - wil::com_ptr_nothrow m_dev; wil::com_ptr_nothrow m_ctx; wil::com_ptr_nothrow m_swapchain; diff --git a/pcsx2/GS/Renderers/DX11/GSTextureFX11.cpp b/pcsx2/GS/Renderers/DX11/GSTextureFX11.cpp index 01eda0619d..30a4806f4d 100644 --- a/pcsx2/GS/Renderers/DX11/GSTextureFX11.cpp +++ b/pcsx2/GS/Renderers/DX11/GSTextureFX11.cpp @@ -280,6 +280,18 @@ void GSDevice11::ClearSamplerCache() m_ps_ss.clear(); } +// clang-format off +static constexpr std::array s_d3d11_blend_factors = { { + D3D11_BLEND_SRC_COLOR, D3D11_BLEND_INV_SRC_COLOR, D3D11_BLEND_DEST_COLOR, D3D11_BLEND_INV_DEST_COLOR, + D3D11_BLEND_SRC1_COLOR, D3D11_BLEND_INV_SRC1_COLOR, D3D11_BLEND_SRC_ALPHA, D3D11_BLEND_INV_SRC_ALPHA, + D3D11_BLEND_DEST_ALPHA, D3D11_BLEND_INV_DEST_ALPHA, D3D11_BLEND_SRC1_ALPHA, D3D11_BLEND_INV_SRC1_ALPHA, + D3D11_BLEND_BLEND_FACTOR, D3D11_BLEND_INV_BLEND_FACTOR, D3D11_BLEND_ONE, D3D11_BLEND_ZERO +} }; +static constexpr std::array s_d3d11_blend_ops = { { + D3D11_BLEND_OP_ADD, D3D11_BLEND_OP_SUBTRACT, D3D11_BLEND_OP_REV_SUBTRACT +} }; +// clang-format on + void GSDevice11::SetupOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, u8 afix) { auto i = std::as_const(m_om_dss).find(dssel.key); @@ -336,24 +348,15 @@ void GSDevice11::SetupOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, u8 memset(&bd, 0, sizeof(bd)); - if (bsel.abe) + if (bsel.blend_enable) { - const HWBlend blend = GetBlend(bsel.blend_index, false); bd.RenderTarget[0].BlendEnable = TRUE; - bd.RenderTarget[0].BlendOp = (D3D11_BLEND_OP)blend.op; - bd.RenderTarget[0].SrcBlend = (D3D11_BLEND)blend.src; - bd.RenderTarget[0].DestBlend = (D3D11_BLEND)blend.dst; + 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; - - if (bsel.accu_blend) - { - bd.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE; - bd.RenderTarget[0].DestBlend = D3D11_BLEND_ONE; - } - else if (bsel.blend_mix) - bd.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE; } if (bsel.wr) bd.RenderTarget[0].RenderTargetWriteMask |= D3D11_COLOR_WRITE_ENABLE_RED; diff --git a/pcsx2/GS/Renderers/HW/GSRendererNew.cpp b/pcsx2/GS/Renderers/HW/GSRendererNew.cpp index 71e50099d8..c9bbbe5850 100644 --- a/pcsx2/GS/Renderers/HW/GSRendererNew.cpp +++ b/pcsx2/GS/Renderers/HW/GSRendererNew.cpp @@ -599,7 +599,7 @@ void GSRendererNew::EmulateBlending(bool& DATE_PRIMID, bool& DATE_BARRIER, bool& blend_ad_alpha_masked = false; u8 blend_index = u8(((m_conf.ps.blend_a * 3 + m_conf.ps.blend_b) * 3 + m_conf.ps.blend_c) * 3 + m_conf.ps.blend_d); - const int blend_flag = g_gs_device->GetBlendFlags(blend_index); + const int blend_flag = GSDevice::GetBlendFlags(blend_index); // Re set alpha, it was modified, must be done after index calculation if (blend_ad_alpha_masked) @@ -732,34 +732,29 @@ void GSRendererNew::EmulateBlending(bool& DATE_PRIMID, bool& DATE_BARRIER, bool& } bool replace_dual_src = false; - if (!features.dual_source_blend) + if (!features.dual_source_blend && GSDevice::IsDualSourceBlend(blend_index)) { - const HWBlend unconverted_blend = g_gs_device->GetUnconvertedBlend(blend_index); - if (GSDevice::IsDualSourceBlendFactor(unconverted_blend.dst) || - GSDevice::IsDualSourceBlendFactor(unconverted_blend.src)) + // if we don't have an alpha channel, we don't need a second pass, just output the alpha blend + // in the single colour's alpha chnanel, and blend with it + if (!m_conf.colormask.wa) { - // if we don't have an alpha channel, we don't need a second pass, just output the alpha blend - // in the single colour's alpha chnanel, and blend with it - if (!m_conf.colormask.wa) - { - GL_INS("Outputting alpha blend in col0 because of no alpha write"); - m_conf.ps.no_ablend = true; - replace_dual_src = true; - } - else if (features.framebuffer_fetch || m_conf.require_one_barrier || m_conf.require_full_barrier) - { - // prefer single pass sw blend (if barrier) or framebuffer fetch over dual pass alpha when supported - sw_blending = true; - color_dest_blend = false; - accumulation_blend &= !features.framebuffer_fetch; - blend_mix = false; - } - else - { - // split the draw into two - blending_alpha_pass = true; - replace_dual_src = true; - } + GL_INS("Outputting alpha blend in col0 because of no alpha write"); + m_conf.ps.no_ablend = true; + replace_dual_src = true; + } + else if (features.framebuffer_fetch || m_conf.require_one_barrier || m_conf.require_full_barrier) + { + // prefer single pass sw blend (if barrier) or framebuffer fetch over dual pass alpha when supported + sw_blending = true; + color_dest_blend = false; + accumulation_blend &= !features.framebuffer_fetch; + blend_mix = false; + } + else + { + // split the draw into two + blending_alpha_pass = true; + replace_dual_src = true; } } else if (features.framebuffer_fetch) @@ -868,6 +863,7 @@ void GSRendererNew::EmulateBlending(bool& DATE_PRIMID, bool& DATE_BARRIER, bool& { // Blend output will be Cd, disable hw/sw blending. m_conf.blend = {}; + m_conf.ps.no_color1 = true; sw_blending = false; // DATE_PRIMID // Output is Cd, set rgb write to 0. @@ -881,10 +877,11 @@ void GSRendererNew::EmulateBlending(bool& DATE_PRIMID, bool& DATE_BARRIER, bool& if (m_conf.ps.blend_c == 2) m_conf.cb_ps.TA_MaxDepth_Af.a = static_cast(ALPHA.FIX) / 128.0f; + const HWBlend blend = GSDevice::GetBlend(blend_index, replace_dual_src); if (accumulation_blend) { // Keep HW blending to do the addition/subtraction - m_conf.blend = {blend_index, 0, false, true, false, replace_dual_src}; + m_conf.blend = {true, GSDevice::CONST_ONE, GSDevice::CONST_ONE, blend.op, false, 0}; if (m_conf.ps.blend_a == 2) { // The blend unit does a reverse subtraction so it means @@ -904,9 +901,13 @@ void GSRendererNew::EmulateBlending(bool& DATE_PRIMID, bool& DATE_BARRIER, bool& } else if (blend_mix) { - m_conf.blend = {blend_index, ALPHA.FIX, m_conf.ps.blend_c == 2, false, true, replace_dual_src}; + // For mixed blend, the source blend is done in the shader (so we use CONST_ONE as a factor). + m_conf.blend = {true, GSDevice::CONST_ONE, blend.dst, blend.op, m_conf.ps.blend_c == 2, ALPHA.FIX}; m_conf.ps.blend_mix = 1; + // Elide DSB colour output if not used by dest. + m_conf.ps.no_color1 |= !GSDevice::IsDualSourceBlendFactor(blend.dst); + if (blend_mix1) { m_conf.ps.blend_a = 0; @@ -938,6 +939,7 @@ void GSRendererNew::EmulateBlending(bool& DATE_PRIMID, bool& DATE_BARRIER, bool& { // Disable HW blending m_conf.blend = {}; + m_conf.ps.no_color1 = true; replace_dual_src = false; blending_alpha_pass = false; @@ -1005,13 +1007,18 @@ void GSRendererNew::EmulateBlending(bool& DATE_PRIMID, bool& DATE_BARRIER, bool& if (m_conf.ps.dfmt == 1 && m_conf.ps.blend_c == 1) { // 24 bits doesn't have an alpha channel so use 1.0f fix factor as equivalent - const u8 hacked_blend_index = blend_index + 3; // +3 <=> +1 on C - m_conf.blend = {hacked_blend_index, 128, true, false, false, replace_dual_src}; + const HWBlend blend(GSDevice::GetBlend(blend_index + 3, replace_dual_src)); // +3 <=> +1 on C + m_conf.blend = {true, blend.src, blend.dst, blend.op, true, 128}; } else { - m_conf.blend = {blend_index, ALPHA.FIX, m_conf.ps.blend_c == 2, false, false, replace_dual_src}; + const HWBlend blend(GSDevice::GetBlend(blend_index, replace_dual_src)); + m_conf.blend = {true, blend.src, blend.dst, blend.op, m_conf.ps.blend_c == 2, ALPHA.FIX}; } + + // Remove second color output when unused. Works around bugs in some drivers (e.g. Intel). + m_conf.ps.no_color1 |= !GSDevice::IsDualSourceBlendFactor(m_conf.blend.src_factor) && + GSDevice::IsDualSourceBlendFactor(m_conf.blend.dst_factor); } // DATE_PRIMID interact very badly with sw blending. DATE_PRIMID uses the primitiveID to find the primitive @@ -1499,10 +1506,16 @@ void GSRendererNew::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sour // Before emulateblending, dither will be used m_conf.ps.dither = GSConfig.Dithering > 0 && m_conf.ps.dfmt == 2 && m_env.DTHE.DTHE; + if (m_conf.ps.dfmt == 1) + { + // Disable writing of the alpha channel + m_conf.colormask.wa = 0; + } + // Blend bool blending_alpha_pass = false; - if (!IsOpaque() && rt) + if (!IsOpaque() && rt && m_conf.colormask.wrgba != 0) { EmulateBlending(DATE_PRIMID, DATE_BARRIER, blending_alpha_pass); } @@ -1519,19 +1532,9 @@ void GSRendererNew::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sour m_conf.require_full_barrier = false; } - // Don't emit the second color output from the pixel shader when it's - // not going to be used (no or sw blending). - m_conf.ps.no_color1 |= (m_conf.blend.index == 0); - if (m_conf.ps.scanmsk & 2) DATE_PRIMID = false; // to have discard in the shader work correctly - if (m_conf.ps.dfmt == 1) - { - // Disable writing of the alpha channel - m_conf.colormask.wa = 0; - } - // DATE setup, no DATE_BARRIER please if (!DATE) diff --git a/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp b/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp index 0c9ebccc67..1656aa1b14 100644 --- a/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp +++ b/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.cpp @@ -1202,7 +1202,7 @@ void GSDeviceOGL::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture void GSDeviceOGL::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, const GL::Program& ps, bool linear) { - StretchRect(sTex, sRect, dTex, dRect, ps, m_NO_BLEND, OMColorMaskSelector(), linear); + StretchRect(sTex, sRect, dTex, dRect, ps, false, OMColorMaskSelector(), linear); } void GSDeviceOGL::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, bool red, bool green, bool blue, bool alpha) @@ -1214,10 +1214,10 @@ void GSDeviceOGL::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture cms.wb = blue; cms.wa = alpha; - StretchRect(sTex, sRect, dTex, dRect, m_convert.ps[(int)ShaderConvert::COPY], m_NO_BLEND, cms, false); + StretchRect(sTex, sRect, dTex, dRect, m_convert.ps[(int)ShaderConvert::COPY], false, cms, false); } -void GSDeviceOGL::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, const GL::Program& ps, int bs, OMColorMaskSelector cms, bool linear) +void GSDeviceOGL::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, const GL::Program& ps, bool alpha_blend, OMColorMaskSelector cms, bool linear) { ASSERT(sTex); @@ -1263,7 +1263,7 @@ void GSDeviceOGL::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture else OMSetDepthStencilState(m_convert.dss); - OMSetBlendState((u8)bs); + OMSetBlendState(alpha_blend, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_FUNC_ADD); OMSetColorMaskState(cms); // ************************************ @@ -1379,12 +1379,12 @@ void GSDeviceOGL::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex, // Blend with a constant alpha m_merge_obj.ps[1].Bind(); m_merge_obj.ps[1].Uniform4fv(0, c.v); - StretchRect(sTex[0], sRect[0], dTex, dRect[0], m_merge_obj.ps[1], m_MERGE_BLEND, OMColorMaskSelector()); + StretchRect(sTex[0], sRect[0], dTex, dRect[0], m_merge_obj.ps[1], true, OMColorMaskSelector()); } else { // Blend with 2 * input alpha - StretchRect(sTex[0], sRect[0], dTex, dRect[0], m_merge_obj.ps[0], m_MERGE_BLEND, OMColorMaskSelector()); + StretchRect(sTex[0], sRect[0], dTex, dRect[0], m_merge_obj.ps[0], true, OMColorMaskSelector()); } } @@ -1687,9 +1687,9 @@ void GSDeviceOGL::OMSetColorMaskState(OMColorMaskSelector sel) } } -void GSDeviceOGL::OMSetBlendState(u8 blend_index, u8 blend_factor, bool is_blend_constant, bool accumulation_blend, bool blend_mix, bool replace_dual_src) +void GSDeviceOGL::OMSetBlendState(bool enable, GLenum src_factor, GLenum dst_factor, GLenum op, bool is_constant, u8 constant) { - if (blend_index) + if (enable) { if (!GLState::blend) { @@ -1697,35 +1697,24 @@ void GSDeviceOGL::OMSetBlendState(u8 blend_index, u8 blend_factor, bool is_blend glEnable(GL_BLEND); } - if (is_blend_constant && GLState::bf != blend_factor) + if (is_constant && GLState::bf != constant) { - GLState::bf = blend_factor; - const float bf = (float)blend_factor / 128.0f; + GLState::bf = constant; + const float bf = (float)constant / 128.0f; glBlendColor(bf, bf, bf, bf); } - HWBlend b = GetBlend(blend_index, replace_dual_src); - if (accumulation_blend) + if (GLState::eq_RGB != op) { - b.src = GL_ONE; - b.dst = GL_ONE; - } - else if (blend_mix) - { - b.src = GL_ONE; + GLState::eq_RGB = op; + glBlendEquationSeparate(op, GL_FUNC_ADD); } - if (GLState::eq_RGB != b.op) + if (GLState::f_sRGB != src_factor || GLState::f_dRGB != dst_factor) { - GLState::eq_RGB = b.op; - glBlendEquationSeparate(b.op, GL_FUNC_ADD); - } - - if (GLState::f_sRGB != b.src || GLState::f_dRGB != b.dst) - { - GLState::f_sRGB = b.src; - GLState::f_dRGB = b.dst; - glBlendFuncSeparate(b.src, b.dst, GL_ONE, GL_ZERO); + GLState::f_sRGB = src_factor; + GLState::f_dRGB = dst_factor; + glBlendFuncSeparate(src_factor, dst_factor, GL_ONE, GL_ZERO); } } else @@ -1829,6 +1818,18 @@ static GSDeviceOGL::VSSelector convertSel(const GSHWDrawConfig::VSSelector sel) return out; } +// clang-format off +static constexpr std::array s_gl_blend_factors = { { + GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_DST_COLOR, GL_ONE_MINUS_DST_COLOR, + GL_SRC1_COLOR, GL_ONE_MINUS_SRC1_COLOR, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, + GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA, GL_SRC1_ALPHA, GL_ONE_MINUS_SRC1_ALPHA, + GL_CONSTANT_COLOR, GL_ONE_MINUS_CONSTANT_COLOR, GL_ONE, GL_ZERO +} }; +static constexpr std::array s_gl_blend_ops = { { + GL_FUNC_ADD, GL_FUNC_SUBTRACT, GL_FUNC_REVERSE_SUBTRACT +} }; +// clang-format on + void GSDeviceOGL::RenderHW(GSHWDrawConfig& config) { if (!GLState::scissor.eq(config.scissor)) @@ -1900,7 +1901,9 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config) PSSetShaderResource(2, config.rt); SetupSampler(config.sampler); - OMSetBlendState(config.blend.index, config.blend.factor, config.blend.is_constant, config.blend.is_accumulation, config.blend.is_mixed_hw_sw, config.blend.replace_dual_src); + 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], + config.blend.constant_enable, config.blend.constant); OMSetColorMaskState(config.colormask); SetupOM(config.depth); @@ -2174,33 +2177,6 @@ void GSDeviceOGL::DebugOutputToFile(GLenum gl_source, GLenum gl_type, GLuint id, #endif } -u16 GSDeviceOGL::ConvertBlendEnum(u16 generic) -{ - switch (generic) - { - case SRC_COLOR : return GL_SRC_COLOR; - case INV_SRC_COLOR : return GL_ONE_MINUS_SRC_COLOR; - case DST_COLOR : return GL_DST_COLOR; - case INV_DST_COLOR : return GL_ONE_MINUS_DST_COLOR; - case SRC1_COLOR : return GL_SRC1_COLOR; - case INV_SRC1_COLOR : return GL_ONE_MINUS_SRC1_COLOR; - case SRC_ALPHA : return GL_SRC_ALPHA; - case INV_SRC_ALPHA : return GL_ONE_MINUS_SRC_ALPHA; - case DST_ALPHA : return GL_DST_ALPHA; - case INV_DST_ALPHA : return GL_ONE_MINUS_DST_ALPHA; - case SRC1_ALPHA : return GL_SRC1_ALPHA; - case INV_SRC1_ALPHA : return GL_ONE_MINUS_SRC1_ALPHA; - case CONST_COLOR : return GL_CONSTANT_COLOR; - case INV_CONST_COLOR : return GL_ONE_MINUS_CONSTANT_COLOR; - case CONST_ONE : return GL_ONE; - case CONST_ZERO : return GL_ZERO; - case OP_ADD : return GL_FUNC_ADD; - case OP_SUBTRACT : return GL_FUNC_SUBTRACT; - case OP_REV_SUBTRACT : return GL_FUNC_REVERSE_SUBTRACT; - default : ASSERT(0); return 0; - } -} - void GSDeviceOGL::PushDebugGroup(const char* fmt, ...) { #ifdef ENABLE_OGL_DEBUG diff --git a/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.h b/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.h index fb75d623b5..4632370e09 100644 --- a/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.h +++ b/pcsx2/GS/Renderers/OpenGL/GSDeviceOGL.h @@ -310,8 +310,6 @@ private: void OMAttachDs(GSTextureOGL* ds = NULL); void OMSetFBO(GLuint fbo); - u16 ConvertBlendEnum(u16 generic) final; - void DrawStretchRect(const GSVector4& sRect, const GSVector4& dRect, const GSVector2i& ds); public: @@ -355,7 +353,7 @@ public: void StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, ShaderConvert shader = ShaderConvert::COPY, bool linear = true) final; void StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, const GL::Program& ps, bool linear = true); void StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, bool red, bool green, bool blue, bool alpha) final; - void StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, const GL::Program& ps, int bs, OMColorMaskSelector cms, bool linear = true); + void StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture* dTex, const GSVector4& dRect, const GL::Program& ps, bool alpha_blend, OMColorMaskSelector cms, bool linear = true); void RenderHW(GSHWDrawConfig& config) final; void SendHWDraw(const GSHWDrawConfig& config); @@ -372,7 +370,7 @@ public: void ClearSamplerCache() final; void OMSetDepthStencilState(GSDepthStencilOGL* dss); - void OMSetBlendState(u8 blend_index = 0, u8 blend_factor = 0, bool is_blend_constant = false, bool accumulation_blend = false, bool blend_mix = false, bool replace_dual_src = false); + 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 OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVector4i* scissor = NULL); void OMSetColorMaskState(OMColorMaskSelector sel = OMColorMaskSelector()); diff --git a/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp b/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp index 3e5cc53e48..1b2cc9ebc9 100644 --- a/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp +++ b/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.cpp @@ -922,54 +922,6 @@ void GSDeviceVK::OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVector SetScissor(scissor); } -u16 GSDeviceVK::ConvertBlendEnum(u16 generic) -{ - switch (generic) - { - case SRC_COLOR: - return VK_BLEND_FACTOR_SRC_COLOR; - case INV_SRC_COLOR: - return VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR; - case DST_COLOR: - return VK_BLEND_FACTOR_DST_COLOR; - case INV_DST_COLOR: - return VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR; - case SRC1_COLOR: - return VK_BLEND_FACTOR_SRC1_COLOR; - case INV_SRC1_COLOR: - return VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR; - case SRC_ALPHA: - return VK_BLEND_FACTOR_SRC_ALPHA; - case INV_SRC_ALPHA: - return VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA; - case DST_ALPHA: - return VK_BLEND_FACTOR_DST_ALPHA; - case INV_DST_ALPHA: - return VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA; - case SRC1_ALPHA: - return VK_BLEND_FACTOR_SRC1_ALPHA; - case INV_SRC1_ALPHA: - return VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA; - case CONST_COLOR: - return VK_BLEND_FACTOR_CONSTANT_COLOR; - case INV_CONST_COLOR: - return VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR; - case CONST_ONE: - return VK_BLEND_FACTOR_ONE; - case CONST_ZERO: - return VK_BLEND_FACTOR_ZERO; - case OP_ADD: - return VK_BLEND_OP_ADD; - case OP_SUBTRACT: - return VK_BLEND_OP_SUBTRACT; - case OP_REV_SUBTRACT: - return VK_BLEND_OP_REVERSE_SUBTRACT; - default: - ASSERT(0); - return 0; - } -} - VkSampler GSDeviceVK::GetSampler(GSHWDrawConfig::SamplerSelector ss) { const auto it = m_samplers.find(ss.key); @@ -1847,12 +1799,10 @@ VkPipeline GSDeviceVK::CreateTFXPipeline(const PipelineSelector& p) if ((p.cms.wrgba & 0x7) == 0) { // disable blending when colours are masked - pbs.index = 0; + pbs = {}; + pps.no_color1 = true; } - // don't output alpha blend when blending is disabled - pps.no_color1 = (pbs.index == 0); - VkShaderModule vs = GetTFXVertexShader(p.vs); VkShaderModule gs = p.gs.expand ? GetTFXGeometryShader(p.gs) : VK_NULL_HANDLE; VkShaderModule fs = GetTFXFragmentShader(pps); @@ -1917,20 +1867,22 @@ VkPipeline GSDeviceVK::CreateTFXPipeline(const PipelineSelector& p) gpb.SetBlendAttachment(0, true, VK_BLEND_FACTOR_ONE, VK_BLEND_FACTOR_ZERO, VK_BLEND_OP_MIN, VK_BLEND_FACTOR_ONE, VK_BLEND_FACTOR_ZERO, VK_BLEND_OP_ADD, VK_COLOR_COMPONENT_R_BIT); } - else if (pbs.index > 0) + else if (pbs.enable) { - const HWBlend blend = GetBlend(pbs.index, pbs.replace_dual_src); -#ifdef PCSX2_DEVBUILD - pxAssertRel(m_features.dual_source_blend || pbs.is_accumulation || - (blend.src != VK_BLEND_FACTOR_SRC1_ALPHA && blend.src != VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA && - blend.dst != VK_BLEND_FACTOR_SRC1_ALPHA && blend.dst != VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA), - "Not using dual source factors"); -#endif + // clang-format off + static constexpr std::array vk_blend_factors = { { + VK_BLEND_FACTOR_SRC_COLOR, VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR, VK_BLEND_FACTOR_DST_COLOR, VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR, + VK_BLEND_FACTOR_SRC1_COLOR, VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR, VK_BLEND_FACTOR_SRC_ALPHA, VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, + VK_BLEND_FACTOR_DST_ALPHA, VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA, VK_BLEND_FACTOR_SRC1_ALPHA, VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA, + VK_BLEND_FACTOR_CONSTANT_COLOR, VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR, VK_BLEND_FACTOR_ONE, VK_BLEND_FACTOR_ZERO + }}; + static constexpr std::array vk_blend_ops = {{ + VK_BLEND_OP_ADD, VK_BLEND_OP_SUBTRACT, VK_BLEND_OP_REVERSE_SUBTRACT + }}; + // clang-format on - gpb.SetBlendAttachment(0, true, - (pbs.is_accumulation || pbs.is_mixed_hw_sw) ? VK_BLEND_FACTOR_ONE : static_cast(blend.src), - pbs.is_accumulation ? VK_BLEND_FACTOR_ONE : static_cast(blend.dst), - static_cast(blend.op), VK_BLEND_FACTOR_ONE, VK_BLEND_FACTOR_ZERO, VK_BLEND_OP_ADD, p.cms.wrgba); + 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); } else { @@ -2718,8 +2670,8 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config) } if (config.pal) PSSetShaderResource(1, config.pal, true); - if (config.blend.is_constant) - SetBlendConstants(config.blend.factor); + if (config.blend.constant_enable) + SetBlendConstants(config.blend.constant); // Primitive ID tracking DATE setup. GSTextureVK* date_image = nullptr; @@ -2995,7 +2947,7 @@ void GSDeviceVK::UpdateHWPipelineSelector(GSHWDrawConfig& config) m_pipeline_selector.ps.key_lo = config.ps.key_lo; m_pipeline_selector.dss.key = config.depth.key; m_pipeline_selector.bs.key = config.blend.key; - m_pipeline_selector.bs.factor = 0; // don't dupe states with different alpha values + m_pipeline_selector.bs.constant = 0; // don't dupe states with different alpha values m_pipeline_selector.cms.key = config.colormask.key; m_pipeline_selector.topology = static_cast(config.topology); m_pipeline_selector.rt = config.rt != nullptr; diff --git a/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.h b/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.h index d8bd20ea6d..125e8b92e9 100644 --- a/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.h +++ b/pcsx2/GS/Renderers/Vulkan/GSDeviceVK.h @@ -152,7 +152,8 @@ private: const GSRegEXTBUF& EXTBUF, const GSVector4& c) final; void DoInterlace(GSTexture* sTex, GSTexture* dTex, int shader, bool linear, float yoffset = 0) final; - u16 ConvertBlendEnum(u16 generic) final; + static VkBlendFactor ConvertBlendFactor(u8 generic); + static VkBlendOp ConvertBlendOp(u8 generic); VkSampler GetSampler(GSHWDrawConfig::SamplerSelector ss); void ClearSamplerCache() final;