TianoCore EDK2 master
Loading...
Searching...
No Matches
DisplayUpdateProgressLibGraphics.c
Go to the documentation of this file.
1
12#include <PiDxe.h>
16#include <Library/DebugLib.h>
17#include <Library/BaseLib.h>
18#include <Library/UefiLib.h>
19
21#include <Protocol/BootLogo2.h>
22
23//
24// Values in percent of of logo height.
25//
26#define LOGO_BOTTOM_PADDING 20
27#define PROGRESS_BLOCK_HEIGHT 10
28
29//
30// Graphics Output Protocol instance to display progress bar
31//
33
34//
35// Set to 100 percent so it is reset on first call.
36//
37UINTN mPreviousProgress = 100;
38
39//
40// Display coordinates for the progress bar.
41//
42UINTN mStartX = 0;
43UINTN mStartY = 0;
44
45//
46// Width and height of the progress bar.
47//
48UINTN mBlockWidth = 0;
49UINTN mBlockHeight = 0;
50
51//
52// GOP bitmap of the progress bar. Initialized on every new progress of 100%
53//
55
56//
57// GOP bitmap of the progress bar backround. Initialized once.
58//
59EFI_GRAPHICS_OUTPUT_BLT_PIXEL *mProgressBarBackground;
60
61//
62// Default mask used to detect the left, right , top, and bottom of logo. Only
63// green and blue pixels are used for logo detection.
64//
65const EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION mLogoDetectionColorMask = {
66 {
67 0xFF, // Blue
68 0xFF, // Green
69 0x00, // Red
70 0x00 // Reserved
71 }
72};
73
74//
75// Background color of progress bar. Grey.
76//
77const EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION mProgressBarBackgroundColor = {
78 {
79 0x80, // Blue
80 0x80, // Green
81 0x80, // Red
82 0x00 // Reserved
83 }
84};
85
86//
87// Default color of progress completion. White.
88//
89const EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION mProgressBarDefaultColor = {
90 {
91 0xFF, // Blue
92 0xFF, // Green
93 0xFF, // Red
94 0x00 // Reserved
95 }
96};
97
98//
99// Set to TRUE if a valid Graphics Output Protocol is found and the progress
100// bar fits under the boot logo using the current graphics mode.
101//
102BOOLEAN mGraphicsGood = FALSE;
103
111VOID
113 VOID
114 )
115{
116 EFI_STATUS Status;
117 INTN LogoX;
118 INTN LogoStartX;
119 INTN LogoEndX;
120 INTN LogoY;
121 INTN LogoStartY;
122 INTN LogoEndY;
123 UINTN OffsetX; // Logo screen coordinate
124 UINTN OffsetY; // Logo screen coordinate
125 UINTN Width; // Width of logo in pixels
126 UINTN Height; // Height of logo in pixels
130
131 Logo = NULL;
132 BootLogo = NULL;
133
134 //
135 // Return if a Graphics Output Protocol ha snot been found.
136 //
137 if (mGop == NULL) {
138 DEBUG ((DEBUG_ERROR, "No GOP found. No progress bar support. \n"));
139 return;
140 }
141
142 //
143 // Get boot logo protocol so we know where on the screen to grab
144 //
145 Status = gBS->LocateProtocol (
146 &gEdkiiBootLogo2ProtocolGuid,
147 NULL,
148 (VOID **)&BootLogo
149 );
150 if ((BootLogo == NULL) || (EFI_ERROR (Status))) {
151 DEBUG ((DEBUG_ERROR, "Failed to locate gEdkiiBootLogo2ProtocolGuid Status = %r. No Progress bar support. \n", Status));
152 return;
153 }
154
155 //
156 // Get logo location and size
157 //
158 Status = BootLogo->GetBootLogo (
159 BootLogo,
160 &Logo,
161 &OffsetX,
162 &OffsetY,
163 &Width,
164 &Height
165 );
166 if (EFI_ERROR (Status)) {
167 DEBUG ((DEBUG_ERROR, "Failed to Get Boot Logo Status = %r. No Progress bar support. \n", Status));
168 return;
169 }
170
171 //
172 // Within logo buffer find where the actual logo starts/ends
173 //
174 LogoEndX = 0;
175 LogoEndY = 0;
176
177 //
178 // Find left side of logo in logo coordinates
179 //
180 for (LogoX = 0, LogoStartX = Width; LogoX < LogoStartX; LogoX++) {
181 Pixel = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION *)(Logo + LogoX);
182 for (LogoY = 0; LogoY < (INTN)Height; LogoY++) {
183 if ((Pixel->Raw & mLogoDetectionColorMask.Raw) != 0x0) {
184 LogoStartX = LogoX;
185 //
186 // For loop searches from right side back to this column.
187 //
188 LogoEndX = LogoX;
189 DEBUG ((DEBUG_INFO, "StartX found at (%d, %d) Color is: 0x%X \n", LogoX, LogoY, Pixel->Raw));
190 break;
191 }
192
193 Pixel = Pixel + Width;
194 }
195 }
196
197 //
198 // Find right side of logo
199 //
200 for (LogoX = Width - 1; LogoX >= LogoEndX; LogoX--) {
201 Pixel = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION *)(Logo + LogoX);
202 for (LogoY = 0; LogoY < (INTN)Height; LogoY++) {
203 if ((Pixel->Raw & mLogoDetectionColorMask.Raw) != 0x0) {
204 LogoEndX = LogoX;
205 DEBUG ((DEBUG_INFO, "EndX found at (%d, %d) Color is: 0x%X \n", LogoX, LogoY, Pixel->Raw));
206 break;
207 }
208
209 Pixel = Pixel + Width;
210 }
211 }
212
213 //
214 // Compute mBlockWidth
215 //
216 mBlockWidth = ((LogoEndX - LogoStartX) + 99) / 100;
217
218 //
219 // Adjust mStartX based on block width so it is centered under logo
220 //
221 mStartX = LogoStartX + OffsetX - (((mBlockWidth * 100) - (LogoEndX - LogoStartX)) / 2);
222 DEBUG ((DEBUG_INFO, "mBlockWidth set to 0x%X\n", mBlockWidth));
223 DEBUG ((DEBUG_INFO, "mStartX set to 0x%X\n", mStartX));
224
225 //
226 // Find the top of the logo
227 //
228 for (LogoY = 0, LogoStartY = Height; LogoY < LogoStartY; LogoY++) {
229 Pixel = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION *)(Logo + (Width * LogoY));
230 for (LogoX = 0; LogoX < (INTN)Width; LogoX++) {
231 // not black or red
232 if ((Pixel->Raw & mLogoDetectionColorMask.Raw) != 0x0) {
233 LogoStartY = LogoY;
234 LogoEndY = LogoY; // for next loop will search from bottom side back to this row.
235 DEBUG ((DEBUG_INFO, "StartY found at (%d, %d) Color is: 0x%X \n", LogoX, LogoY, Pixel->Raw));
236 break;
237 }
238
239 Pixel++;
240 }
241 }
242
243 //
244 // Find the bottom of the logo
245 //
246 for (LogoY = Height - 1; LogoY >= LogoEndY; LogoY--) {
247 Pixel = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION *)(Logo + (Width * LogoY));
248 for (LogoX = 0; LogoX < (INTN)Width; LogoX++) {
249 if ((Pixel->Raw & mLogoDetectionColorMask.Raw) != 0x0) {
250 LogoEndY = LogoY;
251 DEBUG ((DEBUG_INFO, "EndY found at (%d, %d) Color is: 0x%X \n", LogoX, LogoY, Pixel->Raw));
252 break;
253 }
254
255 Pixel++;
256 }
257 }
258
259 //
260 // Compute bottom padding (distance between logo bottom and progress bar)
261 //
262 mStartY = (((LogoEndY - LogoStartY) * LOGO_BOTTOM_PADDING) / 100) + LogoEndY + OffsetY;
263
264 //
265 // Compute progress bar height
266 //
267 mBlockHeight = (((LogoEndY - LogoStartY) * PROGRESS_BLOCK_HEIGHT) / 100);
268
269 DEBUG ((DEBUG_INFO, "mBlockHeight set to 0x%X\n", mBlockHeight));
270
271 //
272 // Create progress bar background (one time init).
273 //
274 mProgressBarBackground = AllocatePool (mBlockWidth * 100 * mBlockHeight * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
275 if (mProgressBarBackground == NULL) {
276 DEBUG ((DEBUG_ERROR, "Failed to allocate progress bar background\n"));
277 return;
278 }
279
280 //
281 // Fill the progress bar with the background color
282 //
283 SetMem32 (
284 mProgressBarBackground,
285 (mBlockWidth * 100 * mBlockHeight * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)),
286 mProgressBarBackgroundColor.Raw
287 );
288
289 //
290 // Allocate mBlockBitmap
291 //
292 mBlockBitmap = AllocatePool (mBlockWidth * mBlockHeight * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
293 if (mBlockBitmap == NULL) {
294 FreePool (mProgressBarBackground);
295 DEBUG ((DEBUG_ERROR, "Failed to allocate block\n"));
296 return;
297 }
298
299 //
300 // Check screen width and height and make sure it fits.
301 //
302 if ((mBlockHeight > Height) || (mBlockWidth > Width) || (mBlockHeight < 1) || (mBlockWidth < 1)) {
303 DEBUG ((DEBUG_ERROR, "DisplayUpdateProgressLib - Progress - Failed to get valid width and height.\n"));
304 DEBUG ((DEBUG_ERROR, "DisplayUpdateProgressLib - Progress - mBlockHeight: 0x%X mBlockWidth: 0x%X.\n", mBlockHeight, mBlockWidth));
305 FreePool (mProgressBarBackground);
306 FreePool (mBlockBitmap);
307 return;
308 }
309
310 mGraphicsGood = TRUE;
311}
312
336EFIAPI
338 IN UINTN Completion,
340 )
341{
342 EFI_STATUS Status;
343 UINTN PreX;
344 UINTN Index;
345
346 //
347 // Check range
348 //
349 if (Completion > 100) {
350 return EFI_INVALID_PARAMETER;
351 }
352
353 //
354 // Check to see if this Completion percentage has already been displayed
355 //
356 if (Completion == mPreviousProgress) {
357 return EFI_SUCCESS;
358 }
359
360 //
361 // Find Graphics Output Protocol if not already set. 1 time.
362 //
363 if (mGop == NULL) {
364 Status = gBS->HandleProtocol (
366 &gEfiGraphicsOutputProtocolGuid,
367 (VOID **)&mGop
368 );
369 if (EFI_ERROR (Status)) {
370 Status = gBS->LocateProtocol (&gEfiGraphicsOutputProtocolGuid, NULL, (VOID **)&mGop);
371 if (EFI_ERROR (Status)) {
372 mGop = NULL;
373 DEBUG ((DEBUG_ERROR, "Show Progress Function could not locate GOP. Status = %r\n", Status));
374 return EFI_NOT_READY;
375 }
376 }
377
378 //
379 // Run once
380 //
381 FindDim ();
382 }
383
384 //
385 // Make sure a valid start, end, and size info are available (find the Logo)
386 //
387 if (!mGraphicsGood) {
388 DEBUG ((DEBUG_INFO, "Graphics Not Good. Not doing any onscreen visual display\n"));
389 return EFI_NOT_READY;
390 }
391
392 //
393 // Do special init on first call of each progress session
394 //
395 if (mPreviousProgress == 100) {
396 //
397 // Draw progress bar background
398 //
399 mGop->Blt (
400 mGop,
401 mProgressBarBackground,
403 0,
404 0,
405 mStartX,
406 mStartY,
407 (mBlockWidth * 100),
408 mBlockHeight,
409 0
410 );
411
412 DEBUG ((
413 DEBUG_VERBOSE,
414 "Color is 0x%X\n",
415 (Color == NULL) ? mProgressBarDefaultColor.Raw : Color->Raw
416 ));
417
418 //
419 // Update block bitmap with correct color
420 //
421 SetMem32 (
422 mBlockBitmap,
423 (mBlockWidth * mBlockHeight * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)),
424 (Color == NULL) ? mProgressBarDefaultColor.Raw : Color->Raw
425 );
426
427 //
428 // Clear previous
429 //
430 mPreviousProgress = 0;
431 }
432
433 //
434 // Can not update progress bar if Completion is less than previous
435 //
436 if (Completion < mPreviousProgress) {
437 DEBUG ((DEBUG_WARN, "WARNING: Completion (%d) should not be lesss than Previous (%d)!!!\n", Completion, mPreviousProgress));
438 return EFI_INVALID_PARAMETER;
439 }
440
441 PreX = ((mPreviousProgress * mBlockWidth) + mStartX);
442 for (Index = 0; Index < (Completion - mPreviousProgress); Index++) {
443 //
444 // Show progress by coloring new area
445 //
446 mGop->Blt (
447 mGop,
448 mBlockBitmap,
450 0,
451 0,
452 PreX,
453 mStartY,
454 mBlockWidth,
455 mBlockHeight,
456 0
457 );
458 PreX += mBlockWidth;
459 }
460
461 mPreviousProgress = Completion;
462
463 return EFI_SUCCESS;
464}
UINT64 UINTN
INT64 INTN
VOID *EFIAPI SetMem32(OUT VOID *Buffer, IN UINTN Length, IN UINT32 Value)
EFI_STATUS EFIAPI DisplayUpdateProgress(IN UINTN Completion, IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL_UNION *Color OPTIONAL)
VOID FindDim(VOID)
VOID EFIAPI FreePool(IN VOID *Buffer)
#define NULL
Definition: Base.h:319
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define DEBUG(Expression)
Definition: DebugLib.h:434
@ EfiBltBufferToVideo
VOID *EFIAPI AllocatePool(IN UINTN AllocationSize)
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_SYSTEM_TABLE * gST
EFI_BOOT_SERVICES * gBS
EFI_HANDLE ConsoleOutHandle
Definition: UefiSpec.h:2059