ReactOS 0.4.16-dev-1946-g52006dd
icdload.c
Go to the documentation of this file.
1/*
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
6 */
7
8#include "opengl32.h"
9
10#include <winreg.h>
11
13
14/* based off https://gitlab.freedesktop.org/mesa/mesa/-/blob/main/src/gallium/frontends/wgl/gldrv.h */
15typedef struct
16{
19 WCHAR DriverName[MAX_PATH + 1];
21
22#ifndef OPENGL_GETINFO_DRVNAME
23#define OPENGL_GETINFO_DRVNAME 0
24#endif
25
26typedef enum
27{
33
34static CRITICAL_SECTION icdload_cs = {NULL, -1, 0, 0, 0, 0};
35static struct ICD_Data* ICD_Data_List = NULL;
36static const WCHAR OpenGLDrivers_Key[] = L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\OpenGLDrivers";
37static const WCHAR CustomDrivers_Key[] = L"SOFTWARE\\ReactOS\\OpenGL";
40
42{
44}
45
47{
49}
50
52{
53 return context->dhglrc;
54}
55
56/* GDI entry points (win32k) */
60
61/* Retrieves the ICD data (driver version + relevant DLL entry points) for a device context */
63{
64 int ret;
65 DWORD dwInput, dwValueType, Version, DriverVersion, Flags;
66 Drv_Opengl_Info DrvInfo;
67 pDrv_Opengl_Info pDrvInfo;
68 struct ICD_Data* data;
69 HKEY OglKey = NULL;
70 HKEY DrvKey, CustomKey;
71 WCHAR DllName[MAX_PATH];
72 BOOL (WINAPI *DrvValidateVersion)(DWORD);
73 void (WINAPI *DrvSetCallbackProcs)(int nProcs, PROC* pProcs);
74
75 /* The following code is ReactOS specific and allows us to easily load an arbitrary ICD:
76 * It checks HKCU\Software\ReactOS\OpenGL for a custom ICD and will always load it
77 * no matter what driver the DC is associated with. It can also force using the
78 * built-in Software Implementation*/
80 {
81 /* Only do this once so there's not any significant performance penalty */
84
86 if(ret != ERROR_SUCCESS)
87 goto custom_end;
88
89 dwInput = sizeof(CustomDrvInfo.DriverName);
90 ret = RegQueryValueExW(CustomKey, L"", 0, &dwValueType, (LPBYTE)CustomDrvInfo.DriverName, &dwInput);
91 RegCloseKey(CustomKey);
92
93 if((ret != ERROR_SUCCESS) || (dwValueType != REG_SZ) || !wcslen(CustomDrvInfo.DriverName))
94 goto custom_end;
95
96 if(!_wcsicmp(CustomDrvInfo.DriverName, L"ReactOS Software Implementation"))
97 {
98 /* Always announce the fact that we're forcing ROSSWI */
99 ERR("Forcing ReactOS Software Implementation\n");
101 return NULL;
102 }
103
105 if(ret != ERROR_SUCCESS)
106 goto custom_end;
107
108 ret = RegOpenKeyExW(OglKey, CustomDrvInfo.DriverName, 0, KEY_READ, &OglKey);
109 if(ret != ERROR_SUCCESS)
110 goto custom_end;
111
112 dwInput = sizeof(CustomDrvInfo.Version);
113 ret = RegQueryValueExW(OglKey, L"Version", 0, &dwValueType, (LPBYTE)&CustomDrvInfo.Version, &dwInput);
114 if((ret != ERROR_SUCCESS) || (dwValueType != REG_DWORD))
115 goto custom_end;
116
117 dwInput = sizeof(DriverVersion);
118 ret = RegQueryValueExW(OglKey, L"DriverVersion", 0, &dwValueType, (LPBYTE)&CustomDrvInfo.DriverVersion, &dwInput);
120
121 /* Always announce the fact that we're overriding the default driver */
122 ERR("Overriding the default OGL ICD with %S\n", CustomDrvInfo.DriverName);
123
124custom_end:
125 if(OglKey)
126 RegCloseKey(OglKey);
127 RegCloseKey(CustomKey);
128 }
129
130 /* If there's a custom ICD or ROSSWI was requested use it, otherwise proceed as usual */
132 {
133 pDrvInfo = &CustomDrvInfo;
134 }
136 {
137 return NULL;
138 }
139 else
140 {
141 /* First, see if the driver supports this */
142 dwInput = OPENGL_GETINFO;
143 ret = ExtEscape(hdc, QUERYESCSUPPORT, sizeof(DWORD), (LPCSTR)&dwInput, 0, NULL);
144
145 /* Driver doesn't support opengl */
146 if(ret <= 0)
147 return NULL;
148
149 /* Query for the ICD DLL name and version */
150 dwInput = OPENGL_GETINFO_DRVNAME;
151 ret = ExtEscape(hdc, OPENGL_GETINFO, sizeof(DWORD), (LPCSTR)&dwInput, sizeof(DrvInfo), (LPSTR)&DrvInfo);
152
153 if(ret <= 0)
154 {
155 ERR("Driver claims to support OPENGL_GETINFO escape code, but doesn't. ret: %X\n", ret);
156 return NULL;
157 }
158
159 pDrvInfo = &DrvInfo;
160 }
161
162 /* Protect the list while we are loading*/
164
165 /* Search for it in the list of already loaded modules */
167 while(data)
168 {
169 if(!_wcsicmp(data->DriverName, pDrvInfo->DriverName))
170 {
171 /* Found it */
172 TRACE("Found already loaded %p.\n", data);
174 return data;
175 }
176 data = data->next;
177 }
178
179 /* It was still not loaded, look for it in the registry */
181 if(ret != ERROR_SUCCESS)
182 {
183 ERR("Failed to open the OpenGLDrivers key.\n");
184 goto end;
185 }
186 ret = RegOpenKeyExW(OglKey, pDrvInfo->DriverName, 0, KEY_READ, &DrvKey);
187 if(ret != ERROR_SUCCESS)
188 {
189 /* Some driver installer just provide the DLL name, like the Matrox G400 */
190 TRACE("No driver subkey for %S, trying to get DLL name directly.\n", pDrvInfo->DriverName);
191 dwInput = sizeof(DllName);
192 ret = RegQueryValueExW(OglKey, pDrvInfo->DriverName, 0, &dwValueType, (LPBYTE)DllName, &dwInput);
193 if((ret != ERROR_SUCCESS) || (dwValueType != REG_SZ))
194 {
195 ERR("Unable to get ICD DLL name!\n");
196 RegCloseKey(OglKey);
197 goto end;
198 }
199 Version = DriverVersion = Flags = 0;
200 TRACE("DLL name is %S.\n", DllName);
201 }
202 else
203 {
204 /* The driver have a subkey for the ICD */
205 TRACE("Querying details from registry for %S.\n", pDrvInfo->DriverName);
206 dwInput = sizeof(DllName);
207 ret = RegQueryValueExW(DrvKey, L"Dll", 0, &dwValueType, (LPBYTE)DllName, &dwInput);
208 if((ret != ERROR_SUCCESS) || (dwValueType != REG_SZ))
209 {
210 ERR("Unable to get ICD DLL name!.\n");
211 RegCloseKey(DrvKey);
212 RegCloseKey(OglKey);
213 goto end;
214 }
215
216 dwInput = sizeof(Version);
217 ret = RegQueryValueExW(DrvKey, L"Version", 0, &dwValueType, (LPBYTE)&Version, &dwInput);
218 if((ret != ERROR_SUCCESS) || (dwValueType != REG_DWORD))
219 {
220 WARN("No version in driver subkey\n");
221 }
222 else if(Version != pDrvInfo->Version)
223 {
224 ERR("Version mismatch between registry (%lu) and display driver (%lu).\n", Version, pDrvInfo->Version);
225 RegCloseKey(DrvKey);
226 RegCloseKey(OglKey);
227 goto end;
228 }
229
230 dwInput = sizeof(DriverVersion);
231 ret = RegQueryValueExW(DrvKey, L"DriverVersion", 0, &dwValueType, (LPBYTE)&DriverVersion, &dwInput);
232 if((ret != ERROR_SUCCESS) || (dwValueType != REG_DWORD))
233 {
234 WARN("No driver version in driver subkey\n");
235 }
236 else if(DriverVersion != pDrvInfo->DriverVersion)
237 {
238 ERR("Driver version mismatch between registry (%lu) and display driver (%lu).\n", DriverVersion, pDrvInfo->DriverVersion);
239 RegCloseKey(DrvKey);
240 RegCloseKey(OglKey);
241 goto end;
242 }
243
244 dwInput = sizeof(Flags);
245 ret = RegQueryValueExW(DrvKey, L"Flags", 0, &dwValueType, (LPBYTE)&Flags, &dwInput);
246 if((ret != ERROR_SUCCESS) || (dwValueType != REG_DWORD))
247 {
248 WARN("No driver version in driver subkey\n");
249 Flags = 0;
250 }
251
252 /* We're done */
253 RegCloseKey(DrvKey);
254 TRACE("DLL name is %S, Version %lx, DriverVersion %lx, Flags %lx.\n", DllName, Version, DriverVersion, Flags);
255 }
256 /* No need for this anymore */
257 RegCloseKey(OglKey);
258
259 /* So far so good, allocate data */
260 data = HeapAlloc(GetProcessHeap(), 0, sizeof(*data));
261 if(!data)
262 {
263 ERR("Unable to allocate ICD data!\n");
264 goto end;
265 }
266
267 /* Load the library */
268 data->hModule = LoadLibraryW(DllName);
269 if(!data->hModule)
270 {
271 ERR("Could not load the ICD DLL: %S.\n", DllName);
273 data = NULL;
274 goto end;
275 }
276
277 /*
278 * Validate version, if needed.
279 * Some drivers (at least VBOX), initialize stuff upon this call.
280 */
281 DrvValidateVersion = (void*)GetProcAddress(data->hModule, "DrvValidateVersion");
282 if(DrvValidateVersion)
283 {
284 if(!DrvValidateVersion(pDrvInfo->DriverVersion))
285 {
286 ERR("DrvValidateVersion failed!.\n");
287 goto fail;
288 }
289 }
290
291 /* Pass the callbacks */
292 DrvSetCallbackProcs = (void*)GetProcAddress(data->hModule, "DrvSetCallbackProcs");
293 if(DrvSetCallbackProcs)
294 {
295 PROC callbacks[] = {
299 DrvSetCallbackProcs(ARRAYSIZE(callbacks), callbacks);
300 }
301
302 /* Get the DLL exports */
303#define DRV_LOAD(x) do \
304{ \
305 data->x = (void*)GetProcAddress(data->hModule, #x); \
306 if(!data->x) { \
307 ERR("%S lacks " #x "!\n", DllName); \
308 goto fail; \
309 } \
310} while(0)
311 DRV_LOAD(DrvCopyContext);
312 DRV_LOAD(DrvCreateContext);
313 DRV_LOAD(DrvCreateLayerContext);
314 DRV_LOAD(DrvDeleteContext);
315 DRV_LOAD(DrvDescribeLayerPlane);
317 DRV_LOAD(DrvGetLayerPaletteEntries);
318 DRV_LOAD(DrvGetProcAddress);
319 DRV_LOAD(DrvReleaseContext);
320 DRV_LOAD(DrvRealizeLayerPalette);
322 DRV_LOAD(DrvSetLayerPaletteEntries);
324 DRV_LOAD(DrvShareLists);
326 DRV_LOAD(DrvSwapLayerBuffers);
327#undef DRV_LOAD
328
329 /* Let's see if GDI should handle this instead of the ICD DLL */
330 // FIXME: maybe there is a better way
331 if (GdiDescribePixelFormat(hdc, 0, 0, NULL) != 0)
332 {
333 /* GDI knows what to do with that. Override */
334 TRACE("Forwarding WGL calls to win32k!\n");
335 data->DrvDescribePixelFormat = GdiDescribePixelFormat;
336 data->DrvSetPixelFormat = GdiSetPixelFormat;
337 data->DrvSwapBuffers = GdiSwapBuffers;
338 }
339
340 /* Copy the DriverName */
341 wcscpy(data->DriverName, pDrvInfo->DriverName);
342
343 /* Push the list */
344 data->next = ICD_Data_List;
346
347 TRACE("Returning %p.\n", data);
348 TRACE("ICD driver %S (%S) successfully loaded.\n", pDrvInfo->DriverName, DllName);
349
350end:
351 /* Unlock and return */
353 return data;
354
355fail:
357 FreeLibrary(data->hModule);
359 return NULL;
360}
361
363{
364 struct ICD_Data* data;
365
367
368 while (ICD_Data_List != NULL)
369 {
371 ICD_Data_List = data->next;
372
373 FreeLibrary(data->hModule);
375 }
376}
#define PROC(name)
Definition: WinHttpOpen.c:37
#define WINE_DEFAULT_DEBUG_CHANNEL(t)
Definition: precomp.h:23
#define WARN(fmt,...)
Definition: precomp.h:61
#define ERR(fmt,...)
Definition: precomp.h:57
#define RegCloseKey(hKey)
Definition: registry.h:49
wcscpy
#define ERROR_SUCCESS
Definition: deptool.c:10
#define NULL
Definition: types.h:112
#define ARRAYSIZE(array)
Definition: filtermapper.c:47
#define APIENTRY
Definition: api.h:79
LONG WINAPI RegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult)
Definition: reg.c:3333
LONG WINAPI RegQueryValueExW(_In_ HKEY hkeyorg, _In_ LPCWSTR name, _In_ LPDWORD reserved, _In_ LPDWORD type, _In_ LPBYTE data, _In_ LPDWORD count)
Definition: reg.c:4103
#define GetProcessHeap()
Definition: compat.h:736
#define GetProcAddress(x, y)
Definition: compat.h:753
#define HeapAlloc
Definition: compat.h:733
#define FreeLibrary(x)
Definition: compat.h:748
#define MAX_PATH
Definition: compat.h:34
#define HeapFree(x, y, z)
Definition: compat.h:735
#define LoadLibraryW(x)
Definition: compat.h:747
return ret
Definition: mutex.c:146
#define L(x)
Definition: resources.c:13
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
GLuint GLuint end
Definition: gl.h:1545
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
void IntDeleteAllICDs(void)
Definition: icdload.c:362
BOOL APIENTRY GdiSetPixelFormat(HDC hdc, INT ipfd)
#define OPENGL_GETINFO_DRVNAME
Definition: icdload.c:23
struct ICD_Data * IntGetIcdData(HDC hdc)
Definition: icdload.c:62
static void APIENTRY wglSetCurrentValue(PVOID value)
Definition: icdload.c:41
static CRITICAL_SECTION icdload_cs
Definition: icdload.c:34
BOOL APIENTRY GdiSwapBuffers(HDC hdc)
static struct ICD_Data * ICD_Data_List
Definition: icdload.c:35
CUSTOM_DRIVER_STATE
Definition: icdload.c:27
@ OGL_CD_NONE
Definition: icdload.c:29
@ OGL_CD_NOT_QUERIED
Definition: icdload.c:28
@ OGL_CD_CUSTOM_ICD
Definition: icdload.c:31
@ OGL_CD_ROSSWI
Definition: icdload.c:30
static CUSTOM_DRIVER_STATE CustomDriverState
Definition: icdload.c:39
static const WCHAR OpenGLDrivers_Key[]
Definition: icdload.c:36
static DHGLRC APIENTRY wglGetDHGLRC(struct wgl_context *context)
Definition: icdload.c:51
struct Drv_Opengl_Info * pDrv_Opengl_Info
INT APIENTRY GdiDescribePixelFormat(HDC hdc, INT ipfd, UINT cjpfd, PPIXELFORMATDESCRIPTOR ppfd)
#define DRV_LOAD(x)
static const WCHAR CustomDrivers_Key[]
Definition: icdload.c:37
static PVOID APIENTRY wglGetCurrentValue()
Definition: icdload.c:46
static Drv_Opengl_Info CustomDrvInfo
Definition: icdload.c:38
_CRTIMP size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
#define REG_SZ
Definition: layer.c:22
HDC hdc
Definition: main.c:9
static HDC
Definition: imagelist.c:88
unsigned int UINT
Definition: ndis.h:50
#define KEY_READ
Definition: nt_native.h:1026
#define BOOL
Definition: nt_native.h:43
#define DWORD
Definition: nt_native.h:44
_In_ INT ipfd
Definition: ntgdi.h:474
FORCEINLINE void IntSetCurrentICDPrivate(void *value)
Definition: opengl32.h:163
FORCEINLINE void * IntGetCurrentICDPrivate(void)
Definition: opengl32.h:170
#define REG_DWORD
Definition: sdbapi.c:615
_Check_return_ _CRTIMP int __cdecl _wcsicmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
#define memset(x, y, z)
Definition: compat.h:39
#define TRACE(s)
Definition: solgame.cpp:4
ULONG Version
Definition: icdload.c:17
WCHAR DriverName[MAX_PATH+1]
Definition: icdload.c:19
ULONG DriverVersion
Definition: icdload.c:18
Definition: icd.h:366
const GLCLTPROCTABLE *WINAPI * DrvSetContext(HDC hdc, DHGLRC hglrc, PFN_SETPROCTABLE callback)
DHGLRC
Definition: icd.h:373
Definition: http.c:7252
unsigned char * LPBYTE
Definition: typedefs.h:53
int32_t INT
Definition: typedefs.h:58
uint32_t ULONG
Definition: typedefs.h:59
Definition: pdh_main.c:96
_Must_inspect_result_ _In_ WDFDEVICE _In_ LPCGUID _Out_ PINTERFACE _In_ USHORT _In_ USHORT Version
Definition: wdffdo.h:469
void WINAPI LeaveCriticalSection(LPCRITICAL_SECTION)
void WINAPI EnterCriticalSection(LPCRITICAL_SECTION)
FN_DrvDescribePixelFormat DrvDescribePixelFormat
FN_DrvSetPixelFormat DrvSetPixelFormat
_In_ LONG _In_ ULONG cjpfd
Definition: winddi.h:3489
_In_ LONG _In_ ULONG _Out_opt_ PIXELFORMATDESCRIPTOR * ppfd
Definition: winddi.h:3490
FN_DrvSwapBuffers DrvSwapBuffers
#define OPENGL_GETINFO
Definition: winddi.h:150
#define WINAPI
Definition: msvc.h:6
int WINAPI ExtEscape(_In_ HDC hdc, _In_ int iEscape, _In_ int cjInput, _In_reads_bytes_opt_(cjInput) LPCSTR lpInData, _In_ int cjOutput, _Out_writes_bytes_opt_(cjOutput) LPSTR lpOutData)
#define QUERYESCSUPPORT
Definition: wingdi.h:1001
#define HKEY_LOCAL_MACHINE
Definition: winreg.h:12
#define HKEY_CURRENT_USER
Definition: winreg.h:11
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
static int callbacks
Definition: xmllint.c:838
const char * LPCSTR
Definition: xmlstorage.h:183
__wchar_t WCHAR
Definition: xmlstorage.h:180
char * LPSTR
Definition: xmlstorage.h:182