Home | History | Annotate | Download | only in LcdGraphicsOutputDxe
      1 /** @file
      2 
      3  Copyright (c) 2011, ARM Ltd. All rights reserved.<BR>
      4  This program and the accompanying materials
      5  are licensed and made available under the terms and conditions of the BSD License
      6  which accompanies this distribution.  The full text of the license may be found at
      7  http://opensource.org/licenses/bsd-license.php
      8 
      9  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     10  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     11 
     12  **/
     13 
     14 #include <PiDxe.h>
     15 #include <Library/BaseMemoryLib.h>
     16 #include <Library/DevicePathLib.h>
     17 #include <Library/UefiBootServicesTableLib.h>
     18 #include <Library/UefiRuntimeServicesTableLib.h>
     19 #include <Library/MemoryAllocationLib.h>
     20 
     21 #include <Guid/GlobalVariable.h>
     22 
     23 #include "LcdGraphicsOutputDxe.h"
     24 
     25 extern BOOLEAN mDisplayInitialized;
     26 
     27 //
     28 // Function Definitions
     29 //
     30 
     31 STATIC
     32 EFI_STATUS
     33 VideoCopyNoHorizontalOverlap (
     34   IN UINTN          BitsPerPixel,
     35   IN volatile VOID  *FrameBufferBase,
     36   IN UINT32         HorizontalResolution,
     37   IN UINTN          SourceX,
     38   IN UINTN          SourceY,
     39   IN UINTN          DestinationX,
     40   IN UINTN          DestinationY,
     41   IN UINTN          Width,
     42   IN UINTN          Height
     43   )
     44 {
     45   EFI_STATUS    Status = EFI_SUCCESS;
     46   UINTN         SourceLine;
     47   UINTN         DestinationLine;
     48   UINTN         WidthInBytes;
     49   UINTN         LineCount;
     50   INTN          Step;
     51   VOID          *SourceAddr;
     52   VOID          *DestinationAddr;
     53 
     54   if( DestinationY <= SourceY ) {
     55     // scrolling up (or horizontally but without overlap)
     56     SourceLine       = SourceY;
     57     DestinationLine  = DestinationY;
     58     Step             = 1;
     59   } else {
     60     // scrolling down
     61     SourceLine       = SourceY + Height;
     62     DestinationLine  = DestinationY + Height;
     63     Step             = -1;
     64   }
     65 
     66   WidthInBytes = Width * 2;
     67 
     68   for( LineCount = 0; LineCount < Height; LineCount++ ) {
     69     // Update the start addresses of source & destination using 16bit pointer arithmetic
     70     SourceAddr      = (VOID *)((UINT16 *)FrameBufferBase + SourceLine      * HorizontalResolution + SourceX     );
     71     DestinationAddr = (VOID *)((UINT16 *)FrameBufferBase + DestinationLine * HorizontalResolution + DestinationX);
     72 
     73     // Copy the entire line Y from video ram to the temp buffer
     74     CopyMem( DestinationAddr, SourceAddr, WidthInBytes);
     75 
     76     // Update the line numbers
     77     SourceLine      += Step;
     78     DestinationLine += Step;
     79   }
     80 
     81   return Status;
     82 }
     83 
     84 STATIC
     85 EFI_STATUS
     86 VideoCopyHorizontalOverlap (
     87   IN UINTN          BitsPerPixel,
     88   IN volatile VOID  *FrameBufferBase,
     89   UINT32            HorizontalResolution,
     90   IN UINTN          SourceX,
     91   IN UINTN          SourceY,
     92   IN UINTN          DestinationX,
     93   IN UINTN          DestinationY,
     94   IN UINTN          Width,
     95   IN UINTN          Height
     96   )
     97 {
     98   EFI_STATUS      Status = EFI_SUCCESS;
     99 
    100   UINT16 *PixelBuffer16bit;
    101   UINT16 *SourcePixel16bit;
    102   UINT16 *DestinationPixel16bit;
    103 
    104   UINT32          SourcePixelY;
    105   UINT32          DestinationPixelY;
    106   UINTN           SizeIn16Bits;
    107 
    108   // Allocate a temporary buffer
    109   PixelBuffer16bit = (UINT16 *) AllocatePool((Height * Width) * sizeof(UINT16));
    110 
    111   if (PixelBuffer16bit == NULL) {
    112     Status = EFI_OUT_OF_RESOURCES;
    113     goto EXIT;
    114   }
    115 
    116   // Access each pixel inside the source area of the Video Memory and copy it to the temp buffer
    117 
    118   SizeIn16Bits = Width * 2;
    119 
    120   for (SourcePixelY = SourceY, DestinationPixel16bit = PixelBuffer16bit;
    121        SourcePixelY < SourceY + Height;
    122        SourcePixelY++, DestinationPixel16bit += Width)
    123   {
    124     // Calculate the source address:
    125     SourcePixel16bit = (UINT16 *)FrameBufferBase + SourcePixelY * HorizontalResolution + SourceX;
    126 
    127     // Copy the entire line Y from Video to the temp buffer
    128     CopyMem( (VOID *)DestinationPixel16bit, (CONST VOID *)SourcePixel16bit, SizeIn16Bits);
    129   }
    130 
    131   // Copy from the temp buffer into the destination area of the Video Memory
    132 
    133   for (DestinationPixelY = DestinationY, SourcePixel16bit = PixelBuffer16bit;
    134        DestinationPixelY < DestinationY + Height;
    135        DestinationPixelY++, SourcePixel16bit += Width)
    136   {
    137     // Calculate the target address:
    138     DestinationPixel16bit = (UINT16 *)FrameBufferBase + (DestinationPixelY * HorizontalResolution + DestinationX);
    139 
    140     // Copy the entire line Y from the temp buffer to Video
    141     CopyMem( (VOID *)DestinationPixel16bit, (CONST VOID *)SourcePixel16bit, SizeIn16Bits);
    142   }
    143 
    144   // Free the allocated memory
    145   FreePool((VOID *) PixelBuffer16bit);
    146 
    147 
    148 EXIT:
    149   return Status;
    150 }
    151 
    152 STATIC
    153 EFI_STATUS
    154 BltVideoFill (
    155   IN EFI_GRAPHICS_OUTPUT_PROTOCOL        *This,
    156   IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL   *EfiSourcePixel,     OPTIONAL
    157   IN UINTN                               SourceX,
    158   IN UINTN                               SourceY,
    159   IN UINTN                               DestinationX,
    160   IN UINTN                               DestinationY,
    161   IN UINTN                               Width,
    162   IN UINTN                               Height,
    163   IN UINTN                               Delta           OPTIONAL   // Number of BYTES in a row of the BltBuffer
    164   )
    165 {
    166   EFI_PIXEL_BITMASK*  PixelInformation;
    167   EFI_STATUS          Status;
    168   UINT32              HorizontalResolution;
    169   VOID                *FrameBufferBase;
    170   UINT16              *DestinationPixel16bit;
    171   UINT16              Pixel16bit;
    172   UINT32              DestinationPixelX;
    173   UINT32              DestinationLine;
    174 
    175   Status           = EFI_SUCCESS;
    176   PixelInformation = &This->Mode->Info->PixelInformation;
    177   FrameBufferBase = (UINTN *)((UINTN)(This->Mode->FrameBufferBase));
    178   HorizontalResolution = This->Mode->Info->HorizontalResolution;
    179 
    180   // Convert the EFI pixel at the start of the BltBuffer(0,0) into a video display pixel
    181   Pixel16bit = (UINT16) (
    182       ( (EfiSourcePixel->Red      <<  8) & PixelInformation->RedMask      )
    183     | ( (EfiSourcePixel->Green    <<  3) & PixelInformation->GreenMask    )
    184     | ( (EfiSourcePixel->Blue     >>  3) & PixelInformation->BlueMask     )
    185    );
    186 
    187   // Copy the SourcePixel into every pixel inside the target rectangle
    188   for (DestinationLine = DestinationY;
    189        DestinationLine < DestinationY + Height;
    190        DestinationLine++)
    191   {
    192     for (DestinationPixelX = DestinationX;
    193          DestinationPixelX < DestinationX + Width;
    194          DestinationPixelX++)
    195     {
    196       // Calculate the target address:
    197       DestinationPixel16bit =  (UINT16 *)FrameBufferBase + DestinationLine * HorizontalResolution  + DestinationPixelX;
    198 
    199       // Copy the pixel into the new target
    200       *DestinationPixel16bit = Pixel16bit;
    201     }
    202   }
    203 
    204 
    205   return Status;
    206 }
    207 
    208 STATIC
    209 EFI_STATUS
    210 BltVideoToBltBuffer (
    211   IN EFI_GRAPHICS_OUTPUT_PROTOCOL        *This,
    212   IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL   *BltBuffer,     OPTIONAL
    213   IN UINTN                               SourceX,
    214   IN UINTN                               SourceY,
    215   IN UINTN                               DestinationX,
    216   IN UINTN                               DestinationY,
    217   IN UINTN                               Width,
    218   IN UINTN                               Height,
    219   IN UINTN                               Delta           OPTIONAL   // Number of BYTES in a row of the BltBuffer
    220   )
    221 {
    222   EFI_STATUS         Status;
    223   UINT32             HorizontalResolution;
    224   EFI_PIXEL_BITMASK  *PixelInformation;
    225   EFI_GRAPHICS_OUTPUT_BLT_PIXEL *EfiDestinationPixel;
    226   VOID               *FrameBufferBase;
    227   UINT16             *SourcePixel16bit;
    228   UINT16             Pixel16bit;
    229   UINT32             SourcePixelX;
    230   UINT32             SourceLine;
    231   UINT32             DestinationPixelX;
    232   UINT32             DestinationLine;
    233   UINT32             BltBufferHorizontalResolution;
    234 
    235   Status = EFI_SUCCESS;
    236   PixelInformation = &This->Mode->Info->PixelInformation;
    237   HorizontalResolution = This->Mode->Info->HorizontalResolution;
    238   FrameBufferBase = (UINTN *)((UINTN)(This->Mode->FrameBufferBase));
    239 
    240   if(( Delta != 0 ) && ( Delta != Width * sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL))) {
    241     // Delta is not zero and it is different from the width.
    242     // Divide it by the size of a pixel to find out the buffer's horizontal resolution.
    243     BltBufferHorizontalResolution = (UINT32) (Delta / sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
    244   } else {
    245     BltBufferHorizontalResolution = Width;
    246   }
    247 
    248   // Access each pixel inside the Video Memory
    249   for (SourceLine = SourceY, DestinationLine = DestinationY;
    250        SourceLine < SourceY + Height;
    251        SourceLine++, DestinationLine++)
    252   {
    253     for (SourcePixelX = SourceX, DestinationPixelX = DestinationX;
    254          SourcePixelX < SourceX + Width;
    255          SourcePixelX++, DestinationPixelX++)
    256     {
    257       // Calculate the source and target addresses:
    258       SourcePixel16bit = (UINT16 *)FrameBufferBase + SourceLine * HorizontalResolution + SourcePixelX;
    259       EfiDestinationPixel = BltBuffer + DestinationLine * BltBufferHorizontalResolution + DestinationPixelX;
    260 
    261       // Snapshot the pixel from the video buffer once, to speed up the operation.
    262       // If we were dereferencing the pointer, as it is volatile, we would perform 3 memory read operations.
    263       Pixel16bit = *SourcePixel16bit;
    264 
    265       // Copy the pixel into the new target
    266       EfiDestinationPixel->Red      = (UINT8) ( (Pixel16bit & PixelInformation->RedMask     ) >>  8 );
    267       EfiDestinationPixel->Green    = (UINT8) ( (Pixel16bit & PixelInformation->GreenMask   ) >>  3 );
    268       EfiDestinationPixel->Blue     = (UINT8) ( (Pixel16bit & PixelInformation->BlueMask    ) <<  3 );
    269     }
    270   }
    271 
    272   return Status;
    273 }
    274 
    275 STATIC
    276 EFI_STATUS
    277 BltBufferToVideo (
    278   IN EFI_GRAPHICS_OUTPUT_PROTOCOL        *This,
    279   IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL   *BltBuffer,     OPTIONAL
    280   IN UINTN                               SourceX,
    281   IN UINTN                               SourceY,
    282   IN UINTN                               DestinationX,
    283   IN UINTN                               DestinationY,
    284   IN UINTN                               Width,
    285   IN UINTN                               Height,
    286   IN UINTN                               Delta           OPTIONAL   // Number of BYTES in a row of the BltBuffer
    287   )
    288 {
    289   EFI_STATUS         Status;
    290   UINT32             HorizontalResolution;
    291   EFI_PIXEL_BITMASK  *PixelInformation;
    292   EFI_GRAPHICS_OUTPUT_BLT_PIXEL *EfiSourcePixel;
    293   VOID               *FrameBufferBase;
    294   UINT16             *DestinationPixel16bit;
    295   UINT32             SourcePixelX;
    296   UINT32             SourceLine;
    297   UINT32             DestinationPixelX;
    298   UINT32             DestinationLine;
    299   UINT32             BltBufferHorizontalResolution;
    300 
    301   Status = EFI_SUCCESS;
    302   PixelInformation = &This->Mode->Info->PixelInformation;
    303   HorizontalResolution = This->Mode->Info->HorizontalResolution;
    304   FrameBufferBase = (UINTN *)((UINTN)(This->Mode->FrameBufferBase));
    305 
    306   if(( Delta != 0 ) && ( Delta != Width * sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL))) {
    307     // Delta is not zero and it is different from the width.
    308     // Divide it by the size of a pixel to find out the buffer's horizontal resolution.
    309     BltBufferHorizontalResolution = (UINT32) (Delta / sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
    310   } else {
    311     BltBufferHorizontalResolution = Width;
    312   }
    313 
    314   // Access each pixel inside the BltBuffer Memory
    315   for (SourceLine = SourceY, DestinationLine = DestinationY;
    316        SourceLine < SourceY + Height;
    317        SourceLine++, DestinationLine++) {
    318 
    319     for (SourcePixelX = SourceX, DestinationPixelX = DestinationX;
    320          SourcePixelX < SourceX + Width;
    321          SourcePixelX++, DestinationPixelX++)
    322     {
    323       // Calculate the source and target addresses:
    324       EfiSourcePixel  = BltBuffer + SourceLine * BltBufferHorizontalResolution + SourcePixelX;
    325       DestinationPixel16bit = (UINT16 *)FrameBufferBase + DestinationLine * HorizontalResolution + DestinationPixelX;
    326 
    327       // Copy the pixel into the new target
    328       // Only the most significant bits will be copied across:
    329       // To convert from 8 bits to 5 bits per pixel we throw away the 3 least significant bits
    330         *DestinationPixel16bit = (UINT16) (
    331               ( (EfiSourcePixel->Red      <<  8) & PixelInformation->RedMask      )
    332             | ( (EfiSourcePixel->Green    <<  3) & PixelInformation->GreenMask    )
    333             | ( (EfiSourcePixel->Blue     >>  3) & PixelInformation->BlueMask     )
    334             );
    335       }
    336     }
    337 
    338   return Status;
    339 }
    340 
    341 STATIC
    342 EFI_STATUS
    343 BltVideoToVideo (
    344   IN EFI_GRAPHICS_OUTPUT_PROTOCOL        *This,
    345   IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL   *BltBuffer,     OPTIONAL
    346   IN UINTN                               SourceX,
    347   IN UINTN                               SourceY,
    348   IN UINTN                               DestinationX,
    349   IN UINTN                               DestinationY,
    350   IN UINTN                               Width,
    351   IN UINTN                               Height,
    352   IN UINTN                               Delta           OPTIONAL   // Number of BYTES in a row of the BltBuffer
    353   )
    354 {
    355   EFI_STATUS         Status;
    356   UINT32             HorizontalResolution;
    357   UINTN              BitsPerPixel;
    358   VOID               *FrameBufferBase;
    359 
    360   BitsPerPixel = 16;
    361 
    362   HorizontalResolution = This->Mode->Info->HorizontalResolution;
    363   FrameBufferBase = (UINTN *)((UINTN)(This->Mode->FrameBufferBase));
    364 
    365   //
    366   // BltVideo to BltVideo:
    367   //
    368   //  Source is the Video Memory,
    369   //  Destination is the Video Memory
    370 
    371   FrameBufferBase = (UINTN *)((UINTN)(This->Mode->FrameBufferBase));
    372 
    373   // The UEFI spec currently states:
    374   // "There is no limitation on the overlapping of the source and destination rectangles"
    375   // Therefore, we must be careful to avoid overwriting the source data
    376   if( SourceY == DestinationY ) {
    377     // Copying within the same height, e.g. horizontal shift
    378     if( SourceX == DestinationX ) {
    379       // Nothing to do
    380       Status = EFI_SUCCESS;
    381     } else if( ((SourceX>DestinationX)?(SourceX - DestinationX):(DestinationX - SourceX)) < Width ) {
    382       // There is overlap
    383       Status = VideoCopyHorizontalOverlap (BitsPerPixel, FrameBufferBase, HorizontalResolution, SourceX, SourceY, DestinationX, DestinationY, Width, Height );
    384     } else {
    385       // No overlap
    386       Status = VideoCopyNoHorizontalOverlap (BitsPerPixel, FrameBufferBase, HorizontalResolution, SourceX, SourceY, DestinationX, DestinationY, Width, Height );
    387     }
    388   } else {
    389     // Copying from different heights
    390     Status = VideoCopyNoHorizontalOverlap (BitsPerPixel, FrameBufferBase, HorizontalResolution, SourceX, SourceY, DestinationX, DestinationY, Width, Height );
    391   }
    392 
    393   return Status;
    394 }
    395 
    396 EFI_STATUS
    397 EFIAPI
    398 LcdGraphicsBlt (
    399   IN EFI_GRAPHICS_OUTPUT_PROTOCOL        *This,
    400   IN OUT EFI_GRAPHICS_OUTPUT_BLT_PIXEL   *BltBuffer,     OPTIONAL
    401   IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION   BltOperation,
    402   IN UINTN                               SourceX,
    403   IN UINTN                               SourceY,
    404   IN UINTN                               DestinationX,
    405   IN UINTN                               DestinationY,
    406   IN UINTN                               Width,
    407   IN UINTN                               Height,
    408   IN UINTN                               Delta           OPTIONAL   // Number of BYTES in a row of the BltBuffer
    409   )
    410 {
    411   EFI_STATUS    Status;
    412   LCD_INSTANCE  *Instance;
    413 
    414   Instance = LCD_INSTANCE_FROM_GOP_THIS(This);
    415 
    416   if (!mDisplayInitialized) {
    417     InitializeDisplay (Instance);
    418   }
    419 
    420   switch (BltOperation) {
    421   case EfiBltVideoFill:
    422     Status = BltVideoFill (This, BltBuffer, SourceX, SourceY, DestinationX, DestinationY, Width, Height, Delta);
    423     break;
    424 
    425   case EfiBltVideoToBltBuffer:
    426     Status = BltVideoToBltBuffer (This, BltBuffer, SourceX, SourceY, DestinationX, DestinationY, Width, Height, Delta);
    427     break;
    428 
    429   case EfiBltBufferToVideo:
    430     Status = BltBufferToVideo (This, BltBuffer, SourceX, SourceY, DestinationX, DestinationY, Width, Height, Delta);
    431     break;
    432 
    433   case EfiBltVideoToVideo:
    434     Status = BltVideoToVideo (This, BltBuffer, SourceX, SourceY, DestinationX, DestinationY, Width, Height, Delta);
    435     break;
    436 
    437   case EfiGraphicsOutputBltOperationMax:
    438   default:
    439     DEBUG((DEBUG_ERROR, "LcdGraphicsBlt: Invalid Operation\n"));
    440     Status = EFI_INVALID_PARAMETER;
    441     break;
    442 }
    443 
    444   return Status;
    445 }
    446