diff --git a/nx/include/switch/gfx/gfx.h b/nx/include/switch/gfx/gfx.h index 4f83befa..a49a9ab1 100644 --- a/nx/include/switch/gfx/gfx.h +++ b/nx/include/switch/gfx/gfx.h @@ -12,13 +12,32 @@ void gfxExit(void); /// The default resolution is 720p, however you should use gfxGetFramebuffer() to get the current width/height. -/// This can only be used before calling gfxInitDefault(), this will use fatalSimple() otherwise. If the input is 0, the default resolution will be used during gfxInitDefault(). This sets the maximum resolution for the framebuffer, used during gfxInitDefault(). This is also used as the current resolution. The width/height are reset to the default when gfxExit() is used. +/// This can only be used before calling gfxInitDefault(), this will use fatalSimple() otherwise. If the input is 0, the default resolution will be used during gfxInitDefault(). This sets the maximum resolution for the framebuffer, used during gfxInitDefault(). This is also used as the current resolution when crop isn't set. The width/height are reset to the default when gfxExit() is used. +/// Normally you should only use this when you need a maximum resolution larger than the default, see above. void gfxInitResolution(u32 width, u32 height); +/// Configure framebuffer crop, by default crop is all-zero. Use all-zero input to reset to default. gfxExit() resets this to the default. +/// When the input is invalid this returns without changing the crop data, this includes the input values being larger than the framebuf width/height. +/// This will update the display width/height returned by gfxGetFramebuffer(), with that width/height being reset to the default when required. +/// gfxGetFramebufferDisplayOffset() uses absolute x/y, it will not adjust for non-zero crop left/top. +/// The new crop config will not take affect with double-buffering disabled. When used during frame-drawing, this should be called before gfxGetFramebuffer(). +void gfxConfigureCrop(s32 left, s32 top, s32 right, s32 bottom); + +/// Wrapper for gfxConfigureCrop(). Use this to set the resolution, within the bounds of the maximum resolution. Use all-zero input to reset to default. +void gfxConfigureResolution(s32 width, s32 height); + void gfxWaitForVsync(); void gfxSwapBuffers(); + +/// Get the current framebuffer address, with optional output ptrs for the display width/height. The display width/height is adjusted by gfxConfigureCrop()/gfxConfigureResolution(). u8* gfxGetFramebuffer(u32* width, u32* height); -size_t gfxGetFramebufferSize(void); /// Use this to get the actual byte-size of the buffer for use with memset/etc, do not calculate the byte-size manually with the width and height from gfxGetFramebuffer. The height returned by gfxGetFramebuffer is the display height not the aligned height. + +/// Get the original framebuffer width/height without crop. +void gfxGetFramebufferResolution(u32* width, u32* height); + +/// Use this to get the actual byte-size of the buffer for use with memset/etc, do not calculate the byte-size manually with the width and height from gfxGetFramebuffer/gfxGetFramebufferResolution. +size_t gfxGetFramebufferSize(void); + void gfxSetDoubleBuffering(bool doubleBuffering); void gfxFlushBuffers(void); @@ -28,7 +47,8 @@ static inline u32 gfxGetFramebufferDisplayOffset(u32 x, u32 y) { u32 width=0, height=0; u32 tilepos, tmp_pos; - gfxGetFramebuffer(&width, &height); + gfxGetFramebufferResolution(&width, NULL); + gfxGetFramebuffer(NULL, &height); if (x >= width || y >= height) return (gfxGetFramebufferSize()-4)/4;//Return the last pixel-offset in the buffer, the data located here is not displayed due to alignment. diff --git a/nx/source/gfx/gfx.c b/nx/source/gfx/gfx.c index a61eb231..172bb10c 100644 --- a/nx/source/gfx/gfx.c +++ b/nx/source/gfx/gfx.c @@ -25,6 +25,7 @@ static bool g_gfxDoubleBuf = 1; static size_t g_gfx_framebuf_width=0, g_gfx_framebuf_aligned_width=0; static size_t g_gfx_framebuf_height=0, g_gfx_framebuf_aligned_height=0; +static size_t g_gfx_framebuf_display_width=0, g_gfx_framebuf_display_height=0; size_t g_gfx_singleframebuf_size=0; extern u32 __nx_applet_type; @@ -167,6 +168,9 @@ static Result _gfxInit(viServiceType servicetype, const char *DisplayName, u32 L g_gfx_framebuf_height = 720; } + g_gfx_framebuf_display_width = g_gfx_framebuf_width; + g_gfx_framebuf_display_height = g_gfx_framebuf_height; + g_gfx_framebuf_aligned_width = (g_gfx_framebuf_width+15) & ~15;//Align to 16. g_gfx_framebuf_aligned_height = (g_gfx_framebuf_height+127) & ~127;//Align to 128. @@ -350,6 +354,8 @@ void gfxExit(void) { g_gfx_framebuf_height = 0; memset(g_gfx_ProducerSlotsRequested, 0, sizeof(g_gfx_ProducerSlotsRequested)); + + memset(&g_gfxQueueBufferData.crop, 0, sizeof(g_gfxQueueBufferData.crop)); } void gfxInitResolution(u32 width, u32 height) { @@ -359,6 +365,32 @@ void gfxInitResolution(u32 width, u32 height) { g_gfx_framebuf_height = height; } +void gfxConfigureCrop(s32 left, s32 top, s32 right, s32 bottom) { + if (right==0 || bottom==0) { + g_gfx_framebuf_display_width = g_gfx_framebuf_width; + g_gfx_framebuf_display_height = g_gfx_framebuf_height; + } + + if (left < 0 || top < 0 || right < 0 || bottom < 0) return; + if (right < left || bottom < top) return; + if (left > g_gfx_framebuf_width || top > g_gfx_framebuf_height) return; + if (right > g_gfx_framebuf_width || bottom > g_gfx_framebuf_height) return; + + g_gfxQueueBufferData.crop.left = left; + g_gfxQueueBufferData.crop.top = top; + g_gfxQueueBufferData.crop.right = right; + g_gfxQueueBufferData.crop.bottom = bottom; + + if (right!=0 && bottom!=0) { + g_gfx_framebuf_display_width = right; + g_gfx_framebuf_display_height = bottom; + } +} + +void gfxConfigureResolution(s32 width, s32 height) { + gfxConfigureCrop(0, 0, width, height); +} + Result _gfxGraphicBufferInit(s32 buf, u32 nvmap_handle) { g_gfx_BufferInitData.refcount = buf; g_gfx_BufferInitData.data.nvmap_handle0 = nvmap_handle; @@ -397,12 +429,17 @@ void gfxSwapBuffers() { } u8* gfxGetFramebuffer(u32* width, u32* height) { - if(width) *width = g_gfx_framebuf_width; - if(height) *height = g_gfx_framebuf_height; + if(width) *width = g_gfx_framebuf_display_width; + if(height) *height = g_gfx_framebuf_display_height; return &g_gfxFramebuf[g_gfxCurrentBuffer*g_gfx_singleframebuf_size]; } +void gfxGetFramebufferResolution(u32* width, u32* height) { + if(width) *width = g_gfx_framebuf_width; + if(height) *height = g_gfx_framebuf_height; +} + size_t gfxGetFramebufferSize(void) { return g_gfx_singleframebuf_size; }