以下功能在opengl32.dll和gdi32.dll之间重复:

[opengl32.dll]         / [gdi32.dll]
wglChoosePixelFormat   / ChoosePixelFormat
wglDescribePixelFormat / DescribePixelFormat
wglGetPixelFormat      / GetPixelFormat
wglSetPixelFormat      / SetPixelFormat
wglSwapBuffers         / SwapBuffers

我一直在寻找答案很久了,但是似乎没有人知 Prop 体的信息,这是为什么以及它们的确切区别是什么。

OpenGL FAQ(第5.190节)建议这些功能在功能上并不相同:



“运行时链接到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机器brings up a webpage,它描述了如何直接加载ICD。当2d和3d加速器是带有独立ICD的两个不同硬件(普通的opengl32.dll + ICD机制无法处理)时,这显然是在Voodoo 1/2天中所必需的。地震1和2显然会加载正因为如此,ICD才得以实现。

但是,下面的帖子显示AMD ICD没有导出wgl变体,这与这个想法相矛盾。

必须有某个人或某个地方掌握此知识的关键。

编辑2:从上面的网页来的最清晰的建议是:



但是,这与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可安装客户端驱动程序(ICD)实现的功能实际上是这样的前缀:DrvSwapBuffers (...)DrvSetPixelFormat (...)DrvGetProcAddress (...)等...因此,如果您调用wglChoosePixelFormat (...)而不是ChoosePixelFormat (...),则绝对不能直接链接到ICD。
opengl32.dll
基本上是Microsoft的OpenGL的GDI实现和ICD的包装器。如果您查看Mesa,您甚至可以看到ICD的实现。注意,这些功能都没有前缀wgl的情况吗? ICD不会导出任何带有wgl前缀的符号,它们实现的WGL功能都是扩展名(例如wglSwapIntervalEXT (...)wglChoosePixelFormatARB (...)等),并且只能使用wglGetProcAddress (...)DrvGetProcAddress (...)加载。

看一下AMD的OpenGL ICD:

您会注意到,AMD实际上在其ICD中完全实现了EGL API(并且可以获取在AMD硬件here上使用EGL所必需的 header ),但是不会导出WGL符号。

更新:
如评论中所述,当您调用wglChoosePixelFormat (...)时, gdi32.dll 实际上会调用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 并从中导入一个命名函数):

现在,ICD实际上并未实现ChoosePixelFormat (...),因为在所有实现中它在功能上都是相同的。这是一个简单的模式匹配功能。如果要在运行时查看 opengl32.dll 如何将其wgl...函数之一分配给ICD,请查看wglSwapBuffers的控制流:

红色的左手分支是在安装ICD时发生的情况,绿色的右手分支是wglSwapBuffers的默认GDI实现。有趣的是,您可以看到GDI实现需要完整的glFinish (...)。交换缓冲区时,大多数硬件驱动程序将趋向于刷新命令队列而不是完成操作,这可以实现更好的CPU/GPU并行性。

10-07 23:54