diff --git a/plugins/GSdx/GSRendererHW.cpp b/plugins/GSdx/GSRendererHW.cpp index 09b7db2b90..cd4cb2a367 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_align_sprite_X = !!theApp.GetConfig("UserHacks_align_sprite_X", 0); m_userhacks_stretch_sprite = !!theApp.GetConfig("UserHacks_stretch_sprite", 0); if(!m_nativeres) @@ -321,7 +322,26 @@ void GSRendererHW::Draw() context->FRAME.FBMSK = fm; context->ZBUF.ZMSK = zm != 0; - // Hack to avoid black line in various games. + // Hack to avoid vertical black line in various games (ace combat/tekken) + if (m_userhacks_align_sprite_X && (m_vt.m_primclass == GS_SPRITE_CLASS)) { + size_t count = m_vertex.next; + GSVertex* v = &m_vertex.buff[0]; + + // Note for performance reason I do the check only once on the first + // primitive + int win_position = v[1].XYZ.X - context->XYOFFSET.OFX; + if (((win_position & 0xF) == 8) && ((v[1].U & 0xF) == 0)) { + // Normaly vertex are aligned on full pixels and texture in half + // pixels. Let's extend the coverage of an half-pixel to avoid + // hole after upscaling + for(size_t i = 0; i < count; i += 2) { + v[i+1].XYZ.X += 8; + v[i+1].U += 8; + } + } + } + + // Hack to avoid black line in various 2D 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]; diff --git a/plugins/GSdx/GSRendererHW.h b/plugins/GSdx/GSRendererHW.h index 9784695f74..8075120b74 100644 --- a/plugins/GSdx/GSRendererHW.h +++ b/plugins/GSdx/GSRendererHW.h @@ -37,6 +37,8 @@ private: int m_userhacks_skipdraw; int m_sub_texel_offset; + bool m_userhacks_align_sprite_X; + #pragma region hacks typedef bool (GSRendererHW::*OI_Ptr)(GSTexture* rt, GSTexture* ds, GSTextureCache::Source* t);