EmulatorPkg/Win: Use FrameBufferBltLib for BLT operation

Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Ruiyu Ni <ruiyu.ni@intel.com>
Reviewed-by: Hao Wu <hao.a.wu@intel.com>
Cc: Andrew Fish <afish@apple.com>
diff --git a/EmulatorPkg/EmulatorPkg.dsc b/EmulatorPkg/EmulatorPkg.dsc
index 9f9f7d3..ee85c9e 100644
--- a/EmulatorPkg/EmulatorPkg.dsc
+++ b/EmulatorPkg/EmulatorPkg.dsc
@@ -55,6 +55,7 @@
   PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf

   PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf

   BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf

+  FrameBufferBltLib|MdeModulePkg/Library/FrameBufferBltLib/FrameBufferBltLib.inf

 

   #

   # UEFI & PI

diff --git a/EmulatorPkg/Win/Host/WinGop.h b/EmulatorPkg/Win/Host/WinGop.h
index de27238..7843b60 100644
--- a/EmulatorPkg/Win/Host/WinGop.h
+++ b/EmulatorPkg/Win/Host/WinGop.h
@@ -31,6 +31,7 @@
 #include <Protocol/SimpleTextIn.h>

 #include <Protocol/SimpleTextInEx.h>

 #include <Protocol/GraphicsOutput.h>

+#include <Library/FrameBufferBltLib.h>

 

 //

 // WM_SYSKEYDOWN/WM_SYSKEYUP Notification

@@ -86,9 +87,8 @@
   // updated in the main thread and displayed in the windows thread.

   //

   BITMAPV4HEADER                *VirtualScreenInfo;

-  RGBQUAD                       *VirtualScreen;

 

-  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *FillLine;

+  FRAME_BUFFER_CONFIGURE        *FrameBufferConfigure;

 

   //

   // Keyboard Queue used by Simple Text In.

