diff --git a/nx/include/switch/runtime/devices/console.h b/nx/include/switch/runtime/devices/console.h index 0d16a6aa..a9867c50 100644 --- a/nx/include/switch/runtime/devices/console.h +++ b/nx/include/switch/runtime/devices/console.h @@ -10,12 +10,9 @@ * * General usage is to initialize the console by: * @code - * consoleDemoInit() - * @endcode - * or to customize the console usage by: - * @code - * consoleInit() + * consoleInit(NULL) * @endcode + * optionally customizing the console usage by passing a pointer to a custom PrintConsole struct. */ #pragma once #include "../../types.h" @@ -31,15 +28,27 @@ #define CONSOLE_CYAN CONSOLE_ESC(36;1m) #define CONSOLE_WHITE CONSOLE_ESC(37;1m) -/// A callback for printing a character. -typedef bool(*ConsolePrint)(void* con, int c); +// Forward declaration +typedef struct PrintConsole PrintConsole; + +/// Renderer interface for the console. +typedef struct ConsoleRenderer +{ + bool (*init)(PrintConsole* con); + void (*deinit)(PrintConsole* con); + void (*drawChar)(PrintConsole* con, int x, int y, int c); + void (*scrollWindow)(PrintConsole* con); + void (*flushAndSwap)(PrintConsole* con); +} ConsoleRenderer; /// A font struct for the console. typedef struct ConsoleFont { - u16* gfx; ///< A pointer to the font graphics + const void* gfx; ///< A pointer to the font graphics u16 asciiOffset; ///< Offset to the first valid character in the font table u16 numChars; ///< Number of characters in the font graphics + u16 tileWidth; + u16 tileHeight; }ConsoleFont; /** @@ -51,10 +60,13 @@ typedef struct ConsoleFont * { * //Font: * { - * (u16*)default_font_bin, //font gfx + * default_font_bin, //font gfx * 0, //first ascii character in the set - * 128, //number of characters in the font set + * 256, //number of characters in the font set + * 16, //tile width + * 16, //tile height * }, + * NULL, //renderer * 0,0, //cursorX cursorY * 0,0, //prevcursorX prevcursorY * 80, //console width @@ -64,18 +76,17 @@ typedef struct ConsoleFont * 80, //window width * 45, //window height * 3, //tab size - * 0, //font character offset - * 0, //print callback + * 7, // foreground color + * 0, // background color + * 0, // flags * false //console initialized * }; * @endcode */ -typedef struct PrintConsole +struct PrintConsole { ConsoleFont font; ///< Font of the console - - u32 *frameBuffer; ///< Framebuffer address - u32 *frameBuffer2; ///< Framebuffer address + ConsoleRenderer* renderer; ///< Renderer of the console int cursorX; ///< Current X location of the cursor (as a tile offset by default) int cursorY; ///< Current Y location of the cursor (as a tile offset by default) @@ -86,20 +97,18 @@ typedef struct PrintConsole int consoleWidth; ///< Width of the console hardware layer in characters int consoleHeight; ///< Height of the console hardware layer in characters - int windowX; ///< Window X location in characters (not implemented) - int windowY; ///< Window Y location in characters (not implemented) - int windowWidth; ///< Window width in characters (not implemented) - int windowHeight; ///< Window height in characters (not implemented) + int windowX; ///< Window X location in characters + int windowY; ///< Window Y location in characters + int windowWidth; ///< Window width in characters + int windowHeight; ///< Window height in characters int tabSize; ///< Size of a tab int fg; ///< Foreground color int bg; ///< Background color int flags; ///< Reverse/bright flags - ConsolePrint PrintChar; ///< Callback for printing a character. Should return true if it has handled rendering the graphics (else the print engine will attempt to render via tiles). - bool consoleInitialised; ///< True if the console is initialized -}PrintConsole; +}; #define CONSOLE_COLOR_BOLD (1<<0) ///< Bold text #define CONSOLE_COLOR_FAINT (1<<1) ///< Faint text @@ -157,11 +166,24 @@ PrintConsole *consoleSelect(PrintConsole* console); */ PrintConsole* consoleInit(PrintConsole* console); +/** + * @brief Deinitialise the console. + * @param console A pointer to the console data to initialize (if it's NULL, the default console will be used). + */ +void consoleExit(PrintConsole* console); + +/** + * @brief Updates the console, submitting a new frame to the display. + * @param console A pointer to the console data to initialize (if it's NULL, the default console will be used). + * @remark This function should be called periodically. Failure to call this function will result in lack of screen updating. + */ +void consoleUpdate(PrintConsole* console); + /** * @brief Initializes debug console output on stderr to the specified device. * @param device The debug device (or devices) to output debug print statements to. */ void consoleDebugInit(debugDevice device); -/// Clears the screan by using iprintf("\x1b[2J"); +/// Clears the screan by using printf("\x1b[2J"); void consoleClear(void); diff --git a/nx/source/runtime/devices/console.c b/nx/source/runtime/devices/console.c index 0386d72c..880ece88 100644 --- a/nx/source/runtime/devices/console.c +++ b/nx/source/runtime/devices/console.c @@ -3,51 +3,21 @@ #include #include "runtime/devices/console.h" #include "kernel/svc.h" -#include "display/gfx.h" #include "default_font_bin.h" -//set up the palette for color printing -static u32 colorTable[] = { - RGBA8_MAXALPHA( 0, 0, 0), // black - RGBA8_MAXALPHA(128, 0, 0), // red - RGBA8_MAXALPHA( 0,128, 0), // green - RGBA8_MAXALPHA(128,128, 0), // yellow - RGBA8_MAXALPHA( 0, 0,128), // blue - RGBA8_MAXALPHA(128, 0,128), // magenta - RGBA8_MAXALPHA( 0,128,128), // cyan - RGBA8_MAXALPHA(192,192,192), // white - - RGBA8_MAXALPHA(128,128,128), // bright black - RGBA8_MAXALPHA(255, 0, 0), // bright red - RGBA8_MAXALPHA( 0,255, 0), // bright green - RGBA8_MAXALPHA(255,255, 0), // bright yellow - RGBA8_MAXALPHA( 0, 0,255), // bright blue - RGBA8_MAXALPHA(255, 0,255), // bright magenta - RGBA8_MAXALPHA( 0,255,255), // bright cyan - RGBA8_MAXALPHA(255,255,255), // bright white - - RGBA8_MAXALPHA( 0, 0, 0), // faint black - RGBA8_MAXALPHA( 64, 0, 0), // faint red - RGBA8_MAXALPHA( 0, 64, 0), // faint green - RGBA8_MAXALPHA( 64, 64, 0), // faint yellow - RGBA8_MAXALPHA( 0, 0, 64), // faint blue - RGBA8_MAXALPHA( 64, 0, 64), // faint magenta - RGBA8_MAXALPHA( 0, 64, 64), // faint cyan - RGBA8_MAXALPHA( 96, 96, 96), // faint white -}; - //The below width/height is for 720p. -PrintConsole defaultConsole = +static PrintConsole defaultConsole = { //Font: { - (u16*)default_font_bin, //font gfx + default_font_bin, //font gfx 0, //first ascii character in the set - 256 //number of characters in the font set + 256, //number of characters in the font set + 16, //tile width + 16, //tile height }, - (u32*)NULL, - (u32*)NULL, + NULL, //renderer 0,0, //cursorX cursorY 0,0, //prevcursorX prevcursorY 80, //console width @@ -60,18 +30,18 @@ PrintConsole defaultConsole = 7, // foreground color 0, // background color 0, // flags - 0, //print callback false //console initialized }; -PrintConsole currentCopy; +static PrintConsole currentCopy; -PrintConsole* currentConsole = ¤tCopy; +static PrintConsole* currentConsole = ¤tCopy; PrintConsole* consoleGetDefault(void){return &defaultConsole;} -void consolePrintChar(int c); -void consoleDrawChar(int c); +static void consoleNewRow(void); +static void consolePrintChar(int c); +static void consoleDrawChar(int c); //--------------------------------------------------------------------------------- static void consoleCls(char mode) { @@ -123,9 +93,6 @@ static void consoleCls(char mode) { break; } } - //gfxFlushBuffers(); - //gfxSwapBuffers(); - //gfxWaitForVsync(); } //--------------------------------------------------------------------------------- static void consoleClearLine(char mode) { @@ -178,9 +145,6 @@ static void consoleClearLine(char mode) { break; } } - //gfxFlushBuffers(); - //gfxSwapBuffers(); - //gfxWaitForVsync(); } @@ -526,6 +490,8 @@ static const devoptab_t dotab_null = { NULL }; +ConsoleRenderer* getDefaultConsoleRenderer(void); + //--------------------------------------------------------------------------------- PrintConsole* consoleInit(PrintConsole* console) { //--------------------------------------------------------------------------------- @@ -549,27 +515,44 @@ PrintConsole* consoleInit(PrintConsole* console) { } *currentConsole = defaultConsole; + if (!console->renderer) { + console->renderer = getDefaultConsoleRenderer(); + } - console->consoleInitialised = 1; - - gfxSetMode(GfxMode_TiledDouble); - - console->frameBuffer = (u32*)gfxGetFramebuffer(NULL, NULL); - gfxSwapBuffers(); - console->frameBuffer2 = (u32*)gfxGetFramebuffer(NULL, NULL); - - //gfxFlushBuffers(); - //gfxSwapBuffers(); - //gfxWaitForVsync(); - - consoleCls('2'); + if (console->renderer->init(console)) { + console->consoleInitialised = true; + consoleCls('2'); + return console; + } return currentConsole; - } //--------------------------------------------------------------------------------- -void consoleDebugInit(debugDevice device){ +void consoleExit(PrintConsole* console) { +//--------------------------------------------------------------------------------- + + if (!console) console = currentConsole; + + if (console->consoleInitialised) { + console->renderer->deinit(console); + console->consoleInitialised = false; + } +} + +//--------------------------------------------------------------------------------- +void consoleUpdate(PrintConsole* console) { +//--------------------------------------------------------------------------------- + + if (!console) console = currentConsole; + + if (console->consoleInitialised) { + console->renderer->flushAndSwap(console); + } +} + +//--------------------------------------------------------------------------------- +void consoleDebugInit(debugDevice device) { //--------------------------------------------------------------------------------- int buffertype = _IONBF; @@ -592,7 +575,7 @@ void consoleDebugInit(debugDevice device){ } //--------------------------------------------------------------------------------- -PrintConsole *consoleSelect(PrintConsole* console){ +PrintConsole *consoleSelect(PrintConsole* console) { //--------------------------------------------------------------------------------- PrintConsole *tmp = currentConsole; currentConsole = console; @@ -600,7 +583,7 @@ PrintConsole *consoleSelect(PrintConsole* console){ } //--------------------------------------------------------------------------------- -void consoleSetFont(PrintConsole* console, ConsoleFont* font){ +void consoleSetFont(PrintConsole* console, ConsoleFont* font) { //--------------------------------------------------------------------------------- if(!console) console = currentConsole; @@ -610,99 +593,28 @@ void consoleSetFont(PrintConsole* console, ConsoleFont* font){ } //--------------------------------------------------------------------------------- -static void newRow(void) { +void consoleNewRow(void) { //--------------------------------------------------------------------------------- - - currentConsole->cursorY ++; - if(currentConsole->cursorY >= currentConsole->windowHeight) { currentConsole->cursorY --; - - int i,j; - u32 x, y; - - x = currentConsole->windowX * 16; - y = currentConsole->windowY * 16; - - for (i=0; iwindowWidth*16; i++) { - u32 *from; - u32 *to; - for (j=0;j<(currentConsole->windowHeight-1)*16;j++) { - to = ¤tConsole->frameBuffer[gfxGetFramebufferDisplayOffset(x + i, y + j)]; - from = ¤tConsole->frameBuffer[gfxGetFramebufferDisplayOffset(x + i, y + 16 + j)]; - *to = *from; - to = ¤tConsole->frameBuffer2[gfxGetFramebufferDisplayOffset(x + i, y + j)]; - from = ¤tConsole->frameBuffer2[gfxGetFramebufferDisplayOffset(x + i, y + 16 + j)]; - *to = *from; - } - } - + currentConsole->renderer->scrollWindow(currentConsole); consoleClearLine('2'); } } + //--------------------------------------------------------------------------------- void consoleDrawChar(int c) { //--------------------------------------------------------------------------------- c -= currentConsole->font.asciiOffset; if ( c < 0 || c > currentConsole->font.numChars ) return; - u16 *fontdata = currentConsole->font.gfx + (16 * c); - - int writingColor = currentConsole->fg; - int screenColor = currentConsole->bg; - - if (currentConsole->flags & CONSOLE_COLOR_BOLD) { - writingColor += 8; - } else if (currentConsole->flags & CONSOLE_COLOR_FAINT) { - writingColor += 16; - } - - if (currentConsole->flags & CONSOLE_COLOR_REVERSE) { - int tmp = writingColor; - writingColor = screenColor; - screenColor = tmp; - } - - u32 bg = colorTable[screenColor]; - u32 fg = colorTable[writingColor]; - - u128 *tmp = (u128*)fontdata; - - u128 bvaltop = tmp[0]; - u128 bvalbtm = tmp[1]; - - if (currentConsole->flags & CONSOLE_UNDERLINE) bvalbtm |= (u128)0xffffULL << 7*16; - - if (currentConsole->flags & CONSOLE_CROSSED_OUT) bvaltop |= (u128)0xffffULL << 7*16; - - u16 mask = 0x8000; - - int i, j; - - int x = (currentConsole->cursorX + currentConsole->windowX) * 16; - int y = ((currentConsole->cursorY + currentConsole->windowY) *16 ); - - u32 *screen; - - for (i=0;i<16;i++) { - for (j=0;j<8;j++) { - uint32_t screenOffset = gfxGetFramebufferDisplayOffset(x + i, y + j); - screen = ¤tConsole->frameBuffer[screenOffset]; - if (bvaltop >> (16*j) & mask) { *screen = fg; }else{ *screen = bg; } - screen = ¤tConsole->frameBuffer2[screenOffset]; - if (bvaltop >> (16*j) & mask) { *screen = fg; }else{ *screen = bg; } - - screenOffset = gfxGetFramebufferDisplayOffset(x + i, y + j + 8); - screen = ¤tConsole->frameBuffer[screenOffset]; - if (bvalbtm >> (16*j) & mask) { *screen = fg; }else{ *screen = bg; } - screen = ¤tConsole->frameBuffer2[screenOffset]; - if (bvalbtm >> (16*j) & mask) { *screen = fg; }else{ *screen = bg; } - } - mask >>= 1; - } - + currentConsole->renderer->drawChar( + currentConsole, + currentConsole->cursorX + currentConsole->windowX, + currentConsole->cursorY + currentConsole->windowY, + c); } //--------------------------------------------------------------------------------- @@ -710,14 +622,10 @@ void consolePrintChar(int c) { //--------------------------------------------------------------------------------- if (c==0) return; - if(currentConsole->PrintChar) - if(currentConsole->PrintChar(currentConsole, c)) - return; - if(currentConsole->cursorX >= currentConsole->windowWidth) { currentConsole->cursorX = 0; - newRow(); + consoleNewRow(); } switch(c) { @@ -730,7 +638,7 @@ void consolePrintChar(int c) { Reason: VT sequences are more specific to the task of cursor placement. The special escape sequences \b \f & \v are archaic and non-portable. */ - case 8: + case '\b': currentConsole->cursorX--; if(currentConsole->cursorX < 0) { @@ -745,16 +653,13 @@ void consolePrintChar(int c) { consoleDrawChar(' '); break; - case 9: + case '\t': currentConsole->cursorX += currentConsole->tabSize - ((currentConsole->cursorX)%(currentConsole->tabSize)); break; - case 10: - newRow(); - case 13: + case '\n': + consoleNewRow(); + case '\r': currentConsole->cursorX = 0; - //gfxFlushBuffers(); - //gfxSwapBuffers(); - //gfxWaitForVsync(); break; default: consoleDrawChar(c); @@ -766,11 +671,11 @@ void consolePrintChar(int c) { //--------------------------------------------------------------------------------- void consoleClear(void) { //--------------------------------------------------------------------------------- - iprintf("\x1b[2J"); + printf("\x1b[2J"); } //--------------------------------------------------------------------------------- -void consoleSetWindow(PrintConsole* console, int x, int y, int width, int height){ +void consoleSetWindow(PrintConsole* console, int x, int y, int width, int height) { //--------------------------------------------------------------------------------- if(!console) console = currentConsole; @@ -784,6 +689,3 @@ void consoleSetWindow(PrintConsole* console, int x, int y, int width, int height console->cursorY = 0; } - - - diff --git a/nx/source/runtime/devices/console_sw.c b/nx/source/runtime/devices/console_sw.c new file mode 100644 index 00000000..1fed754b --- /dev/null +++ b/nx/source/runtime/devices/console_sw.c @@ -0,0 +1,188 @@ +#include +#include +#include +#include "result.h" +#include "runtime/devices/console.h" +#include "display/gfx.h" + +//set up the palette for color printing +static const u32 colorTable[] = { + RGBA8_MAXALPHA( 0, 0, 0), // black + RGBA8_MAXALPHA(128, 0, 0), // red + RGBA8_MAXALPHA( 0,128, 0), // green + RGBA8_MAXALPHA(128,128, 0), // yellow + RGBA8_MAXALPHA( 0, 0,128), // blue + RGBA8_MAXALPHA(128, 0,128), // magenta + RGBA8_MAXALPHA( 0,128,128), // cyan + RGBA8_MAXALPHA(192,192,192), // white + + RGBA8_MAXALPHA(128,128,128), // bright black + RGBA8_MAXALPHA(255, 0, 0), // bright red + RGBA8_MAXALPHA( 0,255, 0), // bright green + RGBA8_MAXALPHA(255,255, 0), // bright yellow + RGBA8_MAXALPHA( 0, 0,255), // bright blue + RGBA8_MAXALPHA(255, 0,255), // bright magenta + RGBA8_MAXALPHA( 0,255,255), // bright cyan + RGBA8_MAXALPHA(255,255,255), // bright white + + RGBA8_MAXALPHA( 0, 0, 0), // faint black + RGBA8_MAXALPHA( 64, 0, 0), // faint red + RGBA8_MAXALPHA( 0, 64, 0), // faint green + RGBA8_MAXALPHA( 64, 64, 0), // faint yellow + RGBA8_MAXALPHA( 0, 0, 64), // faint blue + RGBA8_MAXALPHA( 64, 0, 64), // faint magenta + RGBA8_MAXALPHA( 0, 64, 64), // faint cyan + RGBA8_MAXALPHA( 96, 96, 96), // faint white +}; + +struct ConsoleSwRenderer +{ + ConsoleRenderer base; + u32 *frameBuffer; ///< Framebuffer address + u32 *frameBuffer2; ///< Framebuffer address +}; + +static struct ConsoleSwRenderer* ConsoleSwRenderer(PrintConsole* con) +{ + return (struct ConsoleSwRenderer*)con->renderer; +} + +static bool ConsoleSwRenderer_init(PrintConsole* con) +{ + struct ConsoleSwRenderer* sw = ConsoleSwRenderer(con); + + if (con->font.tileWidth != 16 || con->font.tileHeight != 16) { + // Only 16x16 tiles are supported for the font + return false; + } + + if (R_FAILED(gfxInitDefault())) { + // Graphics failed to initialize + return false; + } + + u32 width, height; + gfxGetFramebufferResolution(&width, &height); + if (con->consoleWidth > (width/16) || con->consoleHeight > (height/16)) { + // Unsupported console size + return false; + } + + gfxSetMode(GfxMode_TiledDouble); + sw->frameBuffer = (u32*)gfxGetFramebuffer(NULL, NULL); + gfxSwapBuffers(); + sw->frameBuffer2 = (u32*)gfxGetFramebuffer(NULL, NULL); + + return true; +} + +static void ConsoleSwRenderer_deinit(PrintConsole* con) +{ + gfxExit(); +} + +static void ConsoleSwRenderer_drawChar(PrintConsole* con, int x, int y, int c) +{ + struct ConsoleSwRenderer* sw = ConsoleSwRenderer(con); + const u16 *fontdata = (const u16*)con->font.gfx + (16 * c); + + int writingColor = con->fg; + int screenColor = con->bg; + + if (con->flags & CONSOLE_COLOR_BOLD) { + writingColor += 8; + } else if (con->flags & CONSOLE_COLOR_FAINT) { + writingColor += 16; + } + + if (con->flags & CONSOLE_COLOR_REVERSE) { + int tmp = writingColor; + writingColor = screenColor; + screenColor = tmp; + } + + u32 bg = colorTable[screenColor]; + u32 fg = colorTable[writingColor]; + + u128 *tmp = (u128*)fontdata; + + u128 bvaltop = tmp[0]; + u128 bvalbtm = tmp[1]; + + if (con->flags & CONSOLE_UNDERLINE) bvalbtm |= (u128)0xffffULL << 7*16; + + if (con->flags & CONSOLE_CROSSED_OUT) bvaltop |= (u128)0xffffULL << 7*16; + + u16 mask = 0x8000; + + int i, j; + + x *= 16; + y *= 16; + + u32 *screen; + + for (i=0;i<16;i++) { + for (j=0;j<8;j++) { + uint32_t screenOffset = gfxGetFramebufferDisplayOffset(x + i, y + j); + screen = &sw->frameBuffer[screenOffset]; + if (bvaltop >> (16*j) & mask) { *screen = fg; }else{ *screen = bg; } + screen = &sw->frameBuffer2[screenOffset]; + if (bvaltop >> (16*j) & mask) { *screen = fg; }else{ *screen = bg; } + + screenOffset = gfxGetFramebufferDisplayOffset(x + i, y + j + 8); + screen = &sw->frameBuffer[screenOffset]; + if (bvalbtm >> (16*j) & mask) { *screen = fg; }else{ *screen = bg; } + screen = &sw->frameBuffer2[screenOffset]; + if (bvalbtm >> (16*j) & mask) { *screen = fg; }else{ *screen = bg; } + } + mask >>= 1; + } +} + +static void ConsoleSwRenderer_scrollWindow(PrintConsole* con) +{ + struct ConsoleSwRenderer* sw = ConsoleSwRenderer(con); + int i,j; + u32 x, y; + + x = con->windowX * 16; + y = con->windowY * 16; + + for (i=0; iwindowWidth*16; i++) { + u32 *from; + u32 *to; + for (j=0;j<(con->windowHeight-1)*16;j++) { + to = &sw->frameBuffer[gfxGetFramebufferDisplayOffset(x + i, y + j)]; + from = &sw->frameBuffer[gfxGetFramebufferDisplayOffset(x + i, y + 16 + j)]; + *to = *from; + to = &sw->frameBuffer2[gfxGetFramebufferDisplayOffset(x + i, y + j)]; + from = &sw->frameBuffer2[gfxGetFramebufferDisplayOffset(x + i, y + 16 + j)]; + *to = *from; + } + } +} + +static void ConsoleSwRenderer_flushAndSwap(PrintConsole* con) +{ + gfxFlushBuffers(); + gfxSwapBuffers(); +} + +static struct ConsoleSwRenderer s_consoleSwRenderer = +{ + { + ConsoleSwRenderer_init, + ConsoleSwRenderer_deinit, + ConsoleSwRenderer_drawChar, + ConsoleSwRenderer_scrollWindow, + ConsoleSwRenderer_flushAndSwap, + }, //base + NULL, //frameBuffer + NULL, //frameBuffer2 +}; + +__attribute__((weak)) ConsoleRenderer* getDefaultConsoleRenderer(void) +{ + return &s_consoleSwRenderer.base; +}