GOP: Difference between revisions
[unchecked revision] | [unchecked revision] |
(Created page with "This is the new standard for UEFI that superseded VESA (BIOS) and UGA (EFI 1.0). == Graphic Output Protocol == It has basicly the same functions as VESA, you can query th...") |
|||
Line 74: | Line 74: | ||
=== Plotting Pixels === |
=== Plotting Pixels === |
||
{{Main|Drawing In Protected Mode}} |
|||
Now you can use the returned framebuffer exactly the same way as you would with VESA, there's no difference. |
Now you can use the returned framebuffer exactly the same way as you would with VESA, there's no difference. |
||
To calculate the offset for an (X,Y) coordinate, do pitch*Y+pixelbytes*X. For example for 32 bit true-color: |
To calculate the offset for an (X,Y) coordinate, do pitch*Y+pixelbytes*X. For example for 32 bit true-color: |
Revision as of 10:50, 5 August 2020
This is the new standard for UEFI that superseded VESA (BIOS) and UGA (EFI 1.0).
Graphic Output Protocol
It has basicly the same functions as VESA, you can query the modes, set the modes. You also have an efficient BitBlitter function, which you can't use from your OS unfortunately. GOP is an EFI Boot Time Service, meaning you can't access it after you call ExitBootServices().
NOTE: UEFI uses it's own ABI. You can either configure your build environment to use that globally, or you must use a wrapper function. These examples use the latter for compatibility reasons. Omit uefi_call_wrapper if you have configured your build system for the former.
Detecting GOP
As with other UEFI protocols, you have to locate a structure with the function pointers first using the protocol's GUID.
EFI_GUID gopGuid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
EFI_GRAPHICS_OUTPUT_PROTOCOL *gop;
status = uefi_call_wrapper(BS->LocateProtocol, 3, &gopGuid, NULL, (void**)&gop);
if(EFI_ERROR(status))
PrintLn(L"Unable to locate GOP");
Get the Current Mode
In order to get the mode code for the current video mode, you must set the mode first to circumvent some buggy UEFI firmware. This is done using the QueryMode function, and then gop->Mode->Mode will contain the code (this is a perfect example how badly designed UEFI is. Look: gop->Mode is a struct, while gop->Mode->Mode is a UINTN). See the QueryMode example below.
Query Available Video Modes
Similarly to VESA, there's no standard mode codes, rather you have a function to query the available modes with video card specific mode codes.
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info;
UINTN SizeOfInfo, numModes, nativeMode;
status = uefi_call_wrapper(gop->QueryMode, 4, gop, gop->Mode==NULL?0:gop->Mode->Mode, &SizeOfInfo, &info);
// this is needed to get the current video mode
if (status == EFI_NOT_STARTED)
status = uefi_call_wrapper(gop->SetMode, 2, gop, 0);
if(EFI_ERROR(status)) {
PrintLn(L"Unable to get native mode");
return status;
}
nativeMode = gop->Mode->Mode;
numModes = gop->Mode->MaxMode;
Now you know how many modes there are, and which one is currently set. You can iterate on the modes and query the information structure for each:
for (i = 0; i < numModes; i++) {
status = uefi_call_wrapper(gop->QueryMode, 4, gop, i, &SizeOfInfo, &info);
PrintLn(L"mode %03d width %d height %d format %x%s",
i,
info->HorizontalResolution,
info->VerticalResolution,
info->PixelFormat,
i == nativeMode ? "(current)" : ""
);
}
Set Video Mode and Get the Framebuffer
This is pretty easy. The mode argument is between 0 and numModes.
status = uefi_call_wrapper(gop->SetMode, 2, gop, mode);
if(EFI_ERROR(status)) {
PrintLn(L"Unable to set mode %03d", mode);
return status;
}
// get framebuffer
PrintLn(L"Framebuffer address %x size %d, width %d height %d pixelperline %d",
gop->Mode->FrameBufferBase,
gop->Mode->FrameBufferSize,
gop->Mode->Info->HorizontalResolution,
gop->Mode->Info->VerticalResolution,
gop->Mode->Info->PixelsPerScanLine
);
To get the same value as scanline in VESA (also called commonly pitch in many graphics libraries), you have to multiply PixelsPerScanLine by the number of bytes per pixel. That can be detected by examining the gop->Mode->Info->PixelFormat field. For example with 32 bit packed pixel formats,
pitch = 4 * gop->Mode->Info->PixelsPerScanLine;
Plotting Pixels
- Main article: Drawing In Protected Mode
Now you can use the returned framebuffer exactly the same way as you would with VESA, there's no difference. To calculate the offset for an (X,Y) coordinate, do pitch*Y+pixelbytes*X. For example for 32 bit true-color:
static inline void PlotPixel_32bpp(int x, int y, uint32_t pixel)
{
*((uint32_t*)(gop->Mode->FrameBufferBase + 4 * gop->Mode->Info->PixelsPerScanLine * y + 4 * x)) = pixel;
}
Don't Read From Video Memory
Reading from the video memory is slooow! Use double buffering instead.
See Also
Articles
- VESA - the former video standard
External Links
- GOP at Wikipedia
- UEFI Graphic Features at Wikipedia
- EDK2 on implementing GOP
- Intel documentation on GOP