opengl - 为什么 opengl32.dll 和 gdi32.dll 之间有重复的函数?

标签 opengl gdi wgl

以下函数在 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:
ICD Exports
您会注意到 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
现在,ICD 并没有真正实现 ChoosePixelFormat (...) ,因为它在所有实现中在功能上是相同的。这是一个简单的模式匹配功能。如果你想看看 opengl32.dll dispatch 其wgl...之一运行时对 ICD 的函数,查看 wglSwapBuffers 的控制流:
wglSwapBuffers - opengl32.dll
红色左侧分支是安装 ICD 时发生的情况,绿色右侧分支是 wglSwapBuffers 的默认 GDI 实现。 .有趣的是,您可以看到 GDI 实现需要完整的 glFinish (...) .大多数硬件驱动程序在交换缓冲区时倾向于刷新命令队列而不是完成,这允许更好的 CPU/GPU 并行性。

关于opengl - 为什么 opengl32.dll 和 gdi32.dll 之间有重复的函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20645706/

相关文章:

c# - 如何测量给定字体/大小的数字的像素宽度 (C#)

c++ - StretchBlt 收缩损坏

c++ - openGL PBO 使用 wglcontext,不创建窗口

c++ - 如何用 C++ 编写 Cocoa OpenGL 应用程序?

opengl - "unknown GLU entry gluOrtho2D"在 Haskell 中使用 opengl

c# - 面板 c# 中出现奇怪的白色区域

windows - Windows 上的 OpenGL ICD 如何加载 OpenGL 1.0 和 1.1 功能?

c++ - 如何将多个纹理加载到片段着色器中

opengl - 为什么分配大量VBO会导致性能问题?

c++ - wglGetProcAddress 返回 NULL