diff --git a/plugins/GSdx/Renderers/DX11/GSDevice11.h b/plugins/GSdx/Renderers/DX11/GSDevice11.h index aec90d2cac..dee3e6f32d 100644 --- a/plugins/GSdx/Renderers/DX11/GSDevice11.h +++ b/plugins/GSdx/Renderers/DX11/GSDevice11.h @@ -99,6 +99,7 @@ public: GSVector4 MinF_TA; GSVector4i MskFix; GSVector4i ChannelShuffle; + GSVector4i FbMask; GSVector4 TC_OffsetHack; @@ -111,6 +112,7 @@ public: MinF_TA = GSVector4::zero(); MskFix = GSVector4i::zero(); ChannelShuffle = GSVector4i::zero(); + FbMask = GSVector4i::zero(); } __forceinline bool Update(const PSConstantBuffer* cb) @@ -118,7 +120,7 @@ public: GSVector4i* a = (GSVector4i*)this; GSVector4i* b = (GSVector4i*)cb; - if(!((a[0] == b[0]) /*& (a[1] == b1)*/ & (a[2] == b[2]) & (a[3] == b[3]) & (a[4] == b[4]) & (a[5] == b[5]) & (a[6] == b[6])).alltrue()) // if WH matches HalfTexel does too + if(!((a[0] == b[0]) /*& (a[1] == b1)*/ & (a[2] == b[2]) & (a[3] == b[3]) & (a[4] == b[4]) & (a[5] == b[5]) & (a[6] == b[6]) & (a[7] == b[7])).alltrue()) // if WH matches HalfTexel does too { a[0] = b[0]; a[1] = b[1]; @@ -127,6 +129,7 @@ public: a[4] = b[4]; a[5] = b[5]; a[6] = b[6]; + a[7] = b[7]; return true; } @@ -201,6 +204,7 @@ public: // Shuffle and fbmask effect uint32 shuffle:1; uint32 read_ba:1; + uint32 fbmask:1; // *** Word 2 // Blend and Colclip @@ -210,7 +214,6 @@ public: uint32 channel:3; // Hack - uint32 aout:1; uint32 spritehack:1; uint32 tcoffsethack:1; uint32 urban_chaos_hle:1; diff --git a/plugins/GSdx/Renderers/DX11/GSRendererDX11.cpp b/plugins/GSdx/Renderers/DX11/GSRendererDX11.cpp index 0e91717444..0a7095f2b9 100644 --- a/plugins/GSdx/Renderers/DX11/GSRendererDX11.cpp +++ b/plugins/GSdx/Renderers/DX11/GSRendererDX11.cpp @@ -26,13 +26,9 @@ GSRendererDX11::GSRendererDX11() : GSRendererHW(new GSTextureCache11(this)) { if (theApp.GetConfigB("UserHacks")) - { UserHacks_AlphaStencil = theApp.GetConfigB("UserHacks_AlphaStencil"); - } else - { UserHacks_AlphaStencil = false; - } ResetStates(); } @@ -244,38 +240,71 @@ void GSRendererDX11::EmulateTextureShuffleAndFbmask() if (rg_mask != 0xFF) { if (write_ba) + { + // fprintf(stderr, "Color shuffle %s => B\n", read_ba ? "B" : "R"); m_om_bsel.wb = 1; + } else + { + // fprintf(stderr, "Color shuffle %s => R"\n, read_ba ? "B" : "R"); m_om_bsel.wr = 1; - } - else if ((fbmask & 0xFF) != 0xFF) - { + } #ifdef _DEBUG - fprintf(stderr, "Please fix me! wb %u wr %u\n", m_om_bsel.wb, m_om_bsel.wr); + if (rg_mask) + { + fprintf(stderr, "ERROR: FBMASK SW emulated fb_mask:%x on RG tex shuffle not supported\n", fbmask); + // ASSERT(0); + } #endif - //ASSERT(0); } if (ba_mask != 0xFF) { if (write_ba) + { + // fprintf(stderr, "Color shuffle %s => A"\n, read_ba ? "A" : "G"); m_om_bsel.wa = 1; + } else + { + // fprintf(stderr, "Color shuffle %s => G"\n, read_ba ? "A" : "G"); m_om_bsel.wg = 1; - } - else if ((fbmask & 0xFF) != 0xFF) - { + } #ifdef _DEBUG - fprintf(stderr, "Please fix me! wa %u wg %u\n", m_om_bsel.wa, m_om_bsel.wg); + if (ba_mask) + { + fprintf(stderr, "ERROR: FBMASK SW emulated fb_mask:%x on BA tex shuffle not supported\n", fbmask); + // ASSERT(0); + } #endif - //ASSERT(0); } } else { m_ps_sel.dfmt = GSLocalMemory::m_psm[m_context->FRAME.PSM].fmt; - m_om_bsel.wrgba = ~GSVector4i::load((int)m_context->FRAME.FBMSK).eq8(GSVector4i::xffffffff()).mask(); + GSVector4i fbmask_v = GSVector4i::load((int)m_context->FRAME.FBMSK); + int ff_fbmask = fbmask_v.eq8(GSVector4i::xffffffff()).mask(); + int zero_fbmask = fbmask_v.eq8(GSVector4i::zero()).mask(); + + m_om_bsel.wrgba = ~ff_fbmask; // Enable channel if at least 1 bit is 0 + + m_ps_sel.fbmask = m_sw_blending && (~ff_fbmask & ~zero_fbmask & 0xF); + + if (m_ps_sel.fbmask) + { + ps_cb.FbMask = fbmask_v.u8to32(); + // Only alpha is special here, I think we can take a very unsafe shortcut + // Alpha isn't blended on the GS but directly copyied into the RT. + // + // Behavior is clearly undefined however there is a high probability that + // it will work. Masked bit will be constant and normally the same everywhere + // RT/FS output/Cached value. + + /*fprintf(stderr, "FBMASK SW emulated alpha fb_mask:%x on %d bits format\n", m_context->FRAME.FBMSK, + (GSLocalMemory::m_psm[m_context->FRAME.PSM].fmt == 2) ? 16 : 32);*/ + m_bind_rtsample = true; + } } } @@ -621,6 +650,8 @@ void GSRendererDX11::EmulateTextureSampler(const GSTextureCache::Source* tex) void GSRendererDX11::ResetStates() { + m_bind_rtsample = false; + m_vs_sel.key = 0; m_gs_sel.key = 0; m_ps_sel.key = 0; @@ -912,6 +943,15 @@ void GSRendererDX11::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sou m_ps_sel.tfx = 4; } + if (m_bind_rtsample) + { + // Bind the RT.This way special effect can use it. + // Do not always bind the rt when it's not needed, + // only bind it when effects use it such as fbmask emulation currently + // because we copy the frame buffer and it is quite slow. + dev->PSSetShaderResource(3, rt); + } + if (m_game.title == CRC::ICO) { GSVertex* v = &m_vertex.buff[0]; diff --git a/plugins/GSdx/Renderers/DX11/GSRendererDX11.h b/plugins/GSdx/Renderers/DX11/GSRendererDX11.h index ef193a10ec..cb490486cf 100644 --- a/plugins/GSdx/Renderers/DX11/GSRendererDX11.h +++ b/plugins/GSdx/Renderers/DX11/GSRendererDX11.h @@ -29,6 +29,7 @@ class GSRendererDX11 final : public GSRendererHW { private: bool UserHacks_AlphaStencil; + bool m_bind_rtsample; private: inline void ResetStates(); diff --git a/plugins/GSdx/Renderers/DX11/GSTextureFX11.cpp b/plugins/GSdx/Renderers/DX11/GSTextureFX11.cpp index 6db9ab1f55..43628152b8 100644 --- a/plugins/GSdx/Renderers/DX11/GSTextureFX11.cpp +++ b/plugins/GSdx/Renderers/DX11/GSTextureFX11.cpp @@ -220,7 +220,7 @@ void GSDevice11::SetupPS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSe str[8] = format("%d", sel.fog); str[9] = format("%d", sel.clr1); str[10] = format("%d", sel.fba); - str[11] = format("%d", sel.aout); + str[11] = format("%d", sel.fbmask); str[12] = format("%d", sel.ltf); str[13] = format("%d", sel.spritehack); str[14] = format("%d", sel.tcoffsethack); @@ -249,7 +249,7 @@ void GSDevice11::SetupPS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSe {"PS_FOG", str[8].c_str()}, {"PS_CLR1", str[9].c_str()}, {"PS_FBA", str[10].c_str()}, - {"PS_AOUT", str[11].c_str()}, + {"PS_FBMASK", str[11].c_str()}, {"PS_LTF", str[12].c_str()}, {"PS_SPRITEHACK", str[13].c_str()}, {"PS_TCOFFSETHACK", str[14].c_str()}, diff --git a/plugins/GSdx/Renderers/HW/GSRendererHW.cpp b/plugins/GSdx/Renderers/HW/GSRendererHW.cpp index 6066348dc2..9f37299dc6 100644 --- a/plugins/GSdx/Renderers/HW/GSRendererHW.cpp +++ b/plugins/GSdx/Renderers/HW/GSRendererHW.cpp @@ -40,6 +40,7 @@ GSRendererHW::GSRendererHW(GSTextureCache* tc) m_upscale_multiplier = theApp.GetConfigI("upscale_multiplier"); m_large_framebuffer = theApp.GetConfigB("large_framebuffer"); m_accurate_date = theApp.GetConfigI("accurate_date"); + m_sw_blending = theApp.GetConfigI("accurate_blending_unit"); if (theApp.GetConfigB("UserHacks")) { m_userhacks_enabled_gs_mem_clear = !theApp.GetConfigB("UserHacks_Disable_Safe_Features"); m_userHacks_enabled_unscale_ptln = !theApp.GetConfigB("UserHacks_Disable_Safe_Features"); diff --git a/plugins/GSdx/Renderers/HW/GSRendererHW.h b/plugins/GSdx/Renderers/HW/GSRendererHW.h index 7481cb535a..676ec8c083 100644 --- a/plugins/GSdx/Renderers/HW/GSRendererHW.h +++ b/plugins/GSdx/Renderers/HW/GSRendererHW.h @@ -151,6 +151,7 @@ protected: float m_userhacks_tcoffset_y; int m_accurate_date; + int m_sw_blending; bool m_channel_shuffle; diff --git a/plugins/GSdx/Renderers/OpenGL/GSRendererOGL.cpp b/plugins/GSdx/Renderers/OpenGL/GSRendererOGL.cpp index 0d59aef64e..0327f9325e 100644 --- a/plugins/GSdx/Renderers/OpenGL/GSRendererOGL.cpp +++ b/plugins/GSdx/Renderers/OpenGL/GSRendererOGL.cpp @@ -26,7 +26,6 @@ GSRendererOGL::GSRendererOGL() : GSRendererHW(new GSTextureCacheOGL(this)) { - m_sw_blending = theApp.GetConfigI("accurate_blending_unit"); if (theApp.GetConfigB("UserHacks")) UserHacks_tri_filter = static_cast(theApp.GetConfigI("UserHacks_TriFilter")); else diff --git a/plugins/GSdx/Renderers/OpenGL/GSRendererOGL.h b/plugins/GSdx/Renderers/OpenGL/GSRendererOGL.h index 1563da93af..08a6b56fd5 100644 --- a/plugins/GSdx/Renderers/OpenGL/GSRendererOGL.h +++ b/plugins/GSdx/Renderers/OpenGL/GSRendererOGL.h @@ -49,7 +49,6 @@ class GSRendererOGL final : public GSRendererHW }; private: - int m_sw_blending; PRIM_OVERLAP m_prim_overlap; std::vector m_drawlist; diff --git a/plugins/GSdx/res/tfx.fx b/plugins/GSdx/res/tfx.fx index ea3b9cd793..a81848a53f 100644 --- a/plugins/GSdx/res/tfx.fx +++ b/plugins/GSdx/res/tfx.fx @@ -29,7 +29,7 @@ #define PS_FOG 0 #define PS_CLR1 0 #define PS_FBA 0 -#define PS_AOUT 0 +#define PS_FBMASK 0 #define PS_LTF 1 #define PS_SPRITEHACK 0 #define PS_TCOFFSETHACK 0 @@ -81,6 +81,7 @@ struct PS_OUTPUT Texture2D Texture : register(t0); Texture2D Palette : register(t1); +Texture2D RtSample : register(t3); Texture2D RawTexture : register(t4); SamplerState TextureSampler : register(s0); SamplerState PaletteSampler : register(s1); @@ -103,6 +104,7 @@ cbuffer cb1 float2 TA; uint4 MskFix; int4 ChannelShuffle; + uint4 FbMask; float4 TC_OffsetHack; }; @@ -902,9 +904,10 @@ PS_OUTPUT ps_main(PS_INPUT input) } } - output.c1 = c.a * 255.0f / 128.0f; // used for alpha blending + // Must be done before alpha correction + float alpha_blend = c.a * 255.0f / 128.0f; - if ((PS_DFMT == FMT_16) || PS_AOUT) // 16 bit output + if (PS_DFMT == FMT_16) // 16 bit output { float a = 128.0f / 255; // alpha output will be 0x80 @@ -915,7 +918,16 @@ PS_OUTPUT ps_main(PS_INPUT input) if (c.a < 128.0f / 255.0f) c.a += 128.0f / 255.0f; } + if (PS_FBMASK) + { + float4 rt = RtSample.Load(int3(input.p.xy, 0)); + uint4 denorm_rt = uint4(rt * 255.0f + 0.5f); + uint4 denorm_c = uint4(c * 255.0f + 0.5f); + c = float4((denorm_c & ~FbMask) | (denorm_rt & FbMask)) / 255.0f; + } + output.c0 = c; + output.c1 = (float4)(alpha_blend); return output; }