diff --git a/pcsx2/GS/Renderers/HW/GSHwHack.cpp b/pcsx2/GS/Renderers/HW/GSHwHack.cpp index 9c008e97a4..63eda22b0a 100644 --- a/pcsx2/GS/Renderers/HW/GSHwHack.cpp +++ b/pcsx2/GS/Renderers/HW/GSHwHack.cpp @@ -737,7 +737,7 @@ bool GSHwHack::OI_PointListPalette(GSRendererHW& r, GSTexture* rt, GSTexture* ds { const u32 FBP = r.m_cached_ctx.FRAME.Block(); const u32 FBW = r.m_cached_ctx.FRAME.FBW; - GL_INS("PointListPalette - m_r = <%d, %d => %d, %d>, n_vertices = %zu, FBP = 0x%x, FBW = %u", r.m_r.x, r.m_r.y, r.m_r.z, r.m_r.w, n_vertices, FBP, FBW); + GL_INS("PointListPalette - m_r = <%d, %d => %d, %d>, n_vertices = %u, FBP = 0x%x, FBW = %u", r.m_r.x, r.m_r.y, r.m_r.z, r.m_r.w, n_vertices, FBP, FBW); const GSVertex* RESTRICT v = r.m_vertex.buff; const int ox(r.m_context->XYOFFSET.OFX); const int oy(r.m_context->XYOFFSET.OFY); diff --git a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp index 2f67d82159..89448d7fa3 100644 --- a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp +++ b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp @@ -1670,9 +1670,24 @@ void GSRendererHW::Draw() return; } - // The rectangle of the draw rounded up. - const GSVector4 rect = m_vt.m_min.p.upld(m_vt.m_max.p + GSVector4::cxpr(0.5f)); - m_r = GSVector4i(rect).rintersect(context->scissor.in); + // GS doesn't fill the right or bottom edges of sprites/triangles, and for a pixel to be shaded, the vertex + // must cross the center. In other words, the range is equal to the floor of coordinates +0.5. Except for + // the case where the minimum equals the maximum, because at least one pixel is filled per line. + // Test cases for the math: + // -------------------------------------- + // | Position range | Draw Range | Size | + // | -0.5,0.0 | 0-0 | 1 | + // | -0.5,0.5 | 0-0 | 1 | + // | 0,1 | 0-0 | 1 | + // | 0,1.5 | 0-1 | 2 | + // | 0.5,1.5 | 1-1 | 1 | + // | 0.5,1.75 | 1-1 | 1 | + // | 0.5,2.25 | 1-1 | 1 | + // | 0.5,2.5 | 1-2 | 2 | + // -------------------------------------- + m_r = GSVector4i(m_vt.m_min.p.upld(m_vt.m_max.p) + GSVector4::cxpr(0.5f)); + m_r = m_r.blend8(m_r + GSVector4i::cxpr(0, 0, 1, 1), (m_r.xyxy() == m_r.zwzw())); + m_r = m_r.rintersect(context->scissor.in); const bool process_texture = PRIM->TME && !(PRIM->ABE && m_context->ALPHA.IsBlack() && !m_cached_ctx.TEX0.TCC); const u32 frame_end_bp = GSLocalMemory::GetEndBlockAddress(m_cached_ctx.FRAME.Block(), m_cached_ctx.FRAME.FBW, m_cached_ctx.FRAME.PSM, m_r);