From d521c997697c9beacf63abee3324415c4fed6a33 Mon Sep 17 00:00:00 2001 From: fincs Date: Sat, 13 Jun 2020 22:48:36 +0200 Subject: [PATCH] gfx: Add support for the top screen's 800px high resolution mode (!!!) --- libctru/include/3ds/gfx.h | 20 +++++++++++++ libctru/source/gfx.c | 63 +++++++++++++++++++++++++++++---------- 2 files changed, 68 insertions(+), 15 deletions(-) diff --git a/libctru/include/3ds/gfx.h b/libctru/include/3ds/gfx.h index bc52f09..ca69b85 100644 --- a/libctru/include/3ds/gfx.h +++ b/libctru/include/3ds/gfx.h @@ -5,6 +5,10 @@ * This API provides basic functionality needed to bring up framebuffers for both screens, * as well as managing display mode (stereoscopic 3D) and double buffering. * It is mainly an abstraction over the gsp service. + * + * Please note that the 3DS uses *portrait* screens rotated 90 degrees counterclockwise. + * Width/height refer to the physical dimensions of the screen; that is, the top screen + * is 240 pixels wide and 400 pixels tall; while the bottom screen is 240x320. */ #pragma once @@ -80,6 +84,22 @@ void gfxSet3D(bool enable); */ bool gfxIs3D(void); +/** + * @brief Retrieves the status of the 800px (double-height) high resolution display mode of the top screen. + * @return true if wide mode enabled, false otherwise. + */ +bool gfxIsWide(void); + +/** + * @brief Enables or disables the 800px (double-height) high resolution display mode of the top screen. + * @param enable Pass true to enable, false to disable. + * @note Wide mode is disabled by default. + * @note Wide and stereoscopic 3D modes are mutually exclusive. + * @note In wide mode pixels are not square, since scanlines are half as tall as they normally are. + * @warning Wide mode does not work on Old 2DS consoles (however it does work on New 2DS XL consoles). + */ +void gfxSetWide(bool enable); + /** * @brief Changes the pixel format of a screen. * @param screen Screen ID (see \ref gfxScreen_t) diff --git a/libctru/source/gfx.c b/libctru/source/gfx.c index 5482959..2baafc3 100644 --- a/libctru/source/gfx.c +++ b/libctru/source/gfx.c @@ -10,7 +10,12 @@ static u32 gfxTopFramebufferMaxSize; static u32 gfxBottomFramebufferMaxSize; static GSPGPU_FramebufferFormat gfxFramebufferFormats[2]; -static bool gfxEnable3D, gfxIsVram; +static enum { + MODE_2D = 0, + MODE_3D = 1, + MODE_WIDE = 2, +} gfxTopMode; +static bool gfxIsVram; static u8 gfxCurBuf[2]; static u8 gfxIsDoubleBuf[2]; @@ -19,12 +24,22 @@ static void *(*screenAlloc)(size_t); void gfxSet3D(bool enable) { - gfxEnable3D = enable; + gfxTopMode = enable ? MODE_3D : MODE_2D; } bool gfxIs3D(void) { - return gfxEnable3D; + return gfxTopMode == MODE_3D; +} + +void gfxSetWide(bool enable) +{ + gfxTopMode = enable ? MODE_WIDE : MODE_2D; +} + +bool gfxIsWide(void) +{ + return gfxTopMode == MODE_WIDE; } void gfxSetScreenFormat(gfxScreen_t screen, GSPGPU_FramebufferFormat format) @@ -77,15 +92,20 @@ static void gfxPresentFramebuffer(gfxScreen_t screen, u8 id) if (screen == GFX_TOP) { fb_a = gfxTopFramebuffers[id]; - if (gfxEnable3D) + switch (gfxTopMode) { - mode |= BIT(5); - fb_b = fb_a + gfxTopFramebufferMaxSize/2; - } - else - { - mode |= BIT(6); - fb_b = fb_a; + default: + case MODE_2D: + mode |= BIT(6); + fb_b = fb_a; + break; + case MODE_3D: + mode |= BIT(5); + fb_b = fb_a + gfxTopFramebufferMaxSize/2; + break; + case MODE_WIDE: + fb_b = fb_a; + break; } } else @@ -173,8 +193,19 @@ u8* gfxGetFramebuffer(gfxScreen_t screen, gfx3dSide_t side, u16* width, u16* hei { fb = gfxTopFramebuffers[id]; scr_height = GSP_SCREEN_HEIGHT_TOP; - if (gfxEnable3D && side != GFX_LEFT) - fb += gfxTopFramebufferMaxSize/2; + switch (gfxTopMode) + { + default: + case MODE_2D: + break; + case MODE_3D: + if (side != GFX_LEFT) + fb += gfxTopFramebufferMaxSize/2; + break; + case MODE_WIDE: + scr_height = GSP_SCREEN_HEIGHT_TOP_2X; + break; + } } else // GFX_BOTTOM { @@ -194,10 +225,12 @@ void gfxFlushBuffers(void) { const u32 baseSize = GSP_SCREEN_WIDTH * gspGetBytesPerPixel(gfxGetScreenFormat(GFX_TOP)); const u32 topSize = GSP_SCREEN_HEIGHT_TOP * baseSize; + const u32 topSize2x = GSP_SCREEN_HEIGHT_TOP_2X * baseSize; const u32 bottomSize = GSP_SCREEN_HEIGHT_BOTTOM * baseSize; - GSPGPU_FlushDataCache(gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL), topSize); - if(gfxEnable3D)GSPGPU_FlushDataCache(gfxGetFramebuffer(GFX_TOP, GFX_RIGHT, NULL, NULL), topSize); + GSPGPU_FlushDataCache(gfxGetFramebuffer(GFX_TOP, GFX_LEFT, NULL, NULL), gfxTopMode == MODE_WIDE ? topSize2x : topSize); + if (gfxTopMode == MODE_3D) + GSPGPU_FlushDataCache(gfxGetFramebuffer(GFX_TOP, GFX_RIGHT, NULL, NULL), topSize); GSPGPU_FlushDataCache(gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, NULL, NULL), bottomSize); }