Multiple QQuickWindows and opengl context persistence



  • Hi everyone,

    While trying to integrate custom opengl rendering and Qt Quick, we encountered the following problem.
    We create our items with help of QQuickFramebufferObject. And create opengl buffers (glGenBuffer and glBufferData) on the first rendering (QQuickFramebufferObject::Renderer::render()), that means we use opengl context attached to QQuickWindow that renders our scene. Vertex buffers are pretty big, and we create them only once on the first render.

    There are several QQuickWindow (integrated into widget application). Empirically we found that all those windows are using the same QOpenGLContext object (QQuickWindow::openglContext). If one of the quickwindow is destroyed and all else of quickwindows aren't visible, then that QOpenGLContext object is destroyed. In Qt documentation it is described here http://qt-project.org/doc/qt-5/qquickwindow.html#exposure-and-visibility
    When one of those quickwindows gets visible, a new QOpenGLContext object is created and shared between all quickwindows.

    In documentation http://qt-project.org/doc/qt-5/qquickwindow.html#setPersistentOpenGLContext it is said that we can ask Qt not to destroy QOpenGLContext object in such situations. However, our test case shows that's not true:

    @class PersistanceTest : public QObject
    {
    Q_OBJECT

    QQuickView * v1;
    QQuickView * v2;
    
    bool m_hidden;
    

    public:

    PersistanceTest()
    {
        m_hidden = false;
    
        // create QQuickViews
        createV1();
        createV2();
    
        // track their contexts
        QTimer::singleShot(1000, this, SLOT(dumpV1Context()));
        QTimer::singleShot(1000, this, SLOT(dumpV2Context()));
    
        QPushButton *but = new QPushButton("Click ME");
        connect(but,
                &QPushButton::clicked,
                [this]() {
                    qDebug() << "clicked";
                    if (!m_hidden)
                    {
                        // hide v2 and destroy v1 -> this will destroy
                        // their opengl context
                        v2->hide();
    
                        delete v1;
                        v1 = nullptr;
                        m_hidden = true;
                    }
                    else
                    {
                        // restore inital state => new QOpenGLContext object
                        // will be created and shared between v1 and v2
                        createV1();
                        v2->show();
                        m_hidden = false;
                    }
                });
    
        but->show();
    }
    
    void createV1()
    {
        v1 = new QQuickView();
        // v1 will be bigger, so that we can distinguish
        // between v1 and v2
        v1->resize(300, 300);
        // just to track v1 was actually destroyed
        QObject::connect(v1,
                         &QObject::destroyed,
                         []() { qDebug("v1 destroyed"); });
    
        // changing true/false doesn't matter
        v1->setPersistentOpenGLContext(true);
        v1->show();
    }
    
    void createV2()
    {
        v2 = new QQuickView();
        // changing true/false doesn't matter
        v2->setPersistentOpenGLContext(true);
        v2->show();
    }
    

    public slots:
    void dumpV1Context()
    {
    if (v1)
    qDebug() << "v1.context = " << v1->openglContext();
    QTimer::singleShot(1000, this, SLOT(dumpV1Context()));
    }

    void dumpV2Context()
    {
        qDebug() << "v2.context = " << v2->openglContext();
        QTimer::singleShot(1000, this, SLOT(dumpV2Context()));
    }
    

    };
    @

    Log of test execution will look smth like this:
    v2.context = 0x2edb9b0
    v1.context = 0x2edb9b0
    v1.context = 0x2edb9b0
    v2.context = 0x2edb9b0
    clicked
    v1 destroyed
    v2.context = 0x0 <---- QOpenGLContext object destroyed
    v2.context = 0x0
    clicked
    v2.context = 0x2e64a10 <----- created for both of them
    v1.context = 0x2e64a10
    v1.context = 0x2e64a10
    v2.context = 0x2e64a10
    clicked
    v1 destroyed
    v2.context = 0x0
    v2.context = 0x0
    clicked
    v2.context = 0x2e8d830
    v1.context = 0x2e8d830
    v1.context = 0x2e8d830
    v2.context = 0x2e8d830

    And here is the problem. When QOpenGLContext object is destroyed, and one of quickwindow gets back to top - everything crashes on the next opengl call (in our implementation of QQuickFramebufferObject::Renderer::render()). The possible reason of that is absence of previously created vertex buffers.

    The question is: is a Qt bug, or application should track context destruction and recreate vertex buffers every time new context is created? Or may be there are some known ways to handle such situation?

    Thanks in advance

    PS: windows 7 x64, Vusial Studio 2012, Qt. 5.2.1 opengl_64



  • I found that turning on threaded render on Window (via QML_FORCE_THREADED_RENDERER=1 env var) forces all instances of QQuickWindow to create their own opengl context.

    But still wondering how to overcome application opengl data destruction when Qt kills opengl contexts object.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.