Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(N3DS) Add support for 3D stereoscopy rendering #11480

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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_
Loading