all repos — mgba @ 338d29f5adb7e4c132dc6b5d6b00a4d20c2bc243

mGBA Game Boy Advance Emulator

DS GX: Start implementing matrix operations
Vicki Pfau vi@endrift.com
Mon, 27 Feb 2017 17:51:30 -0800
commit

338d29f5adb7e4c132dc6b5d6b00a4d20c2bc243

parent

e8bfc7bcca086623f232c1a88456fa6dae2193e2

4 files changed, 142 insertions(+), 0 deletions(-)

jump to
M include/mgba/internal/ds/gx.hinclude/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.csrc/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; +}