GSdx-d3d11: Partial port of EmulateBlending() from OGL renderer to DX11 renderer and ps_blend() from OGL shader to DX11 shader (only accumulation blend).

This commit is contained in:
hibye8313 2019-06-09 12:38:11 -04:00 committed by lightningterror
parent 6bdd4ff186
commit 60cf62fea1
4 changed files with 147 additions and 36 deletions

View File

@ -501,6 +501,99 @@ void GSRendererDX11::EmulateChannelShuffle(GSTexture** rt, const GSTextureCache:
} }
} }
void GSRendererDX11::EmulateBlending()
{
// Partial port of OGL SW blending. Currently only works for accumulation blend.
const GIFRegALPHA& ALPHA = m_context->ALPHA;
bool sw_blending = false;
// No blending so early exit
if (!(PRIM->ABE || (PRIM->AA1 && m_vt.m_primclass == GS_LINE_CLASS)))
return;
m_om_bsel.abe = 1;
m_om_bsel.a = ALPHA.A;
m_om_bsel.b = ALPHA.B;
m_om_bsel.c = ALPHA.C;
m_om_bsel.d = ALPHA.D;
if (m_env.PABE.PABE)
{
if (m_om_bsel.a == 0 && m_om_bsel.b == 1 && m_om_bsel.c == 0 && m_om_bsel.d == 1)
{
// this works because with PABE alpha blending is on when alpha >= 0x80, but since the pixel shader
// cannot output anything over 0x80 (== 1.0) blending with 0x80 or turning it off gives the same result
m_om_bsel.abe = 0;
}
else
{
//Breath of Fire Dragon Quarter triggers this in battles. Graphics are fine though.
//ASSERT(0);
}
}
uint8 blend_index = uint8(((ALPHA.A * 3 + ALPHA.B) * 3 + ALPHA.C) * 3 + ALPHA.D);
int blend_flag = m_dev->GetBlendFlags(blend_index);
bool accumulation_blend = !!(blend_flag & BLEND_ACCU);
switch (m_sw_blending)
{
case ACC_BLEND_HIGH_D3D11:
case ACC_BLEND_MEDIUM_D3D11:
case ACC_BLEND_BASIC_D3D11:
sw_blending |= accumulation_blend;
default: break;
}
if (m_env.COLCLAMP.CLAMP == 0)
{
if (accumulation_blend)
sw_blending = true;
m_ps_sel.hdr = 1;
}
if (sw_blending)
{
m_ps_sel.blend_a = ALPHA.A;
m_ps_sel.blend_b = ALPHA.B;
m_ps_sel.blend_c = ALPHA.C;
m_ps_sel.blend_d = ALPHA.D;
if (accumulation_blend)
{
m_om_bsel.accu_blend = 1;
if (ALPHA.A == 2) {
// The blend unit does a reverse subtraction so it means
// the shader must output a positive value.
// Replace 0 - Cs by Cs - 0
m_ps_sel.blend_a = ALPHA.B;
m_ps_sel.blend_b = 2;
}
// Remove the addition/substraction from the SW blending
m_ps_sel.blend_d = 2;
}
else
{
// We shouldn't hit this path as currently only accumulation blend is implemented
ASSERT(0);
}
// Require the fix alpha vlaue
if (ALPHA.C == 2)
ps_cb.Af.x = (float)ALPHA.FIX / 128.0f;
}
else
{
m_ps_sel.clr1 = !!(blend_flag & BLEND_C_CLR);
// FIXME: When doing HW blending with a 24 bit frambuffer and ALPHA.C == 1 (Ad) it should be handled
// as if Ad = 1.0f. As with OGL side it is probably best to set m_om_bsel.c = 1 (Af) and use
// AFIX = 0x80 (Af = 1.0f).
}
}
void GSRendererDX11::EmulateTextureSampler(const GSTextureCache::Source* tex) void GSRendererDX11::EmulateTextureSampler(const GSTextureCache::Source* tex)
{ {
const GSLocalMemory::psm_t &psm = GSLocalMemory::m_psm[m_context->TEX0.PSM]; const GSLocalMemory::psm_t &psm = GSLocalMemory::m_psm[m_context->TEX0.PSM];
@ -779,34 +872,12 @@ void GSRendererDX11::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sou
} }
// Blend // Blend
if (!IsOpaque() && rt)
if (!IsOpaque())
{ {
m_om_bsel.abe = PRIM->ABE || PRIM->AA1 && m_vt.m_primclass == GS_LINE_CLASS; EmulateBlending();
m_om_bsel.a = m_context->ALPHA.A;
m_om_bsel.b = m_context->ALPHA.B;
m_om_bsel.c = m_context->ALPHA.C;
m_om_bsel.d = m_context->ALPHA.D;
if (m_env.PABE.PABE)
{
if (m_om_bsel.a == 0 && m_om_bsel.b == 1 && m_om_bsel.c == 0 && m_om_bsel.d == 1)
{
// this works because with PABE alpha blending is on when alpha >= 0x80, but since the pixel shader
// cannot output anything over 0x80 (== 1.0) blending with 0x80 or turning it off gives the same result
m_om_bsel.abe = 0;
}
else
{
//Breath of Fire Dragon Quarter triggers this in battles. Graphics are fine though.
//ASSERT(0);
}
} }
// Color clip if (m_ps_sel.hdr)
if (m_env.COLCLAMP.CLAMP == 0 && rt)
{ {
// fprintf(stderr, "COLCLIP HDR mode ENABLED\n"); // fprintf(stderr, "COLCLIP HDR mode ENABLED\n");
GSVector4 dRect(ComputeBoundingBox(rtscale, rtsize)); GSVector4 dRect(ComputeBoundingBox(rtscale, rtsize));
@ -816,7 +887,6 @@ void GSRendererDX11::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sou
// vertices will be overwritten. Trust me you don't want to do that. // vertices will be overwritten. Trust me you don't want to do that.
dev->StretchRect(rt, sRect, hdr_rt, dRect, ShaderConvert_COPY, false); dev->StretchRect(rt, sRect, hdr_rt, dRect, ShaderConvert_COPY, false);
} }
}
if (m_ps_sel.dfmt == 1) if (m_ps_sel.dfmt == 1)
{ {
@ -894,7 +964,6 @@ void GSRendererDX11::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sou
} }
} }
m_ps_sel.clr1 = m_om_bsel.IsCLR1();
m_ps_sel.fba = m_context->FBA.FBA; m_ps_sel.fba = m_context->FBA.FBA;
if (PRIM->FGE) if (PRIM->FGE)

