mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-01 14:58:14 +00:00
softgpu: Interpolate lines to pixel centers, so the last pixel reaches v1
DrawLine weighted the endpoints by (steps - i) / steps with i running 0 to steps - 1, which samples each pixel's leading edge. The last pixel therefore sat a full step short of v1 and the end vertex's values were never used at all. Visible in gpu/texmtx/prims, whose line strip ends exactly on the bottom-left pixel: with normal-projected texgen that pixel should carry v3's texcoords (texel 0, 255) and we produced (1, 254). Working the interpolation out by hand against the hardware reference pins the correct parameter at (i + 0.5) / steps, the pixel center - the same rule the triangle and sprite paths now use. Sampling the endpoint itself is wrong too: that gives (0, 0), because t/q lands on exactly 256 and wraps. Kept in halves so the color interpolation stays integer. The textual half of gpu/texmtx/prims now matches the hardware reference exactly. The test still fails on its screenshot comparison, whose MSE is unchanged to six decimals - that's a different primitive type, not the lines. 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
d603396f30
commit
91e9b73b45
1 file changed
+15
-11
+15
-11
@@ -1719,7 +1719,11 @@ void DrawLine(const VertexData &v0, const VertexData &v1, const BinCoords &range
|
||||
double x = a.x > b.x ? a.x - 1 : a.x;
|
||||
double y = a.y > b.y ? a.y - 1 : a.y;
|
||||
double z = a.z;
|
||||
const int steps1 = steps == 0 ? 1 : steps;
|
||||
// Interpolate to the center of each drawn pixel, i.e. parameter (i + 0.5) / steps. Dividing by
|
||||
// steps with a plain i sampled the leading edge instead, so the last pixel came up a full step
|
||||
// short of v1 and never saw the end vertex's values at all. Kept in halves so the color
|
||||
// interpolation below stays integer: v0's weight is (stepsH - iH) and v1's is iH, over stepsH.
|
||||
const int stepsH = steps <= 0 ? 2 : steps * 2;
|
||||
for (int i = 0; i < steps; i++) {
|
||||
DrawingCoords p = TransformUnit::ScreenToDrawing(x, y);
|
||||
|
||||
@@ -1742,8 +1746,8 @@ void DrawLine(const VertexData &v0, const VertexData &v1, const BinCoords &range
|
||||
Vec4<int> prim_color;
|
||||
Vec3<int> sec_color;
|
||||
if (interpolateColor) {
|
||||
prim_color = (v0_c0 * (steps - i) + v1_c0 * i) / steps1;
|
||||
sec_color = (v0_c1 * (steps - i) + v1_c1 * i) / steps1;
|
||||
prim_color = (v0_c0 * (stepsH - (2 * i + 1)) + v1_c0 * (2 * i + 1)) / stepsH;
|
||||
sec_color = (v0_c1 * (stepsH - (2 * i + 1)) + v1_c1 * (2 * i + 1)) / stepsH;
|
||||
} else {
|
||||
prim_color = v1_c0;
|
||||
sec_color = v1_c1;
|
||||
@@ -1751,7 +1755,7 @@ void DrawLine(const VertexData &v0, const VertexData &v1, const BinCoords &range
|
||||
|
||||
u8 fog = 255;
|
||||
if (pixelID.applyFog) {
|
||||
fog = ClampFogDepth((v0.fogdepth * (float)(steps - i) + v1.fogdepth * (float)i) / steps1);
|
||||
fog = ClampFogDepth((v0.fogdepth * (float)(stepsH - (2 * i + 1)) + v1.fogdepth * (float)(2 * i + 1)) / stepsH);
|
||||
}
|
||||
|
||||
if (state.antialiasLines) {
|
||||
@@ -1764,26 +1768,26 @@ void DrawLine(const VertexData &v0, const VertexData &v1, const BinCoords &range
|
||||
float s, s1;
|
||||
float t, t1;
|
||||
if (state.throughMode) {
|
||||
Vec2<float> tc = (v0.texturecoords.uv() * (float)(steps - i) + v1.texturecoords.uv() * (float)i) / steps1;
|
||||
Vec2<float> tc1 = (v0.texturecoords.uv() * (float)(steps - i - 1) + v1.texturecoords.uv() * (float)(i + 1)) / steps1;
|
||||
Vec2<float> tc = (v0.texturecoords.uv() * (float)(stepsH - (2 * i + 1)) + v1.texturecoords.uv() * (float)(2 * i + 1)) / stepsH;
|
||||
Vec2<float> tc1 = (v0.texturecoords.uv() * (float)(stepsH - (2 * i + 3)) + v1.texturecoords.uv() * (float)(2 * i + 3)) / stepsH;
|
||||
|
||||
s = tc.s() * (1.0f / (float)(1 << state.samplerID.width0Shift));
|
||||
s1 = tc1.s() * (1.0f / (float)(1 << state.samplerID.width0Shift));
|
||||
t = tc.t() * (1.0f / (float)(1 << state.samplerID.height0Shift));
|
||||
t1 = tc1.t() * (1.0f / (float)(1 << state.samplerID.height0Shift));
|
||||
} else if (state.textureProj) {
|
||||
GetTextureCoordinatesProj(v0, v1, (float)(steps - i) / steps1, s, t);
|
||||
GetTextureCoordinatesProj(v0, v1, (float)(steps - i - 1) / steps1, s1, t1);
|
||||
GetTextureCoordinatesProj(v0, v1, (float)(stepsH - (2 * i + 1)) / stepsH, s, t);
|
||||
GetTextureCoordinatesProj(v0, v1, (float)(stepsH - (2 * i + 3)) / stepsH, s1, t1);
|
||||
} else {
|
||||
// Texture coordinate interpolation must definitely be perspective-correct.
|
||||
GetTextureCoordinates(v0, v1, (float)(steps - i) / steps1, s, t);
|
||||
GetTextureCoordinates(v0, v1, (float)(steps - i - 1) / steps1, s1, t1);
|
||||
GetTextureCoordinates(v0, v1, (float)(stepsH - (2 * i + 1)) / stepsH, s, t);
|
||||
GetTextureCoordinates(v0, v1, (float)(stepsH - (2 * i + 3)) / stepsH, s1, t1);
|
||||
}
|
||||
|
||||
// If inc is 0, force the delta to zero.
|
||||
float ds = xinc == 0.0 ? 0.0f : (s1 - s) * (float)SCREEN_SCALE_FACTOR * (1.0f / xinc);
|
||||
float dt = yinc == 0.0 ? 0.0f : (t1 - t) * (float)SCREEN_SCALE_FACTOR * (1.0f / yinc);
|
||||
float w = (v0.clipw * (float)(steps - i) + v1.clipw * (float)i) / steps1;
|
||||
float w = (v0.clipw * (float)(stepsH - (2 * i + 1)) + v1.clipw * (float)(2 * i + 1)) / stepsH;
|
||||
|
||||
int texLevel;
|
||||
int texLevelFrac;
|
||||
|
||||
Reference in new issue
Block a user