/** @file FrameBufferBltLib - Library to perform blt operations on a frame buffer. Copyright (c) 2007 - 2017, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at http://opensource.org/licenses/bsd-license.php THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ #include #include #include #include #include #include struct FRAME_BUFFER_CONFIGURE { UINTN ColorDepth; UINTN WidthInBytes; UINTN BytesPerPixel; UINTN WidthInPixels; UINTN Height; UINT8 *FrameBuffer; EFI_GRAPHICS_PIXEL_FORMAT PixelFormat; EFI_PIXEL_BITMASK PixelMasks; INT8 PixelShl[4]; // R-G-B-Rsvd INT8 PixelShr[4]; // R-G-B-Rsvd UINT8 LineBuffer[0]; }; CONST EFI_PIXEL_BITMASK mRgbPixelMasks = { 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000 }; CONST EFI_PIXEL_BITMASK mBgrPixelMasks = { 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000 }; /** Initialize the bit mask in frame buffer configure. @param BitMask The bit mask of pixel. @param BytesPerPixel Size in bytes of pixel. @param PixelShl Left shift array. @param PixelShr Right shift array. **/ VOID FrameBufferBltLibConfigurePixelFormat ( IN CONST EFI_PIXEL_BITMASK *BitMask, OUT UINTN *BytesPerPixel, OUT INT8 *PixelShl, OUT INT8 *PixelShr ) { UINT8 Index; UINT32 *Masks; UINT32 MergedMasks; ASSERT (BytesPerPixel != NULL); MergedMasks = 0; Masks = (UINT32*) BitMask; for (Index = 0; Index < 3; Index++) { ASSERT ((MergedMasks & Masks[Index]) == 0); PixelShl[Index] = (INT8) HighBitSet32 (Masks[Index]) - 23 + (Index * 8); if (PixelShl[Index] < 0) { PixelShr[Index] = -PixelShl[Index]; PixelShl[Index] = 0; } else { PixelShr[Index] = 0; } DEBUG ((DEBUG_INFO, "%d: shl:%d shr:%d mask:%x\n", Index, PixelShl[Index], PixelShr[Index], Masks[Index])); MergedMasks = (UINT32) (MergedMasks | Masks[Index]); } MergedMasks = (UINT32) (MergedMasks | Masks[3]); ASSERT (MergedMasks != 0); *BytesPerPixel = (UINTN) ((HighBitSet32 (MergedMasks) + 7) / 8); DEBUG ((DEBUG_INFO, "Bytes per pixel: %d\n", *BytesPerPixel)); } /** Create the configuration for a video frame buffer. The configuration is returned in the caller provided buffer. @param[in] FrameBuffer Pointer to the start of the frame buffer. @param[in] FrameBufferInfo Describes the frame buffer characteristics. @param[in,out] Configure The created configuration information. @param[in,out] ConfigureSize Size of the configuration information. @retval RETURN_SUCCESS The configuration was successful created. @retval RETURN_BUFFER_TOO_SMALL The Configure is to too small. The required size is returned in ConfigureSize. @retval RETURN_UNSUPPORTED The requested mode is not supported by this implementaion. **/ RETURN_STATUS EFIAPI FrameBufferBltConfigure ( IN VOID *FrameBuffer, IN EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *FrameBufferInfo, IN OUT FRAME_BUFFER_CONFIGURE *Configure, IN OUT UINTN *ConfigureSize ) { CONST EFI_PIXEL_BITMASK *BitMask; UINTN BytesPerPixel; INT8 PixelShl[4]; INT8 PixelShr[4]; if (ConfigureSize == NULL) { return RETURN_INVALID_PARAMETER; } switch (FrameBufferInfo->PixelFormat) { case PixelRedGreenBlueReserved8BitPerColor: BitMask = &mRgbPixelMasks; break; case PixelBlueGreenRedReserved8BitPerColor: BitMask = &mBgrPixelMasks; break; case PixelBitMask: BitMask = &FrameBufferInfo->PixelInformation; break; case PixelBltOnly: ASSERT (FrameBufferInfo->PixelFormat != PixelBltOnly); return RETURN_UNSUPPORTED; default: ASSERT (FALSE); return RETURN_INVALID_PARAMETER; } FrameBufferBltLibConfigurePixelFormat (BitMask, &BytesPerPixel, PixelShl, PixelShr); if (*ConfigureSize < sizeof (FRAME_BUFFER_CONFIGURE) + FrameBufferInfo->HorizontalResolution * BytesPerPixel) { *ConfigureSize = sizeof (FRAME_BUFFER_CONFIGURE) + FrameBufferInfo->HorizontalResolution * BytesPerPixel; return RETURN_BUFFER_TOO_SMALL; } if (Configure == NULL) { return RETURN_INVALID_PARAMETER; } CopyMem (&Configure->PixelMasks, BitMask, sizeof (*BitMask)); CopyMem (Configure->PixelShl, PixelShl, sizeof (PixelShl)); CopyMem (Configure->PixelShr, PixelShr, sizeof (PixelShr)); Configure->BytesPerPixel = BytesPerPixel; Configure->PixelFormat = FrameBufferInfo->PixelFormat; Configure->FrameBuffer = (UINT8*) FrameBuffer; Configure->WidthInPixels = (UINTN) FrameBufferInfo->HorizontalResolution; Configure->Height = (UINTN) FrameBufferInfo->VerticalResolution; Configure->WidthInBytes = Configure->WidthInPixels * Configure->BytesPerPixel; return RETURN_SUCCESS; } /** Performs a UEFI Graphics Output Protocol Blt Video Fill. @param[in] Configure Pointer to a configuration which was successfully created by FrameBufferBltConfigure (). @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 RETURN_INVALID_PARAMETER Invalid parameter was passed in. @retval RETURN_SUCCESS The video was filled successfully. **/ EFI_STATUS FrameBufferBltLibVideoFill ( IN FRAME_BUFFER_CONFIGURE *Configure, IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Color, IN UINTN DestinationX, IN UINTN DestinationY, IN UINTN Width, IN UINTN Height ) { UINTN IndexX; UINTN IndexY; UINT8 *Destination; 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 > Configure->Height) { DEBUG ((EFI_D_VERBOSE, "VideoFill: Past screen (Y)\n")); return RETURN_INVALID_PARAMETER; } if (DestinationX + Width > Configure->WidthInPixels) { DEBUG ((EFI_D_VERBOSE, "VideoFill: Past screen (X)\n")); return RETURN_INVALID_PARAMETER; } if (Width == 0 || Height == 0) { DEBUG ((EFI_D_VERBOSE, "VideoFill: Width or Height is 0\n")); return RETURN_INVALID_PARAMETER; } WidthInBytes = Width * Configure->BytesPerPixel; Uint32 = *(UINT32*) Color; WideFill = (UINT32) ( (((Uint32 << Configure->PixelShl[0]) >> Configure->PixelShr[0]) & Configure->PixelMasks.RedMask) | (((Uint32 << Configure->PixelShl[1]) >> Configure->PixelShr[1]) & Configure->PixelMasks.GreenMask) | (((Uint32 << Configure->PixelShl[2]) >> Configure->PixelShr[2]) & Configure->PixelMasks.BlueMask) ); DEBUG ((EFI_D_VERBOSE, "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) % Configure->BytesPerPixel) == 0) { for (IndexX = Configure->BytesPerPixel; IndexX < sizeof (WideFill); IndexX++) { ((UINT8*) &WideFill)[IndexX] = ((UINT8*) &WideFill)[IndexX % Configure->BytesPerPixel]; } } else { // // If all the bytes in the pixel are the same value, then use // a wide fill operation. // for ( IndexX = 1, Uint8 = ((UINT8*) &WideFill)[0]; IndexX < Configure->BytesPerPixel; IndexX++) { if (Uint8 != ((UINT8*) &WideFill)[IndexX]) { UseWideFill = FALSE; break; } } if (UseWideFill) { SetMem (&WideFill, sizeof (WideFill), Uint8); } } if (UseWideFill && (DestinationX == 0) && (Width == Configure->WidthInPixels)) { DEBUG ((EFI_D_VERBOSE, "VideoFill (wide, one-shot)\n")); Offset = DestinationY * Configure->WidthInPixels; Offset = Configure->BytesPerPixel * Offset; Destination = Configure->FrameBuffer + Offset; SizeInBytes = WidthInBytes * Height; if (SizeInBytes >= 8) { SetMem32 (Destination, SizeInBytes & ~3, (UINT32) WideFill); SizeInBytes &= 3; } if (SizeInBytes > 0) { SetMem (Destination, SizeInBytes, (UINT8) (UINTN) WideFill); } } else { LineBufferReady = FALSE; for (IndexY = DestinationY; IndexY < (Height + DestinationY); IndexY++) { Offset = (IndexY * Configure->WidthInPixels) + DestinationX; Offset = Configure->BytesPerPixel * Offset; Destination = Configure->FrameBuffer + Offset; if (UseWideFill && (((UINTN) Destination & 7) == 0)) { DEBUG ((EFI_D_VERBOSE, "VideoFill (wide)\n")); SizeInBytes = WidthInBytes; if (SizeInBytes >= 8) { SetMem64 (Destination, SizeInBytes & ~7, WideFill); SizeInBytes &= 7; } if (SizeInBytes > 0) { CopyMem (Destination, &WideFill, SizeInBytes); } } else { DEBUG ((EFI_D_VERBOSE, "VideoFill (not wide)\n")); if (!LineBufferReady) { CopyMem (Configure->LineBuffer, &WideFill, Configure->BytesPerPixel); for (IndexX = 1; IndexX < Width; ) { CopyMem ( (Configure->LineBuffer + (IndexX * Configure->BytesPerPixel)), Configure->LineBuffer, MIN (IndexX, Width - IndexX) * Configure->BytesPerPixel ); IndexX += MIN (IndexX, Width - IndexX); } LineBufferReady = TRUE; } CopyMem (Destination, Configure->LineBuffer, WidthInBytes); } } } return RETURN_SUCCESS; } /** Performs a UEFI Graphics Output Protocol Blt Video to Buffer operation with extended parameters. @param[in] Configure Pointer to a configuration which was successfully created by FrameBufferBltConfigure (). @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 RETURN_INVALID_PARAMETER Invalid parameter were passed in. @retval RETURN_SUCCESS The Blt operation was performed successfully. **/ RETURN_STATUS FrameBufferBltLibVideoToBltBuffer ( IN FRAME_BUFFER_CONFIGURE *Configure, 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; UINT8 *Source; UINT8 *Destination; UINTN IndexX; UINT32 Uint32; UINTN Offset; UINTN WidthInBytes; // // Video to BltBuffer: Source is Video, destination is BltBuffer // if (SourceY + Height > Configure->Height) { return RETURN_INVALID_PARAMETER; } if (SourceX + Width > Configure->WidthInPixels) { return RETURN_INVALID_PARAMETER; } if (Width == 0 || Height == 0) { return RETURN_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 * Configure->BytesPerPixel; // // Video to BltBuffer: Source is Video, destination is BltBuffer // for (SrcY = SourceY, DstY = DestinationY; DstY < (Height + DestinationY); SrcY++, DstY++) { Offset = (SrcY * Configure->WidthInPixels) + SourceX; Offset = Configure->BytesPerPixel * Offset; Source = Configure->FrameBuffer + Offset; if (Configure->PixelFormat == PixelBlueGreenRedReserved8BitPerColor) { Destination = (UINT8 *) BltBuffer + (DstY * Delta) + (DestinationX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)); } else { Destination = Configure->LineBuffer; } CopyMem (Destination, Source, WidthInBytes); if (Configure->PixelFormat != PixelBlueGreenRedReserved8BitPerColor) { for (IndexX = 0; IndexX < Width; IndexX++) { Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) ((UINT8 *) BltBuffer + (DstY * Delta) + (DestinationX + IndexX) * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)); Uint32 = *(UINT32*) (Configure->LineBuffer + (IndexX * Configure->BytesPerPixel)); *(UINT32*) Blt = (UINT32) ( (((Uint32 & Configure->PixelMasks.RedMask) >> Configure->PixelShl[0]) << Configure->PixelShr[0]) | (((Uint32 & Configure->PixelMasks.GreenMask) >> Configure->PixelShl[1]) << Configure->PixelShr[1]) | (((Uint32 & Configure->PixelMasks.BlueMask) >> Configure->PixelShl[2]) << Configure->PixelShr[2]) ); } } } return RETURN_SUCCESS; } /** Performs a UEFI Graphics Output Protocol Blt Buffer to Video operation with extended parameters. @param[in] Configure Pointer to a configuration which was successfully created by FrameBufferBltConfigure (). @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 RETURN_INVALID_PARAMETER Invalid parameter were passed in. @retval RETURN_SUCCESS The Blt operation was performed successfully. **/ RETURN_STATUS FrameBufferBltLibBufferToVideo ( IN FRAME_BUFFER_CONFIGURE *Configure, 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; UINT8 *Source; UINT8 *Destination; UINTN IndexX; UINT32 Uint32; UINTN Offset; UINTN WidthInBytes; // // BltBuffer to Video: Source is BltBuffer, destination is Video // if (DestinationY + Height > Configure->Height) { return RETURN_INVALID_PARAMETER; } if (DestinationX + Width > Configure->WidthInPixels) { return RETURN_INVALID_PARAMETER; } if (Width == 0 || Height == 0) { return RETURN_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 * Configure->BytesPerPixel; for (SrcY = SourceY, DstY = DestinationY; SrcY < (Height + SourceY); SrcY++, DstY++) { Offset = (DstY * Configure->WidthInPixels) + DestinationX; Offset = Configure->BytesPerPixel * Offset; Destination = Configure->FrameBuffer + Offset; if (Configure->PixelFormat == PixelBlueGreenRedReserved8BitPerColor) { Source = (UINT8 *) BltBuffer + (SrcY * Delta); } else { for (IndexX = 0; IndexX < Width; IndexX++) { Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) ( (UINT8 *) BltBuffer + (SrcY * Delta) + ((SourceX + IndexX) * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)) ); Uint32 = *(UINT32*) Blt; *(UINT32*) (Configure->LineBuffer + (IndexX * Configure->BytesPerPixel)) = (UINT32) ( (((Uint32 << Configure->PixelShl[0]) >> Configure->PixelShr[0]) & Configure->PixelMasks.RedMask) | (((Uint32 << Configure->PixelShl[1]) >> Configure->PixelShr[1]) & Configure->PixelMasks.GreenMask) | (((Uint32 << Configure->PixelShl[2]) >> Configure->PixelShr[2]) & Configure->PixelMasks.BlueMask) ); } Source = Configure->LineBuffer; } CopyMem (Destination, Source, WidthInBytes); } return RETURN_SUCCESS; } /** Performs a UEFI Graphics Output Protocol Blt Video to Video operation @param[in] Configure Pointer to a configuration which was successfully created by FrameBufferBltConfigure (). @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 RETURN_INVALID_PARAMETER Invalid parameter were passed in. @retval RETURN_SUCCESS The Blt operation was performed successfully. **/ RETURN_STATUS FrameBufferBltLibVideoToVideo ( IN FRAME_BUFFER_CONFIGURE *Configure, IN UINTN SourceX, IN UINTN SourceY, IN UINTN DestinationX, IN UINTN DestinationY, IN UINTN Width, IN UINTN Height ) { UINT8 *Source; UINT8 *Destination; UINTN Offset; UINTN WidthInBytes; INTN LineStride; // // Video to Video: Source is Video, destination is Video // if (SourceY + Height > Configure->Height) { return RETURN_INVALID_PARAMETER; } if (SourceX + Width > Configure->WidthInPixels) { return RETURN_INVALID_PARAMETER; } if (DestinationY + Height > Configure->Height) { return RETURN_INVALID_PARAMETER; } if (DestinationX + Width > Configure->WidthInPixels) { return RETURN_INVALID_PARAMETER; } if (Width == 0 || Height == 0) { return RETURN_INVALID_PARAMETER; } WidthInBytes = Width * Configure->BytesPerPixel; Offset = (SourceY * Configure->WidthInPixels) + SourceX; Offset = Configure->BytesPerPixel * Offset; Source = Configure->FrameBuffer + Offset; Offset = (DestinationY * Configure->WidthInPixels) + DestinationX; Offset = Configure->BytesPerPixel * Offset; Destination = Configure->FrameBuffer + Offset; LineStride = Configure->WidthInBytes; if (Destination > Source) { // // Copy from last line to avoid source is corrupted by copying // Source += Height * LineStride; Destination += Height * LineStride; LineStride = -LineStride; } while (Height-- > 0) { CopyMem (Destination, Source, WidthInBytes); Source += LineStride; Destination += LineStride; } return RETURN_SUCCESS; } /** Performs a UEFI Graphics Output Protocol Blt operation. @param[in] Configure Pointer to a configuration which was successfully created by FrameBufferBltConfigure (). @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 RETURN_INVALID_PARAMETER Invalid parameter were passed in. @retval RETURN_SUCCESS The Blt operation was performed successfully. **/ RETURN_STATUS EFIAPI FrameBufferBlt ( IN FRAME_BUFFER_CONFIGURE *Configure, 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 ) { if (Configure == NULL) { return RETURN_INVALID_PARAMETER; } switch (BltOperation) { case EfiBltVideoToBltBuffer: return FrameBufferBltLibVideoToBltBuffer ( Configure, BltBuffer, SourceX, SourceY, DestinationX, DestinationY, Width, Height, Delta ); case EfiBltVideoToVideo: return FrameBufferBltLibVideoToVideo ( Configure, SourceX, SourceY, DestinationX, DestinationY, Width, Height ); case EfiBltVideoFill: return FrameBufferBltLibVideoFill ( Configure, BltBuffer, DestinationX, DestinationY, Width, Height ); case EfiBltBufferToVideo: return FrameBufferBltLibBufferToVideo ( Configure, BltBuffer, SourceX, SourceY, DestinationX, DestinationY, Width, Height, Delta ); default: return RETURN_INVALID_PARAMETER; } }