3 * Screen handling functions
5 * Copyright (c) 2006 Christoph Pfisterer
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
15 * * Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the
20 * * Neither the name of Christoph Pfisterer nor the names of the
21 * contributors may be used to endorse or promote products derived
22 * from this software without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 #include "../refind/screen.h"
39 #include "refit_call_wrapper.h"
41 #include <efiUgaDraw.h>
42 /* #include <efiGraphicsOutput.h> */
43 #include <efiConsoleControl.h>
45 // Console defines and variables
47 static EFI_GUID ConsoleControlProtocolGuid
= EFI_CONSOLE_CONTROL_PROTOCOL_GUID
;
48 static EFI_CONSOLE_CONTROL_PROTOCOL
*ConsoleControl
= NULL
;
50 static EFI_GUID UgaDrawProtocolGuid
= EFI_UGA_DRAW_PROTOCOL_GUID
;
51 static EFI_UGA_DRAW_PROTOCOL
*UgaDraw
= NULL
;
53 static EFI_GUID GraphicsOutputProtocolGuid
= EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID
;
54 static EFI_GRAPHICS_OUTPUT_PROTOCOL
*GraphicsOutput
= NULL
;
56 static BOOLEAN egHasGraphics
= FALSE
;
57 static UINTN egScreenWidth
= 800;
58 static UINTN egScreenHeight
= 600;
64 VOID
egInitScreen(VOID
)
66 EFI_STATUS Status
= EFI_SUCCESS
;
67 UINT32 UGAWidth
, UGAHeight
, UGADepth
, UGARefreshRate
;
70 Status
= LibLocateProtocol(&ConsoleControlProtocolGuid
, (VOID
**) &ConsoleControl
);
71 if (EFI_ERROR(Status
))
72 ConsoleControl
= NULL
;
74 Status
= LibLocateProtocol(&UgaDrawProtocolGuid
, (VOID
**) &UgaDraw
);
75 if (EFI_ERROR(Status
))
78 Status
= LibLocateProtocol(&GraphicsOutputProtocolGuid
, (VOID
**) &GraphicsOutput
);
79 if (EFI_ERROR(Status
))
80 GraphicsOutput
= NULL
;
83 egHasGraphics
= FALSE
;
84 if (GraphicsOutput
!= NULL
) {
85 egScreenWidth
= GraphicsOutput
->Mode
->Info
->HorizontalResolution
;
86 egScreenHeight
= GraphicsOutput
->Mode
->Info
->VerticalResolution
;
88 } else if (UgaDraw
!= NULL
) {
89 Status
= refit_call5_wrapper(UgaDraw
->GetMode
, UgaDraw
, &UGAWidth
, &UGAHeight
, &UGADepth
, &UGARefreshRate
);
90 if (EFI_ERROR(Status
)) {
91 UgaDraw
= NULL
; // graphics not available
93 egScreenWidth
= UGAWidth
;
94 egScreenHeight
= UGAHeight
;
100 // Sets the screen resolution to the specified value, if possible.
101 // If the specified value is not valid, displays a warning with the valid
102 // modes on UEFI systems, or silently fails on EFI 1.x systems. Note that
103 // this function attempts to set ANY screen resolution, even 0x0 or
104 // ridiculously large values.
105 // Returns TRUE if successful, FALSE if not.
106 BOOLEAN
egSetScreenSize(IN UINTN ScreenWidth
, IN UINTN ScreenHeight
) {
107 EFI_STATUS Status
= EFI_SUCCESS
;
108 EFI_GRAPHICS_OUTPUT_MODE_INFORMATION
*Info
;
111 BOOLEAN ModeSet
= FALSE
;
112 UINT32 UGAWidth
, UGAHeight
, UGADepth
, UGARefreshRate
;
114 if (GraphicsOutput
!= NULL
) { // GOP mode (UEFI)
115 // Do a loop through the modes to see if the specified one is available;
116 // and if so, switch to it....
117 while ((Status
== EFI_SUCCESS
) && (!ModeSet
)) {
118 Status
= refit_call4_wrapper(GraphicsOutput
->QueryMode
, GraphicsOutput
, ModeNum
, &Size
, &Info
);
119 if ((Status
== EFI_SUCCESS
) && (Size
>= sizeof(*Info
)) &&
120 (Info
->HorizontalResolution
== ScreenWidth
) && (Info
->VerticalResolution
== ScreenHeight
)) {
121 Status
= refit_call2_wrapper(GraphicsOutput
->SetMode
, GraphicsOutput
, ModeNum
);
122 ModeSet
= (Status
== EFI_SUCCESS
);
128 egScreenWidth
= ScreenWidth
;
129 egScreenHeight
= ScreenHeight
;
130 } else {// If unsuccessful, display an error message for the user....
131 Print(L
"Error setting mode %d x %d; using default mode!\nAvailable modes are:\n", ScreenWidth
, ScreenHeight
);
133 Status
= EFI_SUCCESS
;
134 while (Status
== EFI_SUCCESS
) {
135 Status
= refit_call4_wrapper(GraphicsOutput
->QueryMode
, GraphicsOutput
, ModeNum
, &Size
, &Info
);
136 if ((Status
== EFI_SUCCESS
) && (Size
>= sizeof(*Info
))) {
137 Print(L
"Mode %d: %d x %d\n", ModeNum
, Info
->HorizontalResolution
, Info
->VerticalResolution
);
143 } else if (UgaDraw
!= NULL
) { // UGA mode (EFI 1.x)
144 // Try to use current color depth & refresh rate for new mode. Maybe not the best choice
145 // in all cases, but I don't know how to probe for alternatives....
146 Status
= refit_call5_wrapper(UgaDraw
->GetMode
, UgaDraw
, &UGAWidth
, &UGAHeight
, &UGADepth
, &UGARefreshRate
);
147 Status
= refit_call5_wrapper(UgaDraw
->SetMode
, UgaDraw
, ScreenWidth
, ScreenHeight
, UGADepth
, UGARefreshRate
);
148 if (Status
== EFI_SUCCESS
) {
149 egScreenWidth
= ScreenWidth
;
150 egScreenHeight
= ScreenHeight
;
153 // TODO: Find a list of supported modes and display it.
154 // NOTE: Below doesn't actually appear unless we explicitly switch to text mode.
155 // This is just a placeholder until something better can be done....
156 Print(L
"Error setting mode %d x %d; unsupported mode!\n");
160 } // BOOLEAN egSetScreenSize()
162 VOID
egGetScreenSize(OUT UINTN
*ScreenWidth
, OUT UINTN
*ScreenHeight
)
164 if (ScreenWidth
!= NULL
)
165 *ScreenWidth
= egScreenWidth
;
166 if (ScreenHeight
!= NULL
)
167 *ScreenHeight
= egScreenHeight
;
170 CHAR16
* egScreenDescription(VOID
)
173 if (GraphicsOutput
!= NULL
) {
174 return PoolPrint(L
"Graphics Output (UEFI), %dx%d",
175 egScreenWidth
, egScreenHeight
);
176 } else if (UgaDraw
!= NULL
) {
177 return PoolPrint(L
"UGA Draw (EFI 1.10), %dx%d",
178 egScreenWidth
, egScreenHeight
);
180 return L
"Internal Error";
183 return L
"Text Console";
187 BOOLEAN
egHasGraphicsMode(VOID
)
189 return egHasGraphics
;
192 BOOLEAN
egIsGraphicsModeEnabled(VOID
)
194 EFI_CONSOLE_CONTROL_SCREEN_MODE CurrentMode
;
196 if (ConsoleControl
!= NULL
) {
197 refit_call4_wrapper(ConsoleControl
->GetMode
, ConsoleControl
, &CurrentMode
, NULL
, NULL
);
198 return (CurrentMode
== EfiConsoleControlScreenGraphics
) ? TRUE
: FALSE
;
204 VOID
egSetGraphicsModeEnabled(IN BOOLEAN Enable
)
206 EFI_CONSOLE_CONTROL_SCREEN_MODE CurrentMode
;
207 EFI_CONSOLE_CONTROL_SCREEN_MODE NewMode
;
209 if (ConsoleControl
!= NULL
) {
210 refit_call4_wrapper(ConsoleControl
->GetMode
, ConsoleControl
, &CurrentMode
, NULL
, NULL
);
212 NewMode
= Enable
? EfiConsoleControlScreenGraphics
213 : EfiConsoleControlScreenText
;
214 if (CurrentMode
!= NewMode
)
215 refit_call2_wrapper(ConsoleControl
->SetMode
, ConsoleControl
, NewMode
);
220 // Drawing to the screen
223 VOID
egClearScreen(IN EG_PIXEL
*Color
)
225 EFI_UGA_PIXEL FillColor
;
230 FillColor
.Red
= Color
->r
;
231 FillColor
.Green
= Color
->g
;
232 FillColor
.Blue
= Color
->b
;
233 FillColor
.Reserved
= 0;
235 if (GraphicsOutput
!= NULL
) {
236 // EFI_GRAPHICS_OUTPUT_BLT_PIXEL and EFI_UGA_PIXEL have the same
237 // layout, and the header from TianoCore actually defines them
238 // to be the same type.
239 refit_call10_wrapper(GraphicsOutput
->Blt
, GraphicsOutput
, (EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*)&FillColor
, EfiBltVideoFill
,
240 0, 0, 0, 0, egScreenWidth
, egScreenHeight
, 0);
241 } else if (UgaDraw
!= NULL
) {
242 refit_call10_wrapper(UgaDraw
->Blt
, UgaDraw
, &FillColor
, EfiUgaVideoFill
,
243 0, 0, 0, 0, egScreenWidth
, egScreenHeight
, 0);
247 VOID
egDrawImage(IN EG_IMAGE
*Image
, IN UINTN ScreenPosX
, IN UINTN ScreenPosY
)
252 if (Image
->HasAlpha
) {
253 Image
->HasAlpha
= FALSE
;
254 egSetPlane(PLPTR(Image
, a
), 0, Image
->Width
* Image
->Height
);
257 if (GraphicsOutput
!= NULL
) {
258 refit_call10_wrapper(GraphicsOutput
->Blt
, GraphicsOutput
, (EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*)Image
->PixelData
, EfiBltBufferToVideo
,
259 0, 0, ScreenPosX
, ScreenPosY
, Image
->Width
, Image
->Height
, 0);
260 } else if (UgaDraw
!= NULL
) {
261 refit_call10_wrapper(UgaDraw
->Blt
, UgaDraw
, (EFI_UGA_PIXEL
*)Image
->PixelData
, EfiUgaBltBufferToVideo
,
262 0, 0, ScreenPosX
, ScreenPosY
, Image
->Width
, Image
->Height
, 0);
266 VOID
egDrawImageArea(IN EG_IMAGE
*Image
,
267 IN UINTN AreaPosX
, IN UINTN AreaPosY
,
268 IN UINTN AreaWidth
, IN UINTN AreaHeight
,
269 IN UINTN ScreenPosX
, IN UINTN ScreenPosY
)
274 egRestrictImageArea(Image
, AreaPosX
, AreaPosY
, &AreaWidth
, &AreaHeight
);
278 if (Image
->HasAlpha
) {
279 Image
->HasAlpha
= FALSE
;
280 egSetPlane(PLPTR(Image
, a
), 0, Image
->Width
* Image
->Height
);
283 if (GraphicsOutput
!= NULL
) {
284 refit_call10_wrapper(GraphicsOutput
->Blt
, GraphicsOutput
, (EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*)Image
->PixelData
, EfiBltBufferToVideo
,
285 AreaPosX
, AreaPosY
, ScreenPosX
, ScreenPosY
, AreaWidth
, AreaHeight
, Image
->Width
* 4);
286 } else if (UgaDraw
!= NULL
) {
287 refit_call10_wrapper(UgaDraw
->Blt
, UgaDraw
, (EFI_UGA_PIXEL
*)Image
->PixelData
, EfiUgaBltBufferToVideo
,
288 AreaPosX
, AreaPosY
, ScreenPosX
, ScreenPosY
, AreaWidth
, AreaHeight
, Image
->Width
* 4);
296 VOID
egScreenShot(VOID
)
301 UINTN FileDataLength
;
307 // allocate a buffer for the whole screen
308 Image
= egCreateImage(egScreenWidth
, egScreenHeight
, FALSE
);
310 Print(L
"Error egCreateImage returned NULL\n");
314 // get full screen image
315 if (GraphicsOutput
!= NULL
) {
316 refit_call10_wrapper(GraphicsOutput
->Blt
, GraphicsOutput
, (EFI_GRAPHICS_OUTPUT_BLT_PIXEL
*)Image
->PixelData
, EfiBltVideoToBltBuffer
,
317 0, 0, 0, 0, Image
->Width
, Image
->Height
, 0);
318 } else if (UgaDraw
!= NULL
) {
319 refit_call10_wrapper(UgaDraw
->Blt
, UgaDraw
, (EFI_UGA_PIXEL
*)Image
->PixelData
, EfiUgaVideoToBltBuffer
,
320 0, 0, 0, 0, Image
->Width
, Image
->Height
, 0);
324 egEncodeBMP(Image
, &FileData
, &FileDataLength
);
326 if (FileData
== NULL
) {
327 Print(L
"Error egEncodeBMP returned NULL\n");
331 // save to file on the ESP
332 Status
= egSaveFile(NULL
, L
"screenshot.bmp", FileData
, FileDataLength
);
334 if (EFI_ERROR(Status
)) {
335 Print(L
"Error egSaveFile: %x\n", Status
);
341 // DEBUG: switch to text mode
343 egSetGraphicsModeEnabled(FALSE
);
344 refit_call3_wrapper(BS
->WaitForEvent
, 1, &ST
->ConIn
->WaitForKey
, &Index
);