- Use static ifs (C++11 version of them, anyhow) for the triangle draw function

This commit is contained in:
Magnus Norddahl 2018-12-06 03:10:14 +01:00
parent e22e249287
commit 2aefeb6401
2 changed files with 192 additions and 65 deletions

View file

@ -54,6 +54,8 @@ static void SortVertices(const TriDrawTriangleArgs *args, ShadedTriVertex **sort
void ScreenTriangle::Draw(const TriDrawTriangleArgs *args, PolyTriangleThreadData *thread)
{
using namespace TriScreenDrawerModes;
// Sort vertices by Y position
ShadedTriVertex *sortedVertices[3];
SortVertices(args, sortedVertices);
@ -75,8 +77,7 @@ void ScreenTriangle::Draw(const TriDrawTriangleArgs *args, PolyTriangleThreadDat
// Find start/end X positions for each line covered by the triangle:
int leftEdge[MAXHEIGHT];
int rightEdge[MAXHEIGHT];
int16_t edges[MAXHEIGHT * 2];
float longDX = sortedVertices[2]->x - sortedVertices[0]->x;
float longDY = sortedVertices[2]->y - sortedVertices[0]->y;
@ -98,8 +99,8 @@ void ScreenTriangle::Draw(const TriDrawTriangleArgs *args, PolyTriangleThreadDat
x0 = clamp(x0, 0, clipright);
x1 = clamp(x1, 0, clipright);
leftEdge[y] = x0;
rightEdge[y] = x1;
edges[y << 1] = x0;
edges[(y << 1) + 1] = x1;
shortPos += shortStep;
longPos += longStep;
@ -121,64 +122,96 @@ void ScreenTriangle::Draw(const TriDrawTriangleArgs *args, PolyTriangleThreadDat
x0 = clamp(x0, 0, clipright);
x1 = clamp(x1, 0, clipright);
leftEdge[y] = x0;
rightEdge[y] = x1;
edges[y << 1] = x0;
edges[(y << 1) + 1] = x1;
shortPos += shortStep;
longPos += longStep;
}
}
// Draw the triangle:
int opt = 0;
if (args->uniforms->DepthTest()) opt |= SWTRI_DepthTest;
/*if (args->uniforms->StencilTest())*/ opt |= SWTRI_StencilTest;
if (args->uniforms->WriteColor()) opt |= SWTRI_WriteColor;
if (args->uniforms->WriteDepth()) opt |= SWTRI_WriteDepth;
if (args->uniforms->WriteStencil()) opt |= SWTRI_WriteStencil;
int bmode = (int)args->uniforms->BlendMode();
auto drawfunc = args->destBgra ? ScreenTriangle::SpanDrawers32[bmode] : ScreenTriangle::SpanDrawers8[bmode];
TriangleDrawers[opt](args, thread, edges, topY, bottomY);
}
float stepXW = args->gradientX.W;
float v1X = args->v1->x;
float v1Y = args->v1->y;
float v1W = args->v1->w;
template<typename OptT>
void DrawTriangle(const TriDrawTriangleArgs *args, PolyTriangleThreadData *thread, int16_t *edges, int topY, int bottomY)
{
using namespace TriScreenDrawerModes;
bool depthTest = args->uniforms->DepthTest();
bool stencilTest = true;
bool writeColor = args->uniforms->WriteColor();
bool writeStencil = args->uniforms->WriteStencil();
bool writeDepth = args->uniforms->WriteDepth();
uint8_t stencilTestValue = args->uniforms->StencilTestValue();
uint8_t stencilWriteValue = args->uniforms->StencilWriteValue();
void(*drawfunc)(int y, int x0, int x1, const TriDrawTriangleArgs *args, PolyTriangleThreadData *thread);
float stepXW, v1X, v1Y, v1W, posXW;
uint8_t stencilTestValue, stencilWriteValue;
float *zbufferLine;
uint8_t *stencilLine;
if (OptT::Flags & SWTRI_WriteColor)
{
int bmode = (int)args->uniforms->BlendMode();
drawfunc = args->destBgra ? ScreenTriangle::SpanDrawers32[bmode] : ScreenTriangle::SpanDrawers8[bmode];
}
if ((OptT::Flags & SWTRI_DepthTest) || (OptT::Flags & SWTRI_WriteDepth))
{
stepXW = args->gradientX.W;
v1X = args->v1->x;
v1Y = args->v1->y;
v1W = args->v1->w;
}
if (OptT::Flags & SWTRI_StencilTest)
stencilTestValue = args->uniforms->StencilTestValue();
if (OptT::Flags & SWTRI_WriteStencil)
stencilWriteValue = args->uniforms->StencilWriteValue();
int num_cores = thread->num_cores;
for (int y = topY + thread->skipped_by_thread(topY); y < bottomY; y += num_cores)
{
int x = leftEdge[y];
int xend = rightEdge[y];
int x = edges[y << 1];
int xend = edges[(y << 1) + 1];
float *zbufferLine = args->zbuffer + args->stencilpitch * y;
uint8_t *stencilLine = args->stencilbuffer + args->stencilpitch * y;
if ((OptT::Flags & SWTRI_StencilTest) || (OptT::Flags & SWTRI_WriteStencil))
stencilLine = args->stencilbuffer + args->stencilpitch * y;
float startX = x + (0.5f - v1X);
float startY = y + (0.5f - v1Y);
float posXW = v1W + stepXW * startX + args->gradientY.W * startY + args->depthOffset;
if ((OptT::Flags & SWTRI_DepthTest) || (OptT::Flags & SWTRI_WriteDepth))
{
zbufferLine = args->zbuffer + args->stencilpitch * y;
float startX = x + (0.5f - v1X);
float startY = y + (0.5f - v1Y);
posXW = v1W + stepXW * startX + args->gradientY.W * startY + args->depthOffset;
}
#ifndef NO_SSE
__m128 mstepXW = _mm_set1_ps(stepXW * 4.0f);
__m128 mfirstStepXW = _mm_setr_ps(0.0f, stepXW, stepXW + stepXW, stepXW + stepXW + stepXW);
__m128 mstepXW, mfirstStepXW;
if ((OptT::Flags & SWTRI_DepthTest) || (OptT::Flags & SWTRI_WriteDepth))
{
mstepXW = _mm_set1_ps(stepXW * 4.0f);
mfirstStepXW = _mm_setr_ps(0.0f, stepXW, stepXW + stepXW, stepXW + stepXW + stepXW);
}
while (x < xend)
{
int xstart = x;
if (depthTest && stencilTest)
if ((OptT::Flags & SWTRI_DepthTest) && (OptT::Flags & SWTRI_StencilTest))
{
int xendsse = x + ((xend - x) / 4);
__m128 mposXW = _mm_add_ps(_mm_set1_ps(posXW), mfirstStepXW);
while (_mm_movemask_ps(_mm_cmple_ps(_mm_loadu_ps(zbufferLine + x), mposXW)) == 15 &&
while (x < xendsse &&
_mm_movemask_ps(_mm_cmple_ps(_mm_loadu_ps(zbufferLine + x), mposXW)) == 15 &&
stencilLine[x] == stencilTestValue &&
stencilLine[x + 1] == stencilTestValue &&
stencilLine[x + 2] == stencilTestValue &&
stencilLine[x + 3] == stencilTestValue &&
x < xendsse)
stencilLine[x + 3] == stencilTestValue)
{
if (writeDepth)
if (OptT::Flags & SWTRI_WriteDepth)
_mm_storeu_ps(zbufferLine + x, mposXW);
mposXW = _mm_add_ps(mposXW, mstepXW);
x += 4;
@ -187,19 +220,19 @@ void ScreenTriangle::Draw(const TriDrawTriangleArgs *args, PolyTriangleThreadDat
while (zbufferLine[x] <= posXW && stencilLine[x] == stencilTestValue && x < xend)
{
if (writeDepth)
if (OptT::Flags & SWTRI_WriteDepth)
zbufferLine[x] = posXW;
posXW += stepXW;
x++;
}
}
else if (depthTest)
else if (OptT::Flags & SWTRI_DepthTest)
{
int xendsse = x + ((xend - x) / 4);
__m128 mposXW = _mm_add_ps(_mm_set1_ps(posXW), mfirstStepXW);
while (_mm_movemask_ps(_mm_cmple_ps(_mm_loadu_ps(zbufferLine + x), mposXW)) == 15 && x < xendsse)
while (x < xendsse && _mm_movemask_ps(_mm_cmple_ps(_mm_loadu_ps(zbufferLine + x), mposXW)) == 15)
{
if (writeDepth)
if (OptT::Flags & SWTRI_WriteDepth)
_mm_storeu_ps(zbufferLine + x, mposXW);
mposXW = _mm_add_ps(mposXW, mstepXW);
x += 4;
@ -208,14 +241,20 @@ void ScreenTriangle::Draw(const TriDrawTriangleArgs *args, PolyTriangleThreadDat
while (zbufferLine[x] <= posXW && x < xend)
{
if (writeDepth)
if (OptT::Flags & SWTRI_WriteDepth)
zbufferLine[x] = posXW;
posXW += stepXW;
x++;
}
}
else if (stencilTest)
else if (OptT::Flags & SWTRI_StencilTest)
{
int xendsse = x + ((xend - x) / 16);
while (x < xendsse && _mm_movemask_epi8(_mm_cmpeq_epi8(_mm_loadu_si128((const __m128i*)&stencilLine[x]), _mm_set1_epi8(stencilTestValue))) == 0xffff)
{
x += 16;
}
while (stencilLine[x] == stencilTestValue && x < xend)
x++;
}
@ -226,16 +265,24 @@ void ScreenTriangle::Draw(const TriDrawTriangleArgs *args, PolyTriangleThreadDat
if (x > xstart)
{
if (writeColor)
if (OptT::Flags & SWTRI_WriteColor)
drawfunc(y, xstart, x, args, thread);
if (writeStencil)
if (OptT::Flags & SWTRI_WriteStencil)
{
for (int i = xstart; i < x; i++)
stencilLine[i] = stencilWriteValue;
int i = xstart;
int xendsse = xstart + ((x - xstart) / 16);
while (i < xendsse)
{
_mm_storeu_si128((__m128i*)&stencilLine[i], _mm_set1_epi8(stencilWriteValue));
i += 16;
}
while (i < x)
stencilLine[i++] = stencilWriteValue;
}
if (!depthTest && writeDepth)
if (!(OptT::Flags & SWTRI_DepthTest) && (OptT::Flags & SWTRI_WriteDepth))
{
for (int i = xstart; i < x; i++)
{
@ -245,16 +292,16 @@ void ScreenTriangle::Draw(const TriDrawTriangleArgs *args, PolyTriangleThreadDat
}
}
if (depthTest && stencilTest)
if ((OptT::Flags & SWTRI_DepthTest) && (OptT::Flags & SWTRI_StencilTest))
{
int xendsse = x + ((xend - x) / 4);
__m128 mposXW = _mm_add_ps(_mm_set1_ps(posXW), mfirstStepXW);
while ((_mm_movemask_ps(_mm_cmple_ps(_mm_loadu_ps(zbufferLine + x), mposXW)) == 0 ||
while (x < xendsse &&
(_mm_movemask_ps(_mm_cmple_ps(_mm_loadu_ps(zbufferLine + x), mposXW)) == 0 ||
stencilLine[x] != stencilTestValue ||
stencilLine[x + 1] != stencilTestValue ||
stencilLine[x + 2] != stencilTestValue ||
stencilLine[x + 3] != stencilTestValue) &&
x < xendsse)
stencilLine[x + 3] != stencilTestValue))
{
mposXW = _mm_add_ps(mposXW, mstepXW);
x += 4;
@ -267,11 +314,11 @@ void ScreenTriangle::Draw(const TriDrawTriangleArgs *args, PolyTriangleThreadDat
x++;
}
}
else if (depthTest)
else if (OptT::Flags & SWTRI_DepthTest)
{
int xendsse = x + ((xend - x) / 4);
__m128 mposXW = _mm_add_ps(_mm_set1_ps(posXW), mfirstStepXW);
while (_mm_movemask_ps(_mm_cmple_ps(_mm_loadu_ps(zbufferLine + x), mposXW)) == 0 && x < xendsse)
while (x < xendsse && _mm_movemask_ps(_mm_cmple_ps(_mm_loadu_ps(zbufferLine + x), mposXW)) == 0)
{
mposXW = _mm_add_ps(mposXW, mstepXW);
x += 4;
@ -284,11 +331,16 @@ void ScreenTriangle::Draw(const TriDrawTriangleArgs *args, PolyTriangleThreadDat
x++;
}
}
else if (stencilTest)
else if (OptT::Flags & SWTRI_StencilTest)
{
int xendsse = x + ((xend - x) / 16);
while (x < xendsse && _mm_movemask_epi8(_mm_cmpeq_epi8(_mm_loadu_si128((const __m128i*)&stencilLine[x]), _mm_set1_epi8(stencilTestValue))) == 0)
{
x += 16;
}
while (stencilLine[x] != stencilTestValue && x < xend)
{
posXW += stepXW;
x++;
}
}
@ -298,27 +350,27 @@ void ScreenTriangle::Draw(const TriDrawTriangleArgs *args, PolyTriangleThreadDat
{
int xstart = x;
if (depthTest && stencilTest)
if ((OptT::Flags & SWTRI_DepthTest) && (OptT::Flags & SWTRI_StencilTest))
{
while (zbufferLine[x] <= posXW && stencilLine[x] == stencilTestValue && x < xend)
{
if (writeDepth)
if (OptT::Flags & SWTRI_WriteDepth)
zbufferLine[x] = posXW;
posXW += stepXW;
x++;
}
}
else if (depthTest)
else if (OptT::Flags & SWTRI_DepthTest)
{
while (zbufferLine[x] <= posXW && x < xend)
{
if (writeDepth)
if (OptT::Flags & SWTRI_WriteDepth)
zbufferLine[x] = posXW;
posXW += stepXW;
x++;
}
}
else if (stencilTest)
else if (OptT::Flags & SWTRI_StencilTest)
{
while (stencilLine[x] == stencilTestValue && x < xend)
x++;
@ -330,16 +382,16 @@ void ScreenTriangle::Draw(const TriDrawTriangleArgs *args, PolyTriangleThreadDat
if (x > xstart)
{
if (writeColor)
if (OptT::Flags & SWTRI_WriteColor)
drawfunc(y, xstart, x, args, thread);
if (writeStencil)
if (OptT::Flags & SWTRI_WriteStencil)
{
for (int i = xstart; i < x; i++)
stencilLine[i] = stencilWriteValue;
}
if (!depthTest && writeDepth)
if (!(OptT::Flags & SWTRI_DepthTest) && (OptT::Flags & SWTRI_WriteDepth))
{
for (int i = xstart; i < x; i++)
{
@ -349,7 +401,7 @@ void ScreenTriangle::Draw(const TriDrawTriangleArgs *args, PolyTriangleThreadDat
}
}
if (depthTest && stencilTest)
if ((OptT::Flags & SWTRI_DepthTest) && (OptT::Flags & SWTRI_StencilTest))
{
while ((zbufferLine[x] > posXW || stencilLine[x] != stencilTestValue) && x < xend)
{
@ -357,7 +409,7 @@ void ScreenTriangle::Draw(const TriDrawTriangleArgs *args, PolyTriangleThreadDat
x++;
}
}
else if (depthTest)
else if (OptT::Flags & SWTRI_DepthTest)
{
while (zbufferLine[x] > posXW && x < xend)
{
@ -365,11 +417,10 @@ void ScreenTriangle::Draw(const TriDrawTriangleArgs *args, PolyTriangleThreadDat
x++;
}
}
else if (stencilTest)
else if (OptT::Flags & SWTRI_StencilTest)
{
while (stencilLine[x] != stencilTestValue && x < xend)
{
posXW += stepXW;
x++;
}
}
@ -2164,4 +2215,40 @@ void(*ScreenTriangle::RectDrawers32[])(const void *, int, int, int, const RectDr
&DrawRect32<TriScreenDrawerModes::StyleAddShadedTranslated>
};
void(*ScreenTriangle::TriangleDrawers[])(const TriDrawTriangleArgs *args, PolyTriangleThreadData *thread, int16_t *edges, int topY, int bottomY) =
{
nullptr,
nullptr,
nullptr,
nullptr,
&DrawTriangle<TriScreenDrawerModes::TriangleOpt4>,
&DrawTriangle<TriScreenDrawerModes::TriangleOpt5>,
&DrawTriangle<TriScreenDrawerModes::TriangleOpt6>,
&DrawTriangle<TriScreenDrawerModes::TriangleOpt7>,
&DrawTriangle<TriScreenDrawerModes::TriangleOpt8>,
&DrawTriangle<TriScreenDrawerModes::TriangleOpt9>,
&DrawTriangle<TriScreenDrawerModes::TriangleOpt10>,
&DrawTriangle<TriScreenDrawerModes::TriangleOpt11>,
&DrawTriangle<TriScreenDrawerModes::TriangleOpt12>,
&DrawTriangle<TriScreenDrawerModes::TriangleOpt13>,
&DrawTriangle<TriScreenDrawerModes::TriangleOpt14>,
&DrawTriangle<TriScreenDrawerModes::TriangleOpt15>,
&DrawTriangle<TriScreenDrawerModes::TriangleOpt16>,
&DrawTriangle<TriScreenDrawerModes::TriangleOpt17>,
&DrawTriangle<TriScreenDrawerModes::TriangleOpt18>,
&DrawTriangle<TriScreenDrawerModes::TriangleOpt19>,
&DrawTriangle<TriScreenDrawerModes::TriangleOpt20>,
&DrawTriangle<TriScreenDrawerModes::TriangleOpt21>,
&DrawTriangle<TriScreenDrawerModes::TriangleOpt22>,
&DrawTriangle<TriScreenDrawerModes::TriangleOpt23>,
&DrawTriangle<TriScreenDrawerModes::TriangleOpt24>,
&DrawTriangle<TriScreenDrawerModes::TriangleOpt25>,
&DrawTriangle<TriScreenDrawerModes::TriangleOpt26>,
&DrawTriangle<TriScreenDrawerModes::TriangleOpt27>,
&DrawTriangle<TriScreenDrawerModes::TriangleOpt28>,
&DrawTriangle<TriScreenDrawerModes::TriangleOpt29>,
&DrawTriangle<TriScreenDrawerModes::TriangleOpt30>,
&DrawTriangle<TriScreenDrawerModes::TriangleOpt31>
};
int ScreenTriangle::FuzzStart = 0;

View file

@ -142,6 +142,8 @@ class ScreenTriangle
public:
static void Draw(const TriDrawTriangleArgs *args, PolyTriangleThreadData *thread);
static void(*TriangleDrawers[])(const TriDrawTriangleArgs *args, PolyTriangleThreadData *thread, int16_t *edges, int topY, int bottomY);
static void(*SpanDrawers8[])(int y, int x0, int x1, const TriDrawTriangleArgs *args, PolyTriangleThreadData *thread);
static void(*SpanDrawers32[])(int y, int x0, int x1, const TriDrawTriangleArgs *args, PolyTriangleThreadData *thread);
static void(*RectDrawers8[])(const void *, int, int, int, const RectDrawArgs *, PolyTriangleThreadData *);
@ -216,4 +218,42 @@ namespace TriScreenDrawerModes
11, 6, 6, 11, 15, 6, 6, 11, 15, 18,
21, 6, 6, 6, 6, 11, 6, 6, 11, 6,
};
enum SWTriangleFlags
{
SWTRI_DepthTest = 1,
SWTRI_StencilTest = 2,
SWTRI_WriteColor = 4,
SWTRI_WriteDepth = 8,
SWTRI_WriteStencil = 16
};
struct TriangleOpt4 { static const int Flags = 4; };
struct TriangleOpt5 { static const int Flags = 5; };
struct TriangleOpt6 { static const int Flags = 6; };
struct TriangleOpt7 { static const int Flags = 7; };
struct TriangleOpt8 { static const int Flags = 8; };
struct TriangleOpt9 { static const int Flags = 9; };
struct TriangleOpt10 { static const int Flags = 10; };
struct TriangleOpt11 { static const int Flags = 11; };
struct TriangleOpt12 { static const int Flags = 12; };
struct TriangleOpt13 { static const int Flags = 13; };
struct TriangleOpt14 { static const int Flags = 14; };
struct TriangleOpt15 { static const int Flags = 15; };
struct TriangleOpt16 { static const int Flags = 16; };
struct TriangleOpt17 { static const int Flags = 17; };
struct TriangleOpt18 { static const int Flags = 18; };
struct TriangleOpt19 { static const int Flags = 19; };
struct TriangleOpt20 { static const int Flags = 20; };
struct TriangleOpt21 { static const int Flags = 21; };
struct TriangleOpt22 { static const int Flags = 22; };
struct TriangleOpt23 { static const int Flags = 23; };
struct TriangleOpt24 { static const int Flags = 24; };
struct TriangleOpt25 { static const int Flags = 25; };
struct TriangleOpt26 { static const int Flags = 26; };
struct TriangleOpt27 { static const int Flags = 27; };
struct TriangleOpt28 { static const int Flags = 28; };
struct TriangleOpt29 { static const int Flags = 29; };
struct TriangleOpt30 { static const int Flags = 30; };
struct TriangleOpt31 { static const int Flags = 31; };
}