Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OpenGL: secondary thread for loading resources?

Tags:

c

winapi

opengl

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?

like image 540
Jonathan Avatar asked Nov 14 '11 01:11

Jonathan


2 Answers

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:

  • Generate name (GenTextures, GenBuffers)
  • Define object (BindTexture, BindBuffer)
  • Object existence (IsTexture, IsShader, IsFramebuffer)
  • Delete name (and object)

(Note that an object created with Gen routines exists only when they are bound)

Object classes could be

  • Display lists
  • Texture objects
  • Buffer objects
  • Shader objects and program objects
  • Renderbuffer objects
  • Framebuffer objects
  • Query objects
  • Sync objects
  • Transform feedback objects

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..

like image 69
Luca Avatar answered Sep 27 '22 01:09

Luca


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 :)

like image 25
genpfault Avatar answered Sep 24 '22 01:09

genpfault