From 5f7855b6aa0e3338625eb7d30e8ccc5b74050bbf Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Thu, 12 Feb 2026 18:24:14 -0800 Subject: Deferred pipeline --- include/swgfx.h | 4 ++-- src/swgfx.c | 65 ++++++++++++++++++++++++++++++++++----------------------- 2 files changed, 41 insertions(+), 28 deletions(-) diff --git a/include/swgfx.h b/include/swgfx.h index a1ce872..57ba472 100644 --- a/include/swgfx.h +++ b/include/swgfx.h @@ -111,9 +111,9 @@ void sgTriangleStrip (swgfx*, size_t count, const sgVec3*, const sgNormal*); void sgTrianglesIndexed(swgfx*, size_t numIndices, const sgIdx* indices, const sgVec3* positions, const sgVec2* texcoords); void sgTrianglesIndexedNonUniform(swgfx*, size_t numTris, const sgTriIdx* tris, const sgVec3* positions, const sgVec2* texcoords); +void sgLighting(swgfx*); + void sgGamma (swgfx*, sgPixel*, int width, int height); void sgGammaInv(swgfx*, sgPixel*, int width, int height); sgCounters sgGetCounters(const swgfx*); - -void sgCheck(swgfx*); diff --git a/src/swgfx.c b/src/swgfx.c index 8663b62..d41b69d 100644 --- a/src/swgfx.c +++ b/src/swgfx.c @@ -22,6 +22,8 @@ Coordinate systems: static constexpr sgTextureId DefaultTextureId = SWGFX_MAX_TEXTURES; static constexpr size_t SWGFX_TEXTURE_REGISTER_SIZE = SWGFX_MAX_TEXTURES + 1; +static constexpr R DepthClearValue = 1.0f; + static constexpr sgVec3 Up3 = (sgVec3){0,1,0}; typedef struct sgViewport_t { int x0, y0, width, height; } sgViewport_t; @@ -41,7 +43,7 @@ typedef struct swgfx { sgVec2i dims; // Colour buffer dimensions. sgPixel* colour; // Colour buffer. R* depth; // Depth buffer. - sgTextureId* textureId; // Texture ID buffer. + sgTextureId* texture; // Texture ID buffer. sgVec2* texcoords; // Texture coords buffer. sgViewport_t viewport; sgMat4 model; // Model matrix. @@ -307,14 +309,14 @@ static inline sgPixel* Pixel(swgfx* gfx, int x, int y) { return gfx->colour + (y * gfx->dims.x) + x; } -static inline R* Depth(swgfx* gfx, int x, int y) { +static inline const R* Depth(swgfx* gfx, int x, int y) { assert(gfx); assert(gfx->depth); assert(InBounds(gfx->dims.x, gfx->dims.y, x, y)); return gfx->depth + (y * gfx->dims.x) + x; } -static inline void SetPixel(swgfx* gfx, const sgVec2i p, sgPixel colour) { +static inline void SetPixelColour(swgfx* gfx, const sgVec2i p, sgPixel colour) { assert(gfx); *Pixel(gfx, p.x, p.y) = colour; #if SWGFX_PROFILING @@ -322,9 +324,14 @@ static inline void SetPixel(swgfx* gfx, const sgVec2i p, sgPixel colour) { #endif // SWGFX_PROFILING } -static inline void SetDepth(swgfx* gfx, const sgVec2i p, R depth) { +static inline void SetPixelDeferred(swgfx* gfx, const sgVec2i p, R depth, sgTextureId texid, sgVec2 uv) { assert(gfx); - *Depth(gfx, p.x, p.y) = depth; + gfx->depth[(p.y * gfx->dims.x) + p.x] = depth; + gfx->texture[(p.y * gfx->dims.x) + p.x] = texid; + gfx->texcoords[(p.y * gfx->dims.x) + p.x] = uv; +#if SWGFX_PROFILING + gfx->counters.pixels++; +#endif // SWGFX_PROFILING } static inline sgPixel ReadTexture(const sgImage* texture, sgVec2i xy) { @@ -459,7 +466,7 @@ static void DrawTriangle2(swgfx* gfx, const sgTri2* const tri) { assert((bar.x + bar.y + bar.z - 1e7) <= 1.f); const sgVec2 uv = BarycentricInterp2(bar, tri->p0.uv, tri->p1.uv, tri->p2.uv); const sgPixel colour = Sample(texture->image, texture->filter, uv); - SetPixel(gfx, (sgVec2i){x,y}, colour); + SetPixelColour(gfx, (sgVec2i){x,y}, colour); } } } @@ -650,7 +657,6 @@ static void DrawTriangle3PostClip(swgfx* gfx, const sgTri4* const tri) { const sgVec3 one_over_zs = (sgVec3){1.f / p0.w, 1.f / p1.w, 1.f/ p2.w}; const sgVec3 u_over_zs = (sgVec3){tri->p0.uv.x / p0.w, tri->p1.uv.x / p1.w, tri->p2.uv.x / p2.w}; const sgVec3 v_over_zs = (sgVec3){tri->p0.uv.y / p0.w, tri->p1.uv.y / p1.w, tri->p2.uv.y / p2.w}; - const sgTexture* texture = &gfx->textureRegister[gfx->activeTexture]; // Draw. for (int y = pmin.y; y <= pmax.y; ++y) { for (int x = pmin.x; x <= pmax.x; ++x) { @@ -670,17 +676,15 @@ static void DrawTriangle3PostClip(swgfx* gfx, const sgTri4* const tri) { const R p_depth = dot3(bar, depths); const R z = 1.f / p_one_over_z; const sgVec2 uv = (sgVec2){p_u_over_z * z, p_v_over_z * z}; - R* depth = Depth(gfx, x, y); + const R* depth = Depth(gfx, x, y); if ((0.f <= p_depth) && (p_depth <= 1.f) && (p_depth <= *depth)) { - *depth = p_depth; - const sgPixel colour = Sample(texture->image, texture->filter, uv); // TODO: When doing lighting, need to tone-map here and apply inverse // gamma here. //const sgPixel colour = {(uint8_t)(bar.x*255.f), (uint8_t)(bar.y*255.f), (uint8_t)(bar.z*255.f), 255}; //const sgPixel colour = {(int)(z*255.f), (int)(z*255.f), (int)(z*255.f), 255}; //const sgPixel colour = {255, 0, 255, 255}; //const sgPixel colour = {(int)(uv.x * 255.f), (int)(uv.y * 255.f), 255, 255}; - SetPixel(gfx, (sgVec2i){x,y}, colour); + SetPixelDeferred(gfx, (sgVec2i){x,y}, p_depth, gfx->activeTexture, uv); } } } @@ -746,7 +750,7 @@ swgfx* sgNew(int width, int height, void* mem) { gfx->dims = (sgVec2i){width, height}; gfx->colour = SG_ALLOC(&aligned, N, sgPixel); gfx->depth = SG_ALLOC(&aligned, N, R); - gfx->textureId = SG_ALLOC(&aligned, N, sgTextureId); + gfx->texture = SG_ALLOC(&aligned, N, sgTextureId); gfx->texcoords = SG_ALLOC(&aligned, N, sgVec2); gfx->textureRegister = SG_ALLOC(&aligned, SWGFX_TEXTURE_REGISTER_SIZE, sgTexture); gfx->activeTexture = DefaultTextureId; @@ -850,6 +854,10 @@ void sgPerspective(swgfx* gfx, R fovy, R aspect, R near, R far) { void sgViewport(swgfx* gfx, int x0, int y0, int width, int height) { assert(gfx); + assert(x0 >= 0); + assert(y0 >= 0); + assert((x0 + width) <= gfx->dims.x); + assert((y0 + height) <= gfx->dims.y); gfx->viewport = (sgViewport_t){x0, y0, width, height}; } @@ -872,14 +880,14 @@ void sgClear(swgfx* gfx) { const int N = gfx->dims.x * gfx->dims.y; memset(gfx->colour, 0, N * sizeof(*gfx->colour)); for (int i = 0; i < N; ++i) { - gfx->depth[i] = 1.0f; + gfx->depth[i] = DepthClearValue; } } void sgPixels(swgfx* gfx, size_t count, const sgVec2i* positions, sgPixel colour) { assert(gfx); for (size_t i = 0; i < count; ++i) { - SetPixel(gfx, positions[i], colour); + SetPixelColour(gfx, positions[i], colour); } } @@ -956,6 +964,23 @@ static void ImageExp(sgPixel* pixels, int width, int height, R exp) { } } +void sgLighting(swgfx* gfx) { + assert(gfx); + const int N = gfx->dims.x * gfx->dims.y; + for (int i = 0; i < N; ++i) { + const R depth = gfx->depth[i]; + if (depth != DepthClearValue) { + const sgTextureId texid = gfx->texture[i]; + const sgTexture* texture = &gfx->textureRegister[texid]; + const sgVec2 uv = gfx->texcoords[i]; + sgPixel* colour = &gfx->colour[i]; + // TODO: Actual lighting. + const sgPixel albedo = Sample(texture->image, texture->filter, uv); + *colour = albedo; + } + } +} + void sgGamma(swgfx* gfx, sgPixel* pixels, int width, int height) { assert(gfx); assert(pixels); @@ -968,19 +993,7 @@ void sgGammaInv(swgfx* gfx, sgPixel* pixels, int width, int height) { ImageExp(pixels, width, height, 1.0f/2.2f); } -static bool ViewportWithinBuffer(swgfx* gfx) { - assert(gfx); - const sgViewport_t vp = gfx->viewport; - return ((vp.x0 + vp.width) <= gfx->dims.x) && - ((vp.y0 + vp.height) <= gfx->dims.y); -} - sgCounters sgGetCounters(const swgfx* gfx) { assert(gfx); return gfx->counters; } - -void sgCheck(swgfx* gfx) { - assert(gfx); - assert(ViewportWithinBuffer(gfx)); -} -- cgit v1.2.3