From 8b1eb3b4562a79102be611ce9d499b555995da37 Mon Sep 17 00:00:00 2001 From: KrossX Date: Sun, 15 Sep 2019 15:49:34 -0300 Subject: [PATCH] GSdx: Dithering on Hardware --- plugins/GSdx/GSdx.cpp | 1 + plugins/GSdx/Renderers/DX11/GSDevice11.h | 26 +++++++++++++++---- .../GSdx/Renderers/DX11/GSRendererDX11.cpp | 10 +++++++ plugins/GSdx/Renderers/DX11/GSTextureFX11.cpp | 1 + plugins/GSdx/Renderers/HW/GSRendererHW.cpp | 2 +- plugins/GSdx/Renderers/HW/GSRendererHW.h | 1 + plugins/GSdx/Renderers/OpenGL/GSDeviceOGL.cpp | 1 + plugins/GSdx/Renderers/OpenGL/GSDeviceOGL.h | 19 ++++++++++++-- .../GSdx/Renderers/OpenGL/GSRendererOGL.cpp | 12 +++++++++ plugins/GSdx/res/glsl/common_header.glsl | 2 ++ plugins/GSdx/res/glsl/tfx_fs.glsl | 22 +++++++++++++++- plugins/GSdx/res/tfx.fx | 24 +++++++++++++++++ 12 files changed, 112 insertions(+), 9 deletions(-) diff --git a/plugins/GSdx/GSdx.cpp b/plugins/GSdx/GSdx.cpp index 86c2722ae7..700330fcce 100644 --- a/plugins/GSdx/GSdx.cpp +++ b/plugins/GSdx/GSdx.cpp @@ -341,6 +341,7 @@ void GSdxApp::Init() m_default_configuration["debug_glsl_shader"] = "0"; m_default_configuration["debug_opengl"] = "0"; m_default_configuration["disable_hw_gl_draw"] = "0"; + m_default_configuration["dithering_ps2"] = "1"; m_default_configuration["dump"] = "0"; m_default_configuration["extrathreads"] = "2"; m_default_configuration["extrathreads_height"] = "4"; diff --git a/plugins/GSdx/Renderers/DX11/GSDevice11.h b/plugins/GSdx/Renderers/DX11/GSDevice11.h index 1f2682224b..93daf827c5 100644 --- a/plugins/GSdx/Renderers/DX11/GSDevice11.h +++ b/plugins/GSdx/Renderers/DX11/GSDevice11.h @@ -103,6 +103,7 @@ public: GSVector4 TC_OffsetHack; GSVector4 Af; + GSVector4 DitherMatrix[4]; PSConstantBuffer() { @@ -115,6 +116,11 @@ public: ChannelShuffle = GSVector4i::zero(); FbMask = GSVector4i::zero(); Af = GSVector4::zero(); + + DitherMatrix[0] = GSVector4::zero(); + DitherMatrix[1] = GSVector4::zero(); + DitherMatrix[2] = GSVector4::zero(); + DitherMatrix[3] = GSVector4::zero(); } __forceinline bool Update(const PSConstantBuffer* cb) @@ -123,7 +129,8 @@ public: 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]) & (a[7] == b[7]) & (a[9] == b[9])).alltrue()) // if WH matches HalfTexel does too + (a[6] == b[6]) & (a[7] == b[7]) & (a[9] == b[9]) & // if WH matches HalfTexel does too + (a[10] == b[10]) & (a[11] == b[11]) & (a[12] == b[12]) & (a[13] == b[13])).alltrue()) { a[0] = b[0]; a[1] = b[1]; @@ -135,6 +142,11 @@ public: a[7] = b[7]; a[9] = b[9]; + a[10] = b[10]; + a[11] = b[11]; + a[12] = b[12]; + a[13] = b[13]; + return true; } @@ -211,17 +223,21 @@ public: uint32 fbmask:1; // Blend and Colclip + uint32 hdr:1; uint32 blend_a:2; - uint32 blend_b:2; - uint32 blend_c:2; + uint32 blend_b:2; // bit30/31 + uint32 blend_c:2; // bit0 uint32 blend_d:2; uint32 clr1:1; - uint32 hdr:1; + uint32 colclip:1; // Others ways to fetch the texture uint32 channel:3; + // Dithering + uint32 dither:2; + // Hack uint32 tcoffsethack:1; uint32 urban_chaos_hle:1; @@ -229,7 +245,7 @@ public: uint32 point_sampler:1; uint32 invalid_tex0:1; // Lupin the 3rd - uint32 _free:18; + uint32 _free:16; }; uint64 key; diff --git a/plugins/GSdx/Renderers/DX11/GSRendererDX11.cpp b/plugins/GSdx/Renderers/DX11/GSRendererDX11.cpp index fe9799a9a3..c79ed43edf 100644 --- a/plugins/GSdx/Renderers/DX11/GSRendererDX11.cpp +++ b/plugins/GSdx/Renderers/DX11/GSRendererDX11.cpp @@ -986,6 +986,16 @@ void GSRendererDX11::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sou } m_ps_sel.fba = m_context->FBA.FBA; + m_ps_sel.dither = m_dithering > 0 && m_ps_sel.dfmt == 2 && m_env.DTHE.DTHE; + + if(m_ps_sel.dither) + { + m_ps_sel.dither = m_dithering; + ps_cb.DitherMatrix[0] = GSVector4(m_env.DIMX.DM00, m_env.DIMX.DM10, m_env.DIMX.DM20, m_env.DIMX.DM30); + ps_cb.DitherMatrix[1] = GSVector4(m_env.DIMX.DM01, m_env.DIMX.DM11, m_env.DIMX.DM21, m_env.DIMX.DM31); + ps_cb.DitherMatrix[2] = GSVector4(m_env.DIMX.DM02, m_env.DIMX.DM12, m_env.DIMX.DM22, m_env.DIMX.DM32); + ps_cb.DitherMatrix[3] = GSVector4(m_env.DIMX.DM03, m_env.DIMX.DM13, m_env.DIMX.DM23, m_env.DIMX.DM33); + } if (PRIM->FGE) { diff --git a/plugins/GSdx/Renderers/DX11/GSTextureFX11.cpp b/plugins/GSdx/Renderers/DX11/GSTextureFX11.cpp index bd64b48359..c6ffb19458 100644 --- a/plugins/GSdx/Renderers/DX11/GSTextureFX11.cpp +++ b/plugins/GSdx/Renderers/DX11/GSTextureFX11.cpp @@ -219,6 +219,7 @@ void GSDevice11::SetupPS(PSSelector sel, const PSConstantBuffer* cb, PSSamplerSe sm.AddMacro("PS_BLEND_B", sel.blend_b); sm.AddMacro("PS_BLEND_C", sel.blend_c); sm.AddMacro("PS_BLEND_D", sel.blend_d); + sm.AddMacro("PS_DITHER", sel.dither); CComPtr ps; diff --git a/plugins/GSdx/Renderers/HW/GSRendererHW.cpp b/plugins/GSdx/Renderers/HW/GSRendererHW.cpp index 26b18944a2..30809f5b53 100644 --- a/plugins/GSdx/Renderers/HW/GSRendererHW.cpp +++ b/plugins/GSdx/Renderers/HW/GSRendererHW.cpp @@ -28,7 +28,6 @@ GSRendererHW::GSRendererHW(GSTextureCache* tc) , m_custom_width(1024) , m_custom_height(1024) , m_reset(false) - , m_upscale_multiplier(1) , m_userhacks_ts_half_bottom(-1) , m_tc(tc) , m_src(nullptr) @@ -42,6 +41,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_dithering = theApp.GetConfigI("dithering_ps2"); // 0 off, 1 auto, 2 auto no scale if (theApp.GetConfigB("UserHacks")) { m_userhacks_enabled_gs_mem_clear = !theApp.GetConfigB("UserHacks_Disable_Safe_Features"); diff --git a/plugins/GSdx/Renderers/HW/GSRendererHW.h b/plugins/GSdx/Renderers/HW/GSRendererHW.h index ab88dad249..4c9ac3cd7d 100644 --- a/plugins/GSdx/Renderers/HW/GSRendererHW.h +++ b/plugins/GSdx/Renderers/HW/GSRendererHW.h @@ -158,6 +158,7 @@ protected: int m_accurate_date; int m_sw_blending; + int m_dithering; bool m_channel_shuffle; diff --git a/plugins/GSdx/Renderers/OpenGL/GSDeviceOGL.cpp b/plugins/GSdx/Renderers/OpenGL/GSDeviceOGL.cpp index ba20e646d3..ad9b29dfc3 100644 --- a/plugins/GSdx/Renderers/OpenGL/GSDeviceOGL.cpp +++ b/plugins/GSdx/Renderers/OpenGL/GSDeviceOGL.cpp @@ -982,6 +982,7 @@ GLuint GSDeviceOGL::CompilePS(PSSelector sel) + format("#define PS_WRITE_RG %d\n", sel.write_rg) + format("#define PS_FBMASK %d\n", sel.fbmask) + format("#define PS_HDR %d\n", sel.hdr) + + format("#define PS_DITHER %d\n", sel.dither) // + format("#define PS_PABE %d\n", sel.pabe) ; diff --git a/plugins/GSdx/Renderers/OpenGL/GSDeviceOGL.h b/plugins/GSdx/Renderers/OpenGL/GSDeviceOGL.h index d2c65e91b4..f0a0b1ba4d 100644 --- a/plugins/GSdx/Renderers/OpenGL/GSDeviceOGL.h +++ b/plugins/GSdx/Renderers/OpenGL/GSDeviceOGL.h @@ -197,6 +197,7 @@ public: GSVector4 HalfTexel; GSVector4 MinMax; GSVector4 TC_OH_TS; + GSVector4 DitherMatrix[4]; PSConstantBuffer() { @@ -208,6 +209,11 @@ public: MskFix = GSVector4i::zero(); TC_OH_TS = GSVector4::zero(); FbMask = GSVector4i::zero(); + + DitherMatrix[0] = GSVector4::zero(); + DitherMatrix[1] = GSVector4::zero(); + DitherMatrix[2] = GSVector4::zero(); + DitherMatrix[3] = GSVector4::zero(); } __forceinline bool Update(const PSConstantBuffer* cb) @@ -217,7 +223,8 @@ public: // if WH matches both HalfTexel and TC_OH_TS do too // MinMax depends on WH and MskFix so no need to check it too - if(!((a[0] == b[0]) & (a[1] == b[1]) & (a[2] == b[2]) & (a[3] == b[3]) & (a[4] == b[4])).alltrue()) + if(!((a[0] == b[0]) & (a[1] == b[1]) & (a[2] == b[2]) & (a[3] == b[3]) & (a[4] == b[4]) + & (a[8] == b[8]) & (a[9] == b[9]) & (a[10] == b[10]) & (a[11] == b[11])).alltrue()) { // Note previous check uses SSE already, a plain copy will be faster than any memcpy a[0] = b[0]; @@ -227,6 +234,11 @@ public: a[4] = b[4]; a[5] = b[5]; + a[8] = b[8]; + a[9] = b[9]; + a[10] = b[10]; + a[11] = b[11]; + return true; } @@ -287,6 +299,9 @@ public: // Others ways to fetch the texture uint32 channel:3; + // Dithering + uint32 dither:2; + // Hack uint32 tcoffsethack:1; uint32 urban_chaos_hle:1; @@ -297,7 +312,7 @@ public: uint32 point_sampler:1; uint32 invalid_tex0:1; // Lupin the 3rd - uint32 _free2:10; + uint32 _free2:8; }; uint64 key; diff --git a/plugins/GSdx/Renderers/OpenGL/GSRendererOGL.cpp b/plugins/GSdx/Renderers/OpenGL/GSRendererOGL.cpp index e0f419156a..cc0aeb3235 100644 --- a/plugins/GSdx/Renderers/OpenGL/GSRendererOGL.cpp +++ b/plugins/GSdx/Renderers/OpenGL/GSRendererOGL.cpp @@ -1217,6 +1217,18 @@ void GSRendererOGL::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sour } m_ps_sel.fba = m_context->FBA.FBA; + m_ps_sel.dither = m_dithering > 0 && m_ps_sel.dfmt == 2 && m_env.DTHE.DTHE; + + if (m_ps_sel.dither) + { + GL_INS("DITHERING mode ENABLED (%d)", m_dithering); + + m_ps_sel.dither = m_dithering; + ps_cb.DitherMatrix[0] = GSVector4(m_env.DIMX.DM00, m_env.DIMX.DM01, m_env.DIMX.DM02, m_env.DIMX.DM03); + ps_cb.DitherMatrix[1] = GSVector4(m_env.DIMX.DM10, m_env.DIMX.DM11, m_env.DIMX.DM12, m_env.DIMX.DM13); + ps_cb.DitherMatrix[2] = GSVector4(m_env.DIMX.DM20, m_env.DIMX.DM21, m_env.DIMX.DM22, m_env.DIMX.DM23); + ps_cb.DitherMatrix[3] = GSVector4(m_env.DIMX.DM30, m_env.DIMX.DM31, m_env.DIMX.DM32, m_env.DIMX.DM33); + } if (PRIM->FGE) { diff --git a/plugins/GSdx/res/glsl/common_header.glsl b/plugins/GSdx/res/glsl/common_header.glsl index 2673ec848a..a712a9cb27 100644 --- a/plugins/GSdx/res/glsl/common_header.glsl +++ b/plugins/GSdx/res/glsl/common_header.glsl @@ -94,6 +94,8 @@ layout(std140, binding = 21) uniform cb21 vec2 TextureScale; vec2 TC_OffsetHack; + + mat4 DitherMatrix; }; #endif diff --git a/plugins/GSdx/res/glsl/tfx_fs.glsl b/plugins/GSdx/res/glsl/tfx_fs.glsl index 0ce52f7502..80ff1483a2 100644 --- a/plugins/GSdx/res/glsl/tfx_fs.glsl +++ b/plugins/GSdx/res/glsl/tfx_fs.glsl @@ -637,6 +637,18 @@ void ps_fbmask(inout vec4 C) #endif } +void ps_dither(inout vec4 C) +{ +#if PS_DITHER + #if PS_DITHER == 2 + ivec2 fpos = ivec2(gl_FragCoord.xy); + #else + ivec2 fpos = ivec2(gl_FragCoord.xy / ScalingFactor.x); + #endif + C.rgb += DitherMatrix[fpos.y&3][fpos.x&3]; +#endif +} + void ps_blend(inout vec4 Color, float As) { #if SW_BLEND @@ -692,7 +704,8 @@ void ps_blend(inout vec4 Color, float As) Color.rgb = trunc((A - B) * C + D); #endif - // FIXME dithering + // Dithering + ps_dither(Color); // Correct the Color value based on the output format #if PS_COLCLIP == 0 && PS_HDR == 0 @@ -842,6 +855,13 @@ void ps_main() return; #endif +#if !SW_BLEND && PS_DITHER + ps_dither(C); + // Dither matrix range is [-4,3] but positive values can cause issues when + // software blending is not used or is unavailable. + C.rgb -= 3.0; +#endif + ps_blend(C, alpha_blend); ps_fbmask(C); diff --git a/plugins/GSdx/res/tfx.fx b/plugins/GSdx/res/tfx.fx index d293c1d808..6bc4c8b27c 100644 --- a/plugins/GSdx/res/tfx.fx +++ b/plugins/GSdx/res/tfx.fx @@ -49,6 +49,7 @@ #define PS_BLEND_B 0 #define PS_BLEND_C 0 #define PS_BLEND_D 0 +#define PS_DITHER 0 #endif #define SW_BLEND (PS_BLEND_A || PS_BLEND_B || PS_BLEND_D) @@ -116,6 +117,7 @@ cbuffer cb1 float4 TC_OffsetHack; float Af; float3 _pad; + float4x4 DitherMatrix; }; cbuffer cb2 @@ -665,6 +667,18 @@ void ps_fbmask(inout float4 C, float2 pos_xy) } } +void ps_dither(inout float3 C, float2 pos_xy) +{ +#if PS_DITHER + #if PS_DITHER == 2 + int2 fpos = int2(pos_xy); + #else + int2 fpos = int2(pos_xy / (float)PS_SCALE_FACTOR); + #endif + C += DitherMatrix[fpos.y&3][fpos.x&3]; +#endif +} + void ps_blend(inout float4 Color, float As, float2 pos_xy) { if (SW_BLEND) @@ -684,6 +698,9 @@ void ps_blend(inout float4 Color, float As, float2 pos_xy) Cv = (PS_BLEND_A == PS_BLEND_B) ? D : trunc(((A - B) * C) + D); + // Dithering + ps_dither(Cv, pos_xy); + // Standard Clamp if (PS_COLCLIP == 0 && PS_HDR == 0) Cv = clamp(Cv, (float3)0.0f, (float3)255.0f); @@ -746,6 +763,13 @@ PS_OUTPUT ps_main(PS_INPUT input) if (C.a < A_one) C.a += A_one; } +#if !SW_BLEND && PS_DITHER + ps_dither(C.rgb, input.p.xy); + // Dither matrix range is [-4,3] but positive values can cause issues when + // software blending is not used or is unavailable. + C.rgb -= 3.0; +#endif + ps_blend(C, alpha_blend, input.p.xy); ps_fbmask(C, input.p.xy);