all repos — mgba @ 10b14f90d136881c6cf94d67cd809b767a8bde88

mGBA Game Boy Advance Emulator

3DS: Improve graphics pipeline, framelimiting
Vicki Pfau vi@endrift.com
Sat, 02 Sep 2017 15:05:14 -0700
commit

10b14f90d136881c6cf94d67cd809b767a8bde88

parent

41f27bf617daa6daeb13f9fba97fdeac1761bee1

3 files changed, 64 insertions(+), 46 deletions(-)

jump to
M src/platform/3ds/ctr-gpu.csrc/platform/3ds/ctr-gpu.c

@@ -26,23 +26,21 @@ u32 abgr;

float rotate[2]; }; -#define MAX_NUM_QUADS 256 -#define BUFFER_PARTITIONS 4 -#define VERTEX_BUFFER_SIZE MAX_NUM_QUADS * BUFFER_PARTITIONS * sizeof(struct ctrUIVertex) +#define MAX_NUM_QUADS 4096 +#define VERTEX_BUFFER_SIZE MAX_NUM_QUADS * sizeof(struct ctrUIVertex) static struct ctrUIVertex* ctrVertexBuffer = NULL; static int ctrNumVerts = 0; static int ctrVertStart = 0; -static int ctrVertPartition = 0; -static C3D_Tex* activeTexture = NULL; +static const C3D_Tex* activeTexture = NULL; static shaderProgram_s uiProgram; static DVLB_s* uiShader = NULL; static int GSH_FVEC_projectionMtx; static int GSH_FVEC_textureMtx; -bool ctrInitGpu() { +bool ctrInitGpu(void) { // Load vertex shader binary uiShader = DVLB_ParseFile((u32*) uishader, uishader_size); if (uiShader == NULL) {

@@ -85,7 +83,7 @@

