1 /** @file
2
3 Copyright (c) 2011, ARM Ltd. All rights reserved.<BR>
4 This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 **/
13
14 #include <PiDxe.h>
15 #include <Library/BaseMemoryLib.h>
16 #include <Library/DevicePathLib.h>
17 #include <Library/UefiBootServicesTableLib.h>
18 #include <Library/UefiRuntimeServicesTableLib.h>
19 #include <Library/MemoryAllocationLib.h>
20
21 #include <Guid/GlobalVariable.h>
22
23 #include "LcdGraphicsOutputDxe.h"
24
25 extern BOOLEAN mDisplayInitialized;
26
27 //
28 // Function Definitions
29 //
30
31 STATIC
32 EFI_STATUS
VideoCopyNoHorizontalOverlap(IN UINTN BitsPerPixel,IN volatile VOID * FrameBufferBase,IN UINT32 HorizontalResolution,IN UINTN SourceX,IN UINTN SourceY,IN UINTN DestinationX,IN UINTN DestinationY,IN UINTN Width,IN UINTN Height)33 VideoCopyNoHorizontalOverlap (
34 IN UINTN BitsPerPixel,
35 IN volatile VOID *FrameBufferBase,
36 IN UINT32 HorizontalResolution,
37 IN UINTN SourceX,
38 IN UINTN SourceY,
39 IN UINTN DestinationX,
40 IN UINTN DestinationY,
41 IN UINTN Width,
42 IN UINTN Height
43 )
44 {
45 EFI_STATUS Status = EFI_SUCCESS;
46 UINTN SourceLine;
47 UINTN DestinationLine;
48 UINTN WidthInBytes;
49 UINTN LineCount;
50 INTN Step;
51 VOID *SourceAddr;
52 VOID *DestinationAddr;
53
54 if( DestinationY <= SourceY ) {
55 // scrolling up (or horizontally but without overlap)
56 SourceLine = SourceY;
57 DestinationLine = DestinationY;
58 Step = 1;
59 } else {
60 // scrolling down
61 SourceLine = SourceY + Height;
62 DestinationLine = DestinationY + Height;
63 Step = -1;
64 }
65
66 WidthInBytes = Width * 2;
67
68 for( LineCount = 0; LineCount < Height; LineCount++ ) {
69 // Update the start addresses of source & destination using 16bit pointer arithmetic
70 SourceAddr = (VOID *)((UINT16 *)FrameBufferBase + SourceLine * HorizontalResolution + SourceX );
71 DestinationAddr = (VOID *)((UINT16 *)FrameBufferBase + DestinationLine * HorizontalResolution + DestinationX);
72
73 // Copy the entire line Y from video ram to the temp buffer
74 CopyMem( DestinationAddr, SourceAddr, WidthInBytes);
75
76 // Update the line numbers
77 SourceLine += Step;
78 DestinationLine += Step;
79 }
80
81 return Status;
82 }
83
84 STATIC
85 EFI_STATUS
VideoCopyHorizontalOverlap(IN UINTN BitsPerPixel,IN volatile VOID * FrameBufferBase,UINT32 HorizontalResolution,IN UINTN SourceX,IN UINTN SourceY,IN UINTN DestinationX,IN UINTN DestinationY,IN UINTN Width,IN UINTN Height)86 VideoCopyHorizontalOverlap (
87 IN UINTN BitsPerPixel,
88 IN volatile VOID *FrameBufferBase,
89 UINT32 HorizontalResolution,
90 IN UINTN SourceX,
91 IN UINTN SourceY,
92 IN UINTN DestinationX,
93 IN UINTN DestinationY,
94 IN UINTN Width,
95 IN UINTN Height
96 )
97 {
98 EFI_STATUS Status = EFI_SUCCESS;
99
100 UINT16 *PixelBuffer16bit;
101 UINT16 *SourcePixel16bit;
102 UINT16 *DestinationPixel16bit;
103
104 UINT32 SourcePixelY;
105 UINT32 DestinationPixelY;
106 UINTN SizeIn16Bits;
107
108 // Allocate a temporary buffer
109 PixelBuffer16bit = (UINT16 *) AllocatePool((Height * Width) * sizeof(UINT16));
110
111 if (PixelBuffer16bit == NULL) {
112 Status = EFI_OUT_OF_RESOURCES;
113 goto EXIT;
114 }
115
116 // Access each pixel inside the source area of the Video Memory and copy it to the temp buffer
117
118 SizeIn16Bits = Width * 2;
119
120 for (SourcePixelY = SourceY, DestinationPixel16bit = PixelBuffer16bit;
121 SourcePixelY < SourceY + Height;
122 SourcePixelY++, DestinationPixel16bit += Width)
123 {
124 // Calculate the source address:
125 SourcePixel16bit = (UINT16 *)FrameBufferBase + SourcePixelY * HorizontalResolution + SourceX;
126
127 // Copy the entire line Y from Video to the temp buffer
128 CopyMem( (VOID *)DestinationPixel16bit, (CONST VOID *)SourcePixel16bit, SizeIn16Bits);
129 }
130
131 // Copy from the temp buffer into the destination area of the Video Memory
132
133 for (DestinationPixelY = DestinationY, SourcePixel16bit = PixelBuffer16bit;
134 DestinationPixelY < DestinationY + Height;
135 DestinationPixelY++, SourcePixel16bit += Width)
136 {
137 // Calculate the target address:
138 DestinationPixel16bit = (UINT16 *)FrameBufferBase + (DestinationPixelY * HorizontalResolution + DestinationX);
139
140 // Copy the entire line Y from the temp buffer to Video
141 CopyMem( (VOID *)DestinationPixel16bit, (CONST VOID *)SourcePixel16bit, SizeIn16Bits);
142 }
143
144 // Free the allocated memory
145 FreePool((VOID *) PixelBuffer16bit);
146
147
148 EXIT:
149 return Status;
150 }
151
152 STATIC
153 EFI_STATUS
BltVideoFill(IN EFI_GRAPHICS_OUTPUT_PROTOCOL * This,IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL * EfiSourcePixel,OPTIONAL IN UINTN SourceX,IN UINTN SourceY,IN UINTN DestinationX,IN UINTN DestinationY,IN UINTN Width,IN UINTN Height,IN UINTN Delta OPTIONAL)154 BltVideoFill (
155 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
156 IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL *EfiSourcePixel, OPTIONAL
157 IN UINTN SourceX,
158 IN UINTN SourceY,
159 IN UINTN DestinationX,
160 IN UINTN DestinationY,
161 IN UINTN Width,
162 IN UINTN Height,
163 IN UINTN Delta OPTIONAL // Number of BYTES in a row of the BltBuffer
164 )
165 {
166 EFI_PIXEL_BITMASK* PixelInformation;
167 EFI_STATUS Status;
168 UINT32 HorizontalResolution;
169 VOID *FrameBufferBase;
170 UINT16 *DestinationPixel16bit;
171 UINT16 Pixel16bit;
172 UINT32 DestinationPixelX;
173 UINT32 DestinationLine;
174
175 Status = EFI_SUCCESS;
176 PixelInformation = &This->Mode->Info->PixelInformation;
177 FrameBufferBase = (UINTN *)((UINTN)(This->Mode->FrameBufferBase));
178 HorizontalResolution = This->Mode->Info->HorizontalResolution;
179
180 // Convert the EFI pixel at the start of the BltBuffer(0,0) into a video display pixel
181 Pixel16bit = (UINT16) (
182 ( (EfiSourcePixel->Red << 8) & PixelInformation->RedMask )
183 | ( (EfiSourcePixel->Green << 3) & PixelInformation->GreenMask )
184 | ( (EfiSourcePixel->Blue >> 3) & PixelInformation->BlueMask )
185 );
186
187 // Copy the SourcePixel into every pixel inside the target rectangle
188 for (DestinationLine = DestinationY;
189 DestinationLine < DestinationY + Height;
190 DestinationLine++)
191 {
192 for (DestinationPixelX = DestinationX;
193 DestinationPixelX < DestinationX + Width;
194 DestinationPixelX++)
195 {
196 // Calculate the target address:
197 DestinationPixel16bit = (UINT16 *)FrameBufferBase + DestinationLine * HorizontalResolution + DestinationPixelX;
198
199 // Copy the pixel into the new target
200 *DestinationPixel16bit = Pixel16bit;
201 }
202 }
203
204
205 return Status;
206 }
207
208 STATIC
209 EFI_STATUS
BltVideoToBltBuffer(IN EFI_GRAPHICS_OUTPUT_PROTOCOL * This,IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL * BltBuffer,OPTIONAL IN UINTN SourceX,IN UINTN SourceY,IN UINTN DestinationX,IN UINTN DestinationY,IN UINTN Width,IN UINTN Height,IN UINTN Delta OPTIONAL)210 BltVideoToBltBuffer (
211 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
212 IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL
213 IN UINTN SourceX,
214 IN UINTN SourceY,
215 IN UINTN DestinationX,
216 IN UINTN DestinationY,
217 IN UINTN Width,
218 IN UINTN Height,
219 IN UINTN Delta OPTIONAL // Number of BYTES in a row of the BltBuffer
220 )
221 {
222 EFI_STATUS Status;
223 UINT32 HorizontalResolution;
224 EFI_PIXEL_BITMASK *PixelInformation;
225 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *EfiDestinationPixel;
226 VOID *FrameBufferBase;
227 UINT16 *SourcePixel16bit;
228 UINT16 Pixel16bit;
229 UINT32 SourcePixelX;
230 UINT32 SourceLine;
231 UINT32 DestinationPixelX;
232 UINT32 DestinationLine;
233 UINT32 BltBufferHorizontalResolution;
234
235 Status = EFI_SUCCESS;
236 PixelInformation = &This->Mode->Info->PixelInformation;
237 HorizontalResolution = This->Mode->Info->HorizontalResolution;
238 FrameBufferBase = (UINTN *)((UINTN)(This->Mode->FrameBufferBase));
239
240 if(( Delta != 0 ) && ( Delta != Width * sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL))) {
241 // Delta is not zero and it is different from the width.
242 // Divide it by the size of a pixel to find out the buffer's horizontal resolution.
243 BltBufferHorizontalResolution = (UINT32) (Delta / sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
244 } else {
245 BltBufferHorizontalResolution = Width;
246 }
247
248 // Access each pixel inside the Video Memory
249 for (SourceLine = SourceY, DestinationLine = DestinationY;
250 SourceLine < SourceY + Height;
251 SourceLine++, DestinationLine++)
252 {
253 for (SourcePixelX = SourceX, DestinationPixelX = DestinationX;
254 SourcePixelX < SourceX + Width;
255 SourcePixelX++, DestinationPixelX++)
256 {
257 // Calculate the source and target addresses:
258 SourcePixel16bit = (UINT16 *)FrameBufferBase + SourceLine * HorizontalResolution + SourcePixelX;
259 EfiDestinationPixel = BltBuffer + DestinationLine * BltBufferHorizontalResolution + DestinationPixelX;
260
261 // Snapshot the pixel from the video buffer once, to speed up the operation.
262 // If we were dereferencing the pointer, as it is volatile, we would perform 3 memory read operations.
263 Pixel16bit = *SourcePixel16bit;
264
265 // Copy the pixel into the new target
266 EfiDestinationPixel->Red = (UINT8) ( (Pixel16bit & PixelInformation->RedMask ) >> 8 );
267 EfiDestinationPixel->Green = (UINT8) ( (Pixel16bit & PixelInformation->GreenMask ) >> 3 );
268 EfiDestinationPixel->Blue = (UINT8) ( (Pixel16bit & PixelInformation->BlueMask ) << 3 );
269 }
270 }
271
272 return Status;
273 }
274
275 STATIC
276 EFI_STATUS
BltBufferToVideo(IN EFI_GRAPHICS_OUTPUT_PROTOCOL * This,IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL * BltBuffer,OPTIONAL IN UINTN SourceX,IN UINTN SourceY,IN UINTN DestinationX,IN UINTN DestinationY,IN UINTN Width,IN UINTN Height,IN UINTN Delta OPTIONAL)277 BltBufferToVideo (
278 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
279 IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL
280 IN UINTN SourceX,
281 IN UINTN SourceY,
282 IN UINTN DestinationX,
283 IN UINTN DestinationY,
284 IN UINTN Width,
285 IN UINTN Height,
286 IN UINTN Delta OPTIONAL // Number of BYTES in a row of the BltBuffer
287 )
288 {
289 EFI_STATUS Status;
290 UINT32 HorizontalResolution;
291 EFI_PIXEL_BITMASK *PixelInformation;
292 EFI_GRAPHICS_OUTPUT_BLT_PIXEL *EfiSourcePixel;
293 VOID *FrameBufferBase;
294 UINT16 *DestinationPixel16bit;
295 UINT32 SourcePixelX;
296 UINT32 SourceLine;
297 UINT32 DestinationPixelX;
298 UINT32 DestinationLine;
299 UINT32 BltBufferHorizontalResolution;
300
301 Status = EFI_SUCCESS;
302 PixelInformation = &This->Mode->Info->PixelInformation;
303 HorizontalResolution = This->Mode->Info->HorizontalResolution;
304 FrameBufferBase = (UINTN *)((UINTN)(This->Mode->FrameBufferBase));
305
306 if(( Delta != 0 ) && ( Delta != Width * sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL))) {
307 // Delta is not zero and it is different from the width.
308 // Divide it by the size of a pixel to find out the buffer's horizontal resolution.
309 BltBufferHorizontalResolution = (UINT32) (Delta / sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
310 } else {
311 BltBufferHorizontalResolution = Width;
312 }
313
314 // Access each pixel inside the BltBuffer Memory
315 for (SourceLine = SourceY, DestinationLine = DestinationY;
316 SourceLine < SourceY + Height;
317 SourceLine++, DestinationLine++) {
318
319 for (SourcePixelX = SourceX, DestinationPixelX = DestinationX;
320 SourcePixelX < SourceX + Width;
321 SourcePixelX++, DestinationPixelX++)
322 {
323 // Calculate the source and target addresses:
324 EfiSourcePixel = BltBuffer + SourceLine * BltBufferHorizontalResolution + SourcePixelX;
325 DestinationPixel16bit = (UINT16 *)FrameBufferBase + DestinationLine * HorizontalResolution + DestinationPixelX;
326
327 // Copy the pixel into the new target
328 // Only the most significant bits will be copied across:
329 // To convert from 8 bits to 5 bits per pixel we throw away the 3 least significant bits
330 *DestinationPixel16bit = (UINT16) (
331 ( (EfiSourcePixel->Red << 8) & PixelInformation->RedMask )
332 | ( (EfiSourcePixel->Green << 3) & PixelInformation->GreenMask )
333 | ( (EfiSourcePixel->Blue >> 3) & PixelInformation->BlueMask )
334 );
335 }
336 }
337
338 return Status;
339 }
340
341 STATIC
342 EFI_STATUS
BltVideoToVideo(IN EFI_GRAPHICS_OUTPUT_PROTOCOL * This,IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL * BltBuffer,OPTIONAL IN UINTN SourceX,IN UINTN SourceY,IN UINTN DestinationX,IN UINTN DestinationY,IN UINTN Width,IN UINTN Height,IN UINTN Delta OPTIONAL)343 BltVideoToVideo (
344 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
345 IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL
346 IN UINTN SourceX,
347 IN UINTN SourceY,
348 IN UINTN DestinationX,
349 IN UINTN DestinationY,
350 IN UINTN Width,
351 IN UINTN Height,
352 IN UINTN Delta OPTIONAL // Number of BYTES in a row of the BltBuffer
353 )
354 {
355 EFI_STATUS Status;
356 UINT32 HorizontalResolution;
357 UINTN BitsPerPixel;
358 VOID *FrameBufferBase;
359
360 BitsPerPixel = 16;
361
362 HorizontalResolution = This->Mode->Info->HorizontalResolution;
363 FrameBufferBase = (UINTN *)((UINTN)(This->Mode->FrameBufferBase));
364
365 //
366 // BltVideo to BltVideo:
367 //
368 // Source is the Video Memory,
369 // Destination is the Video Memory
370
371 FrameBufferBase = (UINTN *)((UINTN)(This->Mode->FrameBufferBase));
372
373 // The UEFI spec currently states:
374 // "There is no limitation on the overlapping of the source and destination rectangles"
375 // Therefore, we must be careful to avoid overwriting the source data
376 if( SourceY == DestinationY ) {
377 // Copying within the same height, e.g. horizontal shift
378 if( SourceX == DestinationX ) {
379 // Nothing to do
380 Status = EFI_SUCCESS;
381 } else if( ((SourceX>DestinationX)?(SourceX - DestinationX):(DestinationX - SourceX)) < Width ) {
382 // There is overlap
383 Status = VideoCopyHorizontalOverlap (BitsPerPixel, FrameBufferBase, HorizontalResolution, SourceX, SourceY, DestinationX, DestinationY, Width, Height );
384 } else {
385 // No overlap
386 Status = VideoCopyNoHorizontalOverlap (BitsPerPixel, FrameBufferBase, HorizontalResolution, SourceX, SourceY, DestinationX, DestinationY, Width, Height );
387 }
388 } else {
389 // Copying from different heights
390 Status = VideoCopyNoHorizontalOverlap (BitsPerPixel, FrameBufferBase, HorizontalResolution, SourceX, SourceY, DestinationX, DestinationY, Width, Height );
391 }
392
393 return Status;
394 }
395
396 EFI_STATUS
397 EFIAPI
LcdGraphicsBlt(IN EFI_GRAPHICS_OUTPUT_PROTOCOL * This,IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL * BltBuffer,OPTIONAL IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,IN UINTN SourceX,IN UINTN SourceY,IN UINTN DestinationX,IN UINTN DestinationY,IN UINTN Width,IN UINTN Height,IN UINTN Delta OPTIONAL)398 LcdGraphicsBlt (
399 IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
400 IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL
401 IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
402 IN UINTN SourceX,
403 IN UINTN SourceY,
404 IN UINTN DestinationX,
405 IN UINTN DestinationY,
406 IN UINTN Width,
407 IN UINTN Height,
408 IN UINTN Delta OPTIONAL // Number of BYTES in a row of the BltBuffer
409 )
410 {
411 EFI_STATUS Status;
412 LCD_INSTANCE *Instance;
413
414 Instance = LCD_INSTANCE_FROM_GOP_THIS(This);
415
416 if (!mDisplayInitialized) {
417 InitializeDisplay (Instance);
418 }
419
420 switch (BltOperation) {
421 case EfiBltVideoFill:
422 Status = BltVideoFill (This, BltBuffer, SourceX, SourceY, DestinationX, DestinationY, Width, Height, Delta);
423 break;
424
425 case EfiBltVideoToBltBuffer:
426 Status = BltVideoToBltBuffer (This, BltBuffer, SourceX, SourceY, DestinationX, DestinationY, Width, Height, Delta);
427 break;
428
429 case EfiBltBufferToVideo:
430 Status = BltBufferToVideo (This, BltBuffer, SourceX, SourceY, DestinationX, DestinationY, Width, Height, Delta);
431 break;
432
433 case EfiBltVideoToVideo:
434 Status = BltVideoToVideo (This, BltBuffer, SourceX, SourceY, DestinationX, DestinationY, Width, Height, Delta);
435 break;
436
437 case EfiGraphicsOutputBltOperationMax:
438 default:
439 DEBUG((DEBUG_ERROR, "LcdGraphicsBlt: Invalid Operation\n"));
440 Status = EFI_INVALID_PARAMETER;
441 break;
442 }
443
444 return Status;
445 }
446