DS GX: Start implementing matrix operations
Vicki Pfau vi@endrift.com
Mon, 27 Feb 2017 17:51:30 -0800
4 files changed,
142 insertions(+),
0 deletions(-)
M
include/mgba/internal/ds/gx.h
→
include/mgba/internal/ds/gx.h
@@ -13,6 +13,7 @@
#include <mgba/core/interface.h> #include <mgba/core/log.h> #include <mgba/core/timing.h> +#include <mgba/internal/ds/matrix.h> #include <mgba-util/circle-buffer.h> mLOG_DECLARE_CATEGORY(DS_GX);@@ -119,10 +120,24 @@
int outstandingParams[4]; uint8_t outstandingCommand[4]; + int activeParams; + int activeEntries[32]; + bool swapBuffers; int bufferIndex; struct DSGXVertex* vertexBuffer[2]; struct DSGXPolygon* polygonBuffer[2]; + + int mtxMode; + struct DSGXMatrix projMatrixStack; + struct DSGXMatrix texMatrixStack; + struct DSGXMatrix posMatrixStack[32]; + struct DSGXMatrix vecMatrixStack[32]; + + struct DSGXMatrix projMatrix; + struct DSGXMatrix texMatrix; + struct DSGXMatrix posMatrix; + struct DSGXMatrix vecMatrix; }; void DSGXInit(struct DSGX*);
A
include/mgba/internal/ds/matrix.h
@@ -0,0 +1,21 @@
+/* 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_MATRIX_H +#define DS_MATRIX_H + +#include <mgba-util/common.h> + +CXX_GUARD_START + +struct DSGXMatrix { + int32_t m[16]; // 20.12 +}; + +void DSGXMtxIdentity(struct DSGXMatrix*); + +CXX_GUARD_END + +#endif
M
src/ds/gx.c
→
src/ds/gx.c
@@ -145,6 +145,10 @@ if (gx->swapBuffers) {
break; } + DSRegGXSTAT gxstat = gx->p->memory.io9[DS9_REG_GXSTAT_LO >> 1]; + int pvMatrixPointer = DSRegGXSTATGetPVMatrixStackLevel(gxstat); + int projMatrixPointer = DSRegGXSTATGetProjMatrixStackLevel(gxstat); + if (CircleBufferSize(&gx->pipe) <= 2 * sizeof(struct DSGXEntry)) { _pullPipe(gx); }@@ -165,6 +169,71 @@ CircleBufferRead8(&gx->pipe, (int8_t*) &entry.params[2]);
CircleBufferRead8(&gx->pipe, (int8_t*) &entry.params[3]); switch (entry.command) { + case DS_GX_CMD_MTX_MODE: + if (entry.params[0] < 4) { + gx->mtxMode = entry.params[0]; + } else { + mLOG(DS_GX, GAME_ERROR, "Invalid GX MTX_MODE %02X", entry.params[0]); + } + break; + case DS_GX_CMD_MTX_IDENTITY: + switch (gx->mtxMode) { + case 0: + DSGXMtxIdentity(&gx->projMatrix); + break; + case 2: + DSGXMtxIdentity(&gx->vecMatrix); + // Fall through + case 1: + DSGXMtxIdentity(&gx->posMatrix); + break; + case 3: + DSGXMtxIdentity(&gx->texMatrix); + break; + } + break; + case DS_GX_CMD_MTX_PUSH: + switch (gx->mtxMode) { + case 0: + memcpy(&gx->projMatrixStack, &gx->projMatrix, sizeof(gx->projMatrix)); + ++projMatrixPointer; + break; + case 2: + memcpy(&gx->vecMatrixStack[pvMatrixPointer & 0x1F], &gx->vecMatrix, sizeof(gx->vecMatrix)); + // Fall through + case 1: + memcpy(&gx->posMatrixStack[pvMatrixPointer & 0x1F], &gx->posMatrix, sizeof(gx->posMatrix)); + ++pvMatrixPointer; + break; + case 3: + mLOG(DS_GX, STUB, "Unimplemented GX MTX_PUSH mode"); + break; + } + break; + case DS_GX_CMD_MTX_POP: { + int8_t offset = entry.params[0]; + offset <<= 2; + offset >>= 2; + switch (gx->mtxMode) { + case 0: + projMatrixPointer -= offset; + memcpy(&gx->projMatrix, &gx->projMatrixStack, sizeof(gx->projMatrix)); + break; + case 1: + pvMatrixPointer -= offset; + memcpy(&gx->posMatrix, &gx->posMatrixStack[pvMatrixPointer & 0x1F], sizeof(gx->posMatrix)); + break; + case 2: + pvMatrixPointer -= offset; + memcpy(&gx->vecMatrix, &gx->vecMatrixStack[pvMatrixPointer & 0x1F], sizeof(gx->vecMatrix)); + memcpy(&gx->posMatrix, &gx->posMatrixStack[pvMatrixPointer & 0x1F], sizeof(gx->posMatrix)); + break; + case 3: + mLOG(DS_GX, STUB, "Unimplemented GX MTX_POP mode"); + break; + } + break; + } case DS_GX_CMD_SWAP_BUFFERS: gx->swapBuffers = true; break;@@ -172,6 +241,12 @@ default:
mLOG(DS_GX, STUB, "Unimplemented GX command %02X:%02X %02X %02X %02X", entry.command, entry.params[0], entry.params[1], entry.params[2], entry.params[3]); break; } + + gxstat = DSRegGXSTATSetPVMatrixStackLevel(gxstat, pvMatrixPointer); + gxstat = DSRegGXSTATSetProjMatrixStackLevel(gxstat, projMatrixPointer); + gxstat = DSRegGXSTATTestFillMatrixStackError(gxstat, projMatrixPointer || pvMatrixPointer >= 0x1F); + gx->p->memory.io9[DS9_REG_GXSTAT_LO >> 1] = gxstat; + if (cyclesLate >= cycles) { cyclesLate -= cycles; }@@ -205,7 +280,22 @@
void DSGXReset(struct DSGX* gx) { CircleBufferClear(&gx->fifo); CircleBufferClear(&gx->pipe); + DSGXMtxIdentity(&gx->projMatrix); + DSGXMtxIdentity(&gx->texMatrix); + DSGXMtxIdentity(&gx->posMatrix); + DSGXMtxIdentity(&gx->vecMatrix); + + DSGXMtxIdentity(&gx->projMatrixStack); + DSGXMtxIdentity(&gx->texMatrixStack); + int i; + for (i = 0; i < 32; ++i) { + DSGXMtxIdentity(&gx->posMatrixStack[i]); + DSGXMtxIdentity(&gx->vecMatrixStack[i]); + } gx->swapBuffers = false; + gx->bufferIndex = 0; + gx->mtxMode = 0; + memset(gx->outstandingParams, 0, sizeof(gx->outstandingParams)); memset(gx->outstandingCommand, 0, sizeof(gx->outstandingCommand)); }
A
src/ds/matrix.c
@@ -0,0 +1,16 @@
+/* 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/matrix.h> + +#define MTX_ONE 0x00001000 + +void DSGXMtxIdentity(struct DSGXMatrix* mtx) { + memset(mtx, 0, sizeof(*mtx)); + mtx->m[0] = MTX_ONE; + mtx->m[5] = MTX_ONE; + mtx->m[10] = MTX_ONE; + mtx->m[15] = MTX_ONE; +}