diff --git a/src/platform/3ds/ctr-gpu.c b/src/platform/3ds/ctr-gpu.c index 1ac1b7ece..65d29e174 100644 --- a/src/platform/3ds/ctr-gpu.c +++ b/src/platform/3ds/ctr-gpu.c @@ -31,13 +31,15 @@ static struct ctrUIVertex* ctrVertexBuffer = NULL; static u16* ctrIndexBuffer = NULL; static u16 ctrNumQuads = 0; -static void* gpuColorBuffer = NULL; +static void* gpuColorBuffer[2] = { NULL, NULL }; static u32* gpuCommandList = NULL; static void* screenTexture = NULL; static shaderProgram_s gpuShader; static DVLB_s* passthroughShader = NULL; +static int pendingEvents = 0; + static const struct ctrTexture* activeTexture = NULL; static u32 _f24FromFloat(float f) { @@ -85,6 +87,17 @@ static u32 _f31FromFloat(float f) { return sign << 30 | exponent << 23 | mantissa; } +void ctrClearPending(int events) { + int toClear = events & pendingEvents; + if (toClear & (1 << GSPEVENT_PSC0)) { + gspWaitForPSC0(); + } + if (toClear & (1 << GSPEVENT_PPF)) { + gspWaitForPPF(); + } + pendingEvents ^= toClear; +} + // Replacements for the limiting GPU_SetViewport function in ctrulib static void _GPU_SetFramebuffer(intptr_t colorBuffer, intptr_t depthBuffer, u16 w, u16 h) { u32 buf[4]; @@ -145,10 +158,11 @@ Result ctrInitGpu() { Result res = -1; // Allocate buffers - gpuColorBuffer = vramAlloc(400 * 240 * 4); + gpuColorBuffer[0] = vramAlloc(400 * 240 * 4); + gpuColorBuffer[1] = vramAlloc(320 * 240 * 4); gpuCommandList = linearAlloc(COMMAND_LIST_LENGTH * sizeof(u32)); ctrVertexBuffer = linearAlloc(VERTEX_INDEX_BUFFER_SIZE); - if (gpuColorBuffer == NULL || gpuCommandList == NULL || ctrVertexBuffer == NULL) { + if (gpuColorBuffer[0] == NULL || gpuColorBuffer[1] == NULL || gpuCommandList == NULL || ctrVertexBuffer == NULL) { res = -1; goto error_allocs; } @@ -197,9 +211,14 @@ error_allocs: gpuCommandList = NULL; } - if (gpuColorBuffer != NULL) { - vramFree(gpuColorBuffer); - gpuColorBuffer = NULL; + if (gpuColorBuffer[0] != NULL) { + vramFree(gpuColorBuffer[0]); + gpuColorBuffer[0] = NULL; + } + + if (gpuColorBuffer[1] != NULL) { + vramFree(gpuColorBuffer[1]); + gpuColorBuffer[1] = NULL; } return res; } @@ -221,22 +240,31 @@ void ctrDeinitGpu() { linearFree(gpuCommandList); gpuCommandList = NULL; - vramFree(gpuColorBuffer); - gpuColorBuffer = NULL; + vramFree(gpuColorBuffer[0]); + gpuColorBuffer[0] = NULL; + + vramFree(gpuColorBuffer[1]); + gpuColorBuffer[1] = NULL; } -void ctrGpuBeginFrame(void) { +void ctrGpuBeginFrame(int screen) { + if (screen > 1) { + return; + } + + int fw; + if (screen == 0) { + fw = 400; + } else { + fw = 320; + } + + _GPU_SetFramebuffer(osConvertVirtToPhys((u32)gpuColorBuffer[screen]), 0, 240, fw); +} + +void ctrGpuBeginDrawing(void) { shaderProgramUse(&gpuShader); - void* gpuColorBufferEnd = (char*)gpuColorBuffer + 240 * 400 * 4; - - GX_SetMemoryFill(NULL, - gpuColorBuffer, 0x00000000, gpuColorBufferEnd, GX_FILL_32BIT_DEPTH | GX_FILL_TRIGGER, - NULL, 0, NULL, 0); - gspWaitForPSC0(); - - _GPU_SetFramebuffer(osConvertVirtToPhys((u32)gpuColorBuffer), 0, 240, 400); - // Disable depth and stencil testing GPU_SetDepthTestAndWriteMask(false, GPU_ALWAYS, GPU_WRITE_COLOR); GPU_SetStencilTest(false, GPU_ALWAYS, 0, 0xFF, 0); @@ -286,20 +314,47 @@ void ctrGpuBeginFrame(void) { bufferOffsets, arrayTargetAttributes, numAttributesInArray); } -void ctrGpuEndFrame(void* outputFramebuffer, int w, int h) { +void ctrGpuEndFrame(int screen, void* outputFramebuffer, int w, int h) { + if (screen > 1) { + return; + } + + int fw; + if (screen == 0) { + fw = 400; + } else { + fw = 320; + } + ctrFlushBatch(); - void* colorBuffer = (u8*)gpuColorBuffer + ((400 - w) * 240 * 4); + void* colorBuffer = (u8*)gpuColorBuffer[screen] + ((fw - w) * 240 * 4); const u32 GX_CROP_INPUT_LINES = (1 << 2); + ctrClearPending(1 << GSPEVENT_PSC0); + ctrClearPending(1 << GSPEVENT_PPF); + GX_SetDisplayTransfer(NULL, - colorBuffer, GX_BUFFER_DIM(240, 400), + colorBuffer, GX_BUFFER_DIM(240, fw), outputFramebuffer, GX_BUFFER_DIM(h, w), GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGBA8) | GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGB8) | GX_CROP_INPUT_LINES); - gspWaitForPPF(); + pendingEvents |= (1 << GSPEVENT_PPF); +} + +void ctrGpuEndDrawing(void) { + ctrClearPending(1 << GSPEVENT_PPF); + gfxSwapBuffersGpu(); + gspWaitForEvent(GSPEVENT_VBlank0, false); + + void* gpuColorBuffer0End = (char*)gpuColorBuffer[0] + 240 * 400 * 4; + void* gpuColorBuffer1End = (char*)gpuColorBuffer[1] + 240 * 320 * 4; + GX_SetMemoryFill(NULL, + gpuColorBuffer[0], 0x00000000, gpuColorBuffer0End, GX_FILL_32BIT_DEPTH | GX_FILL_TRIGGER, + gpuColorBuffer[1], 0x00000000, gpuColorBuffer1End, GX_FILL_32BIT_DEPTH | GX_FILL_TRIGGER); + pendingEvents |= 1 << GSPEVENT_PSC0; } void ctrSetViewportSize(s16 w, s16 h) { @@ -389,6 +444,8 @@ void ctrFlushBatch(void) { return; } + ctrClearPending((1 << GSPEVENT_PSC0)); + GSPGPU_FlushDataCache(NULL, (u8*)ctrVertexBuffer, VERTEX_INDEX_BUFFER_SIZE); GPU_DrawElements(GPU_UNKPRIM, (u32*)(osConvertVirtToPhys((u32)ctrIndexBuffer) - VRAM_BASE), ctrNumQuads * 6); diff --git a/src/platform/3ds/ctr-gpu.h b/src/platform/3ds/ctr-gpu.h index 0a0637d3f..a761815a0 100644 --- a/src/platform/3ds/ctr-gpu.h +++ b/src/platform/3ds/ctr-gpu.h @@ -28,8 +28,10 @@ inline void ctrTexture_Init(struct ctrTexture* tex) { Result ctrInitGpu(void); void ctrDeinitGpu(void); -void ctrGpuBeginFrame(void); -void ctrGpuEndFrame(void* outputFramebuffer, int w, int h); +void ctrGpuBeginDrawing(void); +void ctrGpuBeginFrame(int screen); +void ctrGpuEndFrame(int screen, void* outputFramebuffer, int w, int h); +void ctrGpuEndDrawing(void); void ctrSetViewportSize(s16 w, s16 h); diff --git a/src/platform/3ds/main.c b/src/platform/3ds/main.c index 988095f4d..70b0236c9 100644 --- a/src/platform/3ds/main.c +++ b/src/platform/3ds/main.c @@ -60,10 +60,12 @@ extern bool allocateRomBuffer(void); static void _postAudioBuffer(struct GBAAVStream* stream, struct GBAAudio* audio); static void _drawStart(void) { - ctrGpuBeginFrame(); + ctrGpuBeginDrawing(); if (screenMode < SM_PA_TOP || (guiDrawn & GUI_ACTIVE)) { + ctrGpuBeginFrame(GFX_BOTTOM); ctrSetViewportSize(320, 240); } else { + ctrGpuBeginFrame(GFX_TOP); ctrSetViewportSize(400, 240); } guiDrawn &= ~GUI_THIS_FRAME; @@ -78,11 +80,10 @@ static void _drawEnd(void) { if (!(guiDrawn & GUI_THIS_FRAME) || screen == GFX_BOTTOM) { void* outputFramebuffer = gfxGetFramebuffer(screen, GFX_LEFT, &height, &width); - ctrGpuEndFrame(outputFramebuffer, width, height); + ctrGpuEndFrame(screen, outputFramebuffer, width, height); } - gfxSwapBuffersGpu(); - gspWaitForEvent(GSPEVENT_VBlank0, false); + ctrGpuEndDrawing(); } static int _batteryState(void) { @@ -110,9 +111,9 @@ static void _guiPrepare(void) { u16 width = 0, height = 0; void* outputFramebuffer = gfxGetFramebuffer(screen, GFX_LEFT, &height, &width); - ctrGpuEndFrame(outputFramebuffer, width, height); + ctrGpuEndFrame(screen, outputFramebuffer, width, height); - ctrGpuBeginFrame(); + ctrGpuBeginFrame(GFX_BOTTOM); ctrSetViewportSize(320, 240); } @@ -125,7 +126,7 @@ static void _guiFinish(void) { u16 width = 0, height = 0; void* outputFramebuffer = gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, &height, &width); - ctrGpuEndFrame(outputFramebuffer, width, height); + ctrGpuEndFrame(GFX_BOTTOM, outputFramebuffer, width, height); } static void _setup(struct GBAGUIRunner* runner) {