Speed up the software renderer

This commit is contained in:
Luke Benstead 2023-05-20 07:45:45 +01:00
parent 5865d57384
commit f6713bc778

View File

@ -30,81 +30,7 @@ static VideoMode vid_mode = {
#define MIN(x, y) ((x) < (y) ? (x) : (y))
#define MAX(x, y) ((x) > (y) ? (x) : (y))
static void DrawTriangle(Vertex* v0, Vertex* v1, Vertex* v2) {
// Compute triangle bounding box.
int minX = MIN(MIN(v0->xyz[0], v1->xyz[0]), v2->xyz[0]);
int maxX = MAX(MAX(v0->xyz[0], v1->xyz[0]), v2->xyz[0]);
int minY = MIN(MIN(v0->xyz[1], v1->xyz[1]), v2->xyz[1]);
int maxY = MAX(MAX(v0->xyz[1], v1->xyz[1]), v2->xyz[1]);
// Clip to scissor rect.
minX = MAX(minX, 0);
maxX = MIN(maxX, vid_mode.width);
minY = MAX(minY, 0);
maxY = MIN(maxY, vid_mode.height);
// Compute edge equations.
EdgeEquation e0, e1, e2;
EdgeEquationInit(&e0, &v0->xyz[0], &v1->xyz[0]);
EdgeEquationInit(&e1, &v1->xyz[0], &v2->xyz[0]);
EdgeEquationInit(&e2, &v2->xyz[0], &v0->xyz[0]);
float area = 0.5 * (e0.c + e1.c + e2.c);
/* This is very ugly. I don't understand the math properly
* so I just swap the vertex order if something is back-facing
* and we want to render it. Patches welcome! */
#define REVERSE_WINDING() \
Vertex* tv = v0; \
v0 = v1; \
v1 = tv; \
EdgeEquationInit(&e0, &v0->xyz[0], &v1->xyz[0]); \
EdgeEquationInit(&e1, &v1->xyz[0], &v2->xyz[0]); \
EdgeEquationInit(&e2, &v2->xyz[0], &v0->xyz[0]); \
area = 0.5f * (e0.c + e1.c + e2.c) \
// Check if triangle is backfacing.
if(CULL_MODE == GPU_CULLING_CCW) {
if(area < 0) {
return;
}
} else if(CULL_MODE == GPU_CULLING_CW) {
if(area < 0) {
// We only draw front-facing polygons, so swap
// the back to front and draw
REVERSE_WINDING();
} else {
// Front facing, so bail
return;
}
} else if(area < 0) {
/* We're not culling, but this is backfacing, so swap vertices and edges */
REVERSE_WINDING();
}
ParameterEquation r, g, b;
ParameterEquationInit(&r, v0->bgra[2], v1->bgra[2], v2->bgra[2], &e0, &e1, &e2, area);
ParameterEquationInit(&g, v0->bgra[1], v1->bgra[1], v2->bgra[1], &e0, &e1, &e2, area);
ParameterEquationInit(&b, v0->bgra[0], v1->bgra[0], v2->bgra[0], &e0, &e1, &e2, area);
// Add 0.5 to sample at pixel centers.
for (float x = minX + 0.5f, xm = maxX + 0.5f; x <= xm; x += 1.0f)
for (float y = minY + 0.5f, ym = maxY + 0.5f; y <= ym; y += 1.0f)
{
if (EdgeEquationTestPoint(&e0, x, y) && EdgeEquationTestPoint(&e1, x, y) && EdgeEquationTestPoint(&e2, x, y)) {
int rint = ParameterEquationEvaluate(&r, x, y);
int gint = ParameterEquationEvaluate(&g, x, y);
int bint = ParameterEquationEvaluate(&b, x, y);
SDL_SetRenderDrawColor(RENDERER, rint, gint, bint, 255);
SDL_RenderDrawPoint(RENDERER, x, y);
}
}
}
AlignedVector vbuffer;
void InitGPU(_Bool autosort, _Bool fsaa) {
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS);
@ -120,6 +46,8 @@ void InitGPU(_Bool autosort, _Bool fsaa) {
RENDERER = SDL_CreateRenderer(
WINDOW, -1, SDL_RENDERER_ACCELERATED
);
aligned_vector_init(&vbuffer, sizeof(SDL_Vertex));
}
void SceneBegin() {
@ -531,13 +459,37 @@ void SceneListFinish() {
Vertex* v0 = (Vertex*) (flags - step - step);
Vertex* v1 = (Vertex*) (flags - step);
Vertex* v2 = (Vertex*) (flags);
(vidx % 2 == 0) ? DrawTriangle(v0, v1, v2) : DrawTriangle(v1, v0, v2);
SDL_Vertex sv0 = {
{v0->xyz[0], v0->xyz[1]},
{v0->bgra[2], v0->bgra[1], v0->bgra[0], v0->bgra[3]},
{v0->uv[0], v0->uv[1]}
};
SDL_Vertex sv1 = {
{v1->xyz[0], v1->xyz[1]},
{v1->bgra[2], v1->bgra[1], v1->bgra[0], v1->bgra[3]},
{v1->uv[0], v1->uv[1]}
};
SDL_Vertex sv2 = {
{v2->xyz[0], v2->xyz[1]},
{v2->bgra[2], v2->bgra[1], v2->bgra[0], v2->bgra[3]},
{v2->uv[0], v2->uv[1]}
};
aligned_vector_push_back(&vbuffer, &sv0, 1);
aligned_vector_push_back(&vbuffer, &sv1, 1);
aligned_vector_push_back(&vbuffer, &sv2, 1);
}
if((*flags) == GPU_CMD_VERTEX_EOL) {
vidx = 0;
}
}
SDL_SetRenderDrawColor(RENDERER, 255, 255, 255, 255);
SDL_RenderGeometry(RENDERER, NULL, aligned_vector_front(&vbuffer), aligned_vector_size(&vbuffer), NULL, 0);
}
void SceneFinish() {