alder_lake_bios/Insyde/InsydeModulePkg/Universal/UserInterface/SetupMouseDxe/SetupMouseScreen.c

579 lines
18 KiB
C

/** @file
Setup Mouse Protocol implementation
;******************************************************************************
;* Copyright (c) 2012 - 2019, Insyde Software Corp. All Rights Reserved.
;*
;* You may not reproduce, distribute, publish, display, perform, modify, adapt,
;* transmit, broadcast, present, recite, release, license or otherwise exploit
;* any part of this publication in any form, by any means, without the prior
;* written permission of Insyde Software Corporation.
;*
;******************************************************************************
*/
#include "SetupMouse.h"
extern PRIVATE_MOUSE_DATA *mPrivate;
/**
SetupMouseScreenBltWorker Blt function to process keyboard display
@param [in] Private Setup mouse private data
@param [in] GopEntry Gop Entry
@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 of 0 is used, the entire BltBuffer will be operated on.
If a subrectangle of the BltBuffer is used, then represents
the number of bytes in a row of the BltBuffer.
@return SetupMouseCursorBlt function status
**/
EFI_STATUS
SetupMouseScreenBltWorker (
IN PRIVATE_MOUSE_DATA *Private,
IN GOP_ENTRY *GopEntry,
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
)
{
EFI_STATUS Status;
EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop;
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *ScreenFrameBuffer;
EFI_TPL OriginalTPL;
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *VScreen;
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *VScreenSrc;
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
INTN Y;
UINT32 FillPixel;
UINT32 VerticalResolution;
UINT32 HorizontalResolution;
RECT InvalidateRc;
UINTN CopyBytes;
if ((BltOperation < 0) || (BltOperation >= EfiGraphicsOutputBltOperationMax)) {
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);
}
//
// We need to fill the Virtual Screen buffer with the blt data.
// The virtual screen is upside down, as the first row is the bootom row of
// the image.
//
Gop = GopEntry->GraphicsOutput;
VerticalResolution = Gop->Mode->Info->VerticalResolution;
HorizontalResolution = Gop->Mode->Info->HorizontalResolution;
ScreenFrameBuffer = GopEntry->Screen.Image;
if (BltOperation == EfiBltVideoToBltBuffer) {
//
// Video to BltBuffer: Source is Video, destination is BltBuffer
//
if (SourceY + Height > VerticalResolution) {
return EFI_INVALID_PARAMETER;
}
if (SourceX + Width > HorizontalResolution) {
return EFI_INVALID_PARAMETER;
}
//
// We have to raise to TPL Notify, so we make an atomic write the frame buffer.
// We would not want a timer based event (Cursor, ...) to come in while we are
// doing this operation.
//
CopyBytes = Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
VScreenSrc = ScreenFrameBuffer + SourceY * HorizontalResolution + SourceX;
Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)((UINT8 *)BltBuffer + DestinationY * Delta + DestinationX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
Y = Height;
while ((--Y) >= 0) {
CopyMem (Blt, VScreenSrc, CopyBytes);
VScreenSrc += HorizontalResolution;
Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)((UINT8 *)Blt + Delta);
}
gBS->RestoreTPL (OriginalTPL);
return EFI_SUCCESS;
}
//
// BltBuffer to Video: Source is BltBuffer, destination is Video
//
if (DestinationY + Height > VerticalResolution) {
return EFI_INVALID_PARAMETER;
}
if (DestinationX + Width > HorizontalResolution) {
return EFI_INVALID_PARAMETER;
}
//
// We have to raise to TPL Notify, so we make an atomic write the frame buffer.
// We would not want a timer based event (Cursor, ...) to come in while we are
// doing this operation.
//
CopyBytes = Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
switch ((UINTN) BltOperation) {
case EfiBltBufferToVideo:
Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)((UINT8 *) BltBuffer + SourceY * Delta + SourceX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
VScreen = ScreenFrameBuffer + DestinationY * HorizontalResolution + DestinationX;
Y = Height;
while ((--Y) >= 0) {
CopyMem (VScreen, Blt, CopyBytes);
Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)((UINT8 *)Blt + Delta);
VScreen += HorizontalResolution;
}
break;
case EfiBltVideoToVideo:
if (DestinationY <= SourceY) {
VScreenSrc = ScreenFrameBuffer + SourceY * HorizontalResolution + SourceX;
VScreen = ScreenFrameBuffer + DestinationY * HorizontalResolution + DestinationX;
Y = Height;
while ((--Y) >= 0) {
CopyMem (VScreen, VScreenSrc, CopyBytes);
VScreenSrc += HorizontalResolution;
VScreen += HorizontalResolution;
}
} else {
VScreenSrc = ScreenFrameBuffer + (SourceY + Height - 1) * HorizontalResolution + SourceX;
VScreen = ScreenFrameBuffer + (DestinationY + Height - 1) * HorizontalResolution + DestinationX;
Y = Height;
while ((--Y) >= 0) {
CopyMem (VScreen, VScreenSrc, CopyBytes);
VScreenSrc -= HorizontalResolution;
VScreen -= HorizontalResolution;
}
}
break;
case EfiBltVideoFill:
FillPixel = *(UINT32 *)BltBuffer;
Blt = GopEntry->FillLine;
Y = Width;
while ((--Y) >= 0) {
*(UINT32 *)Blt = FillPixel;
Blt++;
}
Blt = GopEntry->FillLine;
VScreen = ScreenFrameBuffer + DestinationY * HorizontalResolution + DestinationX;
Y = Height;
while ((--Y) >= 0) {
CopyMem (VScreen, Blt, CopyBytes);
VScreen += HorizontalResolution;
}
break;
}
SetRect (
&InvalidateRc,
(INT32)DestinationX,
(INT32)DestinationY,
(INT32)(DestinationX + Width),
(INT32)(DestinationY + Height)
);
UnionRect (&GopEntry->InvalidateRc, &GopEntry->InvalidateRc, &InvalidateRc);
Status = RenderImage (Private, GopEntry, FALSE);
gBS->RestoreTPL (OriginalTPL);
return Status;
}
/**
SetupMouseCursorBlt Blt function to process keyboard display
@param [in] This Pointer to Graphics Output protocol instance
@param [in] 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 of 0 is used, the entire BltBuffer will be operated on.
If a subrectangle of the BltBuffer is used, then represents
the number of bytes in a row of the BltBuffer.
@return SetupMouseCursorBlt function status
**/
EFI_STATUS
EFIAPI
SetupMouseScreenBlt (
IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
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 OPTIONAL
)
{
PRIVATE_MOUSE_DATA *Private;
LIST_ENTRY *Node;
GOP_ENTRY *GopEntry;
Private = mPrivate;
GopEntry = NULL;
Node = GetFirstNode (&Private->GopList);
while (!IsNull (&Private->GopList, Node)) {
GopEntry = GOP_ENTRY_FROM_THIS (Node);
if (GopEntry->GraphicsOutput == This) {
break;
}
Node = GetNextNode (&Private->GopList, Node);
}
ASSERT (!IsNull (&Private->GopList, Node));
if (IsNull (&Private->GopList, Node) || GopEntry == NULL) {
return EFI_UNSUPPORTED;
}
if (!Private->IsStart) {
return GopEntry->OriginalBlt (
GopEntry->GraphicsOutput,
BltBuffer,
BltOperation,
SourceX,
SourceY,
DestinationX,
DestinationY,
Width,
Height,
Delta
);
} else {
return SetupMouseScreenBltWorker (
Private,
GopEntry,
BltBuffer,
BltOperation,
SourceX,
SourceY,
DestinationX,
DestinationY,
Width,
Height,
Delta
);
}
}
/**
Copy image to blend image
@param [in] Private Setup mouse private data
@param [in] GopEntry Gop Entry
@param [in] Rc Sync rectangle
@param [out] ImageIsSame Screen Image is same as GOP
@retval N/A
**/
VOID
SyncScreenImage (
IN PRIVATE_MOUSE_DATA *Private,
IN GOP_ENTRY *GopEntry,
IN RECT *Rc,
OUT BOOLEAN *ImageIsSame
)
{
INTN X;
INTN Y;
INT32 Width;
INT32 Height;
UINT32 *BlendBlt;
UINT32 *CheckBlt;
UINT32 *ScreenBlt;
UINTN HorizontalResolution;
BOOLEAN IsSame;
UINT32 *BlendBuffer;
UINT32 *CheckBuffer;
UINT32 *ScreenBuffer;
UINTN BufferOffset;
ASSERT (ImageIsSame != NULL);
IsSame = TRUE;
HorizontalResolution = GopEntry->GraphicsOutput->Mode->Info->HorizontalResolution;
Width = Rc->right - Rc->left;
Height = Rc->bottom - Rc->top;
//
// read image from gop
//
BufferOffset = Rc->left * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) + Rc->top * GopEntry->BytesPerScanLine;
GopEntry->OriginalBlt (
GopEntry->GraphicsOutput,
(EFI_GRAPHICS_OUTPUT_BLT_PIXEL *)((UINT8 *)GopEntry->CheckBuffer + BufferOffset),
EfiBltVideoToBltBuffer,
Rc->left,
Rc->top,
0,
0,
Width,
Height,
GopEntry->BytesPerScanLine
);
*ImageIsSame = TRUE;
BlendBuffer = (UINT32 *) GopEntry->BlendBuffer + Rc->top * HorizontalResolution + Rc->left;
CheckBuffer = (UINT32 *) GopEntry->CheckBuffer + Rc->top * HorizontalResolution + Rc->left;
ScreenBuffer = (UINT32 *) GopEntry->Screen.Image + Rc->top * HorizontalResolution + Rc->left;
Y = Height;
while ((--Y) >= 0) {
BlendBlt = BlendBuffer;
CheckBlt = CheckBuffer;
ScreenBlt = ScreenBuffer;
X = Width;
while ((--X) >= 0) {
if (*BlendBlt != *CheckBlt) {
*ScreenBlt = *CheckBlt;
IsSame = FALSE;
}
BlendBlt++;
CheckBlt++;
ScreenBlt++;
}
BlendBuffer += HorizontalResolution;
CheckBuffer += HorizontalResolution;
ScreenBuffer += HorizontalResolution;
}
*ImageIsSame = IsSame;
}
/**
Copy image to blend image
@param [in] Private Setup mouse private data
@param [in] GopEntry Gop Entry
@param [in] ImageInfo Source image information
@param [in] UpdateRc Need update region
@param [in] Transparent Whether have transparent color
@retval N/A
**/
VOID
UpdateImage (
IN PRIVATE_MOUSE_DATA *Private,
IN GOP_ENTRY *GopEntry,
IN IMAGE_INFO *ImageInfo,
IN RECT *UpdateRc,
IN BOOLEAN Transparent
)
{
INTN X;
INTN Y;
INT32 Width;
INT32 Height;
INT32 ImageWidth;
INT32 ImageHeight;
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *ImageBlt;
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BlendBlt;
RECT *ImageRc;
UINTN HorizontalResolution;
UINTN CopyBytes;
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *ImageBuffer;
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BlendBuffer;
Width = UpdateRc->right - UpdateRc->left;
Height = UpdateRc->bottom - UpdateRc->top;
ImageWidth = ImageInfo->ImageRc.right - ImageInfo->ImageRc.left;
ImageHeight = ImageInfo->ImageRc.bottom - ImageInfo->ImageRc.top;
ImageRc = &ImageInfo->ImageRc;
HorizontalResolution = GopEntry->GraphicsOutput->Mode->Info->HorizontalResolution;
ASSERT (Width <= ImageWidth);
ASSERT (Height <= ImageHeight);
ImageBuffer = ImageInfo->Image + (UpdateRc->top - ImageRc->top) * ImageWidth + (UpdateRc->left - ImageRc->left);
BlendBuffer = GopEntry->BlendBuffer + UpdateRc->top * HorizontalResolution + UpdateRc->left;
if (!Transparent) {
CopyBytes = Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
Y = Height;
while ((--Y) >= 0) {
CopyMem (BlendBuffer, ImageBuffer, CopyBytes);
ImageBuffer += ImageWidth;
BlendBuffer += HorizontalResolution;
}
} else {
ImageBuffer = ImageInfo->Image + (UpdateRc->top - ImageRc->top) * ImageWidth + (UpdateRc->left - ImageRc->left);
BlendBuffer = GopEntry->BlendBuffer + UpdateRc->top * HorizontalResolution + UpdateRc->left;
Y = Height;
while ((--Y) >= 0) {
ImageBlt = ImageBuffer;
BlendBlt = BlendBuffer;
X = Width;
while ((--X) >= 0) {
BlendPixel (BlendBlt, ImageBlt);
*(UINT32 *)BlendBlt = (0x80000000 | (*(UINT32 *)BlendBlt & 0x00FFFFFF));
ImageBlt++;
BlendBlt++;
}
ImageBuffer += ImageWidth;
BlendBuffer += HorizontalResolution;
}
}
}
/**
Render Image to GOP
@param [in] Private Setup mouse private data
@param [in] GopEntry Gop Entry
@param [in] NeedSyncScreen Whether need sync screen image
@return EFI_STATUS return original BLT function status
**/
EFI_STATUS
RenderImage (
IN PRIVATE_MOUSE_DATA *Private,
IN GOP_ENTRY *GopEntry,
IN BOOLEAN NeedSyncScreen
)
{
RECT UpdateRc;
RECT InvalidateRc;
BOOLEAN ImageIsSame;
EFI_STATUS Status;
UINTN BufferOffset;
IntersectRect (&InvalidateRc, &GopEntry->InvalidateRc, &GopEntry->Screen.ImageRc);
if (IsRectEmpty (&InvalidateRc)) {
return EFI_SUCCESS;
}
if (NeedSyncScreen && Private->NeedSyncFrameBuffer) {
SyncScreenImage (Private, GopEntry, &InvalidateRc, &ImageIsSame);
}
if (IntersectRect (&UpdateRc, &GopEntry->Screen.ImageRc, &InvalidateRc)) {
UpdateImage (Private, GopEntry, &GopEntry->Screen, &UpdateRc, FALSE);
}
if (Private->Keyboard.Visible && IntersectRect (&UpdateRc, &Private->Keyboard.ImageRc, &InvalidateRc)) {
UpdateImage (Private, GopEntry, &Private->Keyboard, &UpdateRc, TRUE);
}
if (Private->Cursor.Visible && IntersectRect (&UpdateRc, &Private->Cursor.ImageRc, &InvalidateRc)) {
UpdateImage (Private, GopEntry, &Private->Cursor, &UpdateRc, TRUE);
}
BufferOffset = InvalidateRc.left + InvalidateRc.top * GopEntry->GraphicsOutput->Mode->Info->HorizontalResolution;
Status = GopEntry->OriginalBlt (
GopEntry->GraphicsOutput,
GopEntry->BlendBuffer + BufferOffset,
EfiBltBufferToVideo,
0,
0,
InvalidateRc.left,
InvalidateRc.top,
InvalidateRc.right - InvalidateRc.left,
InvalidateRc.bottom - InvalidateRc.top,
sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) * GopEntry->GraphicsOutput->Mode->Info->HorizontalResolution
);
SetRectEmpty (&GopEntry->InvalidateRc);
return Status;
}
/**
Render Image for All GOPs
@param [in] Private Setup mouse private data
@retval N/A
**/
VOID
RenderImageForAllGop (
IN PRIVATE_MOUSE_DATA *Private
)
{
GOP_ENTRY *GopEntry;
LIST_ENTRY *Node;
ASSERT_LOCKED (&Private->SetupMouseLock);
Node = GetFirstNode (&Private->GopList);
while (!IsNull (&Private->GopList, Node)) {
GopEntry = GOP_ENTRY_FROM_THIS (Node);
RenderImage (Private, GopEntry, TRUE);
Node = GetNextNode (&Private->GopList, Node);
}
}