all repos — mgba @ 465dc2b40048e70380ed26a7451d208f4e643d6c

mGBA Game Boy Advance Emulator

3DS: Allow for multiple screens, increasing async ability
Jeffrey Pfau jeffrey@endrift.com
Sat, 19 Sep 2015 19:42:34 -0700
commit

465dc2b40048e70380ed26a7451d208f4e643d6c

parent

8ffcb116f2f65fbf09122d7568e59ad61fa5bfc3

3 files changed, 89 insertions(+), 29 deletions(-)

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

@@ -31,12 +31,14 @@ 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;

@@ -85,6 +87,17 @@

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 @@ linearFree(gpuCommandList);

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,21 +240,30 @@ GPUCMD_SetBuffer(NULL, 0, 0);

linearFree(gpuCommandList); gpuCommandList = NULL; - vramFree(gpuColorBuffer); - gpuColorBuffer = NULL; + vramFree(gpuColorBuffer[0]); + gpuColorBuffer[0] = NULL; + + vramFree(gpuColorBuffer[1]); + gpuColorBuffer[1] = NULL; } -void ctrGpuBeginFrame(void) { - shaderProgramUse(&gpuShader); +void ctrGpuBeginFrame(int screen) { + if (screen > 1) { + return; + } - void* gpuColorBufferEnd = (char*)gpuColorBuffer + 240 * 400 * 4; + int fw; + if (screen == 0) { + fw = 400; + } else { + fw = 320; + } - GX_SetMemoryFill(NULL, - gpuColorBuffer, 0x00000000, gpuColorBufferEnd, GX_FILL_32BIT_DEPTH | GX_FILL_TRIGGER, - NULL, 0, NULL, 0); - gspWaitForPSC0(); + _GPU_SetFramebuffer(osConvertVirtToPhys((u32)gpuColorBuffer[screen]), 0, 240, fw); +} - _GPU_SetFramebuffer(osConvertVirtToPhys((u32)gpuColorBuffer), 0, 240, 400); +void ctrGpuBeginDrawing(void) { + shaderProgramUse(&gpuShader); // Disable depth and stencil testing GPU_SetDepthTestAndWriteMask(false, GPU_ALWAYS, GPU_WRITE_COLOR);

@@ -286,20 +314,47 @@ 1, // Use 1 vertex array

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) {

@@ -388,6 +443,8 @@ void ctrFlushBatch(void) {

if (ctrNumQuads == 0) { 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);
M src/platform/3ds/ctr-gpu.hsrc/platform/3ds/ctr-gpu.h

@@ -28,8 +28,10 @@

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);
M src/platform/3ds/main.csrc/platform/3ds/main.c

@@ -60,10 +60,12 @@

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 @@ }

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 @@

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 @@ }

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) {