Multithreaded opengl
-
Hi,
I'm trying to compile/run this example:
http://doc.qt.nokia.com/qq/qq06-glimpsing.htmlMy code is here:
https://github.com/aewallin/sandbox/tree/master/qt_opengl_threadsI'm on Ubuntu 11.04 with qt4.7 and I am getting:
X Error: BadAccess (attempt to access private resource denied) 10
Extension: 155 (Uknown extension)
Minor opcode: 26 (Unknown request)
Resource id: 0x64000cd
QGLContext::makeCurrent(): Failed.any suggestions? are there more recent examples for this?
feel free to fork my code and edit on github!thanks,
Anders -
I don't know anything about opengl, but my suggestion is: don't use 8+ years old articles. That's referring to Qt3 stuff. Start with 4.8 and read http://labs.qt.nokia.com/2011/06/03/threaded-opengl-in-4-8/
-
I'll look at qt4.8 when it comes to a stable ubuntu release (too much of a hassle to install it manually)
anyway it seems a call to
QGLWidget::doneCurrent() is required to release the current QGLContext.also it seems double-buffering works less than great for me, so I turned that off.
after that, from the QThread subclass the QGLWidget::makeCurrent() succeeds and I can do OpenGL drawing as usual. Here's a screenshot of my current code (just pushed to github):
http://imagebin.org/177291 -
My suggestion would be to avoid multi-threaded opengl context sharing at all costs. You don't actually need Qt 4.8 either.
Designate a single thread to do opengl calls, and stick to it like its a a matter of life and death - i.e. no gl*() calls in any other thread.
I have spent the last six months dealing with reliability problems and opengl drivers. The approach I have taken is to use exactly one opengl context, the one created in the QGLWidget. If you create another opengl context and attempt to share it (say with an upload thread) you are asking for problems:
On Linux/MESA/ Intel graphics - you will run into assertion failures in Xlib/glXSwapBuffers().
Linux/NVidia - works reasonably well, but is slower than single threaded.
Win32/NVidia - works reasonably well, but is slower than single threaded.
Win32/Intel - buggy; can crash.
Win32/ATI - forget it - it just isn't reliable. I've seen incorrect textures rendered and/or random bits of memory shown on screen in place of correct texture maps.
Windows XP/ATI - well you'll be lucky not to get a BSOD...This is essentially what I do in qt 4.7.3/4:
- Create an QGLWidget.
- Create a render thread, which has a pointer to the QGLWidget.
- call doneCurrent in the main thread.
- Start the thread, call makeCurrent() in the thread, run render thread.
You still need to override the methods resizeEvent(), paintEvent(), initializeGL, resizeGL, updateGL(). resizeEvent() in particular should tell the render thread that it needs to resize.
The render thread is roughly this (pseudo code):
@
nextFrameDueAt = NOW() + 16 milliseconds; // get the current time
while (running):
clear the buffer (if needed)
resize viewport (if needed)
renderAllObjects();while (pendingTextureUploadRequest() && (CURRENTTIME() < (nextFrameDueAt-2ms))): processNextTextureUploadRequest(); swapBuffers()
@
Good luck.-bms
Edit: Please wrap (pseudo)code in @ tags; mlong
-
bms, thanks for your input.
I've browsed the interwebs and one of the better explanations I found was by apple:
http://developer.apple.com/library/mac/#documentation/graphicsimaging/conceptual/OpenGL-MacProgGuide/opengl_threading/opengl_threading.htmlI will try to implement something like the "Worker Task" idea from that link. If anyone has some example code where a (double-buffered?) vertex-array or vertex-buffer-object is updated in a worker task I would be interested.
Anders