diff --git a/include/mgba/internal/ds/gx.h b/include/mgba/internal/ds/gx.h index ea1b76a23..c3eff83cc 100644 --- a/include/mgba/internal/ds/gx.h +++ b/include/mgba/internal/ds/gx.h @@ -139,6 +139,7 @@ struct DSGXRenderer { void (*setRAM)(struct DSGXRenderer* renderer, struct DSGXVertex* verts, struct DSGXPolygon* polys, unsigned polyCount, bool wSort); void (*drawScanline)(struct DSGXRenderer* renderer, int y); void (*getScanline)(struct DSGXRenderer* renderer, int y, const color_t** output); + void (*writeRegister)(struct DSGXRenderer* renderer, uint32_t address, uint16_t value); uint16_t* tex[4]; uint16_t* texPal[6]; diff --git a/include/mgba/internal/ds/gx/software.h b/include/mgba/internal/ds/gx/software.h index 7abbf64c0..2e951f039 100644 --- a/include/mgba/internal/ds/gx/software.h +++ b/include/mgba/internal/ds/gx/software.h @@ -93,6 +93,8 @@ struct DSGXSoftwareRenderer { uint8_t* stencilBuffer; color_t* scanlineCache; int sort; + uint16_t clearStencil; + color_t clearColor; bool flushPending; struct DSGXVertex* verts; diff --git a/src/ds/gx.c b/src/ds/gx.c index 705a969b9..68f873503 100644 --- a/src/ds/gx.c +++ b/src/ds/gx.c @@ -20,6 +20,7 @@ static void DSGXDummyRendererInvalidateTex(struct DSGXRenderer* renderer, int sl static void DSGXDummyRendererSetRAM(struct DSGXRenderer* renderer, struct DSGXVertex* verts, struct DSGXPolygon* polys, unsigned polyCount, bool wSort); static void DSGXDummyRendererDrawScanline(struct DSGXRenderer* renderer, int y); static void DSGXDummyRendererGetScanline(struct DSGXRenderer* renderer, int y, const color_t** output); +static void DSGXDummyRendererWriteRegister(struct DSGXRenderer* renderer, uint32_t address, uint16_t value); static void DSGXWriteFIFO(struct DSGX* gx, struct DSGXEntry entry); @@ -111,6 +112,7 @@ static struct DSGXRenderer dummyRenderer = { .setRAM = DSGXDummyRendererSetRAM, .drawScanline = DSGXDummyRendererDrawScanline, .getScanline = DSGXDummyRendererGetScanline, + .writeRegister = DSGXDummyRendererWriteRegister, }; static void _pullPipe(struct DSGX* gx) { @@ -1436,6 +1438,10 @@ uint16_t DSGXWriteRegister(struct DSGX* gx, uint32_t address, uint16_t value) { case DS9_REG_DISP3DCNT: mLOG(DS_GX, STUB, "Unimplemented GX write %03X:%04X", address, value); break; + case DS9_REG_CLEAR_COLOR_LO: + case DS9_REG_CLEAR_COLOR_HI: + gx->renderer->writeRegister(gx->renderer, address, value); + break; case DS9_REG_GXSTAT_LO: value = DSRegGXSTATIsMatrixStackError(value); if (value) { @@ -1483,6 +1489,10 @@ uint32_t DSGXWriteRegister32(struct DSGX* gx, uint32_t address, uint32_t value) value = (value & 0xFFFF0000) | DSGXWriteRegister(gx, DS9_REG_GXSTAT_LO, value); value = (value & 0x0000FFFF) | (DSGXWriteRegister(gx, DS9_REG_GXSTAT_HI, value >> 16) << 16); break; + case DS9_REG_CLEAR_COLOR_LO: + gx->renderer->writeRegister(gx->renderer, address, value); + gx->renderer->writeRegister(gx->renderer, address + 2, value >> 16); + break; default: if (address < DS9_REG_GXFIFO_00) { mLOG(DS_GX, STUB, "Unimplemented GX write %03X:%08X", address, value); @@ -1583,3 +1593,10 @@ static void DSGXDummyRendererGetScanline(struct DSGXRenderer* renderer, int y, c *output = NULL; // Nothing to do } + +static void DSGXDummyRendererWriteRegister(struct DSGXRenderer* renderer, uint32_t address, uint16_t value) { + UNUSED(renderer); + UNUSED(address); + UNUSED(value); + // Nothing to do +} diff --git a/src/ds/gx/software.c b/src/ds/gx/software.c index d1b5759c2..dc9a4638b 100644 --- a/src/ds/gx/software.c +++ b/src/ds/gx/software.c @@ -6,6 +6,7 @@ #include #include +#include #include "gba/renderers/software-private.h" DEFINE_VECTOR(DSGXSoftwarePolygonList, struct DSGXSoftwarePolygon); @@ -18,6 +19,7 @@ static void DSGXSoftwareRendererInvalidateTex(struct DSGXRenderer* renderer, int static void DSGXSoftwareRendererSetRAM(struct DSGXRenderer* renderer, struct DSGXVertex* verts, struct DSGXPolygon* polys, unsigned polyCount, bool wSort); static void DSGXSoftwareRendererDrawScanline(struct DSGXRenderer* renderer, int y); static void DSGXSoftwareRendererGetScanline(struct DSGXRenderer* renderer, int y, const color_t** output); +static void DSGXSoftwareRendererWriteRegister(struct DSGXRenderer* renderer, uint32_t address, uint16_t value); static void _expandColor(uint16_t c15, uint8_t* r, uint8_t* g, uint8_t* b) { *r = ((c15 << 1) & 0x3E) | 1; @@ -407,6 +409,7 @@ void DSGXSoftwareRendererCreate(struct DSGXSoftwareRenderer* renderer) { renderer->d.setRAM = DSGXSoftwareRendererSetRAM; renderer->d.drawScanline = DSGXSoftwareRendererDrawScanline; renderer->d.getScanline = DSGXSoftwareRendererGetScanline; + renderer->d.writeRegister = DSGXSoftwareRendererWriteRegister; } static void DSGXSoftwareRendererInit(struct DSGXRenderer* renderer) { @@ -420,6 +423,8 @@ static void DSGXSoftwareRendererInit(struct DSGXRenderer* renderer) { static void DSGXSoftwareRendererReset(struct DSGXRenderer* renderer) { struct DSGXSoftwareRenderer* softwareRenderer = (struct DSGXSoftwareRenderer*) renderer; + softwareRenderer->clearColor = 0; + softwareRenderer->clearStencil = 0; } static void DSGXSoftwareRendererDeinit(struct DSGXRenderer* renderer) { @@ -705,13 +710,22 @@ static void DSGXSoftwareRendererSetRAM(struct DSGXRenderer* renderer, struct DSG poly->polyId = DSGXSoftwarePolygonListSize(&softwareRenderer->activePolys) - 1; } - memset(softwareRenderer->scanlineCache, 0, sizeof(color_t) * DS_VIDEO_VERTICAL_PIXELS * DS_VIDEO_HORIZONTAL_PIXELS); - memset(softwareRenderer->stencilBuffer, 0, sizeof(uint8_t) * DS_VIDEO_VERTICAL_PIXELS * DS_VIDEO_HORIZONTAL_PIXELS); + color_t clearColor = softwareRenderer->clearColor; + uint16_t clearStencil = softwareRenderer->clearStencil; + for (i = 0; i < DS_VIDEO_VERTICAL_PIXELS * DS_VIDEO_HORIZONTAL_PIXELS ; i += 4) { softwareRenderer->depthBuffer[i] = INT32_MAX; softwareRenderer->depthBuffer[i + 1] = INT32_MAX; softwareRenderer->depthBuffer[i + 2] = INT32_MAX; softwareRenderer->depthBuffer[i + 3] = INT32_MAX; + softwareRenderer->scanlineCache[i] = clearColor; + softwareRenderer->scanlineCache[i + 1] = clearColor; + softwareRenderer->scanlineCache[i + 2] = clearColor; + softwareRenderer->scanlineCache[i + 3] = clearColor; + softwareRenderer->stencilBuffer[i] = clearStencil; + softwareRenderer->stencilBuffer[i + 1] = clearStencil; + softwareRenderer->stencilBuffer[i + 2] = clearStencil; + softwareRenderer->stencilBuffer[i + 3] = clearStencil; } softwareRenderer->flushPending = true; } @@ -761,3 +775,20 @@ static void DSGXSoftwareRendererGetScanline(struct DSGXRenderer* renderer, int y struct DSGXSoftwareRenderer* softwareRenderer = (struct DSGXSoftwareRenderer*) renderer; *output = &softwareRenderer->scanlineCache[DS_VIDEO_HORIZONTAL_PIXELS * y]; } + +static void DSGXSoftwareRendererWriteRegister(struct DSGXRenderer* renderer, uint32_t address, uint16_t value) { + struct DSGXSoftwareRenderer* softwareRenderer = (struct DSGXSoftwareRenderer*) renderer; + switch (address) { + case DS9_REG_CLEAR_COLOR_LO: + softwareRenderer->clearColor &= 0xFF000000; + softwareRenderer->clearColor |= (value & 0x001F) << 3; + softwareRenderer->clearColor |= (value & 0x03E0) << 6; + softwareRenderer->clearColor |= (value & 0x7C00) << 9; + break; + case DS9_REG_CLEAR_COLOR_HI: + softwareRenderer->clearColor &= 0x00FFFFFF; + softwareRenderer->clearColor |= (value & 0x001F) << 27; + softwareRenderer->clearStencil = (value & 0x3F00) >> 8; + break; + } +}