From b6dec1dfdcc336caa17f06127fb1f7bad2460964 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 1 Oct 2026 14:30:03 -0600 Subject: [PATCH] SoftGPU: Setup reciprocal segments from the table's formula Nearly every segment's K is floor(2^39 / (65536 + 256 i) / 16) * 16. The fit to probe data left a few segments loose and slightly low; segment 39 made Blade Dancer's large triangle one depth unit high where the PSP's depth test rejects it (frame dump now exact). Segments 39, 162, 253 and 255 now use the formula, which every probe accepts. Co-Authored-By: Claude Opus 5.5 (1M context) --- GPU/Software/GEMath.cpp | 9 ++++++--- unittest/TestGEMath.cpp | 2 ++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/GPU/Software/GEMath.cpp b/GPU/Software/GEMath.cpp index dda4ee9762..43b0c93378 100644 --- a/GPU/Software/GEMath.cpp +++ b/GPU/Software/GEMath.cpp @@ -152,7 +152,7 @@ static const GESetupRecipSegment geSetupRecip[256] = { { 7669584, -213 }, { 7642288, -212 }, { 7615184, -210 }, { 7588272, -209 }, { 7561552, -208 }, { 7535024, -206 }, { 7508672, -205 }, { 7482512, -203 }, { 7456528, -202 }, { 7430736, -200 }, { 7405104, -199 }, { 7379664, -198 }, - { 7354384, -196 }, { 7329280, -195 }, { 7304352, -194 }, { 7279552, -192 }, + { 7354384, -196 }, { 7329280, -195 }, { 7304352, -194 }, { 7279600, -192 }, { 7255008, -191 }, { 7230576, -190 }, { 7206320, -188 }, { 7182208, -187 }, { 7158272, -186 }, { 7134496, -185 }, { 7110864, -183 }, { 7087392, -182 }, { 7064080, -181 }, { 7040928, -180 }, { 7017920, -179 }, { 6995056, -178 }, @@ -183,7 +183,7 @@ static const GESetupRecipSegment geSetupRecip[256] = { { 5315552, -102 }, { 5302416, -102 }, { 5289360, -101 }, { 5276368, -101 }, { 5263440, -100 }, { 5250560, -100 }, { 5237760, -99 }, { 5225008, -99 }, { 5212336, -98 }, { 5199712, -98 }, { 5187152, -97 }, { 5174656, -97 }, - { 5162208, -96 }, { 5149840, -96 }, { 5137504, -96 }, { 5125248, -95 }, + { 5162208, -96 }, { 5149840, -96 }, { 5137520, -96 }, { 5125248, -95 }, { 5113056, -95 }, { 5100896, -94 }, { 5088816, -94 }, { 5076784, -93 }, { 5064816, -93 }, { 5052896, -92 }, { 5041040, -92 }, { 5029232, -92 }, { 5017472, -91 }, { 5005776, -91 }, { 4994144, -90 }, { 4982560, -90 }, @@ -206,9 +206,12 @@ static const GESetupRecipSegment geSetupRecip[256] = { { 4329600, -68 }, { 4320880, -67 }, { 4312208, -67 }, { 4303568, -67 }, { 4294960, -67 }, { 4286384, -66 }, { 4277840, -66 }, { 4269344, -66 }, { 4260880, -66 }, { 4252432, -65 }, { 4244032, -65 }, { 4235664, -65 }, - { 4227328, -65 }, { 4219008, -64 }, { 4210752, -64 }, { 4202496, -64 }, + { 4227328, -65 }, { 4219024, -64 }, { 4210752, -64 }, { 4202512, -64 }, }; +// Nearly every K is floor(2^39 / (65536 + 256 i) / 16) * 16, the start of segment i in 1/8ths. The table was fit +// to probe data; segments it left loose (39, 161, 162, 253, 255) use that formula, which games confirmed for 39 +// and 161. 105 and 106 differ from it, measured. int64_t GESetupRecip(uint64_t absDet, int *e) { const uint32_t hi = (uint32_t)(absDet >> 32); const int ex = hi ? 63 - (int)clz32_nonzero(hi) : 31 - (int)clz32_nonzero((uint32_t)absDet); diff --git a/unittest/TestGEMath.cpp b/unittest/TestGEMath.cpp index bd8fcf5ed3..34dc48a8f8 100644 --- a/unittest/TestGEMath.cpp +++ b/unittest/TestGEMath.cpp @@ -128,6 +128,8 @@ static bool TestGESetupRecip() { // exp54's Gouraud triangle (det 854491) needs at least 40211 here; exp39 and exp41 bound it from above. int e = 0; EXPECT_EQ_INT(GESetupRecip(65536 + 41275, &e), 40211); + // Blade Dancer's large triangle (det 9668772) needs at least 56859 for its depth (frame dump, index 10001). + EXPECT_EQ_INT(GESetupRecip(9668772, &e), 56859); return true; }