diff --git a/include/mgba/internal/ds/gx.h b/include/mgba/internal/ds/gx.h index 6a8a8fe56..eb05677f2 100644 --- a/include/mgba/internal/ds/gx.h +++ b/include/mgba/internal/ds/gx.h @@ -10,6 +10,7 @@ CXX_GUARD_START +#include #include #include #include @@ -80,9 +81,36 @@ struct DSGXEntry { }; #pragma pack(pop) +struct DSGXVertex { + // Viewport coords + int32_t x; // 16.16 + int32_t y; // 16.16 + int32_t z; // 16.16 + uint16_t color; + // Texcoords + int16_t s; // 12.4 + int16_t t; // 12.4 +}; + +struct DSGXPolygon { + int verts; + unsigned vertIds[4]; +}; + +struct DSGXRenderer { + void (*init)(struct DSGXRenderer* renderer); + void (*reset)(struct DSGXRenderer* renderer); + void (*deinit)(struct DSGXRenderer* renderer); + + void (*setRAM)(struct DSGXRenderer* renderer, struct DSGXVertex* verts, struct DSGXPolygon* polys, unsigned polyCount); + void (*drawScanline)(struct DSGXRenderer* renderer, int y); + void (*getScanline)(struct DSGXRenderer* renderer, int y, color_t** output); +}; + struct DS; struct DSGX { struct DS* p; + struct DSGXRenderer* renderer; struct CircleBuffer fifo; struct CircleBuffer pipe; @@ -92,11 +120,15 @@ struct DSGX { uint8_t outstandingCommand[4]; bool swapBuffers; + int bufferIndex; + struct DSGXVertex* vertexBuffer[2]; + struct DSGXPolygon* polygonBuffer[2]; }; void DSGXInit(struct DSGX*); void DSGXDeinit(struct DSGX*); void DSGXReset(struct DSGX*); +void DSGXAssociateRenderer(struct DSGX* video, struct DSGXRenderer* renderer); uint16_t DSGXWriteRegister(struct DSGX*, uint32_t address, uint16_t value); uint32_t DSGXWriteRegister32(struct DSGX*, uint32_t address, uint32_t value); diff --git a/include/mgba/internal/ds/video.h b/include/mgba/internal/ds/video.h index be0d6c0f5..e7c7afdae 100644 --- a/include/mgba/internal/ds/video.h +++ b/include/mgba/internal/ds/video.h @@ -70,6 +70,7 @@ DECL_BITFIELD(DSRegisterMASTER_BRIGHT, uint16_t); DECL_BITS(DSRegisterMASTER_BRIGHT, Y, 0, 5); DECL_BITS(DSRegisterMASTER_BRIGHT, Mode, 14, 2); +struct DSGX; struct DSVideoRenderer { void (*init)(struct DSVideoRenderer* renderer); void (*reset)(struct DSVideoRenderer* renderer); @@ -96,6 +97,7 @@ struct DSVideoRenderer { uint16_t* vramBBGExtPal[4]; uint16_t* vramBOBJExtPal; union DSOAM* oam; + struct DSGX* gx; }; struct DS; diff --git a/src/ds/gx.c b/src/ds/gx.c index c77937ebf..f2f9715af 100644 --- a/src/ds/gx.c +++ b/src/ds/gx.c @@ -13,6 +13,13 @@ mLOG_DEFINE_CATEGORY(DS_GX, "DS GX"); #define DS_GX_FIFO_SIZE 256 #define DS_GX_PIPE_SIZE 4 +static void DSGXDummyRendererInit(struct DSGXRenderer* renderer); +static void DSGXDummyRendererReset(struct DSGXRenderer* renderer); +static void DSGXDummyRendererDeinit(struct DSGXRenderer* renderer); +static void DSGXDummyRendererSetRAM(struct DSGXRenderer* renderer, struct DSGXVertex* verts, struct DSGXPolygon* polys, unsigned polyCount); +static void DSGXDummyRendererDrawScanline(struct DSGXRenderer* renderer, int y); +static void DSGXDummyRendererGetScanline(struct DSGXRenderer* renderer, int y, color_t** output); + static const int32_t _gxCommandCycleBase[DS_GX_CMD_MAX] = { [DS_GX_CMD_NOP] = 0, [DS_GX_CMD_MTX_MODE] = 2, @@ -91,6 +98,15 @@ static const int32_t _gxCommandParams[DS_GX_CMD_MAX] = { [DS_GX_CMD_VEC_TEST] = 1, }; +static struct DSGXRenderer dummyRenderer = { + .init = DSGXDummyRendererInit, + .reset = DSGXDummyRendererReset, + .deinit = DSGXDummyRendererDeinit, + .setRAM = DSGXDummyRendererSetRAM, + .drawScanline = DSGXDummyRendererDrawScanline, + .getScanline = DSGXDummyRendererGetScanline, +}; + static void _pullPipe(struct DSGX* gx) { if (CircleBufferSize(&gx->fifo) >= sizeof(struct DSGXEntry)) { struct DSGXEntry entry = { 0 }; @@ -171,6 +187,7 @@ static void _fifoRun(struct mTiming* timing, void* context, uint32_t cyclesLate) } void DSGXInit(struct DSGX* gx) { + gx->renderer = &dummyRenderer; CircleBufferInit(&gx->fifo, sizeof(struct DSGXEntry) * DS_GX_FIFO_SIZE); CircleBufferInit(&gx->pipe, sizeof(struct DSGXEntry) * DS_GX_PIPE_SIZE); gx->fifoEvent.name = "DS GX FIFO"; @@ -180,6 +197,7 @@ void DSGXInit(struct DSGX* gx) { } void DSGXDeinit(struct DSGX* gx) { + DSGXAssociateRenderer(gx, &dummyRenderer); CircleBufferDeinit(&gx->fifo); CircleBufferDeinit(&gx->pipe); } @@ -192,6 +210,12 @@ void DSGXReset(struct DSGX* gx) { memset(gx->outstandingCommand, 0, sizeof(gx->outstandingCommand)); } +void DSGXAssociateRenderer(struct DSGX* gx, struct DSGXRenderer* renderer) { + gx->renderer->deinit(gx->renderer); + gx->renderer = renderer; + gx->renderer->init(gx->renderer); +} + void DSGXUpdateGXSTAT(struct DSGX* gx) { uint32_t value = gx->p->memory.io9[DS9_REG_GXSTAT_HI >> 1] << 16; value = DSRegGXSTATIsDoIRQ(value); @@ -379,3 +403,39 @@ void DSGXSwapBuffers(struct DSGX* gx) { mTimingSchedule(&gx->p->ds9.timing, &gx->fifoEvent, 0); } } + +static void DSGXDummyRendererInit(struct DSGXRenderer* renderer) { + UNUSED(renderer); + // Nothing to do +} + +static void DSGXDummyRendererReset(struct DSGXRenderer* renderer) { + UNUSED(renderer); + // Nothing to do +} + +static void DSGXDummyRendererDeinit(struct DSGXRenderer* renderer) { + UNUSED(renderer); + // Nothing to do +} + +static void DSGXDummyRendererSetRAM(struct DSGXRenderer* renderer, struct DSGXVertex* verts, struct DSGXPolygon* polys, unsigned polyCount) { + UNUSED(renderer); + UNUSED(verts); + UNUSED(polys); + UNUSED(polyCount); + // Nothing to do +} + +static void DSGXDummyRendererDrawScanline(struct DSGXRenderer* renderer, int y) { + UNUSED(renderer); + UNUSED(y); + // Nothing to do +} + +static void DSGXDummyRendererGetScanline(struct DSGXRenderer* renderer, int y, color_t** output) { + UNUSED(renderer); + UNUSED(y); + *output = NULL; + // Nothing to do +} diff --git a/src/ds/renderers/software.c b/src/ds/renderers/software.c index 4dabf3dbb..4bfab7017 100644 --- a/src/ds/renderers/software.c +++ b/src/ds/renderers/software.c @@ -7,6 +7,7 @@ #include "gba/renderers/software-private.h" #include +#include #include static void DSVideoSoftwareRendererInit(struct DSVideoRenderer* renderer); @@ -354,7 +355,7 @@ static void DSVideoSoftwareRendererInvalidateExtPal(struct DSVideoRenderer* rend _regenerateExtPalette(softwareRenderer, obj, engB, slot); } -static void DSVideoSoftwareRendererDrawGBAScanline(struct GBAVideoRenderer* renderer, int y) { +static void DSVideoSoftwareRendererDrawGBAScanline(struct GBAVideoRenderer* renderer, struct DSGX* gx, int y) { struct GBAVideoSoftwareRenderer* softwareRenderer = (struct GBAVideoSoftwareRenderer*) renderer; int x; @@ -381,7 +382,9 @@ static void DSVideoSoftwareRendererDrawGBAScanline(struct GBAVideoRenderer* rend GBAVideoSoftwareRendererPostprocessSprite(softwareRenderer, priority); } if (TEST_LAYER_ENABLED(0)) { - if (DSRegisterDISPCNTIs3D(softwareRenderer->dispcnt)) { + if (DSRegisterDISPCNTIs3D(softwareRenderer->dispcnt) && gx) { + color_t* scanline; + gx->renderer->getScanline(gx->renderer, y, &scanline); // TODO } else { GBAVideoSoftwareRendererDrawBackgroundMode0(softwareRenderer, &softwareRenderer->bg[0], y); @@ -472,7 +475,7 @@ static void _drawScanlineA(struct DSVideoSoftwareRenderer* softwareRenderer, int } return; case 1: - DSVideoSoftwareRendererDrawGBAScanline(&softwareRenderer->engA.d, y); + DSVideoSoftwareRendererDrawGBAScanline(&softwareRenderer->engA.d, softwareRenderer->d.gx, y); return; case 2: { uint16_t* vram = &softwareRenderer->d.vram[0x10000 * DSRegisterDISPCNTGetVRAMBlock(softwareRenderer->dispcntA)]; @@ -527,7 +530,7 @@ static void _drawScanlineB(struct DSVideoSoftwareRenderer* softwareRenderer, int } return; case 1: - DSVideoSoftwareRendererDrawGBAScanline(&softwareRenderer->engB.d, y); + DSVideoSoftwareRendererDrawGBAScanline(&softwareRenderer->engB.d, NULL, y); return; }