GNU-EFI GOP How prevent flickering graphics when redrawing ?
Posted: Mon Feb 01, 2021 3:37 pm
Hello, I am drawing cursor for my os with GOP. First I clear entire screen to a color then I draw my cursor. I use a header file called gGraphicsRenderer.h for my GOP.
GraphicsRenderer.h
main.c
I see barely visible flickering when moving my cursor with mouse or arrow keys on keyboard.
What should I do to prevent this issue ?
GraphicsRenderer.h
Code: Select all
#pragma once
#include "efi_reference.h"
#include "gColor.h"
#include <stdbool.h>
//DEFINED
#define PIXEL_SCALE 1
//GRAPHICS
static EFI_STATUS GraphicsStatus;
static EFI_GRAPHICS_OUTPUT_PROTOCOL* gop;
static EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE gopMode;
static EFI_HANDLE* handles = NULL;
static UINTN HandleCount;
static EFI_HANDLE* GraphicsHandleBuffer = NULL;
static EFI_GRAPHICS_OUTPUT_BLT_PIXEL Square[PIXEL_SCALE];
static EFI_GRAPHICS_OUTPUT_BLT_PIXEL Backup[PIXEL_SCALE];
static EFI_EDID_DISCOVERED_PROTOCOL edid;
static EFI_GUID GraphicsOutputProtocolGUID = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
static EFI_UNICODE_COLLATION_PROTOCOL* mUnicodeCollation;
static EFI_GRAPHICS_OUTPUT_MODE_INFORMATION* info;
static UINTN SizeOfInfo;
static UINTN ModeCount;
static void RunGraphics() {
GraphicsStatus = gBS->LocateProtocol(&GraphicsOutputProtocolGUID, NULL, (void**)&gop);
if (EFI_ERROR(GraphicsStatus) || gop == NULL)
{
gST->ConOut->OutputString(gST->ConOut, L"Failed to init gfx!\r\n");
return GraphicsStatus;
}
gST->ConOut->ClearScreen(gST->ConOut);
// Locate all instances of GOP
GraphicsStatus = gBS->LocateHandleBuffer(ByProtocol, &gEfiGraphicsOutputProtocolGuid, NULL, &HandleCount, &GraphicsHandleBuffer);
if (EFI_ERROR(GraphicsStatus)) {
DEBUG((-1, "ShowStatus: Graphics output protocol not found\n"));
return EFI_UNSUPPORTED;
}
ModeCount = gop->Mode->MaxMode - 1;
//gop->Mode->Mode
GraphicsStatus = gop->SetMode(gop, ModeCount);
if (EFI_ERROR(GraphicsStatus)) {
gST->ConOut->OutputString(gST->ConOut, L"Failed to set default mode!\r\n");
return GraphicsStatus;
}
GraphicsStatus = gBS->LocateProtocol(&gEfiUnicodeCollationProtocolGuid, NULL, &mUnicodeCollation);
if (EFI_ERROR(GraphicsStatus))
{
Print(L"Can't Locate Protocol\n");
return GraphicsStatus;
}
gop->QueryMode(gop, gop->Mode->Mode, &SizeOfInfo, &info);
}
static void DrawCursorClassic(UINTN posX, UINTN posY, RGB* CursorColor)
{
for (UINTN i = 0; i < PIXEL_SCALE; i++)
{
Square[i].Blue = CursorColor->b;
Square[i].Green = CursorColor->g;
Square[i].Red = CursorColor->r;
Square[i].Reserved = 0x00;
}
for (int i = 0; i < 16; i++)
{
GraphicsStatus = gop->Blt(gop, &Square, EfiBltVideoFill, 0, 0, (UINTN)(posX+i), (UINTN)(posY + i), 8, 8, 0);
}
}
static void ClearScreen(RGB* Color)
{
for (UINTN i = 0; i < PIXEL_SCALE; i++)
{
Square[i].Red = Color->r;
Square[i].Green = Color->g;
Square[i].Blue = Color->b;
Square[i].Reserved = 0x00;
}
GraphicsStatus = gop->Blt(gop, &Square, EfiBltVideoFill, 0, 0, (UINTN)(0), (UINTN)(0), info->HorizontalResolution, info->VerticalResolution, 0);
}
static void DrawScene() {
for (UINTN i = 0; i < HandleCount; i++)
{
// Handle protocol
GraphicsStatus = gBS->HandleProtocol(GraphicsHandleBuffer[i], &gEfiGraphicsOutputProtocolGuid, (VOID**)&gop);
if (EFI_ERROR(GraphicsStatus))
{
DEBUG((-1, "ShowStatus: gBS->HandleProtocol[%d] returned %r\n", i, Status));
continue;
}
// Backup current image
gop->Blt(gop, Backup, EfiBltVideoToBltBuffer, 0, 0, 0, 0, PIXEL_SCALE, PIXEL_SCALE, 0);
// Draw the status square
gop->Blt(gop, Square, EfiBltBufferToVideo, 0, 0, 0, 0, PIXEL_SCALE, PIXEL_SCALE, 0);
gBS->Stall(0);
// Restore the backup
gop->Blt(gop, Backup, EfiBltBufferToVideo, 0, 0, 0, 0, PIXEL_SCALE, PIXEL_SCALE, 0);
}
}
static void PrintUnicodeText(CHAR16 *unicodeText, int fontSize, bool IsUpperCase)
{
mUnicodeCollation->SupportedLanguages = "en-us;zh-Hant;ar-EG";
Print(L"%s", unicodeText);
}
main.c
Code: Select all
// {...
//Keyboard
Events[1] = gST->ConIn->WaitForKey;
Events[0] = mouse->WaitForInput;
RunGraphics();
setCursorPosition(&cursor, info->HorizontalResolution/2, info->VerticalResolution / 2, info->HorizontalResolution, info->VerticalResolution);
RGB cursor_COLOR = {255,255,255};
RGB background_COLOR = { 0,0,0 };
while (1)
{
ClearScreen(&background_COLOR);
DrawCursorClassic(cursor.Position.X, cursor.Position.Y, &cursor_COLOR);
DrawScene(0);
UINTN index;
Status = gBS->WaitForEvent(2, &Events, &index);
// INDEX 1 IS KEYBOARD MESSAGE
if (index == 1)
{
Status = gST->ConIn->ReadKeyStroke(gST->ConIn, &Key);
if ((UINTN)Key.ScanCode == SCAN_ESC)
{
if(ESC_KEY_DOWN_COUNT == 0)
{
SystemTable->ConIn->Reset(SystemTable->ConIn, FALSE);
SystemTable->RuntimeServices->ResetSystem(EfiResetShutdown, EFI_SUCCESS, 0, NULL);
return EFI_SUCCESS;
}
ESC_KEY_DOWN_COUNT--;
}
else if ((UINTN)Key.ScanCode == SCAN_LEFT){
setCursorPosition(&cursor, cursor.Position.X -1, cursor.Position.Y, info->HorizontalResolution, info->VerticalResolution);
}
else
{
ESC_KEY_DOWN_COUNT = 2;
}
}
else if (index == 0)
{
Status = mouse->GetState(mouse, &State);
Print(L"X:%d Y:%d Z:%d L:%d R:%d\n",
State.RelativeMovementX,
State.RelativeMovementY,
State.RelativeMovementZ,
State.LeftButton,
State.RightButton
);
setCursorPosition(&cursor, cursor.Position.X + State.RelativeMovementX, cursor.Position.Y + State.RelativeMovementY, info->HorizontalResolution, info->VerticalResolution);
}
}
SystemTable->ConIn->Reset(SystemTable->ConIn, FALSE);
SystemTable->RuntimeServices->ResetSystem(EfiResetShutdown, EFI_SUCCESS, 0, NULL);
gClose();
collectGarbage();
return EFI_SUCCESS;
#if defined(_DEBUG)
// If running in debug mode, use the EFI shut down call to close QEMU
SystemTable->RuntimeServices->ResetSystem(EfiResetShutdown, EFI_SUCCESS, 0, NULL);
#endif
return EFI_SUCCESS;
}
What should I do to prevent this issue ?