Threaded OpenGL with shared QGLWidgets issue with Qt 5.1

riv333 picture riv333 · Oct 5, 2013 · Viewed 7.7k times · Source

I use two QGLWidgets. One for loading textures and one for rendering, but it is not working.

I used the following explanation from http://blog.qt.digia.com/blog/2011/06/03/threaded-opengl-in-4-8/

Texture uploading thread Uploading many (or large) textures is typically an expensive operation because of the amount of data being pushed to the GPU. Again, this is one of those operations that can unnecessarily block your main thread. In 4.8 you can solve this problem by creating a pair of shared QGLWidgets. One of the widgets is made current in a separate thread, but is never made visible on screen. The main thread informs the uploading thread which images to upload and the uploading thread simply calls bindTexture() on each of these images and then notifies the main thread when each one has finished so it can be drawn to screen.

With Qt 4.8 with MinGW it works fine, but now i use Qt 5.1 with MSVC. I am getting an error when I want make the widget in the thread current:

Cannot make QOpenGLContext current in a different thread

I understand the error but how can i fix it. When i don't set the widget current i can't load textures (freezed at the bindTexture() function). I also wondering, why it works with my old QT Version. When the error appears i can press "ignore error" and the programm loads the textures anyway.

Here is some sample code:

Loading textures:

GLContext::GLContext(QWidget *parent, QGLWidget *myDisplayWidget) :
  QGLWidget(parent,myDisplayWidget)
{
}

...

GLContext* myTextureWidget = new GLContext(this,myDisplayWidget);

...

void TextureLoadingThread::run()
{    
    makeCurrent(); //Here is the bug!
    QImage *im = new QImage(filename);
    GLuint textid = myTextureWidget->bindTexture(*im, GL_TEXTURE_2D, GL_RGBA);
}

EDIT:

When i move the context of the myTextureWidget to the thread it works, but then i get the makeCurrent Error from the API when the GUI will build (the stack trace said at the QLineEdit::setPlaceHolderText function in QT5Widgetsd). When i move the myTextureWidget to the thread some seconds after the mainwindow has been shown, all works fine. But how can i know when qt finished all GUI building Stuff? I draw the GUI to a QGraphicsView with a QGLWidget viewport.

myTextureWidget->context()->moveToThread(myTextureLoadingThread);

Answer

omgodie picture omgodie · Oct 9, 2013

Before you start the new Thread and call makeCurrent() you have to initiate doneCurrent() e.g.

void QGLWidget::startRendering()
{
    doneCurrent();
    context()->moveToThread(mTextureLoadingThread);
}

and then call

void TextureLoadingThread::run()
{    
    makeCurrent(); //Here is the bug!
    ...
}

This is what i've done to work around this error. Unfortunately i don't have the perfect solution for using a thread for rendering.

// EDIT

I have uploaded an example: https://dl.dropboxusercontent.com/u/165223/thread_example.zip