Register
Handmade Hero»Forums»Code»StretchDIBits isn't working when it has an opengl context and is in fullscreen mode
Karan Joisher
10 posts
StretchDIBits isn't working when it has an opengl context and is in fullscreen mode
1 year, 7 months ago Edited by Karan Joisher on Oct. 13, 2018, 2:58 p.m. Reason: Initial post
I have been writing a platform layer and initially I started with software rendering using StretchDIBits. I also added the toggle fullscreen function that was used in this series.

Software Blit:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
void PfBlitToScreen(PfWindow *window)
{
        // Using CS_OWNDC, hence cached the deviceContext handle.
        HDC deviceContextHandle = window->deviceContext;
        int32 scanLines = StretchDIBits(deviceContextHandle,
                                        0, 0,window->offscreenBuffer.width, window->offscreenBuffer.height,
                                        0,0,window->offscreenBuffer.width, window->offscreenBuffer.height,
                                        window->offscreenBuffer.data, &(window->offscreenBuffer.info),DIB_RGB_COLORS,SRCCOPY);
        
        ASSERT(scanLines);
}



ToggleFullscreen:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
void PfToggleFullscreen(PfWindow *window)
{
    DWORD windowStyle = GetWindowLong(window->windowHandle, GWL_STYLE);
    if(windowStyle & WS_OVERLAPPEDWINDOW)
    {
        MONITORINFO monitorInfo = {sizeof(monitorInfo)};
        if(GetWindowPlacement(window->windowHandle, &(window->prevWindowPlacement)) &&
           GetMonitorInfo(MonitorFromWindow(window->windowHandle, MONITOR_DEFAULTTOPRIMARY), &monitorInfo))
        {
            SetWindowLong(window->windowHandle, GWL_STYLE, windowStyle & ~WS_OVERLAPPEDWINDOW);
            SetWindowPos(window->windowHandle, HWND_TOP,
                         monitorInfo.rcMonitor.left, monitorInfo.rcMonitor.top,
                         monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left,
                         monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top,
                         SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
            window->fullscreen = true;
        }
    }
    else
    {
        SetWindowLong(window->windowHandle, GWL_STYLE, windowStyle | WS_OVERLAPPEDWINDOW);
        SetWindowPlacement(window->windowHandle, &(window->prevWindowPlacement));
        SetWindowPos(window->windowHandle, 0, 0, 0, 0, 0,
                     SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
                     SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
        window->fullscreen = false;
    }
}



This worked as expected.
Later I added OpenGL context and still kept the option to use the PfBlitToScreen()
However when the window toggled to fullscreen mode, it would just clear the screen black.
I tried to find out the cause by stepping through the debugger but it turns out that when I stepped through the function it would output the image properly.

I later changed the PfBlitToScreen() functions such that when the window is in fullscreen mode and when the window has an OpenGL context, I would use "hardware blit" rather than "software blit" i.e. I would send the offscreen buffer as a texture to OpenGL. Having made this change, the image was properly outputted in fullscreen mode.

Modified PfBlitToScreen():
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void PfBlitToScreen(PfWindow *window)
{
    /* HACK(KARAN): stretchdibits doesn't work in fullscreen mode
    when the window has an opengl context. So when in fullscreen mode
    and if we have a glContext, use opengl texture rendering path.
    */

    if(window->fullscreen && (window->glContext != 0))
    {
        PfglMakeCurrent(window);
        PfglRenderWindow(window);
        PfglSwapBuffers(window);
    }
    else
    {
        HDC deviceContextHandle = window->deviceContext;//GetDC(window->windowHandle);
        int32 scanLines = StretchDIBits(deviceContextHandle,
                                        0, 0,window->offscreenBuffer.width, window->offscreenBuffer.height,
                                        0,0,window->offscreenBuffer.width, window->offscreenBuffer.height,
                                        window->offscreenBuffer.data, &(window->offscreenBuffer.info),DIB_RGB_COLORS,SRCCOPY);
        
        ASSERT(scanLines);
    }
}


So my question is why does this happen and is there a way to fix this so that I can use StretchDIBits even in fullscreen OpenGL context mode.
Mārtiņš Možeiko
2074 posts / 1 project
StretchDIBits isn't working when it has an opengl context and is in fullscreen mode
1 year, 7 months ago
Modern windows does a lot of optimizations when window is fully covering monitor. It bypasses compositor to have less lag when flipping buffers. Probably this also bypasses GDI rendered output.

I would avoid calling GDI functions on DC that has GL context created (HGLRC).