【发布时间】:2014-01-05 21:31:48
【问题描述】:
以下函数在 opengl32.dll 和 gdi32.dll 之间重复:
[opengl32.dll] / [gdi32.dll]
wglChoosePixelFormat / ChoosePixelFormat
wglDescribePixelFormat / DescribePixelFormat
wglGetPixelFormat / GetPixelFormat
wglSetPixelFormat / SetPixelFormat
wglSwapBuffers / SwapBuffers
我一直在寻找答案很长时间,但似乎没有人知道为什么会这样以及它们的确切区别是什么。
OpenGL FAQ 第 5.190 节表明这些函数在功能上不相同:
为确保 OpenGL 正确运行,请使用 ChoosePixelformat, DescribePixelformat、GetPixelformat、SetPixelformat 和 SwapBuffers, 而不是 wgl 等效项 wglChoosePixelformat, wglDescribePixelformat、wglGetPixelformat、wglSetPixelformat 和 wglSwapBuffers。在所有其他情况下,使用 wgl 函数,其中 可用的。使用五个 wgl 函数只对 开发人员运行时链接到 OpenGL 驱动程序。
“运行时链接到 OpenGL 驱动程序”是否意味着绕过 opengl32.dll 并直接加载 ICD?
一个名为 "Mesa3D does not like my context creation code" 的 stackoverflow 线程似乎强化了这一点。
另一个名为 wglCreateContext in C# failing but not in managed C++ 的 stackoverflow 线程建议在使用 GDI 函数时必须在 gdi32.dll 之前加载 opengl32.dll,否则可能会出现运行时失败(错误:2000)。
我自己的测试表明,如果调用这些函数的 opengl32/wgl 版本,一些系统(Nvidia,但不是 Intel 或 Parallels VM)上会出现“错误:2000”。更改为 GDI 版本可以解决此问题,但使用 LoadLibrary("opengl32.dll") 似乎没有任何改变。
有没有人研究过这些 WGL 和 GDI 函数之间的区别?很明显,存在某种形式的差异,我试图了解在什么情况下应该使用哪个版本,以及如果使用了错误的版本,可能会遇到什么问题。
编辑:wayback machine brings up a webpage 描述了直接加载 ICD 的工作原理。这显然是 Voodoo 1/2 天的要求,当时 2d 和 3d 加速器是两个不同的硬件,具有单独的 ICD(普通的 opengl32.dll+ICD 机制无法处理)。地震 1 和 2 显然会加载直接因为这个ICD。
但是,下面的帖子显示 AMD ICD 不导出 wgl 变体,这与此想法相矛盾。
必须有人或某个地方掌握着这些知识的钥匙。
编辑 2:从上面的网页中得到了最清晰的建议:
"因此,如果您使用的是名为 opengl32.dll 的 OpenGL 驱动程序,您 必须调用 GDI 函数,如果您不使用名为 opengl32.dll 的驱动程序,则必须不调用 GDI 函数。 "
但这与 AMD ICD 不导出 wgl 函数这一事实有何关系?
编辑 2:显然 Mesa3d 导出 WGL 符号,如下所示:http://cgit.freedesktop.org/mesa/mesa/tree/src/mesa/drivers/windows/gdi
这是有道理的,因为 Mesa3d 不应该用作 ICD。这符合上面链接的 Mesa3d 线程中的模式:它们的调用没有通过 Microsoft 的 opengl32.dll 路由,因此 gdi 函数失败,但 Mesa3d 正在导出 wgl* 函数,因此这些函数仍然有效。但是,这是 Mesa3d 特有的 - 如果您尝试直接使用 AMD 的 ICD,该方法将失败。
【问题讨论】:
-
有一个巨大的区别,即WGL函数的原型没有在任何系统头文件中定义。 OpenGL32.DLL 导出符号,但除非您手动导入函数,否则您永远不会知道这一点。我怀疑这就是“运行时链接”的意思,你必须做一些讨厌的
LoadLibrary (...)的东西。顺便问一下,您使用的是什么语言?大多数情况下,当这个问题出现时,它是在 C# 的上下文中,LoadLibrary (...)是一种更常见的做法。在 C 和 C++ 中,大多数人链接到 opengl32.lib / gdi32.lib 并使用 GDI32 函数。 -
我在开发 OpenTK 时第一次遇到 C# 的这个问题,但我目前正在使用 C++。这个问题与语言无关。使用 LoadLibrary("opengl32.dll") 的原因是为了维护 1.1 之前和 1.1 之后的 OpenGL 函数(GetProcAddress + wglGetProcAddress)的单一代码路径。
-
这肯定不仅仅是早期/晚期绑定的差异。这些函数在 wgl.spec 中定义并记录在 MSDN 中,因此它们是否在特定的 gl.h 实现中导出并不重要。
-
您提到的那些功能在 MSDN 上没有记录,您可能需要使用正确的前缀再次搜索。它们不是公开定义的,您必须手动加载 DLL 导入。为了获得最大的兼容性,您应该避免使用未记录的/私有函数,每当新版本的 Windows 出现时,它们通常是首先要破坏的。
-
opengl32.dll 不是 ICD。也许这将有助于清除一些事情。它使用不同的接口与 ICD 通信:
Drv...,这就是 ICD 不导出wgl...函数的原因。就地震 1 和 2 而言,他们没有使用 ICD。他们有MiniGL drivers,那是很糟糕的事情;他们只实现了雷神之锤 1 和 2 所需的功能,通常不适用于任何其他游戏。