|Summary:||Issue when rendering with 2 contexts to one window|
|Product:||Mesa||Reporter:||Stefan Dösinger <stefandoesinger>|
|Status:||NEW ---||QA Contact:|
|i915 platform:||i915 features:|
|Attachments:||Test app to show the bug|
Description Stefan Dösinger 2006-10-14 12:20:54 UTC
r200 dri seems to have some issues when an application renders from 2 threads to the same window with 2 different contexts. According to the glXSwapBuffers manpage it is ok to render to one window with 2 contexts. I have experienced issues with the glDrawBuffer setting when doing that. I will attach a small test application which shows the bug. (sorry if this bug report appeared 2 times - I had a system crash when I filed it the first time, I couldn't find the bug, so I assumed it wasn't filed and rewrote it)
Comment 1 Stefan Dösinger 2006-10-14 12:34:36 UTC
Created attachment 7414 [details] Test app to show the bug This app creates a window and two glx contexts and starts 2 threads which use the contexts to render to the window. The threads are only hackily synchronised, but it should work, to my knowledge. The program should draw a blue quad and a red primitive, with the red primitive beeing partially covered by the quad. The problem is that the quad flickers as if it was drawn to the front buffer. The flickering goes away if I move the glDrawBuffers(GL_BACK); statements into the rendering loop in both threads. The depth buffer seems to be shared properly between the contexts, and the glColor state seems to work too. The background is implementing multithreaded Direct3D for Wine. Direct3D applications can do rendering from any thread, while a gl context is only valid for one thread. Because of that a d3d app using differnt threads will just crash with the current wine code. We can't easilly take away the context from the thread it is assigned to because we have no control over the threads, so we hope to be able to create one context for each thread that does the rendering and share textures, VBOs, shaders, ..., between the contexts and to render to the same window. Locking in the d3d libs will make sure that only one thread renders at the same time.
Comment 2 Stefan Dösinger 2006-10-14 12:37:10 UTC
Sorry, I forgot to mention, the version identification from glxinfo is: OpenGL vendor string: Tungsten Graphics, Inc. OpenGL renderer string: Mesa DRI R200 20060602 AGP 4x x86/MMX/SSE2 TCL OpenGL version string: 1.3 Mesa 6.5.1
Comment 3 Roland Scheidegger 2006-10-14 18:08:48 UTC
Have you enabled pageflip? It seems to work just fine here without pageflip, but not with pageflip enabled. I think the issue here is that in all of the radeon drivers (didn't look at others), the radeon/r200PageFlip function which will finally get called upon a glxSwapBuffers call updates the (per-context) hw state to adjust for the new offsets. But since the drawable ultimately is bound to 2 contexts the other one will still use the old values.
Comment 4 Stefan Dösinger 2006-10-15 02:53:24 UTC
Good point, yes pageflip is enabled. It seems using different contexts to render to the same window is a bit jerky in general. The nvidia driver seems to share the color attribute between both contexts, and fglrx just crashes :-/ . Is that supposed to work? The glXSwapBuffers manpage suggests that, but I haven't found anything else. Maybe I can persuade our dict^H^H^H^H project maintainer to accept a SetThreadContext hack to take the rendering context away from the thread owning it...
Comment 5 Roland Scheidegger 2006-10-15 13:42:33 UTC
(In reply to comment #4) > Good point, yes pageflip is enabled. > > It seems using different contexts to render to the same window is a bit jerky > in general. The nvidia driver seems to share the color attribute between both > contexts, and fglrx just crashes :-/ . Is that supposed to work? The > glXSwapBuffers manpage suggests that, but I haven't found anything else. From quickly glancing at it, I would just say the same, but I'm no expert in that area. Nevertheless, this looks like genuine driver bugs to me. > Maybe I can persuade our dict^H^H^H^H project maintainer to accept a > SetThreadContext hack to take the rendering context away from the thread > owning it... Well, I guess if it really doesn't work with pretty much any driver, you might need to do that even if what you do is fully legal. I'd fix it for the radeon drivers but I currently can't quite see how you'd notice the other contexts upon a drawable change, as the __DRIdrawablePrivate struct only has a pointer to a single context. Calling glXMakeCurrent in the drawing loops should work around that problem (as that should make sure the hw buffer offsets get updated, just as putting glDrawBuffers(GL_BACK) in there does), though again I don't think this is needed by the spec.
Comment 6 Michel Dänzer 2006-10-16 08:31:22 UTC
The underlying problem is that per-drawable state is tracked per context, which is unfortunately quite widespread in DRI drivers currently, especially related to buffer swaps (and vsync, ...).
Comment 7 Adam Jackson 2009-08-24 12:24:41 UTC
Mass version move, cvs -> git
Comment 8 Michel Dänzer 2011-02-09 02:05:04 UTC
Does this work better now? FWIW, the Mesa demos repository contains a demo src/xdemos/corender which seems to work perfectly here with both the classic and Gallium r300 drivers.
Comment 9 Wolfgang Draxinger 2011-11-08 06:42:35 UTC
Indeed a single drawable may have serveral OpenGL render contexts on it, which also may be active in multiple threads at the same time. This is a common setup to allow for such things like uploading texture or buffer object data, while other threads are blocking, say in glXSwapBuffers. Blocking glXSwapBuffers on V-Sync may give up to 1/50th (say if someone slightly missed a previous frame's retrace deadline) of free CPU and GPU time, which is worth using. But as soon as you go about drawing to the same drawable from multiple render contexts you're begging for trouble. Effectively the target framebuffer is a mutually exclusive, but shared resource, so the driver constantly has to switch locks, and of course the whole rendering process (sending geometry, etc.) is just one big race condition. The bug submitter's test case is just a perfect example for such a race condition. Now I see, that the original application is D3D9 multithreaded rendering emulation. Personally I never experienced (native) D3D9 multithreaded rendering usefull for something else like generating render-to-texture content. Anyway: It is right that OpenGL contexts can be used from only one thread at a time, BUT THEY ARE NOT BOUND TO A SPECIFIC THREAD! Once can unbind the context from one thread, and rebind it to another: thread_A: glXMakeContextCurrent(display, drawable, drawable, NULL) signal_thread(thread_B, "context released") thread_B: wait_for_signal("context released") glXMakeContextCurrent(display, drawable, drawable, context); It may also be worthwile for the D3D9 emulator to use a PBuffer drawable (maybe in combination with a FBO, featuring depth texture attachments); instead of glXSwapBuffer at the and of each thread signal that each threads composition layer has been finished and only the last finishing thread should then collect all intermediary pictures and combine them into a composition, implementing things like depth testing and the like there.