Reputation: 24039
Users of OpenGL APIs typically use a library such as GLEW or glad to load OpenGL functions at runtime. Why is dynamic loading the preferred linking method?
Static linking is clearly not an option since programs using OpenGL are typically compiled by the author and distributed to users who have different OpenGL libraries for their particular graphics cards.
That leaves dynamic linking and dynamic loading. It seems like dynamic linking could work since we know the names of all the functions we'll want to access.
Is dynamic linking a viable option? If not, why? If so, why is dynamic loading preferred?
Upvotes: 4
Views: 2966
Reputation: 473342
What you want is possible. You can make a loader that is a DLL/SO with a static interface, which will load function pointers from the implementation behind the scenes. It will pipe function calls to the implementation, based on which context is current. Indeed, this is essentially how modern Linux distros work.
This is also how WGL works on Windows... up though OpenGL version 1.1, at any rate.
The reason it is not "preferred" is because it requires effort. Someone has to create and maintain this intermediary library that sits between the application and the driver. Whenever a new extension comes out, the library has to be updated. Whenever a new version comes out, the library has to be updated. And then you have to make sure to link with the right version of this library.
That additional dependency worked out OK on Linux, because it was kept up to date. OpenGL32.dll on Windows however was not. WinNT adopted OpenGL for a while, but Microsoft had also gone off and createdpurchased their own graphics API for Win9x. So they never updated OpenGL32.dll for later OpenGL versions or new extensions. And if they were willing to be non-backwards compatible, I imagine they'd have ditched OpenGL32.dll entirely from their OS.
Since you need a runtime loader to work in Windows, it's easier to just make all platforms work using the same runtime loader (though obviously with a different function fetching the function pointers). And while you could create the kind of DLL you're talking about, it would just be one more OpenGL loading library, one more dependency you have to maintain. Without the centralization that Linux/MESA brings to the table, there's just no point in bothering.
I was thinking that an application could be dynamically linked directly to the driver itself without an intermediate library
You can do that. However, you would be linking to that particular driver's library with a static import library. This means that if you link against NVIDIA's implementation, your application will fail to run on AMD's implementation.
And you can't statically link to import libraries for both DLLs. The reason being that if one static import library cannot be loaded, your application terminates. So unless you have both AMD and NVIDIA's implementations on your machine, you would not be able to run on either one.
Also:
since even though the driver library can't be available at compile time, we still know the OpenGL function names
That assumes that their drivers directly export those names. That is hardly guaranteed.
After all, the WGL/GLX interface is to use wgl/glXGetProcAddress
to get function pointers. If the interface between WGL/GLX and the driver is simply to pass the string to the driver's function, then the driver doesn't need to export any functions directly. It exposes its API through a single entrypoint, forcing runtime function pointer loading rather than allowing static linking.
My understanding is that OpenGL loading libraries LoadLibrary/dlopen from dll/dylib/so library files which are themselves graphics card drivers and those driver libraries have symbol tables with OpenGL functions. Which parts of that are wrong?
All parts of that are wrong. You link against the basic interface API (like WGL or GLX). The loading library uses that interface to load function pointers. How the interface API translates loading a function pointer into the driver DLL is a platform-specific issue. On Windows, wglGetProcAddress
calls a function in the driver, passing the string name of the function and getting back the function pointer.
On Linux, GLX tends to manufacture functions internally, using late-binding techniques to load the actual driver function later. That is, you can call glXGetProcAddress
with some bogus name, and it will return a function pointer shim that, when called, will load the function for the current context from the driver.
Upvotes: 7
Reputation: 10390
The OpenGL wiki gives some insight into the OpenGL function loading process. Not that using the GetProcAddress
functions amounts to a form of dynamic linking done outside of the operating system itself. From Wikipedia:
In computing, a dynamic linker is the part of an operating system that loads and links the shared libraries needed by an executable when it is executed (at "run time"), by copying the content of libraries from persistent storage to RAM, and filling jump tables and relocating pointers.
Extensions for OpenGL come out all the time and can be either available or not depending on vendors and driver platforms. The OpenGL wiki states that on MacOSX:
GL functions on OSX have been weak linked since OSX 10.2; this means that you can call them directly and unimplemented extensions will resolve to NULL. Note that this means that you must parse the extension string to determine if a function is valid or not, or your program will crash.
So even if Apple maintains a library to dynamically link with, you still need to add a layer to check whether a given function is available or not depending on the supported OpenGL version and extensions.
Upvotes: 1