diff --git a/plugins/GSdx/GSRendererDX.cpp b/plugins/GSdx/GSRendererDX.cpp index 0a956cbd00..a3f803db9f 100644 --- a/plugins/GSdx/GSRendererDX.cpp +++ b/plugins/GSdx/GSRendererDX.cpp @@ -287,6 +287,8 @@ void GSRendererDX::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sourc const GSLocalMemory::psm_t &cpsm = psm.pal > 0 ? GSLocalMemory::m_psm[context->TEX0.CPSM] : psm; bool bilinear = m_filter == 2 ? m_vt.IsLinear() : m_filter != 0; bool simple_sample = !tex->m_palette && cpsm.fmt == 0 && context->CLAMP.WMS < 3 && context->CLAMP.WMT < 3; + // Don't do extra filtering on sprite (it creates various upscaling issue) + bilinear &= !((m_vt.m_primclass == GS_SPRITE_CLASS) && (m_userhacks_stretch_sprite)); ps_sel.wms = context->CLAMP.WMS; ps_sel.wmt = context->CLAMP.WMT; diff --git a/plugins/GSdx/GSRendererHW.cpp b/plugins/GSdx/GSRendererHW.cpp index fc4e5ef1d5..09b7db2b90 100644 --- a/plugins/GSdx/GSRendererHW.cpp +++ b/plugins/GSdx/GSRendererHW.cpp @@ -32,6 +32,7 @@ GSRendererHW::GSRendererHW(GSTextureCache* tc) { m_upscale_multiplier = theApp.GetConfig("upscale_multiplier", 1); m_userhacks_skipdraw = !!theApp.GetConfig("UserHacks", 0) ? theApp.GetConfig("UserHacks_SkipDraw", 0) : 0; + m_userhacks_stretch_sprite = !!theApp.GetConfig("UserHacks_stretch_sprite", 0); if(!m_nativeres) { @@ -54,6 +55,31 @@ GSRendererHW::GSRendererHW(GSTextureCache* tc) { m_upscale_multiplier = 1; } + // When you upscale sprite will sample invalid data of the texture. The idea is to add a subtexel offset + // so the sampling remains inside the texture. + // The strict minimal value can be computed with this formulae (you need to round above, [1;2[ must be rounded to 2). + // + // s: m_upscale_multiplier + // WH: Width or Height of the texture + // 0.5: initial offset of texture (not sure it is always true) + // L: length of primitive in pixels (after upscaling) + // + // Full formulae is + // 0.5 + (L - 1)* (WH-offset)/L < WH + // + // A reduced formulae is: (hypothesis 1:1 mapping => L == s*WH) + // offset > ((0.5)*s -1)/(s-1/WH)*16 + // + // Rendering is perfect for 2x but some issues remains on higher scaling + switch (m_upscale_multiplier) { + case 1: m_sub_texel_offset = 0; break; + case 2: m_sub_texel_offset = 1; break; + case 3: m_sub_texel_offset = 3; break; // texture of 2 texels need 4 (Is is used?) + case 4: m_sub_texel_offset = 5; break; + case 5: m_sub_texel_offset = 6; break; + case 6: m_sub_texel_offset = 6; break; + default: break; + } } GSRendererHW::~GSRendererHW() @@ -295,6 +321,23 @@ void GSRendererHW::Draw() context->FRAME.FBMSK = fm; context->ZBUF.ZMSK = zm != 0; + // Hack to avoid black line in various games. + if (m_userhacks_stretch_sprite && (m_vt.m_primclass == GS_SPRITE_CLASS)) { + size_t count = m_vertex.next; + GSVertex* v = &m_vertex.buff[0]; + for(size_t i = 0; i < count; i += 2) { + if (v[i+1].U < v[i].U) + v[i+1].U += m_sub_texel_offset; + else + v[i+1].U -= m_sub_texel_offset; + if (v[i+1].V < v[i].V) + v[i+1].V += m_sub_texel_offset; + else + v[i+1].V -= m_sub_texel_offset; + } + } + + // DrawPrims(rt->m_texture, ds->m_texture, tex); diff --git a/plugins/GSdx/GSRendererHW.h b/plugins/GSdx/GSRendererHW.h index 405257ae91..9784695f74 100644 --- a/plugins/GSdx/GSRendererHW.h +++ b/plugins/GSdx/GSRendererHW.h @@ -35,7 +35,8 @@ private: bool m_reset; int m_upscale_multiplier; int m_userhacks_skipdraw; - + int m_sub_texel_offset; + #pragma region hacks typedef bool (GSRendererHW::*OI_Ptr)(GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t); @@ -134,6 +135,8 @@ protected: virtual void DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Source* tex) = 0; + bool m_userhacks_stretch_sprite; + public: GSRendererHW(GSTextureCache* tc); virtual ~GSRendererHW(); diff --git a/plugins/GSdx/GSRendererOGL.cpp b/plugins/GSdx/GSRendererOGL.cpp index 97e31ca554..2cc5645727 100644 --- a/plugins/GSdx/GSRendererOGL.cpp +++ b/plugins/GSdx/GSRendererOGL.cpp @@ -414,6 +414,8 @@ void GSRendererOGL::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sour const GSLocalMemory::psm_t &cpsm = psm.pal > 0 ? GSLocalMemory::m_psm[context->TEX0.CPSM] : psm; bool bilinear = m_filter == 2 ? m_vt.IsLinear() : m_filter != 0; bool simple_sample = !tex->m_palette && cpsm.fmt == 0 && context->CLAMP.WMS < 3 && context->CLAMP.WMT < 3; + // Don't do extra filtering on sprite (it creates various upscaling issue) + bilinear &= !((m_vt.m_primclass == GS_SPRITE_CLASS) && (m_userhacks_stretch_sprite)); ps_sel.wms = context->CLAMP.WMS; ps_sel.wmt = context->CLAMP.WMT; @@ -426,7 +428,7 @@ void GSRendererOGL::DrawPrims(GSTexture* rt, GSTexture* ds, GSTextureCache::Sour // FIXME the ati is currently disabled on the shader. I need to find a .gs to test that we got same // bug on opengl // FIXME for the moment disable it on subroutine (it will kill my perf for nothings) - ps_sel.point_sampler = !(bilinear && simple_sample) && !GLLoader::found_GL_ARB_shader_subroutine; + ps_sel.point_sampler = 0; // !(bilinear && simple_sample) && !GLLoader::found_GL_ARB_shader_subroutine; int w = tex->m_texture->GetWidth(); int h = tex->m_texture->GetHeight();