mirror of https://github.com/PCSX2/pcsx2.git
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:
parent
6bdd4ff186
commit
60cf62fea1
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue