From 048ebd9aef7d321dd5703ca5f7101f39b4e62a6e Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sat, 15 Apr 2023 22:01:09 +1000 Subject: [PATCH] 3DS: Something renders now --- src/Core.h | 10 +- src/Graphics_3DS.c | 262 +++++++++++++++++++++++++++++++++++++-------- 2 files changed, 223 insertions(+), 49 deletions(-) diff --git a/src/Core.h b/src/Core.h index b089af446..412dd6fc7 100644 --- a/src/Core.h +++ b/src/Core.h @@ -286,12 +286,12 @@ typedef struct cc_string_ { Thus it is **NOT SAFE** to allocate a string on the stack. */ #define STRING_REF -#if defined CC_BUILD_D3D9 || defined CC_BUILD_D3D11 -typedef void* GfxResourceID; -#else -/* Ensure size is same as D3D9, even though only 32 bits are used */ -/* NOTE: OpenGL 1.1 does actually use the full 64 bits for 'dynamic' vertex buffers */ +#if defined CC_BUILD_GL +/* NOTE: Although normally OpenGL object/resource IDs are 32 bit integers, */ +/* OpenGL 1.1 does actually use the full 64 bits for 'dynamic' vertex buffers */ typedef cc_uintptr GfxResourceID; +#else +typedef void* GfxResourceID; #endif /* Contains the information to describe a 2D textured quad. */ diff --git a/src/Graphics_3DS.c b/src/Graphics_3DS.c index 83b65648d..3ab9a65c9 100644 --- a/src/Graphics_3DS.c +++ b/src/Graphics_3DS.c @@ -1,4 +1,13 @@ #include "Core.h" + +// https://gbatemp.net/threads/homebrew-development.360646/page-245 +// 3DS defaults to stack size of *32 KB*.. way too small +unsigned int __stacksize__ = 256 * 1024; + +//#define CC_BUILD_GL +//#include "Graphics_GL1.c" + +//#undef CC_BUILD_3DS #if defined CC_BUILD_3DS #include "_GraphicsBase.h" #include "Errors.h" @@ -7,43 +16,124 @@ #include <3ds.h> #include #include "_3DS_textured_shbin.h"// auto generated from .v.pica files by Makefile -#include "_3DS_colored_shbin.h" +#include "_3DS_coloured_shbin.h" #include "_3DS_offset_shbin.h" #define DISPLAY_TRANSFER_FLAGS \ (GX_TRANSFER_FLIP_VERT(0) | GX_TRANSFER_OUT_TILED(0) | GX_TRANSFER_RAW_COPY(0) | \ GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGBA8) | GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGB8) | \ GX_TRANSFER_SCALING(GX_TRANSFER_SCALE_NO)) + +/* Current format and size of vertices */ +static int gfx_stride, gfx_format = -1; -// https://gbatemp.net/threads/homebrew-development.360646/page-245 -// 3DS defaults to stack size of *32 KB*.. way too small -unsigned int __stacksize__ = 256 * 1024; + +/*########################################################################################################################* +*------------------------------------------------------Vertex shaders-----------------------------------------------------* +*#########################################################################################################################*/ +#define UNI_MVP_MATRIX (1 << 0) + +/* cached uniforms (cached for multiple programs */ +static struct Matrix _view, _proj, _mvp; + +static struct CCShader { + DVLB_s* dvlb; + shaderProgram_s program; + int uniforms; /* which associated uniforms need to be resent to GPU */ + int locations[1]; /* location of uniforms (not constant) */ +}; +static struct CCShader* gfx_activeShader; +static struct CCShader shaders[2]; + +static void Shader_Alloc(struct CCShader* shader, u8* binData, int binSize) { + shader->dvlb = DVLB_ParseFile((u32*)binData, binSize); + shaderProgramInit(&shader->program); + shaderProgramSetVsh(&shader->program, &shader->dvlb->DVLE[0]); + + shader->locations[0] = shaderInstanceGetUniformLocation(shader->program.vertexShader, "MVP"); +} + +static void Shader_Free(struct CCShader* shader) { + shaderProgramFree(&shader->program); + DVLB_Free(shader->dvlb); +} + +/* Marks a uniform as changed on all programs */ +static void DirtyUniform(int uniform) { + int i; + for (int i = 0; i < Array_Elems(shaders); i++) { + shaders[i].uniforms |= uniform; + } +} + +/* Sends changed uniforms to the GPU for current program */ +static void ReloadUniforms(void) { + struct CCShader* s = gfx_activeShader; + if (!s) return; /* NULL if context is lost */ + + if (s->uniforms & UNI_MVP_MATRIX) { + C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, s->locations[0], &_mvp); + s->uniforms &= ~UNI_MVP_MATRIX; + } +} + +/* Switches program to one that can render current vertex format and state */ +/* Compiles program and reloads uniforms if needed */ +static void SwitchProgram(void) { + struct CCShader* shader; + int index = 0; + + if (gfx_format == VERTEX_FORMAT_TEXTURED) index++; + + shader = &shaders[index]; + if (shader != gfx_activeShader) { + gfx_activeShader = shader; + C3D_BindProgram(&shader->program); + } + ReloadUniforms(); +} + /*########################################################################################################################* *---------------------------------------------------------General---------------------------------------------------------* *#########################################################################################################################*/ -static cc_uint16 gfx_indices[GFX_MAX_INDICES]; static C3D_RenderTarget* target; +static void AllocShaders(void) { + Shader_Alloc(&shaders[0], (u32*)_3DS_coloured_shbin, _3DS_coloured_shbin_size); + Shader_Alloc(&shaders[1], (u32*)_3DS_textured_shbin, _3DS_textured_shbin_size); +} + +static void FreeShaders(void) { + for (int i = 0; i < Array_Elems(shaders); i++) { + Shader_Free(&shaders[i]); + } +} + void Gfx_Create(void) { -Platform_LogConst("BEGIN.."); + Platform_LogConst("BEGIN.."); Gfx.MaxTexWidth = 512; Gfx.MaxTexHeight = 512; Gfx.Created = true; - //C3D_Init(C3D_DEFAULT_CMDBUF_SIZE); - //target = C3D_RenderTargetCreate(240, 400, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8); - //C3D_RenderTargetSetOutput(target, GFX_TOP, GFX_LEFT, DISPLAY_TRANSFER_FLAGS); - - MakeIndices(gfx_indices, GFX_MAX_INDICES); -Platform_LogConst("DEFAUL CREATE.."); + C3D_Init(C3D_DEFAULT_CMDBUF_SIZE); + target = C3D_RenderTargetCreate(240, 400, GPU_RB_RGBA8, GPU_RB_DEPTH24_STENCIL8); + C3D_RenderTargetSetOutput(target, GFX_TOP, GFX_LEFT, DISPLAY_TRANSFER_FLAGS); + InitDefaultResources(); - Platform_LogConst("LETS GO AHEAD"); + AllocShaders(); + + // Configure the first fragment shading substage to just pass through the vertex color + // See https://www.opengl.org/sdk/docs/man2/xhtml/glTexEnv.xml for more insight + C3D_TexEnv* env = C3D_GetTexEnv(0); + C3D_TexEnvInit(env); + C3D_TexEnvSrc(env, C3D_Both, GPU_PRIMARY_COLOR, 0, 0); + C3D_TexEnvFunc(env, C3D_Both, GPU_REPLACE); } cc_bool Gfx_TryRestoreContext(void) { return true; } -void Gfx_Free(void) { } +void Gfx_Free(void) { FreeShaders(); } void Gfx_RestoreState(void) { } void Gfx_FreeState(void) { } @@ -78,7 +168,11 @@ void Gfx_SetAlphaBlending(cc_bool enabled) { } void Gfx_SetAlphaArgBlend(cc_bool enabled) { } static PackedCol clear_color; -void Gfx_ClearCol(PackedCol color) { clear_color = color; } +void Gfx_ClearCol(PackedCol color) { + //clear_color = color; + // TODO find better way? + clear_color = (PackedCol_R(color) << 24) | (PackedCol_G(color) << 16) | (PackedCol_B(color) << 8) | 0xFF; +} void Gfx_SetColWriteMask(cc_bool r, cc_bool g, cc_bool b, cc_bool a) { } @@ -91,11 +185,13 @@ void Gfx_SetDepthTest(cc_bool enabled) { } *---------------------------------------------------------Matrices--------------------------------------------------------* *#########################################################################################################################*/ void Gfx_CalcOrthoMatrix(float width, float height, struct Matrix* matrix) { - Matrix_Orthographic(matrix, 0.0f, width, 0.0f, height, ORTHO_NEAR, ORTHO_FAR); + //Matrix_Orthographic(matrix, 0.0f, width, 0.0f, height, ORTHO_NEAR, ORTHO_FAR); + Mtx_Ortho(matrix, 0.0f, width, 0.0f, height, ORTHO_NEAR, ORTHO_FAR, false); } void Gfx_CalcPerspectiveMatrix(float fov, float aspect, float zFar, struct Matrix* matrix) { float zNear = 0.1f; - Matrix_PerspectiveFieldOfView(matrix, fov, aspect, zNear, zFar); + //Matrix_PerspectiveFieldOfView(matrix, fov, aspect, zNear, zFar); + Mtx_Persp(matrix, fov, aspect, 0.1f, zFar, false); } @@ -119,53 +215,79 @@ void Gfx_SetFpsLimit(cc_bool vsync, float minFrameMs) { } void Gfx_BeginFrame(void) { - //C3D_FrameBegin(C3D_FRAME_SYNCDRAW); + C3D_FrameBegin(C3D_FRAME_SYNCDRAW); } void Gfx_Clear(void) { - //C3D_RenderTargetClear(target, C3D_CLEAR_ALL, clear_color, 0); - //C3D_FrameDrawOn(target); + //Platform_Log1("CLEAR: %i", &clear_color); + C3D_RenderTargetClear(target, C3D_CLEAR_ALL, clear_color, 0); + C3D_FrameDrawOn(target); } void Gfx_EndFrame(void) { - //C3D_FrameEnd(0); - gfxFlushBuffers(); - gfxSwapBuffers(); + C3D_FrameEnd(0); + //gfxFlushBuffers(); + //gfxSwapBuffers(); - Platform_LogConst("FRAME!"); - if (gfx_vsync) gspWaitForVBlank(); + //Platform_LogConst("FRAME!"); + //if (gfx_vsync) gspWaitForVBlank(); if (gfx_minFrameMs) LimitFPS(); } void Gfx_OnWindowResize(void) { } -static cc_uint8* gfx_vertices; -/* Current format and size of vertices */ -static int gfx_stride, gfx_format = -1, gfx_fields; - - /*########################################################################################################################* *----------------------------------------------------------Buffers--------------------------------------------------------* *#########################################################################################################################*/ -GfxResourceID Gfx_CreateIb(void* indices, int indicesCount) { return 0; } -void Gfx_BindIb(GfxResourceID ib) { } -void Gfx_DeleteIb(GfxResourceID* ib) { } +static cc_uint8* gfx_vertices; +static cc_uint16* gfx_indices; + +static void* AllocBuffer(int count, int elemSize) { + void* ptr = linearAlloc(count * elemSize); + cc_uintptr addr = ptr; + Platform_Log3("BUFFER CREATE: %i X %i = %x", &count, &elemSize, &addr); + + if (!ptr) Logger_Abort("Failed to allocate memory for buffer"); + return ptr; +} + +static void FreeBuffer(GfxResourceID* buffer) { + GfxResourceID ptr = *buffer; + if (!ptr) return; + linearFree(ptr); + *buffer = 0; +} + +GfxResourceID Gfx_CreateIb(void* indices, int indicesCount) { + void* ptr = AllocBuffer(indicesCount, 2); + Mem_Copy(ptr, indices, indicesCount * 2); + return ptr; +} + +void Gfx_BindIb(GfxResourceID ib) { gfx_indices = ib; } + +void Gfx_DeleteIb(GfxResourceID* ib) { FreeBuffer(ib); } GfxResourceID Gfx_CreateVb(VertexFormat fmt, int count) { - Platform_Log2("STA CREATE: %i, %i", &count, &fmt); - return Mem_Alloc(count, strideSizes[fmt], "gfx VB"); + return AllocBuffer(count, strideSizes[fmt]); } -void Gfx_BindVb(GfxResourceID vb) { gfx_vertices = vb; } +void Gfx_BindVb(GfxResourceID vb) { + gfx_vertices = vb; // https://github.com/devkitPro/citro3d/issues/47 + // "Fyi the permutation specifies the order in which the attributes are stored in the buffer, LSB first. So 0x210 indicates attributes 0, 1 & 2." + C3D_BufInfo* bufInfo = C3D_GetBufInfo(); + BufInfo_Init(bufInfo); -void Gfx_DeleteVb(GfxResourceID* vb) { - GfxResourceID data = *vb; - if (!data) return; - Mem_Free(data); - *vb = 0; + if (gfx_format == VERTEX_FORMAT_TEXTURED) { + BufInfo_Add(bufInfo, vb, SIZEOF_VERTEX_TEXTURED, 3, 0x210); + } else { + BufInfo_Add(bufInfo, vb, SIZEOF_VERTEX_COLOURED, 2, 0x10); + } } +void Gfx_DeleteVb(GfxResourceID* vb) { FreeBuffer(vb); } + void* Gfx_LockVb(GfxResourceID vb, VertexFormat fmt, int count) { return vb; } @@ -173,14 +295,14 @@ void* Gfx_LockVb(GfxResourceID vb, VertexFormat fmt, int count) { void Gfx_UnlockVb(GfxResourceID vb) { gfx_vertices = vb; } -GfxResourceID Gfx_CreateDynamicVb(VertexFormat fmt, int maxVertices) { - Platform_Log2("DYN CREATE: %i, %i", &maxVertices, &fmt); - return Mem_Alloc(maxVertices, strideSizes[fmt], "gfx VB"); +GfxResourceID Gfx_CreateDynamicVb(VertexFormat fmt, int maxVertices) { + return AllocBuffer(maxVertices, strideSizes[fmt]); } void* Gfx_LockDynamicVb(GfxResourceID vb, VertexFormat fmt, int count) { return vb; } + void Gfx_UnlockDynamicVb(GfxResourceID vb) { gfx_vertices = vb; } void Gfx_SetDynamicVbData(GfxResourceID vb, void* vertices, int vCount) { @@ -207,6 +329,7 @@ void Gfx_SetFogMode(FogFunc func) { } void Gfx_SetAlphaTest(cc_bool enabled) { + C3D_AlphaTest(enabled, GPU_GREATER, 0x7F); } void Gfx_DepthOnlyRendering(cc_bool depthOnly) { @@ -217,9 +340,16 @@ void Gfx_DepthOnlyRendering(cc_bool depthOnly) { *---------------------------------------------------------Matrices--------------------------------------------------------* *#########################################################################################################################*/ void Gfx_LoadMatrix(MatrixType type, const struct Matrix* matrix) { + if (type == MATRIX_VIEW) _view = *matrix; + if (type == MATRIX_PROJECTION) _proj = *matrix; + + Matrix_Mul(&_mvp, &_view, &_proj); + DirtyUniform(UNI_MVP_MATRIX); + ReloadUniforms(); } void Gfx_LoadIdentityMatrix(MatrixType type) { + Gfx_LoadMatrix(type, &Matrix_Identity); } void Gfx_EnableTextureOffset(float x, float y) { @@ -236,17 +366,61 @@ void Gfx_DisableTextureOffset(void) { cc_bool Gfx_WarnIfNecessary(void) { return false; } void Gfx_SetVertexFormat(VertexFormat fmt) { + if (fmt == gfx_format) return; + gfx_format = fmt; + gfx_stride = strideSizes[fmt]; + SwitchProgram(); + + C3D_AttrInfo* attrInfo = C3D_GetAttrInfo(); + AttrInfo_Init(attrInfo); + + AttrInfo_AddLoader(attrInfo, 0, GPU_FLOAT, 3); // in_pos + AttrInfo_AddLoader(attrInfo, 1, GPU_UNSIGNED_BYTE, 4); // in_col + if (fmt == VERTEX_FORMAT_TEXTURED) { + AttrInfo_AddLoader(attrInfo, 2, GPU_FLOAT, 2); // in_tex + } } void Gfx_DrawVb_Lines(int verticesCount) { } +static void SetVertexBuffer(int startVertex) { + C3D_BufInfo* bufInfo = C3D_GetBufInfo(); + BufInfo_Init(bufInfo); + + if (gfx_format == VERTEX_FORMAT_TEXTURED) { + BufInfo_Add(bufInfo, (struct VertexTextured*)gfx_vertices + startVertex, SIZEOF_VERTEX_TEXTURED, 3, 0x210); + } else { + BufInfo_Add(bufInfo, (struct VertexColoured*)gfx_vertices + startVertex, SIZEOF_VERTEX_COLOURED, 2, 0x10); + } +} + void Gfx_DrawVb_IndexedTris_Range(int verticesCount, int startVertex) { + SetVertexBuffer(startVertex); + C3D_DrawElements(GPU_TRIANGLES, ICOUNT(verticesCount), C3D_UNSIGNED_SHORT, gfx_indices); } void Gfx_DrawVb_IndexedTris(int verticesCount) { + SetVertexBuffer(0); + C3D_DrawElements(GPU_TRIANGLES, ICOUNT(verticesCount), C3D_UNSIGNED_SHORT, gfx_indices); } void Gfx_DrawIndexedTris_T2fC4b(int verticesCount, int startVertex) { + SetVertexBuffer(startVertex); + C3D_DrawElements(GPU_TRIANGLES, ICOUNT(verticesCount), C3D_UNSIGNED_SHORT, gfx_indices); } + + +// this doesn't work properly, because (index buffer + offset) must be aligned to 16 bytes +/*void Gfx_DrawVb_IndexedTris_Range(int verticesCount, int startVertex) { + C3D_DrawElements(GPU_TRIANGLES, ICOUNT(verticesCount), C3D_UNSIGNED_SHORT, gfx_indices + startVertex); +} + +void Gfx_DrawVb_IndexedTris(int verticesCount) { + C3D_DrawElements(GPU_TRIANGLES, ICOUNT(verticesCount), C3D_UNSIGNED_SHORT, gfx_indices); +} + +void Gfx_DrawIndexedTris_T2fC4b(int verticesCount, int startVertex) { + C3D_DrawElements(GPU_TRIANGLES, ICOUNT(verticesCount), C3D_UNSIGNED_SHORT, gfx_indices + startVertex); +}*/ #endif \ No newline at end of file