]> code.delx.au - refind/blobdiff - libeg/screen.c
TianoCore build support; new use_graphics_for refind.conf token
[refind] / libeg / screen.c
index f3a36c49c2d8682eea58d174ee973d87eec329c3..b3327042c013ff8e25f7cc52a36e865d676ca52e 100644 (file)
  */
 
 #include "libegint.h"
-#include "refit_call_wrapper.h"
+#include "../refind/screen.h"
+#include "../include/refit_call_wrapper.h"
 
 #include <efiUgaDraw.h>
-/* #include <efiGraphicsOutput.h> */
 #include <efiConsoleControl.h>
 
+#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);