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 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 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 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 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 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 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 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