以下函数在 opengl32.dll 和 gdi32.dll 之间重复:
[opengl32.dll] / [gdi32.dll]
wglChoosePixelFormat / ChoosePixelFormat
wglDescribePixelFormat / DescribePixelFormat
wglGetPixelFormat / GetPixelFormat
wglSetPixelFormat / SetPixelFormat
wglSwapBuffers / SwapBuffers
我一直在寻找答案很长一段时间,但似乎没有人有任何具体信息为什么会这样以及它们的确切区别是什么。
OpenGL FAQ ,第 5.190 节,表明这些功能在功能上并不相同:
To ensure correct operation of OpenGL use ChoosePixelformat, DescribePixelformat, GetPixelformat, SetPixelformat, and SwapBuffers, instead of the wgl equivalents, wglChoosePixelformat, wglDescribePixelformat, wglGetPixelformat, wglSetPixelformat, and wglSwapBuffers. In all other cases use the wgl function where available. Using the five wgl functions is only of interest to developers run-time linking to an OpenGL driver.
“运行时链接到 OpenGL 驱动程序”是否意味着绕过 opengl32.dll 并直接加载 ICD?
一个名为 "Mesa3D does not like my context creation code" 的 stackoverflow 线程,似乎强化了这一点。
另一个stackoverflow线程,名为wglCreateContext in C# failing but not in managed C++建议在使用 GDI 函数时,opengl32.dll 必须在 gdi32.dll 之前加载,否则有运行时失败的风险(错误:2000)。
我自己的测试表明,如果调用这些函数的 opengl32/wgl 版本,某些系统(Nvidia,但不是 Intel 或 Parallels VM)上会出现“错误:2000”。更改为 GDI 版本可以解决此问题,但使用 LoadLibrary("opengl32.dll") 似乎不会改变任何内容。
有没有人研究过这些 WGL 和 GDI 函数之间的区别?很明显,存在某种形式的差异,我试图了解在什么情况下应该使用哪个版本,以及如果使用了错误的版本,可能会遇到什么问题。
编辑:回程机brings up a webpage描述了直接加载 ICD 的工作原理。这显然是 Voodoo 1/2 天的要求,当时 2d 和 3d 加速器是两个不同的硬件,具有单独的 ICD(普通的 opengl32.dll+ICD 机制无法处理)。地震 1 和 2 显然会加载ICDs 直接因为这个。
但是,下面的帖子显示 AMD ICD 不导出 wgl 变体,这与这个想法相矛盾。
必须有某个人或某个地方掌握着这些知识的 key 。
编辑2:从上面的网页中得到了最明确的建议:
"Therefore if you are using a OpenGL driver named opengl32.dll you must call the GDI functions, and if you are not using a driver named opengl32.dll you must NOT call the GDI functions. "
但这与 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 函数的原型(prototype)没有在任何系统头文件中定义。 opengl32.dll 导出符号,但除非您手动导入函数,否则您永远不会知道这一点。
然而,WGL Installable Client Drivers (ICD) 实现的功能实际上是这样前缀的:DrvSwapBuffers (...)
, DrvSetPixelFormat (...)
, DrvGetProcAddress (...)
等等...所以如果您调用wglChoosePixelFormat (...)
,您肯定不会直接链接到ICD。而不是 ChoosePixelFormat (...)
.
opengl32.dll
基本上是微软的 OpenGL 的 GDI 实现和 ICD 的包装器。如果您查看 Mesa,您甚至可以看到 ICD 的实现是什么样的。 ;注意没有一个函数以 wgl
为前缀? ICD 不导出任何以 wgl 为前缀的符号,它们实现的 WGL 函数都是扩展(例如 wglSwapIntervalEXT (...)
、wglChoosePixelFormatARB (...)
等)并且只能使用 wglGetProcAddress (...)
加载或 DrvGetProcAddress (...)
.
看看 AMD 的 OpenGL ICD:
您会注意到 AMD 实际上在其 ICD 中完全实现了 EGL API(并且您可以获得必要的 header 以在 AMD 硬件 here 上使用 EGL),但不会导出 WGL 符号。
更新:
如评论中所述, gdi32.dll 实际调用 wglChoosePixelFormat (...)
当您调用 ChoosePixelFormat (...)
.该函数所做的第一件事是尝试加载 opengl32.dll 并调用wglChoosePixelFormat (...)
:
.text:4D579CAC ; int __stdcall ChoosePixelFormat(HDC,const PIXELFORMATDESCRIPTOR *)
.text:4D579CAC public _ChoosePixelFormat@8
.text:4D579CAC _ChoosePixelFormat@8 proc near
.text:4D579CAC
.text:4D579CAC hLibModule = dword ptr -4
.text:4D579CAC arg_0 = dword ptr 8
.text:4D579CAC arg_4 = dword ptr 0Ch
.text:4D579CAC
.text:4D579CAC mov edi, edi
.text:4D579CAE push ebp
.text:4D579CAF mov ebp, esp
.text:4D579CB1 push ecx
.text:4D579CB2 push esi
.text:4D579CB3 lea eax, [ebp+hLibModule]
.text:4D579CB6 push eax ; int
.text:4D579CB7 push offset aWglchoosepixel ; "wglChoosePixelFormat"
.text:4D579CBC call _GetAPI@12 ; GetAPI(x,x,x)
.text:4D579CC1 xor esi, esi
.text:4D579CC3 test eax, eax
.text:4D579CC5 jz short loc_4D579CD1
.text:4D579CC7 push [ebp+arg_4]
.text:4D579CCA push [ebp+arg_0]
.text:4D579CCD call eax
.text:4D579CCF mov esi, eax
这里是 GetAPI
(它所做的只是加载 opengl32.dll 并从中导入一个命名函数):![GetAPI - gdi32.dll](https://i.sstatic.net/SprgF.png)
现在,ICD 并没有真正实现
ChoosePixelFormat (...)
,因为它在所有实现中在功能上是相同的。这是一个简单的模式匹配功能。如果你想看看 opengl32.dll dispatch 其wgl...
之一运行时对 ICD 的函数,查看 wglSwapBuffers
的控制流:![wglSwapBuffers - opengl32.dll](https://i.sstatic.net/QvDPj.png)
红色左侧分支是安装 ICD 时发生的情况,绿色右侧分支是
wglSwapBuffers
的默认 GDI 实现。 .有趣的是,您可以看到 GDI 实现需要完整的 glFinish (...)
.大多数硬件驱动程序在交换缓冲区时倾向于刷新命令队列而不是完成,这允许更好的 CPU/GPU 并行性。
关于opengl - 为什么 opengl32.dll 和 gdi32.dll 之间有重复的函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20645706/