/** @file FrameBufferBltLib - Library to perform blt operations on a frame buffer. Copyright (c) 2007 - 2011, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "PiDxe.h" #include #include #include #include #if 0 #define VDEBUG DEBUG #else #define VDEBUG(x) #endif #define MAX_LINE_BUFFER_SIZE (SIZE_4KB * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)) UINTN mBltLibColorDepth; UINTN mBltLibWidthInBytes; UINTN mBltLibBytesPerPixel; UINTN mBltLibWidthInPixels; UINTN mBltLibHeight; UINT8 mBltLibLineBuffer[MAX_LINE_BUFFER_SIZE]; UINT8 *mBltLibFrameBuffer; EFI_GRAPHICS_PIXEL_FORMAT mPixelFormat; EFI_PIXEL_BITMASK mPixelBitMasks; INTN mPixelShl[4]; // R-G-B-Rsvd INTN mPixelShr[4]; // R-G-B-Rsvd VOID ConfigurePixelBitMaskFormat ( IN EFI_PIXEL_BITMASK *BitMask ) { UINTN Loop; UINT32 *Masks; UINT32 MergedMasks; MergedMasks = 0; Masks = (UINT32*) BitMask; for (Loop = 0; Loop < 3; Loop++) { ASSERT ((Loop == 3) || (Masks[Loop] != 0)); ASSERT ((MergedMasks & Masks[Loop]) == 0); mPixelShl[Loop] = HighBitSet32 (Masks[Loop]) - 23 + (Loop * 8); if (mPixelShl[Loop] < 0) { mPixelShr[Loop] = -mPixelShl[Loop]; mPixelShl[Loop] = 0; } else { mPixelShr[Loop] = 0; } MergedMasks = (UINT32) (MergedMasks | Masks[Loop]); DEBUG ((EFI_D_INFO, "%d: shl:%d shr:%d mask:%x\n", Loop, mPixelShl[Loop], mPixelShr[Loop], Masks[Loop])); } MergedMasks = (UINT32) (MergedMasks | Masks[3]); ASSERT (MergedMasks != 0); mBltLibBytesPerPixel = (UINTN) ((HighBitSet32 (MergedMasks) + 7) / 8); DEBUG ((EFI_D_INFO, "Bytes per pixel: %d\n", mBltLibBytesPerPixel)); CopyMem (&mPixelBitMasks, BitMask, sizeof (*BitMask)); } /** Configure the FrameBufferLib instance @param[in] FrameBuffer Pointer to the start of the frame buffer @param[in] FrameBufferInfo Describes the frame buffer characteristics @retval EFI_INVALID_PARAMETER - Invalid parameter @retval EFI_UNSUPPORTED - The BltLib does not support this configuration @retval EFI_SUCCESS - Blt operation success **/ EFI_STATUS EFIAPI BltLibConfigure ( IN VOID *FrameBuffer, IN EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *FrameBufferInfo ) { STATIC EFI_PIXEL_BITMASK RgbPixelMasks = { 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 }; STATIC EFI_PIXEL_BITMASK BgrPixelMasks = { 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 }; switch (FrameBufferInfo->PixelFormat) { case PixelRedGreenBlueReserved8BitPerColor: ConfigurePixelBitMaskFormat (&RgbPixelMasks); break; case PixelBlueGreenRedReserved8BitPerColor: ConfigurePixelBitMaskFormat (&BgrPixelMasks); break; case PixelBitMask: ConfigurePixelBitMaskFormat (&(FrameBufferInfo->PixelInformation)); break; case PixelBltOnly: ASSERT (FrameBufferInfo->PixelFormat != PixelBltOnly); return EFI_UNSUPPORTED; default: ASSERT (FALSE); return EFI_INVALID_PARAMETER; } mPixelFormat = FrameBufferInfo->PixelFormat; mBltLibFrameBuffer = (UINT8*) FrameBuffer; mBltLibWidthInPixels = (UINTN) FrameBufferInfo->HorizontalResolution; mBltLibHeight = (UINTN) FrameBufferInfo->VerticalResolution; mBltLibWidthInBytes = mBltLibWidthInPixels * mBltLibBytesPerPixel; ASSERT (mBltLibWidthInBytes < sizeof (mBltLibLineBuffer)); return EFI_SUCCESS; } /** Performs a UEFI Graphics Output Protocol Blt operation. @param[in,out] BltBuffer - The data to transfer to screen @param[in] BltOperation - The operation to perform @param[in] SourceX - The X coordinate of the source for BltOperation @param[in] SourceY - The Y coordinate of the source for BltOperation @param[in] DestinationX - The X coordinate of the destination for BltOperation @param[in] DestinationY - The Y coordinate of the destination for BltOperation @param[in] Width - The width of a rectangle in the blt rectangle in pixels @param[in] Height - The height of a rectangle in the blt rectangle in pixels @param[in] Delta - Not used for EfiBltVideoFill and EfiBltVideoToVideo operation. If a Delta of 0 is used, the entire BltBuffer will be operated on. If a subrectangle of the BltBuffer is used, then Delta represents the number of bytes in a row of the BltBuffer. @retval EFI_DEVICE_ERROR - A hardware error occured @retval EFI_INVALID_PARAMETER - Invalid parameter passed in @retval EFI_SUCCESS - Blt operation success **/ EFI_STATUS EFIAPI BltLibGopBlt ( IN 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 ) { switch (BltOperation) { case EfiBltVideoToBltBuffer: return BltLibVideoToBltBufferEx ( BltBuffer, SourceX, SourceY, DestinationX, DestinationY, Width, Height, Delta ); case EfiBltVideoToVideo: return BltLibVideoToVideo ( SourceX, SourceY, DestinationX, DestinationY, Width, Height ); case EfiBltVideoFill: return BltLibVideoFill ( BltBuffer, DestinationX, DestinationY, Width, Height ); case EfiBltBufferToVideo: return BltLibBufferToVideoEx ( BltBuffer, SourceX, SourceY, DestinationX, DestinationY, Width, Height, Delta ); default: return EFI_INVALID_PARAMETER; } } /** Performs a UEFI Graphics Output Protocol Blt Video Fill. @param[in] Color Color to fill the region with @param[in] DestinationX X location to start fill operation @param[in] DestinationY Y location to start fill operation @param[in] Width Width (in pixels) to fill @param[in] Height Height to fill @retval EFI_DEVICE_ERROR - A hardware error occured @retval EFI_INVALID_PARAMETER - Invalid parameter passed in @retval EFI_SUCCESS - The sizes were returned **/ EFI_STATUS EFIAPI BltLibVideoFill ( IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Color, IN UINTN DestinationX, IN UINTN DestinationY, IN UINTN Width, IN UINTN Height ) { UINTN DstY; VOID *BltMemDst; UINTN X; UINT8 Uint8; UINT32 Uint32; UINT64 WideFill; BOOLEAN UseWideFill; BOOLEAN LineBufferReady; UINTN Offset; UINTN WidthInBytes; UINTN SizeInBytes; // // BltBuffer to Video: Source is BltBuffer, destination is Video // if (DestinationY + Height > mBltLibHeight) { DEBUG ((EFI_D_INFO, "VideoFill: Past screen (Y)\n")); return EFI_INVALID_PARAMETER; } if (DestinationX + Width > mBltLibWidthInPixels) { DEBUG ((EFI_D_INFO, "VideoFill: Past screen (X)\n")); return EFI_INVALID_PARAMETER; } if (Width == 0 || Height == 0) { DEBUG ((EFI_D_INFO, "VideoFill: Width or Height is 0\n")); return EFI_INVALID_PARAMETER; } WidthInBytes = Width * mBltLibBytesPerPixel; Uint32 = *(UINT32*) Color; WideFill = (UINT32) ( (((Uint32 << mPixelShl[0]) >> mPixelShr[0]) & mPixelBitMasks.RedMask) | (((Uint32 << mPixelShl[1]) >> mPixelShr[1]) & mPixelBitMasks.GreenMask) | (((Uint32 << mPixelShl[2]) >> mPixelShr[2]) & mPixelBitMasks.BlueMask) ); VDEBUG ((EFI_D_INFO, "VideoFill: color=0x%x, wide-fill=0x%x\n", Uint32, WideFill)); // // If the size of the pixel data evenly divides the sizeof // WideFill, then a wide fill operation can be used // UseWideFill = TRUE; if ((sizeof (WideFill) % mBltLibBytesPerPixel) == 0) { for (X = mBltLibBytesPerPixel; X < sizeof (WideFill); X++) { ((UINT8*)&WideFill)[X] = ((UINT8*)&WideFill)[X % mBltLibBytesPerPixel]; } } else { // // If all the bytes in the pixel are the same value, then use // a wide fill operation. // for ( X = 1, Uint8 = ((UINT8*)&WideFill)[0]; X < mBltLibBytesPerPixel; X++) { if (Uint8 != ((UINT8*)&WideFill)[X]) { UseWideFill = FALSE; break; } } if (UseWideFill) { SetMem ((VOID*) &WideFill, sizeof (WideFill), Uint8); } } if (UseWideFill && (DestinationX == 0) && (Width == mBltLibWidthInPixels)) { VDEBUG ((EFI_D_INFO, "VideoFill (wide, one-shot)\n")); Offset = DestinationY * mBltLibWidthInPixels; Offset = mBltLibBytesPerPixel * Offset; BltMemDst = (VOID*) (mBltLibFrameBuffer + Offset); SizeInBytes = WidthInBytes * Height; if (SizeInBytes >= 8) { SetMem32 (BltMemDst, SizeInBytes & ~3, (UINT32) WideFill); SizeInBytes = SizeInBytes & 3; } if (SizeInBytes > 0) { SetMem (BltMemDst, SizeInBytes, (UINT8)(UINTN) WideFill); } } else { LineBufferReady = FALSE; for (DstY = DestinationY; DstY < (Height + DestinationY); DstY++) { Offset = (DstY * mBltLibWidthInPixels) + DestinationX; Offset = mBltLibBytesPerPixel * Offset; BltMemDst = (VOID*) (mBltLibFrameBuffer + Offset); if (UseWideFill && (((UINTN) BltMemDst & 7) == 0)) { VDEBUG ((EFI_D_INFO, "VideoFill (wide)\n")); SizeInBytes = WidthInBytes; if (SizeInBytes >= 8) { SetMem64 (BltMemDst, SizeInBytes & ~7, WideFill); SizeInBytes = SizeInBytes & 7; } if (SizeInBytes > 0) { CopyMem (BltMemDst, (VOID*) &WideFill, SizeInBytes); } } else { VDEBUG ((EFI_D_INFO, "VideoFill (not wide)\n")); if (!LineBufferReady) { CopyMem (mBltLibLineBuffer, &WideFill, mBltLibBytesPerPixel); for (X = 1; X < Width; ) { CopyMem( (mBltLibLineBuffer + (X * mBltLibBytesPerPixel)), mBltLibLineBuffer, MIN (X, Width - X) * mBltLibBytesPerPixel ); X = X + MIN (X, Width - X); } LineBufferReady = TRUE; } CopyMem (BltMemDst, mBltLibLineBuffer, WidthInBytes); } } } return EFI_SUCCESS; } /** Performs a UEFI Graphics Output Protocol Blt Video to Buffer operation. @param[out] BltBuffer Output buffer for pixel color data @param[in] SourceX X location within video @param[in] SourceY Y location within video @param[in] Width Width (in pixels) @param[in] Height Height @retval EFI_DEVICE_ERROR - A hardware error occured @retval EFI_INVALID_PARAMETER - Invalid parameter passed in @retval EFI_SUCCESS - The sizes were returned **/ EFI_STATUS EFIAPI BltLibVideoToBltBuffer ( OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, IN UINTN SourceX, IN UINTN SourceY, IN UINTN Width, IN UINTN Height ) { return BltLibVideoToBltBufferEx ( BltBuffer, SourceX, SourceY, 0, 0, Width, Height, 0 ); } /** Performs a UEFI Graphics Output Protocol Blt Video to Buffer operation with extended parameters. @param[out] BltBuffer Output buffer for pixel color data @param[in] SourceX X location within video @param[in] SourceY Y location within video @param[in] DestinationX X location within BltBuffer @param[in] DestinationY Y location within BltBuffer @param[in] Width Width (in pixels) @param[in] Height Height @param[in] Delta Number of bytes in a row of BltBuffer @retval EFI_DEVICE_ERROR - A hardware error occured @retval EFI_INVALID_PARAMETER - Invalid parameter passed in @retval EFI_SUCCESS - The sizes were returned **/ EFI_STATUS EFIAPI BltLibVideoToBltBufferEx ( OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, IN UINTN SourceX, IN UINTN SourceY, IN UINTN DestinationX, IN UINTN DestinationY, IN UINTN Width, IN UINTN Height, IN UINTN Delta ) { UINTN DstY; UINTN SrcY; EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt; VOID *BltMemSrc; VOID *BltMemDst; UINTN X; UINT32 Uint32; UINTN Offset; UINTN WidthInBytes; // // Video to BltBuffer: Source is Video, destination is BltBuffer // if (SourceY + Height > mBltLibHeight) { return EFI_INVALID_PARAMETER; } if (SourceX + Width > mBltLibWidthInPixels) { return EFI_INVALID_PARAMETER; } if (Width == 0 || Height == 0) { return EFI_INVALID_PARAMETER; } // // If Delta is zero, then the entire BltBuffer is being used, so Delta // is the number of bytes in each row of BltBuffer. Since BltBuffer is Width pixels size, // the number of bytes in each row can be computed. // if (Delta == 0) { Delta = Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL); } WidthInBytes = Width * mBltLibBytesPerPixel; // // Video to BltBuffer: Source is Video, destination is BltBuffer // for (SrcY = SourceY, DstY = DestinationY; DstY < (Height + DestinationY); SrcY++, DstY++) { Offset = (SrcY * mBltLibWidthInPixels) + SourceX; Offset = mBltLibBytesPerPixel * Offset; BltMemSrc = (VOID *) (mBltLibFrameBuffer + Offset); if (mPixelFormat == PixelBlueGreenRedReserved8BitPerColor) { BltMemDst = (VOID *) ( (UINT8 *) BltBuffer + (DstY * Delta) + (DestinationX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)) ); } else { BltMemDst = (VOID *) mBltLibLineBuffer; } CopyMem (BltMemDst, BltMemSrc, WidthInBytes); if (mPixelFormat != PixelBlueGreenRedReserved8BitPerColor) { for (X = 0; X < Width; X++) { Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) ((UINT8 *) BltBuffer + (DstY * Delta) + (DestinationX + X) * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)); Uint32 = *(UINT32*) (mBltLibLineBuffer + (X * mBltLibBytesPerPixel)); *(UINT32*) Blt = (UINT32) ( (((Uint32 & mPixelBitMasks.RedMask) >> mPixelShl[0]) << mPixelShr[0]) | (((Uint32 & mPixelBitMasks.GreenMask) >> mPixelShl[1]) << mPixelShr[1]) | (((Uint32 & mPixelBitMasks.BlueMask) >> mPixelShl[2]) << mPixelShr[2]) ); } } } return EFI_SUCCESS; } /** Performs a UEFI Graphics Output Protocol Blt Buffer to Video operation. @param[in] BltBuffer Output buffer for pixel color data @param[in] DestinationX X location within video @param[in] DestinationY Y location within video @param[in] Width Width (in pixels) @param[in] Height Height @retval EFI_DEVICE_ERROR - A hardware error occured @retval EFI_INVALID_PARAMETER - Invalid parameter passed in @retval EFI_SUCCESS - The sizes were returned **/ EFI_STATUS EFIAPI BltLibBufferToVideo ( IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, IN UINTN DestinationX, IN UINTN DestinationY, IN UINTN Width, IN UINTN Height ) { return BltLibBufferToVideoEx ( BltBuffer, 0, 0, DestinationX, DestinationY, Width, Height, 0 ); } /** Performs a UEFI Graphics Output Protocol Blt Buffer to Video operation with extended parameters. @param[in] BltBuffer Output buffer for pixel color data @param[in] SourceX X location within BltBuffer @param[in] SourceY Y location within BltBuffer @param[in] DestinationX X location within video @param[in] DestinationY Y location within video @param[in] Width Width (in pixels) @param[in] Height Height @param[in] Delta Number of bytes in a row of BltBuffer @retval EFI_DEVICE_ERROR - A hardware error occured @retval EFI_INVALID_PARAMETER - Invalid parameter passed in @retval EFI_SUCCESS - The sizes were returned **/ EFI_STATUS EFIAPI BltLibBufferToVideoEx ( IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, IN UINTN SourceX, IN UINTN SourceY, IN UINTN DestinationX, IN UINTN DestinationY, IN UINTN Width, IN UINTN Height, IN UINTN Delta ) { UINTN DstY; UINTN SrcY; EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt; VOID *BltMemSrc; VOID *BltMemDst; UINTN X; UINT32 Uint32; UINTN Offset; UINTN WidthInBytes; // // BltBuffer to Video: Source is BltBuffer, destination is Video // if (DestinationY + Height > mBltLibHeight) { return EFI_INVALID_PARAMETER; } if (DestinationX + Width > mBltLibWidthInPixels) { return EFI_INVALID_PARAMETER; } if (Width == 0 || Height == 0) { return EFI_INVALID_PARAMETER; } // // If Delta is zero, then the entire BltBuffer is being used, so Delta // is the number of bytes in each row of BltBuffer. Since BltBuffer is Width pixels size, // the number of bytes in each row can be computed. // if (Delta == 0) { Delta = Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL); } WidthInBytes = Width * mBltLibBytesPerPixel; for (SrcY = SourceY, DstY = DestinationY; SrcY < (Height + SourceY); SrcY++, DstY++) { Offset = (DstY * mBltLibWidthInPixels) + DestinationX; Offset = mBltLibBytesPerPixel * Offset; BltMemDst = (VOID*) (mBltLibFrameBuffer + Offset); if (mPixelFormat == PixelBlueGreenRedReserved8BitPerColor) { BltMemSrc = (VOID *) ((UINT8 *) BltBuffer + (SrcY * Delta)); } else { for (X = 0; X < Width; X++) { Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) ( (UINT8 *) BltBuffer + (SrcY * Delta) + ((SourceX + X) * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)) ); Uint32 = *(UINT32*) Blt; *(UINT32*) (mBltLibLineBuffer + (X * mBltLibBytesPerPixel)) = (UINT32) ( (((Uint32 << mPixelShl[0]) >> mPixelShr[0]) & mPixelBitMasks.RedMask) | (((Uint32 << mPixelShl[1]) >> mPixelShr[1]) & mPixelBitMasks.GreenMask) | (((Uint32 << mPixelShl[2]) >> mPixelShr[2]) & mPixelBitMasks.BlueMask) ); } BltMemSrc = (VOID *) mBltLibLineBuffer; } CopyMem (BltMemDst, BltMemSrc, WidthInBytes); } return EFI_SUCCESS; } /** Performs a UEFI Graphics Output Protocol Blt Video to Video operation @param[in] SourceX X location within video @param[in] SourceY Y location within video @param[in] DestinationX X location within video @param[in] DestinationY Y location within video @param[in] Width Width (in pixels) @param[in] Height Height @retval EFI_DEVICE_ERROR - A hardware error occured @retval EFI_INVALID_PARAMETER - Invalid parameter passed in @retval EFI_SUCCESS - The sizes were returned **/ EFI_STATUS EFIAPI BltLibVideoToVideo ( IN UINTN SourceX, IN UINTN SourceY, IN UINTN DestinationX, IN UINTN DestinationY, IN UINTN Width, IN UINTN Height ) { VOID *BltMemSrc; VOID *BltMemDst; UINTN Offset; UINTN WidthInBytes; INTN LineStride; // // Video to Video: Source is Video, destination is Video // if (SourceY + Height > mBltLibHeight) { return EFI_INVALID_PARAMETER; } if (SourceX + Width > mBltLibWidthInPixels) { return EFI_INVALID_PARAMETER; } if (DestinationY + Height > mBltLibHeight) { return EFI_INVALID_PARAMETER; } if (DestinationX + Width > mBltLibWidthInPixels) { return EFI_INVALID_PARAMETER; } if (Width == 0 || Height == 0) { return EFI_INVALID_PARAMETER; } WidthInBytes = Width * mBltLibBytesPerPixel; Offset = (SourceY * mBltLibWidthInPixels) + SourceX; Offset = mBltLibBytesPerPixel * Offset; BltMemSrc = (VOID *) (mBltLibFrameBuffer + Offset); Offset = (DestinationY * mBltLibWidthInPixels) + DestinationX; Offset = mBltLibBytesPerPixel * Offset; BltMemDst = (VOID *) (mBltLibFrameBuffer + Offset); LineStride = mBltLibWidthInBytes; if ((UINTN) BltMemDst > (UINTN) BltMemSrc) { LineStride = -LineStride; } while (Height > 0) { CopyMem (BltMemDst, BltMemSrc, WidthInBytes); BltMemSrc = (VOID*) ((UINT8*) BltMemSrc + LineStride); BltMemDst = (VOID*) ((UINT8*) BltMemDst + LineStride); Height--; } return EFI_SUCCESS; } /** Returns the sizes related to the video device @param[out] Width Width (in pixels) @param[out] Height Height (in pixels) @retval EFI_INVALID_PARAMETER - Invalid parameter passed in @retval EFI_SUCCESS - The sizes were returned **/ EFI_STATUS EFIAPI BltLibGetSizes ( OUT UINTN *Width, OPTIONAL OUT UINTN *Height OPTIONAL ) { if (Width != NULL) { *Width = mBltLibWidthInPixels; } if (Height != NULL) { *Height = mBltLibHeight; } return EFI_SUCCESS; }