以下功能在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并行性。