The following functions are duplicated between opengl32.dll and gdi32.dll:
[opengl32.dll] / [gdi32.dll]
wglChoosePixelFormat / ChoosePixelFormat
wglDescribePixelFormat / DescribePixelFormat
wglGetPixelFormat / GetPixelFormat
wglSetPixelFormat / SetPixelFormat
wglSwapBuffers / SwapBuffers
I have been searching for an answer for a long time now, but noone appears to have any concrete information why that is and what their exact difference is.
The OpenGL FAQ, section 5.190, suggests that these functions are not functionally identical:
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.
Does "run-time linking to an OpenGL driver" imply bypassing opengl32.dll and loading an ICD directly?
A stackoverflow thread named "Mesa3D does not like my context creation code", appears to reinforce this.
Another stackoverflow thread, named wglCreateContext in C# failing but not in managed C++ suggests that opengl32.dll must be loaded before gdi32.dll when using the GDI functions, or risk runtime failure (error: 2000).
My own testing indicates that "error: 2000" occurs on some systems (Nvidia, but not Intel or a Parallels VM) if the opengl32/wgl version of these functions is called. Changing to the GDI version clears this issue, but using LoadLibrary("opengl32.dll") does not appear to change anything.
Has anyone ever investigated the difference between these WGL and GDI functions? It is clear that there is some form of difference, and I am trying to understand which version should be used under which circumstances and what are the potential pitfalls if the wrong version is used.
Edit: wayback machine brings up a webpage that describes how direct loading of an ICD works. This was apparently required back in the Voodoo 1/2 days when the 2d and 3d accelerators were two different pieces of hardware with separate ICDs (which the normal opengl32.dll+ICD mechanism couldn't handle.) Quake 1 and 2 would apparently load ICDs directly because of this.
However, a post below shows that the AMD ICD does not export the wgl variants, which contradicts this idea.
There has to be someone or some place out there that holds the keys to this knowledge.
Edit 2: from the webpage above comes the clearest suggestion yet:
"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. "
But how does this fit in with the fact that the AMD ICD does not export wgl functions?
Edit 2: apparently Mesa3d exports WGL symbols, as can be seen here: http://cgit.freedesktop.org/mesa/mesa/tree/src/mesa/drivers/windows/gdi
This makes sense, since Mesa3d is not supposed to be used as an ICD. This fits with the pattern in the Mesa3d thread linked above: their calls are not being routed through Microsoft's opengl32.dll, so gdi functions fail, but Mesa3d is exporting wgl* functions so these still work. However, that's specific to Mesa3d - that method would fail if you tried to use AMD's ICD directly.
There is a huge difference, namely that the prototypes for the WGL functions are not defined in any system headers. opengl32.dll exports the symbols, but unless you manually import the functions you would never know this.
However, the functions that WGL Installable Client Drivers (ICD) implement are actually prefixed like this:
DrvSwapBuffers (...)
,DrvSetPixelFormat (...)
,DrvGetProcAddress (...)
, etc... So you are definitely not linking directly to an ICD if you callwglChoosePixelFormat (...)
instead ofChoosePixelFormat (...)
.opengl32.dll is basically Microsoft's GDI implementation of OpenGL and a wrapper for ICDs. You can even see what an implementation of an ICD looks like if you look at Mesa; notice how none of the functions are prefixed with
wgl
? ICDs do not export any wgl-prefixed symbols, the WGL functions they do implement are all extensions (e.g.wglSwapIntervalEXT (...)
,wglChoosePixelFormatARB (...)
, etc.) and can only be loaded usingwglGetProcAddress (...)
orDrvGetProcAddress (...)
.Take a look at AMD's OpenGL ICD:
You will notice that AMD actually fully implements the EGL API in their ICD (and you can get the necessary headers to use EGL on AMD hardware here), but WGL symbols are not exported.
Update:
As explained in comments, gdi32.dll actually invokes
wglChoosePixelFormat (...)
when you callChoosePixelFormat (...)
. The very first thing the function does is try and load opengl32.dll and callwglChoosePixelFormat (...)
:Here is
GetAPI
(all it does is load opengl32.dll and import a named function from it):Now, ICDs do not actually implement
ChoosePixelFormat (...)
, as it is functionally identical across all implementations. It is a simple pattern matching function. If you want to see how opengl32.dll dispatches one of itswgl...
functions to an ICD at run-time, take a look at the control flow forwglSwapBuffers
:The red left-hand branch is what occurs when an ICD is installed and the green right-hand branch is the default GDI implementation of
wglSwapBuffers
. Interestingly, you can see that the GDI implementation requires a fullglFinish (...)
. Most hardware drivers will tend to flush the command queue instead of finishing when you swap buffers, this allows better CPU/GPU parallelism.