A question for you about sharing OpenGL contexts. I’ll explain what’s going on, and maybe you will see a problem with my setup or execution : ) The overall idea is to have a thread generate textures while another thread displays those textures.
I create a context, called “DisplayContext”.
I then create a shared context, called “CreateContext”, that shares memory of the first context.
I create a bunch of textures inside the DisplayContext giving them names with glGenTextures. These names should be known in both contexts. For each image I want to display there are double the textures needed such that I can display and create a different set at a time (my double-buffered scheme).
I kick off a thread that runs my CreateContext. It is made current at the start of the thread and whenever a shared memory region is updated, it binds a texture (or textures) and fills in the memory. My setup is double-buffered such that the DisplayContext and CreateContext should never look at the same texture at the same time. When the background buffer is filled the flag is changed and then the DisplayContext should start using the newly created set of textures.
As the program gets going where both threads are working simultaneously, there are often glBindTexture errors in either thread that kills processing.
If the texture IDs are unique, why would there be an error? Are contexts current in either thread, or is there one “global current context” and each thread keeps setting the current while the other is doing something else (say, inbetween a glBegin and glEnd call)?
Any ideas? I can provide more information, just ask!
Just an update:
I was getting a lot of errors around glBindTexture() while both contexts/threads were running full bore. I’ve changed it so that the initial context (DisplayContext) creates all the textures with glGenTexture so the ids are only created in that context. Now either context does not complain when binding.
Would the asyncrous nature of OpenGL have anything to do with this? I’ve heard it doesn’t port well to multi-threading, but are their any locks or techniques that make this work? I tried adding Mutexes around most of the texture calls (either where I Bind and Set Vertices, or where I Bind and push image memory to texture memory) but that didn’t help anything. I’m unsure why things just “don’t work”, though I realize it’s hard to debug something described in that way.
Let me know if you have any thoughts.
The overall idea is to have a thread generate textures while another thread displays those textures.
This could be done with one context using 2 PBOs.
Now, about your concern, I am not well informed about context sharing but take care of what is shared and what is not in a rendering context. Objects and object states are shared between rendering contexts sets for one window. Things like current texture target are not and are individual to each RC. So what I want to say is that textures names in use may not be shared between RC just texture objects. This could lead to duplicated texture names and then your binding problems. This need to be confirmed, I have not experienced that myself.
Pardon my ignorance, but what is a PBO? “Pixel Buffer Object”?
Having a backup object (be it a second set of identical textures or two "PBO"s) works to a degree but I’m finding it bound to how fast I can go through the display loop. While drawing the first object, if I try to update the second object too soon no update ever occurs.
I’ll try an exmaple of what I mean: Let’s say I’m filling the screen with a grid of small textures and I have a second grid waiting in the background. I’m receiving updates every 3 seconds. If the background grid is not filled within 3 seconds it gets the call to “use this new data to fill the grid” and starts over. There’s no point in swapping what is already finished because there will be blank textures and no point waiting for it to finish because then I’m that much closer to the next update (if it takes 3.2 second, then I only have 2.8 until the next).
So that’s my dilemma. I’m hoping that a second thread will make things fast enough that a double-data solution could work. Not having to worry about the Draw cycle’s CPU share could do it . . . in theory.
To your comment about texture names, do you think they should be the same or different in each context. Sounds like you meant different, but then how could the contexts know they were the same texture? I am pretty sure I am not using the same texture name at the same time right now. In a single thread I have a front set and back set. The Display context should only use one set at a time until the Create Context finishes with all the textures and flags “the back set is ready for use.”
Thanks for your reply, I wouldn’t mind hearing some more ideas : )
Pardon my ignorance, but what is a PBO? “Pixel Buffer Object”?
PBO are buffer objects similar to vertex buffer objects but are designed to handle pixel data and not vertex data. Their API is same as vertex buffer objects, it just provides the possibility to read/write pixel data from/to buffer object and in addtion, allows to perform these operations asynchronously benefiting from DMA (Direct Memory Access) decreasing CPU work load.
More information in ARB_pixel_buffer_object spec and here for practical examples.
About your loading speed problems: you may need to implement an event system (or use the OS one) to synchronize texture data loading and reading operations. The only solution is to delay the display routines while data is not ready.
About texture names: you can check if there are duplicated texture names, logging, displaying,… their name. This idea came up to my mind when you said that you don’t experienced any problem when texture name generation is done in only one thread (only one context). My guess is that RC may manage their own texture namespace though they share all their texture objects. As I said I may be wrong on this point.
But to answer your last question, I meant that texture name are IMO unique in their RC but may be not among all RC.
Now if you use PBO, you can actually create just one PBO that loads asynchonously texture data while, you are performing display operation. This way, you do not even have to create two rendering contexts and to create threads.