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
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
;
64 HKEY OglKey
, DrvKey
, CustomKey
;
65 WCHAR DllName
[MAX_PATH
];
66 BOOL (WINAPI
*DrvValidateVersion
)(DWORD
);
67 void (WINAPI
*DrvSetCallbackProcs
)(int nProcs
, PROC
* pProcs
);
69 /* The following code is ReactOS specific and allows us to easily load an arbitrary ICD:
70 * It checks HKCU\Software\ReactOS\OpenGL for a custom ICD and will always load it
71 * no matter what driver the DC is associated with. It can also force using the
72 * built-in Software Implementation*/
73 if(CustomDriverState
== OGL_CD_NOT_QUERIED
)
75 /* Only do this once so there's not any significant performance penalty */
76 CustomDriverState
= OGL_CD_NONE
;
77 memset(&CustomDrvInfo
, 0, sizeof(Drv_Opengl_Info
));
79 ret
= RegOpenKeyExW(HKEY_CURRENT_USER
, CustomDrivers_Key
, 0, KEY_READ
, &CustomKey
);
80 if(ret
!= ERROR_SUCCESS
)
83 dwInput
= sizeof(CustomDrvInfo
.DriverName
);
84 ret
= RegQueryValueExW(CustomKey
, L
"", 0, &dwValueType
, (LPBYTE
)CustomDrvInfo
.DriverName
, &dwInput
);
85 RegCloseKey(CustomKey
);
87 if((ret
!= ERROR_SUCCESS
) || (dwValueType
!= REG_SZ
) || !wcslen(CustomDrvInfo
.DriverName
))
90 if(!_wcsicmp(CustomDrvInfo
.DriverName
, L
"ReactOS Software Implementation"))
92 /* Always announce the fact that we're forcing ROSSWI */
93 ERR("Forcing ReactOS Software Implementation\n");
94 CustomDriverState
= OGL_CD_ROSSWI
;
98 ret
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
, OpenGLDrivers_Key
, 0, KEY_READ
, &OglKey
);
99 if(ret
!= ERROR_SUCCESS
)
102 ret
= RegOpenKeyExW(OglKey
, CustomDrvInfo
.DriverName
, 0, KEY_READ
, &OglKey
);
103 if(ret
!= ERROR_SUCCESS
)
106 dwInput
= sizeof(CustomDrvInfo
.Version
);
107 ret
= RegQueryValueExW(OglKey
, L
"Version", 0, &dwValueType
, (LPBYTE
)&CustomDrvInfo
.Version
, &dwInput
);
108 if((ret
!= ERROR_SUCCESS
) || (dwValueType
!= REG_DWORD
))
111 dwInput
= sizeof(DriverVersion
);
112 ret
= RegQueryValueExW(OglKey
, L
"DriverVersion", 0, &dwValueType
, (LPBYTE
)&CustomDrvInfo
.DriverVersion
, &dwInput
);
113 CustomDriverState
= OGL_CD_CUSTOM_ICD
;
115 /* Always announce the fact that we're overriding the default driver */
116 ERR("Overriding the default OGL ICD with %S\n", CustomDrvInfo
.DriverName
);
121 RegCloseKey(CustomKey
);
124 /* If there's a custom ICD or ROSSWI was requested use it, otherwise proceed as usual */
125 if(CustomDriverState
== OGL_CD_CUSTOM_ICD
)
127 pDrvInfo
= &CustomDrvInfo
;
129 else if(CustomDriverState
== OGL_CD_ROSSWI
)
135 /* First, see if the driver supports this */
136 dwInput
= OPENGL_GETINFO
;
137 ret
= ExtEscape(hdc
, QUERYESCSUPPORT
, sizeof(DWORD
), (LPCSTR
)&dwInput
, 0, NULL
);
139 /* Driver doesn't support opengl */
143 /* Query for the ICD DLL name and version */
145 ret
= ExtEscape(hdc
, OPENGL_GETINFO
, sizeof(DWORD
), (LPCSTR
)&dwInput
, sizeof(DrvInfo
), (LPSTR
)&DrvInfo
);
149 ERR("Driver claims to support OPENGL_GETINFO escape code, but doesn't.\n");
156 /* Protect the list while we are loading*/
157 EnterCriticalSection(&icdload_cs
);
159 /* Search for it in the list of already loaded modules */
160 data
= ICD_Data_List
;
163 if(!_wcsicmp(data
->DriverName
, pDrvInfo
->DriverName
))
166 TRACE("Found already loaded %p.\n", data
);
167 LeaveCriticalSection(&icdload_cs
);
173 /* It was still not loaded, look for it in the registry */
174 ret
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
, OpenGLDrivers_Key
, 0, KEY_READ
, &OglKey
);
175 if(ret
!= ERROR_SUCCESS
)
177 ERR("Failed to open the OpenGLDrivers key.\n");
180 ret
= RegOpenKeyExW(OglKey
, pDrvInfo
->DriverName
, 0, KEY_READ
, &DrvKey
);
181 if(ret
!= ERROR_SUCCESS
)
183 /* Some driver installer just provide the DLL name, like the Matrox G400 */
184 TRACE("No driver subkey for %S, trying to get DLL name directly.\n", pDrvInfo
->DriverName
);
185 dwInput
= sizeof(DllName
);
186 ret
= RegQueryValueExW(OglKey
, pDrvInfo
->DriverName
, 0, &dwValueType
, (LPBYTE
)DllName
, &dwInput
);
187 if((ret
!= ERROR_SUCCESS
) || (dwValueType
!= REG_SZ
))
189 ERR("Unable to get ICD DLL name!\n");
193 Version
= DriverVersion
= Flags
= 0;
194 TRACE("DLL name is %S.\n", DllName
);
198 /* The driver have a subkey for the ICD */
199 TRACE("Querying details from registry for %S.\n", pDrvInfo
->DriverName
);
200 dwInput
= sizeof(DllName
);
201 ret
= RegQueryValueExW(DrvKey
, L
"Dll", 0, &dwValueType
, (LPBYTE
)DllName
, &dwInput
);
202 if((ret
!= ERROR_SUCCESS
) || (dwValueType
!= REG_SZ
))
204 ERR("Unable to get ICD DLL name!.\n");
210 dwInput
= sizeof(Version
);
211 ret
= RegQueryValueExW(DrvKey
, L
"Version", 0, &dwValueType
, (LPBYTE
)&Version
, &dwInput
);
212 if((ret
!= ERROR_SUCCESS
) || (dwValueType
!= REG_DWORD
))
214 WARN("No version in driver subkey\n");
216 else if(Version
!= pDrvInfo
->Version
)
218 ERR("Version mismatch between registry (%lu) and display driver (%lu).\n", Version
, pDrvInfo
->Version
);
224 dwInput
= sizeof(DriverVersion
);
225 ret
= RegQueryValueExW(DrvKey
, L
"DriverVersion", 0, &dwValueType
, (LPBYTE
)&DriverVersion
, &dwInput
);
226 if((ret
!= ERROR_SUCCESS
) || (dwValueType
!= REG_DWORD
))
228 WARN("No driver version in driver subkey\n");
230 else if(DriverVersion
!= pDrvInfo
->DriverVersion
)
232 ERR("Driver version mismatch between registry (%lu) and display driver (%lu).\n", DriverVersion
, pDrvInfo
->DriverVersion
);
238 dwInput
= sizeof(Flags
);
239 ret
= RegQueryValueExW(DrvKey
, L
"Flags", 0, &dwValueType
, (LPBYTE
)&Flags
, &dwInput
);
240 if((ret
!= ERROR_SUCCESS
) || (dwValueType
!= REG_DWORD
))
242 WARN("No driver version in driver subkey\n");
248 TRACE("DLL name is %S, Version %lx, DriverVersion %lx, Flags %lx.\n", DllName
, Version
, DriverVersion
, Flags
);
250 /* No need for this anymore */
253 /* So far so good, allocate data */
254 data
= HeapAlloc(GetProcessHeap(), 0, sizeof(*data
));
257 ERR("Unable to allocate ICD data!\n");
261 /* Load the library */
262 data
->hModule
= LoadLibraryW(DllName
);
265 ERR("Could not load the ICD DLL: %S.\n", DllName
);
266 HeapFree(GetProcessHeap(), 0, data
);
272 * Validate version, if needed.
273 * Some drivers (at least VBOX), initialize stuff upon this call.
275 DrvValidateVersion
= (void*)GetProcAddress(data
->hModule
, "DrvValidateVersion");
276 if(DrvValidateVersion
)
278 if(!DrvValidateVersion(pDrvInfo
->DriverVersion
))
280 ERR("DrvValidateVersion failed!.\n");
285 /* Pass the callbacks */
286 DrvSetCallbackProcs
= (void*)GetProcAddress(data
->hModule
, "DrvSetCallbackProcs");
287 if(DrvSetCallbackProcs
)
289 PROC callbacks
[] = {(PROC
)wglGetCurrentValue
,
290 (PROC
)wglSetCurrentValue
,
292 DrvSetCallbackProcs(3, callbacks
);
295 /* Get the DLL exports */
296 #define DRV_LOAD(x) do \
298 data->x = (void*)GetProcAddress(data->hModule, #x); \
300 ERR("%S lacks " #x "!\n", DllName); \
304 DRV_LOAD(DrvCopyContext
);
305 DRV_LOAD(DrvCreateContext
);
306 DRV_LOAD(DrvCreateLayerContext
);
307 DRV_LOAD(DrvDeleteContext
);
308 DRV_LOAD(DrvDescribeLayerPlane
);
309 DRV_LOAD(DrvDescribePixelFormat
);
310 DRV_LOAD(DrvGetLayerPaletteEntries
);
311 DRV_LOAD(DrvGetProcAddress
);
312 DRV_LOAD(DrvReleaseContext
);
313 DRV_LOAD(DrvRealizeLayerPalette
);
314 DRV_LOAD(DrvSetContext
);
315 DRV_LOAD(DrvSetLayerPaletteEntries
);
316 DRV_LOAD(DrvSetPixelFormat
);
317 DRV_LOAD(DrvShareLists
);
318 DRV_LOAD(DrvSwapBuffers
);
319 DRV_LOAD(DrvSwapLayerBuffers
);
322 /* Let's see if GDI should handle this instead of the ICD DLL */
323 // FIXME: maybe there is a better way
324 if (GdiDescribePixelFormat(hdc
, 0, 0, NULL
) != 0)
326 /* GDI knows what to do with that. Override */
327 TRACE("Forwarding WGL calls to win32k!\n");
328 data
->DrvDescribePixelFormat
= GdiDescribePixelFormat
;
329 data
->DrvSetPixelFormat
= GdiSetPixelFormat
;
330 data
->DrvSwapBuffers
= GdiSwapBuffers
;
333 /* Copy the DriverName */
334 wcscpy(data
->DriverName
, pDrvInfo
->DriverName
);
337 data
->next
= ICD_Data_List
;
338 ICD_Data_List
= data
;
340 TRACE("Returning %p.\n", data
);
341 TRACE("ICD driver %S (%S) successfully loaded.\n", pDrvInfo
->DriverName
, DllName
);
344 /* Unlock and return */
345 LeaveCriticalSection(&icdload_cs
);
349 LeaveCriticalSection(&icdload_cs
);
350 FreeLibrary(data
->hModule
);
351 HeapFree(GetProcessHeap(), 0, data
);
355 void IntDeleteAllICDs(void)
357 struct ICD_Data
* data
;
359 EnterCriticalSection(&icdload_cs
);
361 while (ICD_Data_List
!= NULL
)
363 data
= ICD_Data_List
;
364 ICD_Data_List
= data
->next
;
366 FreeLibrary(data
->hModule
);
367 HeapFree(GetProcessHeap(), 0, data
);