From 5ca5c1a4a1fdc5e249fc452722176cce3af37645 Mon Sep 17 00:00:00 2001 From: Jaklyy <102590697+Jaklyy@users.noreply.github.com> Date: Fri, 2 Aug 2024 13:34:05 -0400 Subject: [PATCH] rework entire fix to do things in a (potentially) more hw accurate way also remove some tangentially related but kinda dumb code i wrote --- src/GPU3D_Soft.cpp | 42 ++++++++++++++++-------- src/GPU3D_Soft.h | 79 ++++++++-------------------------------------- 2 files changed, 43 insertions(+), 78 deletions(-) diff --git a/src/GPU3D_Soft.cpp b/src/GPU3D_Soft.cpp index 1221ed59..7f03b3b7 100644 --- a/src/GPU3D_Soft.cpp +++ b/src/GPU3D_Soft.cpp @@ -757,6 +757,12 @@ void SoftRenderer::RenderShadowMaskScanline(const GPU3D& gpu3d, RendererPolygon* s32 zl = rp->SlopeL.Interp.InterpolateZ(polygon->FinalZ[rp->CurVL], polygon->FinalZ[rp->NextVL], polygon->WBuffer); s32 zr = rp->SlopeR.Interp.InterpolateZ(polygon->FinalZ[rp->CurVR], polygon->FinalZ[rp->NextVR], polygon->WBuffer); + + rp->SlopeL.EdgeParams(&l_edgelen, &l_edgecov); + rp->SlopeR.EdgeParams(&r_edgelen, &r_edgecov); + + if (rp->SlopeL.XMajor && rp->SlopeL.Negative) xstart -= l_edgelen; + if (rp->SlopeR.XMajor && !rp->SlopeR.Negative) xend += r_edgelen; // right vertical edges are pushed 1px to the left as long as either: // the left edge slope is not 0, or the span is not 0 pixels wide, and it is not at the leftmost pixel of the screen @@ -773,11 +779,14 @@ void SoftRenderer::RenderShadowMaskScanline(const GPU3D& gpu3d, RendererPolygon* interp_start = &rp->SlopeR.Interp; interp_end = &rp->SlopeL.Interp; - - rp->SlopeR.EdgeParams(&l_edgelen, &l_edgecov); - rp->SlopeL.EdgeParams(&r_edgelen, &r_edgecov); - + std::swap(xstart, xend); + + l_edgelen = 1; + r_edgelen = 1; + + // ignore fixing coverage, shadow masks don't use it + std::swap(wl, wr); std::swap(zl, zr); @@ -806,9 +815,6 @@ void SoftRenderer::RenderShadowMaskScanline(const GPU3D& gpu3d, RendererPolygon* interp_start = &rp->SlopeL.Interp; interp_end = &rp->SlopeR.Interp; - rp->SlopeL.EdgeParams(&l_edgelen, &l_edgecov); - rp->SlopeR.EdgeParams(&r_edgelen, &r_edgecov); - // CHECKME: edge fill rules for unswapped opaque shadow mask polygons if ((gpu3d.RenderDispCnt & ((1<<4)|(1<<5))) || ((polyalpha < 31) && (gpu3d.RenderDispCnt & (1<<3))) || wireframe) { @@ -982,6 +988,12 @@ void SoftRenderer::RenderPolygonScanline(const GPU& gpu, RendererPolygon* rp, s3 s32 zl = rp->SlopeL.Interp.InterpolateZ(polygon->FinalZ[rp->CurVL], polygon->FinalZ[rp->NextVL], polygon->WBuffer); s32 zr = rp->SlopeR.Interp.InterpolateZ(polygon->FinalZ[rp->CurVR], polygon->FinalZ[rp->NextVR], polygon->WBuffer); + + rp->SlopeL.EdgeParams(&l_edgelen, &l_edgecov); + rp->SlopeR.EdgeParams(&r_edgelen, &r_edgecov); + + if (rp->SlopeL.XMajor && rp->SlopeL.Negative) xstart -= l_edgelen; + if (rp->SlopeR.XMajor && !rp->SlopeR.Negative) xend += r_edgelen; // right vertical edges are pushed 1px to the left as long as either: // the left edge slope is not 0, or the span is not 0 pixels wide, and it is not at the leftmost pixel of the screen @@ -1003,10 +1015,17 @@ void SoftRenderer::RenderPolygonScanline(const GPU& gpu, RendererPolygon* rp, s3 interp_start = &rp->SlopeR.Interp; interp_end = &rp->SlopeL.Interp; - rp->SlopeR.EdgeParams(&l_edgelen, &l_edgecov); - rp->SlopeL.EdgeParams(&r_edgelen, &r_edgecov); - std::swap(xstart, xend); + + l_edgelen = 1; + r_edgelen = 1; + + std::swap(l_edgecov, r_edgecov); + + // yes this breaks vertical slopes, blame hw + if (!rp->SlopeR.XMajor) l_edgecov = 31-l_edgecov; + if (!rp->SlopeL.XMajor) r_edgecov = 31-r_edgecov; + std::swap(wl, wr); std::swap(zl, zr); @@ -1041,9 +1060,6 @@ void SoftRenderer::RenderPolygonScanline(const GPU& gpu, RendererPolygon* rp, s3 interp_start = &rp->SlopeL.Interp; interp_end = &rp->SlopeR.Interp; - rp->SlopeL.EdgeParams(&l_edgelen, &l_edgecov); - rp->SlopeR.EdgeParams(&r_edgelen, &r_edgecov); - // edge fill rules for unswapped opaque edges: // * right edge is filled if slope > 1 // * left edge is filled if slope <= 1 diff --git a/src/GPU3D_Soft.h b/src/GPU3D_Soft.h index e42b2ca2..85d500dc 100644 --- a/src/GPU3D_Soft.h +++ b/src/GPU3D_Soft.h @@ -295,11 +295,11 @@ private: XMajor = (Increment > 0x40000); - if constexpr (side) + if (side) { // right - if (XMajor) dx = Negative ? (0x20000 + 0x40000) : (Increment - 0x20000); + if (XMajor) dx = Negative ? (0x20000 + 0x40000) : -0x20000; else if (Increment != 0) dx = Negative ? 0x40000 : 0; else dx = 0; } @@ -307,27 +307,15 @@ private: { // left - if (XMajor) dx = Negative ? ((Increment - 0x20000) + 0x40000) : 0x20000; + if (XMajor) dx = 0x20000; else if (Increment != 0) dx = Negative ? 0x40000 : 0; else dx = 0; } dx += (y - y0) * Increment; - if (XMajor) - { - // used for calculating AA coverage - xcov_incr = (ylen << 10) / xlen; - - if (side ^ Negative) - { - dxold = dx; - // I dont think the first span can have a gap but - // I think its technically correct to do this calc anyway? - // could probably be removed as a minor optimization - dx &= ~0x1FF; - } - } + // used for calculating AA coverage + if (XMajor) xcov_incr = (ylen << 10) / xlen; s32 x = XVal(); @@ -340,15 +328,7 @@ private: constexpr s32 Step() { - if (XMajor && (side ^ Negative)) // tl, br = \ (right side end) & tr, bl = / (left side start) - { - // round dx; required to create gaps in lines like on hw - // increment using dxold to make the line not completely borked after rendering a gap - dx = (dxold & ~0x1FF) + Increment; - dxold += Increment; - } - else - dx += Increment; + dx += Increment; y++; @@ -363,26 +343,13 @@ private: if (Negative) ret = x0 - (dx >> 18); else ret = x0 + (dx >> 18); - if (ret < xmin) ret = xmin; - else if (ret > xmax) ret = xmax; return ret; } - template constexpr void EdgeParams_XMajor(s32* length, s32* coverage) const { - // only do length calc for right side when swapped as it's - // only needed for aa calcs, as actual line spans are broken - if constexpr (!swapped || side) - { - // credit to StrikerX3 for working out this weird rounding nonsense - if (side ^ Negative) // tr, bl = / (left side end) & tl br = \ (right side start) - // dxold used here to avoid rounding the endpoint - *length = (dx >> 18) - (dxold - Increment >> 18); - else // tl, br = \ (left side end) & tr, bl = / (right side start) - // dx rounded down to create gaps in lines like on hw - *length = ((dx & ~0x1FF) + Increment >> 18) - (dx >> 18); - } + // credit to StrikerX3 for their efforts researching the strange rounding behavior of the "length" calculation + *length = (dx & (0x1FF << 9)) + Increment >> 18; // for X-major edges, we return the coverage // for the first pixel, and the increment for @@ -394,49 +361,31 @@ private: s32 startcov = (((startx << 10) + 0x1FF) * ylen) / xlen; *coverage = (1<<31) | ((startcov & 0x3FF) << 12) | (xcov_incr & 0x3FF); - - if constexpr (swapped) *length = 1; } - template constexpr void EdgeParams_YMajor(s32* length, s32* coverage) const { *length = 1; - if (Increment == 0) - { - // for some reason vertical edges' aa values - // are inverted too when the edges are swapped - if constexpr (swapped) - *coverage = 0; - else - *coverage = 31; - } + if (Increment == 0) *coverage = 31; else { s32 cov = ((dx >> 9) + (Increment >> 10)) >> 4; if ((cov >> 5) != (dx >> 18)) cov = 31; cov &= 0x1F; - if constexpr (swapped) - { - if (side ^ Negative) cov = 0x1F - cov; - } - else - { - if (!(side ^ Negative)) cov = 0x1F - cov; - } + + if (!(side ^ Negative)) cov = 0x1F - cov; *coverage = cov; } } - template constexpr void EdgeParams(s32* length, s32* coverage) const { if (XMajor) - return EdgeParams_XMajor(length, coverage); + return EdgeParams_XMajor(length, coverage); else - return EdgeParams_YMajor(length, coverage); + return EdgeParams_YMajor(length, coverage); } s32 Increment; @@ -447,7 +396,7 @@ private: private: s32 x0, xmin, xmax; s32 xlen, ylen; - s32 dx, dxold; + s32 dx; s32 y; s32 xcov_incr;