Qt World Summit: Register Today!


WGL Window on non-GUI thread



  • Hi guys,

    I started out trying to create an OpenGL render window on a non-GUI thread using QT's OpenGL resources as explained in this thread:

    https://forum.qt.io/topic/123151/qwindow-on-a-non-gui-thread

    My reason for attempting to do this is because my GUI thread is pretty busy with a lot of events and widgets and this causes stuttering and dropped frames when I use a QWindow.

    At the moment, I've gotten as far as creating a native WGL context / window which I used to create a QOpenGLContext:
    Here is a github link to the project: https://github.com/rtavakko/WinGL

    void OpenGLNativeRenderWindow::showNative()
    {
        //Create native window and context
        createNative();
    
        //Allocate memory for the context object and prepare to create it
        openGLContext = new QOpenGLContext(this);
    
        QWGLNativeContext nativeContext(hglrc,hwnd);
        openGLContext->setNativeHandle(QVariant::fromValue(nativeContext));
    
        openGLContext->setFormat(openGLFormat);
        if(sharedOpenGLContext)
            openGLContext->setShareContext(sharedOpenGLContext);
    
        //Make sure the context is created & is sharing resources with the shared context
        bool contextCreated = openGLContext->create();
        assert(contextCreated);
    
        if(sharedOpenGLContext)
        {
            bool sharing = QOpenGLContext::areSharing(openGLContext,sharedOpenGLContext);
            assert(sharing);
        }
    
        //Resize / show window
        resize(renderSpecs.frameType.width,renderSpecs.frameType.height);
        visible = !ShowWindow(hwnd,SW_SHOWNORMAL);
    }
    

    All the resources, including the native window, are created without issues and I'm able to make the QT context current on a separate thread and OpenGL rendering also produces no errors but Hello Triangle doesn't render on my window. It seems that the native WGL context and the QT context are still separate entities.

    If I make direct WGL calls to make the context current / swap buffers, I seem to be able to make OpenGL calls on the native window but it still seems I can't access the resources the QT context renders (e.g. FBO output texture).

    Any thoughts on what could be wrong?

    Cheers!



  • It seems like it is not possible to render into a native OpenGL window on a separate thread using QT resources and classes. This is the project I worked on for this:
    https://github.com/rtavakko/GLFWInterop

    There are no errors and OpenGL also seems happy when rendering but no frame is rendered into the native window.

    It seems like the QT - native OpenGL interop system is designed to render from a native window into a window managed by QT e.g. a QWindow which does not really solve this issue. The QWindow would still live on the GUI thread which would mean that your rendering performance is limited by how efficiently your UI and widgets run.

    I had success completely getting away from the QT OpenGL classes and only using GLEW along with GLFW windows. GLFW allows resource sharing between OpenGL contexts / windows and also having render windows on different threads. This is a link to the GLFW project:
    https://github.com/rtavakko/GLFWEngine

    So it seems the only option at this point is to have a QT-based GUI and a third party OpenGL engine. It would definitely make sense to have a QT class similar to QWindow that can live in a non-GUI thread but this is not possible at the moment.



  • Any ideas on this?



  • It seems like it is not possible to render into a native OpenGL window on a separate thread using QT resources and classes. This is the project I worked on for this:
    https://github.com/rtavakko/GLFWInterop

    There are no errors and OpenGL also seems happy when rendering but no frame is rendered into the native window.

    It seems like the QT - native OpenGL interop system is designed to render from a native window into a window managed by QT e.g. a QWindow which does not really solve this issue. The QWindow would still live on the GUI thread which would mean that your rendering performance is limited by how efficiently your UI and widgets run.

    I had success completely getting away from the QT OpenGL classes and only using GLEW along with GLFW windows. GLFW allows resource sharing between OpenGL contexts / windows and also having render windows on different threads. This is a link to the GLFW project:
    https://github.com/rtavakko/GLFWEngine

    So it seems the only option at this point is to have a QT-based GUI and a third party OpenGL engine. It would definitely make sense to have a QT class similar to QWindow that can live in a non-GUI thread but this is not possible at the moment.



  • Here are all the WGL functions
    https://docs.microsoft.com/en-us/windows/win32/opengl/wgl-functions

    The function of interest is
    wglMakeCurrent
    https://docs.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-wglmakecurrent

    The line of interest is
    "A thread must set a current rendering context before calling any OpenGL functions. Otherwise, all OpenGL calls are ignored."

    so, what I recommend is to call
    wglMakeCurrent(NULL, NULL); (or whatever the Qt equivalent is.)
    from your GUI thread.

    Then, in your other thread, make a context current by calling.
    wglMakeCurrent(hdc, glcontext); (or whatever the Qt equivalent is.)
    and now, you can make gl funciton calls.

    When you are finished, call
    wglMakeCurrent(NULL, NULL);
    then, release the GL context, destroy the GL context and all that stuff.