diff --git a/src/platform/3ds/ctr-gpu.c b/src/platform/3ds/ctr-gpu.c index fe61c0566..02810e221 100644 --- a/src/platform/3ds/ctr-gpu.c +++ b/src/platform/3ds/ctr-gpu.c @@ -26,23 +26,21 @@ struct ctrUIVertex { 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 @@ bool ctrInitGpu() { return true; } -void ctrDeinitGpu() { +void ctrDeinitGpu(void) { if (ctrVertexBuffer) { linearFree(ctrVertexBuffer); ctrVertexBuffer = NULL; @@ -110,10 +108,23 @@ void ctrSetViewportSize(s16 w, s16 h, bool tilt) { 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 @@ void ctrAddRectEx(u32 color, s16 x, s16 y, s16 w, s16 h, s16 u, s16 v, s16 uw, s 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); } diff --git a/src/platform/3ds/ctr-gpu.h b/src/platform/3ds/ctr-gpu.h index e4d30965f..b271636f9 100644 --- a/src/platform/3ds/ctr-gpu.h +++ b/src/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 diff --git a/src/platform/3ds/main.c b/src/platform/3ds/main.c index 7912ca8b0..3377b3be9 100644 --- a/src/platform/3ds/main.c +++ b/src/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 _csndPlaySound(u32 flags, u32 sampleRate, float vol, void* left, voi 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 @@ static int _batteryState(void) { } static void _guiPrepare(void) { + _frameStart(); C3D_FrameDrawOn(bottomScreen[doubleBuffer]); ctrSetViewportSize(320, 240, true); } @@ -442,12 +460,8 @@ static void _gameUnloaded(struct mGUIRunner* runner) { } } -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 _incrementScreenMode(struct mGUIRunner* runner) { 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 @@ int main() { .teardown = 0, .gameLoaded = _gameLoaded, .gameUnloaded = _gameUnloaded, - .prepareForFrame = _storeCounter, + .prepareForFrame = 0, .drawFrame = _drawFrame, .drawScreenshot = _drawScreenshot, .paused = _gameUnloaded,