From a382eeed2b100f5a2844b3f5d713fa8ce398f306 Mon Sep 17 00:00:00 2001 From: fincs Date: Tue, 14 Feb 2017 18:34:14 +0100 Subject: [PATCH] Use framebuffers instead of renderbuffers in rendertargets, details: - The color buffer is mandatory, and it can either be a simple buffer (whose allocation lifetime managed automatically by citro3d), or be linked to a texture - The depth buffer is optional, and it can only be a simple buffer - Added C3D_RenderTargetCreateFromTex - Clear bits in C3D_RenderTargetSetClear now work properly --- include/c3d/renderqueue.h | 41 ++++++++--- source/renderqueue.c | 149 ++++++++++++++++++++++++++++++++------ 2 files changed, 155 insertions(+), 35 deletions(-) diff --git a/include/c3d/renderqueue.h b/include/c3d/renderqueue.h index 36b687f..0c0a4b5 100644 --- a/include/c3d/renderqueue.h +++ b/include/c3d/renderqueue.h @@ -1,17 +1,27 @@ #pragma once -#include "renderbuffer.h" +#include "framebuffer.h" + +// Flags for C3D_RenderTargetSetClear +typedef enum +{ + C3D_CLEAR_COLOR = BIT(0), + C3D_CLEAR_DEPTH = BIT(1), + C3D_CLEAR_ALL = C3D_CLEAR_COLOR | C3D_CLEAR_DEPTH, +} C3D_ClearBits; typedef struct C3D_RenderTarget_tag C3D_RenderTarget; struct C3D_RenderTarget_tag { C3D_RenderTarget *next, *prev, *link, *frame[2]; - C3D_RenderBuf renderBuf; + C3D_FrameBuf frameBuf; + u32 transferFlags; + u32 clearColor, clearDepth; + C3D_ClearBits clearBits; + bool ownsColor, ownsDepth; - u8 clearBits; bool drawOk, transferOk; - bool linked; gfxScreen_t screen; gfx3dSide_t side; @@ -29,17 +39,24 @@ bool C3D_FrameBegin(u8 flags); bool C3D_FrameDrawOn(C3D_RenderTarget* target); void C3D_FrameEnd(u8 flags); -// Flags for C3D_RenderTargetSetClear (only C3D_CLEAR_ALL implemented atm) -enum +#if defined(__GNUC__) && !defined(__cplusplus) +typedef union __attribute__((__transparent_union__)) { - C3D_CLEAR_COLOR = BIT(0), - C3D_CLEAR_DEPTH = BIT(1), - C3D_CLEAR_ALL = C3D_CLEAR_COLOR | C3D_CLEAR_DEPTH, -}; + int __i; + GPU_DEPTHBUF __e; +} C3D_DEPTHTYPE; +#define C3D_DEPTHTYPE_OK(_x) ((_x).__i >= 0) +#define C3D_DEPTHTYPE_VAL(_x) ((_x).__e) +#else +typedef int C3D_DEPTHTYPE; +#define C3D_DEPTHTYPE_OK(_x) ((_x) >= 0) +#define C3D_DEPTHTYPE_VAL(_x) ((GPU_DEPTHBUF)(_x)) +#endif -C3D_RenderTarget* C3D_RenderTargetCreate(int width, int height, int colorFmt, int depthFmt); +C3D_RenderTarget* C3D_RenderTargetCreate(int width, int height, GPU_COLORBUF colorFmt, C3D_DEPTHTYPE depthFmt); +C3D_RenderTarget* C3D_RenderTargetCreateFromTex(C3D_Tex* tex, GPU_TEXFACE face, int level, C3D_DEPTHTYPE depthFmt); void C3D_RenderTargetDelete(C3D_RenderTarget* target); -void C3D_RenderTargetSetClear(C3D_RenderTarget* target, u32 clearBits, u32 clearColor, u32 clearDepth); +void C3D_RenderTargetSetClear(C3D_RenderTarget* target, C3D_ClearBits 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); diff --git a/source/renderqueue.c b/source/renderqueue.c index b011013..5c0fc9f 100644 --- a/source/renderqueue.c +++ b/source/renderqueue.c @@ -1,7 +1,11 @@ #include "internal.h" +#include #include #include +static const u8 colorFmtSizes[] = {2,1,0,0,0}; +static const u8 depthFmtSizes[] = {0,0,1,2}; + static C3D_RenderTarget *firstTarget, *lastTarget; static C3D_RenderTarget *linkedTarget[3]; static C3D_RenderTarget *transferQueue, *clearQueue; @@ -32,21 +36,50 @@ 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); + C3D_FrameBuf* frameBuf = &transferQueue->frameBuf; + u32* outputFrameBuf = (u32*)gfxGetFramebuffer(transferQueue->screen, transferQueue->side, NULL, NULL); if (transferQueue->side == GFX_LEFT) gfxConfigScreen(transferQueue->screen, false); + + u32 dim = GX_BUFFER_DIM((u32)frameBuf->width, (u32)frameBuf->height); gspSetEventCallback(GSPGPU_EVENT_PPF, onTransferFinish, NULL, true); - C3D_RenderBufTransferAsync(renderBuf, frameBuf, transferQueue->transferFlags); + GX_DisplayTransfer((u32*)frameBuf->colorBuf, dim, outputFrameBuf, dim, transferQueue->transferFlags); } 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); - C3D_RenderBufClearAsync(renderBuf); + C3D_RenderTarget* target = clearQueue; + while (target && !target->clearBits) + { + target->drawOk = true; + target = target->link; + clearQueue = target; + } + if (!target) return; + + C3D_FrameBuf* frameBuf = &target->frameBuf; + u32 size = (u32)frameBuf->width * frameBuf->height; + u32 cfs = colorFmtSizes[frameBuf->colorFmt]; + u32 dfs = depthFmtSizes[frameBuf->depthFmt]; + void* colorBufEnd = (u8*)frameBuf->colorBuf + size*(2+cfs); + void* depthBufEnd = (u8*)frameBuf->depthBuf + size*(2+dfs); + + gspSetEventCallback(GSPGPU_EVENT_PSC0, onClearDone, NULL, true); + if (target->clearBits & C3D_CLEAR_COLOR) + { + if (target->clearBits & C3D_CLEAR_DEPTH) + GX_MemoryFill( + (u32*)frameBuf->colorBuf, target->clearColor, (u32*)colorBufEnd, BIT(0) | (cfs << 8), + (u32*)frameBuf->depthBuf, target->clearDepth, (u32*)depthBufEnd, BIT(0) | (dfs << 8)); + else + GX_MemoryFill( + (u32*)frameBuf->colorBuf, target->clearColor, (u32*)colorBufEnd, BIT(0) | (cfs << 8), + NULL, 0, NULL, 0); + } else + GX_MemoryFill( + (u32*)frameBuf->depthBuf, target->clearDepth, (u32*)depthBufEnd, BIT(0) | (dfs << 8), + NULL, 0, NULL, 0); } static bool framerateLimit(int id) @@ -301,7 +334,8 @@ bool C3D_FrameDrawOn(C3D_RenderTarget* target) } } - C3D_RenderBufBind(&target->renderBuf); + C3D_SetFrameBuf(&target->frameBuf); + C3D_SetViewport(0, 0, target->frameBuf.width, target->frameBuf.height); return true; } @@ -331,18 +365,16 @@ void C3D_FrameEnd(u8 flags) updateFrameQueue(); } -C3D_RenderTarget* C3D_RenderTargetCreate(int width, int height, int colorFmt, int depthFmt) +static C3D_RenderTarget* C3Di_RenderTargetNew(void) { - if (!checkRenderQueueInit()) return NULL; C3D_RenderTarget* target = (C3D_RenderTarget*)malloc(sizeof(C3D_RenderTarget)); if (!target) return NULL; memset(target, 0, sizeof(C3D_RenderTarget)); - if (!C3D_RenderBufInit(&target->renderBuf, width, height, colorFmt, depthFmt)) - { - free(target); - return NULL; - } + return target; +} +static void C3Di_RenderTargetFinishInit(C3D_RenderTarget* target) +{ target->drawOk = true; target->prev = lastTarget; target->next = NULL; @@ -351,7 +383,73 @@ C3D_RenderTarget* C3D_RenderTargetCreate(int width, int height, int colorFmt, in if (!firstTarget) firstTarget = target; lastTarget = target; +} +C3D_RenderTarget* C3D_RenderTargetCreate(int width, int height, GPU_COLORBUF colorFmt, C3D_DEPTHTYPE depthFmt) +{ + if (!checkRenderQueueInit()) goto _fail0; + + u32 size = width*height; + GPU_DEPTHBUF depthFmtReal = GPU_RB_DEPTH16; + void* depthBuf = NULL; + void* colorBuf = vramAlloc(size*(2+colorFmtSizes[colorFmt])); + if (!colorBuf) goto _fail0; + if (C3D_DEPTHTYPE_OK(depthFmt)) + { + depthFmtReal = C3D_DEPTHTYPE_VAL(depthFmt); + depthBuf = vramAlloc(size*(2+depthFmtSizes[depthFmtReal])); + if (!depthBuf) goto _fail1; + } + + C3D_RenderTarget* target = C3Di_RenderTargetNew(); + if (!target) goto _fail2; + + C3D_FrameBuf* fb = &target->frameBuf; + C3D_FrameBufAttrib(fb, width, height, false); + C3D_FrameBufColor(fb, colorBuf, colorFmt); + target->ownsColor = true; + if (depthBuf) + { + C3D_FrameBufDepth(fb, depthBuf, depthFmtReal); + target->ownsDepth = true; + } + C3Di_RenderTargetFinishInit(target); + return target; + +_fail2: + if (depthBuf) vramFree(depthBuf); +_fail1: + vramFree(colorBuf); +_fail0: + return NULL; +} + +C3D_RenderTarget* C3D_RenderTargetCreateFromTex(C3D_Tex* tex, GPU_TEXFACE face, int level, C3D_DEPTHTYPE depthFmt) +{ + if (!checkRenderQueueInit()) return NULL; + + C3D_RenderTarget* target = C3Di_RenderTargetNew(); + if (!target) return NULL; + + C3D_FrameBuf* fb = &target->frameBuf; + C3D_FrameBufTex(fb, tex, face, level); + + if (C3D_DEPTHTYPE_OK(depthFmt)) + { + GPU_DEPTHBUF depthFmtReal = C3D_DEPTHTYPE_VAL(depthFmt); + u32 size = (u32)fb->width*fb->height; + void* depthBuf = vramAlloc(size*(2+depthFmtSizes[depthFmtReal])); + if (!depthBuf) + { + free(target); + return NULL; + } + + C3D_FrameBufDepth(fb, depthBuf, depthFmtReal); + target->ownsDepth = true; + } + + C3Di_RenderTargetFinishInit(target); return target; } @@ -361,7 +459,12 @@ void C3D_RenderTargetDelete(C3D_RenderTarget* target) target->linked = false; while (!target->drawOk) gspWaitForAnyEvent(); - C3D_RenderBufDelete(&target->renderBuf); + + 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; @@ -369,15 +472,15 @@ void C3D_RenderTargetDelete(C3D_RenderTarget* target) free(target); } -void C3D_RenderTargetSetClear(C3D_RenderTarget* target, u32 clearBits, u32 clearColor, u32 clearDepth) +void C3D_RenderTargetSetClear(C3D_RenderTarget* target, C3D_ClearBits clearBits, u32 clearColor, u32 clearDepth) { - if (target->renderBuf.colorBuf.data==NULL) clearBits &= ~C3D_CLEAR_COLOR; - if (target->renderBuf.depthBuf.data==NULL) clearBits &= ~C3D_CLEAR_DEPTH; + if (!target->frameBuf.colorBuf) clearBits &= ~C3D_CLEAR_COLOR; + if (!target->frameBuf.depthBuf) clearBits &= ~C3D_CLEAR_DEPTH; - u32 oldClearBits = target->clearBits; - target->clearBits = clearBits & 0xFF; - target->renderBuf.clearColor = clearColor; - target->renderBuf.clearDepth = clearDepth; + C3D_ClearBits oldClearBits = target->clearBits; + target->clearBits = clearBits; + target->clearColor = clearColor; + target->clearDepth = clearDepth; if (clearBits &~ oldClearBits && target->drawOk) {