Skip to content

Commit

Permalink
(N3DS) Add support for 3D rendering
Browse files Browse the repository at this point in the history
  • Loading branch information
FelixWolf committed Nov 16, 2024
1 parent 7f14eb3 commit 656b5cd
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 12 deletions.
37 changes: 32 additions & 5 deletions src/video/n3ds/SDL_n3dsframebuffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand All @@ -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)
Expand All @@ -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;
}
Expand Down Expand Up @@ -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)
Expand Down
21 changes: 15 additions & 6 deletions src/video/n3ds/SDL_n3dsvideo.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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
Expand Down Expand Up @@ -127,16 +128,17 @@ 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();

return true;
}

static bool AddN3DSDisplay(gfxScreen_t screen)
static bool AddN3DSDisplay(gfxScreen_t screen, gfx3dSide_t side)
{
SDL_DisplayMode mode;
SDL_DisplayModeData *modedata;
Expand All @@ -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) {
Expand All @@ -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;

Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down
8 changes: 7 additions & 1 deletion src/video/n3ds/SDL_n3dsvideo.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_

0 comments on commit 656b5cd

Please sign in to comment.