Skip to content

Commit

Permalink
Updated gfx API. Replaced gfxSetDoubleBuffering() with gfxSetMode(), …
Browse files Browse the repository at this point in the history
…and added GfxMode enum. Updated gfx.h comments. Updated gfxGetFramebufferDisplayOffset() for using the aligned width. The new GfxMode_LinearDouble is now used by default, apps must not use gfxGetFramebufferDisplayOffset() with this mode. Apps using gfxGetFramebufferDisplayOffset() must be updated.
  • Loading branch information
yellows8 committed Feb 12, 2018
1 parent 4b2a32a commit 13b4c74
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 18 deletions.
27 changes: 18 additions & 9 deletions nx/include/switch/gfx/gfx.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@
/// Same as \ref RGBA8 except with alpha=0xff.
#define RGBA8_MAXALPHA(r,g,b) RGBA8(r,g,b,0xff)

/// GfxMode set by \ref gfxSetMode. The default is GfxMode_LinearDouble.
typedef enum
{
GfxMode_TiledSingle, /// Single-buffering with raw tiled (block-linear) framebuffer.
GfxMode_TiledDouble, /// Double-buffering with raw tiled (block-linear) framebuffer.
GfxMode_LinearDouble /// Double-buffering with linear framebuffer, which is transferred to the actual framebuffer by \ref gfxFlushBuffers().
} GfxMode;

/**
* @brief Initializes the graphics subsystem.
* @warning Do not use \ref viInitialize when using this function.
Expand All @@ -30,7 +38,7 @@ void gfxExit(void);
* @brief Sets the resolution to be used when initializing the graphics subsystem.
* @param[in] width Horizontal resolution, in pixels.
* @param[in] height Vertical resolution, in pixels.
* @note The default resolution is 720p, however you should use \ref gfxGetFramebuffer to get the current width/height.
* @note The default resolution is 720p.
* @note This can only be used before calling \ref gfxInitDefault, this will use \ref fatalSimple otherwise. If the input is 0, the default resolution will be used during \ref gfxInitDefault. This sets the maximum resolution for the framebuffer, used during \ref gfxInitDefault. This is also used as the current resolution when crop isn't set. The width/height are reset to the default when \ref gfxExit is used.
* @note Normally you should only use this when you need a maximum resolution larger than the default, see above.
*/
Expand Down Expand Up @@ -61,34 +69,35 @@ void gfxWaitForVsync(void);
/// Swaps the framebuffers (for double-buffering).
void gfxSwapBuffers(void);

/// Get the current framebuffer address, with optional output ptrs for the display width/height. The display width/height is adjusted by \ref gfxConfigureCrop and \ref gfxConfigureResolution.
/// Get the current framebuffer address, with optional output ptrs for the display framebuffer width/height. The display width/height is adjusted by \ref gfxConfigureCrop and \ref gfxConfigureResolution.
u8* gfxGetFramebuffer(u32* width, u32* height);

/// Get the original framebuffer width/height without crop.
/// Get the 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 \ref gfxGetFramebuffer or \ref gfxGetFramebufferResolution.
/// Use this to get the actual byte-size of the framebuffer for use with memset/etc.
size_t gfxGetFramebufferSize(void);

/// Enables or disables double-buffering.
void gfxSetDoubleBuffering(bool doubleBuffering);
/// Sets the \ref GfxMode.
void gfxSetMode(GfxMode mode);

/// Flushes the framebuffer in the data cache.
/// Flushes the framebuffer in the data cache. When \ref GfxMode is GfxMode_LinearDouble, this also transfers the linear-framebuffer to the actual framebuffer.
void gfxFlushBuffers(void);

