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
This commit is contained in:
fincs 2017-02-14 18:34:14 +01:00
parent 5c1d037fa2
commit a382eeed2b
2 changed files with 155 additions and 35 deletions

View File

@ -1,17 +1,27 @@
#pragma once #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; typedef struct C3D_RenderTarget_tag C3D_RenderTarget;
struct C3D_RenderTarget_tag struct C3D_RenderTarget_tag
{ {
C3D_RenderTarget *next, *prev, *link, *frame[2]; C3D_RenderTarget *next, *prev, *link, *frame[2];
C3D_RenderBuf renderBuf; C3D_FrameBuf frameBuf;
u32 transferFlags; u32 transferFlags;
u32 clearColor, clearDepth;
C3D_ClearBits clearBits;
bool ownsColor, ownsDepth;
u8 clearBits;
bool drawOk, transferOk; bool drawOk, transferOk;
bool linked; bool linked;
gfxScreen_t screen; gfxScreen_t screen;
gfx3dSide_t side; gfx3dSide_t side;
@ -29,17 +39,24 @@ bool C3D_FrameBegin(u8 flags);
bool C3D_FrameDrawOn(C3D_RenderTarget* target); bool C3D_FrameDrawOn(C3D_RenderTarget* target);
void C3D_FrameEnd(u8 flags); void C3D_FrameEnd(u8 flags);
// Flags for C3D_RenderTargetSetClear (only C3D_CLEAR_ALL implemented atm) #if defined(__GNUC__) && !defined(__cplusplus)
enum typedef union __attribute__((__transparent_union__))
{ {
C3D_CLEAR_COLOR = BIT(0), int __i;
C3D_CLEAR_DEPTH = BIT(1), GPU_DEPTHBUF __e;
C3D_CLEAR_ALL = C3D_CLEAR_COLOR | C3D_CLEAR_DEPTH, } 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_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_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_SafeDisplayTransfer(u32* inadr, u32 indim, u32* outadr, u32 outdim, u32 flags);

View File

@ -1,7 +1,11 @@
#include "internal.h" #include "internal.h"
#include <c3d/base.h>
#include <c3d/renderqueue.h> #include <c3d/renderqueue.h>
#include <stdlib.h> #include <stdlib.h>
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 *firstTarget, *lastTarget;
static C3D_RenderTarget *linkedTarget[3]; static C3D_RenderTarget *linkedTarget[3];
static C3D_RenderTarget *transferQueue, *clearQueue; static C3D_RenderTarget *transferQueue, *clearQueue;
@ -32,21 +36,50 @@ static void performDraw(void)
static void performTransfer(void) static void performTransfer(void)
{ {
if (inSafeTransfer) return; // Let the safe transfer finish handler retry this if (inSafeTransfer) return; // Let the safe transfer finish handler retry this
C3D_RenderBuf* renderBuf = &transferQueue->renderBuf; C3D_FrameBuf* frameBuf = &transferQueue->frameBuf;
u32* frameBuf = (u32*)gfxGetFramebuffer(transferQueue->screen, transferQueue->side, NULL, NULL); u32* outputFrameBuf = (u32*)gfxGetFramebuffer(transferQueue->screen, transferQueue->side, NULL, NULL);
if (transferQueue->side == GFX_LEFT) if (transferQueue->side == GFX_LEFT)
gfxConfigScreen(transferQueue->screen, false); gfxConfigScreen(transferQueue->screen, false);
u32 dim = GX_BUFFER_DIM((u32)frameBuf->width, (u32)frameBuf->height);
gspSetEventCallback(GSPGPU_EVENT_PPF, onTransferFinish, NULL, true); 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) static void performClear(void)
{ {
if (inSafeClear) return; // Let the safe clear finish handler retry this if (inSafeClear) return; // Let the safe clear finish handler retry this
C3D_RenderBuf* renderBuf = &clearQueue->renderBuf; C3D_RenderTarget* target = clearQueue;
// TODO: obey renderBuf->clearBits while (target && !target->clearBits)
gspSetEventCallback(renderBuf->colorBuf.data ? GSPGPU_EVENT_PSC0 : GSPGPU_EVENT_PSC1, onClearDone, NULL, true); {
C3D_RenderBufClearAsync(renderBuf); 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) 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; return true;
} }
@ -331,18 +365,16 @@ void C3D_FrameEnd(u8 flags)
updateFrameQueue(); 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)); C3D_RenderTarget* target = (C3D_RenderTarget*)malloc(sizeof(C3D_RenderTarget));
if (!target) return NULL; if (!target) return NULL;
memset(target, 0, sizeof(C3D_RenderTarget)); memset(target, 0, sizeof(C3D_RenderTarget));
if (!C3D_RenderBufInit(&target->renderBuf, width, height, colorFmt, depthFmt)) return target;
{ }
free(target);
return NULL;
}
static void C3Di_RenderTargetFinishInit(C3D_RenderTarget* target)
{
target->drawOk = true; target->drawOk = true;
target->prev = lastTarget; target->prev = lastTarget;
target->next = NULL; target->next = NULL;
@ -351,7 +383,73 @@ C3D_RenderTarget* C3D_RenderTargetCreate(int width, int height, int colorFmt, in
if (!firstTarget) if (!firstTarget)
firstTarget = target; firstTarget = target;
lastTarget = 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; return target;
} }
@ -361,7 +459,12 @@ void C3D_RenderTargetDelete(C3D_RenderTarget* target)
target->linked = false; target->linked = false;
while (!target->drawOk) while (!target->drawOk)
gspWaitForAnyEvent(); 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** prevNext = target->prev ? &target->prev->next : &firstTarget;
C3D_RenderTarget** nextPrev = target->next ? &target->next->prev : &lastTarget; C3D_RenderTarget** nextPrev = target->next ? &target->next->prev : &lastTarget;
*prevNext = target->next; *prevNext = target->next;
@ -369,15 +472,15 @@ void C3D_RenderTargetDelete(C3D_RenderTarget* target)
free(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->frameBuf.colorBuf) clearBits &= ~C3D_CLEAR_COLOR;
if (target->renderBuf.depthBuf.data==NULL) clearBits &= ~C3D_CLEAR_DEPTH; if (!target->frameBuf.depthBuf) clearBits &= ~C3D_CLEAR_DEPTH;
u32 oldClearBits = target->clearBits; C3D_ClearBits oldClearBits = target->clearBits;
target->clearBits = clearBits & 0xFF; target->clearBits = clearBits;
target->renderBuf.clearColor = clearColor; target->clearColor = clearColor;
target->renderBuf.clearDepth = clearDepth; target->clearDepth = clearDepth;
if (clearBits &~ oldClearBits && target->drawOk) if (clearBits &~ oldClearBits && target->drawOk)
{ {