View File

@ -43,6 +43,7 @@ private:
inline void SetupIA(const float& sx, const float& sy); inline void SetupIA(const float& sx, const float& sy);
inline void EmulateAtst(const int pass, const GSTextureCache::Source* tex); inline void EmulateAtst(const int pass, const GSTextureCache::Source* tex);
inline void EmulateZbuffer(); inline void EmulateZbuffer();
inline void EmulateBlending();
inline void EmulateTextureShuffleAndFbmask(); inline void EmulateTextureShuffleAndFbmask();
inline void EmulateChannelShuffle(GSTexture** rt, const GSTextureCache::Source* tex); inline void EmulateChannelShuffle(GSTexture** rt, const GSTextureCache::Source* tex);
inline void EmulateTextureSampler(const GSTextureCache::Source* tex); inline void EmulateTextureSampler(const GSTextureCache::Source* tex);

View File

@ -415,6 +415,12 @@ void GSDevice11::SetupOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, uin
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;
}
} }
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

@ -880,6 +880,37 @@ void gs_main(line VS_OUTPUT input[2], inout TriangleStream<VS_OUTPUT> stream)
#endif #endif
void ps_blend(inout float4 Color, float As, float2 pos_xy)
{
if (SW_BLEND)
{
float4 RT = RtSampler.Load(int3(pos_xy, 0));
float3 Cs = trunc(Color.rgb * 255.0f + 0.1f);
float3 Cd = trunc(RT.rgb * 255.0f + 0.1f);
float3 Cv;
float Ad = (PS_DFMT == FMT_24) ? 1.0f : (RT.a * 255.0f / 128.0f);
float3 A = (PS_BLEND_A == 0) ? Cs : ((PS_BLEND_A == 1) ? Cd : (float3)0.0f);
float3 B = (PS_BLEND_B == 0) ? Cs : ((PS_BLEND_B == 1) ? Cd : (float3)0.0f);
float3 C = (PS_BLEND_C == 0) ? As : ((PS_BLEND_C == 1) ? Ad : Af);
float3 D = (PS_BLEND_D == 0) ? Cs : ((PS_BLEND_D == 1) ? Cd : (float3)0.0f);
Cv = (PS_BLEND_A == PS_BLEND_B) ? D : trunc(((A - B) * C) + D);
// Standard Clamp
if (PS_HDR == 0)
Cv = clamp(Cv, (float3)0.0f, (float3)255.0f);
// In 16 bits format, only 5 bits of color are used. It impacts shadows computation of Castlevania
if (PS_DFMT == FMT_16)
Cv = (float3)((int3)Cv & (int3)0xF8);
Color.rgb = Cv / 255.0f;
}
}
PS_OUTPUT ps_main(PS_INPUT input) PS_OUTPUT ps_main(PS_INPUT input)
{ {
float4 c = ps_color(input); float4 c = ps_color(input);
@ -916,6 +947,10 @@ PS_OUTPUT ps_main(PS_INPUT input)
// Must be done before alpha correction // Must be done before alpha correction
float alpha_blend = c.a * 255.0f / 128.0f; float alpha_blend = c.a * 255.0f / 128.0f;
// Blending
ps_blend(c, alpha_blend, input.p.xy);
// Alpha correction
if (PS_DFMT == FMT_16) // 16 bit output if (PS_DFMT == FMT_16) // 16 bit output
{ {
float a = 128.0f / 255; // alpha output will be 0x80 float a = 128.0f / 255; // alpha output will be 0x80