From a37648f42fe5a8f9a30899e1b3889a2eebb25e30 Mon Sep 17 00:00:00 2001 From: fincs Date: Sat, 26 Mar 2016 00:30:43 +0100 Subject: [PATCH] Add renderqueue-safe versions of GX_DisplayTransfer/TextureCopy/MemoryFill --- include/c3d/renderqueue.h | 4 ++++ source/renderqueue.c | 47 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/include/c3d/renderqueue.h b/include/c3d/renderqueue.h index 5ccec65..1865663 100644 --- a/include/c3d/renderqueue.h +++ b/include/c3d/renderqueue.h @@ -40,3 +40,7 @@ C3D_RenderTarget* C3D_RenderTargetCreate(int width, int height, int colorFmt, in void C3D_RenderTargetDelete(C3D_RenderTarget* target); void C3D_RenderTargetSetClear(C3D_RenderTarget* target, u32 clearBits, u32 clearColor, u32 clearDepth); void C3D_RenderTargetSetOutput(C3D_RenderTarget* target, gfxScreen_t screen, gfx3dSide_t side, u32 transferFlags); + +void C3D_SafeDisplayTransfer(u32* inadr, u32 indim, u32* outadr, u32 outdim, u32 flags); +void C3D_SafeTextureCopy(u32* inadr, u32 indim, u32* outadr, u32 outdim, u32 size, u32 flags); +void C3D_SafeMemoryFill(u32* buf0a, u32 buf0v, u32* buf0e, u16 control0, u32* buf1a, u32 buf1v, u32* buf1e, u16 control1); diff --git a/source/renderqueue.c b/source/renderqueue.c index a1d6878..67dd13b 100644 --- a/source/renderqueue.c +++ b/source/renderqueue.c @@ -16,7 +16,7 @@ static struct } queuedFrame[2]; static u8 queueSwap, queuedCount, queuedState; -static bool inFrame; +static bool inFrame, inSafeTransfer, inSafeClear; static void onRenderFinish(void* unused); static void onTransferFinish(void* unused); @@ -30,6 +30,7 @@ static void performDraw(void) static void performTransfer(void) { + if (inSafeTransfer) return; // Let the safe transfer finish handler retry this C3D_RenderBuf* renderBuf = &transferQueue->renderBuf; u32* frameBuf = (u32*)gfxGetFramebuffer(transferQueue->screen, transferQueue->side, NULL, NULL); if (transferQueue->side == GFX_LEFT) @@ -40,6 +41,7 @@ static void performTransfer(void) static void performClear(void) { + if (inSafeClear) return; // Let the safe clear finish handler retry this C3D_RenderBuf* renderBuf = &clearQueue->renderBuf; // TODO: obey renderBuf->clearBits gspSetEventCallback(renderBuf->colorBuf.data ? GSPGPU_EVENT_PSC0 : GSPGPU_EVENT_PSC1, onClearDone, NULL, true); @@ -153,6 +155,14 @@ void onRenderFinish(void* unused) void onTransferFinish(void* unused) { C3D_RenderTarget* target = transferQueue; + if (inSafeTransfer) + { + inSafeTransfer = false; + // Try again if there are queued transfers + if (target) + performTransfer(); + return; + } transferQueue = target->link; if (target->clearBits) clearTarget(target); @@ -167,6 +177,14 @@ void onTransferFinish(void* unused) void onClearDone(void* unused) { C3D_RenderTarget* target = clearQueue; + if (inSafeClear) + { + inSafeClear = false; + // Try again if there are queued clears + if (target) + performClear(); + return; + } clearQueue = target->link; target->drawOk = true; if (clearQueue) @@ -357,3 +375,30 @@ void C3D_RenderTargetSetOutput(C3D_RenderTarget* target, gfxScreen_t screen, gfx target->screen = screen; target->side = side; } + +void C3D_SafeDisplayTransfer(u32* inadr, u32 indim, u32* outadr, u32 outdim, u32 flags) +{ + while (transferQueue || inSafeTransfer) + gspWaitForPPF(); + inSafeTransfer = true; + gspSetEventCallback(GSPGPU_EVENT_PPF, onTransferFinish, NULL, true); + GX_DisplayTransfer(inadr, indim, outadr, outdim, flags); +} + +void C3D_SafeTextureCopy(u32* inadr, u32 indim, u32* outadr, u32 outdim, u32 size, u32 flags) +{ + while (transferQueue || inSafeTransfer) + gspWaitForPPF(); + inSafeTransfer = true; + gspSetEventCallback(GSPGPU_EVENT_PPF, onTransferFinish, NULL, true); + GX_TextureCopy(inadr, indim, outadr, outdim, size, flags); +} + +void C3D_SafeMemoryFill(u32* buf0a, u32 buf0v, u32* buf0e, u16 control0, u32* buf1a, u32 buf1v, u32* buf1e, u16 control1) +{ + while (clearQueue || inSafeClear) + gspWaitForAnyEvent(); + inSafeClear = true; + gspSetEventCallback(buf0a ? GSPGPU_EVENT_PSC0 : GSPGPU_EVENT_PSC1, onClearDone, NULL, true); + GX_MemoryFill(buf0a, buf0v, buf0e, control0, buf1a, buf1v, buf1e, control1); +}