你想要的都是可能的。您可以制作一个带有静态接口的 DLL/SO 加载器,它将从幕后的实现中加载函数指针。它将根据当前的上下文将函数调用传递给实现。事实上,这就是现代 Linux 发行版的本质。
这也是 WGL 在 Windows 上的工作方式……至少 OpenGL 版本 1.1。
它不是“首选”的原因是因为它需要努力。必须有人创建和维护这个位于应用程序和驱动程序之间的中间库。每当出现新的扩展时,都必须更新库。每当新版本出现时,都必须更新库。然后你必须确保链接到这个库的正确版本。
这个额外的依赖在 Linux 上运行良好,因为它一直是最新的。 Windows 上的 OpenGL32.dll 但不是。 WinNT 采用 OpenGL 有一段时间了,但微软也离开并创建为 Win9x 购买了他们自己的图形 API。因此,他们从未为更高版本的 OpenGL 或新扩展更新 OpenGL32.dll。如果他们愿意不向后兼容,我想他们会完全从他们的操作系统中放弃 OpenGL32.dll。
由于您需要一个运行时加载程序才能在 Windows 中工作,因此使用相同的运行时加载程序让所有平台都工作会更容易(尽管显然使用不同的函数来获取函数指针)。虽然您可以创建您正在谈论的那种 DLL,但它只是多了一个 OpenGL 加载库,多了一个您必须维护的依赖项。如果没有 Linux/MESA 带来的集中化,那么麻烦就没有意义了。
我在想一个应用程序可以直接动态链接到驱动程序本身而无需中间库
你可以这样做。但是,您将使用静态导入库链接到该特定驱动程序的库。这意味着如果您链接到 NVIDIA 的实现,您的应用程序将无法在 AMD 的实现上运行。
而且您不能静态链接到两个 DLL 的导入库。原因是如果一个静态导入库无法加载,您的应用程序终止。因此,除非您的计算机上同时拥有 AMD 和 NVIDIA 的实现,否则您将无法在其中任何一个上运行。
还有:
即使驱动库在编译时不可用,我们仍然知道 OpenGL 函数名称
假设他们的驱动程序直接导出这些名称。这很难保证。
毕竟WGL/GLX接口是使用wgl/glXGetProcAddress来获取函数指针的。如果WGL/GLX与驱动的接口只是简单的将字符串传递给驱动的函数,那么驱动就不需要直接导出任何函数。它通过单个入口点公开其 API,强制加载运行时函数指针而不是允许静态链接。
我的理解是 OpenGL 从 dll/dylib/so 库文件中加载库 LoadLibrary/dlopen,这些库文件本身就是显卡驱动程序,并且这些驱动程序库具有带有 OpenGL 函数的符号表。其中哪些部分是错误的?
所有部分都是错误的。您链接到基本接口 API(如 WGL 或 GLX)。加载库使用该接口来加载函数指针。接口 API 如何将函数指针加载到驱动程序 DLL 是一个特定于平台的问题。在 Windows 上,wglGetProcAddress 调用驱动程序中的函数,传递函数的字符串名称并取回函数指针。
在 Linux 上,GLX 倾向于在内部制造函数,使用后期绑定技术稍后加载实际的驱动程序函数。也就是说,您可以使用一些虚假名称调用glXGetProcAddress,它会返回一个函数指针 shim,当调用该函数指针时,将从驱动程序加载当前上下文的函数。