GS: Make factors part of blend state

Instead of using the blend map indices.
This commit is contained in:
Connor McLaughlin 2022-03-20 17:28:18 +10:00 committed by refractionpcsx2
parent 19d310475b
commit 6b32e00097
10 changed files with 195 additions and 276 deletions

View File

@ -498,18 +498,9 @@ GSAdapter::GSAdapter(const DXGI_ADAPTER_DESC1& desc_dxgi)
// TODO // TODO
#endif #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 // clang-format off
const std::array<u16, 16> GSDevice::m_replaceDualSrcBlendMap = const std::array<u8, 16> GSDevice::m_replaceDualSrcBlendMap =
{{ {{
SRC_COLOR, // SRC_COLOR SRC_COLOR, // SRC_COLOR
INV_SRC_COLOR, // INV_SRC_COLOR INV_SRC_COLOR, // INV_SRC_COLOR
@ -529,7 +520,7 @@ const std::array<u16, 16> GSDevice::m_replaceDualSrcBlendMap =
CONST_ZERO // CONST_ZERO CONST_ZERO // CONST_ZERO
}}; }};
const std::array<HWBlend, 3*3*3*3 + 1> GSDevice::m_blendMap = const std::array<HWBlend, 3*3*3*3> GSDevice::m_blendMap =
{{ {{
{ BLEND_NO_REC , OP_ADD , CONST_ONE , CONST_ZERO} , // 0000: (Cs - Cs)*As + Cs ==> Cs { 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 { BLEND_CD , OP_ADD , CONST_ZERO , CONST_ONE} , // 0001: (Cs - Cs)*As + Cd ==> Cd
@ -612,5 +603,4 @@ const std::array<HWBlend, 3*3*3*3 + 1> GSDevice::m_blendMap =
{ BLEND_NO_REC , OP_ADD , CONST_ONE , CONST_ZERO} , // 2220: (0 - 0)*F + Cs ==> Cs { 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_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 { 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
}}; }};

View File

