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
#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<u16, 16> GSDevice::m_replaceDualSrcBlendMap =
const std::array<u8, 16> GSDevice::m_replaceDualSrcBlendMap =
{{
SRC_COLOR, // 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 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_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_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
}};

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_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<GSTexture*> m_pool;
static const std::array<HWBlend, 3*3*3*3 + 1> m_blendMap;
static const std::array<u16, 16> 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<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;
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

View File

@ -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;
}
}

View File

@ -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<ID3D11Device> m_dev;
wil::com_ptr_nothrow<ID3D11DeviceContext> m_ctx;
wil::com_ptr_nothrow<IDXGISwapChain1> m_swapchain;

View File

@ -280,6 +280,18 @@ void GSDevice11::ClearSamplerCache()
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)
{
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;

View File

@ -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<float>(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)

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)
{
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<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)
{
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

View File

@ -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());

View File

@ -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<VkBlendFactor, 16> 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<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,
(pbs.is_accumulation || pbs.is_mixed_hw_sw) ? VK_BLEND_FACTOR_ONE : static_cast<VkBlendFactor>(blend.src),
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);
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<u32>(config.topology);
m_pipeline_selector.rt = config.rt != nullptr;

View File

@ -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;