xref: /reactos/boot/environ/lib/io/display/guicons.c (revision 9393fc32)
1 /*
2  * COPYRIGHT:       See COPYING.ARM in the top level directory
3  * PROJECT:         ReactOS UEFI Boot Library
4  * FILE:            boot/environ/lib/io/display/guicons.c
5  * PURPOSE:         Boot Library GUI Console Routines
6  * PROGRAMMER:      Alex Ionescu (alex.ionescu@reactos.org)
7  */
8 
9 /* INCLUDES ******************************************************************/
10 
11 #include "bl.h"
12 
13 /* DATA VARIABLES ************************************************************/
14 
15 BL_GRAPHICS_CONSOLE_VTABLE ConsoleGraphicalVtbl =
16 {
17     {
18         (PCONSOLE_DESTRUCT)ConsoleGraphicalDestruct,
19         (PCONSOLE_REINITIALIZE)ConsoleGraphicalReinitialize,
20         ConsoleTextBaseGetTextState,
21         (PCONSOLE_SET_TEXT_STATE)ConsoleGraphicalSetTextState,
22         NULL, // GetTextResolution
23         NULL, // SetTextResolution
24         (PCONSOLE_CLEAR_TEXT)ConsoleGraphicalClearText
25     },
26     ConsoleGraphicalIsEnabled,
27     ConsoleGraphicalEnable,
28     NULL,
29     ConsoleGraphicalGetGraphicalResolution,
30     ConsoleGraphicalGetOriginalResolution,
31     NULL,
32 };
33 
34 /* FUNCTIONS *****************************************************************/
35 
36 NTSTATUS
ConsoleGraphicalSetTextState(_In_ PBL_GRAPHICS_CONSOLE Console,_In_ ULONG Mask,_In_ PBL_DISPLAY_STATE TextState)37 ConsoleGraphicalSetTextState (
38     _In_ PBL_GRAPHICS_CONSOLE Console,
39     _In_ ULONG Mask,
40     _In_ PBL_DISPLAY_STATE TextState
41     )
42 {
43     /* Is the text console active? */
44     if (Console->TextConsole.Active)
45     {
46         /* Let it handle that */
47         return ConsoleFirmwareTextSetState(&Console->TextConsole,
48                                            Mask,
49                                            TextState);
50     }
51 
52     /* Not yet */
53     EfiPrintf(L"FFX set not implemented\r\n");
54     return STATUS_NOT_IMPLEMENTED;
55 }
56 
57 NTSTATUS
ConsoleGraphicalConstruct(_In_ PBL_GRAPHICS_CONSOLE GraphicsConsole)58 ConsoleGraphicalConstruct (
59     _In_ PBL_GRAPHICS_CONSOLE GraphicsConsole
60     )
61 {
62     NTSTATUS Status;
63 
64     /* Create a text console */
65     Status = ConsoleTextLocalConstruct(&GraphicsConsole->TextConsole, FALSE);
66     if (!NT_SUCCESS(Status))
67     {
68         EfiPrintf(L"Text failed: %lx\r\n", Status);
69         return Status;
70     }
71 
72     /* But overwrite its callbacks with ours */
73     GraphicsConsole->TextConsole.Callbacks = &ConsoleGraphicalVtbl.Text;
74 
75     /* Try to create a GOP console */
76     Status = ConsoleEfiGraphicalOpenProtocol(GraphicsConsole, BlGopConsole);
77     if (!NT_SUCCESS(Status))
78     {
79         /* That failed, try an older EFI 1.02 UGA console */
80         EfiPrintf(L"GOP open failed!\r\n", Status);
81         Status = ConsoleEfiGraphicalOpenProtocol(GraphicsConsole, BlUgaConsole);
82         if (!NT_SUCCESS(Status))
83         {
84             /* That failed too, give up */
85             EfiPrintf(L"UGA failed!\r\n", Status);
86             ConsoleTextLocalDestruct(&GraphicsConsole->TextConsole);
87             return STATUS_UNSUCCESSFUL;
88         }
89     }
90 
91     /* Enable the console */
92     Status = ConsoleFirmwareGraphicalEnable(GraphicsConsole);
93     if (!NT_SUCCESS(Status))
94     {
95         /* Failed to enable it, undo everything */
96         EfiPrintf(L"Enable failed\r\n");
97         ConsoleFirmwareGraphicalClose(GraphicsConsole);
98         ConsoleTextLocalDestruct(&GraphicsConsole->TextConsole);
99         return STATUS_UNSUCCESSFUL;
100     }
101 
102     /* Save the graphics text color from the text mode text color */
103     GraphicsConsole->FgColor = GraphicsConsole->TextConsole.State.FgColor;
104     GraphicsConsole->BgColor = GraphicsConsole->TextConsole.State.BgColor;
105     return STATUS_SUCCESS;
106 }
107 
108 VOID
ConsolepClearBuffer(_In_ PUCHAR FrameBuffer,_In_ ULONG Width,_In_ PUCHAR FillColor,_In_ ULONG Height,_In_ ULONG ScanlineWidth,_In_ ULONG PixelDepth)109 ConsolepClearBuffer (
110     _In_ PUCHAR FrameBuffer,
111     _In_ ULONG Width,
112     _In_ PUCHAR FillColor,
113     _In_ ULONG Height,
114     _In_ ULONG ScanlineWidth,
115     _In_ ULONG PixelDepth
116     )
117 {
118     PUCHAR Scanline, Current, FrameBufferEnd, LineEnd;
119     ULONG LineBytes, WidthBytes, BytesPerPixel;
120 
121     /* Get the BPP */
122     BytesPerPixel = PixelDepth / 8;
123 
124     /* Using that, calculate the size of a scan line */
125     LineBytes = ScanlineWidth * BytesPerPixel;
126 
127     /* And the size of line we'll have to clear */
128     WidthBytes = Width * BytesPerPixel;
129 
130     /* Allocate a scanline */
131     Scanline = BlMmAllocateHeap(WidthBytes);
132     if (Scanline)
133     {
134         /* For each remaining pixel on the scanline */
135         Current = Scanline;
136         while (Width--)
137         {
138             /* Copy in the fill color */
139             RtlCopyMemory(Current, FillColor, BytesPerPixel);
140             Current += BytesPerPixel;
141         }
142 
143         /* For each scanline in the frame buffer */
144         while (Height--)
145         {
146             /* Copy our constructed scanline */
147             RtlCopyMemory(FrameBuffer, Scanline, WidthBytes);
148             FrameBuffer += LineBytes;
149         }
150     }
151     else
152     {
153         FrameBufferEnd = FrameBuffer + Height * LineBytes;
154         ScanlineWidth = BytesPerPixel * (ScanlineWidth - Width);
155         while (FrameBuffer != FrameBufferEnd)
156         {
157             if (FrameBuffer != (FrameBuffer + WidthBytes))
158             {
159                 LineEnd = FrameBuffer + WidthBytes;
160                 do
161                 {
162                     RtlCopyMemory(FrameBuffer, FillColor, BytesPerPixel);
163                     FrameBuffer += BytesPerPixel;
164                 }
165                 while (FrameBuffer != LineEnd);
166             }
167 
168             FrameBuffer += ScanlineWidth;
169         }
170     }
171 }
172 
173 NTSTATUS
ConsolepConvertColorToPixel(_In_ BL_COLOR Color,_Out_ PUCHAR Pixel)174 ConsolepConvertColorToPixel (
175     _In_ BL_COLOR Color,
176     _Out_ PUCHAR Pixel
177     )
178 {
179     NTSTATUS Status;
180 
181     /* Assume success */
182     Status = STATUS_SUCCESS;
183 
184     /* Convert the color to a pixel value */
185     switch (Color)
186     {
187     case Black:
188         Pixel[1] = 0;
189         Pixel[2] = 0;
190         Pixel[0] = 0;
191         break;
192     case Blue:
193         Pixel[1] = 0;
194         Pixel[2] = 0;
195         Pixel[0] = 0x7F;
196         break;
197     case Green:
198         Pixel[1] = 0x7F;
199         Pixel[2] = 0;
200         Pixel[0] = 0;
201         break;
202     case Cyan:
203         Pixel[1] = 0x7F;
204         Pixel[2] = 0;
205         Pixel[0] = 0x7F;
206         break;
207     case Red:
208         Pixel[1] = 0;
209         Pixel[2] = 0x7F;
210         Pixel[0] = 0x7F;
211         break;
212     case Magenta:
213         Pixel[1] = 0;
214         Pixel[2] = 0x7F;
215         Pixel[0] = 0x7F;
216         break;
217     case Brown:
218         Pixel[1] = 0x3F;
219         Pixel[2] = 0x7F;
220         Pixel[0] = 0;
221         break;
222     case LtGray:
223         Pixel[1] = 0xBFu;
224         Pixel[2] = 0xBFu;
225         *Pixel = 0xBFu;
226         break;
227     case Gray:
228         Pixel[1] = 0x7F;
229         Pixel[2] = 0x7F;
230         Pixel[0] = 0x7F;
231         break;
232     case LtBlue:
233         Pixel[1] = 0;
234         Pixel[2] = 0;
235         Pixel[0] = 0xFF;
236         break;
237     case LtGreen:
238         Pixel[1] = 0xFF;
239         Pixel[2] = 0;
240         Pixel[0] = 0;
241         break;
242     case LtCyan:
243         Pixel[1] = 0xFF;
244         Pixel[2] = 0;
245         Pixel[0] = 0xFF;
246         break;
247     case LtRed:
248         Pixel[1] = 0;
249         Pixel[2] = 0xFF;
250         Pixel[0] = 0;
251         break;
252     case LtMagenta:
253         Pixel[1] = 0;
254         Pixel[2] = 0xFF;
255         Pixel[0] = 0xFF;
256         break;
257     case Yellow:
258         Pixel[1] = 0xFF;
259         Pixel[2] = 0xFF;
260         Pixel[0] = 0;
261         break;
262     case White:
263         Pixel[1] = 0xFF;
264         Pixel[2] = 0xFF;
265         Pixel[0] = 0xFF;
266         break;
267     default:
268         Status = STATUS_INVALID_PARAMETER;
269         break;
270     }
271     return Status;
272 }
273 
274 NTSTATUS
ConsoleGraphicalClearPixels(_In_ PBL_GRAPHICS_CONSOLE Console,_In_ ULONG Color)275 ConsoleGraphicalClearPixels  (
276     _In_ PBL_GRAPHICS_CONSOLE Console,
277     _In_ ULONG Color
278     )
279 {
280     NTSTATUS Status;
281 
282     /* Check if the text console is active */
283     if (Console->TextConsole.Active)
284     {
285         /* We shouldn't be here */
286         Status = STATUS_UNSUCCESSFUL;
287     }
288     else
289     {
290         /* Clear it in graphics mode */
291         Status = ConsoleFirmwareGraphicalClear(Console, Color);
292     }
293 
294     /* All good */
295     return Status;
296 }
297 
298 NTSTATUS
ConsoleGraphicalClearText(_In_ PBL_GRAPHICS_CONSOLE Console,_In_ BOOLEAN LineOnly)299 ConsoleGraphicalClearText (
300     _In_ PBL_GRAPHICS_CONSOLE Console,
301     _In_ BOOLEAN LineOnly
302     )
303 {
304     /* Is the text console active? */
305     if (Console->TextConsole.Active)
306     {
307         /* Let firmware clear do it */
308         return ConsoleFirmwareTextClear(&Console->TextConsole, LineOnly);
309     }
310 
311     /* Are we clearing a line only? */
312     if (LineOnly)
313     {
314         return BfClearToEndOfLine(Console);
315     }
316 
317     /* Nope -- the whole screen */
318     return BfClearScreen(Console);
319 }
320 
321 BOOLEAN
ConsoleGraphicalIsEnabled(_In_ PBL_GRAPHICS_CONSOLE Console)322 ConsoleGraphicalIsEnabled  (
323     _In_ PBL_GRAPHICS_CONSOLE Console
324     )
325 {
326     /* Is the text console active? If so, the graphics console isn't */
327     return !Console->TextConsole.Active;
328 }
329 
330 VOID
ConsoleGraphicalDestruct(_In_ PBL_GRAPHICS_CONSOLE Console)331 ConsoleGraphicalDestruct (
332     _In_ PBL_GRAPHICS_CONSOLE Console
333     )
334 {
335     /* Is the text console active? */
336     if (Console->TextConsole.Active)
337     {
338         /* Disable it */
339         ConsoleFirmwareGraphicalDisable(Console);
340     }
341 
342     /* Close the firmware protocols */
343     ConsoleFirmwareGraphicalClose(Console);
344 
345     /* Destroy the console object */
346     ConsoleTextLocalDestruct(&Console->TextConsole);
347 }
348 
349 NTSTATUS
ConsoleGraphicalReinitialize(_In_ PBL_GRAPHICS_CONSOLE Console)350 ConsoleGraphicalReinitialize (
351     _In_ PBL_GRAPHICS_CONSOLE Console
352     )
353 {
354     /* Is the text console active? */
355     if (Console->TextConsole.Active)
356     {
357         /* Reinitialize it */
358         ConsoleTextLocalReinitialize(&Console->TextConsole);
359     }
360 
361     /* Disable the graphics console */
362     ConsoleFirmwareGraphicalDisable(Console);
363 
364     /* Then bring it back again */
365     return ConsoleFirmwareGraphicalEnable(Console);
366 }
367 
368 NTSTATUS
ConsoleGraphicalEnable(_In_ PBL_GRAPHICS_CONSOLE Console,_In_ BOOLEAN Enable)369 ConsoleGraphicalEnable (
370     _In_ PBL_GRAPHICS_CONSOLE Console,
371     _In_ BOOLEAN Enable
372     )
373 {
374     BOOLEAN Active;
375     NTSTATUS Status;
376 
377     /* The text mode console state should be the opposite of what we want to do */
378     Active = Console->TextConsole.Active;
379     if (Active == Enable)
380     {
381         /* Are we trying to enable graphics? */
382         if (Enable)
383         {
384             /* Enable the console */
385             Status = ConsoleFirmwareGraphicalEnable(Console);
386             if (NT_SUCCESS(Status))
387             {
388                 return Status;
389             }
390 
391             /* Is the text console active? */
392             if (Console->TextConsole.Active)
393             {
394                 /* Turn it off */
395                 ConsoleFirmwareTextClose(&Console->TextConsole);
396                 Console->TextConsole.Active = FALSE;
397             }
398 
399             /* Preserve the text colors */
400             Console->FgColor = Console->TextConsole.State.FgColor;
401             Console->BgColor = Console->TextConsole.State.BgColor;
402         }
403         else
404         {
405             /* We are turning off graphics -- is the text console active? */
406             if (Active != TRUE)
407             {
408                 /* It isn't, so let's turn it on */
409                 Status = ConsoleFirmwareTextOpen(&Console->TextConsole);
410                 if (!NT_SUCCESS(Status))
411                 {
412                     return Status;
413                 }
414 
415                 /* Remember that it's on */
416                 Console->TextConsole.Active = TRUE;
417             }
418 
419             /* Disable the graphics console */
420             ConsoleFirmwareGraphicalDisable(Console);
421         }
422     }
423 
424     /* All good */
425     return STATUS_SUCCESS;
426 }
427 
428 NTSTATUS
ConsoleGraphicalGetGraphicalResolution(_In_ PBL_GRAPHICS_CONSOLE Console,_In_ PBL_DISPLAY_MODE DisplayMode)429 ConsoleGraphicalGetGraphicalResolution (
430     _In_ PBL_GRAPHICS_CONSOLE Console,
431     _In_ PBL_DISPLAY_MODE DisplayMode
432     )
433 {
434     /* Is the text console active? */
435     if (Console->TextConsole.Active)
436     {
437         /* There's no graphics resolution then */
438         return STATUS_UNSUCCESSFUL;
439     }
440 
441     /* Return the current display mode */
442     *DisplayMode = Console->DisplayMode;
443     return STATUS_SUCCESS;
444 }
445 
446 NTSTATUS
ConsoleGraphicalGetOriginalResolution(_In_ PBL_GRAPHICS_CONSOLE Console,_In_ PBL_DISPLAY_MODE DisplayMode)447 ConsoleGraphicalGetOriginalResolution (
448     _In_ PBL_GRAPHICS_CONSOLE Console,
449     _In_ PBL_DISPLAY_MODE DisplayMode
450     )
451 {
452     /* Is the text console active? */
453     if (Console->TextConsole.Active)
454     {
455         /* There's no graphics resolution then */
456         return STATUS_UNSUCCESSFUL;
457     }
458 
459     /* Return the current display mode */
460     *DisplayMode = Console->OldDisplayMode;
461     return STATUS_SUCCESS;
462 }
463