From 216bdcedc3d8d8555e17c16aa7c44f512ef90ffd Mon Sep 17 00:00:00 2001 From: Mike Beaton Date: Wed, 26 Apr 2023 06:53:59 +0100 Subject: [PATCH] OcConsoleLib: Builtin renderer updates - Avoid additional clear screen when resyncing - Use same values to trigger full clear screen after background colour change as after mark uncontrolled - Only scroll used width when controlled - Reset controlled area after clear screen - Fix mConsoleMaxPosY init error for controlled mode o Present since 76e889f89af7ecdec0a8de191d7ded5856b338fb - Fix ConsoleControl wording in docs - Add ASSERTS and comments --- Docs/Configuration.tex | 4 +- Library/OcConsoleLib/TextOutputBuiltin.c | 91 ++++++++++++++++-------- Library/OcConsoleLib/TextOutputSystem.c | 1 + 3 files changed, 63 insertions(+), 33 deletions(-) diff --git a/Docs/Configuration.tex b/Docs/Configuration.tex index f79f0f1b..2a64bd6f 100755 --- a/Docs/Configuration.tex +++ b/Docs/Configuration.tex @@ -8123,7 +8123,7 @@ for additional options. UEFI firmware typically supports \texttt{ConsoleControl} with two rendering modes: \texttt{Graphics} and \texttt{Text}. Some types of firmware do not support \texttt{ConsoleControl} and rendering modes. OpenCore - and macOS expect text to only be shown in \texttt{Graphics} mode and + and macOS expect text to only be shown in \texttt{Text} mode but graphics to be drawn in any mode. Since this is not required by UEFI specification, exact behaviour varies. @@ -8150,7 +8150,7 @@ for additional options. The use of \texttt{BuiltinGraphics} is straightforward. For most platforms, it is necessary to enable \texttt{ProvideConsoleGop} and set \texttt{Resolution} to \texttt{Max}. The \texttt{BuiltinText} variant is - an alternative \texttt{BuiltinGraphics} for some very old and defective + an alternative to \texttt{BuiltinGraphics} for some very old and defective laptop firmware, which can only draw in \texttt{Text} mode. The use of \texttt{System} protocols is more complicated. Typically, diff --git a/Library/OcConsoleLib/TextOutputBuiltin.c b/Library/OcConsoleLib/TextOutputBuiltin.c index 63dd0ca8..61989e8e 100644 --- a/Library/OcConsoleLib/TextOutputBuiltin.c +++ b/Library/OcConsoleLib/TextOutputBuiltin.c @@ -323,9 +323,12 @@ RenderScroll ( VOID ) { + UINTN Width; + // - // Move data. + // Move used screen region. // + Width = TGT_PADD_WIDTH + (mConsoleMaxPosX + 1) * TGT_CHAR_WIDTH; mGraphicsOutput->Blt ( mGraphicsOutput, NULL, @@ -334,7 +337,7 @@ RenderScroll ( TGT_PADD_HEIGHT + TGT_CHAR_HEIGHT, 0, TGT_PADD_HEIGHT, - mGraphicsOutput->Mode->Info->HorizontalResolution, + MIN (Width, mGraphicsOutput->Mode->Info->HorizontalResolution), TGT_CHAR_HEIGHT * (mConsoleHeight - 1), 0 ); @@ -350,12 +353,15 @@ RenderScroll ( 0, 0, TGT_PADD_HEIGHT + TGT_CHAR_HEIGHT * (mConsoleHeight - 1), - mGraphicsOutput->Mode->Info->HorizontalResolution, + MIN (Width, mGraphicsOutput->Mode->Info->HorizontalResolution), TGT_CHAR_HEIGHT, 0 ); } +// +// Resync - called on detected change of GOP mode and on reset. +// STATIC EFI_STATUS RenderResync ( @@ -366,8 +372,8 @@ RenderResync ( Info = mGraphicsOutput->Mode->Info; - if ( (Info->HorizontalResolution < TGT_CHAR_WIDTH * 3) - || (Info->VerticalResolution < TGT_CHAR_HEIGHT * 3)) + if ( (Info->HorizontalResolution < TGT_CHAR_WIDTH * (2 * SCR_PADD + 1)) + || (Info->VerticalResolution < TGT_CHAR_HEIGHT * (2 * SCR_PADD + 1))) { return EFI_LOAD_ERROR; } @@ -590,11 +596,15 @@ AsciiTextTestString ( ) { if (StrCmp (String, OC_CONSOLE_MARK_UNCONTROLLED) == 0) { + // + // Set values which intentionally slightly overflow the screen clear calculations + // and get clamped to full screen. + // mConsoleMaxPosX = mGraphicsOutput->Mode->Info->HorizontalResolution / TGT_CHAR_WIDTH; mConsoleMaxPosY = mGraphicsOutput->Mode->Info->VerticalResolution / TGT_CHAR_HEIGHT; } else if (StrCmp (String, OC_CONSOLE_MARK_CONTROLLED) == 0) { mConsoleMaxPosX = 0; - mConsoleMaxPosX = 0; + mConsoleMaxPosY = 0; } return EFI_SUCCESS; @@ -697,11 +707,14 @@ AsciiTextSetAttribute ( BgColor = BitFieldRead32 ((UINT32)Attribute, 4, 6); // - // Once we change the background we should redraw everything. + // Once we change the background colour, any clear screen must cover the whole screen. // if (mGraphicsEfiColors[BgColor] != mBackgroundColor.Raw) { - mConsoleMaxPosX = mConsoleWidth + SCR_PADD; - mConsoleMaxPosY = mConsoleHeight + SCR_PADD; + // + // Match uncontrolled values. + // + mConsoleMaxPosX = mGraphicsOutput->Mode->Info->HorizontalResolution / TGT_CHAR_WIDTH; + mConsoleMaxPosY = mGraphicsOutput->Mode->Info->VerticalResolution / TGT_CHAR_HEIGHT; } mForegroundColor.Raw = mGraphicsEfiColors[FgColor]; @@ -715,6 +728,11 @@ AsciiTextSetAttribute ( return EFI_SUCCESS; } +// +// Note: This intentionally performs a partial screen clear, affecting only the +// area containing text which has been written using our renderer, unless console +// is marked uncontrolled prior to clearing. +// STATIC EFI_STATUS EFIAPI @@ -729,35 +747,42 @@ AsciiTextClearScreen ( OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + // + // No need to re-clear screen straight after resync; but note that the initial screen + // clear after reset, although of non-zero size, is intentionally very lightweight. + // if (mConsoleGopMode != mGraphicsOutput->Mode->Mode) { Status = RenderResync (This); if (EFI_ERROR (Status)) { gBS->RestoreTPL (OldTpl); return EFI_DEVICE_ERROR; } + } else { + // + // When controlled, we assume that only text which we rendered needs to be cleared. + // When marked uncontrolled anyone may have put content anywhere (in particular, graphics) + // so always clear full screen. + // mConsoleMaxPosX,Y coordinates are the top left coordinates of the of the greatest + // occupied character position. Because there is a cursor, there is always at least + // one character position occupied. + // + Width = TGT_PADD_WIDTH + (mConsoleMaxPosX + 1) * TGT_CHAR_WIDTH; + Height = TGT_PADD_HEIGHT + (mConsoleMaxPosY + 1) * TGT_CHAR_HEIGHT; + + mGraphicsOutput->Blt ( + mGraphicsOutput, + &mBackgroundColor.Pixel, + EfiBltVideoFill, + 0, + 0, + 0, + 0, + MIN (Width, mGraphicsOutput->Mode->Info->HorizontalResolution), + MIN (Height, mGraphicsOutput->Mode->Info->VerticalResolution), + 0 + ); } - // - // X coordinate points to the right most coordinate of the last printed - // character, but after this character we may also have cursor. - // Y coordinate points to the top most coordinate of the last printed row. - // - Width = TGT_PADD_WIDTH + (mConsoleMaxPosX + 1) * TGT_CHAR_WIDTH; - Height = TGT_PADD_HEIGHT + (mConsoleMaxPosY + 1) * TGT_CHAR_HEIGHT; - - mGraphicsOutput->Blt ( - mGraphicsOutput, - &mBackgroundColor.Pixel, - EfiBltVideoFill, - 0, - 0, - 0, - 0, - MIN (Width, mGraphicsOutput->Mode->Info->HorizontalResolution), - MIN (Height, mGraphicsOutput->Mode->Info->VerticalResolution), - 0 - ); - // // Handle cursor. // @@ -766,8 +791,12 @@ AsciiTextClearScreen ( FlushCursor (This->Mode->CursorVisible, mPrivateColumn, mPrivateRow); // - // We do not reset max here, as we may still scroll (e.g. in shell via page buttons). + // After clear screen, shell may scroll through old text via page up/down buttons, + // but it is okay to reset max x/y here anyway, as any old text is brought on via + // full redraw. // + mConsoleMaxPosX = 0; + mConsoleMaxPosY = 0; gBS->RestoreTPL (OldTpl); return EFI_SUCCESS; diff --git a/Library/OcConsoleLib/TextOutputSystem.c b/Library/OcConsoleLib/TextOutputSystem.c index 5e512c1f..53bb066f 100644 --- a/Library/OcConsoleLib/TextOutputSystem.c +++ b/Library/OcConsoleLib/TextOutputSystem.c @@ -350,6 +350,7 @@ OcUseSystemTextOutput ( OcConsoleControlSetMode (EfiConsoleControlScreenText); OcConsoleControlInstallProtocol (&mConsoleControlProtocol, NULL, &mConsoleMode); } else { + ASSERT (Renderer == OcConsoleRendererSystemGeneric); OcConsoleControlInstallProtocol (&mConsoleControlProtocol, &mOriginalConsoleControlProtocol, &mConsoleMode); }