(N3DS) Add support for 3D rendering

This commit is contained in:
Kyler Eastridge 2024-11-16 05:43:24 -05:00
parent 7f14eb33c6
commit 656b5cd042
3 changed files with 54 additions and 12 deletions

View File

@ -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)

View File

@ -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;

View File

@ -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_