OpenGL函数加载机制是如何工作的?

How does the OpenGL function loading mechanism work?

现代 OpenGL (>1.2) 函数必须在运行时加载。具体是如何完成的取决于平台,但它似乎总是涉及调用一个 returns 指向您请求的函数的指针的“get-function”。两个问题:

  1. 谁实现了这个神奇的 get 函数?
  2. 谁实现了函数(指针)呢returns?

让我们以 Linux 和 Mesa3D 为例。

我现在的理解是Mesa3D通过libgl.so和gl.h提供get-function,并且它只在用户空间运行。也是 Mesa3D 实现了 get 函数返回的函数的用户空间端,内核端由 GPU 驱动程序实现。这是正确的吗?

这意味着(在这个例子中)像 glad/glew/gl3w 这样的加载库直接位于 Mesa3D 之上并且只与 Mesa3D 对话?

  1. Who implements this magical get-function?

这个函数实际上有点棘手,因为这个函数不是 OpenGL 的一部分,而是平台特定的 OpenGL 绑定库的一部分。例如,您在 Win32/wgl 上有 wglGetProcAddress,在 X11 上有 glxGetProcAddress,在 EGL(多平台,更现代和灵活的替代方案)上有 elgGetProcAddress

在 Linux,EGL 和 glX 实现是 OpenGL 实现的一部分(例如 mesa,但 nivida 的专有驱动程序带有它自己的 glX 和 egl 库),所以你的问题的答案是“ opengl 实现者。

在 windows 上,答案是“Microsoft”,但这是一个毫无意义的答案,因为 Microsoft 函数基本上只调用 OpenGL ICD(可安装的客户端驱动程序)中的一些特定于实现者的函数,它真正工作,那个来自 cousre 的 opengl 实现者(通常是 intel、nvidia、AMD,但你甚至可以在 windows 上 运行 mesa 软件光栅器)。

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

OpenGL 实现者。通常,OpenGL 实现是图形驱动程序的一部分。

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 有点特殊,因为它是一个多供应商 OpenGL 实现。实际上,mesa 由一些共享前端(构成 libGL 和其他的外部接口)和实用程序功能,以及一些特定于供应商的后端组成。那些 mesa 后端实际上被认为是图形驱动程序的一部分,驱动程序不仅仅是 mesa 与之通信的内核模块。大量的图形 API(尤其是在 GL 中)是在用户 space 中实现的,并且仍然是高度特定于设备的。

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?

或多或少。事实有点复杂和丑陋。在某些平台上,扩展函数指针查询函数不需要 return OpenGL 1.1 核心中函数的指针,因此大多数加载器通过求助于 GetProcAddress (win32) 或 dlsym 在 运行 时间查询这些符号,因此他们通常也可能在 Linux 上使用 libdl.so(以及 dlopen 你背后的 GL 库)。请注意,这也意味着当您使用像 GLAD 这样的 GL 加载程序时,您根本不必(实际上不应该)手动 link 到 libGL.so 在你的项目中——无论如何,它在 运行 时间完全加载,如果用户系统上没有可用的 GL 库,你的程序也可以很好地退出,而不是二进制文件由于缺少库而没有启动。

此外,现代 Linux 发行版使用 libgvnd 供应商中立的 GL 调度方案,这意味着即使您使用 Mesa3D,GL 加载器实际上也会与 GLvnd 存根对话,它在内部会将请求路由到您使用的实现(在您的情况下为 mesa3d)。