@ -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_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_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_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 // Determines the HW blend function for DX11/OGL
struct HWBlend struct HWBlend
{ {
u16 flags, op, src, dst; u16 flags;
u8 op, src, dst;
}; };
struct alignas(16) GSHWDrawConfig struct alignas(16) GSHWDrawConfig
@ -483,25 +485,25 @@ struct alignas(16) GSHWDrawConfig
{ {
struct struct
{ {
u8 index; u8 enable : 1;
u8 factor; u8 constant_enable : 1;
bool is_constant : 1; u8 op : 6;
bool is_accumulation : 1; u8 src_factor;
bool is_mixed_hw_sw : 1; u8 dst_factor;
bool replace_dual_src: 1; u8 constant;
}; };
u32 key; u32 key;
}; };
BlendState(): key(0) {} 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) : key(0)
{ {
this->index = index; enable = enable_;
this->factor = factor; constant_enable = constant_enable_;
this->is_constant = is_constant; src_factor = src_factor_;
this->is_accumulation = is_accumulation; dst_factor = dst_factor_;
this->is_mixed_hw_sw = is_mixed_hw_sw; op = op_;
this->replace_dual_src = replace_dual_src; constant = constant_;
} }
}; };
enum class DestinationAlphaMode : u8 enum class DestinationAlphaMode : u8
@ -563,6 +565,7 @@ struct alignas(16) GSHWDrawConfig
class GSDevice : public GSAlignedClass<32> class GSDevice : public GSAlignedClass<32>
{ {
public: public:
// clang-format off
struct FeatureSupport struct FeatureSupport
{ {
bool broken_point_sampler : 1; ///< Issue with AMD cards, see tfx shader for details bool broken_point_sampler : 1; ///< Issue with AMD cards, see tfx shader for details
@ -582,28 +585,30 @@ public:
memset(this, 0, sizeof(*this)); memset(this, 0, sizeof(*this));
} }
}; };
// clang-format on
private: // clang-format off
FastList<GSTexture*> m_pool; enum : u8
static const std::array<HWBlend, 3*3*3*3 + 1> m_blendMap;
static const std::array<u16, 16> m_replaceDualSrcBlendMap;
protected:
enum : u16
{ {
// HW blend factors // HW blend factors
SRC_COLOR, INV_SRC_COLOR, DST_COLOR, INV_DST_COLOR, SRC_COLOR, INV_SRC_COLOR, DST_COLOR, INV_DST_COLOR,
SRC1_COLOR, INV_SRC1_COLOR, SRC_ALPHA, INV_SRC_ALPHA, SRC1_COLOR, INV_SRC1_COLOR, SRC_ALPHA, INV_SRC_ALPHA,
DST_ALPHA, INV_DST_ALPHA, SRC1_ALPHA, INV_SRC1_ALPHA, DST_ALPHA, INV_DST_ALPHA, SRC1_ALPHA, INV_SRC1_ALPHA,
CONST_COLOR, INV_CONST_COLOR, CONST_ONE, CONST_ZERO, CONST_COLOR, INV_CONST_COLOR, CONST_ONE, CONST_ZERO,
};
enum : u8
{
// HW blend operations // HW blend operations
OP_ADD, OP_SUBTRACT, OP_REV_SUBTRACT OP_ADD, OP_SUBTRACT, OP_REV_SUBTRACT
}; };
// clang-format on
static const int m_NO_BLEND = 0; private:
static const int m_MERGE_BLEND = m_blendMap.size() - 1; FastList<GSTexture*> m_pool;
static const std::array<HWBlend, 3*3*3*3> m_blendMap;
static const std::array<u8, 16> m_replaceDualSrcBlendMap;
protected:
static constexpr u32 MAX_POOLED_TEXTURES = 300; static constexpr u32 MAX_POOLED_TEXTURES = 300;
HostDisplay* m_display; HostDisplay* m_display;
@ -632,7 +637,6 @@ protected:
virtual void DoFXAA(GSTexture* sTex, GSTexture* dTex) {} virtual void DoFXAA(GSTexture* sTex, GSTexture* dTex) {}
virtual void DoShadeBoost(GSTexture* sTex, GSTexture* dTex) {} virtual void DoShadeBoost(GSTexture* sTex, GSTexture* dTex) {}
virtual void DoExternalFX(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: public:
GSDevice(); GSDevice();
@ -641,12 +645,6 @@ public:
__fi HostDisplay* GetDisplay() const { return m_display; } __fi HostDisplay* GetDisplay() const { return m_display; }
__fi unsigned int GetFrameNumber() const { return m_frame; } __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); void Recycle(GSTexture* t);
enum enum
@ -737,11 +735,34 @@ public:
virtual void PrintMemoryUsage(); 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. // 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); __ri static HWBlend GetBlend(u32 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; } 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 struct GSAdapter

View File

@ -1251,10 +1251,14 @@ static GSDevice11::OMBlendSelector convertSel(GSHWDrawConfig::ColorMaskSelector
{ {
GSDevice11::OMBlendSelector out; GSDevice11::OMBlendSelector out;
out.wrgba = cm.wrgba; out.wrgba = cm.wrgba;
out.abe = blend.index != 0; if (blend.enable)
out.blend_index = blend.index; {
out.accu_blend = blend.is_accumulation; out.blend_enable = true;
out.blend_mix = blend.is_mixed_hw_sw; out.blend_src_factor = blend.src_factor;
out.blend_dst_factor = blend.dst_factor;
out.blend_op = blend.op;
}
return out; return out;
} }
@ -1348,7 +1352,7 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
PSSetShaderResource(0, rt_copy); 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); SetupVS(config.vs, &config.cb_vs);
SetupGS(config.gs); SetupGS(config.gs);
SetupPS(config.ps, &config.cb_ps, config.sampler); 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); 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(); DrawIndexedPrimitive();
} }
@ -1388,30 +1392,3 @@ void GSDevice11::RenderHW(GSHWDrawConfig& config)
Recycle(hdr_rt); 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;
}
}

View File

