mirror of https://github.com/PCSX2/pcsx2.git
gsdx-ogl: blend management cleanup
* reorder the blend function * remove OM bsel object * add a bit to support pabe (miss the glsl part)
This commit is contained in:
parent
4d12410707
commit
5b57405517
|
@ -353,7 +353,6 @@ bool GSDeviceOGL::Create(GSWnd* wnd)
|
||||||
ASSERT(sizeof(PSSamplerSelector) == 4);
|
ASSERT(sizeof(PSSamplerSelector) == 4);
|
||||||
ASSERT(sizeof(OMDepthStencilSelector) == 4);
|
ASSERT(sizeof(OMDepthStencilSelector) == 4);
|
||||||
ASSERT(sizeof(OMColorMaskSelector) == 4);
|
ASSERT(sizeof(OMColorMaskSelector) == 4);
|
||||||
ASSERT(sizeof(OMBlendSelector) == 4);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -663,6 +662,7 @@ GLuint GSDeviceOGL::CompilePS(PSSelector sel)
|
||||||
+ format("#define PS_WRITE_RG %d\n", sel.write_rg)
|
+ format("#define PS_WRITE_RG %d\n", sel.write_rg)
|
||||||
+ format("#define PS_FBMASK %d\n", sel.fbmask)
|
+ format("#define PS_FBMASK %d\n", sel.fbmask)
|
||||||
+ format("#define PS_HDR %d\n", sel.hdr)
|
+ format("#define PS_HDR %d\n", sel.hdr)
|
||||||
|
+ format("#define PS_PABE %d\n", sel.pabe);
|
||||||
;
|
;
|
||||||
|
|
||||||
return m_shader->Compile("tfx.glsl", "ps_main", GL_FRAGMENT_SHADER, tfx_fs_all_glsl, macro);
|
return m_shader->Compile("tfx.glsl", "ps_main", GL_FRAGMENT_SHADER, tfx_fs_all_glsl, macro);
|
||||||
|
|
|
@ -285,6 +285,7 @@ class GSDeviceOGL : public GSDevice
|
||||||
uint32 blend_c:2;
|
uint32 blend_c:2;
|
||||||
uint32 blend_d:2;
|
uint32 blend_d:2;
|
||||||
uint32 clr1:1; // useful?
|
uint32 clr1:1; // useful?
|
||||||
|
uint32 pabe:1;
|
||||||
uint32 hdr:1;
|
uint32 hdr:1;
|
||||||
uint32 colclip:1;
|
uint32 colclip:1;
|
||||||
|
|
||||||
|
@ -292,7 +293,7 @@ class GSDeviceOGL : public GSDevice
|
||||||
uint32 tcoffsethack:1;
|
uint32 tcoffsethack:1;
|
||||||
//uint32 point_sampler:1; Not tested, so keep the bit for blend
|
//uint32 point_sampler:1; Not tested, so keep the bit for blend
|
||||||
|
|
||||||
uint32 _free2:20;
|
uint32 _free2:19;
|
||||||
};
|
};
|
||||||
|
|
||||||
uint64 key;
|
uint64 key;
|
||||||
|
@ -378,42 +379,6 @@ class GSDeviceOGL : public GSDevice
|
||||||
OMColorMaskSelector(uint32 c) { wrgba = c; }
|
OMColorMaskSelector(uint32 c) { wrgba = c; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct OMBlendSelector
|
|
||||||
{
|
|
||||||
union
|
|
||||||
{
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
uint32 abe:1;
|
|
||||||
uint32 a:2;
|
|
||||||
uint32 b:2;
|
|
||||||
uint32 c:2;
|
|
||||||
uint32 d:2;
|
|
||||||
|
|
||||||
uint32 _free:23;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
|
||||||
uint32 _abe:1;
|
|
||||||
uint32 abcd:8;
|
|
||||||
|
|
||||||
uint32 _free2:23;
|
|
||||||
};
|
|
||||||
|
|
||||||
uint32 key;
|
|
||||||
};
|
|
||||||
|
|
||||||
operator uint32() {return key;}
|
|
||||||
|
|
||||||
OMBlendSelector() : key(0) {}
|
|
||||||
|
|
||||||
bool IsCLR1() const
|
|
||||||
{
|
|
||||||
return (key & 0x19f) == 0x93; // abe == 1 && a == 1 && b == 2 && d == 1
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct D3D9Blend {int bogus, op, src, dst;};
|
struct D3D9Blend {int bogus, op, src, dst;};
|
||||||
static const D3D9Blend m_blendMapD3D9[3*3*3*3 + 1];
|
static const D3D9Blend m_blendMapD3D9[3*3*3*3 + 1];
|
||||||
static const int m_NO_BLEND;
|
static const int m_NO_BLEND;
|
||||||
|
|
|
@ -303,91 +303,74 @@ bool GSRendererOGL::EmulateTextureShuffleAndFbmask(GSDeviceOGL::PSSelector& ps_s
|
||||||
|
|
||||||
bool GSRendererOGL::EmulateBlending(GSDeviceOGL::PSSelector& ps_sel, bool DATE_GL42)
|
bool GSRendererOGL::EmulateBlending(GSDeviceOGL::PSSelector& ps_sel, bool DATE_GL42)
|
||||||
{
|
{
|
||||||
|
GSDeviceOGL* dev = (GSDeviceOGL*)m_dev;
|
||||||
const GIFRegALPHA& ALPHA = m_context->ALPHA;
|
const GIFRegALPHA& ALPHA = m_context->ALPHA;
|
||||||
bool require_barrier = false;
|
bool require_barrier = false;
|
||||||
GSDeviceOGL* dev = (GSDeviceOGL*)m_dev;
|
bool sw_blending = false;
|
||||||
float afix = (float)m_context->ALPHA.FIX / 0x80;
|
float afix = (float)m_context->ALPHA.FIX / 0x80;
|
||||||
GSDeviceOGL::OMBlendSelector om_bsel;
|
|
||||||
|
|
||||||
om_bsel.abe = PRIM->ABE || PRIM->AA1 && m_vt.m_primclass == GS_LINE_CLASS;
|
// No blending so early exit
|
||||||
|
if (!(PRIM->ABE || PRIM->AA1 && m_vt.m_primclass == GS_LINE_CLASS)) {
|
||||||
om_bsel.a = ALPHA.A;
|
#ifdef ENABLE_OGL_DEBUG
|
||||||
om_bsel.b = ALPHA.B;
|
if (m_env.PABE.PABE) {
|
||||||
om_bsel.c = ALPHA.C;
|
GL_INS("!!! ENV PABE without ABE !!!");
|
||||||
om_bsel.d = ALPHA.D;
|
}
|
||||||
|
#endif
|
||||||
|
dev->OMSetBlendState();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (m_env.PABE.PABE)
|
if (m_env.PABE.PABE)
|
||||||
{
|
{
|
||||||
GL_INS("!!! ENV PABE not supported !!!");
|
GL_INS("!!! ENV PABE not supported !!!");
|
||||||
// FIXME it could be supported with SW blending!
|
if (m_sw_blending >= ACC_BLEND_CCLIP_DALPHA) {
|
||||||
if (om_bsel.a == 0 && om_bsel.b == 1 && om_bsel.c == 0 && om_bsel.d == 1)
|
ps_sel.pabe = 1;
|
||||||
{
|
require_barrier |= (ALPHA.C == 1);
|
||||||
// this works because with PABE alpha blending is on when alpha >= 0x80, but since the pixel shader
|
sw_blending = true;
|
||||||
// cannot output anything over 0x80 (== 1.0) blending with 0x80 or turning it off gives the same result
|
|
||||||
om_bsel.abe = 0;
|
|
||||||
}
|
}
|
||||||
else
|
//Breath of Fire Dragon Quarter triggers this in battles. Graphics are fine though.
|
||||||
{
|
//ASSERT(0);
|
||||||
//Breath of Fire Dragon Quarter triggers this in battles. Graphics are fine though.
|
|
||||||
//ASSERT(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// No blending so early exit
|
|
||||||
if (!om_bsel.abe) {
|
|
||||||
dev->OMSetBlendState();
|
|
||||||
return require_barrier;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute the blending equation to detect special case
|
// Compute the blending equation to detect special case
|
||||||
int blend_sel = ((om_bsel.a * 3 + om_bsel.b) * 3 + om_bsel.c) * 3 + om_bsel.d;
|
int blend_index = ((ALPHA.A * 3 + ALPHA.B) * 3 + ALPHA.C) * 3 + ALPHA.D;
|
||||||
int blend_flag = GSDeviceOGL::m_blendMapD3D9[blend_sel].bogus;
|
int blend_flag = GSDeviceOGL::m_blendMapD3D9[blend_index].bogus;
|
||||||
|
|
||||||
// SW Blend is (nearly) free. Let's use it.
|
// SW Blend is (nearly) free. Let's use it.
|
||||||
bool free_blend = (blend_flag & BLEND_NO_BAR) || (m_prim_overlap == PRIM_OVERLAP_NO);
|
bool impossible_or_free_blend = (blend_flag & (BLEND_NO_BAR|BLEND_A_MAX|BLEND_ACCU))
|
||||||
// We really need SW blending for this one, barely used
|
|| (m_prim_overlap == PRIM_OVERLAP_NO);
|
||||||
bool impossible_blend = (blend_flag & BLEND_A_MAX);
|
|
||||||
// Do the multiplication in shader for blending accumulation: Cs*As + Cd or Cs*Af + Cd
|
// Do the multiplication in shader for blending accumulation: Cs*As + Cd or Cs*Af + Cd
|
||||||
bool accumulation_blend = (blend_flag & BLEND_ACCU);
|
bool accumulation_blend = (blend_flag & BLEND_ACCU);
|
||||||
|
|
||||||
bool sw_blending_base = m_sw_blending && (free_blend || impossible_blend);
|
// Warning no break on purpose
|
||||||
|
switch (m_sw_blending) {
|
||||||
|
case ACC_BLEND_ULTRA: sw_blending |= true;
|
||||||
|
case ACC_BLEND_FULL: sw_blending |= !( (ALPHA.A == ALPHA.B) || (ALPHA.C == 2 && ALPHA.FIX <= 128u) );
|
||||||
|
case ACC_BLEND_CCLIP_DALPHA: sw_blending |= (ALPHA.C == 1) || (m_env.COLCLAMP.CLAMP == 0);
|
||||||
|
case ACC_BLEND_SPRITE: sw_blending |= m_vt.m_primclass == GS_SPRITE_CLASS;
|
||||||
|
case ACC_BLEND_FREE: sw_blending |= ps_sel.fbmask || impossible_or_free_blend;
|
||||||
|
default: sw_blending |= accumulation_blend;
|
||||||
|
}
|
||||||
|
// SW Blending
|
||||||
|
// GL42 interact very badly with sw blending. GL42 uses the primitiveID to find the primitive
|
||||||
|
// that write the bad alpha value. Sw blending will force the draw to run primitive by primitive
|
||||||
|
// (therefore primitiveID will be constant to 1)
|
||||||
|
sw_blending &= !DATE_GL42;
|
||||||
|
|
||||||
// Color clip
|
// Color clip
|
||||||
if (m_env.COLCLAMP.CLAMP == 0) {
|
if (m_env.COLCLAMP.CLAMP == 0) {
|
||||||
if (accumulation_blend) {
|
if (accumulation_blend) {
|
||||||
ps_sel.hdr = 1;
|
ps_sel.hdr = 1;
|
||||||
GL_INS("COLCLIP Fast HDR mode ENABLED");
|
GL_INS("COLCLIP Fast HDR mode ENABLED");
|
||||||
} else if (m_sw_blending >= ACC_BLEND_CCLIP_DALPHA || sw_blending_base) {
|
} else if (sw_blending) {
|
||||||
ps_sel.colclip = 1;
|
ps_sel.colclip = 1;
|
||||||
sw_blending_base = true;
|
|
||||||
GL_INS("COLCLIP SW ENABLED (blending is %d/%d/%d/%d)", ALPHA.A, ALPHA.B, ALPHA.C, ALPHA.D);
|
GL_INS("COLCLIP SW ENABLED (blending is %d/%d/%d/%d)", ALPHA.A, ALPHA.B, ALPHA.C, ALPHA.D);
|
||||||
} else {
|
} else {
|
||||||
GL_INS("Sorry colclip isn't supported");
|
GL_INS("Sorry colclip isn't supported");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: Option is duplicated, one impact the blend unit / the other the shader.
|
|
||||||
sw_blending_base |= accumulation_blend;
|
|
||||||
|
|
||||||
// Warning no break on purpose
|
|
||||||
bool sw_blending_adv = false;
|
|
||||||
switch (m_sw_blending) {
|
|
||||||
case ACC_BLEND_ULTRA: sw_blending_adv |= true;
|
|
||||||
case ACC_BLEND_FULL: sw_blending_adv |= !( (ALPHA.A == ALPHA.B) || (ALPHA.C == 2 && afix <= 1.002f) );
|
|
||||||
case ACC_BLEND_CCLIP_DALPHA: sw_blending_adv |= (ALPHA.C == 1);
|
|
||||||
case ACC_BLEND_SPRITE: sw_blending_adv |= m_vt.m_primclass == GS_SPRITE_CLASS;
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool sw_blending = sw_blending_base // Free case or Impossible blend
|
|
||||||
|| sw_blending_adv // complex blending case (for special effect)
|
|
||||||
|| ps_sel.fbmask; // accurate fbmask
|
|
||||||
|
|
||||||
|
|
||||||
// SW Blending
|
|
||||||
// GL42 interact very badly with sw blending. GL42 uses the primitiveID to find the primitive
|
|
||||||
// that write the bad alpha value. Sw blending will force the draw to run primitive by primitive
|
|
||||||
// (therefore primitiveID will be constant to 1)
|
|
||||||
sw_blending &= !DATE_GL42;
|
|
||||||
// Seriously don't expect me to support this kind of crazyness.
|
// Seriously don't expect me to support this kind of crazyness.
|
||||||
// No mix of COLCLIP + accumulation_blend + DATE GL42
|
// No mix of COLCLIP + accumulation_blend + DATE GL42
|
||||||
// Neither fbmask and GL42
|
// Neither fbmask and GL42
|
||||||
|
@ -397,18 +380,17 @@ bool GSRendererOGL::EmulateBlending(GSDeviceOGL::PSSelector& ps_sel, bool DATE_G
|
||||||
// For stat to optimize accurate option
|
// For stat to optimize accurate option
|
||||||
#if 0
|
#if 0
|
||||||
GL_INS("BLEND_INFO: %d/%d/%d/%d. Clamp:%d. Prim:%d number %d (sw %d)",
|
GL_INS("BLEND_INFO: %d/%d/%d/%d. Clamp:%d. Prim:%d number %d (sw %d)",
|
||||||
om_bsel.a, om_bsel.b, om_bsel.c, om_bsel.d, m_env.COLCLAMP.CLAMP, m_vt.m_primclass, m_vertex.next, sw_blending);
|
ALPHA.A, ALPHA.B, ALPHA.C, ALPHA.D, m_env.COLCLAMP.CLAMP, m_vt.m_primclass, m_vertex.next, sw_blending);
|
||||||
#endif
|
#endif
|
||||||
if (sw_blending) {
|
if (sw_blending) {
|
||||||
ps_sel.blend_a = om_bsel.a;
|
ps_sel.blend_a = ALPHA.A;
|
||||||
ps_sel.blend_b = om_bsel.b;
|
ps_sel.blend_b = ALPHA.B;
|
||||||
ps_sel.blend_c = om_bsel.c;
|
ps_sel.blend_c = ALPHA.C;
|
||||||
ps_sel.blend_d = om_bsel.d;
|
ps_sel.blend_d = ALPHA.D;
|
||||||
|
|
||||||
if (accumulation_blend) {
|
if (accumulation_blend) {
|
||||||
// Keep HW blending to do the addition
|
// Keep HW blending to do the addition
|
||||||
dev->OMSetBlendState(blend_sel);
|
dev->OMSetBlendState(blend_index);
|
||||||
om_bsel.abe = 1;
|
|
||||||
// Remove the addition from the SW blending
|
// Remove the addition from the SW blending
|
||||||
ps_sel.blend_d = 2;
|
ps_sel.blend_d = 2;
|
||||||
} else {
|
} else {
|
||||||
|
@ -424,13 +406,13 @@ bool GSRendererOGL::EmulateBlending(GSDeviceOGL::PSSelector& ps_sel, bool DATE_G
|
||||||
// No need to flush for every primitive
|
// No need to flush for every primitive
|
||||||
require_barrier |= !(blend_flag & BLEND_NO_BAR) && !accumulation_blend;
|
require_barrier |= !(blend_flag & BLEND_NO_BAR) && !accumulation_blend;
|
||||||
} else {
|
} else {
|
||||||
ps_sel.clr1 = om_bsel.IsCLR1();
|
ps_sel.clr1 = (blend_flag & BLEND_C_CLR);
|
||||||
if (ps_sel.dfmt == 1 && ALPHA.C == 1) {
|
if (ps_sel.dfmt == 1 && ALPHA.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
|
||||||
int hacked_blend_sel = blend_sel + 3; // +3 <=> +1 on C
|
int hacked_blend_index = blend_index + 3; // +3 <=> +1 on C
|
||||||
dev->OMSetBlendState(hacked_blend_sel, 1.0f, true);
|
dev->OMSetBlendState(hacked_blend_index, 1.0f, true);
|
||||||
} else {
|
} else {
|
||||||
dev->OMSetBlendState(blend_sel, afix, (ALPHA.C == 2));
|
dev->OMSetBlendState(blend_index, afix, (ALPHA.C == 2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue