diff --git a/include/mgba/internal/ds/gx.h b/include/mgba/internal/ds/gx.h index 14c0d3c7e..9e49bdb1c 100644 --- a/include/mgba/internal/ds/gx.h +++ b/include/mgba/internal/ds/gx.h @@ -18,6 +18,9 @@ CXX_GUARD_START 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); diff --git a/include/mgba/internal/ds/gx/software.h b/include/mgba/internal/ds/gx/software.h new file mode 100644 index 000000000..54aafc2c2 --- /dev/null +++ b/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 + +CXX_GUARD_START + +#include +#include +#include + +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 diff --git a/src/ds/core.c b/src/ds/core.c index 2ebfd0cbf..98168e031 100644 --- a/src/ds/core.c +++ b/src/ds/core.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -21,6 +22,7 @@ struct DSCore { struct ARMCore* arm7; struct ARMCore* arm9; struct DSVideoSoftwareRenderer renderer; + struct DSGXSoftwareRenderer gxRenderer; int keys; int cursorX; int cursorY; @@ -58,6 +60,7 @@ static bool _DSCoreInit(struct mCore* core) { ARMInit(arm9); DSVideoSoftwareRendererCreate(&dscore->renderer); + DSGXSoftwareRendererCreate(&dscore->gxRenderer); dscore->renderer.outputBuffer = NULL; dscore->keys = 0; @@ -187,6 +190,9 @@ static void _DSCoreReset(struct mCore* core) { 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 diff --git a/src/ds/gx.c b/src/ds/gx.c index e383357ac..9bf3e58c6 100644 --- a/src/ds/gx.c +++ b/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); diff --git a/src/ds/gx/software.c b/src/ds/gx/software.c new file mode 100644 index 000000000..cdb87443a --- /dev/null +++ b/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 + +#include + +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]; +}