@ -51,10 +51,10 @@ public:
u32 wb : 1; u32 wb : 1;
u32 wa : 1; u32 wa : 1;
// Alpha blending // Alpha blending
u32 blend_index : 7; u32 blend_enable : 1;
u32 abe : 1; u32 blend_op : 2;
u32 accu_blend : 1; u32 blend_src_factor : 4;
u32 blend_mix : 1; u32 blend_dst_factor : 4;
}; };
struct struct
@ -66,7 +66,7 @@ public:
u32 key; u32 key;
}; };
operator u32() { return key & 0x3fff; } operator u32() { return key & 0x7fff; }
OMBlendSelector() OMBlendSelector()
: key(0) : key(0)
@ -127,8 +127,6 @@ private:
void DoShadeBoost(GSTexture* sTex, GSTexture* dTex) final; void DoShadeBoost(GSTexture* sTex, GSTexture* dTex) final;
void DoExternalFX(GSTexture* sTex, GSTexture* dTex) final; void DoExternalFX(GSTexture* sTex, GSTexture* dTex) final;
u16 ConvertBlendEnum(u16 generic) final;
wil::com_ptr_nothrow<ID3D11Device> m_dev; wil::com_ptr_nothrow<ID3D11Device> m_dev;
wil::com_ptr_nothrow<ID3D11DeviceContext> m_ctx; wil::com_ptr_nothrow<ID3D11DeviceContext> m_ctx;
wil::com_ptr_nothrow<IDXGISwapChain1> m_swapchain; wil::com_ptr_nothrow<IDXGISwapChain1> m_swapchain;

View File

@ -280,6 +280,18 @@ void GSDevice11::ClearSamplerCache()
m_ps_ss.clear(); m_ps_ss.clear();
} }
// clang-format off
static constexpr std::array<D3D11_BLEND, 16> 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<D3D11_BLEND_OP, 3> 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) void GSDevice11::SetupOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, u8 afix)
{ {
auto i = std::as_const(m_om_dss).find(dssel.key); 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)); 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].BlendEnable = TRUE;
bd.RenderTarget[0].BlendOp = (D3D11_BLEND_OP)blend.op; bd.RenderTarget[0].BlendOp = s_d3d11_blend_ops[bsel.blend_op];
bd.RenderTarget[0].SrcBlend = (D3D11_BLEND)blend.src; bd.RenderTarget[0].SrcBlend = s_d3d11_blend_factors[bsel.blend_src_factor];
bd.RenderTarget[0].DestBlend = (D3D11_BLEND)blend.dst; bd.RenderTarget[0].DestBlend = s_d3d11_blend_factors[bsel.blend_dst_factor];
bd.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; bd.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
bd.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; bd.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
bd.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO; 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; if (bsel.wr) bd.RenderTarget[0].RenderTargetWriteMask |= D3D11_COLOR_WRITE_ENABLE_RED;

View File

