From 3d26fa08fcf0086eaf5f1085b233abd2200adb3e Mon Sep 17 00:00:00 2001 From: refractionpcsx2 Date: Thu, 27 Feb 2025 00:56:19 +0000 Subject: [PATCH] Testing further tweaks to bring it closer to SW --- pcsx2/GS/Renderers/HW/GSRendererHW.cpp | 46 +++++++++++++++++++++----- 1 file changed, 37 insertions(+), 9 deletions(-) diff --git a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp index 0c041317be2b1..1e5c5072f3443 100644 --- a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp +++ b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp @@ -5165,20 +5165,25 @@ __ri void GSRendererHW::EmulateTextureSampler(const GSTextureCache::Target* rt, { if (!m_downscale_source && tex->m_scale > 1.0f) { + const GSVertex* v = &m_vertex.buff[0]; if (PRIM->FST) { - m_conf.cb_vs.texture_offset.x = 6.0f + (0.25f * tex->m_scale); - m_conf.cb_vs.texture_offset.y = 6.0f + (0.25f * tex->m_scale); + const int x1_frac = (((v[1].XYZ.X - m_context->XYOFFSET.OFX) >> 4) & 0xf); + const int y1_frac = (((v[1].XYZ.Y - m_context->XYOFFSET.OFY) >> 4) & 0xf); + + if (!(x1_frac & 8)) + m_conf.cb_vs.texture_offset.x = 6.0f + (0.25f * tex->m_scale); + if (!(y1_frac & 8)) + m_conf.cb_vs.texture_offset.y = 6.0f + (0.25f * tex->m_scale); } else { - const GSVertex* v = &m_vertex.buff[0]; const float tw = static_cast(1 << m_cached_ctx.TEX0.TW); const float th = static_cast(1 << m_cached_ctx.TEX0.TH); const float q = v[0].RGBAQ.Q; - m_conf.cb_vs.texture_offset.x = 0.5f * q / tw; - m_conf.cb_vs.texture_offset.y = 0.5f * q / th; + m_conf.cb_vs.texture_offset.x = (0.5f * tex->m_scale) * q / tw; + m_conf.cb_vs.texture_offset.y = (0.5f * tex->m_scale) * q / th; } } } @@ -5237,14 +5242,20 @@ __ri void GSRendererHW::EmulateTextureSampler(const GSTextureCache::Target* rt, { if (!m_downscale_source && tex->m_scale > 1.0f) { + const GSVertex* v = &m_vertex.buff[0]; + const int x0_frac = (((v[1].XYZ.X - m_context->XYOFFSET.OFX) >> 4) & 0xf); + const int y0_frac = (((v[1].XYZ.Y - m_context->XYOFFSET.OFY) >> 4) & 0xf); + const int x1_frac = (((v[1].XYZ.X - m_context->XYOFFSET.OFX) >> 4) & 0xf); + const int y1_frac = (((v[1].XYZ.Y - m_context->XYOFFSET.OFY) >> 4) & 0xf); if (PRIM->FST) { - m_conf.cb_vs.texture_offset.x = 6.0f + (0.25f * tex->m_scale); - m_conf.cb_vs.texture_offset.y = 6.0f + (0.25f * tex->m_scale); + if (!(x1_frac & 8)) + m_conf.cb_vs.texture_offset.x = 6.0f + (0.25f * tex->m_scale); + if (!(y1_frac & 8)) + m_conf.cb_vs.texture_offset.y = 6.0f + (0.25f * tex->m_scale); } else { - const GSVertex* v = &m_vertex.buff[0]; const float tw = static_cast(1 << m_cached_ctx.TEX0.TW); const float th = static_cast(1 << m_cached_ctx.TEX0.TH); const float q = v[0].RGBAQ.Q; @@ -6346,10 +6357,27 @@ __ri void GSRendererHW::DrawPrims(GSTextureCache::Target* rt, GSTextureCache::Ta const int unscaled_y = rt_or_ds ? rt_or_ds->GetUnscaledHeight() : 0; sx = 2.0f / (unscaled_x << 4); sy = 2.0f / (unscaled_y << 4); - if ((!tex || !tex->m_from_target || tex->m_scale > 1.0f) && GSConfig.UserHacks_HalfPixelOffset == GSHalfPixelOffset::NativeWTexOffset) + + if ((!tex || !tex->m_from_target || tex->m_scale > 1.0f) && !m_downscale_source && GSConfig.UserHacks_HalfPixelOffset == GSHalfPixelOffset::NativeWTexOffset) { ox2 = (-1.0f / (unscaled_x * rtscale)); oy2 = (-1.0f / (unscaled_y * rtscale)); + + // Having the vertex negatively offset is a common thing for copying sprites but this causes problems when upscaling, so we need to further adjust the offset. + if (m_vt.m_primclass == GS_SPRITE_CLASS && rtscale > 1.0f && PRIM->FST) + { + const GSVertex* v = &m_vertex.buff[0]; + const int x1_frac = (((v[1].XYZ.X - m_context->XYOFFSET.OFX) >> 4) & 0xf); + const int y1_frac = (((v[1].XYZ.Y - m_context->XYOFFSET.OFY) >> 4) & 0xf); + if (x1_frac & 8) + { + ox2 *= 1.0f + (((x1_frac / 16.0f) - 0.1f) * rtscale); + } + if (y1_frac & 8) + { + oy2 *= 1.0f + (((y1_frac / 16.0f) - 0.1f) * rtscale); + } + } } else {