diff --git a/EmulatorPkg/Win/Host/WinGopScreen.c b/EmulatorPkg/Win/Host/WinGopScreen.c
index 2ca51d2..0e1f1ff 100644
--- a/EmulatorPkg/Win/Host/WinGopScreen.c
+++ b/EmulatorPkg/Win/Host/WinGopScreen.c
@@ -1,6 +1,6 @@
 /** @file

 

-Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>

+Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>

 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

@@ -193,15 +193,63 @@
   IN  UINT32                        Height

 )

 {

-  UINT32                            Size;

-  GRAPHICS_PRIVATE_DATA             *Private;

-  RECT                              Rect;

-  EFI_GRAPHICS_OUTPUT_BLT_PIXEL     *NewFillLine;

+  RETURN_STATUS                        RStatus;

+  EFI_GRAPHICS_OUTPUT_MODE_INFORMATION Info;

+  GRAPHICS_PRIVATE_DATA                *Private;

+  RECT                                 Rect;

+  BITMAPV4HEADER                       *VirtualScreenInfo;

+  FRAME_BUFFER_CONFIGURE               *FrameBufferConfigure;

+  UINTN                                FrameBufferConfigureSize;

 

   Private = GRAPHICS_PRIVATE_DATA_FROM_THIS (GraphicsIo);

-  Private->Width  = Width;

-  Private->Height = Height;

 

+  //

+  // Allocate DIB frame buffer directly from NT for performance enhancement

+  // This buffer is the virtual screen/frame buffer.

+  //

+  VirtualScreenInfo = HeapAlloc (

+    GetProcessHeap (),

+    HEAP_ZERO_MEMORY,

+    Width * Height * sizeof (RGBQUAD) + sizeof (BITMAPV4HEADER)

+  );

+  if (VirtualScreenInfo == NULL) {

+    return EFI_OUT_OF_RESOURCES;

+  }

+

+  //

+  // Update the virtual screen info data structure

+  // Use negative Height to make sure screen/buffer are using the same coordinate.

+  //

+  VirtualScreenInfo->bV4Size = sizeof (BITMAPV4HEADER);

+  VirtualScreenInfo->bV4Width = Width;

+  VirtualScreenInfo->bV4Height = -(LONG)Height;

+  VirtualScreenInfo->bV4Planes = 1;

+  VirtualScreenInfo->bV4BitCount = 32;

+  //

+  // uncompressed

+  //

+  VirtualScreenInfo->bV4V4Compression = BI_RGB;

+

+  Info.HorizontalResolution = Width;

+  Info.VerticalResolution   = Height;

+  Info.PixelFormat          = PixelBlueGreenRedReserved8BitPerColor;

+  Info.PixelsPerScanLine    = Width;

+  FrameBufferConfigureSize  = 0;

+  RStatus = FrameBufferBltConfigure (VirtualScreenInfo + 1, &Info, NULL, &FrameBufferConfigureSize);

+  ASSERT (RStatus == EFI_BUFFER_TOO_SMALL);

+  FrameBufferConfigure = AllocatePool (FrameBufferConfigureSize);

+  if (FrameBufferConfigure == NULL) {

+    HeapFree (GetProcessHeap (), 0, VirtualScreenInfo);

+    return EFI_OUT_OF_RESOURCES;

+  }

+  RStatus = FrameBufferBltConfigure (VirtualScreenInfo + 1, &Info, FrameBufferConfigure, &FrameBufferConfigureSize);

+  ASSERT_RETURN_ERROR (RStatus);

+

+

+  if (Private->FrameBufferConfigure != NULL) {

+    FreePool (Private->FrameBufferConfigure);

+  }

+  Private->FrameBufferConfigure = FrameBufferConfigure;

 

   //

   // Free the old buffer. We do not save the content of the old buffer since the

@@ -211,46 +259,19 @@
   if (Private->VirtualScreenInfo != NULL) {

     HeapFree (GetProcessHeap (), 0, Private->VirtualScreenInfo);

   }

+  Private->VirtualScreenInfo = VirtualScreenInfo;

 

-  //

-  // Allocate DIB frame buffer directly from NT for performance enhancement

-  // This buffer is the virtual screen/frame buffer. This buffer is not the

-  // same a a frame buffer. The first row of this buffer will be the bottom

-  // line of the image. This is an artifact of the way we draw to the screen.

-  //

-  Size = Private->Width * Private->Height * sizeof (RGBQUAD) + sizeof (BITMAPV4HEADER);

-  Private->VirtualScreenInfo = HeapAlloc (

-    GetProcessHeap (),

-    HEAP_ZERO_MEMORY,

-    Size

-  );

-

-  //

-  // Update the virtual screen info data structure

-  //

-  Private->VirtualScreenInfo->bV4Size = sizeof (BITMAPV4HEADER);

-  Private->VirtualScreenInfo->bV4Width = Private->Width;

-  Private->VirtualScreenInfo->bV4Height = Private->Height;

-  Private->VirtualScreenInfo->bV4Planes = 1;

-  Private->VirtualScreenInfo->bV4BitCount = 32;

-  //

-  // uncompressed

-  //

-  Private->VirtualScreenInfo->bV4V4Compression = BI_RGB;

-

-  //

-  // The rest of the allocated memory block is the virtual screen buffer

-  //

-  Private->VirtualScreen = (RGBQUAD *)(Private->VirtualScreenInfo + 1);

+  Private->Width  = Width;

+  Private->Height = Height;

 

   //

   // Use the AdjuctWindowRect fuction to calculate the real width and height

   // of the new window including the border and caption

   //

-  Rect.left = 0;

-  Rect.top = 0;

-  Rect.right = Private->Width;

-  Rect.bottom = Private->Height;

+  Rect.left   = 0;

+  Rect.top    = 0;

+  Rect.right  = Width;

+  Rect.bottom = Height;

 

   AdjustWindowRect (&Rect, WS_OVERLAPPEDWINDOW, 0);

 

@@ -267,16 +288,6 @@
   //

   MoveWindow (Private->WindowHandle, Rect.left, Rect.top, (INT32)Width, (INT32)Height, TRUE);

 

-  NewFillLine = AllocatePool (sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) * Private->Width);

-  if (NewFillLine == NULL) {

-    return EFI_DEVICE_ERROR;

-  }

-

-  if (Private->FillLine != NULL) {

-    FreePool (Private->FillLine);

-  }

-

-  Private->FillLine = NewFillLine;

   return EFI_SUCCESS;

 }

 

@@ -322,68 +333,22 @@
   IN  EMU_GRAPHICS_WINDOWS__BLT_ARGS          *Args

 )

 {

+  RETURN_STATUS                 RStatus;

   GRAPHICS_PRIVATE_DATA         *Private;

-  UINTN                         DstY;

-  UINTN                         SrcY;

-  RGBQUAD                       *VScreen;

-  RGBQUAD                       *VScreenSrc;

-  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;

-  UINTN                         Index;

   RECT                          Rect;

-  EFI_GRAPHICS_OUTPUT_BLT_PIXEL *FillPixel;

-  UINT32                        VerticalResolution;

-  UINT32                        HorizontalResolution;

 

   Private = GRAPHICS_PRIVATE_DATA_FROM_THIS (GraphicsIo);

-

-  //

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

-  //

-  VerticalResolution = Private->VirtualScreenInfo->bV4Height;

-  HorizontalResolution = Private->VirtualScreenInfo->bV4Width;

-  if (BltOperation == EfiBltVideoToBltBuffer) {

-

-    for (SrcY = Args->SourceY, DstY = Args->DestinationY; DstY < (Args->Height + Args->DestinationY); SrcY++, DstY++) {

-      Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) ((UINT8 *) BltBuffer + (DstY * Args->Delta) + Args->DestinationX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));

-      VScreen = &Private->VirtualScreen[(VerticalResolution - SrcY - 1) * HorizontalResolution + Args->SourceX];

-      CopyMem (Blt, VScreen, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) * Args->Width);

-    }

-  } else {

-    if (BltOperation == EfiBltVideoFill) {

-      FillPixel = BltBuffer;

-      for (Index = 0; Index < Args->Width; Index++) {

-        Private->FillLine[Index] = *FillPixel;

-      }

-    }

-

-    for (Index = 0; Index < Args->Height; Index++) {

-      if (Args->DestinationY <= Args->SourceY) {

-        SrcY  = Args->SourceY + Index;

-        DstY  = Args->DestinationY + Index;

-      } else {

-        SrcY  = Args->SourceY + Args->Height - Index - 1;

-        DstY  = Args->DestinationY + Args->Height - Index - 1;

-      }

-

-      VScreen = &Private->VirtualScreen[(VerticalResolution - DstY - 1) * HorizontalResolution + Args->DestinationX];

-      switch (BltOperation) {

-      case EfiBltBufferToVideo:

-        Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) ((UINT8 *) BltBuffer + (SrcY * Args->Delta) + Args->SourceX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));

-        CopyMem (VScreen, Blt, Args->Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));

-        break;

-

-      case EfiBltVideoToVideo:

-        VScreenSrc = &Private->VirtualScreen[(VerticalResolution - SrcY - 1) * HorizontalResolution + Args->SourceX];

-        CopyMem (VScreen, VScreenSrc, Args->Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));

-        break;

-

-      case EfiBltVideoFill:

-        CopyMem (VScreen, Private->FillLine, Args->Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));

-        break;

-      }

-    }

+  RStatus = FrameBufferBlt (

+              Private->FrameBufferConfigure,

+              BltBuffer,

+              BltOperation,

+              Args->SourceX, Args->SourceY,

+              Args->DestinationX, Args->DestinationY,

+              Args->Width, Args->Height,

+              Args->Delta

+              );

+  if (RETURN_ERROR (RStatus)) {

+    return (EFI_STATUS)RStatus;

   }

 

   if (BltOperation != EfiBltVideoToBltBuffer) {

@@ -435,7 +400,6 @@
   )

 {

   GRAPHICS_PRIVATE_DATA *Private;

-  UINTN                 Size;

   HDC                   Handle;

   PAINTSTRUCT           PaintStruct;

   LPARAM                Index;

@@ -443,14 +407,6 @@
   BOOLEAN               AltIsPress;

 

   //

-  // BugBug - if there are two instances of this DLL in memory (such as is

-  // the case for ERM), the correct instance of this function may not be called.

-  // This also means that the address of the mTlsIndex value will be wrong, and

-  // the value may be wrong too.

-  //

-

-

-  //

   // Use mTlsIndex global to get a Thread Local Storage version of Private.

   // This works since each Gop protocol has a unique Private data instance and

   // a unique thread.

@@ -460,39 +416,7 @@
   ASSERT (NULL != Private);

 

   switch (iMsg) {

-  case WM_CREATE:

-    Size = Private->Width * Private->Height * sizeof (RGBQUAD);

-

-    //

-    // Allocate DIB frame buffer directly from NT for performance enhancement

-    // This buffer is the virtual screen/frame buffer. This buffer is not the

-    // same a a frame buffer. The first fow of this buffer will be the bottom

-    // line of the image. This is an artifact of the way we draw to the screen.

-    //

-    Private->VirtualScreenInfo = HeapAlloc (

-                                   GetProcessHeap (),

-                                   HEAP_ZERO_MEMORY,

-                                   Size

-                                   );

-

-    Private->VirtualScreenInfo->bV4Size           = sizeof (BITMAPV4HEADER);

-    Private->VirtualScreenInfo->bV4Width          = Private->Width;

-    Private->VirtualScreenInfo->bV4Height         = Private->Height;

-    Private->VirtualScreenInfo->bV4Planes         = 1;

-    Private->VirtualScreenInfo->bV4BitCount       = 32;

-    //

-    // uncompressed

-    //

-    Private->VirtualScreenInfo->bV4V4Compression  = BI_RGB;

-    Private->VirtualScreen = (RGBQUAD *) (Private->VirtualScreenInfo + 1);

-    return 0;

-

   case WM_PAINT:

-    //

-    // I have not found a way to convert hwnd into a Private context. So for

-    // now we use this API to convert hwnd to Private data.

-    //

-

     Handle = BeginPaint (hwnd, &PaintStruct);

 

     SetDIBitsToDevice (

@@ -505,7 +429,7 @@
       0,                                          // Source Y

       0,                                          // DIB Start Scan Line

       Private->Height,                            // Number of scan lines

-      Private->VirtualScreen,                     // Address of array of DIB bits

+      Private->VirtualScreenInfo + 1,             // Address of array of DIB bits

       (BITMAPINFO *) Private->VirtualScreenInfo,  // Address of structure with bitmap info

       DIB_RGB_COLORS                              // RGB or palette indexes

       );

@@ -691,10 +615,6 @@
   // This call will fail after the first time, but thats O.K. since we only need

   // WIN_NT_GOP_CLASS_NAME to exist to create the window.

   //

-  // Note: Multiple instances of this DLL will use the same instance of this

-  // Class, including the callback function, unless the Class is unregistered and

-  // successfully registered again.

-  //

   RegisterClassEx (&Private->WindowsClass);

 

   //

diff --git a/EmulatorPkg/Win/Host/WinHost.inf b/EmulatorPkg/Win/Host/WinHost.inf
index 501edac..940f24d 100644
--- a/EmulatorPkg/Win/Host/WinHost.inf
+++ b/EmulatorPkg/Win/Host/WinHost.inf
@@ -56,6 +56,7 @@
   ThunkProtocolList

   PpiListLib

   PeiServicesLib

+  FrameBufferBltLib

 

 [Ppis]

   gEmuThunkPpiGuid