/// Use this to get the pixel-offset in the framebuffer. Returned value is in pixels, not bytes.
/// This implements tegra blocklinear, with hard-coded constants etc.
/// Do not use this when \ref GfxMode is GfxMode_LinearDouble.
static inline u32 gfxGetFramebufferDisplayOffset(u32 x, u32 y) {
u32 tmp_pos;

extern size_t g_gfx_framebuf_width;
extern size_t g_gfx_framebuf_aligned_width;
extern size_t g_gfx_framebuf_display_height;

//if (x >= g_gfx_framebuf_width || y >= g_gfx_framebuf_display_height) return (gfxGetFramebufferSize()-4)/4;//Return the last pixel-offset in the buffer, the data located here is not displayed due to alignment. (Disabled for perf)

y = g_gfx_framebuf_display_height-1-y;

tmp_pos = ((y & 127) / 16) + (x/16*8) + ((y/16/8)*(g_gfx_framebuf_width/16*8));
tmp_pos = ((y & 127) / 16) + (x/16*8) + ((y/16/8)*(g_gfx_framebuf_aligned_width/16*8));
tmp_pos *= 16*16 * 4;

tmp_pos += ((y%16)/8)*512 + ((x%16)/8)*256 + ((y%8)/2)*64 + ((x%8)/4)*32 + (y%2)*16 + (x%4)*4;//This line is a modified version of code from the Tegra X1 datasheet.
Expand Down
63 changes: 55 additions & 8 deletions nx/source/gfx/gfx.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <string.h>
#include <malloc.h>
#include "types.h"
#include "result.h"
#include "arm/cache.h"
Expand Down Expand Up @@ -29,12 +30,15 @@ static bufferProducerFence g_gfx_DequeueBuffer_fence;
static bufferProducerQueueBufferOutput g_gfx_Connect_QueueBufferOutput;
static bufferProducerQueueBufferOutput g_gfx_QueueBuffer_QueueBufferOutput;

static bool g_gfxDoubleBuf = 1;
static GfxMode g_gfxMode = GfxMode_LinearDouble;

static u8 *g_gfxFramebufLinear;

size_t g_gfx_framebuf_width=0, g_gfx_framebuf_aligned_width=0;
size_t g_gfx_framebuf_height=0, g_gfx_framebuf_aligned_height=0;
size_t g_gfx_framebuf_display_width=0, g_gfx_framebuf_display_height=0;
size_t g_gfx_singleframebuf_size=0;
size_t g_gfx_singleframebuf_linear_size=0;

static AppletHookCookie g_gfx_autoresolution_applethookcookie;
static bool g_gfx_autoresolution_enabled;
Expand Down Expand Up @@ -125,7 +129,7 @@ static Result _gfxDequeueBuffer(void) {
bufferProducerFence tmp_fence;
bool async=0;

if (!g_gfxDoubleBuf) {
if (g_gfxMode == GfxMode_TiledSingle) {
g_gfxCurrentProducerBuffer = -1;
return 0;
}
Expand Down Expand Up @@ -173,7 +177,7 @@ static Result _gfxInit(ViServiceType servicetype, const char *DisplayName, u32 L
g_gfx_ProducerConnected = 0;
g_gfxFramebuf = NULL;
g_gfxFramebufSize = 0;
g_gfxDoubleBuf = 1;
g_gfxMode = GfxMode_LinearDouble;

memset(g_gfx_ProducerSlotsRequested, 0, sizeof(g_gfx_ProducerSlotsRequested));
memset(&g_gfx_DequeueBuffer_fence, 0, sizeof(g_gfx_DequeueBuffer_fence));
Expand All @@ -190,6 +194,7 @@ static Result _gfxInit(ViServiceType servicetype, const char *DisplayName, u32 L
g_gfx_framebuf_aligned_height = (g_gfx_framebuf_height+127) & ~127;//Align to 128.

g_gfx_singleframebuf_size = g_gfx_framebuf_aligned_width*g_gfx_framebuf_aligned_height*4;
g_gfx_singleframebuf_linear_size = g_gfx_framebuf_width*g_gfx_framebuf_height*4;

g_gfx_BufferInitData.width = g_gfx_framebuf_width;
g_gfx_BufferInitData.height = g_gfx_framebuf_height;
Expand All @@ -204,10 +209,18 @@ static Result _gfxInit(ViServiceType servicetype, const char *DisplayName, u32 L
g_gfx_BufferInitData.data.buffer_size0 = g_gfx_singleframebuf_size;
g_gfx_BufferInitData.data.buffer_size1 = g_gfx_singleframebuf_size;

g_gfxFramebufLinear = memalign(0x1000, g_gfx_singleframebuf_linear_size);
if (g_gfxFramebufLinear) {
memset(g_gfxFramebufLinear, 0, g_gfx_singleframebuf_linear_size);
}
else {
rc = MAKERESULT(Module_Libnx, LibnxError_OutOfMemory);
return rc;
}

rc = viInitialize(servicetype);
if (R_FAILED(rc)) return rc;

rc = viOpenDisplay(DisplayName, &g_gfxDisplay);
if (R_SUCCEEDED(rc)) rc = viOpenDisplay(DisplayName, &g_gfxDisplay);

if (R_SUCCEEDED(rc)) rc = viGetDisplayVsyncEvent(&g_gfxDisplay, &g_gfxDisplayVsyncEvent);

Expand Down Expand Up @@ -286,6 +299,9 @@ static Result _gfxInit(ViServiceType servicetype, const char *DisplayName, u32 L
g_gfxDisplayVsyncEvent = INVALID_HANDLE;
}

free(g_gfxFramebufLinear);
g_gfxFramebufLinear = NULL;

g_gfxNativeWindow_ID = 0;
g_gfxCurrentBuffer = 0;
g_gfxCurrentProducerBuffer = -1;
Expand Down Expand Up @@ -356,6 +372,9 @@ void gfxExit(void)

viExit();

free(g_gfxFramebufLinear);
g_gfxFramebufLinear = NULL;

g_gfxInitialized = 0;
g_gfxNativeWindow_ID = 0;

Expand Down Expand Up @@ -495,6 +514,9 @@ u8* gfxGetFramebuffer(u32* width, u32* height) {
if(width) *width = g_gfx_framebuf_display_width;
if(height) *height = g_gfx_framebuf_display_height;

if (g_gfxMode == GfxMode_LinearDouble)
return g_gfxFramebufLinear;

return &g_gfxFramebuf[g_gfxCurrentBuffer*g_gfx_singleframebuf_size];
}

Expand All @@ -504,15 +526,40 @@ void gfxGetFramebufferResolution(u32* width, u32* height) {
}

size_t gfxGetFramebufferSize(void) {
if (g_gfxMode == GfxMode_LinearDouble)
return g_gfx_singleframebuf_linear_size;

return g_gfx_singleframebuf_size;
}

void gfxSetDoubleBuffering(bool doubleBuffering) {
g_gfxDoubleBuf = doubleBuffering;
void gfxSetMode(GfxMode mode) {
g_gfxMode = mode;
}

void gfxFlushBuffers(void) {
armDCacheFlush(&g_gfxFramebuf[g_gfxCurrentBuffer*g_gfx_singleframebuf_size], g_gfx_singleframebuf_size);
u32 *actual_framebuf = (u32*)&g_gfxFramebuf[g_gfxCurrentBuffer*g_gfx_singleframebuf_size];

if (g_gfxMode == GfxMode_LinearDouble) {
//TODO: Implement block-linear here without re-calculating the entire offset with gfxGetFramebufferDisplayOffset().

size_t x, y, j, tmpoff;
size_t width = g_gfx_framebuf_display_width;
size_t height = g_gfx_framebuf_display_height;
u32 *in_framebuf = (u32*)g_gfxFramebufLinear;

for (y=0; y<height; y++) {
for (x=0; x<width; x+=4) {
tmpoff = gfxGetFramebufferDisplayOffset(x, y);
for(j=0; j<4; j++) {
if (x+j >= width)
break;
actual_framebuf[tmpoff+j] = in_framebuf[y * width + x+j];
}
}
}
}

armDCacheFlush(actual_framebuf, g_gfx_singleframebuf_size);
}

/*static Result _gfxGetDisplayResolution(u64 *width, u64 *height) {
Expand Down
2 changes: 1 addition & 1 deletion nx/source/runtime/devices/console.c
Original file line number Diff line number Diff line change
Expand Up @@ -547,7 +547,7 @@ PrintConsole* consoleInit(PrintConsole* console) {

console->consoleInitialised = 1;

gfxSetDoubleBuffering(false);
gfxSetMode(GfxMode_TiledSingle);
gfxFlushBuffers();
gfxWaitForVsync();

Expand Down

0 comments on commit 13b4c74

Please sign in to comment.