Select blend function once per triangle

This commit is contained in:
Magnus Norddahl 2019-12-08 14:42:20 +01:00
parent 73c62c5404
commit f7ae955e6a
2 changed files with 62 additions and 36 deletions

View file

@ -272,6 +272,8 @@ public:
uint8_t StencilTestValue = 0; uint8_t StencilTestValue = 0;
uint8_t StencilWriteValue = 0; uint8_t StencilWriteValue = 0;
void (*WriteColorFunc)(int y, int x0, int x1, PolyTriangleThreadData* thread) = nullptr;
private: private:
ShadedTriVertex ShadeVertex(int index); ShadedTriVertex ShadeVertex(int index);
void DrawShadedPoint(const ShadedTriVertex *const* vertex); void DrawShadedPoint(const ShadedTriVertex *const* vertex);

View file

@ -596,57 +596,78 @@ static void BlendColor(int y, int x0, int x1, PolyTriangleThreadData* thread)
} }
#endif #endif
static void WriteColor(int y, int x0, int x1, PolyTriangleThreadData* thread) #ifdef NO_SSE
static void BlendColorOpaque(int y, int x0, int x1, PolyTriangleThreadData* thread)
{ {
using namespace TriScreenDrawerModes; uint32_t* dest = (uint32_t*)thread->dest;
uint32_t* line = dest + y * (ptrdiff_t)thread->dest_pitch;
uint32_t* fragcolor = thread->scanline.FragColor;
memcpy(line + x0, fragcolor + x0, (x1 - x0) * sizeof(uint32_t));
}
#else
static void BlendColorOpaque(int y, int x0, int x1, PolyTriangleThreadData* thread)
{
uint32_t* dest = (uint32_t*)thread->dest;
uint32_t* line = dest + y * (ptrdiff_t)thread->dest_pitch;
uint32_t* fragcolor = thread->scanline.FragColor;
int ssecount = ((x1 - x0) & ~3);
int sseend = x0 + ssecount;
for (int x = x0; x < sseend; x += 4)
{
__m128i v = _mm_loadu_si128((__m128i*) & fragcolor[x]);
_mm_storeu_si128((__m128i*) & line[x], v);
}
for (int x = sseend; x < x1; x++)
{
line[x] = fragcolor[x];
}
}
#endif
static void BlendColorOpaqueAlphaTest(int y, int x0, int x1, PolyTriangleThreadData* thread)
{
uint32_t* dest = (uint32_t*)thread->dest;
uint32_t* line = dest + y * (ptrdiff_t)thread->dest_pitch;
uint32_t* fragcolor = thread->scanline.FragColor;
uint8_t* discard = thread->scanline.discard;
for (int x = x0; x < x1; x++)
{
if (!discard[x])
line[x] = fragcolor[x];
}
}
static void SelectWriteColorFunc(PolyTriangleThreadData* thread)
{
void(*writecolorfunc)(int y, int x0, int x1, PolyTriangleThreadData * thread);
FRenderStyle style = thread->RenderStyle; FRenderStyle style = thread->RenderStyle;
if (style.BlendOp == STYLEOP_Add && style.SrcAlpha == STYLEALPHA_One && style.DestAlpha == STYLEALPHA_Zero) if (style.BlendOp == STYLEOP_Add && style.SrcAlpha == STYLEALPHA_One && style.DestAlpha == STYLEALPHA_Zero)
{ {
uint32_t* dest = (uint32_t*)thread->dest;
uint32_t* line = dest + y * (ptrdiff_t)thread->dest_pitch;
uint32_t* fragcolor = thread->scanline.FragColor;
if (!thread->AlphaTest) if (!thread->AlphaTest)
{ {
#if !defined(NO_SSE) writecolorfunc = &BlendColorOpaque;
int ssecount = ((x1 - x0) & ~3);
int sseend = x0 + ssecount;
for (int x = x0; x < sseend; x += 4)
{
__m128i v = _mm_loadu_si128((__m128i*)&fragcolor[x]);
_mm_storeu_si128((__m128i*)&line[x], v);
}
for (int x = sseend; x < x1; x++)
{
line[x] = fragcolor[x];
}
#else
memcpy(line + x0, fragcolor + x0, (x1 - x0) * sizeof(uint32_t));
#endif
} }
else else
{ {
uint8_t* discard = thread->scanline.discard; writecolorfunc = &BlendColorOpaqueAlphaTest;
for (int x = x0; x < x1; x++)
{
if (!discard[x])
line[x] = fragcolor[x];
}
} }
} }
else else
{ {
using namespace TriScreenDrawerModes;
if (!thread->AlphaTest) if (!thread->AlphaTest)
{ {
switch (style.BlendOp) switch (style.BlendOp)
{ {
default: default:
case STYLEOP_Add: BlendColor<BlendColorOpt_Add>(y, x0, x1, thread); break; case STYLEOP_Add: writecolorfunc = &BlendColor<BlendColorOpt_Add>; break;
case STYLEOP_Sub: BlendColor<BlendColorOpt_Sub>(y, x0, x1, thread); break; case STYLEOP_Sub: writecolorfunc = &BlendColor<BlendColorOpt_Sub>; break;
case STYLEOP_RevSub: BlendColor<BlendColorOpt_RevSub>(y, x0, x1, thread); break; case STYLEOP_RevSub: writecolorfunc = &BlendColor<BlendColorOpt_RevSub>; break;
} }
} }
else else
@ -654,12 +675,13 @@ static void WriteColor(int y, int x0, int x1, PolyTriangleThreadData* thread)
switch (style.BlendOp) switch (style.BlendOp)
{ {
default: default:
case STYLEOP_Add: BlendColor<BlendColorOpt_AlphaTest_Add>(y, x0, x1, thread); break; case STYLEOP_Add: writecolorfunc = BlendColor<BlendColorOpt_AlphaTest_Add>; break;
case STYLEOP_Sub: BlendColor<BlendColorOpt_AlphaTest_Sub>(y, x0, x1, thread); break; case STYLEOP_Sub: writecolorfunc = BlendColor<BlendColorOpt_AlphaTest_Sub>; break;
case STYLEOP_RevSub: BlendColor<BlendColorOpt_AlphaTest_RevSub>(y, x0, x1, thread); break; case STYLEOP_RevSub: writecolorfunc = BlendColor<BlendColorOpt_AlphaTest_RevSub>; break;
} }
} }
} }
thread->WriteColorFunc = writecolorfunc;
} }
static void WriteDepth(int y, int x0, int x1, PolyTriangleThreadData* thread) static void WriteDepth(int y, int x0, int x1, PolyTriangleThreadData* thread)
@ -1210,7 +1232,7 @@ static void DrawSpan(int y, int x0, int x1, const TriDrawTriangleArgs* args, Pol
RunShader(x0, x1, thread); RunShader(x0, x1, thread);
if (thread->WriteColor) if (thread->WriteColor)
WriteColor(y, x0, x1, thread); thread->WriteColorFunc(y, x0, x1, thread);
if (thread->WriteDepth) if (thread->WriteDepth)
WriteDepth(y, x0, x1, thread); WriteDepth(y, x0, x1, thread);
if (thread->WriteStencil) if (thread->WriteStencil)
@ -1340,6 +1362,8 @@ void ScreenTriangle::Draw(const TriDrawTriangleArgs* args, PolyTriangleThreadDat
if (topY >= bottomY) if (topY >= bottomY)
return; return;
SelectWriteColorFunc(thread);
void(*testfunc)(int y, int x0, int x1, const TriDrawTriangleArgs * args, PolyTriangleThreadData * thread); void(*testfunc)(int y, int x0, int x1, const TriDrawTriangleArgs * args, PolyTriangleThreadData * thread);
int opt = 0; int opt = 0;