From b48099b6259a6a2c906cb035035b38d54c8eb323 Mon Sep 17 00:00:00 2001 From: Adrian Siekierka Date: Sun, 18 Sep 2022 22:24:52 +0200 Subject: [PATCH] Initial work on N3DS accelerated renderer. Just a bunch of code right now - requires a lot of fixes (vertex coordinates, shader, etc.) to get anywhere. --- CMakeLists.txt | 7 +- include/SDL_config.h.cmake | 1 + src/core/n3ds/SDL_n3ds.c | 53 ++ src/core/n3ds/SDL_n3ds.h | 41 + src/render/SDL_render.c | 20 +- src/render/SDL_sysrender.h | 10 + src/render/n3ds/SDL_render_n3ds.c | 966 ++++++++++++++++++++++ src/render/n3ds/SDL_render_n3ds_shaders.h | 49 ++ src/render/n3ds/shader_src/shader.v.pica | 50 ++ test/CMakeLists.txt | 6 +- 10 files changed, 1199 insertions(+), 4 deletions(-) create mode 100644 src/core/n3ds/SDL_n3ds.c create mode 100644 src/core/n3ds/SDL_n3ds.h create mode 100644 src/render/n3ds/SDL_render_n3ds.c create mode 100644 src/render/n3ds/SDL_render_n3ds_shaders.h create mode 100644 src/render/n3ds/shader_src/shader.v.pica diff --git a/CMakeLists.txt b/CMakeLists.txt index 0a9269a7e1..8ba4de3bde 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2854,6 +2854,9 @@ elseif(N3DS) file(GLOB N3DS_MAIN_SOURCES ${SDL2_SOURCE_DIR}/src/main/n3ds/*.c) set(SDLMAIN_SOURCES ${SDLMAIN_SOURCES} ${N3DS_MAIN_SOURCES}) + file(GLOB N3DS_CORE_SOURCES ${SDL2_SOURCE_DIR}/src/core/n3ds/*.c) + list(APPEND SOURCE_FILES ${N3DS_CORE_SOURCES}) + if(SDL_AUDIO) set(SDL_AUDIO_DRIVER_N3DS 1) file(GLOB N3DS_AUDIO_SOURCES ${SDL2_SOURCE_DIR}/src/audio/n3ds/*.c) @@ -2907,8 +2910,10 @@ elseif(N3DS) if(SDL_VIDEO) set(SDL_VIDEO_DRIVER_N3DS 1) - file(GLOB N3DS_VIDEO_SOURCES ${SDL2_SOURCE_DIR}/src/video/n3ds/*.c) + set(SDL_VIDEO_RENDER_N3DS 1) + file(GLOB N3DS_VIDEO_SOURCES ${SDL2_SOURCE_DIR}/src/video/n3ds/*.c ${SDL2_SOURCE_DIR}/src/render/n3ds/*.c) list(APPEND SOURCE_FILES ${N3DS_VIDEO_SOURCES}) + set(SDL_VIDEO_OPENGL 0) set(HAVE_SDL_VIDEO TRUE) endif() diff --git a/include/SDL_config.h.cmake b/include/SDL_config.h.cmake index ffcafd895c..1b6ca2cdd7 100644 --- a/include/SDL_config.h.cmake +++ b/include/SDL_config.h.cmake @@ -464,6 +464,7 @@ #cmakedefine SDL_VIDEO_RENDER_OGL_ES2 @SDL_VIDEO_RENDER_OGL_ES2@ #cmakedefine SDL_VIDEO_RENDER_DIRECTFB @SDL_VIDEO_RENDER_DIRECTFB@ #cmakedefine SDL_VIDEO_RENDER_METAL @SDL_VIDEO_RENDER_METAL@ +#cmakedefine SDL_VIDEO_RENDER_N3DS @SDL_VIDEO_RENDER_N3DS@ #cmakedefine SDL_VIDEO_RENDER_VITA_GXM @SDL_VIDEO_RENDER_VITA_GXM@ #cmakedefine SDL_VIDEO_RENDER_PS2 @SDL_VIDEO_RENDER_PS2@ #cmakedefine SDL_VIDEO_RENDER_PSP @SDL_VIDEO_RENDER_PSP@ diff --git a/src/core/n3ds/SDL_n3ds.c b/src/core/n3ds/SDL_n3ds.c new file mode 100644 index 0000000000..cc0cc53b48 --- /dev/null +++ b/src/core/n3ds/SDL_n3ds.c @@ -0,0 +1,53 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2022 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include <3ds.h> +#include "../../SDL_internal.h" + +#include "3ds/allocator/linear.h" +#include "SDL_stdinc.h" + +#ifdef __3DS__ + +void* N3DS_linearRealloc(void* mem, size_t size) { + /* FIXME: Remove this once libctru implements linearRealloc(). */ + if (mem == NULL) { + return linearAlloc(size); + } else if (linearGetSize(mem) <= size) { + return mem; + } else { + void *newMem = linearAlloc(size); + if (newMem != NULL) { + SDL_memcpy(newMem, mem, size); + linearFree(mem); + return newMem; + } else { + return NULL; + } + } +} + +void N3DS_linearFree(void* mem) { + linearFree(mem); +} + +#endif /* __3DS__ */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/core/n3ds/SDL_n3ds.h b/src/core/n3ds/SDL_n3ds.h new file mode 100644 index 0000000000..15c34975ef --- /dev/null +++ b/src/core/n3ds/SDL_n3ds.h @@ -0,0 +1,41 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2022 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "../../SDL_internal.h" +#include "SDL_system.h" + +/* Set up for C function definitions, even when using C++ */ +#ifdef __cplusplus +/* *INDENT-OFF* */ +extern "C" { +/* *INDENT-ON* */ +#endif + +extern void* N3DS_linearRealloc(void* mem, size_t size); +extern void N3DS_linearFree(void* mem); + +/* Ends C function definitions when using C++ */ +#ifdef __cplusplus +/* *INDENT-OFF* */ +} +/* *INDENT-ON* */ +#endif + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/render/SDL_render.c b/src/render/SDL_render.c index 7ff4f87a19..616b4d0d38 100644 --- a/src/render/SDL_render.c +++ b/src/render/SDL_render.c @@ -33,6 +33,10 @@ #include "../core/android/SDL_android.h" #endif +#if defined(__3DS__) +# include "../core/n3ds/SDL_n3ds.h" +#endif + /* as a courtesy to iOS apps, we don't try to draw when in the background, as that will crash the app. However, these apps _should_ have used SDL_AddEventWatch to catch SDL_APP_WILLENTERBACKGROUND events and stopped @@ -122,6 +126,9 @@ static const SDL_RenderDriver *render_drivers[] = { #if SDL_VIDEO_RENDER_DIRECTFB &DirectFB_RenderDriver, #endif +#if SDL_VIDEO_RENDER_N3DS + &N3DS_RenderDriver, +#endif #if SDL_VIDEO_RENDER_PS2 &PS2_RenderDriver, #endif @@ -306,7 +313,12 @@ void *SDL_AllocateRenderVertices(SDL_Renderer *renderer, const size_t numbytes, newsize *= 2; } +#ifdef __3DS__ + /* The 3DS GPU expects vertex data to be linear in physical memory. */ + ptr = N3DS_linearRealloc(renderer->vertex_data, newsize); +#else ptr = SDL_realloc(renderer->vertex_data, newsize); +#endif if (!ptr) { SDL_OutOfMemory(); @@ -906,7 +918,7 @@ static SDL_INLINE void VerifyDrawQueueFunctions(const SDL_Renderer *renderer) have to check that they aren't NULL over and over. */ SDL_assert(renderer->QueueSetViewport != NULL); SDL_assert(renderer->QueueSetDrawColor != NULL); - SDL_assert(renderer->QueueDrawPoints != NULL); + SDL_assert(renderer->QueueDrawPoints != NULL || renderer->QueueGeometry != NULL); SDL_assert(renderer->QueueDrawLines != NULL || renderer->QueueGeometry != NULL); SDL_assert(renderer->QueueFillRects != NULL || renderer->QueueGeometry != NULL); SDL_assert(renderer->QueueCopy != NULL || renderer->QueueGeometry != NULL); @@ -2929,7 +2941,7 @@ static int RenderDrawLineBresenham(SDL_Renderer *renderer, int x1, int y1, int x } } - if (renderer->scale.x != 1.0f || renderer->scale.y != 1.0f) { + if (renderer->scale.x != 1.0f || renderer->scale.y != 1.0f || renderer->point_method == SDL_RENDERPOINTMETHOD_GEOMETRY) { retval = RenderDrawPointsWithRectsF(renderer, points, numpixels); } else { retval = QueueCmdDrawPoints(renderer, points, numpixels); @@ -4380,7 +4392,11 @@ void SDL_DestroyRendererWithoutFreeing(SDL_Renderer *renderer) cmd = next; } +#ifdef __3DS__ + N3DS_linearFree(renderer->vertex_data); +#else SDL_free(renderer->vertex_data); +#endif /* Free existing textures for this renderer */ while (renderer->textures) { diff --git a/src/render/SDL_sysrender.h b/src/render/SDL_sysrender.h index 9fdc385f65..df79d513ec 100644 --- a/src/render/SDL_sysrender.h +++ b/src/render/SDL_sysrender.h @@ -133,6 +133,12 @@ typedef struct SDL_VertexSolid SDL_Color color; } SDL_VertexSolid; +typedef enum +{ + SDL_RENDERPOINTMETHOD_POINTS, + SDL_RENDERPOINTMETHOD_GEOMETRY, +} SDL_RenderPointMethod; + typedef enum { SDL_RENDERLINEMETHOD_POINTS, @@ -246,6 +252,9 @@ struct SDL_Renderer /* Whether or not to scale relative mouse motion */ SDL_bool relative_scaling; + /* The method of drawing points */ + SDL_RenderPointMethod point_method; + /* The method of drawing lines */ SDL_RenderLineMethod line_method; @@ -305,6 +314,7 @@ extern SDL_RenderDriver GLES2_RenderDriver; extern SDL_RenderDriver GLES_RenderDriver; extern SDL_RenderDriver DirectFB_RenderDriver; extern SDL_RenderDriver METAL_RenderDriver; +extern SDL_RenderDriver N3DS_RenderDriver; extern SDL_RenderDriver PS2_RenderDriver; extern SDL_RenderDriver PSP_RenderDriver; extern SDL_RenderDriver SW_RenderDriver; diff --git a/src/render/n3ds/SDL_render_n3ds.c b/src/render/n3ds/SDL_render_n3ds.c new file mode 100644 index 0000000000..38f835f454 --- /dev/null +++ b/src/render/n3ds/SDL_render_n3ds.c @@ -0,0 +1,966 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2022 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include "../../SDL_internal.h" +#include "3ds/gfx.h" +#include "3ds/services/gspgpu.h" +#include "SDL_error.h" +#include "SDL_pixels.h" +#include "SDL_render.h" +#include "SDL_stdinc.h" +#include "SDL_video.h" + +#if SDL_VIDEO_RENDER_N3DS + +#include "SDL_hints.h" +#include "../SDL_sysrender.h" + +#include +#include <3ds.h> +#include + +#include "SDL_render_n3ds_shaders.h" + +/* N3DS renderer implementation, derived from the PSP implementation */ + +static int +PixelFormatToN3DSGPU(Uint32 format) +{ + switch (format) { + case SDL_PIXELFORMAT_RGBA8888: + return GPU_RGBA8; + case SDL_PIXELFORMAT_RGB888: + return GPU_RGB8; + case SDL_PIXELFORMAT_RGBA5551: + return GPU_RGBA5551; + case SDL_PIXELFORMAT_RGB565: + return GPU_RGB565; + case SDL_PIXELFORMAT_RGBA4444: + return GPU_RGBA4; + default: + return GPU_RGBA8; + } +} + +#define COL5650(r,g,b,a) ((b>>3) | ((g>>2)<<5) | ((r>>3)<<11)) +#define COL5551(r,g,b,a) (((b>>3)<<1) | ((g>>3)<<6) | ((r>>3)<<11) | (a>0?1:0)) +#define COL4444(r,g,b,a) ((a>>4) | ((b>>4)<<4) | ((g>>4)<<8) | ((r>>4)<<12)) +#define COL8888(r,g,b,a) ((a) | ((b)<<8) | ((g)<<16) | ((r)<<24)) +#define COL888(r,g,b) ((b) | ((g)<<16) | ((r)<<24)) + +typedef struct +{ + C3D_Tex texture; + C3D_RenderTarget* renderTarget; + C3D_Mtx renderProjMtx; + unsigned int width; /**< Image width. */ + unsigned int height; /**< Image height. */ + unsigned int pitch; + unsigned int size; + /** + * The 3DS GPU requires all textures to be *swizzled* before use. + * + * For textures considered STREAMING, we keep an unswizzled buffer in memory + * at all times. For textures considered STATIC or TARGET, we generate an + * unswizzled memory buffer on demand - this saves memory usage, but slows + * down updates. + * + * To save on memory usage, we align the unswizzled buffer's width/height + * to a multiple of 8, as opposed to the next power of two. The 3DS GPU can + * deal with that. + */ + void* unswizzledBuffer; + unsigned int unswizzledWidth; + unsigned int unswizzledHeight; + unsigned int unswizzledPitch; + unsigned int unswizzledSize; +} N3DS_TextureData; + +typedef struct +{ + SDL_BlendMode mode; + SDL_Texture* texture; +} N3DS_BlendState; + +typedef struct +{ + C3D_RenderTarget* renderTarget; + C3D_Mtx renderProjMtx; + SDL_Texture* boundTarget; /**< currently bound rendertarget */ + SDL_bool initialized; /**< is driver initialized */ + unsigned int psm; /**< format of the display buffers */ + unsigned int bpp; /**< bits per pixel of the main display */ + + SDL_bool vsync; /**< wether we do vsync */ + N3DS_BlendState blendState; /**< current blend mode */ + + C3D_TexEnv envTex; + C3D_TexEnv envNoTex; + + DVLB_s *dvlb; + shaderProgram_s shaderProgram; + int projMtxShaderLoc; +} N3DS_RenderData; + +typedef struct +{ + float x, y; + SDL_Color col; + float u, v; +} VertVCT; + +#define PI 3.14159265358979f + +#define radToDeg(x) ((x)*180.f/PI) +#define degToRad(x) ((x)*PI/180.f) + +static inline void +Swap(float *a, float *b) +{ + float n=*a; + *a = *b; + *b = n; +} + +static inline int +InVram(void* data) +{ + return data < (void*)0x20000000; +} + +static int +TextureNextPow2(unsigned int w) +{ + if (w < 8) + return 8; + + w -= 1; + w |= w >> 1; + w |= w >> 2; + w |= w >> 4; + w |= w >> 8; + return w + 1; +} + +static int +TextureAlign8(unsigned int w) { + return (w + 7) & (~7); +} + +static void +TextureActivate(SDL_Texture *texture) +{ + N3DS_TextureData *N3DS_texture = (N3DS_TextureData *) texture->driverdata; + C3D_TexBind(0, &N3DS_texture->texture); +} + +static void +N3DS_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event) +{ +} + +static int +N3DS_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) +{ + N3DS_TextureData* N3DS_texture = (N3DS_TextureData*) SDL_calloc(1, sizeof(*N3DS_texture)); + bool initialized = SDL_FALSE; + + if(!N3DS_texture) + return SDL_OutOfMemory(); + + N3DS_texture->width = texture->w; + N3DS_texture->height = texture->h; + + initialized = C3D_TexInitVRAM(&N3DS_texture->texture, + TextureNextPow2(texture->w), + TextureNextPow2(texture->h), + PixelFormatToN3DSGPU(texture->format)); + + if (!initialized) { + initialized = C3D_TexInit(&N3DS_texture->texture, + TextureNextPow2(texture->w), + TextureNextPow2(texture->h), + PixelFormatToN3DSGPU(texture->format)); + } + + if (!initialized) { + SDL_free(N3DS_texture); + return SDL_OutOfMemory(); + } + + N3DS_texture->pitch = N3DS_texture->texture.width * SDL_BYTESPERPIXEL(texture->format); + N3DS_texture->size = N3DS_texture->texture.height * N3DS_texture->pitch; + + N3DS_texture->unswizzledWidth = TextureAlign8(texture->w); + N3DS_texture->unswizzledHeight = TextureAlign8(texture->h); + N3DS_texture->unswizzledPitch = N3DS_texture->unswizzledWidth * SDL_BYTESPERPIXEL(texture->format); + N3DS_texture->unswizzledSize = N3DS_texture->unswizzledHeight * N3DS_texture->unswizzledPitch; + + if (texture->access == SDL_TEXTUREACCESS_TARGET) { + N3DS_texture->renderTarget = C3D_RenderTargetCreateFromTex(&N3DS_texture->texture, GPU_TEXFACE_2D, 0, GPU_RB_DEPTH16); + if (N3DS_texture->renderTarget == NULL) { + SDL_free(N3DS_texture); + return SDL_OutOfMemory(); + } + Mtx_Ortho(&N3DS_texture->renderProjMtx, 0.0, N3DS_texture->texture.width, 0.0, N3DS_texture->texture.height, -1.0, 1.0, true); + } else if (texture->access == SDL_TEXTUREACCESS_STREAMING) { + N3DS_texture->unswizzledBuffer = linearAlloc(N3DS_texture->unswizzledSize); + } + + texture->driverdata = N3DS_texture; + + return 0; +} + +static int +N3DS_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, + const SDL_Rect * rect, void **pixels, int *pitch); + +static void +N3DS_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture); + +static int +N3DS_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, + const SDL_Rect * rect, const void *pixels, int pitch) +{ + N3DS_TextureData *N3DS_texture = (N3DS_TextureData *) texture->driverdata; + + const Uint8 *src; + Uint8 *dst; + int row, length,dpitch; + src = pixels; + + if (texture->access != SDL_TEXTUREACCESS_STREAMING) { + N3DS_texture->unswizzledBuffer = linearAlloc(N3DS_texture->unswizzledSize); + if (N3DS_texture->unswizzledBuffer == NULL) { + return SDL_OutOfMemory(); + } + } + + N3DS_LockTexture(renderer, texture, rect,(void **)&dst, &dpitch); + length = rect->w * SDL_BYTESPERPIXEL(texture->format); + if (length == pitch && length == dpitch) { + SDL_memcpy(dst, src, length*rect->h); + } else { + for (row = 0; row < rect->h; ++row) { + SDL_memcpy(dst, src, length); + src += pitch; + dst += dpitch; + } + } + N3DS_UnlockTexture(renderer, texture); + + if (texture->access != SDL_TEXTUREACCESS_STREAMING) { + linearFree(N3DS_texture->unswizzledBuffer); + } + + return 0; +} + +static int +N3DS_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, + const SDL_Rect * rect, void **pixels, int *pitch) +{ + N3DS_TextureData *N3DS_texture = (N3DS_TextureData *) texture->driverdata; + + *pixels = + (void *) ((Uint8 *) N3DS_texture->unswizzledBuffer + rect->y * N3DS_texture->unswizzledPitch + + rect->x * SDL_BYTESPERPIXEL(texture->format)); + *pitch = N3DS_texture->unswizzledPitch; + + return 0; +} + +static void +N3DS_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture) +{ + N3DS_TextureData *N3DS_texture = (N3DS_TextureData *) texture->driverdata; + + /* We do whole texture updates, at least for now */ + GSPGPU_FlushDataCache(N3DS_texture->unswizzledBuffer, N3DS_texture->unswizzledSize); + C3D_SyncDisplayTransfer( + N3DS_texture->unswizzledBuffer, + GX_BUFFER_DIM(N3DS_texture->unswizzledWidth, N3DS_texture->unswizzledHeight), + N3DS_texture->texture.data, + GX_BUFFER_DIM(N3DS_texture->texture.width, N3DS_texture->texture.height), + GX_TRANSFER_FLIP_VERT(0) | GX_TRANSFER_OUT_TILED(1) | GX_TRANSFER_RAW_COPY(0) | + GX_TRANSFER_IN_FORMAT(N3DS_texture->texture.fmt) | GX_TRANSFER_OUT_FORMAT(N3DS_texture->texture.fmt) | + GX_TRANSFER_SCALING(GX_TRANSFER_SCALE_NO) + ); +} + +static void +N3DS_SetTextureScaleMode(SDL_Renderer * renderer, SDL_Texture * texture, SDL_ScaleMode scaleMode) +{ + N3DS_TextureData *N3DS_texture = (N3DS_TextureData *) texture->driverdata; + GPU_TEXTURE_FILTER_PARAM filter = (scaleMode == SDL_ScaleModeNearest) ? GPU_NEAREST : GPU_LINEAR; + + C3D_TexSetFilter(&N3DS_texture->texture, filter, filter); +} + +static int +N3DS_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture) +{ + N3DS_RenderData *data = renderer->driverdata; + data->boundTarget = texture; + + if (texture == NULL) { + if (!C3D_FrameDrawOn(data->renderTarget)) { + return SDL_Unsupported(); + } + C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, data->projMtxShaderLoc, &data->renderProjMtx); + } else { + N3DS_TextureData *N3DS_texture = (N3DS_TextureData *) texture->driverdata; + if (N3DS_texture->renderTarget != NULL) { + if (!C3D_FrameDrawOn(N3DS_texture->renderTarget)) { + return SDL_Unsupported(); + } + C3D_FVUnifMtx4x4(GPU_VERTEX_SHADER, data->projMtxShaderLoc, &N3DS_texture->renderProjMtx); + } else { + return SDL_Unsupported(); + } + } + + return 0; +} + +static int +N3DS_QueueSetViewport(SDL_Renderer * renderer, SDL_RenderCommand *cmd) +{ + return 0; /* nothing to do in this backend. */ +} + +static int +N3DS_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture, + const float *xy, int xy_stride, const SDL_Color *color, int color_stride, const float *uv, int uv_stride, + int num_vertices, const void *indices, int num_indices, int size_indices, + float scale_x, float scale_y) +{ + int i; + int count = indices ? num_indices : num_vertices; + N3DS_TextureData *N3DS_texture = (N3DS_TextureData *) texture->driverdata; + VertVCT *verts; + + cmd->data.draw.count = count; + size_indices = indices ? size_indices : 0; + + verts = (VertVCT *) SDL_AllocateRenderVertices(renderer, count * sizeof (VertVCT), 0, &cmd->data.draw.first); + if (!verts) { + return -1; + } + + if (texture == NULL) { + for (i = 0; i < count; i++) { + int j; + float *xy_; + SDL_Color col_; + if (size_indices == 4) { + j = ((const Uint32 *)indices)[i]; + } else if (size_indices == 2) { + j = ((const Uint16 *)indices)[i]; + } else if (size_indices == 1) { + j = ((const Uint8 *)indices)[i]; + } else { + j = i; + } + + xy_ = (float *)((char*)xy + j * xy_stride); + col_ = *(SDL_Color *)((char*)color + j * color_stride); + + verts->x = xy_[0] * scale_x; + verts->y = xy_[1] * scale_y; + + verts->col = col_; + + verts++; + } + } else { + for (i = 0; i < count; i++) { + int j; + float *xy_; + SDL_Color col_; + float *uv_; + + if (size_indices == 4) { + j = ((const Uint32 *)indices)[i]; + } else if (size_indices == 2) { + j = ((const Uint16 *)indices)[i]; + } else if (size_indices == 1) { + j = ((const Uint8 *)indices)[i]; + } else { + j = i; + } + + xy_ = (float *)((char*)xy + j * xy_stride); + col_ = *(SDL_Color *)((char*)color + j * color_stride); + uv_ = (float *)((char*)uv + j * uv_stride); + + verts->x = xy_[0] * scale_x; + verts->y = xy_[1] * scale_y; + + verts->col = col_; + + verts->u = uv_[0] * N3DS_texture->texture.width; + verts->v = uv_[1] * N3DS_texture->texture.height; + + verts++; + } + } + + return 0; +} + +static int +N3DS_QueueFillRects(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FRect * rects, int count) +{ + SDL_Color color = *((SDL_Color*) &(cmd->data.draw.r)); + VertVCT *verts = (VertVCT *) SDL_AllocateRenderVertices(renderer, count * 2 * sizeof (VertVCT), 4, &cmd->data.draw.first); + int i; + + if (!verts) { + return -1; + } + + cmd->data.draw.count = count * 4; + + for (i = 0; i < count; i++, rects++) { + verts->x = rects->x; + verts->y = rects->y; + verts->col = color; + verts++; + + verts->x = rects->x + rects->w; + verts->y = rects->y; + verts->col = color; + verts++; + + verts->x = rects->x; + verts->y = rects->y + rects->h; + verts->col = color; + verts++; + + verts->x = rects->x + rects->w; + verts->y = rects->y + rects->h; + verts->col = color; + verts++; + } + + return 0; +} + +static int +N3DS_QueueCopy(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture, + const SDL_Rect * srcrect, const SDL_FRect * dstrect) +{ + SDL_Color color = *((SDL_Color*) &(cmd->data.draw.r)); + VertVCT *verts; + const float x = dstrect->x; + const float y = dstrect->y; + const float width = dstrect->w; + const float height = dstrect->h; + + const float u0 = srcrect->x; + const float v0 = srcrect->y; + const float u1 = srcrect->x + srcrect->w; + const float v1 = srcrect->y + srcrect->h; + + verts = (VertVCT *) SDL_AllocateRenderVertices(renderer, 2 * sizeof (VertVCT), 4, &cmd->data.draw.first); + if (!verts) { + return -1; + } + + cmd->data.draw.count = 4; + + verts->u = u0; + verts->v = v0; + verts->x = x; + verts->y = y; + verts->col = color; + verts++; + + verts->u = u1; + verts->v = v0; + verts->x = x + width; + verts->y = y; + verts->col = color; + verts++; + + verts->u = u0; + verts->v = v1; + verts->x = x; + verts->y = y + 1; + verts->col = color; + verts++; + + verts->u = u1; + verts->v = v1; + verts->x = x + width; + verts->y = y + height; + verts->col = color; + verts++; + + return 0; +} + +static int +N3DS_QueueCopyEx(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture, + const SDL_Rect * srcrect, const SDL_FRect * dstrect, + const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip, float scale_x, float scale_y) +{ + SDL_Color color = *((SDL_Color*) &(cmd->data.draw.r)); + VertVCT *verts = (VertVCT *) SDL_AllocateRenderVertices(renderer, 4 * sizeof (VertVCT), 4, &cmd->data.draw.first); + const float centerx = center->x; + const float centery = center->y; + const float x = dstrect->x + centerx; + const float y = dstrect->y + centery; + const float width = dstrect->w - centerx; + const float height = dstrect->h - centery; + float s, c; + float cw1, sw1, ch1, sh1, cw2, sw2, ch2, sh2; + + float u0 = srcrect->x; + float v0 = srcrect->y; + float u1 = srcrect->x + srcrect->w; + float v1 = srcrect->y + srcrect->h; + + if (!verts) { + return -1; + } + + cmd->data.draw.count = 4; + + s = sinf(degToRad(360-angle)); + c = cosf(degToRad(360-angle)); + + cw1 = c * -centerx; + sw1 = s * -centerx; + ch1 = c * -centery; + sh1 = s * -centery; + cw2 = c * width; + sw2 = s * width; + ch2 = c * height; + sh2 = s * height; + + if (flip & SDL_FLIP_VERTICAL) { + Swap(&v0, &v1); + } + + if (flip & SDL_FLIP_HORIZONTAL) { + Swap(&u0, &u1); + } + + verts->u = u0; + verts->v = v0; + verts->x = x + cw1 + sh1; + verts->y = y - sw1 + ch1; + verts->col = color; + verts++; + + verts->u = u0; + verts->v = v1; + verts->x = x + cw1 + sh2; + verts->y = y - sw1 + ch2; + verts->col = color; + verts++; + + verts->u = u1; + verts->v = v0; + verts->x = x + cw2 + sh1; + verts->y = y - sw2 + ch1; + verts->col = color; + verts++; + + verts->u = u1; + verts->v = v1; + verts->x = x + cw2 + sh2; + verts->y = y - sw2 + ch2; + verts->col = color; + + if (scale_x != 1.0f || scale_y != 1.0f) { + verts->x *= scale_x; + verts->y *= scale_y; + verts--; + verts->x *= scale_x; + verts->y *= scale_y; + verts--; + verts->x *= scale_x; + verts->y *= scale_y; + verts--; + verts->x *= scale_x; + verts->y *= scale_y; + } + + return 0; +} + +static void +ResetBlendState(N3DS_RenderData *data, N3DS_BlendState* state) { + state->mode = SDL_BLENDMODE_INVALID; + state->texture = NULL; + C3D_SetTexEnv(0, &data->envNoTex); +} + +static void +N3DS_SetBlendState(N3DS_RenderData* data, N3DS_BlendState* state) +{ + N3DS_BlendState* current = &data->blendState; + + if (state->mode != current->mode) { + switch (state->mode) { + case SDL_BLENDMODE_NONE: + C3D_AlphaBlend(GPU_BLEND_ADD, GPU_BLEND_ADD, GPU_ONE, GPU_ZERO, GPU_ONE, GPU_ZERO); + break; + case SDL_BLENDMODE_BLEND: + C3D_AlphaBlend(GPU_BLEND_ADD, GPU_BLEND_ADD, GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA); + break; + case SDL_BLENDMODE_ADD: + C3D_AlphaBlend(GPU_BLEND_ADD, GPU_BLEND_ADD, GPU_SRC_ALPHA, GPU_ONE, GPU_ZERO, GPU_ONE); + break; + case SDL_BLENDMODE_MOD: + C3D_AlphaBlend(GPU_BLEND_ADD, GPU_BLEND_ADD, GPU_DST_COLOR, GPU_ZERO, GPU_ZERO, GPU_ONE); + break; + case SDL_BLENDMODE_MUL: + C3D_AlphaBlend(GPU_BLEND_ADD, GPU_BLEND_ADD, GPU_DST_COLOR, GPU_ONE_MINUS_SRC_ALPHA, GPU_DST_ALPHA, GPU_ONE_MINUS_SRC_ALPHA); + break; + case SDL_BLENDMODE_INVALID: + break; + } + } + + if(state->texture != current->texture) { + if(state->texture != NULL) { + TextureActivate(state->texture); + C3D_SetTexEnv(0, &data->envTex); + } else { + C3D_SetTexEnv(0,&data->envNoTex); + } + } + + *current = *state; +} + +static int +N3DS_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize) +{ + N3DS_RenderData *data = (N3DS_RenderData *) renderer->driverdata; + + C3D_BufInfo *bufInfo = C3D_GetBufInfo(); + BufInfo_Init(bufInfo); + BufInfo_Add(bufInfo, vertices, sizeof(VertVCT), 3, 0x210); + + while (cmd) { + switch (cmd->command) { + case SDL_RENDERCMD_SETVIEWPORT: { + SDL_Rect *viewport = &cmd->data.viewport.rect; + C3D_SetViewport(viewport->x, viewport->y, viewport->w, viewport->h); + C3D_SetScissor(GPU_SCISSOR_NORMAL, viewport->x, viewport->y, viewport->x + viewport->w, viewport->y + viewport->h); + break; + } + + case SDL_RENDERCMD_SETDRAWCOLOR: { + break; + } + + case SDL_RENDERCMD_DRAW_POINTS: { + /* Output as geometry */ + break; + } + + case SDL_RENDERCMD_DRAW_LINES: { + /* Output as geometry */ + break; + } + + case SDL_RENDERCMD_SETCLIPRECT: { + const SDL_Rect *rect = &cmd->data.cliprect.rect; + if(cmd->data.cliprect.enabled){ + C3D_SetScissor(GPU_SCISSOR_NORMAL, rect->x, rect->y, rect->x + rect->w, rect->y + rect->h); + } else { + C3D_SetScissor(GPU_SCISSOR_DISABLE, 0, 0, 0, 0); + } + break; + } + + case SDL_RENDERCMD_CLEAR: { + const Uint8 r = cmd->data.color.r; + const Uint8 g = cmd->data.color.g; + const Uint8 b = cmd->data.color.b; + const Uint8 a = cmd->data.color.a; + C3D_FrameBufClear( + C3D_GetFrameBuf(), + C3D_CLEAR_ALL, + COL8888(r, g, b, a), + 0 + ); + break; + } + + case SDL_RENDERCMD_FILL_RECTS: { + const size_t first = cmd->data.draw.first; + const size_t count = cmd->data.draw.count; + N3DS_BlendState state = { + .texture = NULL, + .mode = cmd->data.draw.blend + }; + N3DS_SetBlendState(data, &state); + C3D_DrawArrays(GPU_TRIANGLE_STRIP, first, count); + break; + } + + case SDL_RENDERCMD_COPY: + case SDL_RENDERCMD_COPY_EX: { + const size_t first = cmd->data.draw.first; + const size_t count = cmd->data.draw.count; + N3DS_BlendState state = { + .texture = cmd->data.draw.texture, + .mode = cmd->data.draw.blend + }; + N3DS_SetBlendState(data, &state); + C3D_DrawArrays(GPU_TRIANGLE_STRIP, first, count); + break; + } + + case SDL_RENDERCMD_GEOMETRY: { + const size_t first = cmd->data.draw.first; + const size_t count = cmd->data.draw.count; + N3DS_BlendState state = { + .texture = cmd->data.draw.texture, + .mode = cmd->data.draw.blend + }; + N3DS_SetBlendState(data, &state); + C3D_DrawArrays(GPU_TRIANGLES, first, count); + break; + } + + case SDL_RENDERCMD_NO_OP: + break; + } + + cmd = cmd->next; + } + + return 0; +} + +static int +N3DS_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, + Uint32 pixel_format, void * pixels, int pitch) +{ + return SDL_Unsupported(); +} + +static int +N3DS_RenderPresent(SDL_Renderer * renderer) +{ + N3DS_RenderData *data = (N3DS_RenderData *) renderer->driverdata; + C3D_FrameEnd(0); + + C3D_FrameBegin(data->vsync ? C3D_FRAME_SYNCDRAW : 0); + N3DS_SetRenderTarget(renderer, data->boundTarget); + + return 0; +} + +static void +N3DS_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture) +{ + N3DS_RenderData *renderdata = (N3DS_RenderData *) renderer->driverdata; + N3DS_TextureData *N3DS_texture = (N3DS_TextureData *) texture->driverdata; + + if (renderdata == 0) + return; + + if (N3DS_texture == 0) + return; + + if (N3DS_texture->renderTarget != NULL) { + C3D_RenderTargetDelete(N3DS_texture->renderTarget); + } + + if (N3DS_texture->unswizzledBuffer != NULL) { + linearFree(N3DS_texture->unswizzledBuffer); + } + + C3D_TexDelete(&N3DS_texture->texture); + SDL_free(N3DS_texture); + texture->driverdata = NULL; +} + +static void +N3DS_DestroyRenderer(SDL_Renderer * renderer) +{ + N3DS_RenderData *data = (N3DS_RenderData *) renderer->driverdata; + if (data) { + if (!data->initialized) + return; + + C3D_RenderTargetDelete(data->renderTarget); + + shaderProgramFree(&data->shaderProgram); + DVLB_Free(data->dvlb); + + C3D_Fini(); + + data->initialized = SDL_FALSE; + SDL_free(data); + } +} + +static int +N3DS_SetVSync(SDL_Renderer * renderer, const int vsync) +{ + N3DS_RenderData *data = renderer->driverdata; + data->vsync = vsync; + return 0; +} + +int +N3DS_CreateRenderer(SDL_Renderer * renderer, SDL_Window * window, Uint32 flags) +{ + N3DS_RenderData *data; + int width, height, pixelFormat; + C3D_AttrInfo *attrInfo; + bool windowIsBottom; + + data = (N3DS_RenderData *) SDL_calloc(1, sizeof(*data)); + if (!data) { + N3DS_DestroyRenderer(renderer); + return SDL_OutOfMemory(); + } + + renderer->WindowEvent = N3DS_WindowEvent; + renderer->CreateTexture = N3DS_CreateTexture; + renderer->UpdateTexture = N3DS_UpdateTexture; + renderer->LockTexture = N3DS_LockTexture; + renderer->UnlockTexture = N3DS_UnlockTexture; + renderer->SetTextureScaleMode = N3DS_SetTextureScaleMode; + renderer->SetRenderTarget = N3DS_SetRenderTarget; + renderer->QueueSetViewport = N3DS_QueueSetViewport; + renderer->QueueSetDrawColor = N3DS_QueueSetViewport; /* SetViewport and SetDrawColor are (currently) no-ops. */ + renderer->QueueGeometry = N3DS_QueueGeometry; + renderer->QueueFillRects = N3DS_QueueFillRects; + renderer->QueueCopy = N3DS_QueueCopy; + renderer->QueueCopyEx = N3DS_QueueCopyEx; + renderer->RunCommandQueue = N3DS_RunCommandQueue; + renderer->RenderReadPixels = N3DS_RenderReadPixels; + renderer->RenderPresent = N3DS_RenderPresent; + renderer->DestroyTexture = N3DS_DestroyTexture; + renderer->DestroyRenderer = N3DS_DestroyRenderer; + renderer->SetVSync = N3DS_SetVSync; + renderer->info = N3DS_RenderDriver.info; + renderer->info.flags = (SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE); + renderer->driverdata = data; + renderer->window = window; + renderer->point_method = SDL_RENDERPOINTMETHOD_GEOMETRY; + renderer->line_method = SDL_RENDERLINEMETHOD_GEOMETRY; + + if (data->initialized != SDL_FALSE) + return 0; + data->initialized = SDL_TRUE; + + if (flags & SDL_RENDERER_PRESENTVSYNC) { + data->vsync = SDL_TRUE; + } else { + data->vsync = SDL_FALSE; + } + + C3D_Init(C3D_DEFAULT_CMDBUF_SIZE); + + /* Load shader */ + + data->dvlb = DVLB_ParseFile((uint32_t*) n3ds_shader_v, sizeof(n3ds_shader_v)); + shaderProgramInit(&data->shaderProgram); + shaderProgramSetVsh(&data->shaderProgram, &data->dvlb->DVLE[0]); + data->projMtxShaderLoc = shaderInstanceGetUniformLocation(data->shaderProgram.vertexShader, "projection"); + + /* Create render targets */ + + SDL_GetWindowSizeInPixels(window, &width, &height); + pixelFormat = PixelFormatToN3DSGPU(SDL_GetWindowPixelFormat(window)); + /* FIXME: We might need a more resilient way of detecting the window<->screen mapping in the future. */ + windowIsBottom = (width == 320); + + data->renderTarget = C3D_RenderTargetCreate(height, width, pixelFormat, GPU_RB_DEPTH16); + data->boundTarget = NULL; + + C3D_RenderTargetClear(data->renderTarget, C3D_CLEAR_ALL, 0, 0); + C3D_RenderTargetSetOutput(data->renderTarget, + windowIsBottom ? GFX_BOTTOM : GFX_TOP, GFX_LEFT, + GX_TRANSFER_IN_FORMAT(pixelFormat) | GX_TRANSFER_OUT_FORMAT(GPU_RB_RGBA8)); + Mtx_OrthoTilt(&data->renderProjMtx, 0.0, width, 0.0, height, -1.0, 1.0, true); + + C3D_FrameBegin(data->vsync ? C3D_FRAME_SYNCDRAW : 0); + N3DS_SetRenderTarget(renderer, NULL); + + C3D_DepthTest(false, GPU_GEQUAL, GPU_WRITE_ALL); + + /* Scissoring */ + C3D_SetScissor(GPU_SCISSOR_NORMAL, 0, 0, width, height); + + /* Bind shader */ + C3D_BindProgram(&data->shaderProgram); + + attrInfo = C3D_GetAttrInfo(); + AttrInfo_Init(attrInfo); + AttrInfo_AddLoader(attrInfo, 0, GPU_FLOAT, 2); + AttrInfo_AddLoader(attrInfo, 1, GPU_UNSIGNED_BYTE, 4); + AttrInfo_AddLoader(attrInfo, 2, GPU_FLOAT, 2); + C3D_SetAttrInfo(attrInfo); + + /* Texture environments */ + C3D_TexEnvInit(&data->envTex); + C3D_TexEnvSrc(&data->envTex, C3D_Both, GPU_TEXTURE0, (GPU_TEVSRC) 0, (GPU_TEVSRC) 0); + C3D_TexEnvOpRgb(&data->envTex, (GPU_TEVOP_RGB) 0, (GPU_TEVOP_RGB) 0, (GPU_TEVOP_RGB) 0); + C3D_TexEnvOpAlpha(&data->envTex, (GPU_TEVOP_A) 0, (GPU_TEVOP_A) 0, (GPU_TEVOP_A) 0); + C3D_TexEnvFunc(&data->envTex, C3D_Both, GPU_MODULATE); + + C3D_TexEnvInit(&data->envNoTex); + C3D_TexEnvSrc(&data->envNoTex, C3D_Both, GPU_PRIMARY_COLOR, (GPU_TEVSRC) 0, (GPU_TEVSRC) 0); + C3D_TexEnvOpRgb(&data->envNoTex, (GPU_TEVOP_RGB) 0, (GPU_TEVOP_RGB) 0, (GPU_TEVOP_RGB) 0); + C3D_TexEnvOpAlpha(&data->envNoTex, (GPU_TEVOP_A) 0, (GPU_TEVOP_A) 0, (GPU_TEVOP_A) 0); + C3D_TexEnvFunc(&data->envNoTex, C3D_Both, GPU_REPLACE); + + ResetBlendState(data, &data->blendState); + + return 0; +} + +SDL_RenderDriver N3DS_RenderDriver = { + .CreateRenderer = N3DS_CreateRenderer, + .info = { + .name = "N3DS", + .flags = SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE, + .num_texture_formats = 5, + .texture_formats = { + [0] = SDL_PIXELFORMAT_RGBA8888, // GPU_RGBA8 + [1] = SDL_PIXELFORMAT_RGB888, // GPU_RGB8 + [2] = SDL_PIXELFORMAT_RGBA5551, // GPU_RGBA5551 + [3] = SDL_PIXELFORMAT_RGB565, // GPU_RGB565 + [4] = SDL_PIXELFORMAT_RGBA4444 // GPU_RGBA4 + }, + .max_texture_width = 1024, + .max_texture_height = 1024, + } +}; + +#endif /* SDL_VIDEO_RENDER_N3DS */ + +/* vi: set ts=4 sw=4 expandtab: */ + diff --git a/src/render/n3ds/SDL_render_n3ds_shaders.h b/src/render/n3ds/SDL_render_n3ds_shaders.h new file mode 100644 index 0000000000..5d4b3b2e06 --- /dev/null +++ b/src/render/n3ds/SDL_render_n3ds_shaders.h @@ -0,0 +1,49 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2022 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#ifndef SDL_RENDER_N3DS_SHADERS_H +#define SDL_RENDER_N3DS_SHADERS_H + +unsigned char n3ds_shader_v[] = { + 0x44, 0x56, 0x4c, 0x42, 0x01, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0x44, 0x56, 0x4c, 0x50, + 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x01, 0xf0, 0x07, 0x4e, 0x02, 0x08, 0x02, 0x08, + 0x03, 0x18, 0x02, 0x08, 0x04, 0x28, 0x02, 0x08, 0x05, 0x38, 0x02, 0x08, 0x06, 0x20, 0x20, 0x4c, + 0x07, 0xf0, 0x27, 0x4e, 0x88, 0x18, 0x40, 0x20, 0x00, 0x00, 0x00, 0x88, 0x6c, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xa3, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0xc3, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x64, 0xc3, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0xc3, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x61, 0xc3, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6f, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x4f, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x1c, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x44, 0x56, 0x4c, 0x45, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, + 0x0b, 0x00, 0x00, 0x00, 0x02, 0x00, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, + 0x01, 0x01, 0x37, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x01, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x0f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x13, 0x00, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x00, 0x00, +}; + +#endif // SDL_RENDER_N3DS_SHADERS_H + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/render/n3ds/shader_src/shader.v.pica b/src/render/n3ds/shader_src/shader.v.pica new file mode 100644 index 0000000000..8d7fb67fea --- /dev/null +++ b/src/render/n3ds/shader_src/shader.v.pica @@ -0,0 +1,50 @@ +; Simple DirectMedia Layer +; Copyright (C) 1997-2022 Sam Lantinga +; +; This software is provided 'as-is', without any express or implied +; warranty. In no event will the authors be held liable for any damages +; arising from the use of this software. +; +; Permission is granted to anyone to use this software for any purpose, +; including commercial applications, and to alter it and redistribute it +; freely, subject to the following restrictions: +; +; 1. The origin of this software must not be misrepresented; you must not +; claim that you wrote the original software. If you use this software +; in a product, an acknowledgment in the product documentation would be +; appreciated but is not required. +; 2. Altered source versions must be plainly marked as such, and must not be +; misrepresented as being the original software. +; 3. This notice may not be removed or altered from any source distribution. + +.fvec projection[4] + +.out outpos position +.out outtc0 texcoord0 +.out outclr color + +.alias inpos v0 +.alias inclr v1 +.alias intc0 v2 + +.constf const(0.0, 1.0, 0.00392156862745098, 1.0) +.alias ZEROS const.xxxx +.alias ONES const.yyyy +.alias RGBS const.zzzz + +.proc main + mov r0.xy, inpos + mov r0.zw, ONES + + 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, intc0 + + mov r1, RGBS + mul outclr, inclr.wzyx, r1.x + + end +.end diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8d413c85d5..52235c9b4b 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -215,7 +215,11 @@ add_sdl_test_executable(testvulkan testvulkan.c) add_sdl_test_executable(testoffscreen testoffscreen.c) if(N3DS) - sdltest_link_librararies(SDL2::SDL2main) + sdltest_link_librararies( + SDL2::SDL2main + SDL2::SDL2-static + citro3d + ) endif() if(PSP)