rework entire fix to do things in a (potentially) more hw accurate way

also remove some tangentially related but kinda dumb code i wrote
This commit is contained in:
Jaklyy 2024-08-02 13:34:05 -04:00
parent 36ff3a41b9
commit 5ca5c1a4a1
2 changed files with 43 additions and 78 deletions

View File

@ -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<true>(&l_edgelen, &l_edgecov);
rp->SlopeL.EdgeParams<true>(&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<false>(&l_edgelen, &l_edgecov);
rp->SlopeR.EdgeParams<false>(&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<true>(&l_edgelen, &l_edgecov);
rp->SlopeL.EdgeParams<true>(&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<false>(&l_edgelen, &l_edgecov);
rp->SlopeR.EdgeParams<false>(&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

View File

@ -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<bool swapped>
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<bool swapped>
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<bool swapped>
constexpr void EdgeParams(s32* length, s32* coverage) const
{
if (XMajor)
return EdgeParams_XMajor<swapped>(length, coverage);
return EdgeParams_XMajor(length, coverage);
else
return EdgeParams_YMajor<swapped>(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;