UEFI Unable to write correctly to the screen with GOP buffer

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
Cathedox
Posts: 1
Joined: Fri Aug 19, 2022 8:59 am

UEFI Unable to write correctly to the screen with GOP buffer

Post by Cathedox »

Hello, I have a problem that i don't know how to resolve. I'm trying to draw some icon to the screen using the BMP format in my UEFI boot loader using the base address of the GOP buffer. The problem is that the results are completely incoherent on a particular resolution (1366x768) my code is completely dynamic depending on the resolutions and work perfectly fine on other resolutions. Does anyone have an idea on what the problem could be?

Code: Select all

VOID RenderBitmapImage(IN GRAPHICS_INFO* GraphicsInfo, IN BITMAP_IMAGE* Image, UINT32 x, UINT32 y) {
    // Some pointer verifications to prevent any fault
    if (GraphicsInfo == NULL)
        return;
    if (Image == NULL)
        return;
    if (Image->Header == NULL || Image->Info == NULL || Image->PixelData == NULL)
        return;
    
    // Check if x and y are in the buffer
    if (x > GraphicsInfo->PixelsPerScanLine)
        return;
    if (y > GraphicsInfo->VerticalResolution)
        return;

    // Safer and easier to use typed pointers
    BITMAP_PIXEL_DATA_32BPP* ImagePixelData = (BITMAP_PIXEL_DATA_32BPP*)Image->PixelData;
    UINT8* FrameBufferAddr = (UINT8*)GraphicsInfo->BufferBaseAddress;
    UINT8* FremeBufferMaxAddr =FrameBufferAddr + GraphicsInfo->BufferSize;

    //Offsetting address at the x and y position
    //Don't be confused it's only algebraic distribution of PixelSize
    FrameBufferAddr += GraphicsInfo->PixelSize * (x + (y * GraphicsInfo->PixelsPerScanLine));

    //Offsetting address so the image is drawn from bottom to top
    FrameBufferAddr += Image->Info->Height * GraphicsInfo->PixelsPerScanLine * GraphicsInfo->PixelSize;

    //Use of local variable to enhance performances
    UINT8 PixelFormat = GraphicsInfo->PixelFormat;

    // for each line of pixels in the image, every pixel in the line is converted to the correct PixelFormat and drawn to the screen
    for (UINT32 h = 0; h < Image->Info->Height; h++) {
        for (UINT32 w = 0; w < Image->Info->Width; w++, ImagePixelData++, FrameBufferAddr += GraphicsInfo->PixelSize) {
            if (FrameBufferAddr > FremeBufferMaxAddr) {
                break;
            }

            if (PixelFormat == 1) { // Format is RedGreenBlueReserved 8bit per color
                PIXEL_32BPP_RGBReserved* FrameBufferPixelData = (PIXEL_32BPP_RGBReserved*)FrameBufferAddr;
                FrameBufferPixelData->Red = ImagePixelData->Red;
                FrameBufferPixelData->Green = ImagePixelData->Green;
                FrameBufferPixelData->Blue = ImagePixelData->Blue;
            } else if (PixelFormat == 2) { // Format is BlueGreenRedReserved 8bit per color
                PIXEL_32BPP_BGRReserved* FrameBufferPixelData = (PIXEL_32BPP_BGRReserved*)FrameBufferAddr;
                FrameBufferPixelData->Red = ImagePixelData->Red;
                FrameBufferPixelData->Green = ImagePixelData->Green;
                FrameBufferPixelData->Blue = ImagePixelData->Blue;
            }
        }
        FrameBufferAddr -= Image->Info->Width * GraphicsInfo->PixelSize;
        FrameBufferAddr -= GraphicsInfo->PixelsPerScanLine * GraphicsInfo->PixelSize;
    }
Octocontrabass
Member
Member
Posts: 5563
Joined: Mon Mar 25, 2013 7:01 pm

Re: UEFI Unable to write correctly to the screen with GOP bu

Post by Octocontrabass »

Cathedox wrote:The problem is that the results are completely incoherent on a particular resolution (1366x768) my code is completely dynamic depending on the resolutions and work perfectly fine on other resolutions.
Got a picture? It might be possible to identify the problem based on what appears on the screen.
Cathedox wrote:

Code: Select all

    // Check if x and y are in the buffer
    if (x > GraphicsInfo->PixelsPerScanLine)
You should use HorizontalResolution instead of PixelsPerScanLine when clipping your image to fit on the display.
xeyes
Member
Member
Posts: 212
Joined: Mon Dec 07, 2020 8:09 am

Re: UEFI Unable to write correctly to the screen with GOP bu

Post by xeyes »

Not sure about UEFI, at least for VBE, sometimes there can be padding between lines of pixels. I've seen more than one 1366 column screens that have this padding.

If there is padding, and you do:
FrameBufferAddr -= GraphicsInfo->PixelsPerScanLine * GraphicsInfo->PixelSize;
You may get a distorted image that only occupy part of the screen.
klange
Member
Member
Posts: 679
Joined: Wed Mar 30, 2011 12:31 am
Libera.chat IRC: klange
Discord: klange

Re: UEFI Unable to write correctly to the screen with GOP bu

Post by klange »

xeyes wrote:Not sure about UEFI, at least for VBE, sometimes there can be padding between lines of pixels. I've seen more than one 1366 column screens that have this padding.

If there is padding, and you do:
FrameBufferAddr -= GraphicsInfo->PixelsPerScanLine * GraphicsInfo->PixelSize;
You may get a distorted image that only occupy part of the screen.
That's actually what PixelsPerScanLine is for, vs. HorizontalResolution.
xeyes
Member
Member
Posts: 212
Joined: Mon Dec 07, 2020 8:09 am

Re: UEFI Unable to write correctly to the screen with GOP bu

Post by xeyes »

klange wrote: That's actually what PixelsPerScanLine is for, vs. HorizontalResolution.
Thanks for correcting me.

Seems more confusing than VBE's "BytesPerScanLine" name. OP and I were both confused by it, albeit in different ways.
Post Reply