mirror of https://github.com/acidanthera/audk.git
888 lines
35 KiB
C
888 lines
35 KiB
C
/** @file
|
|
|
|
Copyright (c) 2011 - 2020, Arm Limited. All rights reserved.<BR>
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
|
|
**/
|
|
|
|
#include <PiDxe.h>
|
|
#include <Library/BaseMemoryLib.h>
|
|
#include <Library/DevicePathLib.h>
|
|
#include <Library/UefiBootServicesTableLib.h>
|
|
#include <Library/UefiRuntimeServicesTableLib.h>
|
|
#include <Library/MemoryAllocationLib.h>
|
|
|
|
#include <Guid/GlobalVariable.h>
|
|
|
|
#include "LcdGraphicsOutputDxe.h"
|
|
|
|
extern BOOLEAN mDisplayInitialized;
|
|
|
|
//
|
|
// Function Definitions
|
|
//
|
|
|
|
STATIC
|
|
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
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINTN SourceLine;
|
|
UINTN DestinationLine;
|
|
UINTN WidthInBytes;
|
|
UINTN LineCount;
|
|
INTN Step;
|
|
VOID *SourceAddr;
|
|
VOID *DestinationAddr;
|
|
|
|
Status = EFI_SUCCESS;
|
|
|
|
if ( DestinationY <= SourceY ) {
|
|
// scrolling up (or horizontally but without overlap)
|
|
SourceLine = SourceY;
|
|
DestinationLine = DestinationY;
|
|
Step = 1;
|
|
} else {
|
|
// scrolling down
|
|
SourceLine = SourceY + Height;
|
|
DestinationLine = DestinationY + Height;
|
|
Step = -1;
|
|
}
|
|
|
|
switch (BitsPerPixel) {
|
|
case LcdBitsPerPixel_24:
|
|
|
|
WidthInBytes = Width * 4;
|
|
|
|
for ( LineCount = 0; LineCount < Height; LineCount++ ) {
|
|
// Update the start addresses of source & destination using 32bit pointer arithmetic
|
|
SourceAddr = (VOID *)((UINT32 *)FrameBufferBase + SourceLine * HorizontalResolution + SourceX);
|
|
DestinationAddr = (VOID *)((UINT32 *)FrameBufferBase + DestinationLine * HorizontalResolution + DestinationX);
|
|
|
|
// Copy the entire line Y from video ram to the temp buffer
|
|
CopyMem (DestinationAddr, SourceAddr, WidthInBytes);
|
|
|
|
// Update the line numbers
|
|
SourceLine += Step;
|
|
DestinationLine += Step;
|
|
}
|
|
|
|
break;
|
|
|
|
case LcdBitsPerPixel_16_555:
|
|
case LcdBitsPerPixel_16_565:
|
|
case LcdBitsPerPixel_12_444:
|
|
|
|
WidthInBytes = Width * 2;
|
|
|
|
for ( LineCount = 0; LineCount < Height; LineCount++ ) {
|
|
// Update the start addresses of source & destination using 16bit pointer arithmetic
|
|
SourceAddr = (VOID *)((UINT16 *)FrameBufferBase + SourceLine * HorizontalResolution + SourceX);
|
|
DestinationAddr = (VOID *)((UINT16 *)FrameBufferBase + DestinationLine * HorizontalResolution + DestinationX);
|
|
|
|
// Copy the entire line Y from video ram to the temp buffer
|
|
CopyMem (DestinationAddr, SourceAddr, WidthInBytes);
|
|
|
|
// Update the line numbers
|
|
SourceLine += Step;
|
|
DestinationLine += Step;
|
|
}
|
|
|
|
break;
|
|
|
|
case LcdBitsPerPixel_8:
|
|
case LcdBitsPerPixel_4:
|
|
case LcdBitsPerPixel_2:
|
|
case LcdBitsPerPixel_1:
|
|
default:
|
|
// Can't handle this case
|
|
DEBUG ((DEBUG_ERROR, "ArmVeGraphics_Blt: EfiBltVideoToVideo: INVALID Number of Bits Per Pixel: %d\n", BitsPerPixel));
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto EXIT;
|
|
// break;
|
|
}
|
|
|
|
EXIT:
|
|
return Status;
|
|
}
|
|
|
|
STATIC
|
|
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
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
|
|
UINT32 *PixelBuffer32bit;
|
|
UINT32 *SourcePixel32bit;
|
|
UINT32 *DestinationPixel32bit;
|
|
|
|
UINT16 *PixelBuffer16bit;
|
|
UINT16 *SourcePixel16bit;
|
|
UINT16 *DestinationPixel16bit;
|
|
|
|
UINT32 SourcePixelY;
|
|
UINT32 DestinationPixelY;
|
|
UINTN SizeIn32Bits;
|
|
UINTN SizeIn16Bits;
|
|
|
|
Status = EFI_SUCCESS;
|
|
|
|
switch (BitsPerPixel) {
|
|
case LcdBitsPerPixel_24:
|
|
// Allocate a temporary buffer
|
|
|
|
PixelBuffer32bit = (UINT32 *)AllocatePool ((Height * Width) * sizeof (UINT32));
|
|
|
|
if (PixelBuffer32bit == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto EXIT;
|
|
}
|
|
|
|
SizeIn32Bits = Width * 4;
|
|
|
|
// Copy from the video ram (source region) to a temp buffer
|
|
for (SourcePixelY = SourceY, DestinationPixel32bit = PixelBuffer32bit;
|
|
SourcePixelY < SourceY + Height;
|
|
SourcePixelY++, DestinationPixel32bit += Width)
|
|
{
|
|
// Update the start address of line Y (source)
|
|
SourcePixel32bit = (UINT32 *)FrameBufferBase + SourcePixelY * HorizontalResolution + SourceX;
|
|
|
|
// Copy the entire line Y from video ram to the temp buffer
|
|
CopyMem ((VOID *)DestinationPixel32bit, (CONST VOID *)SourcePixel32bit, SizeIn32Bits);
|
|
}
|
|
|
|
// Copy from the temp buffer to the video ram (destination region)
|
|
for (DestinationPixelY = DestinationY, SourcePixel32bit = PixelBuffer32bit;
|
|
DestinationPixelY < DestinationY + Height;
|
|
DestinationPixelY++, SourcePixel32bit += Width)
|
|
{
|
|
// Update the start address of line Y (target)
|
|
DestinationPixel32bit = (UINT32 *)FrameBufferBase + DestinationPixelY * HorizontalResolution + DestinationX;
|
|
|
|
// Copy the entire line Y from the temp buffer to video ram
|
|
CopyMem ((VOID *)DestinationPixel32bit, (CONST VOID *)SourcePixel32bit, SizeIn32Bits);
|
|
}
|
|
|
|
// Free up the allocated memory
|
|
FreePool ((VOID *)PixelBuffer32bit);
|
|
|
|
break;
|
|
|
|
case LcdBitsPerPixel_16_555:
|
|
case LcdBitsPerPixel_16_565:
|
|
case LcdBitsPerPixel_12_444:
|
|
// Allocate a temporary buffer
|
|
PixelBuffer16bit = (UINT16 *)AllocatePool ((Height * Width) * sizeof (UINT16));
|
|
|
|
if (PixelBuffer16bit == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto EXIT;
|
|
}
|
|
|
|
// Access each pixel inside the source area of the Video Memory and copy it to the temp buffer
|
|
|
|
SizeIn16Bits = Width * 2;
|
|
|
|
for (SourcePixelY = SourceY, DestinationPixel16bit = PixelBuffer16bit;
|
|
SourcePixelY < SourceY + Height;
|
|
SourcePixelY++, DestinationPixel16bit += Width)
|
|
{
|
|
// Calculate the source address:
|
|
SourcePixel16bit = (UINT16 *)FrameBufferBase + SourcePixelY * HorizontalResolution + SourceX;
|
|
|
|
// Copy the entire line Y from Video to the temp buffer
|
|
CopyMem ((VOID *)DestinationPixel16bit, (CONST VOID *)SourcePixel16bit, SizeIn16Bits);
|
|
}
|
|
|
|
// Copy from the temp buffer into the destination area of the Video Memory
|
|
|
|
for (DestinationPixelY = DestinationY, SourcePixel16bit = PixelBuffer16bit;
|
|
DestinationPixelY < DestinationY + Height;
|
|
DestinationPixelY++, SourcePixel16bit += Width)
|
|
{
|
|
// Calculate the target address:
|
|
DestinationPixel16bit = (UINT16 *)FrameBufferBase + (DestinationPixelY * HorizontalResolution + DestinationX);
|
|
|
|
// Copy the entire line Y from the temp buffer to Video
|
|
CopyMem ((VOID *)DestinationPixel16bit, (CONST VOID *)SourcePixel16bit, SizeIn16Bits);
|
|
}
|
|
|
|
// Free the allocated memory
|
|
FreePool ((VOID *)PixelBuffer16bit);
|
|
|
|
break;
|
|
|
|
case LcdBitsPerPixel_8:
|
|
case LcdBitsPerPixel_4:
|
|
case LcdBitsPerPixel_2:
|
|
case LcdBitsPerPixel_1:
|
|
default:
|
|
// Can't handle this case
|
|
DEBUG ((DEBUG_ERROR, "ArmVeGraphics_Blt: EfiBltVideoToVideo: INVALID Number of Bits Per Pixel: %d\n", BitsPerPixel));
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto EXIT;
|
|
// break;
|
|
}
|
|
|
|
EXIT:
|
|
return Status;
|
|
}
|
|
|
|
STATIC
|
|
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 // Number of BYTES in a row of the BltBuffer
|
|
)
|
|
{
|
|
EFI_PIXEL_BITMASK *PixelInformation;
|
|
EFI_STATUS Status;
|
|
UINT32 HorizontalResolution;
|
|
LCD_BPP BitsPerPixel;
|
|
VOID *FrameBufferBase;
|
|
VOID *DestinationAddr;
|
|
UINT16 *DestinationPixel16bit;
|
|
UINT16 Pixel16bit;
|
|
UINT32 DestinationPixelX;
|
|
UINT32 DestinationLine;
|
|
UINTN WidthInBytes;
|
|
|
|
Status = EFI_SUCCESS;
|
|
PixelInformation = &This->Mode->Info->PixelInformation;
|
|
FrameBufferBase = (UINTN *)((UINTN)(This->Mode->FrameBufferBase));
|
|
HorizontalResolution = This->Mode->Info->HorizontalResolution;
|
|
|
|
LcdPlatformGetBpp (This->Mode->Mode, &BitsPerPixel);
|
|
|
|
switch (BitsPerPixel) {
|
|
case LcdBitsPerPixel_24:
|
|
WidthInBytes = Width * 4;
|
|
|
|
// Copy the SourcePixel into every pixel inside the target rectangle
|
|
for (DestinationLine = DestinationY;
|
|
DestinationLine < DestinationY + Height;
|
|
DestinationLine++)
|
|
{
|
|
// Calculate the target address using 32bit pointer arithmetic:
|
|
DestinationAddr = (VOID *)((UINT32 *)FrameBufferBase + DestinationLine * HorizontalResolution + DestinationX);
|
|
|
|
// Fill the entire line
|
|
SetMem32 (DestinationAddr, WidthInBytes, *((UINT32 *)EfiSourcePixel));
|
|
}
|
|
|
|
break;
|
|
|
|
case LcdBitsPerPixel_16_555:
|
|
// Convert the EFI pixel at the start of the BltBuffer(0,0) into a video display pixel
|
|
Pixel16bit = (UINT16)(
|
|
((EfiSourcePixel->Red << 7) & PixelInformation->RedMask)
|
|
| ((EfiSourcePixel->Green << 2) & PixelInformation->GreenMask)
|
|
| ((EfiSourcePixel->Blue >> 3) & PixelInformation->BlueMask)
|
|
// | ( 0 & PixelInformation->ReservedMask )
|
|
);
|
|
|
|
// Copy the SourcePixel into every pixel inside the target rectangle
|
|
for (DestinationLine = DestinationY;
|
|
DestinationLine < DestinationY + Height;
|
|
DestinationLine++)
|
|
{
|
|
for (DestinationPixelX = DestinationX;
|
|
DestinationPixelX < DestinationX + Width;
|
|
DestinationPixelX++)
|
|
{
|
|
// Calculate the target address:
|
|
DestinationPixel16bit = (UINT16 *)FrameBufferBase + DestinationLine * HorizontalResolution + DestinationPixelX;
|
|
|
|
// Copy the pixel into the new target
|
|
*DestinationPixel16bit = Pixel16bit;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case LcdBitsPerPixel_16_565:
|
|
// Convert the EFI pixel at the start of the BltBuffer(0,0) into a video display pixel
|
|
Pixel16bit = (UINT16)(
|
|
((EfiSourcePixel->Red << 8) & PixelInformation->RedMask)
|
|
| ((EfiSourcePixel->Green << 3) & PixelInformation->GreenMask)
|
|
| ((EfiSourcePixel->Blue >> 3) & PixelInformation->BlueMask)
|
|
);
|
|
|
|
// Copy the SourcePixel into every pixel inside the target rectangle
|
|
for (DestinationLine = DestinationY;
|
|
DestinationLine < DestinationY + Height;
|
|
DestinationLine++)
|
|
{
|
|
for (DestinationPixelX = DestinationX;
|
|
DestinationPixelX < DestinationX + Width;
|
|
DestinationPixelX++)
|
|
{
|
|
// Calculate the target address:
|
|
DestinationPixel16bit = (UINT16 *)FrameBufferBase + DestinationLine * HorizontalResolution + DestinationPixelX;
|
|
|
|
// Copy the pixel into the new target
|
|
*DestinationPixel16bit = Pixel16bit;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case LcdBitsPerPixel_12_444:
|
|
// Convert the EFI pixel at the start of the BltBuffer(0,0) into a video display pixel
|
|
Pixel16bit = (UINT16)(
|
|
((EfiSourcePixel->Red >> 4) & PixelInformation->RedMask)
|
|
| ((EfiSourcePixel->Green) & PixelInformation->GreenMask)
|
|
| ((EfiSourcePixel->Blue << 4) & PixelInformation->BlueMask)
|
|
);
|
|
|
|
// Copy the SourcePixel into every pixel inside the target rectangle
|
|
for (DestinationLine = DestinationY;
|
|
DestinationLine < DestinationY + Height;
|
|
DestinationLine++)
|
|
{
|
|
for (DestinationPixelX = DestinationX;
|
|
DestinationPixelX < DestinationX + Width;
|
|
DestinationPixelX++)
|
|
{
|
|
// Calculate the target address:
|
|
DestinationPixel16bit = (UINT16 *)FrameBufferBase + DestinationLine * HorizontalResolution + DestinationPixelX;
|
|
|
|
// Copy the pixel into the new target
|
|
*DestinationPixel16bit = Pixel16bit;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case LcdBitsPerPixel_8:
|
|
case LcdBitsPerPixel_4:
|
|
case LcdBitsPerPixel_2:
|
|
case LcdBitsPerPixel_1:
|
|
default:
|
|
// Can't handle this case
|
|
DEBUG ((DEBUG_ERROR, "LcdGraphicsBlt: EfiBltVideoFill: INVALID Number of Bits Per Pixel: %d\n", BitsPerPixel));
|
|
Status = EFI_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
STATIC
|
|
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 // Number of BYTES in a row of the BltBuffer
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT32 HorizontalResolution;
|
|
LCD_BPP BitsPerPixel;
|
|
EFI_PIXEL_BITMASK *PixelInformation;
|
|
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *EfiDestinationPixel;
|
|
VOID *FrameBufferBase;
|
|
VOID *SourceAddr;
|
|
VOID *DestinationAddr;
|
|
UINT16 *SourcePixel16bit;
|
|
UINT16 Pixel16bit;
|
|
UINT32 SourcePixelX;
|
|
UINT32 SourceLine;
|
|
UINT32 DestinationPixelX;
|
|
UINT32 DestinationLine;
|
|
UINT32 BltBufferHorizontalResolution;
|
|
UINTN WidthInBytes;
|
|
|
|
Status = EFI_SUCCESS;
|
|
PixelInformation = &This->Mode->Info->PixelInformation;
|
|
HorizontalResolution = This->Mode->Info->HorizontalResolution;
|
|
FrameBufferBase = (UINTN *)((UINTN)(This->Mode->FrameBufferBase));
|
|
|
|
if ((Delta != 0) && (Delta != Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL))) {
|
|
// Delta is not zero and it is different from the width.
|
|
// Divide it by the size of a pixel to find out the buffer's horizontal resolution.
|
|
BltBufferHorizontalResolution = (UINT32)(Delta / sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
|
|
} else {
|
|
BltBufferHorizontalResolution = Width;
|
|
}
|
|
|
|
LcdPlatformGetBpp (This->Mode->Mode, &BitsPerPixel);
|
|
|
|
switch (BitsPerPixel) {
|
|
case LcdBitsPerPixel_24:
|
|
WidthInBytes = Width * 4;
|
|
|
|
// Access each line inside the Video Memory
|
|
for (SourceLine = SourceY, DestinationLine = DestinationY;
|
|
SourceLine < SourceY + Height;
|
|
SourceLine++, DestinationLine++)
|
|
{
|
|
// Calculate the source and target addresses using 32bit pointer arithmetic:
|
|
SourceAddr = (VOID *)((UINT32 *)FrameBufferBase + SourceLine * HorizontalResolution + SourceX);
|
|
DestinationAddr = (VOID *)((UINT32 *)BltBuffer + DestinationLine * BltBufferHorizontalResolution + DestinationX);
|
|
|
|
// Copy the entire line
|
|
CopyMem (DestinationAddr, SourceAddr, WidthInBytes);
|
|
}
|
|
|
|
break;
|
|
|
|
case LcdBitsPerPixel_16_555:
|
|
// Access each pixel inside the Video Memory
|
|
for (SourceLine = SourceY, DestinationLine = DestinationY;
|
|
SourceLine < SourceY + Height;
|
|
SourceLine++, DestinationLine++)
|
|
{
|
|
for (SourcePixelX = SourceX, DestinationPixelX = DestinationX;
|
|
SourcePixelX < SourceX + Width;
|
|
SourcePixelX++, DestinationPixelX++)
|
|
{
|
|
// Calculate the source and target addresses:
|
|
SourcePixel16bit = (UINT16 *)FrameBufferBase + SourceLine * HorizontalResolution + SourcePixelX;
|
|
EfiDestinationPixel = BltBuffer + DestinationLine * BltBufferHorizontalResolution + DestinationPixelX;
|
|
|
|
// Snapshot the pixel from the video buffer once, to speed up the operation.
|
|
// If we were dereferencing the pointer, as it is volatile, we would perform 3 memory read operations.
|
|
Pixel16bit = *SourcePixel16bit;
|
|
|
|
// Copy the pixel into the new target
|
|
EfiDestinationPixel->Red = (UINT8)((Pixel16bit & PixelInformation->RedMask) >> 7);
|
|
EfiDestinationPixel->Green = (UINT8)((Pixel16bit & PixelInformation->GreenMask) >> 2);
|
|
EfiDestinationPixel->Blue = (UINT8)((Pixel16bit & PixelInformation->BlueMask) << 3);
|
|
// EfiDestinationPixel->Reserved = (UINT8) 0;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case LcdBitsPerPixel_16_565:
|
|
// Access each pixel inside the Video Memory
|
|
for (SourceLine = SourceY, DestinationLine = DestinationY;
|
|
SourceLine < SourceY + Height;
|
|
SourceLine++, DestinationLine++)
|
|
{
|
|
for (SourcePixelX = SourceX, DestinationPixelX = DestinationX;
|
|
SourcePixelX < SourceX + Width;
|
|
SourcePixelX++, DestinationPixelX++)
|
|
{
|
|
// Calculate the source and target addresses:
|
|
SourcePixel16bit = (UINT16 *)FrameBufferBase + SourceLine * HorizontalResolution + SourcePixelX;
|
|
EfiDestinationPixel = BltBuffer + DestinationLine * BltBufferHorizontalResolution + DestinationPixelX;
|
|
|
|
// Snapshot the pixel from the video buffer once, to speed up the operation.
|
|
// If we were dereferencing the pointer, as it is volatile, we would perform 3 memory read operations.
|
|
Pixel16bit = *SourcePixel16bit;
|
|
|
|
// Copy the pixel into the new target
|
|
// There is no info for the Reserved byte, so we set it to zero
|
|
EfiDestinationPixel->Red = (UINT8)((Pixel16bit & PixelInformation->RedMask) >> 8);
|
|
EfiDestinationPixel->Green = (UINT8)((Pixel16bit & PixelInformation->GreenMask) >> 3);
|
|
EfiDestinationPixel->Blue = (UINT8)((Pixel16bit & PixelInformation->BlueMask) << 3);
|
|
// EfiDestinationPixel->Reserved = (UINT8) 0;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case LcdBitsPerPixel_12_444:
|
|
// Access each pixel inside the Video Memory
|
|
for (SourceLine = SourceY, DestinationLine = DestinationY;
|
|
SourceLine < SourceY + Height;
|
|
SourceLine++, DestinationLine++)
|
|
{
|
|
for (SourcePixelX = SourceX, DestinationPixelX = DestinationX;
|
|
SourcePixelX < SourceX + Width;
|
|
SourcePixelX++, DestinationPixelX++)
|
|
{
|
|
// Calculate the source and target addresses:
|
|
SourcePixel16bit = (UINT16 *)FrameBufferBase + SourceLine * HorizontalResolution + SourcePixelX;
|
|
EfiDestinationPixel = BltBuffer + DestinationLine * BltBufferHorizontalResolution + DestinationPixelX;
|
|
|
|
// Snapshot the pixel from the video buffer once, to speed up the operation.
|
|
// If we were dereferencing the pointer, as it is volatile, we would perform 3 memory read operations.
|
|
Pixel16bit = *SourcePixel16bit;
|
|
|
|
// Copy the pixel into the new target
|
|
EfiDestinationPixel->Red = (UINT8)((Pixel16bit & PixelInformation->RedMask) >> 4);
|
|
EfiDestinationPixel->Green = (UINT8)((Pixel16bit & PixelInformation->GreenMask));
|
|
EfiDestinationPixel->Blue = (UINT8)((Pixel16bit & PixelInformation->BlueMask) << 4);
|
|
// EfiDestinationPixel->Reserved = (UINT8) 0;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case LcdBitsPerPixel_8:
|
|
case LcdBitsPerPixel_4:
|
|
case LcdBitsPerPixel_2:
|
|
case LcdBitsPerPixel_1:
|
|
default:
|
|
// Can't handle this case
|
|
DEBUG ((DEBUG_ERROR, "LcdGraphicsBlt: EfiBltVideoToBltBuffer: INVALID Number of Bits Per Pixel: %d\n", BitsPerPixel));
|
|
Status = EFI_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
STATIC
|
|
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 // Number of BYTES in a row of the BltBuffer
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT32 HorizontalResolution;
|
|
LCD_BPP BitsPerPixel;
|
|
EFI_PIXEL_BITMASK *PixelInformation;
|
|
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *EfiSourcePixel;
|
|
VOID *FrameBufferBase;
|
|
VOID *SourceAddr;
|
|
VOID *DestinationAddr;
|
|
UINT16 *DestinationPixel16bit;
|
|
UINT32 SourcePixelX;
|
|
UINT32 SourceLine;
|
|
UINT32 DestinationPixelX;
|
|
UINT32 DestinationLine;
|
|
UINT32 BltBufferHorizontalResolution;
|
|
UINTN WidthInBytes;
|
|
|
|
Status = EFI_SUCCESS;
|
|
PixelInformation = &This->Mode->Info->PixelInformation;
|
|
HorizontalResolution = This->Mode->Info->HorizontalResolution;
|
|
FrameBufferBase = (UINTN *)((UINTN)(This->Mode->FrameBufferBase));
|
|
|
|
if ((Delta != 0) && (Delta != Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL))) {
|
|
// Delta is not zero and it is different from the width.
|
|
// Divide it by the size of a pixel to find out the buffer's horizontal resolution.
|
|
BltBufferHorizontalResolution = (UINT32)(Delta / sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
|
|
} else {
|
|
BltBufferHorizontalResolution = Width;
|
|
}
|
|
|
|
LcdPlatformGetBpp (This->Mode->Mode, &BitsPerPixel);
|
|
|
|
switch (BitsPerPixel) {
|
|
case LcdBitsPerPixel_24:
|
|
WidthInBytes = Width * 4;
|
|
|
|
// Access each pixel inside the BltBuffer Memory
|
|
for (SourceLine = SourceY, DestinationLine = DestinationY;
|
|
SourceLine < SourceY + Height;
|
|
SourceLine++, DestinationLine++)
|
|
{
|
|
// Calculate the source and target addresses using 32bit pointer arithmetic:
|
|
SourceAddr = (VOID *)((UINT32 *)BltBuffer + SourceLine * BltBufferHorizontalResolution + SourceX);
|
|
DestinationAddr = (VOID *)((UINT32 *)FrameBufferBase + DestinationLine * HorizontalResolution + DestinationX);
|
|
|
|
// Copy the entire row Y
|
|
CopyMem (DestinationAddr, SourceAddr, WidthInBytes);
|
|
}
|
|
|
|
break;
|
|
|
|
case LcdBitsPerPixel_16_555:
|
|
// Access each pixel inside the BltBuffer Memory
|
|
for (SourceLine = SourceY, DestinationLine = DestinationY;
|
|
SourceLine < SourceY + Height;
|
|
SourceLine++, DestinationLine++)
|
|
{
|
|
for (SourcePixelX = SourceX, DestinationPixelX = DestinationX;
|
|
SourcePixelX < SourceX + Width;
|
|
SourcePixelX++, DestinationPixelX++)
|
|
{
|
|
// Calculate the source and target addresses:
|
|
EfiSourcePixel = BltBuffer + SourceLine * BltBufferHorizontalResolution + SourcePixelX;
|
|
DestinationPixel16bit = (UINT16 *)FrameBufferBase + DestinationLine * HorizontalResolution + DestinationPixelX;
|
|
|
|
// Copy the pixel into the new target
|
|
// Only the most significant bits will be copied across:
|
|
// To convert from 8 bits to 5 bits per pixel we throw away the 3 least significant bits
|
|
*DestinationPixel16bit = (UINT16)(
|
|
((EfiSourcePixel->Red << 7) & PixelInformation->RedMask)
|
|
| ((EfiSourcePixel->Green << 2) & PixelInformation->GreenMask)
|
|
| ((EfiSourcePixel->Blue >> 3) & PixelInformation->BlueMask)
|
|
// | ( 0 & PixelInformation->ReservedMask )
|
|
);
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case LcdBitsPerPixel_16_565:
|
|
// Access each pixel inside the BltBuffer Memory
|
|
for (SourceLine = SourceY, DestinationLine = DestinationY;
|
|
SourceLine < SourceY + Height;
|
|
SourceLine++, DestinationLine++)
|
|
{
|
|
for (SourcePixelX = SourceX, DestinationPixelX = DestinationX;
|
|
SourcePixelX < SourceX + Width;
|
|
SourcePixelX++, DestinationPixelX++)
|
|
{
|
|
// Calculate the source and target addresses:
|
|
EfiSourcePixel = BltBuffer + SourceLine * BltBufferHorizontalResolution + SourcePixelX;
|
|
DestinationPixel16bit = (UINT16 *)FrameBufferBase + DestinationLine * HorizontalResolution + DestinationPixelX;
|
|
|
|
// Copy the pixel into the new target
|
|
// Only the most significant bits will be copied across:
|
|
// To convert from 8 bits to 5 or 6 bits per pixel we throw away the 3 or 2 least significant bits
|
|
// There is no room for the Reserved byte so we ignore that completely
|
|
*DestinationPixel16bit = (UINT16)(
|
|
((EfiSourcePixel->Red << 8) & PixelInformation->RedMask)
|
|
| ((EfiSourcePixel->Green << 3) & PixelInformation->GreenMask)
|
|
| ((EfiSourcePixel->Blue >> 3) & PixelInformation->BlueMask)
|
|
);
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case LcdBitsPerPixel_12_444:
|
|
// Access each pixel inside the BltBuffer Memory
|
|
for (SourceLine = SourceY, DestinationLine = DestinationY;
|
|
SourceLine < SourceY + Height;
|
|
SourceLine++, DestinationLine++)
|
|
{
|
|
for (SourcePixelX = SourceX, DestinationPixelX = DestinationX;
|
|
SourcePixelX < SourceX + Width;
|
|
SourcePixelX++, DestinationPixelX++)
|
|
{
|
|
// Calculate the source and target addresses:
|
|
EfiSourcePixel = BltBuffer + SourceLine * BltBufferHorizontalResolution + SourcePixelX;
|
|
DestinationPixel16bit = (UINT16 *)FrameBufferBase + DestinationLine * HorizontalResolution + DestinationPixelX;
|
|
|
|
// Copy the pixel into the new target
|
|
// Only the most significant bits will be copied across:
|
|
// To convert from 8 bits to 5 bits per pixel we throw away the 3 least significant bits
|
|
*DestinationPixel16bit = (UINT16)(
|
|
((EfiSourcePixel->Red << 4) & PixelInformation->RedMask)
|
|
| ((EfiSourcePixel->Green) & PixelInformation->GreenMask)
|
|
| ((EfiSourcePixel->Blue >> 4) & PixelInformation->BlueMask)
|
|
// | ( 0 & PixelInformation->ReservedMask )
|
|
);
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case LcdBitsPerPixel_8:
|
|
case LcdBitsPerPixel_4:
|
|
case LcdBitsPerPixel_2:
|
|
case LcdBitsPerPixel_1:
|
|
default:
|
|
// Can't handle this case
|
|
DEBUG ((DEBUG_ERROR, "LcdGraphicsBlt: EfiBltBufferToVideo: INVALID Number of Bits Per Pixel: %d\n", BitsPerPixel));
|
|
Status = EFI_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
STATIC
|
|
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 // Number of BYTES in a row of the BltBuffer
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT32 HorizontalResolution;
|
|
LCD_BPP BitsPerPixel;
|
|
VOID *FrameBufferBase;
|
|
|
|
HorizontalResolution = This->Mode->Info->HorizontalResolution;
|
|
FrameBufferBase = (UINTN *)((UINTN)(This->Mode->FrameBufferBase));
|
|
|
|
//
|
|
// BltVideo to BltVideo:
|
|
//
|
|
// Source is the Video Memory,
|
|
// Destination is the Video Memory
|
|
|
|
LcdPlatformGetBpp (This->Mode->Mode, &BitsPerPixel);
|
|
FrameBufferBase = (UINTN *)((UINTN)(This->Mode->FrameBufferBase));
|
|
|
|
// The UEFI spec currently states:
|
|
// "There is no limitation on the overlapping of the source and destination rectangles"
|
|
// Therefore, we must be careful to avoid overwriting the source data
|
|
if ( SourceY == DestinationY ) {
|
|
// Copying within the same height, e.g. horizontal shift
|
|
if ( SourceX == DestinationX ) {
|
|
// Nothing to do
|
|
Status = EFI_SUCCESS;
|
|
} else if (((SourceX > DestinationX) ? (SourceX - DestinationX) : (DestinationX - SourceX)) < Width ) {
|
|
// There is overlap
|
|
Status = VideoCopyHorizontalOverlap (BitsPerPixel, FrameBufferBase, HorizontalResolution, SourceX, SourceY, DestinationX, DestinationY, Width, Height);
|
|
} else {
|
|
// No overlap
|
|
Status = VideoCopyNoHorizontalOverlap (BitsPerPixel, FrameBufferBase, HorizontalResolution, SourceX, SourceY, DestinationX, DestinationY, Width, Height);
|
|
}
|
|
} else {
|
|
// Copying from different heights
|
|
Status = VideoCopyNoHorizontalOverlap (BitsPerPixel, FrameBufferBase, HorizontalResolution, SourceX, SourceY, DestinationX, DestinationY, Width, Height);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/***************************************
|
|
* GraphicsOutput Protocol function, mapping to
|
|
* EFI_GRAPHICS_OUTPUT_PROTOCOL.Blt
|
|
*
|
|
* PRESUMES: 1 pixel = 4 bytes (32bits)
|
|
* ***************************************/
|
|
EFI_STATUS
|
|
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 // Number of BYTES in a row of the BltBuffer
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT32 HorizontalResolution;
|
|
UINT32 VerticalResolution;
|
|
LCD_INSTANCE *Instance;
|
|
|
|
Instance = LCD_INSTANCE_FROM_GOP_THIS (This);
|
|
|
|
// Setup the hardware if not already done
|
|
if (!mDisplayInitialized) {
|
|
Status = InitializeDisplay (Instance);
|
|
if (EFI_ERROR (Status)) {
|
|
goto EXIT;
|
|
}
|
|
}
|
|
|
|
HorizontalResolution = This->Mode->Info->HorizontalResolution;
|
|
VerticalResolution = This->Mode->Info->VerticalResolution;
|
|
|
|
// Check we have reasonable parameters
|
|
if ((Width == 0) || (Height == 0)) {
|
|
DEBUG ((DEBUG_ERROR, "LcdGraphicsBlt: ERROR - Invalid dimension: Zero size area.\n"));
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto EXIT;
|
|
}
|
|
|
|
if ((BltOperation == EfiBltVideoFill) || (BltOperation == EfiBltBufferToVideo) || (BltOperation == EfiBltVideoToBltBuffer)) {
|
|
ASSERT (BltBuffer != NULL);
|
|
}
|
|
|
|
/*if ((DestinationX >= HorizontalResolution) || (DestinationY >= VerticalResolution)) {
|
|
DEBUG((DEBUG_ERROR, "LcdGraphicsBlt: ERROR - Invalid destination.\n" ));
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto EXIT;
|
|
}*/
|
|
|
|
// If we are reading data out of the video buffer, check that the source area is within the display limits
|
|
if ((BltOperation == EfiBltVideoToBltBuffer) || (BltOperation == EfiBltVideoToVideo)) {
|
|
if ((SourceY + Height > VerticalResolution) || (SourceX + Width > HorizontalResolution)) {
|
|
DEBUG ((DEBUG_INFO, "LcdGraphicsBlt: ERROR - Invalid source resolution.\n"));
|
|
DEBUG ((DEBUG_INFO, " - SourceY=%d + Height=%d > VerticalResolution=%d.\n", SourceY, Height, VerticalResolution));
|
|
DEBUG ((DEBUG_INFO, " - SourceX=%d + Width=%d > HorizontalResolution=%d.\n", SourceX, Width, HorizontalResolution));
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto EXIT;
|
|
}
|
|
}
|
|
|
|
// If we are writing data into the video buffer, that the destination area is within the display limits
|
|
if ((BltOperation == EfiBltVideoFill) || (BltOperation == EfiBltBufferToVideo) || (BltOperation == EfiBltVideoToVideo)) {
|
|
if ((DestinationY + Height > VerticalResolution) || (DestinationX + Width > HorizontalResolution)) {
|
|
DEBUG ((DEBUG_INFO, "LcdGraphicsBlt: ERROR - Invalid destination resolution.\n"));
|
|
DEBUG ((DEBUG_INFO, " - DestinationY=%d + Height=%d > VerticalResolution=%d.\n", DestinationY, Height, VerticalResolution));
|
|
DEBUG ((DEBUG_INFO, " - DestinationX=%d + Width=%d > HorizontalResolution=%d.\n", DestinationX, Width, HorizontalResolution));
|
|
Status = EFI_INVALID_PARAMETER;
|
|
goto EXIT;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Perform the Block Transfer Operation
|
|
//
|
|
|
|
switch (BltOperation) {
|
|
case EfiBltVideoFill:
|
|
Status = BltVideoFill (This, BltBuffer, SourceX, SourceY, DestinationX, DestinationY, Width, Height, Delta);
|
|
break;
|
|
|
|
case EfiBltVideoToBltBuffer:
|
|
Status = BltVideoToBltBuffer (This, BltBuffer, SourceX, SourceY, DestinationX, DestinationY, Width, Height, Delta);
|
|
break;
|
|
|
|
case EfiBltBufferToVideo:
|
|
Status = BltBufferToVideo (This, BltBuffer, SourceX, SourceY, DestinationX, DestinationY, Width, Height, Delta);
|
|
break;
|
|
|
|
case EfiBltVideoToVideo:
|
|
Status = BltVideoToVideo (This, BltBuffer, SourceX, SourceY, DestinationX, DestinationY, Width, Height, Delta);
|
|
break;
|
|
|
|
case EfiGraphicsOutputBltOperationMax:
|
|
default:
|
|
DEBUG ((DEBUG_ERROR, "LcdGraphicsBlt: Invalid Operation\n"));
|
|
Status = EFI_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
EXIT:
|
|
return Status;
|
|
}
|