@ -599,7 +599,7 @@ void GSRendererNew::EmulateBlending(bool& DATE_PRIMID, bool& DATE_BARRIER, bool&
blend_ad_alpha_masked = false; 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); 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 // Re set alpha, it was modified, must be done after index calculation
if (blend_ad_alpha_masked) if (blend_ad_alpha_masked)
@ -732,34 +732,29 @@ void GSRendererNew::EmulateBlending(bool& DATE_PRIMID, bool& DATE_BARRIER, bool&
} }
bool replace_dual_src = false; 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 we don't have an alpha channel, we don't need a second pass, just output the alpha blend
if (GSDevice::IsDualSourceBlendFactor(unconverted_blend.dst) || // in the single colour's alpha chnanel, and blend with it
GSDevice::IsDualSourceBlendFactor(unconverted_blend.src)) 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 GL_INS("Outputting alpha blend in col0 because of no alpha write");
// in the single colour's alpha chnanel, and blend with it m_conf.ps.no_ablend = true;
if (!m_conf.colormask.wa) replace_dual_src = true;
{ }
GL_INS("Outputting alpha blend in col0 because of no alpha write"); else if (features.framebuffer_fetch || m_conf.require_one_barrier || m_conf.require_full_barrier)
m_conf.ps.no_ablend = true; {
replace_dual_src = true; // prefer single pass sw blend (if barrier) or framebuffer fetch over dual pass alpha when supported
} sw_blending = true;
else if (features.framebuffer_fetch || m_conf.require_one_barrier || m_conf.require_full_barrier) color_dest_blend = false;
{ accumulation_blend &= !features.framebuffer_fetch;
// prefer single pass sw blend (if barrier) or framebuffer fetch over dual pass alpha when supported blend_mix = false;
sw_blending = true; }
color_dest_blend = false; else
accumulation_blend &= !features.framebuffer_fetch; {
blend_mix = false; // split the draw into two
} blending_alpha_pass = true;
else replace_dual_src = true;
{
// split the draw into two
blending_alpha_pass = true;
replace_dual_src = true;
}
} }
} }
else if (features.framebuffer_fetch) 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. // Blend output will be Cd, disable hw/sw blending.
m_conf.blend = {}; m_conf.blend = {};
m_conf.ps.no_color1 = true;
sw_blending = false; // DATE_PRIMID sw_blending = false; // DATE_PRIMID
// Output is Cd, set rgb write to 0. // 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) if (m_conf.ps.blend_c == 2)
m_conf.cb_ps.TA_MaxDepth_Af.a = static_cast<float>(ALPHA.FIX) / 128.0f; m_conf.cb_ps.TA_MaxDepth_Af.a = static_cast<float>(ALPHA.FIX) / 128.0f;
const HWBlend blend = GSDevice::GetBlend(blend_index, replace_dual_src);
if (accumulation_blend) if (accumulation_blend)
{ {
// Keep HW blending to do the addition/subtraction // 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) if (m_conf.ps.blend_a == 2)
{ {
// The blend unit does a reverse subtraction so it means // 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) 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; 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) if (blend_mix1)
{ {
m_conf.ps.blend_a = 0; m_conf.ps.blend_a = 0;
@ -938,6 +939,7 @@ void GSRendererNew::EmulateBlending(bool& DATE_PRIMID, bool& DATE_BARRIER, bool&
{ {
// Disable HW blending // Disable HW blending
m_conf.blend = {}; m_conf.blend = {};
m_conf.ps.no_color1 = true;
replace_dual_src = false; replace_dual_src = false;
blending_alpha_pass = 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) 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 // 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 const HWBlend blend(GSDevice::GetBlend(blend_index + 3, replace_dual_src)); // +3 <=> +1 on C
m_conf.blend = {hacked_blend_index, 128, true, false, false, replace_dual_src}; m_conf.blend = {true, blend.src, blend.dst, blend.op, true, 128};
} }
else 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 // 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 // Before emulateblending, dither will be used
m_conf.ps.dither = GSConfig.Dithering > 0 && m_conf.ps.dfmt == 2 && m_env.DTHE.DTHE; 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 // Blend
bool blending_alpha_pass = false; bool blending_alpha_pass = false;
if (!IsOpaque() && rt) if (!IsOpaque() && rt && m_conf.colormask.wrgba != 0)
{ {
EmulateBlending(DATE_PRIMID, DATE_BARRIER, blending_alpha_pass); 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; 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) if (m_conf.ps.scanmsk & 2)
DATE_PRIMID = false; // to have discard in the shader work correctly 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 // DATE setup, no DATE_BARRIER please
if (!DATE) if (!DATE)

View File

@ -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) 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) 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.wb = blue;
cms.wa = alpha; 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); ASSERT(sTex);
@ -1263,7 +1263,7 @@ void GSDeviceOGL::StretchRect(GSTexture* sTex, const GSVector4& sRect, GSTexture
else else
OMSetDepthStencilState(m_convert.dss); OMSetDepthStencilState(m_convert.dss);
OMSetBlendState((u8)bs); OMSetBlendState(alpha_blend, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_FUNC_ADD);
OMSetColorMaskState(cms); OMSetColorMaskState(cms);
// ************************************ // ************************************
@ -1379,12 +1379,12 @@ void GSDeviceOGL::DoMerge(GSTexture* sTex[3], GSVector4* sRect, GSTexture* dTex,
// Blend with a constant alpha // Blend with a constant alpha
m_merge_obj.ps[1].Bind(); m_merge_obj.ps[1].Bind();
m_merge_obj.ps[1].Uniform4fv(0, c.v); 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 else
{ {
// Blend with 2 * input alpha // 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) if (!GLState::blend)
{ {
@ -1697,35 +1697,24 @@ void GSDeviceOGL::OMSetBlendState(u8 blend_index, u8 blend_factor, bool is_blend
glEnable(GL_BLEND); glEnable(GL_BLEND);
} }
if (is_blend_constant && GLState::bf != blend_factor) if (is_constant && GLState::bf != constant)
{ {
GLState::bf = blend_factor; GLState::bf = constant;
const float bf = (float)blend_factor / 128.0f; const float bf = (float)constant / 128.0f;
glBlendColor(bf, bf, bf, bf); glBlendColor(bf, bf, bf, bf);
} }
HWBlend b = GetBlend(blend_index, replace_dual_src); if (GLState::eq_RGB != op)
if (accumulation_blend)
{ {
b.src = GL_ONE; GLState::eq_RGB = op;
b.dst = GL_ONE; glBlendEquationSeparate(op, GL_FUNC_ADD);
}
else if (blend_mix)
{
b.src = GL_ONE;
} }
if (GLState::eq_RGB != b.op) if (GLState::f_sRGB != src_factor || GLState::f_dRGB != dst_factor)
{ {
GLState::eq_RGB = b.op; GLState::f_sRGB = src_factor;
glBlendEquationSeparate(b.op, GL_FUNC_ADD); GLState::f_dRGB = dst_factor;
} glBlendFuncSeparate(src_factor, dst_factor, GL_ONE, GL_ZERO);
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);
} }
} }
else else
@ -1829,6 +1818,18 @@ static GSDeviceOGL::VSSelector convertSel(const GSHWDrawConfig::VSSelector sel)
return out; return out;
} }
// clang-format off
static constexpr std::array<GLenum, 16> 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<GLenum, 3> s_gl_blend_ops = { {
GL_FUNC_ADD, GL_FUNC_SUBTRACT, GL_FUNC_REVERSE_SUBTRACT
} };
// clang-format on
void GSDeviceOGL::RenderHW(GSHWDrawConfig& config) void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
{ {
if (!GLState::scissor.eq(config.scissor)) if (!GLState::scissor.eq(config.scissor))
@ -1900,7 +1901,9 @@ void GSDeviceOGL::RenderHW(GSHWDrawConfig& config)
PSSetShaderResource(2, config.rt); PSSetShaderResource(2, config.rt);
SetupSampler(config.sampler); 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); OMSetColorMaskState(config.colormask);
SetupOM(config.depth); SetupOM(config.depth);
@ -2174,33 +2177,6 @@ void GSDeviceOGL::DebugOutputToFile(GLenum gl_source, GLenum gl_type, GLuint id,
#endif #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, ...) void GSDeviceOGL::PushDebugGroup(const char* fmt, ...)
{ {
#ifdef ENABLE_OGL_DEBUG #ifdef ENABLE_OGL_DEBUG

View File

@ -310,8 +310,6 @@ private:
void OMAttachDs(GSTextureOGL* ds = NULL); void OMAttachDs(GSTextureOGL* ds = NULL);
void OMSetFBO(GLuint fbo); void OMSetFBO(GLuint fbo);
u16 ConvertBlendEnum(u16 generic) final;
void DrawStretchRect(const GSVector4& sRect, const GSVector4& dRect, const GSVector2i& ds); void DrawStretchRect(const GSVector4& sRect, const GSVector4& dRect, const GSVector2i& ds);
public: 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, 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, 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, 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 RenderHW(GSHWDrawConfig& config) final;
void SendHWDraw(const GSHWDrawConfig& config); void SendHWDraw(const GSHWDrawConfig& config);
@ -372,7 +370,7 @@ public:
void ClearSamplerCache() final; void ClearSamplerCache() final;
void OMSetDepthStencilState(GSDepthStencilOGL* dss); 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 OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVector4i* scissor = NULL);
void OMSetColorMaskState(OMColorMaskSelector sel = OMColorMaskSelector()); void OMSetColorMaskState(OMColorMaskSelector sel = OMColorMaskSelector());

View File

@ -922,54 +922,6 @@ void GSDeviceVK::OMSetRenderTargets(GSTexture* rt, GSTexture* ds, const GSVector
SetScissor(scissor); 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) VkSampler GSDeviceVK::GetSampler(GSHWDrawConfig::SamplerSelector ss)
{ {
const auto it = m_samplers.find(ss.key); const auto it = m_samplers.find(ss.key);
@ -1847,12 +1799,10 @@ VkPipeline GSDeviceVK::CreateTFXPipeline(const PipelineSelector& p)
if ((p.cms.wrgba & 0x7) == 0) if ((p.cms.wrgba & 0x7) == 0)
{ {
// disable blending when colours are masked // 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 vs = GetTFXVertexShader(p.vs);
VkShaderModule gs = p.gs.expand ? GetTFXGeometryShader(p.gs) : VK_NULL_HANDLE; VkShaderModule gs = p.gs.expand ? GetTFXGeometryShader(p.gs) : VK_NULL_HANDLE;
VkShaderModule fs = GetTFXFragmentShader(pps); 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, 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); 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); // clang-format off
#ifdef PCSX2_DEVBUILD static constexpr std::array<VkBlendFactor, 16> vk_blend_factors = { {
pxAssertRel(m_features.dual_source_blend || pbs.is_accumulation || VK_BLEND_FACTOR_SRC_COLOR, VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR, VK_BLEND_FACTOR_DST_COLOR, VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR,
(blend.src != VK_BLEND_FACTOR_SRC1_ALPHA && blend.src != VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA && VK_BLEND_FACTOR_SRC1_COLOR, VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR, VK_BLEND_FACTOR_SRC_ALPHA, VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
blend.dst != VK_BLEND_FACTOR_SRC1_ALPHA && blend.dst != VK_BLEND_FACTOR_ONE_MINUS_SRC1_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,
"Not using dual source factors"); VK_BLEND_FACTOR_CONSTANT_COLOR, VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR, VK_BLEND_FACTOR_ONE, VK_BLEND_FACTOR_ZERO
#endif }};
static constexpr std::array<VkBlendOp, 3> vk_blend_ops = {{
VK_BLEND_OP_ADD, VK_BLEND_OP_SUBTRACT, VK_BLEND_OP_REVERSE_SUBTRACT
}};
// clang-format on
gpb.SetBlendAttachment(0, true, gpb.SetBlendAttachment(0, true, vk_blend_factors[pbs.src_factor], vk_blend_factors[pbs.dst_factor],
(pbs.is_accumulation || pbs.is_mixed_hw_sw) ? VK_BLEND_FACTOR_ONE : static_cast<VkBlendFactor>(blend.src), vk_blend_ops[pbs.op], VK_BLEND_FACTOR_ONE, VK_BLEND_FACTOR_ZERO, VK_BLEND_OP_ADD, p.cms.wrgba);
pbs.is_accumulation ? VK_BLEND_FACTOR_ONE : static_cast<VkBlendFactor>(blend.dst),
static_cast<VkBlendOp>(blend.op), VK_BLEND_FACTOR_ONE, VK_BLEND_FACTOR_ZERO, VK_BLEND_OP_ADD, p.cms.wrgba);
} }
else else
{ {
@ -2718,8 +2670,8 @@ void GSDeviceVK::RenderHW(GSHWDrawConfig& config)
} }
if (config.pal) if (config.pal)
PSSetShaderResource(1, config.pal, true); PSSetShaderResource(1, config.pal, true);
if (config.blend.is_constant) if (config.blend.constant_enable)
SetBlendConstants(config.blend.factor); SetBlendConstants(config.blend.constant);
// Primitive ID tracking DATE setup. // Primitive ID tracking DATE setup.
GSTextureVK* date_image = nullptr; 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.ps.key_lo = config.ps.key_lo;
m_pipeline_selector.dss.key = config.depth.key; m_pipeline_selector.dss.key = config.depth.key;
m_pipeline_selector.bs.key = config.blend.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.cms.key = config.colormask.key;
m_pipeline_selector.topology = static_cast<u32>(config.topology); m_pipeline_selector.topology = static_cast<u32>(config.topology);
m_pipeline_selector.rt = config.rt != nullptr; m_pipeline_selector.rt = config.rt != nullptr;

View File

@ -152,7 +152,8 @@ private:
const GSRegEXTBUF& EXTBUF, const GSVector4& c) final; const GSRegEXTBUF& EXTBUF, const GSVector4& c) final;
void DoInterlace(GSTexture* sTex, GSTexture* dTex, int shader, bool linear, float yoffset = 0) 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); VkSampler GetSampler(GSHWDrawConfig::SamplerSelector ss);
void ClearSamplerCache() final; void ClearSamplerCache() final;