X-Git-Url: https://code.delx.au/refind/blobdiff_plain/e22f7ac1eccb5958dd960e157d0f35606f7db26e..4c9f41e161bd197922912efbcf4cc676077d5c00:/libeg/screen.c diff --git a/libeg/screen.c b/libeg/screen.c index f3a36c4..b332704 100644 --- a/libeg/screen.c +++ b/libeg/screen.c @@ -35,12 +35,16 @@ */ #include "libegint.h" -#include "refit_call_wrapper.h" +#include "../refind/screen.h" +#include "../include/refit_call_wrapper.h" #include -/* #include */ #include +#ifndef __MAKEWITH_GNUEFI +#define LibLocateProtocol EfiLibLocateProtocol +#endif + // Console defines and variables static EFI_GUID ConsoleControlProtocolGuid = EFI_CONSOLE_CONTROL_PROTOCOL_GUID; @@ -62,22 +66,22 @@ static UINTN egScreenHeight = 600; VOID egInitScreen(VOID) { - EFI_STATUS Status; + EFI_STATUS Status = EFI_SUCCESS; UINT32 UGAWidth, UGAHeight, UGADepth, UGARefreshRate; - + // get protocols Status = LibLocateProtocol(&ConsoleControlProtocolGuid, (VOID **) &ConsoleControl); if (EFI_ERROR(Status)) ConsoleControl = NULL; - + Status = LibLocateProtocol(&UgaDrawProtocolGuid, (VOID **) &UgaDraw); if (EFI_ERROR(Status)) UgaDraw = NULL; - + Status = LibLocateProtocol(&GraphicsOutputProtocolGuid, (VOID **) &GraphicsOutput); if (EFI_ERROR(Status)) GraphicsOutput = NULL; - + // get screen size egHasGraphics = FALSE; if (GraphicsOutput != NULL) { @@ -96,6 +100,68 @@ VOID egInitScreen(VOID) } } +// Sets the screen resolution to the specified value, if possible. +// If the specified value is not valid, displays a warning with the valid +// modes on UEFI systems, or silently fails on EFI 1.x systems. Note that +// this function attempts to set ANY screen resolution, even 0x0 or +// ridiculously large values. +// Returns TRUE if successful, FALSE if not. +BOOLEAN egSetScreenSize(IN UINTN ScreenWidth, IN UINTN ScreenHeight) { + EFI_STATUS Status = EFI_SUCCESS; + EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info; + UINT32 ModeNum = 0; + UINTN Size; + BOOLEAN ModeSet = FALSE; + UINT32 UGAWidth, UGAHeight, UGADepth, UGARefreshRate; + + if (GraphicsOutput != NULL) { // GOP mode (UEFI) + // Do a loop through the modes to see if the specified one is available; + // and if so, switch to it.... + while ((Status == EFI_SUCCESS) && (!ModeSet)) { + Status = refit_call4_wrapper(GraphicsOutput->QueryMode, GraphicsOutput, ModeNum, &Size, &Info); + if ((Status == EFI_SUCCESS) && (Size >= sizeof(*Info)) && + (Info->HorizontalResolution == ScreenWidth) && (Info->VerticalResolution == ScreenHeight)) { + Status = refit_call2_wrapper(GraphicsOutput->SetMode, GraphicsOutput, ModeNum); + ModeSet = (Status == EFI_SUCCESS); + } // if + ModeNum++; + } // while() + + if (ModeSet) { + egScreenWidth = ScreenWidth; + egScreenHeight = ScreenHeight; + } else {// If unsuccessful, display an error message for the user.... + Print(L"Error setting mode %d x %d; using default mode!\nAvailable modes are:\n", ScreenWidth, ScreenHeight); + ModeNum = 0; + Status = EFI_SUCCESS; + while (Status == EFI_SUCCESS) { + Status = refit_call4_wrapper(GraphicsOutput->QueryMode, GraphicsOutput, ModeNum, &Size, &Info); + if ((Status == EFI_SUCCESS) && (Size >= sizeof(*Info))) { + Print(L"Mode %d: %d x %d\n", ModeNum, Info->HorizontalResolution, Info->VerticalResolution); + } // else + ModeNum++; + } // while() + PauseForKey(); + } // if() + } else if (UgaDraw != NULL) { // UGA mode (EFI 1.x) + // Try to use current color depth & refresh rate for new mode. Maybe not the best choice + // in all cases, but I don't know how to probe for alternatives.... + Status = refit_call5_wrapper(UgaDraw->GetMode, UgaDraw, &UGAWidth, &UGAHeight, &UGADepth, &UGARefreshRate); + Status = refit_call5_wrapper(UgaDraw->SetMode, UgaDraw, ScreenWidth, ScreenHeight, UGADepth, UGARefreshRate); + if (Status == EFI_SUCCESS) { + egScreenWidth = ScreenWidth; + egScreenHeight = ScreenHeight; + ModeSet = TRUE; + } else { + // TODO: Find a list of supported modes and display it. + // NOTE: Below doesn't actually appear unless we explicitly switch to text mode. + // This is just a placeholder until something better can be done.... + Print(L"Error setting mode %d x %d; unsupported mode!\n"); + } // if/else + } // if/else if + return (ModeSet); +} // BOOLEAN egSetScreenSize() + VOID egGetScreenSize(OUT UINTN *ScreenWidth, OUT UINTN *ScreenHeight) { if (ScreenWidth != NULL) @@ -106,13 +172,17 @@ VOID egGetScreenSize(OUT UINTN *ScreenWidth, OUT UINTN *ScreenHeight) CHAR16 * egScreenDescription(VOID) { + CHAR16 *Temp; + if (egHasGraphics) { if (GraphicsOutput != NULL) { - return PoolPrint(L"Graphics Output (UEFI), %dx%d", - egScreenWidth, egScreenHeight); + Temp = AllocateZeroPool(256 * sizeof(CHAR16)); + SPrint(Temp, 255, L"Graphics Output (UEFI), %dx%d", egScreenWidth, egScreenHeight); + return Temp; } else if (UgaDraw != NULL) { - return PoolPrint(L"UGA Draw (EFI 1.10), %dx%d", - egScreenWidth, egScreenHeight); + Temp = AllocateZeroPool(256 * sizeof(CHAR16)); + SPrint(Temp, 255, L"UGA Draw (EFI 1.10), %dx%d", egScreenWidth, egScreenHeight); + return Temp; } else { return L"Internal Error"; } @@ -129,12 +199,12 @@ BOOLEAN egHasGraphicsMode(VOID) BOOLEAN egIsGraphicsModeEnabled(VOID) { EFI_CONSOLE_CONTROL_SCREEN_MODE CurrentMode; - + if (ConsoleControl != NULL) { refit_call4_wrapper(ConsoleControl->GetMode, ConsoleControl, &CurrentMode, NULL, NULL); return (CurrentMode == EfiConsoleControlScreenGraphics) ? TRUE : FALSE; } - + return FALSE; } @@ -142,14 +212,14 @@ VOID egSetGraphicsModeEnabled(IN BOOLEAN Enable) { EFI_CONSOLE_CONTROL_SCREEN_MODE CurrentMode; EFI_CONSOLE_CONTROL_SCREEN_MODE NewMode; - + if (ConsoleControl != NULL) { refit_call4_wrapper(ConsoleControl->GetMode, ConsoleControl, &CurrentMode, NULL, NULL); - + NewMode = Enable ? EfiConsoleControlScreenGraphics : EfiConsoleControlScreenText; if (CurrentMode != NewMode) - refit_call2_wrapper(ConsoleControl->SetMode, ConsoleControl, NewMode); + refit_call2_wrapper(ConsoleControl->SetMode, ConsoleControl, NewMode); } } @@ -160,15 +230,15 @@ VOID egSetGraphicsModeEnabled(IN BOOLEAN Enable) 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 @@ -185,12 +255,12 @@ VOID egDrawImage(IN EG_IMAGE *Image, IN UINTN ScreenPosX, IN UINTN ScreenPosY) { if (!egHasGraphics) return; - + if (Image->HasAlpha) { Image->HasAlpha = FALSE; egSetPlane(PLPTR(Image, a), 0, Image->Width * Image->Height); } - + if (GraphicsOutput != NULL) { refit_call10_wrapper(GraphicsOutput->Blt, GraphicsOutput, (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)Image->PixelData, EfiBltBufferToVideo, 0, 0, ScreenPosX, ScreenPosY, Image->Width, Image->Height, 0); @@ -207,16 +277,16 @@ VOID egDrawImageArea(IN EG_IMAGE *Image, { if (!egHasGraphics) return; - + egRestrictImageArea(Image, AreaPosX, AreaPosY, &AreaWidth, &AreaHeight); if (AreaWidth == 0) return; - + if (Image->HasAlpha) { Image->HasAlpha = FALSE; egSetPlane(PLPTR(Image, a), 0, Image->Width * Image->Height); } - + if (GraphicsOutput != NULL) { refit_call10_wrapper(GraphicsOutput->Blt, GraphicsOutput, (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)Image->PixelData, EfiBltBufferToVideo, AreaPosX, AreaPosY, ScreenPosX, ScreenPosY, AreaWidth, AreaHeight, Image->Width * 4); @@ -226,6 +296,24 @@ VOID egDrawImageArea(IN EG_IMAGE *Image, } } +// Display a message in the center of the screen, surrounded by a box of the +// specified color. For the moment, uses graphics calls only. (It still works +// in text mode on GOP/UEFI systems, but not on UGA/EFI 1.x systems.) +VOID egDisplayMessage(IN CHAR16 *Text, EG_PIXEL *BGColor) { + UINTN BoxWidth, BoxHeight; + EG_IMAGE *Box; + + if ((Text != NULL) && (BGColor != NULL)) { + BoxWidth = (StrLen(Text) + 2) * FONT_CELL_WIDTH; + if (BoxWidth > egScreenWidth) + BoxWidth = egScreenWidth; + BoxHeight = 2 * FONT_CELL_HEIGHT; + Box = egCreateFilledImage(BoxWidth, BoxHeight, FALSE, BGColor); + egRenderText(Text, Box, FONT_CELL_WIDTH, FONT_CELL_HEIGHT / 2); + egDrawImage(Box, (egScreenWidth - BoxWidth) / 2, (egScreenHeight - BoxHeight) / 2); + } // if non-NULL inputs +} // VOID egDisplayMessage() + // // Make a screenshot // @@ -237,17 +325,17 @@ VOID egScreenShot(VOID) UINT8 *FileData; UINTN FileDataLength; UINTN Index; - + if (!egHasGraphics) return; - + // allocate a buffer for the whole screen Image = egCreateImage(egScreenWidth, egScreenHeight, FALSE); if (Image == NULL) { Print(L"Error egCreateImage returned NULL\n"); goto bailout_wait; } - + // get full screen image if (GraphicsOutput != NULL) { refit_call10_wrapper(GraphicsOutput->Blt, GraphicsOutput, (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)Image->PixelData, EfiBltVideoToBltBuffer, @@ -256,7 +344,7 @@ VOID egScreenShot(VOID) refit_call10_wrapper(UgaDraw->Blt, UgaDraw, (EFI_UGA_PIXEL *)Image->PixelData, EfiUgaVideoToBltBuffer, 0, 0, 0, 0, Image->Width, Image->Height, 0); } - + // encode as BMP egEncodeBMP(Image, &FileData, &FileDataLength); egFreeImage(Image); @@ -264,7 +352,7 @@ VOID egScreenShot(VOID) Print(L"Error egEncodeBMP returned NULL\n"); goto bailout_wait; } - + // save to file on the ESP Status = egSaveFile(NULL, L"screenshot.bmp", FileData, FileDataLength); FreePool(FileData); @@ -272,9 +360,9 @@ VOID egScreenShot(VOID) Print(L"Error egSaveFile: %x\n", Status); goto bailout_wait; } - + return; - + // DEBUG: switch to text mode bailout_wait: egSetGraphicsModeEnabled(FALSE);