为什么 OpenGL 函数在运行时加载而不是动态链接?

Why are OpenGL functions loaded at runtime instead of dynamically linked?

OpenGL API 的用户通常使用 GLEW 等库,或者乐于在运行时加载 OpenGL 函数。为什么动态加载是首选的链接方法?

静态链接显然不是一种选择,因为使用 OpenGL 的程序通常由作者编译,并分发给针对其特定显卡具有不同 OpenGL 库的用户。

这样就剩下动态链接和动态加载了。似乎动态链接可以工作,因为我们知道我们想要访问的所有函数的名称。

动态链接是否可行?如果不是,为什么?如果是这样,为什么首选动态加载?

你想要的都有可能。您可以制作一个带有静态接口的 DLL/SO 加载器,它将从幕后的实现中加载函数指针。它将根据当前的上下文将函数调用传递给实现。事实上,这基本上就是现代 Linux 发行版的工作方式。

这也是 WGL 在 Windows 上的工作方式...无论如何,通过 OpenGL 1.1 版。

它不是 "preferred" 的原因是它需要努力。必须有人创建并维护 这个位于应用程序和驱动程序之间的中间库。每当出现新的扩展时,就必须更新库。每当出现新版本时,都必须更新库。然后你必须确保 link 使用这个库的正确版本。

该附加依赖项在 Linux 上运行良好,因为它保持最新。 OpenGL32.dll 在 Windows 然而不是。 WinNT 采用了 OpenGL 一段时间,但 Microsoft 也离开了 创建 为 Win9x 购买了自己的图形 API。所以他们从来没有为更高版本的 OpenGL 或新的扩展更新 OpenGL32.dll。如果他们愿意不向后兼容,我想他们会完全放弃 OpenGL32.dll 他们的 OS.

由于您需要一个 运行time loader 才能在 Windows 中工作,使用相同的 运行time loader 可以更容易地让所有平台都工作(尽管显然具有不同的功能获取函数指针)。虽然您可以创建您正在谈论的那种 DLL,但它只是一个 OpenGL 加载库,一个您必须维护的依赖项。没有 Linux/MESA 给 table 带来的集中化,就没有必要打扰了。


I was thinking that an application could be dynamically linked directly to the driver itself without an intermediate library

你可以的。但是,您将 link 使用静态导入库访问该特定驱动程序的库。这意味着如果您 link 反对 NVIDIA 的实现,您的应用程序将无法 运行 AMD 的实现。

而且您不能静态地link 为两个 DLL 导入库。原因是如果无法加载一个静态导入库,您的应用程序 将终止 。因此,除非您的机器上 AMD 和 NVIDIA 的实现,否则您将无法 运行 任何一个。

还有:

since even though the driver library can't be available at compile time, we still know the OpenGL function names

假设他们的驱动程序直接 导出 这些名称。很难保证。

毕竟WGL/GLX接口是用wgl/glXGetProcAddress获取函数指针的。如果WGL/GLX和驱动之间的接口只是将字符串传递给驱动的函数,那么驱动不需要直接导出任何函数。它通过单个入口点公开其 API,强制 运行time 函数指针加载而不是允许静态 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?

所有部分都是错误的。您 link 反对基本界面 API(如 WGL 或 GLX)。加载库使用该接口加载函数指针。接口 API 如何将函数指针加载到驱动程序 DLL 中是一个特定于平台的问题。在 Windows 上,wglGetProcAddress 调用驱动程序中的函数,传递函数的字符串名称并取回函数指针。

在 Linux,GLX 倾向于在内部制造功能,使用后期绑定技术稍后加载实际的驱动程序功能。也就是说,您可以使用一些伪造的名称调用 glXGetProcAddress,它会 return 一个函数指针 shim,调用时将从驱动程序加载当前上下文的函数。

OpenGL wiki 提供了对 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.

OpenGL 的扩展一直在出现,并且可能可用也可能不可用,具体取决于供应商和驱动程序平台。 OpenGL wiki 声明在 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.

因此,即使 Apple 维护了一个动态库link,您仍然需要添加一个层来检查给定功能是否可用,具体取决于支持的 OpenGL 版本和扩展。