ref: 82630cedb72a493672bce45fb0d63053aad4a39a
parent: ffcd989cead2365a399942a2799f419e0911c43d
author: Clownacy <Clownacy@users.noreply.github.com>
date: Tue Oct 13 09:22:02 EDT 2020
Added unfinished 3DS hardware renderer I'm commiting what I have now because I'm thinking of switching to Citro2D instead of Citro3D.
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -319,6 +319,9 @@
target_sources(CSE2 PRIVATE "src/Backends/Rendering/SDLSurface.cpp")
elseif(BACKEND_RENDERER MATCHES "WiiU")
target_sources(CSE2 PRIVATE "src/Backends/Rendering/WiiU.cpp")
+elseif(BACKEND_RENDERER MATCHES "3DS")
+ target_sources(CSE2 PRIVATE "src/Backends/Rendering/3DS.cpp")
+ target_link_libraries(CSE2 PRIVATE "${CTRU_ROOT}/lib/libcitro3d.a")
elseif(BACKEND_RENDERER MATCHES "Software")
target_sources(CSE2 PRIVATE "src/Backends/Rendering/Software.cpp")
else()
@@ -430,6 +433,7 @@
elseif(BACKEND_PLATFORM MATCHES "WiiU" AND BACKEND_RENDERER MATCHES "WiiU")
elseif(BACKEND_PLATFORM MATCHES "WiiU" AND BACKEND_RENDERER MATCHES "Software")
target_sources(CSE2 PRIVATE "src/Backends/Rendering/Window/Software/WiiU.cpp")
+elseif(BACKEND_PLATFORM MATCHES "3DS" AND BACKEND_RENDERER MATCHES "3DS")
elseif(BACKEND_PLATFORM MATCHES "3DS" AND BACKEND_RENDERER MATCHES "Software")
target_sources(CSE2 PRIVATE "src/Backends/Rendering/Window/Software/3DS.cpp")
elseif(BACKEND_PLATFORM MATCHES "Null" AND BACKEND_RENDERER MATCHES "Software")
--- /dev/null
+++ b/src/Backends/Rendering/3DS.cpp
@@ -1,0 +1,395 @@
+#include "../Rendering.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <3ds.h>
+#include <citro3d.h>
+#include <c3d/renderqueue.h>
+
+#include "../Misc.h"
+#include "../../Attributes.h"
+
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+
+// Used to transfer the final rendered display to the framebuffer
+#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))
+
+// Used to convert textures to 3DS tiled format
+// Note: vertical flip flag set so 0,0 is top left of texture
+#define TEXTURE_TRANSFER_FLAGS \
+ (GX_TRANSFER_FLIP_VERT(1) | GX_TRANSFER_OUT_TILED(1) | GX_TRANSFER_RAW_COPY(0) | \
+ GX_TRANSFER_IN_FORMAT(GX_TRANSFER_FMT_RGBA8) | GX_TRANSFER_OUT_FORMAT(GX_TRANSFER_FMT_RGBA8) | \
+ GX_TRANSFER_SCALING(GX_TRANSFER_SCALE_NO))
+
+typedef struct
+{
+ float x, y, z;
+ float u, v;
+} VBOEntry;
+
+typedef struct RenderBackend_Surface
+{
+ C3D_Tex texture;
+ C3D_RenderTarget *render_target;
+ size_t width;
+ size_t height;
+ size_t padded_width;
+ size_t padded_height;
+} RenderBackend_Surface;
+
+typedef struct RenderBackend_GlyphAtlas
+{
+} RenderBackend_GlyphAtlas;
+/*
+static RenderBackend_Surface framebuffer;
+
+static RenderBackend_GlyphAtlas *glyph_atlas;
+static RenderBackend_Surface *glyph_destination_surface;
+static unsigned char glyph_colour_channels[3];
+*/
+
+static C3D_RenderTarget *screen_render_target;
+
+static RenderBackend_Surface *framebuffer_surface;
+
+static DVLB_s *vertex_shader;
+static shaderProgram_s shader_program;
+static int uniform_projection;
+
+static VBOEntry *vbo;
+
+static C3D_Mtx projection_matrix;
+
+static const unsigned char vshader[] = {
+ #include "vshader.h"
+};
+
+static size_t NextPowerOfTwo(size_t value)
+{
+ size_t accumulator = 1;
+
+ while (accumulator < value)
+ accumulator <<= 1;
+
+ return accumulator;
+}
+
+RenderBackend_Surface* RenderBackend_Init(const char *window_title, size_t screen_width, size_t screen_height, bool fullscreen)
+{
+ C3D_Init(C3D_DEFAULT_CMDBUF_SIZE);
+
+ // Set up screen render target
+ screen_render_target = C3D_RenderTargetCreate(240, 400, GPU_RB_RGBA8, GPU_RB_DEPTH16);
+ C3D_RenderTargetSetOutput(screen_render_target, GFX_TOP, GFX_LEFT, DISPLAY_TRANSFER_FLAGS);
+
+ // Set up shader
+ vertex_shader = DVLB_ParseFile((u32*)vshader, sizeof(vshader));
+
+ shaderProgramInit(&shader_program);
+ shaderProgramSetVsh(&shader_program, &vertex_shader->DVLE[0]);
+ C3D_BindProgram(&shader_program);
+
+ uniform_projection = shaderInstanceGetUniformLocation(shader_program.vertexShader, "projection");
+
+ // Set up VBO
+ vbo = (VBOEntry*)linearAlloc(sizeof(VBOEntry) * 6);
+
+ C3D_AttrInfo* attrInfo = C3D_GetAttrInfo();
+ AttrInfo_Init(attrInfo);
+ AttrInfo_AddLoader(attrInfo, 0, GPU_FLOAT, 3); // v0=position
+ AttrInfo_AddLoader(attrInfo, 1, GPU_FLOAT, 2); // v2=texcoord
+
+ // Buffer
+ C3D_BufInfo* bufInfo = C3D_GetBufInfo();
+ BufInfo_Init(bufInfo);
+ BufInfo_Add(bufInfo, vbo, sizeof(VBOEntry), 2, 0x10);
+
+ C3D_TexEnv* env = C3D_GetTexEnv(0);
+ C3D_TexEnvInit(env);
+ C3D_TexEnvSrc(env, C3D_Both, GPU_TEXTURE0, GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR);
+ C3D_TexEnvFunc(env, C3D_Both, GPU_REPLACE);
+
+ C3D_DepthTest(false, GPU_GEQUAL, GPU_WRITE_ALL);
+
+ framebuffer_surface = RenderBackend_CreateSurface(screen_width, screen_height, true);
+
+ if (framebuffer_surface == NULL)
+ Backend_PrintError("RenderBackend_CreateSurface failed");
+
+ return framebuffer_surface;
+}
+
+void RenderBackend_Deinit(void)
+{
+ shaderProgramFree(&shader_program);
+ DVLB_Free(vertex_shader);
+
+ linearFree(vbo);
+
+ C3D_RenderTargetDelete(screen_render_target);
+
+ C3D_Fini();
+}
+
+void RenderBackend_DrawScreen(void)
+{
+ Mtx_OrthoTilt(&projection_matrix, 0.0f, 400.0f, 240.0f, 0.0f, 0.0f, 1.0f, true);
+
+ C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uniform_projection, &projection_matrix);
+
+ C3D_TexBind(0, &framebuffer_surface->texture);
+
+ C3D_FrameBegin(C3D_FRAME_SYNCDRAW);
+
+ C3D_RenderTargetClear(screen_render_target, C3D_CLEAR_COLOR, 0x000000FF, 0);
+ C3D_FrameDrawOn(screen_render_target);
+
+ const float vertex_left = (400 - framebuffer_surface->width) / 2;
+ const float vertex_top = (240 - framebuffer_surface->height) / 2;
+ const float vertex_right = vertex_left + framebuffer_surface->width;
+ const float vertex_bottom = vertex_top + framebuffer_surface->height;
+
+ const float texture_left = 0.0f;
+ const float texture_top = 0.0f;
+ const float texture_right = (float)framebuffer_surface->width / framebuffer_surface->padded_width;
+ const float texture_bottom = (float)framebuffer_surface->height / framebuffer_surface->padded_height;
+
+/* vbo[0] = (VBOEntry){vertex_left, vertex_top, 0.5f, texture_left, texture_top};
+ vbo[1] = (VBOEntry){vertex_left, vertex_bottom, 0.5f, texture_left, texture_bottom};
+ vbo[2] = (VBOEntry){vertex_right, vertex_top, 0.5f, texture_right, texture_top};
+ vbo[3] = (VBOEntry){vertex_left, vertex_bottom, 0.5f, texture_left, texture_bottom};
+ vbo[4] = (VBOEntry){vertex_right, vertex_bottom, 0.5f, texture_right, texture_bottom};
+ vbo[5] = (VBOEntry){vertex_right, vertex_top, 0.5f, texture_right, texture_top};
+
+ C3D_DrawArrays(GPU_TRIANGLES, 0, 6);
+*/
+
+ // Draw a textured quad directly
+ C3D_ImmDrawBegin(GPU_TRIANGLES);
+ C3D_ImmSendAttrib(vertex_left, vertex_top, 0.5f, 0.0f); // v0=position
+ C3D_ImmSendAttrib( texture_left, texture_top, 0.0f, 0.0f);
+
+ C3D_ImmSendAttrib(vertex_left, vertex_bottom, 0.5f, 0.0f);
+ C3D_ImmSendAttrib( texture_left, texture_bottom, 0.0f, 0.0f);
+
+ C3D_ImmSendAttrib(vertex_right, vertex_top, 0.5f, 0.0f);
+ C3D_ImmSendAttrib( texture_right, texture_top, 0.0f, 0.0f);
+
+ C3D_ImmSendAttrib(vertex_left, vertex_bottom, 0.5f, 0.0f);
+ C3D_ImmSendAttrib( texture_left, texture_bottom, 0.0f, 0.0f);
+
+ C3D_ImmSendAttrib(vertex_right, vertex_bottom, 0.5f, 0.0f);
+ C3D_ImmSendAttrib( texture_right, texture_bottom, 0.0f, 0.0f);
+
+ C3D_ImmSendAttrib(vertex_right, vertex_top, 0.5f, 0.0f);
+ C3D_ImmSendAttrib( texture_right, texture_top, 0.0f, 0.0f);
+ C3D_ImmDrawEnd();
+/*
+ vbo[0] = (VBOEntry){0.0f, 0.0f, 0.5f, 0.0f, 0.0f};
+ vbo[1] = (VBOEntry){framebuffer_surface->width, 0.0f, 0.5f, 1.0f, 0.0f};
+ vbo[2] = (VBOEntry){0.0f, framebuffer_surface->height, 0.5f, 0.0f, 1.0f};
+ vbo[3] = (VBOEntry){0.0f, framebuffer_surface->height, 0.5f, 0.0f, 1.0f};
+ vbo[4] = (VBOEntry){framebuffer_surface->width, 0.0f, 0.5f, 1.0f, 0.0f};
+ vbo[5] = (VBOEntry){framebuffer_surface->width, framebuffer_surface->height, 0.5f, 1.0f, 1.0f};
+*/
+// C3D_DrawArrays(GPU_TRIANGLES, 0, 6);
+
+ C3D_FrameEnd(0);
+}
+
+RenderBackend_Surface* RenderBackend_CreateSurface(size_t width, size_t height, bool render_target)
+{
+ RenderBackend_Surface *surface = (RenderBackend_Surface*)malloc(sizeof(RenderBackend_Surface));
+
+ if (surface != NULL)
+ {
+ surface->width = width;
+ surface->height = height;
+ surface->padded_width = NextPowerOfTwo(width);
+ surface->padded_height = NextPowerOfTwo(height);
+ surface->render_target = NULL;
+
+ memset(&surface->texture, 0, sizeof(surface->texture));
+ C3D_TexInitVRAM(&surface->texture, surface->padded_width, surface->padded_height, GPU_RGBA8);
+ C3D_TexSetFilter(&surface->texture, GPU_NEAREST, GPU_NEAREST);
+
+ if (!render_target)
+ {
+ return surface;
+ }
+ else
+ {
+ surface->render_target = C3D_RenderTargetCreateFromTex(&surface->texture, GPU_TEXFACE_2D, 0, GPU_RB_DEPTH16);
+
+ if (surface->render_target != NULL)
+ {
+ return surface;
+ }
+ else
+ {
+ Backend_PrintError("C3D_RenderTargetCreateFromTex failed");
+ }
+
+ C3D_TexDelete(&surface->texture);
+
+ free(surface);
+ }
+ }
+
+ return NULL;
+}
+
+void RenderBackend_FreeSurface(RenderBackend_Surface *surface)
+{
+ if (surface->render_target != NULL)
+ C3D_RenderTargetDelete(surface->render_target);
+
+ C3D_TexDelete(&surface->texture);
+
+ free(surface);
+}
+
+bool RenderBackend_IsSurfaceLost(RenderBackend_Surface *surface)
+{
+ (void)surface;
+
+ return false;
+}
+
+void RenderBackend_RestoreSurface(RenderBackend_Surface *surface)
+{
+ (void)surface;
+}
+
+void RenderBackend_UploadSurface(RenderBackend_Surface *surface, const unsigned char *pixels, size_t width, size_t height)
+{
+ u8 *gpusrc = (u8*)linearAlloc(width * height * 4);
+
+ // GX_DisplayTransfer needs input buffer in linear RAM
+ const u8* src=pixels; u8 *dst=gpusrc;
+
+ // lodepng outputs big endian rgba so we need to convert
+ for (size_t i = 0; i< width * height; ++i)
+ {
+ unsigned char r = *src++;
+ unsigned char g = *src++;
+ unsigned char b = *src++;
+
+ *dst++ = r == 0 && g == 0 && b == 0 ? 0 : 0xFF;
+ *dst++ = b;
+ *dst++ = g;
+ *dst++ = r;
+ }
+
+ // ensure data is in physical ram
+ GSPGPU_FlushDataCache(gpusrc, width * height * 4);
+
+ C3D_SyncDisplayTransfer ((u32*)gpusrc, GX_BUFFER_DIM(width, height), (u32*)surface->texture.data, GX_BUFFER_DIM(surface->padded_width, surface->padded_height), TEXTURE_TRANSFER_FLAGS);
+// C3D_SyncDisplayTransfer ((u32*)gpusrc, GX_BUFFER_DIM(width, height), (u32*)framebuffer_surface->texture.data, GX_BUFFER_DIM(framebuffer_surface->padded_width, framebuffer_surface->padded_height), TEXTURE_TRANSFER_FLAGS);
+
+ linearFree(gpusrc);
+}
+
+ATTRIBUTE_HOT void RenderBackend_Blit(RenderBackend_Surface *source_surface, const RenderBackend_Rect *rect, RenderBackend_Surface *destination_surface, long x, long y, bool colour_key)
+{
+ Mtx_Ortho(&projection_matrix, 0.0f, destination_surface->padded_width, 0.0f, destination_surface->padded_height, 0.0f, 1.0f, true);
+// Mtx_OrthoTilt(&projection_matrix, 0.0f, 400.0f, 240.0f, 0.0f, 0.0f, 1.0f, true);
+
+ C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, uniform_projection, &projection_matrix);
+
+ C3D_TexBind(0, &source_surface->texture);
+
+ C3D_FrameBegin(0);
+
+ C3D_FrameDrawOn(destination_surface->render_target);
+// C3D_FrameDrawOn(screen_render_target);
+
+ const float vertex_left = x;
+ const float vertex_top = y;
+ const float vertex_right = x + (rect->right - rect->left);
+ const float vertex_bottom = y + (rect->bottom - rect->top);
+
+ const float texture_left = (float)rect->left / source_surface->padded_width;
+ const float texture_top = (float)rect->top / source_surface->padded_height;
+ const float texture_right = (float)rect->right / source_surface->padded_width;
+ const float texture_bottom = (float)rect->bottom / source_surface->padded_height;
+
+/* vbo[0] = (VBOEntry){vertex_left, vertex_top, 0.5f, texture_left, texture_top};
+ vbo[1] = (VBOEntry){vertex_left, vertex_bottom, 0.5f, texture_left, texture_bottom};
+ vbo[2] = (VBOEntry){vertex_right, vertex_top, 0.5f, texture_right, texture_top};
+ vbo[3] = (VBOEntry){vertex_left, vertex_bottom, 0.5f, texture_left, texture_bottom};
+ vbo[4] = (VBOEntry){vertex_right, vertex_bottom, 0.5f, texture_right, texture_bottom};
+ vbo[5] = (VBOEntry){vertex_right, vertex_top, 0.5f, texture_right, texture_top};
+
+ C3D_DrawArrays(GPU_TRIANGLES, 0, 6);
+*/
+
+ // Draw a textured quad directly
+ C3D_ImmDrawBegin(GPU_TRIANGLES);
+ C3D_ImmSendAttrib(vertex_left, vertex_top, 0.5f, 0.0f); // v0=position
+ C3D_ImmSendAttrib( texture_left, texture_top, 0.0f, 0.0f);
+
+ C3D_ImmSendAttrib(vertex_right, vertex_top, 0.5f, 0.0f);
+ C3D_ImmSendAttrib( texture_right, texture_top, 0.0f, 0.0f);
+
+ C3D_ImmSendAttrib(vertex_left, vertex_bottom, 0.5f, 0.0f);
+ C3D_ImmSendAttrib( texture_left, texture_bottom, 0.0f, 0.0f);
+
+ C3D_ImmSendAttrib(vertex_left, vertex_bottom, 0.5f, 0.0f);
+ C3D_ImmSendAttrib( texture_left, texture_bottom, 0.0f, 0.0f);
+
+ C3D_ImmSendAttrib(vertex_right, vertex_top, 0.5f, 0.0f);
+ C3D_ImmSendAttrib( texture_right, texture_top, 0.0f, 0.0f);
+
+ C3D_ImmSendAttrib(vertex_right, vertex_bottom, 0.5f, 0.0f);
+ C3D_ImmSendAttrib( texture_right, texture_bottom, 0.0f, 0.0f);
+ C3D_ImmDrawEnd();
+
+ C3D_FrameEnd(0);
+}
+
+ATTRIBUTE_HOT void RenderBackend_ColourFill(RenderBackend_Surface *surface, const RenderBackend_Rect *rect, unsigned char red, unsigned char green, unsigned char blue)
+{
+
+}
+
+RenderBackend_GlyphAtlas* RenderBackend_CreateGlyphAtlas(size_t width, size_t height)
+{
+ return NULL;
+}
+
+void RenderBackend_DestroyGlyphAtlas(RenderBackend_GlyphAtlas *atlas)
+{
+
+}
+
+void RenderBackend_UploadGlyph(RenderBackend_GlyphAtlas *atlas, size_t x, size_t y, const unsigned char *pixels, size_t width, size_t height, size_t pitch)
+{
+
+}
+
+void RenderBackend_PrepareToDrawGlyphs(RenderBackend_GlyphAtlas *atlas, RenderBackend_Surface *destination_surface, unsigned char red, unsigned char green, unsigned char blue)
+{
+
+}
+
+void RenderBackend_DrawGlyph(long x, long y, size_t glyph_x, size_t glyph_y, size_t glyph_width, size_t glyph_height)
+{
+
+}
+
+void RenderBackend_HandleRenderTargetLoss(void)
+{
+ // No problem for us
+}
+
+void RenderBackend_HandleWindowResize(size_t width, size_t height)
+{
+
+}
--- /dev/null
+++ b/src/Backends/Rendering/vshader.h
@@ -1,0 +1,5 @@
+68,86,76,66,1,0,0,0,140,0,0,0,68,86,76,80,0,0,0,0,40,0,0,0,8,0,0,0,72,0,0,0,7,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,78,1,240,7,78,2,8,2,8,
+3,24,2,8,4,40,2,8,5,56,2,8,6,16,32,76,0,0,0,136,110,3,0,0,0,0,0,0,161,10,0,0,0,0,0,0,104,195,6,0,0,0,0,0,100,195,6,0,0,0,0,0,98,195,6,0,0,0,0,0,97,195,6,0,
+0,0,0,0,111,3,0,0,0,0,0,0,68,86,76,69,2,16,0,0,0,0,0,0,8,0,0,0,0,0,3,0,0,0,0,0,64,0,0,0,2,0,0,0,104,0,0,0,0,0,0,0,104,0,0,0,2,0,0,0,120,0,0,0,
+2,0,0,0,136,0,0,0,16,0,0,0,2,0,95,0,0,0,0,0,0,0,63,0,0,0,191,0,153,153,59,0,2,0,94,0,51,51,61,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,0,0,0,3,0,1,0,
+15,0,0,0,0,0,0,0,16,0,19,0,11,0,0,0,120,0,120,0,112,114,111,106,101,99,116,105,111,110,0,116,101,115,116,0
binary files /dev/null b/src/Backends/Rendering/vshader.o differ
--- /dev/null
+++ b/src/Backends/Rendering/vshader.v.pica
@@ -1,0 +1,36 @@
+; Example PICA200 vertex shader
+
+; Uniforms
+.fvec projection[4]
+
+; Constants
+.constf myconst(0.0, 1.0, -1.0, 0.1)
+.constf myconst2(0.3, 0.0, 0.0, 0.0)
+.alias zeros myconst.xxxx ; Vector full of zeros
+.alias ones myconst.yyyy ; Vector full of ones
+
+; Outputs
+.out outpos position
+.out outtc0 texcoord0
+
+; Inputs (defined as aliases for convenience)
+.alias inpos v0
+.alias intex v1
+
+.bool test
+
+.proc main
+ ; Force the w component of inpos to be 1.0
+ mov r0.xyz, inpos
+ mov r0.w, ones
+
+ ; outpos = projectionMatrix * inpos
+ dp4 outpos.x, projection[0], r0
+ dp4 outpos.y, projection[1], r0
+ dp4 outpos.z, projection[2], r0
+ dp4 outpos.w, projection[3], r0
+
+ mov outtc0, intex
+
+ end
+.end