ReactOS  0.4.14-dev-342-gdc047f9
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 typedef struct
15 {
20 
21 typedef enum
22 {
28 
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";
35 
37 {
39 }
40 
42 {
43  return IntGetCurrentICDPrivate();
44 }
45 
47 {
48  return context->dhglrc;
49 }
50 
51 /* GDI entry points (win32k) */
55 
56 /* Retrieves the ICD data (driver version + relevant DLL entry points) for a device context */
58 {
59  int ret;
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 = NULL;
65  HKEY DrvKey, CustomKey;
66  WCHAR DllName[MAX_PATH];
67  BOOL (WINAPI *DrvValidateVersion)(DWORD);
68  void (WINAPI *DrvSetCallbackProcs)(int nProcs, PROC* pProcs);
69 
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*/
75  {
76  /* Only do this once so there's not any significant performance penalty */
78  memset(&CustomDrvInfo, 0, sizeof(Drv_Opengl_Info));
79 
81  if(ret != ERROR_SUCCESS)
82  goto custom_end;
83 
84  dwInput = sizeof(CustomDrvInfo.DriverName);
85  ret = RegQueryValueExW(CustomKey, L"", 0, &dwValueType, (LPBYTE)CustomDrvInfo.DriverName, &dwInput);
86  RegCloseKey(CustomKey);
87 
88  if((ret != ERROR_SUCCESS) || (dwValueType != REG_SZ) || !wcslen(CustomDrvInfo.DriverName))
89  goto custom_end;
90 
91  if(!_wcsicmp(CustomDrvInfo.DriverName, L"ReactOS Software Implementation"))
92  {
93  /* Always announce the fact that we're forcing ROSSWI */
94  ERR("Forcing ReactOS Software Implementation\n");
96  return NULL;
97  }
98 
100  if(ret != ERROR_SUCCESS)
101  goto custom_end;
102 
103  ret = RegOpenKeyExW(OglKey, CustomDrvInfo.DriverName, 0, KEY_READ, &OglKey);
104  if(ret != ERROR_SUCCESS)
105  goto custom_end;
106 
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))
110  goto custom_end;
111 
112  dwInput = sizeof(DriverVersion);
113  ret = RegQueryValueExW(OglKey, L"DriverVersion", 0, &dwValueType, (LPBYTE)&CustomDrvInfo.DriverVersion, &dwInput);
115 
116  /* Always announce the fact that we're overriding the default driver */
117  ERR("Overriding the default OGL ICD with %S\n", CustomDrvInfo.DriverName);
118 
119 custom_end:
120  if(OglKey)
121  RegCloseKey(OglKey);
122  RegCloseKey(CustomKey);
123  }
124 
125  /* If there's a custom ICD or ROSSWI was requested use it, otherwise proceed as usual */
127  {
128  pDrvInfo = &CustomDrvInfo;
129  }
130  else if(CustomDriverState == OGL_CD_ROSSWI)
131  {
132  return NULL;
133  }
134  else
135  {
136  /* First, see if the driver supports this */
137  dwInput = OPENGL_GETINFO;
138  ret = ExtEscape(hdc, QUERYESCSUPPORT, sizeof(DWORD), (LPCSTR)&dwInput, 0, NULL);
139 
140  /* Driver doesn't support opengl */
141  if(ret <= 0)
142  return NULL;
143 
144  /* Query for the ICD DLL name and version */
145  dwInput = 0;
146  ret = ExtEscape(hdc, OPENGL_GETINFO, sizeof(DWORD), (LPCSTR)&dwInput, sizeof(DrvInfo), (LPSTR)&DrvInfo);
147 
148  if(ret <= 0)
149  {
150  ERR("Driver claims to support OPENGL_GETINFO escape code, but doesn't.\n");
151  return NULL;
152  }
153 
154  pDrvInfo = &DrvInfo;
155  }
156 
157  /* Protect the list while we are loading*/
159 
160  /* Search for it in the list of already loaded modules */
162  while(data)
163  {
164  if(!_wcsicmp(data->DriverName, pDrvInfo->DriverName))
165  {
166  /* Found it */
167  TRACE("Found already loaded %p.\n", data);
169  return data;
170  }
171  data = data->next;
172  }
173 
174  /* It was still not loaded, look for it in the registry */
176  if(ret != ERROR_SUCCESS)
177  {
178  ERR("Failed to open the OpenGLDrivers key.\n");
179  goto end;
180  }
181  ret = RegOpenKeyExW(OglKey, pDrvInfo->DriverName, 0, KEY_READ, &DrvKey);
182  if(ret != ERROR_SUCCESS)
183  {
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))
189  {
190  ERR("Unable to get ICD DLL name!\n");
191  RegCloseKey(OglKey);
192  goto end;
193  }
194  Version = DriverVersion = Flags = 0;
195  TRACE("DLL name is %S.\n", DllName);
196  }
197  else
198  {
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))
204  {
205  ERR("Unable to get ICD DLL name!.\n");
206  RegCloseKey(DrvKey);
207  RegCloseKey(OglKey);
208  goto end;
209  }
210 
211  dwInput = sizeof(Version);
212  ret = RegQueryValueExW(DrvKey, L"Version", 0, &dwValueType, (LPBYTE)&Version, &dwInput);
213  if((ret != ERROR_SUCCESS) || (dwValueType != REG_DWORD))
214  {
215  WARN("No version in driver subkey\n");
216  }
217  else if(Version != pDrvInfo->Version)
218  {
219  ERR("Version mismatch between registry (%lu) and display driver (%lu).\n", Version, pDrvInfo->Version);
220  RegCloseKey(DrvKey);
221  RegCloseKey(OglKey);
222  goto end;
223  }
224 
225  dwInput = sizeof(DriverVersion);
226  ret = RegQueryValueExW(DrvKey, L"DriverVersion", 0, &dwValueType, (LPBYTE)&DriverVersion, &dwInput);
227  if((ret != ERROR_SUCCESS) || (dwValueType != REG_DWORD))
228  {
229  WARN("No driver version in driver subkey\n");
230  }
231  else if(DriverVersion != pDrvInfo->DriverVersion)
232  {
233  ERR("Driver version mismatch between registry (%lu) and display driver (%lu).\n", DriverVersion, pDrvInfo->DriverVersion);
234  RegCloseKey(DrvKey);
235  RegCloseKey(OglKey);
236  goto end;
237  }
238 
239  dwInput = sizeof(Flags);
240  ret = RegQueryValueExW(DrvKey, L"Flags", 0, &dwValueType, (LPBYTE)&Flags, &dwInput);
241  if((ret != ERROR_SUCCESS) || (dwValueType != REG_DWORD))
242  {
243  WARN("No driver version in driver subkey\n");
244  Flags = 0;
245  }
246 
247  /* We're done */
248  RegCloseKey(DrvKey);
249  TRACE("DLL name is %S, Version %lx, DriverVersion %lx, Flags %lx.\n", DllName, Version, DriverVersion, Flags);
250  }
251  /* No need for this anymore */
252  RegCloseKey(OglKey);
253 
254  /* So far so good, allocate data */
255  data = HeapAlloc(GetProcessHeap(), 0, sizeof(*data));
256  if(!data)
257  {
258  ERR("Unable to allocate ICD data!\n");
259  goto end;
260  }
261 
262  /* Load the library */
263  data->hModule = LoadLibraryW(DllName);
264  if(!data->hModule)
265  {
266  ERR("Could not load the ICD DLL: %S.\n", DllName);
268  data = NULL;
269  goto end;
270  }
271 
272  /*
273  * Validate version, if needed.
274  * Some drivers (at least VBOX), initialize stuff upon this call.
275  */
276  DrvValidateVersion = (void*)GetProcAddress(data->hModule, "DrvValidateVersion");
277  if(DrvValidateVersion)
278  {
279  if(!DrvValidateVersion(pDrvInfo->DriverVersion))
280  {
281  ERR("DrvValidateVersion failed!.\n");
282  goto fail;
283  }
284  }
285 
286  /* Pass the callbacks */
287  DrvSetCallbackProcs = (void*)GetProcAddress(data->hModule, "DrvSetCallbackProcs");
288  if(DrvSetCallbackProcs)
289  {
290  PROC callbacks[] = {
293  (PROC)wglGetDHGLRC};
294  DrvSetCallbackProcs(ARRAYSIZE(callbacks), callbacks);
295  }
296 
297  /* Get the DLL exports */
298 #define DRV_LOAD(x) do \
299 { \
300  data->x = (void*)GetProcAddress(data->hModule, #x); \
301  if(!data->x) { \
302  ERR("%S lacks " #x "!\n", DllName); \
303  goto fail; \
304  } \
305 } while(0)
306  DRV_LOAD(DrvCopyContext);
307  DRV_LOAD(DrvCreateContext);
308  DRV_LOAD(DrvCreateLayerContext);
309  DRV_LOAD(DrvDeleteContext);
310  DRV_LOAD(DrvDescribeLayerPlane);
312  DRV_LOAD(DrvGetLayerPaletteEntries);
313  DRV_LOAD(DrvGetProcAddress);
314  DRV_LOAD(DrvReleaseContext);
315  DRV_LOAD(DrvRealizeLayerPalette);
317  DRV_LOAD(DrvSetLayerPaletteEntries);
319  DRV_LOAD(DrvShareLists);
321  DRV_LOAD(DrvSwapLayerBuffers);
322 #undef DRV_LOAD
323 
324  /* Let's see if GDI should handle this instead of the ICD DLL */
325  // FIXME: maybe there is a better way
326  if (GdiDescribePixelFormat(hdc, 0, 0, NULL) != 0)
327  {
328  /* GDI knows what to do with that. Override */
329  TRACE("Forwarding WGL calls to win32k!\n");
330  data->DrvDescribePixelFormat = GdiDescribePixelFormat;
331  data->DrvSetPixelFormat = GdiSetPixelFormat;
332  data->DrvSwapBuffers = GdiSwapBuffers;
333  }
334 
335  /* Copy the DriverName */
336  wcscpy(data->DriverName, pDrvInfo->DriverName);
337 
338  /* Push the list */
339  data->next = ICD_Data_List;
341 
342  TRACE("Returning %p.\n", data);
343  TRACE("ICD driver %S (%S) successfully loaded.\n", pDrvInfo->DriverName, DllName);
344 
345 end:
346  /* Unlock and return */
348  return data;
349 
350 fail:
352  FreeLibrary(data->hModule);
354  return NULL;
355 }
356 
358 {
359  struct ICD_Data* data;
360 
362 
363  while (ICD_Data_List != NULL)
364  {
366  ICD_Data_List = data->next;
367 
368  FreeLibrary(data->hModule);
370  }
371 }
static CUSTOM_DRIVER_STATE CustomDriverState
Definition: icdload.c:34
void IntDeleteAllICDs(void)
Definition: icdload.c:357
IN PVOID IN PVOID IN USHORT Version
Definition: pci.h:359
struct png_info_def **typedef void(__cdecl typeof(png_destroy_read_struct))(struct png_struct_def **
Definition: typeof.h:49
#define ERROR_SUCCESS
Definition: deptool.c:10
FORCEINLINE void * IntGetCurrentICDPrivate(void)
Definition: opengl32.h:170
Definition: http.c:6587
#define KEY_READ
Definition: nt_native.h:1023
#define HKEY_CURRENT_USER
Definition: winreg.h:11
_In_ INT ipfd
Definition: ntgdi.h:474
#define WARN(fmt,...)
Definition: debug.h:111
static HDC
Definition: imagelist.c:92
struct Drv_Opengl_Info * pDrv_Opengl_Info
DHGLRC
Definition: icd.h:373
#define ARRAYSIZE(array)
Definition: filtermapper.c:47
GLuint GLuint end
Definition: gl.h:1545
_In_ LONG _In_ ULONG _Out_opt_ PIXELFORMATDESCRIPTOR * ppfd
Definition: winddi.h:3488
void WINAPI EnterCriticalSection(LPCRITICAL_SECTION)
char * LPSTR
Definition: xmlstorage.h:182
#define BOOL
Definition: nt_native.h:43
#define DWORD
Definition: nt_native.h:44
int32_t INT
Definition: typedefs.h:56
static DHGLRC APIENTRY wglGetDHGLRC(struct wgl_context *context)
Definition: icdload.c:46
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
_In_ LONG _In_ ULONG cjpfd
Definition: winddi.h:3488
LONG WINAPI RegCloseKey(HKEY hKey)
Definition: reg.c:423
static void APIENTRY wglSetCurrentValue(PVOID value)
Definition: icdload.c:36
unsigned char * LPBYTE
Definition: typedefs.h:52
unsigned int BOOL
Definition: ntddk_ex.h:94
FN_DrvDescribePixelFormat DrvDescribePixelFormat
static PVOID APIENTRY wglGetCurrentValue()
Definition: icdload.c:41
static CRITICAL_SECTION icdload_cs
Definition: icdload.c:29
#define LoadLibraryW(x)
Definition: compat.h:412
smooth NULL
Definition: ftsmooth.c:416
static struct ICD_Data * ICD_Data_List
Definition: icdload.c:30
#define DRV_LOAD(x)
DWORD Version
Definition: icdload.c:16
const char * LPCSTR
Definition: xmlstorage.h:183
FORCEINLINE void IntSetCurrentICDPrivate(void *value)
Definition: opengl32.h:163
#define TRACE(s)
Definition: solgame.cpp:4
#define FreeLibrary(x)
Definition: compat.h:413
#define GetProcessHeap()
Definition: compat.h:403
PVOID WINAPI HeapAlloc(HANDLE, DWORD, SIZE_T)
LONG WINAPI RegQueryValueExW(_In_ HKEY hkeyorg, _In_ LPCWSTR name, _In_ LPDWORD reserved, _In_ LPDWORD type, _In_ LPBYTE data, _In_ LPDWORD count)
Definition: reg.c:4116
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define MAX_PATH
Definition: compat.h:26
#define WINAPI
Definition: msvc.h:8
unsigned long DWORD
Definition: ntddk_ex.h:95
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
BOOL APIENTRY GdiSwapBuffers(HDC hdc)
FN_DrvSwapBuffers DrvSwapBuffers
int ret
_CRTIMP wchar_t *__cdecl wcscpy(_Out_writes_z_(_String_length_(_Source)+1) wchar_t *_Dest, _In_z_ const wchar_t *_Source)
static const WCHAR L[]
Definition: oid.c:1250
HDC hdc
Definition: main.c:9
#define QUERYESCSUPPORT
Definition: wingdi.h:1000
WINE_DEFAULT_DEBUG_CHANNEL(opengl32)
static const WCHAR CustomDrivers_Key[]
Definition: icdload.c:32
#define ERR(fmt,...)
Definition: debug.h:109
DWORD DriverVersion
Definition: icdload.c:17
#define OPENGL_GETINFO
Definition: winddi.h:150
unsigned int UINT
Definition: ndis.h:50
Definition: icd.h:365
WCHAR DriverName[256]
Definition: icdload.c:18
LONG WINAPI RegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult)
Definition: reg.c:3366
INT_PTR(WINAPI * PROC)()
Definition: windef.h:250
#define GetProcAddress(x, y)
Definition: compat.h:418
INT APIENTRY GdiDescribePixelFormat(HDC hdc, INT ipfd, UINT cjpfd, PPIXELFORMATDESCRIPTOR ppfd)
void WINAPI LeaveCriticalSection(LPCRITICAL_SECTION)
WCHAR DriverName[256]
Definition: icd.h:368
struct ICD_Data * IntGetIcdData(HDC hdc)
Definition: icdload.c:57
const GLCLTPROCTABLE *WINAPI * DrvSetContext(HDC hdc, DHGLRC hglrc, PFN_SETPROCTABLE callback)
static int callbacks
Definition: xmllint.c:873
CUSTOM_DRIVER_STATE
Definition: icdload.c:21
#define memset(x, y, z)
Definition: compat.h:39
#define REG_DWORD
Definition: sdbapi.c:596
static Drv_Opengl_Info CustomDrvInfo
Definition: icdload.c:33
size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
#define HeapFree(x, y, z)
Definition: compat.h:402
FN_DrvSetPixelFormat DrvSetPixelFormat
_Check_return_ _CRTIMP int __cdecl _wcsicmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
#define APIENTRY
Definition: api.h:79
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 HKEY_LOCAL_MACHINE
Definition: winreg.h:12
static const WCHAR OpenGLDrivers_Key[]
Definition: icdload.c:31
#define REG_SZ
Definition: layer.c:22
BOOL APIENTRY GdiSetPixelFormat(HDC hdc, INT ipfd)