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 call wglChoosePixelFormat (...)
instead of ChoosePixelFormat (...)
.
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 using wglGetProcAddress (...)
or DrvGetProcAddress (...)
.
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 call ChoosePixelFormat (...)
. The very first thing the function does is try and load opengl32.dll and call 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
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 its wgl...
functions to an ICD at run-time, take a look at the control flow for wglSwapBuffers
:
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 full glFinish (...)
. Most hardware drivers will tend to flush the command queue instead of finishing when you swap buffers, this allows better CPU/GPU parallelism.