From 0d36359615d5c502ad153a3040c522bb247a8c33 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sun, 7 Apr 2024 15:27:56 +1000 Subject: [PATCH] 3DS: Try to fix crash sometimes when quitting game --- src/Graphics_3DS.c | 37 ++++++++++--------- third_party/citro3d.c | 83 +++++++++---------------------------------- 2 files changed, 37 insertions(+), 83 deletions(-) diff --git a/src/Graphics_3DS.c b/src/Graphics_3DS.c index 3743f1baa..b7a49522c 100644 --- a/src/Graphics_3DS.c +++ b/src/Graphics_3DS.c @@ -109,9 +109,10 @@ static void SwitchProgram(void) { /*########################################################################################################################* *---------------------------------------------------------General---------------------------------------------------------* *#########################################################################################################################*/ -static C3D_RenderTarget* topTargetLeft; -static C3D_RenderTarget* topTargetRight; -static C3D_RenderTarget* bottomTarget; +static C3D_RenderTarget topTargetLeft; +static C3D_RenderTarget topTargetRight; +static C3D_RenderTarget bottomTarget; +static cc_bool createdTopTargetRight; static void AllocShaders(void) { Shader_Alloc(&shaders[0], coloured_shbin, coloured_shbin_size); @@ -135,13 +136,13 @@ static void SetDefaultState(void) { static void InitCitro3D(void) { C3D_Init(C3D_DEFAULT_CMDBUF_SIZE * 4); - topTargetLeft = C3D_RenderTargetCreate(240, 400, GPU_RB_RGBA8, GPU_RB_DEPTH24); - C3D_RenderTargetSetOutput(topTargetLeft, GFX_TOP, GFX_LEFT, DISPLAY_TRANSFER_FLAGS); + C3D_RenderTargetCreate(&topTargetLeft, 240, 400, GPU_RB_RGBA8, GPU_RB_DEPTH24); + C3D_RenderTargetSetOutput(&topTargetLeft, GFX_TOP, GFX_LEFT, DISPLAY_TRANSFER_FLAGS); // Even though the bottom screen is 320 pixels wide, we use 400 here so that the same ortho matrix // can be used for both screens. The output is clipped to the actual screen width, anyway. - bottomTarget = C3D_RenderTargetCreate(240, 400, GPU_RB_RGBA8, GPU_RB_DEPTH24); - C3D_RenderTargetSetOutput(bottomTarget, GFX_BOTTOM, GFX_LEFT, DISPLAY_TRANSFER_FLAGS); + C3D_RenderTargetCreate(&bottomTarget, 240, 400, GPU_RB_RGBA8, GPU_RB_DEPTH24); + C3D_RenderTargetSetOutput(&bottomTarget, GFX_BOTTOM, GFX_LEFT, DISPLAY_TRANSFER_FLAGS); gfxSetDoubleBuffering(GFX_TOP, true); SetDefaultState(); @@ -151,6 +152,7 @@ static void InitCitro3D(void) { static GfxResourceID white_square; void Gfx_Create(void) { if (!Gfx.Created) InitCitro3D(); + else C3Di_RenderQueueInit(); Gfx.MaxTexWidth = 1024; Gfx.MaxTexHeight = 1024; @@ -166,6 +168,8 @@ void Gfx_Create(void) { void Gfx_Free(void) { Gfx_FreeState(); + C3Di_RenderQueueExit(); + // FreeShaders() // C3D_Fini() } @@ -190,7 +194,7 @@ void Gfx_FreeState(void) { } void Gfx_3DS_SetRenderScreen(enum Screen3DS screen) { - C3D_FrameDrawOn(screen == TOP_SCREEN ? topTargetLeft : bottomTarget); + C3D_FrameDrawOn(screen == TOP_SCREEN ? &topTargetLeft : &bottomTarget); } @@ -217,13 +221,14 @@ void Gfx_Set3DLeft(struct Matrix* proj, struct Matrix* view) { void Gfx_Set3DRight(struct Matrix* proj, struct Matrix* view) { Calc3DProjection(+1, proj); - if (!topTargetRight) { - topTargetRight = C3D_RenderTargetCreate(240, 400, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8); - C3D_RenderTargetSetOutput(topTargetRight, GFX_TOP, GFX_RIGHT, DISPLAY_TRANSFER_FLAGS); + if (!createdTopTargetRight) { + C3D_RenderTargetCreate(&topTargetRight, 240, 400, GPU_RB_RGBA8, GPU_RB_DEPTH24); + C3D_RenderTargetSetOutput(&topTargetRight, GFX_TOP, GFX_RIGHT, DISPLAY_TRANSFER_FLAGS); + createdTopTargetRight = true; } - C3D_RenderTargetClear(topTargetRight, C3D_CLEAR_ALL, clear_color, 0); - C3D_FrameDrawOn(topTargetRight); + C3D_RenderTargetClear(&topTargetRight, C3D_CLEAR_ALL, clear_color, 0); + C3D_FrameDrawOn(&topTargetRight); } void Gfx_End3D(struct Matrix* proj, struct Matrix* view) { @@ -532,7 +537,7 @@ void Gfx_BeginFrame(void) { if (gfx_vsync) C3D_FrameSync(); C3D_FrameBegin(0); - C3D_FrameDrawOn(topTargetLeft); + C3D_FrameDrawOn(&topTargetLeft); extern void C3Di_UpdateContext(void); C3Di_UpdateContext(); @@ -543,8 +548,8 @@ void Gfx_ClearBuffers(GfxBuffers buffers) { if (buffers & GFX_BUFFER_COLOR) targets |= C3D_CLEAR_COLOR; if (buffers & GFX_BUFFER_DEPTH) targets |= C3D_CLEAR_DEPTH; - C3D_RenderTargetClear(topTargetLeft, targets, clear_color, 0); - C3D_RenderTargetClear(bottomTarget, targets, 0, 0); + C3D_RenderTargetClear(&topTargetLeft, targets, clear_color, 0); + C3D_RenderTargetClear(&bottomTarget, targets, 0, 0); } void Gfx_EndFrame(void) { diff --git a/third_party/citro3d.c b/third_party/citro3d.c index 96afe5e76..b5e31b163 100644 --- a/third_party/citro3d.c +++ b/third_party/citro3d.c @@ -311,13 +311,9 @@ typedef struct C3D_RenderTarget_tag C3D_RenderTarget; struct C3D_RenderTarget_tag { - C3D_RenderTarget *next, *prev; C3D_FrameBuf frameBuf; - bool used; - bool ownsColor, ownsDepth; - - bool linked; + bool used, linked; gfxScreen_t screen; gfx3dSide_t side; u32 transferFlags; @@ -337,7 +333,7 @@ static bool C3D_FrameDrawOn(C3D_RenderTarget* target); static void C3D_FrameSplit(u8 flags); static void C3D_FrameEnd(u8 flags); -static C3D_RenderTarget* C3D_RenderTargetCreate(int width, int height, GPU_COLORBUF colorFmt, GPU_DEPTHBUF depthFmt); +static void C3D_RenderTargetCreate(C3D_RenderTarget* target, int width, int height, GPU_COLORBUF colorFmt, GPU_DEPTHBUF depthFmt); static void C3D_RenderTargetDelete(C3D_RenderTarget* target); static void C3D_RenderTargetSetOutput(C3D_RenderTarget* target, gfxScreen_t screen, gfx3dSide_t side, u32 transferFlags); @@ -977,7 +973,6 @@ static void C3D_ImmDrawEnd(void) -static C3D_RenderTarget *firstTarget, *lastTarget; static C3D_RenderTarget *linkedTarget[3]; static bool inFrame, inSafeTransfer; @@ -1069,23 +1064,11 @@ static void C3Di_RenderQueueInit(void) static void C3Di_RenderQueueExit(void) { - int i; - C3D_RenderTarget *a, *next; - C3Di_WaitAndClearQueue(-1); gxCmdQueueSetCallback(&C3Di_GetContext()->gxQueue, NULL, NULL); GX_BindQueue(NULL); C3Di_RenderQueueDisableVBlank(); - - for (i = 0; i < 3; i ++) - linkedTarget[i] = NULL; - - for (a = firstTarget; a; a = next) - { - next = a->next; - C3Di_RenderTargetDestroy(a); - } } static void C3Di_RenderQueueWaitDone(void) @@ -1161,70 +1144,36 @@ static void C3D_FrameEnd(u8 flags) gxCmdQueueRun(&ctx->gxQueue); } -static C3D_RenderTarget* C3Di_RenderTargetNew(void) +void C3D_RenderTargetCreate(C3D_RenderTarget* target, int width, int height, GPU_COLORBUF colorFmt, GPU_DEPTHBUF depthFmt) { - C3D_RenderTarget* target = (C3D_RenderTarget*)malloc(sizeof(C3D_RenderTarget)); - if (!target) return NULL; - memset(target, 0, sizeof(C3D_RenderTarget)); - return target; -} - -static void C3Di_RenderTargetFinishInit(C3D_RenderTarget* target) -{ - target->prev = lastTarget; - target->next = NULL; - if (lastTarget) - lastTarget->next = target; - if (!firstTarget) - firstTarget = target; - lastTarget = target; -} - -C3D_RenderTarget* C3D_RenderTargetCreate(int width, int height, GPU_COLORBUF colorFmt, GPU_DEPTHBUF depthFmt) -{ - void* depthBuf = NULL; - void* colorBuf = vramAlloc(C3D_CalcColorBufSize(width,height,colorFmt)); - if (!colorBuf) goto _fail0; - + size_t colorSize = C3D_CalcColorBufSize(width,height,colorFmt); size_t depthSize = C3D_CalcDepthBufSize(width,height,depthFmt); + memset(target, 0, sizeof(C3D_RenderTarget)); + + void* depthBuf = NULL; + void* colorBuf = vramAlloc(colorSize); + if (!colorBuf) goto _fail; + vramAllocPos vramBank = addrGetVRAMBank(colorBuf); depthBuf = vramAllocAt(depthSize, vramBank ^ VRAM_ALLOC_ANY); // Attempt opposite bank first... if (!depthBuf) depthBuf = vramAllocAt(depthSize, vramBank); // ... if that fails, attempt same bank - if (!depthBuf) goto _fail1; - - C3D_RenderTarget* target = C3Di_RenderTargetNew(); - if (!target) goto _fail2; + if (!depthBuf) goto _fail; C3D_FrameBuf* fb = &target->frameBuf; C3D_FrameBufAttrib(fb, width, height, false); C3D_FrameBufColor(fb, colorBuf, colorFmt); C3D_FrameBufDepth(fb, depthBuf, depthFmt); - target->ownsDepth = true; - target->ownsColor = true; + return; - C3Di_RenderTargetFinishInit(target); - return target; - -_fail2: +_fail: if (depthBuf) vramFree(depthBuf); -_fail1: - vramFree(colorBuf); -_fail0: - return NULL; + if (colorBuf) vramFree(colorBuf); } static void C3Di_RenderTargetDestroy(C3D_RenderTarget* target) { - if (target->ownsColor) - vramFree(target->frameBuf.colorBuf); - if (target->ownsDepth) - vramFree(target->frameBuf.depthBuf); - - C3D_RenderTarget** prevNext = target->prev ? &target->prev->next : &firstTarget; - C3D_RenderTarget** nextPrev = target->next ? &target->next->prev : &lastTarget; - *prevNext = target->next; - *nextPrev = target->prev; - free(target); + vramFree(target->frameBuf.colorBuf); + vramFree(target->frameBuf.depthBuf); } static void C3D_RenderTargetDelete(C3D_RenderTarget* target)