mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-01 14:58:14 +00:00
softgpu: Fix subpixel rounding of negative screen coords, and a stale +1
Two leftovers from the sample point having been a sixteenth of a pixel off center. They're one commit because they can't be separated: each was compensating for the other, so applying either alone makes gpu/filtering/precisionnearest3d fail. I tried both orderings. 1. DrawRectangle advanced ST to the first sample with (minX - entireX1 + 1). The +1 existed to make up for centerOff being 7 instead of 8; now that minX already sits at the pixel center it double-counts and pushes the texture coordinate a sixteenth of a texel too far. Only visible when that lands exactly on a texel boundary, which is what precisionnearest2d's offset-7 case constructs: the sprite spans x from -7/16, so u at pixel 0's center is 0.9375 and should sample texel 0, but the extra sixteenth made it exactly 1.0. 2. Removing the +1 exposed the other one. ClipToScreenInternal used a plain (int) cast, which truncates toward zero - so once the region offset makes the value negative it rounds the opposite way from the positive case, and from the through-mode path that computes screenpos directly. The two disagreed by one subpixel for negative coordinates, which is why the 2D and 3D variants of the same test failed at different offsets, 7 and 8. floorf is what the +0.375 nudge was always meant to pair with, and it makes both paths agree. Now passing: gpu/filtering/precisionnearest2d, promoted to tests_good since it passes on Vulkan too. precisionlinear2d and precisionlinear3d also start passing on software but still fail on the hardware backends, so they stay in tests_next with a comment saying so, as does gpu/primitives/continue from the last commit. 317 pspautotests pass, 0 fail. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Vd8ntC2brCUtCrDJMqLbs8
This commit is contained in:
1 parent
c9aac4f992
commit
d603396f30
3 files changed
+14
-5
No files matched your search
@@ -1293,8 +1293,11 @@ void DrawRectangle(const VertexData &v0, const VertexData &v1, const BinCoords &
|
||||
}
|
||||
|
||||
// Okay, now move ST to the minX, minY position.
|
||||
rowST += (stx / (float)(SCREEN_SCALE_FACTOR * 2)) * (minX - entireX1 + 1);
|
||||
rowST += (sty / (float)(SCREEN_SCALE_FACTOR * 2)) * (minY - entireY1 + 1);
|
||||
// This is the exact distance from the primitive's edge to the sample point - minX and minY
|
||||
// already sit at the pixel center. The +1 that used to be here was compensating for
|
||||
// TriangleEdge::Start's centerOff being a sixteenth of a pixel short of center.
|
||||
rowST += (stx / (float)(SCREEN_SCALE_FACTOR * 2)) * (minX - entireX1);
|
||||
rowST += (sty / (float)(SCREEN_SCALE_FACTOR * 2)) * (minY - entireY1);
|
||||
}
|
||||
|
||||
// And now what we add to spread out to 4 values.
|
||||
|
||||
@@ -176,8 +176,11 @@ static ScreenCoords ClipToScreenInternal(Vec3f scaled, const ClipCoords &coords,
|
||||
// 16 = 0xFFFF / 4095.9375
|
||||
// Round up at 0.625 to the nearest subpixel.
|
||||
static_assert(SCREEN_SCALE_FACTOR == 16, "Currently only supports scale 16");
|
||||
int x = (int)(scaled.x * 16.0f + 0.375f - gstate.getOffsetX16());
|
||||
int y = (int)(scaled.y * 16.0f + 0.375f - gstate.getOffsetY16());
|
||||
// floorf, not a plain (int) cast: the cast truncates toward zero, so once the region offset
|
||||
// pushes the result negative it rounds the opposite way from the positive case - and from the
|
||||
// through-mode path below, which is what made the two disagree by one subpixel.
|
||||
int x = (int)floorf(scaled.x * 16.0f + 0.375f - gstate.getOffsetX16());
|
||||
int y = (int)floorf(scaled.y * 16.0f + 0.375f - gstate.getOffsetY16());
|
||||
return ScreenCoords(x, y, scaled.z);
|
||||
}
|
||||
|
||||
|
||||
@@ -167,6 +167,7 @@ tests_good = [
|
||||
"gpu/displaylist/alignment",
|
||||
"gpu/dither/dither",
|
||||
"gpu/filtering/mipmaplinear",
|
||||
"gpu/filtering/precisionnearest2d",
|
||||
"gpu/filtering/precisionnearest3d",
|
||||
"gpu/ge/break",
|
||||
"gpu/ge/context",
|
||||
@@ -424,12 +425,14 @@ tests_next = [
|
||||
"gpu/displaylist/state",
|
||||
"gpu/filtering/linear",
|
||||
"gpu/filtering/nearest",
|
||||
# These two pass with --graphics=software, but still fail on the hardware backends,
|
||||
# so they stay here rather than in tests_good until those match too.
|
||||
"gpu/filtering/precisionlinear2d",
|
||||
"gpu/filtering/precisionlinear3d",
|
||||
"gpu/filtering/precisionnearest2d",
|
||||
"gpu/ge/edramswizzle",
|
||||
"gpu/ge/get",
|
||||
"gpu/primitives/bezier",
|
||||
# Passes with --graphics=software, still fails on the hardware backends.
|
||||
"gpu/primitives/continue",
|
||||
"gpu/primitives/immediate",
|
||||
"gpu/primitives/lines",
|
||||
|
||||
Reference in new issue
Block a user