Page 1 of 1

UEFI Unable to write correctly to the screen with GOP buffer

Posted: Fri Aug 19, 2022 9:16 am
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;
    }

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

Posted: Fri Aug 26, 2022 11:05 am
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.

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

Posted: Sun Aug 28, 2022 2:34 am
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.

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

Posted: Sun Aug 28, 2022 6:12 am
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.

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

Posted: Tue Aug 30, 2022 11:48 pm
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.