return true; } -void ctrDeinitGpu() { +void ctrDeinitGpu(void) { if (ctrVertexBuffer) { linearFree(ctrVertexBuffer); ctrVertexBuffer = NULL;

@@ -110,10 +108,23 @@ }

C3D_FVUnifMtx4x4(GPU_GEOMETRY_SHADER, GSH_FVEC_projectionMtx, &projectionMtx); } -void ctrActivateTexture(C3D_Tex* texture) { +void ctrFlushBatch(void) { + int thisBatch = ctrNumVerts - ctrVertStart; + if (!thisBatch) { + return; + } + if (thisBatch < 0) { + svcBreak(USERBREAK_PANIC); + } + C3D_DrawArrays(GPU_GEOMETRY_PRIM, ctrVertStart, thisBatch); + ctrVertStart = ctrNumVerts; +} + +void ctrActivateTexture(const C3D_Tex* texture) { if (texture == activeTexture) { return; } + if (activeTexture) { ctrFlushBatch(); }

@@ -174,16 +185,11 @@ if (y >= 240 && h >= 0) {

return; } - if (ctrNumVerts + ctrVertStart == MAX_NUM_QUADS) { - ctrFlushBatch(); - ++ctrVertPartition; - if (ctrVertPartition == BUFFER_PARTITIONS) { - svcBreak(USERBREAK_PANIC); - } - ctrVertStart = ctrVertPartition * MAX_NUM_QUADS; + if (ctrNumVerts == MAX_NUM_QUADS) { + abort(); } - struct ctrUIVertex* vtx = &ctrVertexBuffer[ctrVertStart + ctrNumVerts]; + struct ctrUIVertex* vtx = &ctrVertexBuffer[ctrNumVerts]; vtx->x = x; vtx->y = y; vtx->w = w;

@@ -203,24 +209,17 @@ void ctrAddRect(u32 color, s16 x, s16 y, s16 u, s16 v, s16 w, s16 h) {

ctrAddRectEx(color, x, y, w, h, u, v, w, h, 0); } -void ctrFlushBatch(void) { - if (ctrNumVerts == 0) { - return; - } +void ctrStartFrame(void) { + ctrNumVerts = 0; + ctrVertStart = 0; + activeTexture = NULL; C3D_BufInfo* bufInfo = C3D_GetBufInfo(); BufInfo_Init(bufInfo); - BufInfo_Add(bufInfo, &ctrVertexBuffer[ctrVertStart], sizeof(struct ctrUIVertex), 4, 0x3210); - - GSPGPU_FlushDataCache(&ctrVertexBuffer[ctrVertStart], sizeof(struct ctrUIVertex) * ctrNumVerts); - C3D_DrawArrays(GPU_GEOMETRY_PRIM, 0, ctrNumVerts); - - ctrVertStart += ctrNumVerts; - ctrNumVerts = 0; + BufInfo_Add(bufInfo, ctrVertexBuffer, sizeof(struct ctrUIVertex), 4, 0x3210); } -void ctrFinalize(void) { +void ctrEndFrame(void) { ctrFlushBatch(); - ctrVertStart = 0; - ctrVertPartition = 0; + GSPGPU_FlushDataCache(ctrVertexBuffer, sizeof(struct ctrUIVertex) * ctrNumVerts); }
M src/platform/3ds/ctr-gpu.hsrc/platform/3ds/ctr-gpu.h

@@ -16,12 +16,13 @@ void ctrDeinitGpu(void);

void ctrSetViewportSize(s16 w, s16 h, bool tilt); -void ctrActivateTexture(C3D_Tex* texture); +void ctrActivateTexture(const C3D_Tex* texture); void ctrTextureMultiply(void); void ctrTextureBias(u32 color); void ctrAddRectEx(u32 color, s16 x, s16 y, s16 w, s16 h, s16 u, s16 v, s16 uw, s16 vh, float rotate); void ctrAddRect(u32 color, s16 x, s16 y, s16 u, s16 v, s16 w, s16 h); void ctrFlushBatch(void); -void ctrFinalize(void); +void ctrStartFrame(void); +void ctrEndFrame(void); #endif
M src/platform/3ds/main.csrc/platform/3ds/main.c

@@ -92,11 +92,12 @@ static C3D_Tex outputTexture;

static ndspWaveBuf dspBuffer[DSP_BUFFERS]; static int bufferId = 0; static bool frameLimiter = true; -static unsigned frameCounter; +static u64 tickCounter; static C3D_RenderTarget* topScreen[2]; static C3D_RenderTarget* bottomScreen[2]; static int doubleBuffer = 0; +static bool frameStarted = false; static C3D_RenderTarget* upscaleBuffer; static C3D_Tex upscaleBufferTex;

@@ -226,22 +227,38 @@

static void _postAudioBuffer(struct mAVStream* stream, blip_t* left, blip_t* right); static void _drawStart(void) { - C3D_FrameBegin(frameLimiter ? 0 : C3D_FRAME_NONBLOCK); +} + +static void _frameStart(void) { + if (frameStarted) { + return; + } + frameStarted = true; + u8 flags = 0; + if (!frameLimiter) { + if (tickCounter + 4481000 > svcGetSystemTick()) { + flags = C3D_FRAME_NONBLOCK; + } else { + tickCounter = svcGetSystemTick(); + } + } + C3D_FrameBegin(flags); // Mark both buffers used to make sure they get cleared C3D_FrameDrawOn(topScreen[doubleBuffer]); C3D_FrameDrawOn(bottomScreen[doubleBuffer]); + ctrStartFrame(); } static void _drawEnd(void) { - ctrFinalize(); + if (!frameStarted) { + return; + } + ctrEndFrame(); C3D_RenderTargetSetOutput(topScreen[doubleBuffer], GFX_TOP, GFX_LEFT, GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGB8) | GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGB8)); C3D_RenderTargetSetOutput(bottomScreen[doubleBuffer], GFX_BOTTOM, GFX_LEFT, GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGB8) | GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGB8)); C3D_FrameEnd(GX_CMDLIST_FLUSH); - if (frameLimiter) { - while (frameCounter == C3D_FrameCounter(0)) { - gspWaitForAnyEvent(); - } - } + frameStarted = false; + doubleBuffer ^= 1; C3D_FrameBufClear(&bottomScreen[doubleBuffer]->frameBuf, C3D_CLEAR_COLOR, 0, 0); C3D_FrameBufClear(&topScreen[doubleBuffer]->frameBuf, C3D_CLEAR_COLOR, 0, 0);

@@ -263,6 +280,7 @@ return state | charge;

} static void _guiPrepare(void) { + _frameStart(); C3D_FrameDrawOn(bottomScreen[doubleBuffer]); ctrSetViewportSize(320, 240, true); }

@@ -442,12 +460,8 @@ break;

} } -static void _storeCounter(struct mGUIRunner* runner) { - UNUSED(runner); - frameCounter = C3D_FrameCounter(0); -} - static void _drawTex(struct mCore* core, bool faded) { + _frameStart(); unsigned screen_w, screen_h; switch (screenMode) { case SM_PA_BOTTOM:

@@ -657,7 +671,11 @@ }

static void _setFrameLimiter(struct mGUIRunner* runner, bool limit) { UNUSED(runner); + if (frameLimiter == limit) { + return; + } frameLimiter = limit; + tickCounter = svcGetSystemTick(); } static uint32_t _pollInput(const struct mInputMap* map) {

@@ -995,7 +1013,7 @@ .setup = _setup,

.teardown = 0, .gameLoaded = _gameLoaded, .gameUnloaded = _gameUnloaded, - .prepareForFrame = _storeCounter, + .prepareForFrame = 0, .drawFrame = _drawFrame, .drawScreenshot = _drawScreenshot, .paused = _gameUnloaded,