From 61a7c747e15eeddb2e375ce0c9b5e38cb65f5368 Mon Sep 17 00:00:00 2001 From: Gregory Hainaut Date: Tue, 21 Jun 2016 09:51:47 +0200 Subject: [PATCH] gsdx-ogl: alternate implementation of half pixel offset The previous implementation of HPO adds an offset on vertex position. It doesn't always work beside it moves the rendering window. The new implementation will add a texture offset so that instead to sample the middle of the GS texel, we will sample the middle of the real texture texel. It must be manually enabled with * UserHacks_HalfPixelOffset_New = 1 (keep a small offset as intended by GS effect) * UserHacks_HalfPixelOffset_New = 2 (no offset) v2: always apply a 0.5 offset in case of float coordinates (Tales of Abyss) Might break other games but few of them uses float coordinates to read back the target --- plugins/GSdx/GSRendererOGL.cpp | 62 +++++++++++++++++++++++++++++- plugins/GSdx/GSRendererOGL.h | 2 + plugins/GSdx/GSdx.cpp | 1 + plugins/GSdx/res/glsl/tfx_vgs.glsl | 2 +- plugins/GSdx/res/glsl_source.h | 2 +- 5 files changed, 66 insertions(+), 3 deletions(-) diff --git a/plugins/GSdx/GSRendererOGL.cpp b/plugins/GSdx/GSRendererOGL.cpp index 54265309af..ce85ece8b3 100644 --- a/plugins/GSdx/GSRendererOGL.cpp +++ b/plugins/GSdx/GSRendererOGL.cpp @@ -39,6 +39,7 @@ GSRendererOGL::GSRendererOGL() UserHacks_TCO_y = ((UserHacks_TCOffset >> 16) & 0xFFFF) / -1000.0f; UserHacks_merge_sprite = theApp.GetConfigB("UserHacks_merge_pp_sprite"); UserHacks_unscale_pt_ln = theApp.GetConfigB("UserHacks_unscale_point_line"); + UserHacks_HPO = theApp.GetConfigI("UserHacks_HalfPixelOffset_New"); m_prim_overlap = PRIM_OVERLAP_UNKNOW; ResetStates(); @@ -49,6 +50,7 @@ GSRendererOGL::GSRendererOGL() UserHacks_TCO_y = 0; UserHacks_merge_sprite = false; UserHacks_unscale_pt_ln = false; + UserHacks_HPO = 0; } } @@ -736,6 +738,59 @@ void GSRendererOGL::EmulateBlending(bool DATE_GL42) } } +void GSRendererOGL::RealignTargetTextureCoordinate(const GSTextureCache::Source* tex) +{ + if (!UserHacks_HPO || GetUpscaleMultiplier() == 1) return; + + GSVertex* v = &m_vertex.buff[0]; + const GSVector2& scale = tex->m_texture->GetScale(); + bool linear = m_vt.IsLinear(); + int t_position = v[0].U; + GSVector4 half_offset(0.0f); + + // FIXME Let's start with something wrong same mess on X and Y + // FIXME Maybe it will be enough to check linear + + if (PRIM->FST) { + + if (UserHacks_HPO > 1) { + if (!linear && t_position == 8) { + half_offset.x = 8; + half_offset.y = 8; + } else if (linear && t_position == 16) { + half_offset.x = 16; + half_offset.y = 16; + } + } else { + if (!linear && t_position == 8) { + half_offset.x = 8 - 8 / scale.x; + half_offset.y = 8 - 8 / scale.y; + } else if (linear && t_position == 16) { + half_offset.x = 16 - 16 / scale.x; + half_offset.y = 16 - 16 / scale.y; + } + } + + GL_INS("offset detected %f,%f t_pos %d (linear %d, scale %f)", + half_offset.x, half_offset.y, t_position, linear, scale.x); + + } else if (m_vt.m_eq.q) { + float tw = (float)(1 << m_context->TEX0.TW); + float th = (float)(1 << m_context->TEX0.TH); + float q = v[0].RGBAQ.Q; + + // Tales of Abyss + half_offset.x = 0.5f * q / tw; + half_offset.y = 0.5f * q / th; + + GL_INS("ST offset detected %f,%f (linear %d, scale %f)", + half_offset.x, half_offset.y, linear, scale.x); + + } + + vs_cb.TextureOffset = GSVector4(half_offset); +} + void GSRendererOGL::EmulateTextureSampler(const GSTextureCache::Source* tex) { GSDeviceOGL* dev = (GSDeviceOGL*)m_dev; @@ -829,6 +884,8 @@ void GSRendererOGL::EmulateTextureSampler(const GSTextureCache::Source* tex) // The purpose of texture shuffle is to move color channel. Extra interpolation is likely a bad idea. bilinear &= m_vt.IsLinear(); + RealignTargetTextureCoordinate(tex); + } else if (tex->m_target) { // Use an old target. AEM and index aren't resolved it must be done // on the GPU @@ -877,6 +934,8 @@ void GSRendererOGL::EmulateTextureSampler(const GSTextureCache::Source* tex) bilinear &= m_vt.IsLinear(); } + RealignTargetTextureCoordinate(tex); + } else if (tex->m_palette) { // Use a standard 8 bits texture. AEM is already done on the CLUT // Therefore you only need to set the index @@ -1158,6 +1217,7 @@ void GSRendererOGL::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sour bool ate_second_pass = m_context->TEST.DoSecondPass(); ResetStates(); + vs_cb.TextureOffset = GSVector4(0.0f); ASSERT(m_dev != NULL); GSDeviceOGL* dev = (GSDeviceOGL*)m_dev; @@ -1354,7 +1414,7 @@ void GSRendererOGL::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sour //The resulting shifted output aligns better with common blending / corona / blurring effects, //but introduces a few bad pixels on the edges. - if (rt && rt->LikelyOffset) + if (rt && rt->LikelyOffset && !UserHacks_HPO) { ox2 *= rt->OffsetHack_modx; oy2 *= rt->OffsetHack_mody; diff --git a/plugins/GSdx/GSRendererOGL.h b/plugins/GSdx/GSRendererOGL.h index a633d203e5..8b8663a81b 100644 --- a/plugins/GSdx/GSRendererOGL.h +++ b/plugins/GSdx/GSRendererOGL.h @@ -54,6 +54,7 @@ class GSRendererOGL final : public GSRendererHW float UserHacks_TCO_x, UserHacks_TCO_y; bool UserHacks_merge_sprite; bool UserHacks_unscale_pt_ln; + int UserHacks_HPO; GSDeviceOGL::VSConstantBuffer vs_cb; GSDeviceOGL::PSConstantBuffer ps_cb; @@ -75,6 +76,7 @@ class GSRendererOGL final : public GSRendererHW inline void ResetStates(); inline void Lines2Sprites(); inline void SetupIA(const float& sx, const float& sy); + inline void RealignTargetTextureCoordinate(const GSTextureCache::Source* tex); inline void EmulateTextureShuffleAndFbmask(); inline void EmulateChannelShuffle(GSTexture** rt, const GSTextureCache::Source* tex); inline void EmulateBlending(bool DATE_GL42); diff --git a/plugins/GSdx/GSdx.cpp b/plugins/GSdx/GSdx.cpp index 4d89ac9625..dd2ce6df0f 100644 --- a/plugins/GSdx/GSdx.cpp +++ b/plugins/GSdx/GSdx.cpp @@ -351,6 +351,7 @@ void GSdxApp::Init() m_default_configuration["UserHacks_DisableGsMemClear"] = "0"; m_default_configuration["UserHacks_DisablePartialInvalidation"] = "0"; m_default_configuration["UserHacks_HalfPixelOffset"] = "0"; + m_default_configuration["UserHacks_HalfPixelOffset_New"] = "0"; m_default_configuration["UserHacks_merge_pp_sprite"] = "0"; m_default_configuration["UserHacks_MSAA"] = "0"; m_default_configuration["UserHacks_unscale_point_line"] = "0"; diff --git a/plugins/GSdx/res/glsl/tfx_vgs.glsl b/plugins/GSdx/res/glsl/tfx_vgs.glsl index 229ea8815f..eb405e8ef2 100644 --- a/plugins/GSdx/res/glsl/tfx_vgs.glsl +++ b/plugins/GSdx/res/glsl/tfx_vgs.glsl @@ -27,7 +27,7 @@ void texture_coord() vec2 uv = vec2(i_uv) - TextureOffset.xy; // Float coordinate - VSout.t_float.xy = i_st - TextureOffset.zw; // FIXME or .xy check final code + VSout.t_float.xy = i_st - TextureOffset.xy; VSout.t_float.w = i_q; // Integer coordinate => normalized diff --git a/plugins/GSdx/res/glsl_source.h b/plugins/GSdx/res/glsl_source.h index de4a99a7f0..39a403b580 100644 --- a/plugins/GSdx/res/glsl_source.h +++ b/plugins/GSdx/res/glsl_source.h @@ -770,7 +770,7 @@ static const char* const tfx_vgs_glsl = " vec2 uv = vec2(i_uv) - TextureOffset.xy;\n" "\n" " // Float coordinate\n" - " VSout.t_float.xy = i_st - TextureOffset.zw; // FIXME or .xy check final code\n" + " VSout.t_float.xy = i_st - TextureOffset.xy;\n" " VSout.t_float.w = i_q;\n" "\n" " // Integer coordinate => normalized\n"