openglgraphicsmesa

How does the OpenGL function loading mechanism work?


Modern OpenGL (>1.2) functions must be loaded at runtime. Exactly how this is done is platform-dependent, but it always seems to involve calling a "get-function" that returns a pointer to the function you requested. Two questions:

  1. Who implements this magical get-function?
  2. Who implements the function (pointers) it returns?

Let's use Linux with Mesa3D as an example.

My understanding right now is that it's Mesa3D that provides the get-function via libgl.so and gl.h, and it only operates in userspace. It's also Mesa3D that implements the userspace-side of the functions returned by the get-function, the kernel side is implemented by the GPU driver. Is this correct?

This would imply that (in this example) a loading library like glad/glew/gl3w sits directly above Mesa3D and talks to no one other than Mesa3D?


Solution

    1. Who implements this magical get-function?

    That one is actually a bit tricky, since this function is not part of OpenGL, but of the plattform-specific OpenGL binding library. For example, you have wglGetProcAddress on Win32/wgl, glxGetProcAddress on X11, elgGetProcAddress on EGL (multi-platform, more modern and flexible alternative).

    On Linux, the EGL and glX implementations are part of the OpenGL implementation (for example mesa, but nivida's proprietary driver comes with its own glX and egl libs), so the answer to your question is "the opengl implementor".

    On windows, the answer is "Microsoft" but that is a meaningless answer as the microsoft function basically only calls some implementor-specific function in the OpenGL ICD (installable client driver), which does the real work, and that one comes from the opengl implementor of cousre (intel, nvidia, AMD typically, but you could even run mesa software rasterizer on windows).

    1. Who implements the function (pointers) it returns?

    The OpenGL implementor. Typically, the OpenGL implementation is part of the graphics driver.

    My understanding right now is that it's Mesa3D that provides the get-function via libgl.so and gl.h, and it only operates in userspace. It's also Mesa3D that implements the userspace-side of the functions returned by the get-function, the kernel side is implemented by the GPU driver. Is this correct?

    Mesa3D is a bit a special case as it is a multi-vendor OpenGL implementation. Actually, mesa consists of some shared frontend (which forms the outer interface of the libGL and others) and utility functionality, and some vendor-specific backends. Those mesa backends are actually considered part of the graphics driver, the driver is not just the kernel module to which mesa talks to. A very big deal of the graphics APIs (especially in the GL) is implemented in user space, and that is still highly device-specific.

    This would imply that (in this example) a loading library like glad/glew/gl3w sits directly above Mesa3D and talks to no one other than Mesa3D?

    More or less. The truth is a bit more complex and ugly. There are some platforms where the extension function pointer query function is not required to return pointers for functions which are in OpenGL 1.1 core, so most loaders work around this by resorting to GetProcAddress (win32) or dlsym to query those symbols at runtime, so they typically they might use libdl.so on Linux, too (and dlopen the GL lib behind your back). Note that this also means that when you use a GL loader like GLAD, you do not have to (and actually should not) manually link to libGL.so at all in your project - it is completely loaded at runtime anyway, and you program could also bail out nicely if no GL lib is available on the user's system, instead of the binary not even starting due to missing libs.

    Also, modern Linux distributions use the libgvnd vendor neutral GL dispatch scheme, which means that even when you use Mesa3D, the GL loader would actually talk to the GLvnd stub, which internally would route the requests to the implementaition you use (mesa3d in your case).