Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Migration from QGLWidget to QOpenGLWidget?



  • Hi,
    I'm still in my problems to migrate an application written in Qt4.8.4 (so using QGLWidget) to a version in QT5. Due to the numerous problems we have by using the Qt5 version of QGLWidget, we have decided to make a try by migrating them to QOpenGLWidget. BUt I'm still facing a problem.

    In the QT 4.8.4 version we created a special QGLWidget that is never displayed. But it is shared between all our OpenGL widgets using the syntax QGLWidget(QWidget *parent = Q_NULLPTR, const QGLWidget *shareWidget = Q_NULLPTR, Qt::WindowFlags f = Qt::WindowFlags()).

    With QOpenGLWidget this syntax no more exist. It is replaced by the notion of shared QOpenGLContext. But, to be effective (.i.e. gives the ability to create OpenGL objects), the QOpenGLContext seems to require a QSurface. And this is where my problem stands. Because, when my application calls an OpenGL function it does not know if a QOpenGLWidget has already been displayed (so a current context is present), or not (so a QOffscreenSurface is required with an explicit call to context()->makeCurrent(Surface)). Does it exist a clue to solce this problem without having to check the state of the current context before calling OpenGL functions?


  • Lifetime Qt Champion

    Hi,

    Can you provide a minimal sample that shows your setup ?



  • Hi,
    This is the partial code of the shared QGLWidget (in 4.8.4):

    //----------------------------------------------------------------------------
    SharedGLWidget::SharedGLWidget() : QGLWidget(), m_shaderDirectory("shaders/")
    //----------------------------------------------------------------------------
    {// SharedGLWidget()
            updateGL();
    }// SharedGLWidget()
    
    //----------------------------------------------------------------------------
    void SharedGLWidget::initializeGL()
    //----------------------------------------------------------------------------
    {// initializeGL()
            GLenum msg = glewInit();
    
            if (msg != GLEW_OK)
        {// check glew init
            astk::log::msg((const char *)glewGetErrorString(msg));
        }// check glew init  
    
            this->loadShader("Slice"          , m_sliceProgram);
            this->loadShader("Implant"        , m_implantProgram);
            this->loadShader("Color"          , m_colorProgram);
            this->loadShader("Depth"          , m_depthProg);
            this->loadShader("Texture2D_RGBA" , m_texture2DProgram);
            this->loadShader("VolumeRendering", m_vrProgram);
            this->loadShader("Contour"        , m_contourProgram);
            this->loadShader("Radio"          , m_radioProgram);
    
            // initial constant member of slice program
            unsigned int program = 0;;
            program = m_sliceProgram.programId();
            glUseProgram(program);
            glUniform1i(glGetUniformLocation(program, "tex2"), 8);
    
            glUniform1i(glGetUniformLocation(program, "tex3d0"), 0);
            glUniform1i(glGetUniformLocation(program, "tex3d1"), 1);
            glUniform1i(glGetUniformLocation(program, "tex3d2"), 2);
            glUniform1i(glGetUniformLocation(program, "tex3d3"), 3);
            glUniform1i(glGetUniformLocation(program, "tex3d4"), 4);
            glUniform1i(glGetUniformLocation(program, "tex3d5"), 5);
            glUniform1i(glGetUniformLocation(program, "tex3d6"), 6);
            glUniform1i(glGetUniformLocation(program, "tex3d7"), 7);
            glUseProgram(0);
    
            // initial constant member of radio program
            program = m_radioProgram.programId();
            glUseProgram(program);
            glUniform1i(glGetUniformLocation(program, "tex3d0"), 0);
            glUniform1i(glGetUniformLocation(program, "tex3d1"), 1);
            glUniform1i(glGetUniformLocation(program, "tex3d2"), 2);
            glUniform1i(glGetUniformLocation(program, "tex3d3"), 3);
            glUniform1i(glGetUniformLocation(program, "tex3d4"), 4);
            glUniform1i(glGetUniformLocation(program, "tex3d5"), 5);
            glUniform1i(glGetUniformLocation(program, "tex3d6"), 6);
            glUniform1i(glGetUniformLocation(program, "tex3d7"), 7);
            glUseProgram(0);
    
            // initial constant member of vrprogram
            program = m_vrProgram.programId();
            glUseProgram(program);
            glUniform1i(glGetUniformLocation(program, "tex3d0"), 0);
            glUniform1i(glGetUniformLocation(program, "tex3d1"), 1);
            glUniform1i(glGetUniformLocation(program, "tex3d2"), 2);
            glUniform1i(glGetUniformLocation(program, "tex3d3"), 3);
            glUniform1i(glGetUniformLocation(program, "tex3d4"), 4);
            glUniform1i(glGetUniformLocation(program, "tex3d5"), 5);
            glUniform1i(glGetUniformLocation(program, "tex3d6"), 6);
            glUniform1i(glGetUniformLocation(program, "tex3d7"), 7);
            glUseProgram(0);
    }// initializeGL()
    
    

    A global instance is created at the beginning, just before the first use of an OpenGL command:

            SharedGLWidget::getInstance()->makeCurrent();
            char * retPtr = (char *) glGetString(GL_EXTENSIONS);// Retrieve the whole extension list
    

    And each visible QGLWidget is created by:

    Display2DView::Display2DView(QWidget * p_parent) : QGLWidget(p_parent, SharedGLWidget::getInstance())
    {
    ...
    }
    

    Now, our application is a state-machine application. I.e. each state has its own GUI. The GUIs of the first steps do not have OpenGL widgets. But in the transition between them and the first state with OpenGL GUI, a lot of OpenGL processes (texture creation, preparation of the widgets) is performed with no OpenGL widget yet displayed.



  • OK,
    Application now seems to work. I have to run the unitary tests to be sure. If I have too many bad suprises with unitary tests, we will go back to Qt 4.8.4. And in every cases what I did is much more hacks that clean development.

    The major changes that created a lot of problems are:

    • In Qt4.8.4 when an QGLWidget is created, even if it is not displayed, an OpenGL context is created. So, all OpenGL operations are possible. In Qt5 to be able to use the OpenGL operation, with a QOpenGLWidget, the widget must be displayed, or linked to an off-screen surface,

    • In Qt4.8.4 when a QGLWidget is passed to every other QGLWidget, there is really a single OPenGL Context that is used. In Qt5, force the application to use shared contexts does not mean "a single context". And the impact is that OpenGL activated at one moment (in one context) are not necessarily activated globally. So application that runs well in QT4.8.4 does not necessarily work well with QT5,

    • And finally QGLWidget in QT5 and QGLWidget in QT4.8.4 are totally uncorrelated. This is the same class name, the same API. But QT has not only marked QGLWidget as deprecated. They also changed the whole implementation. Thus, an application working under Qt4.8.4 may encounter problems in QT5 due to unmanaged hidden QSurface.

    This is again a proof of an axiom that I well know: "Never change the version of frameworks in a product. Unless whether the current development step requires a full rewriting of the application".


Log in to reply