mirror of
https://github.com/CloverHackyColor/CloverBootloader.git
synced 2024-12-11 14:28:08 +01:00
823 lines
28 KiB
C++
823 lines
28 KiB
C++
/*
|
|
* libeg/screen.c
|
|
* Screen handling functions
|
|
*
|
|
* Copyright (c) 2006 Christoph Pfisterer
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are
|
|
* met:
|
|
*
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
*
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the
|
|
* distribution.
|
|
*
|
|
* * Neither the name of Christoph Pfisterer nor the names of the
|
|
* contributors may be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include "libegint.h"
|
|
|
|
#if defined(LODEPNG)
|
|
#include "lodepng.h"
|
|
#endif //LODEPNG
|
|
|
|
//#include <efiUgaDraw.h>
|
|
#include <Protocol/GraphicsOutput.h>
|
|
//#include <Protocol/efiConsoleControl.h>
|
|
|
|
// Console defines and variables
|
|
|
|
static EFI_GUID ConsoleControlProtocolGuid = EFI_CONSOLE_CONTROL_PROTOCOL_GUID;
|
|
static EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL;
|
|
|
|
static EFI_GUID UgaDrawProtocolGuid = EFI_UGA_DRAW_PROTOCOL_GUID;
|
|
static EFI_UGA_DRAW_PROTOCOL *UgaDraw = NULL;
|
|
|
|
static EFI_GUID GraphicsOutputProtocolGuid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
|
|
static EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput = NULL;
|
|
|
|
static BOOLEAN egHasGraphics = FALSE;
|
|
static UINTN egScreenWidth = 0; //1024;
|
|
static UINTN egScreenHeight = 0; //768;
|
|
|
|
static BOOLEAN IgnoreConsoleSetMode = FALSE;
|
|
static EFI_CONSOLE_CONTROL_SCREEN_MODE CurrentForcedConsoleMode = EfiConsoleControlScreenText;
|
|
static EFI_CONSOLE_CONTROL_PROTOCOL_GET_MODE ConsoleControlGetMode = NULL;
|
|
static EFI_CONSOLE_CONTROL_PROTOCOL_SET_MODE ConsoleControlSetMode = NULL;
|
|
|
|
static EFI_STATUS GopSetModeAndReconnectTextOut(IN UINT32 ModeNumber);
|
|
|
|
//
|
|
// Wrapped ConsoleControl GetMode() implementation - for blocking resolution switch when changing modes
|
|
//
|
|
EFI_STATUS EFIAPI
|
|
egConsoleControlGetMode(IN EFI_CONSOLE_CONTROL_PROTOCOL *This, OUT EFI_CONSOLE_CONTROL_SCREEN_MODE *Mode, OUT BOOLEAN *GopUgaExists, OPTIONAL OUT BOOLEAN *StdInLocked OPTIONAL) {
|
|
if (IgnoreConsoleSetMode) {
|
|
*Mode = CurrentForcedConsoleMode;
|
|
if (GopUgaExists)
|
|
*GopUgaExists = TRUE;
|
|
if (StdInLocked)
|
|
*StdInLocked = FALSE;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
return ConsoleControlGetMode(This, Mode, GopUgaExists, StdInLocked);
|
|
}
|
|
|
|
EFI_STATUS EFIAPI
|
|
egConsoleControlSetMode(IN EFI_CONSOLE_CONTROL_PROTOCOL *This, IN EFI_CONSOLE_CONTROL_SCREEN_MODE Mode) {
|
|
// Pretend that we updated our console mode but do not call SetMode itself to avoid breaking the resolution.
|
|
// Please note, that it is also relevant for proper boot.efi progress bar rendering with FileVault 2.
|
|
// See more details in refit/main.c
|
|
if (IgnoreConsoleSetMode) {
|
|
CurrentForcedConsoleMode = Mode;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
return ConsoleControlSetMode(This, Mode);
|
|
}
|
|
|
|
//
|
|
// Screen handling
|
|
//
|
|
/*
|
|
VOID egDumpGOPVideoModes(VOID)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT32 MaxMode;
|
|
UINT32 Mode;
|
|
UINTN SizeOfInfo;
|
|
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
|
|
CHAR16 *PixelFormatDesc;
|
|
|
|
if (GraphicsOutput == NULL) {
|
|
return;
|
|
}
|
|
|
|
// get dump
|
|
MaxMode = GraphicsOutput->Mode->MaxMode;
|
|
Mode = GraphicsOutput->Mode->Mode;
|
|
// MsgLog("Available graphics modes for refit.conf screen_resolution:\n");
|
|
// MsgLog("Curr. Mode = %d, Modes = %d, FB = %lx, FB size=0x%x\n",
|
|
// Mode, MaxMode, GraphicsOutput->Mode->FrameBufferBase, GraphicsOutput->Mode->FrameBufferSize);
|
|
|
|
for (Mode = 0; Mode < MaxMode; Mode++) {
|
|
Status = GraphicsOutput->QueryMode(GraphicsOutput, Mode, &SizeOfInfo, &Info);
|
|
if (Status == EFI_SUCCESS) {
|
|
|
|
switch (Info->PixelFormat) {
|
|
case PixelRedGreenBlueReserved8BitPerColor:
|
|
PixelFormatDesc = L"8bit RGB";
|
|
break;
|
|
|
|
case PixelBlueGreenRedReserved8BitPerColor:
|
|
PixelFormatDesc = L"8bit BGR";
|
|
break;
|
|
|
|
case PixelBitMask:
|
|
PixelFormatDesc = L"BITMASK";
|
|
break;
|
|
|
|
case PixelBltOnly:
|
|
PixelFormatDesc = L"NO FB";
|
|
break;
|
|
|
|
default:
|
|
PixelFormatDesc = L"invalid";
|
|
break;
|
|
}
|
|
|
|
MsgLog("- Mode %d: %dx%d PixFmt = %s, PixPerScanLine = %d\n",
|
|
Mode, Info->HorizontalResolution, Info->VerticalResolution, PixelFormatDesc, Info->PixelsPerScanLine);
|
|
} else {
|
|
MsgLog("- Mode %d: %r\n", Mode, Status);
|
|
}
|
|
}
|
|
|
|
}
|
|
*/
|
|
VOID egDumpSetConsoleVideoModes(VOID)
|
|
{
|
|
UINTN i;
|
|
UINTN Width, Height;
|
|
UINTN BestMode = 0, BestWidth = 0, BestHeight = 0;
|
|
EFI_STATUS Status;
|
|
STATIC int Once=0;
|
|
|
|
if (gST->ConOut != NULL && gST->ConOut->Mode != NULL) {
|
|
if (!Once) {
|
|
MsgLog("Console modes reported: %d, available modes:\n",gST->ConOut->Mode->MaxMode);
|
|
}
|
|
|
|
for (i=1; i <= (UINTN)gST->ConOut->Mode->MaxMode; i++) {
|
|
Status = gST->ConOut->QueryMode(gST->ConOut, i-1, &Width, &Height);
|
|
if (Status == EFI_SUCCESS) {
|
|
//MsgLog(" Mode %d: %dx%d%s\n", i, Width, Height, (i-1==(UINTN)gST->ConOut->Mode->Mode)?L" (current mode)":L"");
|
|
if (!Once) {
|
|
MsgLog(" - [%02d]: %dx%d%s\n", i, Width, Height, (i-1==(UINTN)gST->ConOut->Mode->Mode)?L" (current mode)":L"");
|
|
}
|
|
// Select highest mode (-1) or lowest mode (-2) as/if requested
|
|
if ((GlobalConfig.ConsoleMode == -1 && (BestMode == 0 || Width > BestWidth || (Width == BestWidth && Height > BestHeight))) ||
|
|
(GlobalConfig.ConsoleMode == -2 && (BestMode == 0 || Width < BestWidth || (Width == BestWidth && Height < BestHeight)))) {
|
|
BestMode = i;
|
|
BestWidth = Width;
|
|
BestHeight = Height;
|
|
}
|
|
}
|
|
}
|
|
Once++;
|
|
} else {
|
|
MsgLog("Console modes are not available.\n");
|
|
return;
|
|
}
|
|
|
|
if (GlobalConfig.ConsoleMode > 0) {
|
|
// Specific mode chosen, try to set it
|
|
BestMode = GlobalConfig.ConsoleMode;
|
|
}
|
|
|
|
if (BestMode >= 1 && BestMode <= (UINTN)gST->ConOut->Mode->MaxMode) {
|
|
// Mode is valid
|
|
if (BestMode-1 != (UINTN)gST->ConOut->Mode->Mode) {
|
|
Status = gST->ConOut->SetMode(gST->ConOut, BestMode-1);
|
|
MsgLog(" Setting mode (%d): %r\n", BestMode, Status);
|
|
} else {
|
|
MsgLog(" Selected mode (%d) is already set\n", BestMode);
|
|
}
|
|
} else if (BestMode != 0) {
|
|
MsgLog(" Selected mode (%d) is not valid\n", BestMode);
|
|
}
|
|
}
|
|
|
|
EFI_STATUS egSetMaxResolution()
|
|
{
|
|
EFI_STATUS Status = EFI_UNSUPPORTED;
|
|
UINT32 Width = 0;
|
|
UINT32 Height = 0;
|
|
UINT32 BestMode = 0;
|
|
UINT32 MaxMode;
|
|
UINT32 Mode;
|
|
UINTN SizeOfInfo = 0;
|
|
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info = NULL;
|
|
|
|
if (GraphicsOutput == NULL) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
MsgLog("SetMaxResolution: ");
|
|
MaxMode = GraphicsOutput->Mode->MaxMode;
|
|
for (Mode = 0; Mode < MaxMode; Mode++) {
|
|
Status = GraphicsOutput->QueryMode(GraphicsOutput, Mode, &SizeOfInfo, &Info);
|
|
if (Status == EFI_SUCCESS) {
|
|
if (Width > Info->HorizontalResolution) {
|
|
continue;
|
|
}
|
|
if (Height > Info->VerticalResolution) {
|
|
continue;
|
|
}
|
|
Width = Info->HorizontalResolution;
|
|
Height = Info->VerticalResolution;
|
|
BestMode = Mode;
|
|
}
|
|
}
|
|
MsgLog("found best mode %d: %dx%d\n", BestMode, Width, Height);
|
|
// check if requested mode is equal to current mode
|
|
if (BestMode == GraphicsOutput->Mode->Mode) {
|
|
MsgLog(" - already set\n");
|
|
egScreenWidth = GraphicsOutput->Mode->Info->HorizontalResolution;
|
|
egScreenHeight = GraphicsOutput->Mode->Info->VerticalResolution;
|
|
Status = EFI_SUCCESS;
|
|
} else {
|
|
//Status = GraphicsOutput->SetMode(GraphicsOutput, BestMode);
|
|
Status = GopSetModeAndReconnectTextOut(BestMode);
|
|
if (Status == EFI_SUCCESS) {
|
|
egScreenWidth = Width;
|
|
egScreenHeight = Height;
|
|
MsgLog(" - set\n");
|
|
} else {
|
|
// we can not set BestMode - search for first one that we can
|
|
MsgLog(" - %r\n", Status);
|
|
Status = egSetMode(1);
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS egSetMode(INT32 Next)
|
|
{
|
|
EFI_STATUS Status = EFI_UNSUPPORTED;
|
|
UINT32 MaxMode;
|
|
UINTN SizeOfInfo = 0;
|
|
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info = NULL;
|
|
INT32 Mode;
|
|
UINT32 Index = 0;
|
|
|
|
if (GraphicsOutput == NULL) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
MaxMode = GraphicsOutput->Mode->MaxMode;
|
|
Mode = GraphicsOutput->Mode->Mode;
|
|
while (EFI_ERROR(Status) && Index <= MaxMode) {
|
|
Mode = Mode + Next;
|
|
Mode = (Mode >= (INT32)MaxMode)?0:Mode;
|
|
Mode = (Mode < 0)?((INT32)MaxMode - 1):Mode;
|
|
Status = GraphicsOutput->QueryMode(GraphicsOutput, (UINT32)Mode, &SizeOfInfo, &Info);
|
|
MsgLog("QueryMode %d Status=%r\n", Mode, Status);
|
|
if (Status == EFI_SUCCESS) {
|
|
//Status = GraphicsOutput->SetMode(GraphicsOutput, (UINT32)Mode);
|
|
Status = GopSetModeAndReconnectTextOut((UINT32)Mode);
|
|
//MsgLog("SetMode %d Status=%r\n", Mode, Status);
|
|
egScreenWidth = GraphicsOutput->Mode->Info->HorizontalResolution;
|
|
egScreenHeight = GraphicsOutput->Mode->Info->VerticalResolution;
|
|
}
|
|
Index++;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
EFI_STATUS egSetScreenResolution(IN CHAR16 *WidthHeight)
|
|
{
|
|
EFI_STATUS Status = EFI_UNSUPPORTED;
|
|
UINT32 Width;
|
|
UINT32 Height;
|
|
CHAR16 *HeightP;
|
|
UINT32 MaxMode;
|
|
UINT32 Mode;
|
|
UINTN SizeOfInfo;
|
|
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
|
|
|
|
if (GraphicsOutput == NULL) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
if (WidthHeight == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
MsgLog("SetScreenResolution: %s", WidthHeight);
|
|
// we are expecting WidthHeight=L"1024x768"
|
|
// parse Width and Height
|
|
HeightP = WidthHeight;
|
|
while (*HeightP != L'\0' && *HeightP != L'x' && *HeightP != L'X') {
|
|
HeightP++;
|
|
}
|
|
if (*HeightP == L'\0') {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
HeightP++;
|
|
Width = (UINT32)StrDecimalToUintn(WidthHeight);
|
|
Height = (UINT32)StrDecimalToUintn(HeightP);
|
|
|
|
// check if requested mode is equal to current mode
|
|
if ((GraphicsOutput->Mode->Info->HorizontalResolution == Width) && (GraphicsOutput->Mode->Info->VerticalResolution == Height)) {
|
|
MsgLog(" - already set\n");
|
|
egScreenWidth = GraphicsOutput->Mode->Info->HorizontalResolution;
|
|
egScreenHeight = GraphicsOutput->Mode->Info->VerticalResolution;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
// iterate through modes and set it if found
|
|
MaxMode = GraphicsOutput->Mode->MaxMode;
|
|
for (Mode = 0; Mode < MaxMode; Mode++) {
|
|
Status = GraphicsOutput->QueryMode(GraphicsOutput, Mode, &SizeOfInfo, &Info);
|
|
if (Status == EFI_SUCCESS) {
|
|
if (Width == Info->HorizontalResolution && Height == Info->VerticalResolution) {
|
|
MsgLog(" - setting Mode %d\n", Mode);
|
|
//Status = GraphicsOutput->SetMode(GraphicsOutput, Mode);
|
|
Status = GopSetModeAndReconnectTextOut(Mode);
|
|
if (Status == EFI_SUCCESS) {
|
|
egScreenWidth = Width;
|
|
egScreenHeight = Height;
|
|
return EFI_SUCCESS;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
MsgLog(" - not found!\n");
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
VOID egInitScreen(IN BOOLEAN SetMaxResolution)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT32 Width, Height, Depth, RefreshRate;
|
|
CHAR16 *Resolution;
|
|
|
|
// get protocols
|
|
Status = EfiLibLocateProtocol(&ConsoleControlProtocolGuid, (VOID **) &ConsoleControl);
|
|
if (EFI_ERROR(Status))
|
|
ConsoleControl = NULL;
|
|
|
|
Status = EfiLibLocateProtocol(&UgaDrawProtocolGuid, (VOID **) &UgaDraw);
|
|
if (EFI_ERROR(Status))
|
|
UgaDraw = NULL;
|
|
|
|
Status = EfiLibLocateProtocol(&GraphicsOutputProtocolGuid, (VOID **) &GraphicsOutput);
|
|
if (EFI_ERROR(Status))
|
|
GraphicsOutput = NULL;
|
|
|
|
// Wrap GetMode and SetMode
|
|
if (ConsoleControl != NULL && (ConsoleControlGetMode == NULL || ConsoleControlSetMode == NULL)) {
|
|
ConsoleControlGetMode = ConsoleControl->GetMode;
|
|
ConsoleControlSetMode = ConsoleControl->SetMode;
|
|
ConsoleControl->GetMode = egConsoleControlGetMode;
|
|
ConsoleControl->SetMode = egConsoleControlSetMode;
|
|
}
|
|
|
|
// if it not the first run, just restore resolution
|
|
if (egScreenWidth != 0 && egScreenHeight != 0) {
|
|
Resolution = PoolPrint(L"%dx%d",egScreenWidth,egScreenHeight);
|
|
if (Resolution) {
|
|
Status = egSetScreenResolution(Resolution);
|
|
FreePool(Resolution);
|
|
if (!EFI_ERROR(Status)) {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
egDumpSetConsoleVideoModes();
|
|
|
|
// get screen size
|
|
egHasGraphics = FALSE;
|
|
if (GraphicsOutput != NULL) {
|
|
// egDumpGOPVideoModes();
|
|
if (GlobalConfig.ScreenResolution != NULL) {
|
|
if (EFI_ERROR(egSetScreenResolution(GlobalConfig.ScreenResolution))) {
|
|
if (SetMaxResolution) {
|
|
egSetMaxResolution();
|
|
}
|
|
}
|
|
} else {
|
|
if (SetMaxResolution) {
|
|
egSetMaxResolution();
|
|
}
|
|
}
|
|
egScreenWidth = GraphicsOutput->Mode->Info->HorizontalResolution;
|
|
egScreenHeight = GraphicsOutput->Mode->Info->VerticalResolution;
|
|
egHasGraphics = TRUE;
|
|
}
|
|
//is there anybody ever see UGA protocol???
|
|
else if (UgaDraw != NULL) {
|
|
//MsgLog("you are lucky guy having UGA, inform please projectosx!\n");
|
|
Status = UgaDraw->GetMode(UgaDraw, &Width, &Height, &Depth, &RefreshRate);
|
|
if (EFI_ERROR(Status)) {
|
|
UgaDraw = NULL; // graphics not available
|
|
} else {
|
|
egScreenWidth = Width;
|
|
egScreenHeight = Height;
|
|
egHasGraphics = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID egGetScreenSize(OUT INTN *ScreenWidth, OUT INTN *ScreenHeight)
|
|
{
|
|
if (ScreenWidth != NULL)
|
|
*ScreenWidth = egScreenWidth;
|
|
if (ScreenHeight != NULL)
|
|
*ScreenHeight = egScreenHeight;
|
|
}
|
|
|
|
CONST CHAR16 * egScreenDescription(VOID)
|
|
{
|
|
if (egHasGraphics) {
|
|
if (GraphicsOutput != NULL) {
|
|
return PoolPrint(L"Graphics Output (UEFI), %dx%d",
|
|
egScreenWidth, egScreenHeight);
|
|
} else if (UgaDraw != NULL) {
|
|
return PoolPrint(L"UGA Draw (EFI 1.10), %dx%d",
|
|
egScreenWidth, egScreenHeight);
|
|
} else {
|
|
return L"Internal Error";
|
|
}
|
|
} else {
|
|
return L"Text Console";
|
|
}
|
|
}
|
|
|
|
BOOLEAN egHasGraphicsMode(VOID)
|
|
{
|
|
return egHasGraphics;
|
|
}
|
|
|
|
BOOLEAN egIsGraphicsModeEnabled(VOID)
|
|
{
|
|
EFI_CONSOLE_CONTROL_SCREEN_MODE CurrentMode;
|
|
|
|
if (ConsoleControl != NULL) {
|
|
ConsoleControl->GetMode(ConsoleControl, &CurrentMode, NULL, NULL);
|
|
return (CurrentMode == EfiConsoleControlScreenGraphics) ? TRUE : FALSE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
VOID egSetGraphicsModeEnabled(IN BOOLEAN Enable)
|
|
{
|
|
EFI_CONSOLE_CONTROL_SCREEN_MODE CurrentMode;
|
|
EFI_CONSOLE_CONTROL_SCREEN_MODE NewMode;
|
|
|
|
if (ConsoleControl != NULL) {
|
|
// Some UEFI bioses may cause resolution switch when switching to Text Mode via the ConsoleControl->SetMode command
|
|
// EFI applications wishing to use text, call the ConsoleControl->GetMode() command, and depending on its result may call ConsoleControl->SetMode().
|
|
// To avoid the resolution switch, when we set text mode, we can make ConsoleControl->GetMode report that text mode is enabled.
|
|
|
|
// ConsoleControl->SetMode should not be needed on UEFI 2.x to switch to text, but some firmwares seem to block text out if it is not given.
|
|
// We know it blocks text out on HPQ UEFI (HP ProBook for example - reported by dmazar), Apple firmwares with UGA, and some VMs.
|
|
// So, it may be better considering to do this only with firmware vendors where the bug was observed (currently it is known to exist on some AMI firmwares).
|
|
//if (GraphicsOutput != NULL && StrCmp(gST->FirmwareVendor, L"American Megatrends") == 0) {
|
|
if (GraphicsOutput != NULL && StrCmp(gST->FirmwareVendor, L"HPQ") != 0 &&
|
|
StrCmp(gST->FirmwareVendor, L"VMware, Inc.") != 0 &&
|
|
StrCmp(gST->FirmwareVendor, L"INSYDE Corp.") != 0) {
|
|
if (!Enable) {
|
|
// Don't allow switching to text mode, but report that we are in text mode when queried
|
|
CurrentForcedConsoleMode = EfiConsoleControlScreenText;
|
|
IgnoreConsoleSetMode = TRUE;
|
|
return;
|
|
}
|
|
// Allow mode switching to work normally again
|
|
IgnoreConsoleSetMode = FALSE;
|
|
}
|
|
|
|
ConsoleControl->GetMode(ConsoleControl, &CurrentMode, NULL, NULL);
|
|
|
|
|
|
NewMode = Enable ? EfiConsoleControlScreenGraphics : EfiConsoleControlScreenText;
|
|
|
|
if (CurrentMode != NewMode) {
|
|
ConsoleControl->SetMode(ConsoleControl, NewMode);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Drawing to the screen
|
|
//
|
|
|
|
VOID egClearScreen(IN EG_PIXEL *Color)
|
|
{
|
|
EFI_UGA_PIXEL FillColor;
|
|
|
|
if (!egHasGraphics)
|
|
return;
|
|
|
|
FillColor.Red = Color->r;
|
|
FillColor.Green = Color->g;
|
|
FillColor.Blue = Color->b;
|
|
FillColor.Reserved = 0;
|
|
|
|
if (GraphicsOutput != NULL) {
|
|
// EFI_GRAPHICS_OUTPUT_BLT_PIXEL and EFI_UGA_PIXEL have the same
|
|
// layout, and the header from TianoCore actually defines them
|
|
// to be the same type.
|
|
GraphicsOutput->Blt(GraphicsOutput, (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)&FillColor, EfiBltVideoFill,
|
|
0, 0, 0, 0, egScreenWidth, egScreenHeight, 0);
|
|
} else if (UgaDraw != NULL) {
|
|
UgaDraw->Blt(UgaDraw, &FillColor, EfiUgaVideoFill,
|
|
0, 0, 0, 0, egScreenWidth, egScreenHeight, 0);
|
|
}
|
|
}
|
|
|
|
VOID egDrawImageArea(IN EG_IMAGE *Image,
|
|
IN INTN AreaPosX, IN INTN AreaPosY,
|
|
IN INTN AreaWidth, IN INTN AreaHeight,
|
|
IN INTN ScreenPosX, IN INTN ScreenPosY)
|
|
{
|
|
if (!egHasGraphics || !Image) return;
|
|
|
|
if (ScreenPosX < 0 || ScreenPosX >= UGAWidth || ScreenPosY < 0 || ScreenPosY >= UGAHeight) {
|
|
// This is outside of screen area
|
|
return;
|
|
}
|
|
|
|
if (AreaWidth == 0) {
|
|
AreaWidth = Image->Width;
|
|
}
|
|
|
|
if (AreaHeight == 0) {
|
|
AreaHeight = Image->Height;
|
|
}
|
|
|
|
if ((AreaPosX != 0) || (AreaPosY != 0)) {
|
|
egRestrictImageArea(Image, AreaPosX, AreaPosY, &AreaWidth, &AreaHeight);
|
|
if (AreaWidth == 0)
|
|
return;
|
|
}
|
|
|
|
// if (Image->HasAlpha) { // It shouldn't harm Blt
|
|
// //Image->HasAlpha = FALSE;
|
|
// egSetPlane(PLPTR(Image, a), 255, Image->Width * Image->Height);
|
|
// }
|
|
|
|
if (ScreenPosX + AreaWidth > UGAWidth)
|
|
{
|
|
AreaWidth = UGAWidth - ScreenPosX;
|
|
}
|
|
if (ScreenPosY + AreaHeight > UGAHeight)
|
|
{
|
|
AreaHeight = UGAHeight - ScreenPosY;
|
|
}
|
|
|
|
if (GraphicsOutput != NULL) {
|
|
GraphicsOutput->Blt(GraphicsOutput, (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)Image->PixelData,
|
|
EfiBltBufferToVideo,
|
|
(UINTN)AreaPosX, (UINTN)AreaPosY, (UINTN)ScreenPosX, (UINTN)ScreenPosY,
|
|
(UINTN)AreaWidth, (UINTN)AreaHeight, (UINTN)Image->Width * 4);
|
|
} else if (UgaDraw != NULL) {
|
|
UgaDraw->Blt(UgaDraw, (EFI_UGA_PIXEL *)Image->PixelData, EfiUgaBltBufferToVideo,
|
|
(UINTN)AreaPosX, (UINTN)AreaPosY, (UINTN)ScreenPosX, (UINTN)ScreenPosY,
|
|
(UINTN)AreaWidth, (UINTN)AreaHeight, (UINTN)Image->Width * 4);
|
|
}
|
|
}
|
|
// Blt(this, Buffer, mode, srcX, srcY, destX, destY, w, h, deltaSrc);
|
|
VOID egTakeImage(IN EG_IMAGE *Image, INTN ScreenPosX, INTN ScreenPosY,
|
|
IN INTN AreaWidth, IN INTN AreaHeight)
|
|
{
|
|
// if (GraphicsOutput != NULL) {
|
|
if (ScreenPosX + AreaWidth > UGAWidth)
|
|
{
|
|
AreaWidth = UGAWidth - ScreenPosX;
|
|
}
|
|
if (ScreenPosY + AreaHeight > UGAHeight)
|
|
{
|
|
AreaHeight = UGAHeight - ScreenPosY;
|
|
}
|
|
|
|
if (GraphicsOutput != NULL) {
|
|
GraphicsOutput->Blt(GraphicsOutput,
|
|
(EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)Image->PixelData,
|
|
EfiBltVideoToBltBuffer,
|
|
ScreenPosX,
|
|
ScreenPosY,
|
|
0, 0, AreaWidth, AreaHeight, (UINTN)Image->Width * 4);
|
|
} else if (UgaDraw != NULL) {
|
|
UgaDraw->Blt(UgaDraw,
|
|
(EFI_UGA_PIXEL *)Image->PixelData,
|
|
EfiUgaVideoToBltBuffer,
|
|
ScreenPosX,
|
|
ScreenPosY,
|
|
0, 0, AreaWidth, AreaHeight, (UINTN)Image->Width * 4);
|
|
}
|
|
|
|
// }
|
|
}
|
|
|
|
//
|
|
// Make a screenshot
|
|
//
|
|
CONST CHAR8 ScreenShotName[] = "EFI\\CLOVER\\misc\\screenshot";
|
|
#define USE_XIMAGE 1
|
|
#if USE_XIMAGE
|
|
EFI_STATUS egScreenShot(VOID)
|
|
{
|
|
EFI_STATUS Status = EFI_NOT_READY;
|
|
//take screen
|
|
XImage Screen(egScreenWidth, egScreenHeight);
|
|
MsgLog("Make screenshot W=%d H=%d\n", egScreenWidth, egScreenHeight);
|
|
Screen.GetArea(0, 0, egScreenWidth, egScreenHeight);
|
|
//convert to PNG
|
|
UINT8 *FileData = NULL;
|
|
UINTN FileDataLength = 0U;
|
|
Screen.ToPNG(&FileData, FileDataLength);
|
|
//save file with a first unoccupied name
|
|
XStringW CommonName(L"EFI\\CLOVER\\misc\\screenshot");
|
|
for (UINTN Index = 0; Index < 60; Index++) {
|
|
// ScreenshotName = PoolPrint(L"%a%d.png", ScreenShotName, Index);
|
|
XStringW Name = CommonName + SPrintf("%lld", Index) + L".png";
|
|
if (!FileExists(SelfRootDir, Name.data())) {
|
|
Status = egSaveFile(SelfRootDir, Name.data(), FileData, FileDataLength);
|
|
if (!EFI_ERROR(Status)) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
FreePool(FileData);
|
|
return Status;
|
|
}
|
|
#else
|
|
EFI_STATUS egScreenShot(VOID)
|
|
{
|
|
EFI_STATUS Status = EFI_NOT_READY;
|
|
EG_IMAGE *Image;
|
|
UINT8 *FileData = NULL;
|
|
UINTN FileDataLength = 0U;
|
|
// UINTN Index;
|
|
// CHAR16 ScreenshotName[128];
|
|
CHAR16 *ScreenshotName;
|
|
|
|
if (!egHasGraphics)
|
|
return EFI_NOT_READY;
|
|
MsgLog("Make screenshot W=%d H=%d\n", egScreenWidth, egScreenHeight);
|
|
// allocate a buffer for the whole screen
|
|
Image = egCreateImage(egScreenWidth, egScreenHeight, FALSE);
|
|
if (Image == NULL) {
|
|
MsgLog("Error egCreateImage returned NULL\n");
|
|
return EFI_NO_MEDIA;
|
|
}
|
|
MsgLog("take screen\n");
|
|
// get full screen image
|
|
if (GraphicsOutput != NULL) {
|
|
GraphicsOutput->Blt(GraphicsOutput, (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)Image->PixelData,
|
|
EfiBltVideoToBltBuffer,
|
|
0, 0, 0, 0, (UINTN)Image->Width, (UINTN)Image->Height, 0);
|
|
} else if (UgaDraw != NULL) {
|
|
UgaDraw->Blt(UgaDraw, (EFI_UGA_PIXEL *)Image->PixelData, EfiUgaVideoToBltBuffer,
|
|
0, 0, 0, 0, (UINTN)Image->Width, (UINTN)Image->Height, 0);
|
|
} else {
|
|
MsgLog("Error no GOP\n");
|
|
return EFI_NOT_READY;
|
|
}
|
|
// yyyyy
|
|
#if defined(LODEPNG)
|
|
{
|
|
EFI_UGA_PIXEL *ImagePNG = (EFI_UGA_PIXEL *)Image->PixelData;
|
|
UINTN ImageSize = Image->Width * Image->Height;
|
|
// UINTN i;
|
|
unsigned lode_return;
|
|
//MsgLog("convert BGR\n");
|
|
// Convert BGR to RGBA with Alpha set to 0xFF
|
|
for (UINTN i = 0; i < ImageSize; i++) {
|
|
UINT8 Temp = ImagePNG[i].Blue;
|
|
ImagePNG[i].Blue = ImagePNG[i].Red;
|
|
ImagePNG[i].Red = Temp;
|
|
ImagePNG[i].Reserved = 0xFF;
|
|
}
|
|
//MsgLog("eglodepng_encode\n");
|
|
// Encode raw RGB image to PNG format
|
|
lode_return = eglodepng_encode(&FileData, &FileDataLength, (CONST UINT8*)ImagePNG, (UINTN)Image->Width, (UINTN)Image->Height);
|
|
if (lode_return) {
|
|
MsgLog("egScreenShot(): eglodepng_encode failed on ImagePNG %p, Width %ld, Height %ld with error %u\n",
|
|
ImagePNG, Image->Width, Image->Height, lode_return);
|
|
}
|
|
}
|
|
#else //LODEPNG
|
|
// encode as BMP
|
|
egEncodeBMP(Image, &FileData, &FileDataLength);
|
|
#endif //LODEPNG
|
|
//MsgLog("egFreeImage\n");
|
|
egFreeImage(Image);
|
|
if (FileData == NULL) {
|
|
MsgLog("Error egEncode returned NULL\n");
|
|
return EFI_NO_MEDIA;
|
|
}
|
|
|
|
for (UINTN Index=0; Index < 60; Index++) {
|
|
// MsgLog("create name [%d]\n", Index);
|
|
#if defined(LODEPNG)
|
|
// UnicodeSPrint(ScreenshotName, 256, L"EFI\\CLOVER\\misc\\screenshot%d.png", Index);
|
|
ScreenshotName = PoolPrint(L"%a%d.png", ScreenShotName, Index);
|
|
#else //LODEPNG
|
|
ScreenshotName = PoolPrint(L"%a%d.bmp", ScreenShotName, Index);
|
|
// UnicodeSPrint(ScreenshotName, 256, L"EFI\\CLOVER\\misc\\screenshot%d.bmp", Index);
|
|
#endif //LODEPNG
|
|
if(!FileExists(SelfRootDir, ScreenshotName)){
|
|
Status = egSaveFile(SelfRootDir, ScreenshotName, FileData, FileDataLength);
|
|
FreePool(ScreenshotName);
|
|
ScreenshotName = NULL;
|
|
if (!EFI_ERROR(Status)) {
|
|
break;
|
|
}
|
|
} else {
|
|
FreePool(ScreenshotName);
|
|
}
|
|
}
|
|
// else save to file on the ESP
|
|
if (EFI_ERROR(Status)) {
|
|
for (UINTN Index=0; Index < 60; Index++) {
|
|
#if defined(LODEPNG)
|
|
// UnicodeSPrint(ScreenshotName, 256, L"EFI\\CLOVER\\misc\\screenshot%d.png", Index);
|
|
ScreenshotName = PoolPrint(L"%a%d.png", ScreenShotName, Index);
|
|
#else //LODEPNG
|
|
ScreenshotName = PoolPrint(L"%a%d.bmp", ScreenShotName, Index);
|
|
// UnicodeSPrint(ScreenshotName, 256, L"EFI\\CLOVER\\misc\\screenshot%d.bmp", Index);
|
|
#endif //LODEPNG
|
|
// if(!FileExists(NULL, ScreenshotName)){
|
|
Status = egSaveFile(NULL, ScreenshotName, FileData, FileDataLength);
|
|
FreePool(ScreenshotName);
|
|
if (!EFI_ERROR(Status)) {
|
|
break;
|
|
}
|
|
// }
|
|
}
|
|
CheckError(Status, L"Error egSaveFile\n");
|
|
}
|
|
#if defined(LODEPNG)
|
|
lodepng_free(FileData);
|
|
#else //LODEPNG
|
|
FreePool(FileData);
|
|
#endif //LODEPNG
|
|
|
|
return Status;
|
|
}
|
|
#endif
|
|
//
|
|
// Sets mode via GOP protocol, and reconnects simple text out drivers
|
|
//
|
|
|
|
static EFI_STATUS GopSetModeAndReconnectTextOut(IN UINT32 ModeNumber)
|
|
{
|
|
UINTN HandleCount = 0;
|
|
// UINTN Index;
|
|
EFI_HANDLE *HandleBuffer = NULL;
|
|
EFI_STATUS Status;
|
|
|
|
if (GraphicsOutput == NULL) {
|
|
return EFI_UNSUPPORTED;
|
|
}
|
|
|
|
Status = GraphicsOutput->SetMode(GraphicsOutput, ModeNumber);
|
|
MsgLog("Video mode change to mode #%d: %r\n", ModeNumber, Status);
|
|
|
|
if (gFirmwareClover && !EFI_ERROR (Status)) {
|
|
// When we change mode on GOP, we need to reconnect the drivers which produce simple text out
|
|
// Otherwise, they won't produce text based on the new resolution
|
|
Status = gBS->LocateHandleBuffer (
|
|
ByProtocol,
|
|
&gEfiSimpleTextOutProtocolGuid,
|
|
NULL,
|
|
&HandleCount,
|
|
&HandleBuffer
|
|
);
|
|
if (!EFI_ERROR (Status)) {
|
|
for (UINTN Index = 0; Index < HandleCount; Index++) {
|
|
gBS->DisconnectController (HandleBuffer[Index], NULL, NULL);
|
|
}
|
|
for (UINTN Index = 0; Index < HandleCount; Index++) {
|
|
gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
|
|
}
|
|
if (HandleBuffer != NULL) {
|
|
FreePool (HandleBuffer);
|
|
}
|
|
egDumpSetConsoleVideoModes();
|
|
}
|
|
// return value is according to whether SetMode succeeded
|
|
Status = EFI_SUCCESS;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/* EOF */
|