DS GX: Start filling in software renderer
Vicki Pfau vi@endrift.com
Tue, 28 Feb 2017 11:06:48 -0800
5 files changed,
229 insertions(+),
2 deletions(-)
M
include/mgba/internal/ds/gx.h
→
include/mgba/internal/ds/gx.h
@@ -18,6 +18,9 @@ #include <mgba-util/circle-buffer.h>
mLOG_DECLARE_CATEGORY(DS_GX); +#define DS_GX_POLYGON_BUFFER_SIZE 2048 +#define DS_GX_VERTEX_BUFFER_SIZE 6144 + DECL_BITFIELD(DSRegGXSTAT, uint32_t); DECL_BIT(DSRegGXSTAT, TestBusy, 0); DECL_BIT(DSRegGXSTAT, BoxTestResult, 1);
A
include/mgba/internal/ds/gx/software.h
@@ -0,0 +1,58 @@
+/* Copyright (c) 2013-2017 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef DS_GX_SOFTWARE_H +#define DS_GX_SOFTWARE_H + +#include <mgba-util/common.h> + +CXX_GUARD_START + +#include <mgba/internal/ds/gx.h> +#include <mgba/internal/ds/video.h> +#include <mgba-util/vector.h> + +struct DSGXSoftwarePolygon { + struct DSGXPolygon* poly; + int32_t topY; + int32_t bottomY; + int32_t topZ; +}; + +struct DSGXSoftwareEdge { + struct DSGXPolygon* poly; + int32_t y0; + int32_t x0; + int32_t w0; + int32_t c0; // 6.6.6.6 ARGB + int16_t s0; + int16_t t0; + + int32_t y1; + int32_t x1; + int32_t w1; + int32_t c1; // 6.6.6.6 ARGB + int16_t s1; + int16_t t1; +}; + +DECLARE_VECTOR(DSGXSoftwarePolygonList, struct DSGXSoftwarePolygon); +DECLARE_VECTOR(DSGXSoftwareEdgeList, struct DSGXSoftwareEdge); + +struct DSGXSoftwareRenderer { + struct DSGXRenderer d; + + struct DSGXSoftwarePolygonList activePolys; + struct DSGXSoftwareEdgeList activeEdges; + + uint16_t depthBuffer[DS_VIDEO_HORIZONTAL_PIXELS]; + color_t* scanlineCache; + + struct DSGXVertex* verts; +}; + +CXX_GUARD_END + +#endif
M
src/ds/core.c
→
src/ds/core.c
@@ -12,6 +12,7 @@ #include <mgba/internal/arm/debugger/debugger.h>
#include <mgba/internal/ds/ds.h> #include <mgba/internal/ds/extra/cli.h> #include <mgba/internal/ds/renderers/software.h> +#include <mgba/internal/ds/gx/software.h> #include <mgba-util/memory.h> #include <mgba-util/patch.h> #include <mgba-util/vfs.h>@@ -21,6 +22,7 @@ struct mCore d;
struct ARMCore* arm7; struct ARMCore* arm9; struct DSVideoSoftwareRenderer renderer; + struct DSGXSoftwareRenderer gxRenderer; int keys; int cursorX; int cursorY;@@ -58,6 +60,7 @@ ARMInit(arm7);
ARMInit(arm9); DSVideoSoftwareRendererCreate(&dscore->renderer); + DSGXSoftwareRendererCreate(&dscore->gxRenderer); dscore->renderer.outputBuffer = NULL; dscore->keys = 0;@@ -187,6 +190,9 @@
if (dscore->renderer.outputBuffer) { struct DSVideoRenderer* renderer = &dscore->renderer.d; DSVideoAssociateRenderer(&ds->video, renderer); + + struct DSGXRenderer* gxRenderer = &dscore->gxRenderer.d; + DSGXAssociateRenderer(&ds->gx, gxRenderer); } #if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2
M
src/ds/gx.c
→
src/ds/gx.c
@@ -12,8 +12,6 @@ mLOG_DEFINE_CATEGORY(DS_GX, "DS GX");
#define DS_GX_FIFO_SIZE 256 #define DS_GX_PIPE_SIZE 4 -#define DS_GX_POLYGON_BUFFER_SIZE 2048 -#define DS_GX_VERTEX_BUFFER_SIZE 6144 static void DSGXDummyRendererInit(struct DSGXRenderer* renderer); static void DSGXDummyRendererReset(struct DSGXRenderer* renderer);
A
src/ds/gx/software.c
@@ -0,0 +1,162 @@
+/* Copyright (c) 2013-2017 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include <mgba/internal/ds/gx/software.h> + +#include <mgba-util/memory.h> + +DEFINE_VECTOR(DSGXSoftwarePolygonList, struct DSGXSoftwarePolygon); +DEFINE_VECTOR(DSGXSoftwareEdgeList, struct DSGXSoftwareEdge); + +static void DSGXSoftwareRendererInit(struct DSGXRenderer* renderer); +static void DSGXSoftwareRendererReset(struct DSGXRenderer* renderer); +static void DSGXSoftwareRendererDeinit(struct DSGXRenderer* renderer); +static void DSGXSoftwareRendererSetRAM(struct DSGXRenderer* renderer, struct DSGXVertex* verts, struct DSGXPolygon* polys, unsigned polyCount); +static void DSGXSoftwareRendererDrawScanline(struct DSGXRenderer* renderer, int y); +static void DSGXSoftwareRendererGetScanline(struct DSGXRenderer* renderer, int y, color_t** output); + +static int _edgeSort(const void* a, const void* b) { + const struct DSGXSoftwareEdge* ea = a; + const struct DSGXSoftwareEdge* eb = b; + + if (ea->y0 < eb->y0) { + return -1; + } + if (ea->y0 > eb->y0) { + return 1; + } + if (ea->y1 < eb->y1) { + return -1; + } + if (ea->y1 > eb->y1) { + return 1; + } + return 0; +} + +void DSGXSoftwareRendererCreate(struct DSGXSoftwareRenderer* renderer) { + renderer->d.init = DSGXSoftwareRendererInit; + renderer->d.reset = DSGXSoftwareRendererReset; + renderer->d.deinit = DSGXSoftwareRendererDeinit; + renderer->d.setRAM = DSGXSoftwareRendererSetRAM; + renderer->d.drawScanline = DSGXSoftwareRendererDrawScanline; + renderer->d.getScanline = DSGXSoftwareRendererGetScanline; +} + +static void DSGXSoftwareRendererInit(struct DSGXRenderer* renderer) { + struct DSGXSoftwareRenderer* softwareRenderer = (struct DSGXSoftwareRenderer*) renderer; + DSGXSoftwarePolygonListInit(&softwareRenderer->activePolys, DS_GX_POLYGON_BUFFER_SIZE / 4); + DSGXSoftwareEdgeListInit(&softwareRenderer->activeEdges, DS_GX_POLYGON_BUFFER_SIZE); + softwareRenderer->scanlineCache = anonymousMemoryMap(sizeof(color_t) * DS_VIDEO_HORIZONTAL_PIXELS * 48); +} + +static void DSGXSoftwareRendererReset(struct DSGXRenderer* renderer) { + struct DSGXSoftwareRenderer* softwareRenderer = (struct DSGXSoftwareRenderer*) renderer; + // TODO +} + +static void DSGXSoftwareRendererDeinit(struct DSGXRenderer* renderer) { + struct DSGXSoftwareRenderer* softwareRenderer = (struct DSGXSoftwareRenderer*) renderer; + DSGXSoftwarePolygonListDeinit(&softwareRenderer->activePolys); + DSGXSoftwareEdgeListDeinit(&softwareRenderer->activeEdges); + mappedMemoryFree(softwareRenderer->scanlineCache, sizeof(color_t) * DS_VIDEO_HORIZONTAL_PIXELS * 48); +} + +static void DSGXSoftwareRendererSetRAM(struct DSGXRenderer* renderer, struct DSGXVertex* verts, struct DSGXPolygon* polys, unsigned polyCount) { + struct DSGXSoftwareRenderer* softwareRenderer = (struct DSGXSoftwareRenderer*) renderer; + + softwareRenderer->verts = verts; + DSGXSoftwarePolygonListClear(&softwareRenderer->activePolys); + DSGXSoftwareEdgeListClear(&softwareRenderer->activeEdges); + unsigned i; + for (i = 0; i < polyCount; ++i) { + struct DSGXSoftwarePolygon* poly = DSGXSoftwarePolygonListAppend(&softwareRenderer->activePolys); + struct DSGXSoftwareEdge* edge = DSGXSoftwareEdgeListAppend(&softwareRenderer->activeEdges); + poly->poly = &polys[i]; + + struct DSGXVertex* v0 = &verts[poly->poly->vertIds[0]]; + struct DSGXVertex* v1; + + int v; + for (v = 1; v < poly->poly->verts; ++v) { + v1 = &verts[poly->poly->vertIds[v]]; + if (v0->vy <= v1->vy) { + edge->y0 = v0->vy; + edge->x0 = v0->vx; + edge->w0 = v0->vw; + edge->c0 = v0->color; + edge->s0 = v0->s; + edge->t0 = v0->t; + + edge->y1 = v1->vy; + edge->x1 = v1->vx; + edge->w1 = v1->vw; + edge->c1 = v1->color; + edge->s1 = v1->s; + edge->t1 = v1->t; + } else { + edge->y0 = v1->vy; + edge->x0 = v1->vx; + edge->w0 = v1->vw; + edge->c0 = v1->color; + edge->s0 = v1->s; + edge->t0 = v1->t; + + edge->y1 = v0->vy; + edge->x1 = v0->vx; + edge->w1 = v0->vw; + edge->c1 = v0->color; + edge->s1 = v0->s; + edge->t1 = v0->t; + } + + edge = DSGXSoftwareEdgeListAppend(&softwareRenderer->activeEdges); + v0 = v1; + } + + v1 = &verts[poly->poly->vertIds[0]]; + if (v0->vy <= v1->vy) { + edge->y0 = v0->vy; + edge->x0 = v0->vx; + edge->w0 = v0->vw; + edge->c0 = v0->color; + edge->s0 = v0->s; + edge->t0 = v0->t; + + edge->y1 = v1->vy; + edge->x1 = v1->vx; + edge->w1 = v1->vw; + edge->c1 = v1->color; + edge->s1 = v1->s; + edge->t1 = v1->t; + } else { + edge->y0 = v1->vy; + edge->x0 = v1->vx; + edge->w0 = v1->vw; + edge->c0 = v1->color; + edge->s0 = v1->s; + edge->t0 = v1->t; + + edge->y1 = v0->vy; + edge->x1 = v0->vx; + edge->w1 = v0->vw; + edge->c1 = v0->color; + edge->s1 = v0->s; + edge->t1 = v0->t; + } + } + qsort(DSGXSoftwareEdgeListGetPointer(&softwareRenderer->activeEdges, 0), DSGXSoftwareEdgeListSize(&softwareRenderer->activeEdges), sizeof(struct DSGXSoftwareEdge), _edgeSort); +} + +static void DSGXSoftwareRendererDrawScanline(struct DSGXRenderer* renderer, int y) { + struct DSGXSoftwareRenderer* softwareRenderer = (struct DSGXSoftwareRenderer*) renderer; + // TODO +} + +static void DSGXSoftwareRendererGetScanline(struct DSGXRenderer* renderer, int y, color_t** output) { + struct DSGXSoftwareRenderer* softwareRenderer = (struct DSGXSoftwareRenderer*) renderer; + y %= 48; + *output = &softwareRenderer->scanlineCache[DS_VIDEO_HORIZONTAL_PIXELS * y]; +}