From 60cf62fea13c20548dbb7ddd5572077272fdf4c0 Mon Sep 17 00:00:00 2001 From: hibye8313 <49872607+hibye8313@users.noreply.github.com> Date: Sun, 9 Jun 2019 12:38:11 -0400 Subject: [PATCH] GSdx-d3d11: Partial port of EmulateBlending() from OGL renderer to DX11 renderer and ps_blend() from OGL shader to DX11 shader (only accumulation blend). --- .../GSdx/Renderers/DX11/GSRendererDX11.cpp | 141 +++++++++++++----- plugins/GSdx/Renderers/DX11/GSRendererDX11.h | 1 + plugins/GSdx/Renderers/DX11/GSTextureFX11.cpp | 6 + plugins/GSdx/res/tfx.fx | 35 +++++ 4 files changed, 147 insertions(+), 36 deletions(-) diff --git a/plugins/GSdx/Renderers/DX11/GSRendererDX11.cpp b/plugins/GSdx/Renderers/DX11/GSRendererDX11.cpp index 69177ecb68..e8046423b3 100644 --- a/plugins/GSdx/Renderers/DX11/GSRendererDX11.cpp +++ b/plugins/GSdx/Renderers/DX11/GSRendererDX11.cpp @@ -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) { const GSLocalMemory::psm_t &psm = GSLocalMemory::m_psm[m_context->TEX0.PSM]; @@ -779,43 +872,20 @@ void GSRendererDX11::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sou } // Blend - - if (!IsOpaque()) + if (!IsOpaque() && rt) { - 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_env.COLCLAMP.CLAMP == 0 && rt) - { - // fprintf(stderr, "COLCLIP HDR mode ENABLED\n"); - GSVector4 dRect(ComputeBoundingBox(rtscale, rtsize)); - GSVector4 sRect = dRect / GSVector4(rtsize.x, rtsize.y).xyxy(); - hdr_rt = dev->CreateRenderTarget(rtsize.x, rtsize.y, DXGI_FORMAT_R32G32B32A32_FLOAT); - // Warning: StretchRect must be called before BeginScene otherwise - // vertices will be overwritten. Trust me you don't want to do that. - dev->StretchRect(rt, sRect, hdr_rt, dRect, ShaderConvert_COPY, false); - } + if (m_ps_sel.hdr) + { + // fprintf(stderr, "COLCLIP HDR mode ENABLED\n"); + GSVector4 dRect(ComputeBoundingBox(rtscale, rtsize)); + GSVector4 sRect = dRect / GSVector4(rtsize.x, rtsize.y).xyxy(); + hdr_rt = dev->CreateRenderTarget(rtsize.x, rtsize.y, DXGI_FORMAT_R32G32B32A32_FLOAT); + // Warning: StretchRect must be called before BeginScene otherwise + // vertices will be overwritten. Trust me you don't want to do that. + dev->StretchRect(rt, sRect, hdr_rt, dRect, ShaderConvert_COPY, false); } 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; if (PRIM->FGE) diff --git a/plugins/GSdx/Renderers/DX11/GSRendererDX11.h b/plugins/GSdx/Renderers/DX11/GSRendererDX11.h index a3189e06e8..3c33f0d9d2 100644 --- a/plugins/GSdx/Renderers/DX11/GSRendererDX11.h +++ b/plugins/GSdx/Renderers/DX11/GSRendererDX11.h @@ -43,6 +43,7 @@ private: inline void SetupIA(const float& sx, const float& sy); inline void EmulateAtst(const int pass, const GSTextureCache::Source* tex); inline void EmulateZbuffer(); + inline void EmulateBlending(); inline void EmulateTextureShuffleAndFbmask(); inline void EmulateChannelShuffle(GSTexture** rt, const GSTextureCache::Source* tex); inline void EmulateTextureSampler(const GSTextureCache::Source* tex); diff --git a/plugins/GSdx/Renderers/DX11/GSTextureFX11.cpp b/plugins/GSdx/Renderers/DX11/GSTextureFX11.cpp index ca4a9330c5..a7eaa3f90b 100644 --- a/plugins/GSdx/Renderers/DX11/GSTextureFX11.cpp +++ b/plugins/GSdx/Renderers/DX11/GSTextureFX11.cpp @@ -415,6 +415,12 @@ void GSDevice11::SetupOM(OMDepthStencilSelector dssel, OMBlendSelector bsel, uin 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; + } } if(bsel.wr) bd.RenderTarget[0].RenderTargetWriteMask |= D3D11_COLOR_WRITE_ENABLE_RED; diff --git a/plugins/GSdx/res/tfx.fx b/plugins/GSdx/res/tfx.fx index 6ff810851e..dafb0a4282 100644 --- a/plugins/GSdx/res/tfx.fx +++ b/plugins/GSdx/res/tfx.fx @@ -880,6 +880,37 @@ void gs_main(line VS_OUTPUT input[2], inout TriangleStream stream) #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) { float4 c = ps_color(input); @@ -916,6 +947,10 @@ PS_OUTPUT ps_main(PS_INPUT input) // Must be done before alpha correction 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 { float a = 128.0f / 255; // alpha output will be 0x80