From e896203f32435753efef4b01bbdd2f92b164225d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 9 Oct 2026 15:43:17 +0200 Subject: [PATCH] Reinterpret between 16- and 32-bit framebuffers by PSP pixel at higher render scales The 16-to-32-bit reinterpret sampled a quarter texel either side of the render pixel, which only lands in the two 16-bit halves of a 32-bit pixel at 1x: at 3x, two of every three render pixels took both halves from the same 16-bit pixel. The 32-to-16-bit one picked the half by render pixel too. Now both go by the PSP pixel. Cars Race-O-Rama rewrites its 8888 frame through 565 views in 16-pixel columns, and drew vertical stripes at 2x and up (#15914); now it renders like 1x. Nothing changes at 1x. Co-Authored-By: Claude Opus 5.5 --- GPU/Common/ReinterpretFramebuffer.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/GPU/Common/ReinterpretFramebuffer.cpp b/GPU/Common/ReinterpretFramebuffer.cpp index d22108c966..f630e2dc85 100644 --- a/GPU/Common/ReinterpretFramebuffer.cpp +++ b/GPU/Common/ReinterpretFramebuffer.cpp @@ -165,8 +165,11 @@ Draw2DPipelineInfo GenerateReinterpretFragmentShader(ShaderWriter &writer, GEBuf } else if (IsBufferFormat16Bit(from) && !IsBufferFormat16Bit(to)) { // 16-to-32-bit (two pixels, draw size is halved) - writer.C(" vec4 valLeft = ").SampleTexture2D("tex", "v_texcoord.xy + vec2(-0.25 / texSize.x, 0.0)").C(";\n"); - writer.C(" vec4 valRight = ").SampleTexture2D("tex", "v_texcoord.xy + vec2(0.25 / texSize.x, 0.0)").C(";\n"); + // The two 16-bit pixels of the PSP pixel this is in, at their centers: at a higher render scale, the render + // pixels around this one's can both be in the same 16-bit pixel. + writer.C(" float pspX = floor(v_texcoord.x * texSize.x / (2.0 * scaleFactor));\n"); + writer.C(" vec4 valLeft = ").SampleTexture2D("tex", "vec2((2.0 * pspX + 0.5) * scaleFactor / texSize.x, v_texcoord.y)").C(";\n"); + writer.C(" vec4 valRight = ").SampleTexture2D("tex", "vec2((2.0 * pspX + 1.5) * scaleFactor / texSize.x, v_texcoord.y)").C(";\n"); writer.C(" vec4 outColor = unpackColor(packColor(valLeft), packColor(valRight));\n"); _assert_("not yet implemented"); @@ -174,7 +177,8 @@ Draw2DPipelineInfo GenerateReinterpretFragmentShader(ShaderWriter &writer, GEBuf // 32-to-16-bit (half of the pixel, draw size is doubled). writer.C(" vec4 val = ").SampleTexture2D("tex", "v_texcoord.xy").C(";\n"); - writer.C(" float u = mod(floor(v_texcoord.x * texSize.x * 2.0), 2.0);\n"); + // Which half, by the 16-bit PSP pixel this is in (not the render pixel). + writer.C(" float u = mod(floor(v_texcoord.x * texSize.x * 2.0 / scaleFactor), 2.0);\n"); writer.C(" vec4 outColor = unpackColor(u == 0.0 ? packColor(val.rg) : packColor(val.ba));\n"); }