2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: lib/opengl32/icdload.c
5 * PURPOSE: OpenGL32 lib, ICD dll loader
12 WINE_DEFAULT_DEBUG_CHANNEL(opengl32
);
16 DWORD Version
; /*!< Driver interface version */
17 DWORD DriverVersion
; /*!< Driver version */
18 WCHAR DriverName
[256]; /*!< Driver name */
19 } Drv_Opengl_Info
, *pDrv_Opengl_Info
;
27 } CUSTOM_DRIVER_STATE
;
29 static CRITICAL_SECTION icdload_cs
= {NULL
, -1, 0, 0, 0, 0};
30 static struct ICD_Data
* ICD_Data_List
= NULL
;
31 static const WCHAR OpenGLDrivers_Key
[] = L
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\OpenGLDrivers";
32 static const WCHAR CustomDrivers_Key
[] = L
"SOFTWARE\\ReactOS\\OpenGL";
33 static Drv_Opengl_Info CustomDrvInfo
;
34 static CUSTOM_DRIVER_STATE CustomDriverState
= OGL_CD_NOT_QUERIED
;
36 static void APIENTRY
wglSetCurrentValue(PVOID value
)
38 IntSetCurrentICDPrivate(value
);
41 static PVOID APIENTRY
wglGetCurrentValue()
43 return IntGetCurrentICDPrivate();
46 static DHGLRC APIENTRY
wglGetDHGLRC(struct wgl_context
* context
)
48 return context
->dhglrc
;
51 /* GDI entry points (win32k) */
52 extern INT APIENTRY
GdiDescribePixelFormat(HDC hdc
, INT ipfd
, UINT cjpfd
, PPIXELFORMATDESCRIPTOR ppfd
);
53 extern BOOL APIENTRY
GdiSetPixelFormat(HDC hdc
, INT ipfd
);
54 extern BOOL APIENTRY
GdiSwapBuffers(HDC hdc
);
56 /* Retrieves the ICD data (driver version + relevant DLL entry points) for a device context */
57 struct ICD_Data
* IntGetIcdData(HDC hdc
)
60 DWORD dwInput
, dwValueType
, Version
, DriverVersion
, Flags
;
61 Drv_Opengl_Info DrvInfo
;
62 pDrv_Opengl_Info pDrvInfo
;
63 struct ICD_Data
* data
;
65 HKEY DrvKey
, CustomKey
;
66 WCHAR DllName
[MAX_PATH
];
67 BOOL (WINAPI
*DrvValidateVersion
)(DWORD
);
68 void (WINAPI
*DrvSetCallbackProcs
)(int nProcs
, PROC
* pProcs
);
70 /* The following code is ReactOS specific and allows us to easily load an arbitrary ICD:
71 * It checks HKCU\Software\ReactOS\OpenGL for a custom ICD and will always load it
72 * no matter what driver the DC is associated with. It can also force using the
73 * built-in Software Implementation*/
74 if(CustomDriverState
== OGL_CD_NOT_QUERIED
)
76 /* Only do this once so there's not any significant performance penalty */
77 CustomDriverState
= OGL_CD_NONE
;
78 memset(&CustomDrvInfo
, 0, sizeof(Drv_Opengl_Info
));
80 ret
= RegOpenKeyExW(HKEY_CURRENT_USER
, CustomDrivers_Key
, 0, KEY_READ
, &CustomKey
);
81 if(ret
!= ERROR_SUCCESS
)
84 dwInput
= sizeof(CustomDrvInfo
.DriverName
);
85 ret
= RegQueryValueExW(CustomKey
, L
"", 0, &dwValueType
, (LPBYTE
)CustomDrvInfo
.DriverName
, &dwInput
);
86 RegCloseKey(CustomKey
);
88 if((ret
!= ERROR_SUCCESS
) || (dwValueType
!= REG_SZ
) || !wcslen(CustomDrvInfo
.DriverName
))
91 if(!_wcsicmp(CustomDrvInfo
.DriverName
, L
"ReactOS Software Implementation"))
93 /* Always announce the fact that we're forcing ROSSWI */
94 ERR("Forcing ReactOS Software Implementation\n");
95 CustomDriverState
= OGL_CD_ROSSWI
;
99 ret
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
, OpenGLDrivers_Key
, 0, KEY_READ
, &OglKey
);
100 if(ret
!= ERROR_SUCCESS
)
103 ret
= RegOpenKeyExW(OglKey
, CustomDrvInfo
.DriverName
, 0, KEY_READ
, &OglKey
);
104 if(ret
!= ERROR_SUCCESS
)
107 dwInput
= sizeof(CustomDrvInfo
.Version
);
108 ret
= RegQueryValueExW(OglKey
, L
"Version", 0, &dwValueType
, (LPBYTE
)&CustomDrvInfo
.Version
, &dwInput
);
109 if((ret
!= ERROR_SUCCESS
) || (dwValueType
!= REG_DWORD
))
112 dwInput
= sizeof(DriverVersion
);
113 ret
= RegQueryValueExW(OglKey
, L
"DriverVersion", 0, &dwValueType
, (LPBYTE
)&CustomDrvInfo
.DriverVersion
, &dwInput
);
114 CustomDriverState
= OGL_CD_CUSTOM_ICD
;
116 /* Always announce the fact that we're overriding the default driver */
117 ERR("Overriding the default OGL ICD with %S\n", CustomDrvInfo
.DriverName
);
122 RegCloseKey(CustomKey
);
125 /* If there's a custom ICD or ROSSWI was requested use it, otherwise proceed as usual */
126 if(CustomDriverState
== OGL_CD_CUSTOM_ICD
)
128 pDrvInfo
= &CustomDrvInfo
;
130 else if(CustomDriverState
== OGL_CD_ROSSWI
)
136 /* First, see if the driver supports this */
137 dwInput
= OPENGL_GETINFO
;
138 ret
= ExtEscape(hdc
, QUERYESCSUPPORT
, sizeof(DWORD
), (LPCSTR
)&dwInput
, 0, NULL
);
140 /* Driver doesn't support opengl */
144 /* Query for the ICD DLL name and version */
146 ret
= ExtEscape(hdc
, OPENGL_GETINFO
, sizeof(DWORD
), (LPCSTR
)&dwInput
, sizeof(DrvInfo
), (LPSTR
)&DrvInfo
);
150 ERR("Driver claims to support OPENGL_GETINFO escape code, but doesn't.\n");
157 /* Protect the list while we are loading*/
158 EnterCriticalSection(&icdload_cs
);
160 /* Search for it in the list of already loaded modules */
161 data
= ICD_Data_List
;
164 if(!_wcsicmp(data
->DriverName
, pDrvInfo
->DriverName
))
167 TRACE("Found already loaded %p.\n", data
);
168 LeaveCriticalSection(&icdload_cs
);
174 /* It was still not loaded, look for it in the registry */
175 ret
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
, OpenGLDrivers_Key
, 0, KEY_READ
, &OglKey
);
176 if(ret
!= ERROR_SUCCESS
)
178 ERR("Failed to open the OpenGLDrivers key.\n");
181 ret
= RegOpenKeyExW(OglKey
, pDrvInfo
->DriverName
, 0, KEY_READ
, &DrvKey
);
182 if(ret
!= ERROR_SUCCESS
)
184 /* Some driver installer just provide the DLL name, like the Matrox G400 */
185 TRACE("No driver subkey for %S, trying to get DLL name directly.\n", pDrvInfo
->DriverName
);
186 dwInput
= sizeof(DllName
);
187 ret
= RegQueryValueExW(OglKey
, pDrvInfo
->DriverName
, 0, &dwValueType
, (LPBYTE
)DllName
, &dwInput
);
188 if((ret
!= ERROR_SUCCESS
) || (dwValueType
!= REG_SZ
))
190 ERR("Unable to get ICD DLL name!\n");
194 Version
= DriverVersion
= Flags
= 0;
195 TRACE("DLL name is %S.\n", DllName
);
199 /* The driver have a subkey for the ICD */
200 TRACE("Querying details from registry for %S.\n", pDrvInfo
->DriverName
);
201 dwInput
= sizeof(DllName
);
202 ret
= RegQueryValueExW(DrvKey
, L
"Dll", 0, &dwValueType
, (LPBYTE
)DllName
, &dwInput
);
203 if((ret
!= ERROR_SUCCESS
) || (dwValueType
!= REG_SZ
))
205 ERR("Unable to get ICD DLL name!.\n");
211 dwInput
= sizeof(Version
);
212 ret
= RegQueryValueExW(DrvKey
, L
"Version", 0, &dwValueType
, (LPBYTE
)&Version
, &dwInput
);
213 if((ret
!= ERROR_SUCCESS
) || (dwValueType
!= REG_DWORD
))
215 WARN("No version in driver subkey\n");
217 else if(Version
!= pDrvInfo
->Version
)
219 ERR("Version mismatch between registry (%lu) and display driver (%lu).\n", Version
, pDrvInfo
->Version
);
225 dwInput
= sizeof(DriverVersion
);
226 ret
= RegQueryValueExW(DrvKey
, L
"DriverVersion", 0, &dwValueType
, (LPBYTE
)&DriverVersion
, &dwInput
);
227 if((ret
!= ERROR_SUCCESS
) || (dwValueType
!= REG_DWORD
))
229 WARN("No driver version in driver subkey\n");
231 else if(DriverVersion
!= pDrvInfo
->DriverVersion
)
233 ERR("Driver version mismatch between registry (%lu) and display driver (%lu).\n", DriverVersion
, pDrvInfo
->DriverVersion
);
239 dwInput
= sizeof(Flags
);
240 ret
= RegQueryValueExW(DrvKey
, L
"Flags", 0, &dwValueType
, (LPBYTE
)&Flags
, &dwInput
);
241 if((ret
!= ERROR_SUCCESS
) || (dwValueType
!= REG_DWORD
))
243 WARN("No driver version in driver subkey\n");
249 TRACE("DLL name is %S, Version %lx, DriverVersion %lx, Flags %lx.\n", DllName
, Version
, DriverVersion
, Flags
);
251 /* No need for this anymore */
254 /* So far so good, allocate data */
255 data
= HeapAlloc(GetProcessHeap(), 0, sizeof(*data
));
258 ERR("Unable to allocate ICD data!\n");
262 /* Load the library */
263 data
->hModule
= LoadLibraryW(DllName
);
266 ERR("Could not load the ICD DLL: %S.\n", DllName
);
267 HeapFree(GetProcessHeap(), 0, data
);
273 * Validate version, if needed.
274 * Some drivers (at least VBOX), initialize stuff upon this call.
276 DrvValidateVersion
= (void*)GetProcAddress(data
->hModule
, "DrvValidateVersion");
277 if(DrvValidateVersion
)
279 if(!DrvValidateVersion(pDrvInfo
->DriverVersion
))
281 ERR("DrvValidateVersion failed!.\n");
286 /* Pass the callbacks */
287 DrvSetCallbackProcs
= (void*)GetProcAddress(data
->hModule
, "DrvSetCallbackProcs");
288 if(DrvSetCallbackProcs
)
290 PROC callbacks
[] = {(PROC
)wglGetCurrentValue
,
291 (PROC
)wglSetCurrentValue
,
293 DrvSetCallbackProcs(3, callbacks
);
296 /* Get the DLL exports */
297 #define DRV_LOAD(x) do \
299 data->x = (void*)GetProcAddress(data->hModule, #x); \
301 ERR("%S lacks " #x "!\n", DllName); \
305 DRV_LOAD(DrvCopyContext
);
306 DRV_LOAD(DrvCreateContext
);
307 DRV_LOAD(DrvCreateLayerContext
);
308 DRV_LOAD(DrvDeleteContext
);
309 DRV_LOAD(DrvDescribeLayerPlane
);
310 DRV_LOAD(DrvDescribePixelFormat
);
311 DRV_LOAD(DrvGetLayerPaletteEntries
);
312 DRV_LOAD(DrvGetProcAddress
);
313 DRV_LOAD(DrvReleaseContext
);
314 DRV_LOAD(DrvRealizeLayerPalette
);
315 DRV_LOAD(DrvSetContext
);
316 DRV_LOAD(DrvSetLayerPaletteEntries
);
317 DRV_LOAD(DrvSetPixelFormat
);
318 DRV_LOAD(DrvShareLists
);
319 DRV_LOAD(DrvSwapBuffers
);
320 DRV_LOAD(DrvSwapLayerBuffers
);
323 /* Let's see if GDI should handle this instead of the ICD DLL */
324 // FIXME: maybe there is a better way
325 if (GdiDescribePixelFormat(hdc
, 0, 0, NULL
) != 0)
327 /* GDI knows what to do with that. Override */
328 TRACE("Forwarding WGL calls to win32k!\n");
329 data
->DrvDescribePixelFormat
= GdiDescribePixelFormat
;
330 data
->DrvSetPixelFormat
= GdiSetPixelFormat
;
331 data
->DrvSwapBuffers
= GdiSwapBuffers
;
334 /* Copy the DriverName */
335 wcscpy(data
->DriverName
, pDrvInfo
->DriverName
);
338 data
->next
= ICD_Data_List
;
339 ICD_Data_List
= data
;
341 TRACE("Returning %p.\n", data
);
342 TRACE("ICD driver %S (%S) successfully loaded.\n", pDrvInfo
->DriverName
, DllName
);
345 /* Unlock and return */
346 LeaveCriticalSection(&icdload_cs
);
350 LeaveCriticalSection(&icdload_cs
);
351 FreeLibrary(data
->hModule
);
352 HeapFree(GetProcessHeap(), 0, data
);
356 void IntDeleteAllICDs(void)
358 struct ICD_Data
* data
;
360 EnterCriticalSection(&icdload_cs
);
362 while (ICD_Data_List
!= NULL
)
364 data
= ICD_Data_List
;
365 ICD_Data_List
= data
->next
;
367 FreeLibrary(data
->hModule
);
368 HeapFree(GetProcessHeap(), 0, data
);