+
+
3#include <c3d/renderqueue.h>
+
+
+
6static C3D_RenderTarget *firstTarget, *lastTarget;
+
7static C3D_RenderTarget *linkedTarget[3];
+
+
9static TickCounter gpuTime, cpuTime;
+
+
11static bool inFrame, inSafeTransfer, measureGpuTime;
+
12static bool needSwapTop, needSwapBot, isTopStereo;
+
13static float framerate = 60.0f;
+
14static float framerateCounter[2] = { 60.0f, 60.0f };
+
15static u32 frameCounter[2];
+
16static void (* frameEndCb)(
void*);
+
17static void* frameEndCbData;
+
+
19static void C3Di_RenderTargetDestroy(C3D_RenderTarget* target);
+
+
21static bool framerateLimit(
int id)
+
+
23 framerateCounter[id] -= framerate;
+
24 if (framerateCounter[
id] <= 0.0f)
+
+
26 framerateCounter[id] += 60.0f;
+
+
+
+
+
+
+
+
34 if (framerateLimit(0))
+
+
+
+
+
+
40 if (framerateLimit(1))
+
+
+
+
44static void onQueueFinish(gxCmdQueue_s* queue)
+
+
+
+
48 osTickCounterUpdate(&gpuTime);
+
49 measureGpuTime =
false;
+
+
+
+
53 inSafeTransfer =
false;
+
+
+
56 gxCmdQueueStop(queue);
+
57 gxCmdQueueClear(queue);
+
+
+
+
+
+
+
64 gfxScreenSwapBuffers(GFX_TOP, isTopStereo);
+
+
+
+
+
69 gfxScreenSwapBuffers(GFX_BOTTOM,
false);
+
+
+
+
+
+
+
+
+
78 u32 start[2] = { frameCounter[0], frameCounter[1] };
+
+
+
+
82 cur[0] = frameCounter[0];
+
83 cur[1] = frameCounter[1];
+
84 }
while (cur[0]==start[0] || cur[1]==start[1]);
+
+
+
+
+
89 return frameCounter[id];
+
+
+
92static bool C3Di_WaitAndClearQueue(s64 timeout)
+
+
94 gxCmdQueue_s* queue = &C3Di_GetContext()->gxQueue;
+
95 if (!gxCmdQueueWait(queue, timeout))
+
+
97 gxCmdQueueStop(queue);
+
98 gxCmdQueueClear(queue);
+
+
+
+
+
+
104 gspSetEventCallback(GSPGPU_EVENT_VBlank0, onVBlank0, NULL,
false);
+
105 gspSetEventCallback(GSPGPU_EVENT_VBlank1, onVBlank1, NULL,
false);
+
+
+
+
+
110 gspSetEventCallback(GSPGPU_EVENT_VBlank0, NULL, NULL,
false);
+
111 gspSetEventCallback(GSPGPU_EVENT_VBlank1, NULL, NULL,
false);
+
+
+
+
+
+
+
+
+
+
121 gxCmdQueueSetCallback(&ctx->
gxQueue, onQueueFinish, NULL);
+
+
+
+
+
+
+
128 C3D_RenderTarget *a, *next;
+
+
130 C3Di_WaitAndClearQueue(-1);
+
131 gxCmdQueueSetCallback(&C3Di_GetContext()->gxQueue, NULL, NULL);
+
+
+
+
+
136 for (i = 0; i < 3; i ++)
+
137 linkedTarget[i] = NULL;
+
+
139 for (a = firstTarget; a; a = next)
+
+
+
142 C3Di_RenderTargetDestroy(a);
+
+
+
+
+
+
148 C3Di_WaitAndClearQueue(-1);
+
+
+
+
+
153 float old = framerate;
+
154 if (fps > 0.0f && fps <= 60.0f)
+
+
+
157 framerateCounter[0] = fps;
+
158 framerateCounter[1] = fps;
+
+
+
+
+
+
+
+
166 if (inFrame)
return false;
+
+
168 if (flags & C3D_FRAME_SYNCDRAW)
+
+
170 if (!C3Di_WaitAndClearQueue((flags & C3D_FRAME_NONBLOCK) ? 0 : -1))
+
+
+
+
174 osTickCounterStart(&cpuTime);
+
+
+
+
+
+
+
181 if (!inFrame)
return false;
+
+
+
+
185 C3D_SetViewport(0, 0, target->frameBuf.width, target->frameBuf.height);
+
+
+
+
+
+
191 u32 *cmdBuf, cmdBufSize;
+
192 if (!inFrame)
return;
+
+
194 GX_ProcessCommandList(cmdBuf, cmdBufSize*4, flags);
+
+
+
+
+
+
200 if (!inFrame)
return;
+
+
+
203 frameEndCb(frameEndCbData);
+
+
+
206 GPUCMD_SetBuffer(NULL, 0, 0);
+
207 osTickCounterUpdate(&cpuTime);
+
+
+
+
211 if (!(flags & GX_CMDLIST_FLUSH))
+
+
213 extern u32 __ctru_linear_heap;
+
214 extern u32 __ctru_linear_heap_size;
+
215 GSPGPU_FlushDataCache((
void*)__ctru_linear_heap, __ctru_linear_heap_size);
+
+
+
+
219 C3D_RenderTarget* target;
+
+
221 for (i = 2; i >= 0; i --)
+
+
223 target = linkedTarget[i];
+
224 if (!target || !target->used)
+
+
226 target->used =
false;
+
+
228 if (target->screen == GFX_TOP)
+
+
+
231 if (target->side == GFX_RIGHT)
+
+
+
234 else if (target->screen == GFX_BOTTOM)
+
+
+
+
238 measureGpuTime =
true;
+
239 osTickCounterStart(&gpuTime);
+
+
+
+
+
+
+
246 frameEndCbData = param;
+
+
+
+
+
251 return osTickCounterRead(&gpuTime);
+
+
+
+
+
256 return osTickCounterRead(&cpuTime);
+
+
+
259static C3D_RenderTarget* C3Di_RenderTargetNew(
void)
+
+
261 C3D_RenderTarget* target = (C3D_RenderTarget*)malloc(
sizeof(C3D_RenderTarget));
+
262 if (!target)
return NULL;
+
263 memset(target, 0,
sizeof(C3D_RenderTarget));
+
+
+
+
267static void C3Di_RenderTargetFinishInit(C3D_RenderTarget* target)
+
+
269 target->prev = lastTarget;
+
+
+
272 lastTarget->next = target;
+
+
274 firstTarget = target;
+
+
+
+
+
+
280 GPU_DEPTHBUF depthFmtReal = GPU_RB_DEPTH16;
+
281 void* depthBuf = NULL;
+
+
283 if (!colorBuf)
goto _fail0;
+
284 if (C3D_DEPTHTYPE_OK(depthFmt))
+
+
286 depthFmtReal = C3D_DEPTHTYPE_VAL(depthFmt);
+
+
288 vramAllocPos vramBank = addrGetVRAMBank(colorBuf);
+
289 depthBuf = vramAllocAt(depthSize, vramBank ^ VRAM_ALLOC_ANY);
+
290 if (!depthBuf) depthBuf = vramAllocAt(depthSize, vramBank);
+
291 if (!depthBuf)
goto _fail1;
+
+
+
294 C3D_RenderTarget* target = C3Di_RenderTargetNew();
+
295 if (!target)
goto _fail2;
+
+
297 C3D_FrameBuf* fb = &target->frameBuf;
+
298 C3D_FrameBufAttrib(fb, width, height,
false);
+
299 C3D_FrameBufColor(fb, colorBuf, colorFmt);
+
300 target->ownsColor =
true;
+
+
+
303 C3D_FrameBufDepth(fb, depthBuf, depthFmtReal);
+
304 target->ownsDepth =
true;
+
+
306 C3Di_RenderTargetFinishInit(target);
+
+
+
+
310 if (depthBuf) vramFree(depthBuf);
+
+
+
+
+
+
+
+
+
319 if (!addrIsVRAM(tex->data))
return NULL;
+
320 C3D_RenderTarget* target = C3Di_RenderTargetNew();
+
321 if (!target)
return NULL;
+
+
323 C3D_FrameBuf* fb = &target->frameBuf;
+
+
+
326 if (C3D_DEPTHTYPE_OK(depthFmt))
+
+
328 GPU_DEPTHBUF depthFmtReal = C3D_DEPTHTYPE_VAL(depthFmt);
+
+
330 vramAllocPos vramBank = addrGetVRAMBank(tex->data);
+
331 void* depthBuf = vramAllocAt(depthSize, vramBank ^ VRAM_ALLOC_ANY);
+
332 if (!depthBuf) depthBuf = vramAllocAt(depthSize, vramBank);
+
+
+
+
+
+
+
339 C3D_FrameBufDepth(fb, depthBuf, depthFmtReal);
+
340 target->ownsDepth =
true;
+
+
+
343 C3Di_RenderTargetFinishInit(target);
+
+
+
+
347void C3Di_RenderTargetDestroy(C3D_RenderTarget* target)
+
+
349 if (target->ownsColor)
+
350 vramFree(target->frameBuf.colorBuf);
+
351 if (target->ownsDepth)
+
352 vramFree(target->frameBuf.depthBuf);
+
+
354 C3D_RenderTarget** prevNext = target->prev ? &target->prev->next : &firstTarget;
+
355 C3D_RenderTarget** nextPrev = target->next ? &target->next->prev : &lastTarget;
+
356 *prevNext = target->next;
+
357 *nextPrev = target->prev;
+
+
+
+
+
+
+
364 svcBreak(USERBREAK_PANIC);
+
+
366 C3D_RenderTargetDetachOutput(target);
+
+
368 C3Di_WaitAndClearQueue(-1);
+
369 C3Di_RenderTargetDestroy(target);
+
+
+
+
+
+
375 if (screen==GFX_BOTTOM)
id = 2;
+
376 else if (side==GFX_RIGHT)
id = 1;
+
377 if (linkedTarget[
id])
+
+
379 linkedTarget[id]->linked =
false;
+
+
381 C3Di_WaitAndClearQueue(-1);
+
+
383 linkedTarget[id] = target;
+
+
+
386 target->linked =
true;
+
387 target->transferFlags = transferFlags;
+
388 target->screen = screen;
+
+
+
+
+
393static void C3Di_SafeDisplayTransfer(u32* inadr, u32 indim, u32* outadr, u32 outdim, u32 flags)
+
+
395 C3Di_WaitAndClearQueue(-1);
+
396 inSafeTransfer =
true;
+
397 GX_DisplayTransfer(inadr, indim, outadr, outdim, flags);
+
398 gxCmdQueueRun(&C3Di_GetContext()->gxQueue);
+
+
+
401static void C3Di_SafeTextureCopy(u32* inadr, u32 indim, u32* outadr, u32 outdim, u32 size, u32 flags)
+
+
403 C3Di_WaitAndClearQueue(-1);
+
404 inSafeTransfer =
true;
+
405 GX_TextureCopy(inadr, indim, outadr, outdim, size, flags);
+
406 gxCmdQueueRun(&C3Di_GetContext()->gxQueue);
+
+
+
409static void C3Di_SafeMemoryFill(u32* buf0a, u32 buf0v, u32* buf0e, u16 control0, u32* buf1a, u32 buf1v, u32* buf1e, u16 control1)
+
+
411 C3Di_WaitAndClearQueue(-1);
+
412 inSafeTransfer =
true;
+
413 GX_MemoryFill(buf0a, buf0v, buf0e, control0, buf1a, buf1v, buf1e, control1);
+
414 gxCmdQueueRun(&C3Di_GetContext()->gxQueue);
+
+
+
+
+
+
+
+
422 GX_DisplayTransfer(inadr, indim, outadr, outdim, flags);
+
+
+
425 C3Di_SafeDisplayTransfer(inadr, indim, outadr, outdim, flags);
+
+
+
+
+
+
+
+
+
+
435 GX_TextureCopy(inadr, indim, outadr, outdim, size, flags);
+
+
+
438 C3Di_SafeTextureCopy(inadr, indim, outadr, outdim, size, flags);
+
+
+
+
+
443void C3D_SyncMemoryFill(u32* buf0a, u32 buf0v, u32* buf0e, u16 control0, u32* buf1a, u32 buf1v, u32* buf1e, u16 control1)
+
+
+
+
+
448 GX_MemoryFill(buf0a, buf0v, buf0e, control0, buf1a, buf1v, buf1e, control1);
+
+
+
451 C3Di_SafeMemoryFill(buf0a, buf0v, buf0e, control0, buf1a, buf1v, buf1e, control1);
+
+
+
+
bool C3Di_SplitFrame(u32 **pBuf, u32 *pSize)
+
void C3D_SetViewport(u32 x, u32 y, u32 w, u32 h)
+
void C3D_FrameBufTex(C3D_FrameBuf *fb, C3D_Tex *tex, GPU_TEXFACE face, int level)
+
void C3D_FrameBufTransfer(C3D_FrameBuf *frameBuf, gfxScreen_t screen, gfx3dSide_t side, u32 transferFlags)
+
u32 C3D_CalcColorBufSize(u32 width, u32 height, GPU_COLORBUF fmt)
+
u32 C3D_CalcDepthBufSize(u32 width, u32 height, GPU_DEPTHBUF fmt)
+
void C3D_SetFrameBuf(C3D_FrameBuf *fb)
+
+
+
void C3D_FrameEndHook(void(*hook)(void *), void *param)
+
void C3Di_RenderQueueInit(void)
+
bool C3D_FrameDrawOn(C3D_RenderTarget *target)
+
void C3D_FrameSplit(u8 flags)
+
C3D_RenderTarget * C3D_RenderTargetCreateFromTex(C3D_Tex *tex, GPU_TEXFACE face, int level, C3D_DEPTHTYPE depthFmt)
+
void C3D_SyncTextureCopy(u32 *inadr, u32 indim, u32 *outadr, u32 outdim, u32 size, u32 flags)
+
+
float C3D_GetProcessingTime(void)
+
float C3D_GetDrawingTime(void)
+
u32 C3D_FrameCounter(int id)
+
C3D_RenderTarget * C3D_RenderTargetCreate(int width, int height, GPU_COLORBUF colorFmt, C3D_DEPTHTYPE depthFmt)
+
void C3Di_RenderQueueDisableVBlank(void)
+
void C3Di_RenderQueueEnableVBlank(void)
+
bool C3D_FrameBegin(u8 flags)
+
void C3Di_RenderQueueWaitDone(void)
+
void C3D_SyncMemoryFill(u32 *buf0a, u32 buf0v, u32 *buf0e, u16 control0, u32 *buf1a, u32 buf1v, u32 *buf1e, u16 control1)
+
float C3D_FrameRate(float fps)
+
void C3D_RenderTargetSetOutput(C3D_RenderTarget *target, gfxScreen_t screen, gfx3dSide_t side, u32 transferFlags)
+
void C3Di_RenderQueueExit(void)
+
void C3D_SyncDisplayTransfer(u32 *inadr, u32 indim, u32 *outadr, u32 outdim, u32 flags)
+
void C3D_RenderTargetDelete(C3D_RenderTarget *target)
+
void C3D_FrameEnd(u8 flags)
+
+
+
+
+