From 153f01e74159325a6349a48fc6d94850ac89aad5 Mon Sep 17 00:00:00 2001 From: fincs Date: Sat, 7 Mar 2015 23:41:32 +0100 Subject: [PATCH] Add Render Buffer API + Viewport/Scissor + Update Example --- examples/gputest/source/main.c | 50 +++++++---------- include/c3d/base.h | 3 ++ include/c3d/renderbuffer.h | 44 +++++++++++++++ include/citro3d.h | 2 + source/base.c | 48 +++++++++++++++++ source/context.h | 10 ++++ source/renderbuffer.c | 99 ++++++++++++++++++++++++++++++++++ 7 files changed, 225 insertions(+), 31 deletions(-) create mode 100644 include/c3d/renderbuffer.h create mode 100644 source/renderbuffer.c diff --git a/examples/gputest/source/main.c b/examples/gputest/source/main.c index 02d13b7..006cc49 100644 --- a/examples/gputest/source/main.c +++ b/examples/gputest/source/main.c @@ -21,8 +21,9 @@ #define TOPSCR_COPYFLAG 0x01001000 #endif -u32* gpuDepthBuf; -u32* gpuColorBuf; +#define CLEAR_COLOR 0x80FF80FF + +C3D_RenderBuf rbTop, rbBot; static DVLB_s *pVsh, *pGsh; static shaderProgram_s shader; @@ -49,23 +50,14 @@ static const vertex_t vertices[] = {{-0.5f, +0.5f, -4.0f}, {0.0f, 1.0f}, {1.0f, 0.0f, 0.0f}}, }; -//#define BG_COLOR 0x68B0D8FF -#define BG_COLOR 0x80FF80FF - #define FOVY (2.0f/15) -static inline void clearGpuBuffers(u32 color) -{ - GX_SetMemoryFill(NULL, gpuColorBuf, color, gpuColorBuf+0x2EE00, 0x201, gpuDepthBuf, 0x00000000, gpuDepthBuf+0x2EE00, 0x201); - gspWaitForPSC0(); -} - static C3D_VBO myVbo; static C3D_Tex myTex; static void drawScene(float trX, float trY) { - GPU_SetViewport((u32*)osConvertVirtToPhys((u32)gpuDepthBuf), (u32*)osConvertVirtToPhys((u32)gpuColorBuf), 0, 0, TOPSCR_WIDTH, 400); + C3D_RenderBufBind(&rbTop); C3D_TexBind(0, &myTex); @@ -88,7 +80,7 @@ static void drawScene(float trX, float trY) static void drawSceneBottom(float trX, float trY) { - GPU_SetViewport((u32*)osConvertVirtToPhys((u32)gpuDepthBuf), (u32*)osConvertVirtToPhys((u32)gpuColorBuf), 0, 0, 240/**2*/, 320); + C3D_RenderBufBind(&rbBot); C3D_TexBind(0, NULL); @@ -119,8 +111,10 @@ int main() printf("Testing...\n"); #endif - gpuDepthBuf = (u32*)vramAlloc(400*240*2*sizeof(float)); - gpuColorBuf = (u32*)vramAlloc(400*240*2*sizeof(u32)); + C3D_RenderBufInit(&rbTop, TOPSCR_WIDTH, 400, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8); + C3D_RenderBufInit(&rbBot, 240, 320, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8); + rbTop.clearColor = CLEAR_COLOR; + rbBot.clearColor = CLEAR_COLOR; C3D_Init(C3D_DEFAULT_CMDBUF_SIZE); @@ -154,7 +148,9 @@ int main() C3D_VBOInit(&myVbo, sizeof(vertices)); C3D_VBOAddData(&myVbo, vertices, sizeof(vertices), sizeof(vertices)/sizeof(vertex_t)); - clearGpuBuffers(BG_COLOR); + // Clear buffers + C3D_RenderBufClear(&rbTop); + C3D_RenderBufClear(&rbBot); float trX = 0, trY = 0; float zDist = 0.1f; @@ -188,30 +184,22 @@ int main() float czDist = zDist*slider/2; drawScene(trX-czDist, trY); - - GX_SetDisplayTransfer(NULL, gpuColorBuf, GX_BUFFER_DIM(TOPSCR_WIDTH,400), (u32*)gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL), GX_BUFFER_DIM(TOPSCR_WIDTH,400), TOPSCR_COPYFLAG); - gspWaitForPPF(); + C3D_RenderBufTransfer(&rbTop, (u32*)gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL), TOPSCR_COPYFLAG); if (slider > 0.0f) { - clearGpuBuffers(BG_COLOR); - + C3D_RenderBufClear(&rbTop); drawScene(trX+czDist, trY); - - GX_SetDisplayTransfer(NULL, gpuColorBuf, GX_BUFFER_DIM(TOPSCR_WIDTH,400), (u32*)gfxGetFramebuffer(GFX_TOP, GFX_RIGHT, NULL, NULL), GX_BUFFER_DIM(TOPSCR_WIDTH,400), TOPSCR_COPYFLAG); - gspWaitForPPF(); + C3D_RenderBufTransfer(&rbTop, (u32*)gfxGetFramebuffer(GFX_TOP, GFX_RIGHT, NULL, NULL), TOPSCR_COPYFLAG); } + + C3D_RenderBufClear(&rbTop); // In theory this could be async but meh... #ifndef DEBUG - clearGpuBuffers(BG_COLOR); - drawSceneBottom(trX, trY); - - GX_SetDisplayTransfer(NULL, gpuColorBuf, GX_BUFFER_DIM(240,320), (u32*)gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, NULL, NULL), GX_BUFFER_DIM(240,320), 0x1000); - gspWaitForPPF(); + C3D_RenderBufTransfer(&rbBot, (u32*)gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, NULL, NULL), 0x1000); + C3D_RenderBufClear(&rbBot); // Same here #endif - - clearGpuBuffers(BG_COLOR); } C3D_Fini(); diff --git a/include/c3d/base.h b/include/c3d/base.h index b33841a..a636da2 100644 --- a/include/c3d/base.h +++ b/include/c3d/base.h @@ -7,6 +7,9 @@ bool C3D_Init(size_t cmdBufSize); void C3D_FlushAsync(void); void C3D_Fini(void); +void C3D_SetViewport(u32 x, u32 y, u32 w, u32 h); +void C3D_SetScissor(GPU_SCISSORMODE mode, u32 x, u32 y, u32 w, u32 h); + void C3D_DrawArray(C3D_VBO* vbo, GPU_Primitive_t primitive); void C3D_DrawElements(C3D_IBO* ibo, GPU_Primitive_t primitive); diff --git a/include/c3d/renderbuffer.h b/include/c3d/renderbuffer.h new file mode 100644 index 0000000..3610912 --- /dev/null +++ b/include/c3d/renderbuffer.h @@ -0,0 +1,44 @@ +#pragma once +#include "types.h" + +typedef struct +{ + void *colorBuf, *depthBuf; + u16 colorFmt, depthFmt; + u16 width, height; + u32 clearColor, clearDepth; +} C3D_RenderBuf; + +enum +{ + // Renderbuffer color formats + GPU_RB_RGBA8 = 0, + GPU_RB_RGB8, + GPU_RB_RGB5_A1, + GPU_RB_R5_G6_B5, + GPU_RB_RGBA4, + + // Renderbuffer depth formats + GPU_RB_DEPTH16 = 0, + GPU_RB_DEPTHXX, + GPU_RB_DEPTH24, + GPU_RB_DEPTH24_STENCIL8, +}; + +bool C3D_RenderBufInit(C3D_RenderBuf* rb, int width, int height, int colorFmt, int depthFmt); +void C3D_RenderBufClearAsync(C3D_RenderBuf* rb); +void C3D_RenderBufTransferAsync(C3D_RenderBuf* rb, u32* frameBuf, u32 flags); +void C3D_RenderBufBind(C3D_RenderBuf* rb); +void C3D_RenderBufDelete(C3D_RenderBuf* rb); + +static inline void C3D_RenderBufClear(C3D_RenderBuf* rb) +{ + C3D_RenderBufClearAsync(rb); + gspWaitForPSC0(); +} + +static inline void C3D_RenderBufTransfer(C3D_RenderBuf* rb, u32* frameBuf, u32 flags) +{ + C3D_RenderBufTransferAsync(rb, frameBuf, flags); + gspWaitForPPF(); +} diff --git a/include/citro3d.h b/include/citro3d.h index 34c73a0..a5053e1 100644 --- a/include/citro3d.h +++ b/include/citro3d.h @@ -21,6 +21,8 @@ extern "C" { #include "c3d/effect.h" #include "c3d/texture.h" +#include "c3d/renderbuffer.h" + #ifdef __cplusplus } #endif diff --git a/source/base.c b/source/base.c index 4d384b6..06086b5 100644 --- a/source/base.c +++ b/source/base.c @@ -14,6 +14,13 @@ u32 C3Di_Float24(float f) return (exp >= 0) ? (man | (exp << 16) | (s << 23)) : (s << 23); } +u32 C3Di_FloatInv24(u32 val) +{ + // Too lazy to copy & paste & cleanup the libctru function + extern u32 computeInvValue(u32 val); + return computeInvValue(val); +} + static void C3Di_SetTex(GPU_TEXUNIT unit, C3D_Tex* tex) { u32 reg[4]; @@ -81,6 +88,28 @@ bool C3D_Init(size_t cmdBufSize) return true; } +void C3D_SetViewport(u32 x, u32 y, u32 w, u32 h) +{ + C3D_Context* ctx = C3Di_GetContext(); + ctx->flags |= C3DiF_Viewport | C3DiF_Scissor; + ctx->viewport[0] = C3Di_Float24((float)w/2); + ctx->viewport[1] = C3Di_FloatInv24(w); + ctx->viewport[2] = C3Di_Float24((float)h/2); + ctx->viewport[3] = C3Di_FloatInv24(h); + ctx->viewport[4] = (y << 16) | (x & 0xFFFF); + ctx->scissor[0] = GPU_SCISSOR_DISABLE; +} + +void C3D_SetScissor(GPU_SCISSORMODE mode, u32 x, u32 y, u32 w, u32 h) +{ + C3D_Context* ctx = C3Di_GetContext(); + ctx->flags |= C3DiF_Scissor; + ctx->scissor[0] = mode; + if (mode == GPU_SCISSOR_DISABLE) return; + ctx->scissor[1] = (y << 16) | (x & 0xFFFF); + ctx->scissor[2] = ((h-1) << 16) | ((w-1) & 0xFFFF); +} + void C3Di_UpdateContext(void) { int i; @@ -92,6 +121,25 @@ void C3Di_UpdateContext(void) //GPU_FinishDrawing(); } + if (ctx->flags & C3DiF_RenderBuf) + { + ctx->flags &= ~C3DiF_RenderBuf; + C3Di_RenderBufBind(ctx->rb); + } + + if (ctx->flags & C3DiF_Viewport) + { + ctx->flags &= ~C3DiF_Viewport; + GPUCMD_AddIncrementalWrites(GPUREG_0041, ctx->viewport, 4); + GPUCMD_AddWrite(GPUREG_0068, ctx->viewport[4]); + } + + if (ctx->flags & C3DiF_Scissor) + { + ctx->flags &= ~C3DiF_Scissor; + GPUCMD_AddIncrementalWrites(GPUREG_SCISSORTEST_MODE, ctx->scissor, 3); + } + if (ctx->flags & C3DiF_AttrBuf) { ctx->flags &= ~C3DiF_AttrBuf; diff --git a/source/context.h b/source/context.h index ac7ea07..9b1f4e4 100644 --- a/source/context.h +++ b/source/context.h @@ -6,6 +6,7 @@ #include #include #include +#include typedef struct { @@ -34,6 +35,10 @@ typedef struct C3D_Tex* tex[3]; C3D_TexEnv texEnv[6]; + C3D_RenderBuf* rb; + u32 viewport[5]; + u32 scissor[3]; + } C3D_Context; enum @@ -42,6 +47,9 @@ enum C3DiF_NeedFinishDrawing = BIT(1), C3DiF_AttrBuf = BIT(2), C3DiF_Effect = BIT(3), + C3DiF_RenderBuf = BIT(4), + C3DiF_Viewport = BIT(5), + C3DiF_Scissor = BIT(6), #define C3DiF_Tex(n) BIT(23+(n)) C3DiF_TexAll = 7 << 23, @@ -56,8 +64,10 @@ static inline C3D_Context* C3Di_GetContext(void) } u32 C3Di_Float24(float f); +u32 C3Di_FloatInv24(u32 val); void C3Di_UpdateContext(void); void C3Di_IBOBind(C3D_IBO* ibo); void C3Di_AttrInfoBind(C3D_AttrInfo* info); void C3Di_TexEnvBind(int id, C3D_TexEnv* env); void C3Di_EffectBind(C3D_Effect* effect); +void C3Di_RenderBufBind(C3D_RenderBuf* rb); diff --git a/source/renderbuffer.c b/source/renderbuffer.c new file mode 100644 index 0000000..3f2375e --- /dev/null +++ b/source/renderbuffer.c @@ -0,0 +1,99 @@ +#include "context.h" + +static const u8 colorFmtSizes[] = {2,1,0,0,0}; +static const u8 depthFmtSizes[] = {0,0,1,2}; + +static inline u32 calcColorBufSize(u32 width, u32 height, u32 fmt) +{ + return width*height*(colorFmtSizes[fmt]+2); +} + +static inline u32 calcDepthBufSize(u32 width, u32 height, u32 fmt) +{ + return width*height*(depthFmtSizes[fmt]+2); +} + +bool C3D_RenderBufInit(C3D_RenderBuf* rb, int width, int height, int colorFmt, int depthFmt) +{ + if (rb->colorBuf || rb->depthBuf) return false; + + rb->colorFmt = colorFmt; + rb->depthFmt = depthFmt; + rb->width = width; + rb->height = height; + rb->clearColor = rb->clearDepth = 0; + + rb->colorBuf = vramAlloc(calcColorBufSize(width, height, colorFmt)); + if (!rb->colorBuf) return false; + + rb->depthBuf = vramAlloc(calcDepthBufSize(width, height, depthFmt)); + if (!rb->depthBuf) + { + vramFree(rb->colorBuf); + rb->colorBuf = NULL; + return false; + } + + return true; +} + +void C3D_RenderBufClearAsync(C3D_RenderBuf* rb) +{ + u32 colorBufSize = calcColorBufSize(rb->width, rb->height, rb->colorFmt); + u32 depthBufSize = calcDepthBufSize(rb->width, rb->height, rb->depthFmt); + GX_SetMemoryFill(NULL, + (u32*)rb->colorBuf, rb->clearColor, (u32*)((u8*)rb->colorBuf+colorBufSize), BIT(0) | ((u32)colorFmtSizes[rb->colorFmt] << 8), + (u32*)rb->depthBuf, rb->clearDepth, (u32*)((u8*)rb->depthBuf+depthBufSize), BIT(0) | ((u32)colorFmtSizes[rb->depthFmt] << 8)); +} + +void C3D_RenderBufTransferAsync(C3D_RenderBuf* rb, u32* frameBuf, u32 flags) +{ + u32 dim = GX_BUFFER_DIM((u32)rb->width, (u32)rb->height); + GX_SetDisplayTransfer(NULL, (u32*)rb->colorBuf, dim, frameBuf, dim, flags); +} + +void C3D_RenderBufBind(C3D_RenderBuf* rb) +{ + C3D_Context* ctx = C3Di_GetContext(); + ctx->flags |= C3DiF_RenderBuf; + ctx->rb = rb; + C3D_SetViewport(0, 0, rb->width, rb->height); +} + +void C3Di_RenderBufBind(C3D_RenderBuf* rb) +{ + u32 param[4]; + + param[0] = param[1] = 1; + GPUCMD_AddIncrementalWrites(GPUREG_0110, param, 2); + + param[0] = osConvertVirtToPhys((u32)rb->depthBuf) >> 3; + param[1] = osConvertVirtToPhys((u32)rb->colorBuf) >> 3; + param[2] = 0x01000000 | (((u32)(rb->height-1) & 0xFFF) << 12) | (rb->width & 0xFFF); + GPUCMD_AddIncrementalWrites(GPUREG_DEPTHBUFFER_LOC, param, 3); + + GPUCMD_AddWrite(GPUREG_006E, param[2]); //? + GPUCMD_AddWrite(GPUREG_DEPTHBUFFER_FORMAT, rb->depthFmt); + GPUCMD_AddWrite(GPUREG_COLORBUFFER_FORMAT, ((u32)rb->colorFmt << 16) | colorFmtSizes[rb->colorFmt]); + GPUCMD_AddWrite(GPUREG_011B, 0x00000000); //? + + // "Enable depth buffer" (?) + param[0] = param[1] = 0xF; + param[2] = param[3] = 0x2; + GPUCMD_AddIncrementalWrites(GPUREG_0112, param, 4); +} + +void C3D_RenderBufDelete(C3D_RenderBuf* rb) +{ + if (rb->colorBuf) + { + vramFree(rb->colorBuf); + rb->colorBuf = NULL; + } + + if (rb->depthBuf) + { + vramFree(rb->depthBuf); + rb->depthBuf = NULL; + } +}