Working with C and Win32, I would like to know how to implement a secondary OpenGL thread for loading resources(textures and VBOs).
From what I found, this should be done with wglShareLists(), but I am unsure about how to set up the secondary thread:
Do I need a new device context or only a new rendering context?
What wgl functions do I need to call?
You don't need a new context because you can reuse the same device context of the first one. Btw, you can specify another device context, but depending on your platform you should take care about it (on Windows, device contextes must have the same pixel format), otherwise you could fail to share objects between two contextes
Create both context in the main thread, the second one sharing with the first one. Then, make the first one current on the main thread, while making the other one current on the secondary thread. Note that you can share with any render context: all sharing contextes "see" the same object by its name, indeed they share an object name space. Two different object name spaces (i.e. two non-sharing contextes) can have defined the same object (i.e. texture object name is 1), but the same name actually points to different object depending on the current context.
Objects created by the secondary thread are visible concurrently and consistently. However, not all objects can be shared across contextes. Keep in mind that sometimes it happens that the driver supports unexpected objects, and other times it happens that driver doesn't support correctly an expected object.
OpenGL is becoming an object oriented language. You can see a certain pattern for creating objects:
(Note that an object created with Gen routines exists only when they are bound)
Object classes could be
I would suggest to use a "runtime" test, like the following:
private bool TestSharingObject(RenderContext rContextShare)
{
uint texture = 0;
// rContextShader is a context sharing with this RenderCOntext
this.MakeCurrent(true);
if (Caps.TextureObject.Supported == true) {
// Generate texture name
Gl.GenTextures(1, out texture);
// Ensure existing texture object
Gl.BindTexture(Gl.TEXTURE_2D, texture);
Gl.BindTexture(Gl.TEXTURE_2D, 0);
// Self test
if (Gl.IsTexture(texture) == false)
throw new NotSupportedException();
}
// Make current sharing context
rContextShare.MakeCurrent(true);
return ((texture != 0) && (Gl.IsTexture(texture) == true));
}
Another suggestion would be to run on secondary thread operations that are CPU intensive, and not directly affecting drawing system windows buffers. A good example would be a shader compilation, since the compilation runs on CPU side; keep also in mind that the driver could async your operations, and that OpenGL implementations may pipeline different operations..
Load resources however you need to in your secondary thread and then pass ownership of them back to your primary for the GL calls.
Sharing "lists" between GL contexts should work. Doing all your GL calls on your primary thread does work :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With