18.6.3 PCI I/O CopyMem() Operations

The following examples show how scrolling a frame buffer by different methods can provide performance improvements. In the first, the scroll operation is performed using a loop to move one scan line at a time. The PCI I/O Protocol CopyMem() service is similar to the UEFI Boot Service CopyMem(), except the PCI I/O Protocol operates on PCI MMIO ranges described by PCI MMIO BARs.

In general, the PCI I/O Protocol should be used, whenever possible, to eliminate loops in the UEFI Driver. This example assumes a 1 MB frame buffer MMIO, accessed through BAR #0 of the PCI graphics controller, with a screen 800 pixels wide, and 32 bits per pixel.

In the second example, the scroll operation is performed using a single PCI I/O Protocol call to CopyMem() to produce the exact same result. The second example executes significantly faster if the UEFI Driver is compiled with an EBC compiler because the loop has been removed from the UEFI Driver.

Example 188-Scroll frame buffer using a loop
#include <Uefi.h>
#include <Protocol/PciIo.h>

EFI_STATUS Status;
EFI_PCI_IO_PROTOCOL *PciIo;
UINTN ScanLineWidth;
UINTN Index;
UINT32 Value;

//
// This is the slowest method that moves one pxiel at a time
// through the PCI I/O protocol.
//
ScanLineWidth = 800 * sizeof (UINT32);
for (Index = ScanLineWidth; Index < SIZE_1MB; Index += 4) {
  Status = PciIo->Mem.Read (
                        PciIo,                                   // This
                        EfiPciIoWidthUint32,                     // Width
                        0,                                       // BarIndex
                        Index,                                   // Offset
                        1,                                       // Count
                        &Value                                   // Buffer
                        );
  Status = PciIo->Mem.Write (
                        PciIo,                                   // This
                        EfiPciIoWidthUint32,                     // Width
                        0,                                       // Bar Index
                        Index - ScanLineWidth,                   // Offset
                        1,                                       // Count
                        &Value                                   // Buffer
                        );
}
Example 189-Scroll frame buffer without a loop
#include <Uefi.h>
#include <Protocol/PciIo.h>

EFI_STATUS Status;
EFI_PCI_IO_PROTOCOL *PciIo;
UINTN ScanLineWidth;

//
// This is the faster method that makes a single call to CopyMem().
//
ScanLineWidth = 800 * sizeof (UINT32);
Status = PciIo->CopyMem (
                  PciIo,                                        // This
                  EfiPciIoWidthUint32,                          // Width
                  0,                                            // DestBarIndex
                  0,                                            // DestOffset
                  0,                                            // SrcBarIndex
                  ScanLineWidth,                                // SrcOffset
                  (SIZE_1MB / sizeof (UINT32)) - ScanLineWidth  // Count
                  );