From d6f8e8017726f714e0465ec7ec4d9c43bdc66af0 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Mon, 1 Mar 2021 02:24:15 +0100 Subject: [PATCH] Fix portals not working in softpoly (#1323) --- .../polyrenderer/drawers/poly_thread.cpp | 14 +- .../polyrenderer/drawers/poly_thread.h | 2 + .../drawers/screen_scanline_setup.cpp | 8 +- .../polyrenderer/drawers/screen_triangle.cpp | 179 +++++++++--------- .../polyrenderer/drawers/screen_triangle.h | 5 - 5 files changed, 105 insertions(+), 103 deletions(-) diff --git a/src/common/rendering/polyrenderer/drawers/poly_thread.cpp b/src/common/rendering/polyrenderer/drawers/poly_thread.cpp index 67cc1e688..d90741399 100644 --- a/src/common/rendering/polyrenderer/drawers/poly_thread.cpp +++ b/src/common/rendering/polyrenderer/drawers/poly_thread.cpp @@ -186,13 +186,8 @@ void PolyTriangleThreadData::SetDepthFunc(int func) void PolyTriangleThreadData::SetDepthRange(float min, float max) { - // The only two variants used by hwrenderer layer - if (min == 0.0f && max == 1.0f) - { - } - else if (min == 1.0f && max == 1.0f) - { - } + DepthRangeStart = min; + DepthRangeScale = max - min; } void PolyTriangleThreadData::SetDepthBias(float depthBiasConstantFactor, float depthBiasSlopeFactor) @@ -210,19 +205,18 @@ void PolyTriangleThreadData::SetStencil(int stencilRef, int op) StencilTestValue = stencilRef; if (op == SOP_Increment) { - WriteStencil = StencilTest; StencilWriteValue = MIN(stencilRef + 1, (int)255); } else if (op == SOP_Decrement) { - WriteStencil = StencilTest; StencilWriteValue = MAX(stencilRef - 1, (int)0); } else // SOP_Keep { - WriteStencil = false; StencilWriteValue = stencilRef; } + + WriteStencil = StencilTest && (StencilTestValue != StencilWriteValue); } void PolyTriangleThreadData::SetCulling(int mode) diff --git a/src/common/rendering/polyrenderer/drawers/poly_thread.h b/src/common/rendering/polyrenderer/drawers/poly_thread.h index 66ea42641..3cc352285 100644 --- a/src/common/rendering/polyrenderer/drawers/poly_thread.h +++ b/src/common/rendering/polyrenderer/drawers/poly_thread.h @@ -174,6 +174,8 @@ public: bool WriteDepth = true; uint8_t StencilTestValue = 0; uint8_t StencilWriteValue = 0; + float DepthRangeStart = 0.0f; + float DepthRangeScale = 1.0f; void (*FragmentShader)(int x0, int x1, PolyTriangleThreadData* thread) = nullptr; void (*WriteColorFunc)(int y, int x0, int x1, PolyTriangleThreadData* thread) = nullptr; diff --git a/src/common/rendering/polyrenderer/drawers/screen_scanline_setup.cpp b/src/common/rendering/polyrenderer/drawers/screen_scanline_setup.cpp index e35b826ec..5aa4855d6 100644 --- a/src/common/rendering/polyrenderer/drawers/screen_scanline_setup.cpp +++ b/src/common/rendering/polyrenderer/drawers/screen_scanline_setup.cpp @@ -70,11 +70,13 @@ void WriteW(int y, int x0, int x1, const TriDrawTriangleArgs* args, PolyTriangle mposW = _mm_add_ps(mposW, mstepW); } - posW += ssecount * stepW; + mstepW = _mm_set_ss(stepW); for (int x = sseend; x < x1; x++) { - w[x] = 1.0f / posW; - posW += stepW; + __m128 res = _mm_rcp_ss(mposW); + __m128 muls = _mm_mul_ss(mposW, _mm_mul_ss(res, res)); + _mm_store_ss(w + x, _mm_sub_ss(_mm_add_ss(res, res), muls)); + mposW = _mm_add_ss(mposW, mstepW); } } #endif diff --git a/src/common/rendering/polyrenderer/drawers/screen_triangle.cpp b/src/common/rendering/polyrenderer/drawers/screen_triangle.cpp index d7c80442e..53c9afabe 100644 --- a/src/common/rendering/polyrenderer/drawers/screen_triangle.cpp +++ b/src/common/rendering/polyrenderer/drawers/screen_triangle.cpp @@ -34,19 +34,28 @@ static void WriteDepth(int y, int x0, int x1, PolyTriangleThreadData* thread) { - size_t pitch = thread->depthstencil->Width(); - float* line = thread->depthstencil->DepthValues() + pitch * y; - float* w = thread->scanline.W; - for (int x = x0; x < x1; x++) + float* line = thread->depthstencil->DepthValues() + (size_t)thread->depthstencil->Width() * y; + + if (thread->DepthRangeScale != 0.0f) { - line[x] = w[x]; + float* w = thread->scanline.W; + for (int x = x0; x < x1; x++) + { + line[x] = w[x]; + } + } + else // portal fills always uses DepthRangeStart = 1 and DepthRangeScale = 0 + { + for (int x = x0; x < x1; x++) + { + line[x] = 65536.0f; + } } } static void WriteStencil(int y, int x0, int x1, PolyTriangleThreadData* thread) { - size_t pitch = thread->depthstencil->Width(); - uint8_t* line = thread->depthstencil->StencilValues() + pitch * y; + uint8_t* line = thread->depthstencil->StencilValues() + (size_t)thread->depthstencil->Width() * y; uint8_t value = thread->StencilWriteValue; for (int x = x0; x < x1; x++) { @@ -54,11 +63,16 @@ static void WriteStencil(int y, int x0, int x1, PolyTriangleThreadData* thread) } } -static void DrawSpan(int y, int x0, int x1, const TriDrawTriangleArgs* args, PolyTriangleThreadData* thread) +static void RunFragmentShader(int y, int x0, int x1, const TriDrawTriangleArgs* args, PolyTriangleThreadData* thread) { WriteVaryings(y, x0, x1, args, thread); - thread->FragmentShader(x0, x1, thread); +} + +static void DrawSpan(int y, int x0, int x1, const TriDrawTriangleArgs* args, PolyTriangleThreadData* thread) +{ + if (thread->WriteColor || thread->AlphaTest) + RunFragmentShader(y, x0, x1, args, thread); if (!thread->AlphaTest) { @@ -92,88 +106,83 @@ static void DrawSpan(int y, int x0, int x1, const TriDrawTriangleArgs* args, Pol } } -template -static void TestSpan(int y, int x0, int x1, const TriDrawTriangleArgs* args, PolyTriangleThreadData* thread) +static void NoTestSpan(int y, int x0, int x1, const TriDrawTriangleArgs* args, PolyTriangleThreadData* thread) +{ + WriteW(y, x0, x1, args, thread); + DrawSpan(y, x0, x1, args, thread); +} + +static void DepthTestSpan(int y, int x0, int x1, const TriDrawTriangleArgs* args, PolyTriangleThreadData* thread) { WriteW(y, x0, x1, args, thread); - if ((OptT::Flags & SWTRI_DepthTest) || (OptT::Flags & SWTRI_StencilTest)) + float* zbufferLine = thread->depthstencil->DepthValues() + (size_t)thread->depthstencil->Width() * y; + float* w = thread->scanline.W; + float depthbias = thread->depthbias; + + int x = x0; + int xend = x1; + while (x < xend) { - size_t pitch = thread->depthstencil->Width(); + int xstart = x; - uint8_t* stencilbuffer; - uint8_t* stencilLine; - uint8_t stencilTestValue; - if (OptT::Flags & SWTRI_StencilTest) + while (zbufferLine[x] >= w[x] + depthbias && x < xend) + x++; + + if (x > xstart) { - stencilbuffer = thread->depthstencil->StencilValues(); - stencilLine = stencilbuffer + pitch * y; - stencilTestValue = thread->StencilTestValue; + DrawSpan(y, xstart, x, args, thread); } - float* zbuffer; - float* zbufferLine; - float* w; - float depthbias; - if (OptT::Flags & SWTRI_DepthTest) - { - zbuffer = thread->depthstencil->DepthValues(); - zbufferLine = zbuffer + pitch * y; - w = thread->scanline.W; - depthbias = thread->depthbias; - } - - int x = x0; - int xend = x1; - while (x < xend) - { - int xstart = x; - - if ((OptT::Flags & SWTRI_DepthTest) && (OptT::Flags & SWTRI_StencilTest)) - { - while (zbufferLine[x] >= w[x] + depthbias && stencilLine[x] == stencilTestValue && x < xend) - x++; - } - else if (OptT::Flags & SWTRI_DepthTest) - { - while (zbufferLine[x] >= w[x] + depthbias && x < xend) - x++; - } - else if (OptT::Flags & SWTRI_StencilTest) - { - while (stencilLine[x] == stencilTestValue && x < xend) - x++; - } - else - { - x = xend; - } - - if (x > xstart) - { - DrawSpan(y, xstart, x, args, thread); - } - - if ((OptT::Flags & SWTRI_DepthTest) && (OptT::Flags & SWTRI_StencilTest)) - { - while ((zbufferLine[x] < w[x] + depthbias || stencilLine[x] != stencilTestValue) && x < xend) - x++; - } - else if (OptT::Flags & SWTRI_DepthTest) - { - while (zbufferLine[x] < w[x] + depthbias && x < xend) - x++; - } - else if (OptT::Flags & SWTRI_StencilTest) - { - while (stencilLine[x] != stencilTestValue && x < xend) - x++; - } - } + while (zbufferLine[x] < w[x] + depthbias && x < xend) + x++; } - else +} + +static void DepthStencilTestSpan(int y, int x0, int x1, const TriDrawTriangleArgs* args, PolyTriangleThreadData* thread) +{ + uint8_t* stencilLine = thread->depthstencil->StencilValues() + (size_t)thread->depthstencil->Width() * y; + uint8_t stencilTestValue = thread->StencilTestValue; + + int x = x0; + int xend = x1; + while (x < xend) { - DrawSpan(y, x0, x1, args, thread); + int xstart = x; + while (stencilLine[x] == stencilTestValue && x < xend) + x++; + + if (x > xstart) + { + DepthTestSpan(y, xstart, x, args, thread); + } + + while (stencilLine[x] != stencilTestValue && x < xend) + x++; + } +} + +static void StencilTestSpan(int y, int x0, int x1, const TriDrawTriangleArgs* args, PolyTriangleThreadData* thread) +{ + uint8_t* stencilLine = thread->depthstencil->StencilValues() + (size_t)thread->depthstencil->Width() * y; + uint8_t stencilTestValue = thread->StencilTestValue; + + int x = x0; + int xend = x1; + while (x < xend) + { + int xstart = x; + while (stencilLine[x] == stencilTestValue && x < xend) + x++; + + if (x > xstart) + { + WriteW(y, x0, x1, args, thread); + DrawSpan(y, xstart, x, args, thread); + } + + while (stencilLine[x] != stencilTestValue && x < xend) + x++; } } @@ -287,8 +296,8 @@ void ScreenTriangle::Draw(const TriDrawTriangleArgs* args, PolyTriangleThreadDat void(*ScreenTriangle::TestSpanOpts[])(int y, int x0, int x1, const TriDrawTriangleArgs* args, PolyTriangleThreadData* thread) = { - &TestSpan, - &TestSpan, - &TestSpan, - &TestSpan + &NoTestSpan, + &DepthTestSpan, + &StencilTestSpan, + &DepthStencilTestSpan }; diff --git a/src/common/rendering/polyrenderer/drawers/screen_triangle.h b/src/common/rendering/polyrenderer/drawers/screen_triangle.h index 24af61699..db63f2547 100644 --- a/src/common/rendering/polyrenderer/drawers/screen_triangle.h +++ b/src/common/rendering/polyrenderer/drawers/screen_triangle.h @@ -122,8 +122,3 @@ enum SWTestSpan SWTRI_DepthTest = 1, SWTRI_StencilTest = 2 }; - -struct TestSpanOpt0 { static const int Flags = 0; }; -struct TestSpanOpt1 { static const int Flags = 1; }; -struct TestSpanOpt2 { static const int Flags = 2; }; -struct TestSpanOpt3 { static const int Flags = 3; };