From c9623374b1da0a8d02a545e51da9abbaede4356f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 10 Jun 2026 15:29:18 +0200 Subject: [PATCH] Fix some issues with sprite border fix for RECT primitives --- GPU/Common/SoftwareTransformCommon.cpp | 65 +++++++++++++++----------- assets/compat.ini | 4 ++ 2 files changed, 41 insertions(+), 28 deletions(-) diff --git a/GPU/Common/SoftwareTransformCommon.cpp b/GPU/Common/SoftwareTransformCommon.cpp index 31c165e6b8..a27d3296bc 100644 --- a/GPU/Common/SoftwareTransformCommon.cpp +++ b/GPU/Common/SoftwareTransformCommon.cpp @@ -1012,20 +1012,41 @@ static bool ExpandRectangles(int vertexCount, int &numDecodedVerts, int vertsSiz } bool pixelMapped = g_Config.bSmart2DTexFiltering && !gstate_c.textureIsVideo; + if (pixelMapped) { + // Check for pixel mapping. If we find pixel mapping, abandon spriteBorderFix. + for (int i = 0; i < vertexCount; i += 2) { + const TransformedVertex &transVtxTL = transformed[indsIn[i + 0]]; + const TransformedVertex &transVtxBR = transformed[indsIn[i + 1]]; + + if (pixelMapped) { + float dx = transVtxBR.x - transVtxTL.x; + float dy = transVtxBR.y - transVtxTL.y; + float du = transVtxBR.u - transVtxTL.u; + float dv = transVtxBR.v - transVtxTL.v; + + // NOTE: We will accept it as pixel mapped if only one dimension is stretched. This fixes dialog frames in FFI. + // Though, there could be false positives in other games due to this. Let's see if it is a problem... + if (dx <= 0 || dy <= 0 || (dx != du && dy != dv)) { + pixelMapped = false; + break; + } + } + } + } float spriteBorderFixL = 0.0f; float spriteBorderFixR = 0.0f; float spriteBorderFixT = 0.0f; float spriteBorderFixB = 0.0f; - float spriteBorderFix = PSP_CoreParameter().compat.flags().SpriteBorderFix; - if (spriteBorderFix && !ShouldApplySpriteBorderFix(gstate)) { - spriteBorderFix = 0.0f; + const float spriteBorderFix = PSP_CoreParameter().compat.flags().SpriteBorderFix; + if (pixelMapped || (spriteBorderFix && !ShouldApplySpriteBorderFix(gstate))) { + // Don't apply spriteBorderFix if pixel mapped. } else { if (spriteBorderFix < 0.0f) { - spriteBorderFixL = (spriteBorderFix / uScale) / gstate_c.curTextureWidth; - spriteBorderFixT = (spriteBorderFix / vScale) / gstate_c.curTextureHeight; - spriteBorderFixR = (spriteBorderFix / uScale) / gstate_c.curTextureWidth; - spriteBorderFixB = (spriteBorderFix / vScale) / gstate_c.curTextureHeight; + spriteBorderFixL = (-spriteBorderFix / uScale) / gstate_c.curTextureWidth; + spriteBorderFixT = (-spriteBorderFix / vScale) / gstate_c.curTextureHeight; + spriteBorderFixR = (-spriteBorderFix / uScale) / gstate_c.curTextureWidth; + spriteBorderFixB = (-spriteBorderFix / vScale) / gstate_c.curTextureHeight; } else if (spriteBorderFix > 0.0f) { spriteBorderFixL = 0.0f; spriteBorderFixR = (spriteBorderFix / uScale) / gstate_c.curTextureWidth; @@ -1034,23 +1055,11 @@ static bool ExpandRectangles(int vertexCount, int &numDecodedVerts, int vertsSiz } } + for (int i = 0; i < vertexCount; i += 2) { const TransformedVertex &transVtxTL = transformed[indsIn[i + 0]]; const TransformedVertex &transVtxBR = transformed[indsIn[i + 1]]; - if (pixelMapped) { - float dx = transVtxBR.x - transVtxTL.x; - float dy = transVtxBR.y - transVtxTL.y; - float du = transVtxBR.u - transVtxTL.u; - float dv = transVtxBR.v - transVtxTL.v; - - // NOTE: We will accept it as pixel mapped if only one dimension is stretched. This fixes dialog frames in FFI. - // Though, there could be false positives in other games due to this. Let's see if it is a problem... - if (dx <= 0 || dy <= 0 || (dx != du && dy != dv)) { - pixelMapped = false; - } - } - float z = transVtxBR.z; // Apply Z clamping. It appears clipping/culling does not affect rectangles, see #12058. // TODO: We might want to make this 65536.999. Since those will pass, and if a game mixes through and non-through... @@ -1065,30 +1074,30 @@ static bool ExpandRectangles(int vertexCount, int &numDecodedVerts, int vertsSiz // bottom right trans[0] = transVtxBR; - trans[0].u = (transVtxBR.u + spriteBorderFixR) * uScale; - trans[0].v = (transVtxBR.v + spriteBorderFixB) * vScale; + trans[0].u = (transVtxBR.u - spriteBorderFixR) * uScale; + trans[0].v = (transVtxBR.v - spriteBorderFixB) * vScale; trans[0].z = z; // top right trans[1] = transVtxBR; trans[1].y = transVtxTL.y; - trans[1].u = (transVtxBR.u + spriteBorderFixR) * uScale; - trans[1].v = (transVtxTL.v - spriteBorderFixT) * vScale; + trans[1].u = (transVtxBR.u - spriteBorderFixR) * uScale; + trans[1].v = (transVtxTL.v + spriteBorderFixT) * vScale; trans[1].z = z; // top left trans[2] = transVtxBR; trans[2].x = transVtxTL.x; trans[2].y = transVtxTL.y; - trans[2].u = (transVtxTL.u - spriteBorderFixL) * uScale; - trans[2].v = (transVtxTL.v - spriteBorderFixT) * vScale; + trans[2].u = (transVtxTL.u + spriteBorderFixL) * uScale; + trans[2].v = (transVtxTL.v + spriteBorderFixT) * vScale; trans[2].z = z; // bottom left trans[3] = transVtxBR; trans[3].x = transVtxTL.x; - trans[3].u = (transVtxTL.u - spriteBorderFixL) * uScale; - trans[3].v = (transVtxBR.v + spriteBorderFixB) * vScale; + trans[3].u = (transVtxTL.u + spriteBorderFixL) * uScale; + trans[3].v = (transVtxBR.v - spriteBorderFixB) * vScale; trans[3].z = z; // That's the four corners. Now process UV rotation. diff --git a/assets/compat.ini b/assets/compat.ini index 72e028198f..523e856eb1 100644 --- a/assets/compat.ini +++ b/assets/compat.ini @@ -2136,3 +2136,7 @@ ULJS00097 = -0.25 ULES00262 = 0.5 ULUS10064 = 0.5 ULKS46087 = 0.5 + +# Tokiden (issue #19422) +# This works in the provided dump, but needs more testing. +# NPJH50878 = -0.4