From 656b5cd0422f2a1172cae4fd03d3d3aca33c2872 Mon Sep 17 00:00:00 2001 From: Kyler Eastridge Date: Sat, 16 Nov 2024 05:43:24 -0500 Subject: [PATCH] (N3DS) Add support for 3D rendering --- src/video/n3ds/SDL_n3dsframebuffer.c | 37 ++++++++++++++++++++++++---- src/video/n3ds/SDL_n3dsvideo.c | 21 +++++++++++----- src/video/n3ds/SDL_n3dsvideo.h | 8 +++++- 3 files changed, 54 insertions(+), 12 deletions(-) diff --git a/src/video/n3ds/SDL_n3dsframebuffer.c b/src/video/n3ds/SDL_n3dsframebuffer.c index f6a319dcf64bf..2bd2f65cda1a7 100644 --- a/src/video/n3ds/SDL_n3dsframebuffer.c +++ b/src/video/n3ds/SDL_n3dsframebuffer.c @@ -39,7 +39,7 @@ static void CopyFramebuffertoN3DS_24(u8 *dest, const Dimensions dest_dim, const static void CopyFramebuffertoN3DS_32(u32 *dest, const Dimensions dest_dim, const u32 *source, const Dimensions source_dim); static int GetDestOffset(int x, int y, int dest_width); static int GetSourceOffset(int x, int y, int source_width); -static void FlushN3DSBuffer(const void *buffer, u32 bufsize, gfxScreen_t screen); +static void FlushN3DSBuffer(const void *buffer, u32 bufsize, gfxScreen_t screen, bool swap); bool SDL_N3DS_CreateWindowFramebuffer(SDL_VideoDevice *_this, SDL_Window *window, SDL_PixelFormat *format, void **pixels, int *pitch) @@ -67,6 +67,7 @@ bool SDL_N3DS_CreateWindowFramebuffer(SDL_VideoDevice *_this, SDL_Window *window bool SDL_N3DS_UpdateWindowFramebuffer(SDL_VideoDevice *_this, SDL_Window *window, const SDL_Rect *rects, int numrects) { + SDL_VideoData *internal = (SDL_VideoData *)_this->internal; SDL_WindowData *drv_data = window->internal; SDL_Surface *surface; u16 width, height; @@ -79,7 +80,7 @@ bool SDL_N3DS_UpdateWindowFramebuffer(SDL_VideoDevice *_this, SDL_Window *window } // Get the N3DS internal framebuffer and its size - framebuffer = gfxGetFramebuffer(drv_data->screen, GFX_LEFT, &width, &height); + framebuffer = gfxGetFramebuffer(drv_data->screen, drv_data->side, &width, &height); bufsize = width * height * 4; if (SDL_BYTESPERPIXEL(surface->format) == 2) @@ -91,7 +92,32 @@ bool SDL_N3DS_UpdateWindowFramebuffer(SDL_VideoDevice *_this, SDL_Window *window else CopyFramebuffertoN3DS_32(framebuffer, (Dimensions){ width, height }, surface->pixels, (Dimensions){ surface->w, surface->h }); - FlushN3DSBuffer(framebuffer, bufsize, drv_data->screen); + + if(gfxIs3D() == false || drv_data->screen == GFX_BOTTOM) + FlushN3DSBuffer(framebuffer, bufsize, drv_data->screen, true); + + else if(drv_data->screen == GFX_TOP) { + // We have to check if both screens are ready because if we can only + // swap both at the same time. + + if(drv_data->side == GFX_LEFT) + internal->top_left_ready = true; + + else if(drv_data->side == GFX_RIGHT) + internal->top_right_ready = true; + + if(internal->top_left_ready && internal->top_right_ready) { + internal->top_left_ready = false; + internal->top_right_ready = false; + + // This is safe because both screens share the same size + framebuffer = gfxGetFramebuffer(GFX_TOP, GFX_LEFT, &width, &height); + FlushN3DSBuffer(framebuffer, bufsize, GFX_TOP, false); + + framebuffer = gfxGetFramebuffer(GFX_TOP, GFX_RIGHT, &width, &height); + FlushN3DSBuffer(framebuffer, bufsize, GFX_TOP, true); + } + } return true; } @@ -147,10 +173,11 @@ static int GetSourceOffset(int x, int y, int source_width) return x + y * source_width; } -static void FlushN3DSBuffer(const void *buffer, u32 bufsize, gfxScreen_t screen) +static void FlushN3DSBuffer(const void *buffer, u32 bufsize, gfxScreen_t screen, bool swap) { GSPGPU_FlushDataCache(buffer, bufsize); - gfxScreenSwapBuffers(screen, false); + if(swap) + gfxScreenSwapBuffers(screen, gfxIs3D()); } void SDL_N3DS_DestroyWindowFramebuffer(SDL_VideoDevice *_this, SDL_Window *window) diff --git a/src/video/n3ds/SDL_n3dsvideo.c b/src/video/n3ds/SDL_n3dsvideo.c index bdf19367c3041..a9eb283e89ba3 100644 --- a/src/video/n3ds/SDL_n3dsvideo.c +++ b/src/video/n3ds/SDL_n3dsvideo.c @@ -31,7 +31,7 @@ #define N3DSVID_DRIVER_NAME "n3ds" -static bool AddN3DSDisplay(gfxScreen_t screen); +static bool AddN3DSDisplay(gfxScreen_t screen, gfx3dSide_t side); static bool N3DS_VideoInit(SDL_VideoDevice *_this); static void N3DS_VideoQuit(SDL_VideoDevice *_this); @@ -44,6 +44,7 @@ static void N3DS_DestroyWindow(SDL_VideoDevice *_this, SDL_Window *window); struct SDL_DisplayData { gfxScreen_t screen; + gfx3dSide_t side; }; struct SDL_DisplayModeData @@ -127,8 +128,9 @@ static bool N3DS_VideoInit(SDL_VideoDevice *_this) gfxInit(GSP_RGBA8_OES, GSP_RGBA8_OES, false); hidInit(); - internal->top_display = AddN3DSDisplay(GFX_TOP); - internal->touch_display = AddN3DSDisplay(GFX_BOTTOM); + internal->top_left_display = AddN3DSDisplay(GFX_TOP, GFX_LEFT); + internal->top_right_display = AddN3DSDisplay(GFX_TOP, GFX_RIGHT); + internal->touch_display = AddN3DSDisplay(GFX_BOTTOM, GFX_LEFT); // Bottom screen is always left N3DS_InitTouch(); N3DS_SwkbInit(); @@ -136,7 +138,7 @@ static bool N3DS_VideoInit(SDL_VideoDevice *_this) return true; } -static bool AddN3DSDisplay(gfxScreen_t screen) +static bool AddN3DSDisplay(gfxScreen_t screen, gfx3dSide_t side) { SDL_DisplayMode mode; SDL_DisplayModeData *modedata; @@ -150,6 +152,7 @@ static bool AddN3DSDisplay(gfxScreen_t screen) SDL_zero(display); display_driver_data->screen = screen; + display_driver_data->side = side; modedata = SDL_malloc(sizeof(SDL_DisplayModeData)); if (!modedata) { @@ -163,7 +166,7 @@ static bool AddN3DSDisplay(gfxScreen_t screen) mode.internal = modedata; modedata->fmt = GSP_RGBA8_OES; - display.name = (screen == GFX_TOP) ? "N3DS top screen" : "N3DS bottom screen"; + display.name = (screen == GFX_BOTTOM) ? "N3DS bottom screen" : (side == GFX_LEFT) ? "N3DS top screen" : "N3DS right screen"; display.desktop_mode = mode; display.internal = display_driver_data; @@ -228,7 +231,12 @@ static bool N3DS_GetDisplayBounds(SDL_VideoDevice *_this, SDL_VideoDisplay *disp } rect->x = 0; - rect->y = (driver_data->screen == GFX_TOP) ? 0 : GSP_SCREEN_WIDTH; + rect->y = 0; + if(driver_data->screen == GFX_BOTTOM) + rect->y = GSP_SCREEN_WIDTH; + if(driver_data->screen == GFX_TOP && driver_data->side == GFX_RIGHT) + rect->y = GSP_SCREEN_WIDTH * 2; + rect->w = display->current_mode->w; rect->h = display->current_mode->h; return true; @@ -243,6 +251,7 @@ static bool N3DS_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_Pr } display_data = SDL_GetDisplayDriverDataForWindow(window); window_data->screen = display_data->screen; + window_data->side = display_data->side; window->internal = window_data; SDL_SetKeyboardFocus(window); return true; diff --git a/src/video/n3ds/SDL_n3dsvideo.h b/src/video/n3ds/SDL_n3dsvideo.h index adac2626d66e7..eaaf8d1c21153 100644 --- a/src/video/n3ds/SDL_n3dsvideo.h +++ b/src/video/n3ds/SDL_n3dsvideo.h @@ -29,13 +29,19 @@ struct SDL_VideoData { - int top_display; + int top_left_display; + int top_right_display; int touch_display; + + // The following two variables keep track of if it is ready to swap the buffers + bool top_left_ready; + bool top_right_ready; }; struct SDL_WindowData { gfxScreen_t screen; /**< Keeps track of which N3DS screen is targeted */ + gfx3dSide_t side; }; #endif // SDL_n3dsvideo_h_