1cd1e19edc716bcba0b452e220eb30200c2dce2f
[reactos.git] / reactos / dll / opengl / opengl32 / icdload.c
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 #include <winreg.h>
10
11 #include <wine/debug.h>
12 WINE_DEFAULT_DEBUG_CHANNEL(opengl32);
13
14 struct Drv_Opengl_Info
15 {
16 DWORD Version; /*!< Driver interface version */
17 DWORD DriverVersion; /*!< Driver version */
18 WCHAR DriverName[256]; /*!< Driver name */
19 };
20
21 static CRITICAL_SECTION icdload_cs = {NULL, -1, 0, 0, 0, 0};
22 static struct ICD_Data* ICD_Data_List = NULL;
23 static const WCHAR OpenGLDrivers_Key[] = L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\OpenGLDrivers";
24
25 static void APIENTRY wglSetCurrentValue(PVOID value)
26 {
27 IntSetCurrentICDPrivate(value);
28 }
29
30 static PVOID APIENTRY wglGetCurrentValue()
31 {
32 return IntGetCurrentICDPrivate();
33 }
34
35 static DHGLRC wglGetDHGLRC(struct wgl_context* context)
36 {
37 return context->dhglrc;
38 }
39
40 /* Retrieves the ICD data (driver version + relevant DLL entry points) for a device context */
41 struct ICD_Data* IntGetIcdData(HDC hdc)
42 {
43 int ret;
44 DWORD dwInput, dwValueType, Version, DriverVersion, Flags;
45 struct Drv_Opengl_Info DrvInfo;
46 struct ICD_Data* data;
47 HKEY OglKey, DrvKey;
48 WCHAR DllName[MAX_PATH];
49 BOOL (WINAPI *DrvValidateVersion)(DWORD);
50 void (WINAPI *DrvSetCallbackProcs)(int nProcs, PROC* pProcs);
51
52 /* First, see if the driver supports this */
53 dwInput = OPENGL_GETINFO;
54 ret = ExtEscape(hdc,
55 QUERYESCSUPPORT,
56 sizeof(DWORD),
57 (LPCSTR)&dwInput,
58 0,
59 NULL);
60
61 if(ret <= 0)
62 {
63 /* Driver doesn't support opengl */
64 return NULL;
65 }
66
67 /* Query for the ICD DLL name and version */
68 dwInput = 0;
69 ret = ExtEscape(hdc,
70 OPENGL_GETINFO,
71 sizeof(DWORD),
72 (LPCSTR)&dwInput,
73 sizeof(DrvInfo),
74 (LPSTR)&DrvInfo);
75
76 if(ret <= 0)
77 {
78 ERR("Driver claims to support OPENGL_GETINFO escape code, but doesn't.\n");
79 return NULL;
80 }
81
82 /* Protect the list while we are loading*/
83 EnterCriticalSection(&icdload_cs);
84
85 /* Search for it in the list of already loaded modules */
86 data = ICD_Data_List;
87 while(data)
88 {
89 if(!_wcsicmp(data->DriverName, DrvInfo.DriverName))
90 {
91 /* Found it */
92 TRACE("Found already loaded %p.\n", data);
93 LeaveCriticalSection(&icdload_cs);
94 return data;
95 }
96 data = data->next;
97 }
98
99 /* It was still not loaded, look for it in the registry */
100 ret = RegOpenKeyExW(HKEY_LOCAL_MACHINE, OpenGLDrivers_Key, 0, KEY_READ, &OglKey);
101 if(ret != ERROR_SUCCESS)
102 {
103 ERR("Failed to open the OpenGLDrivers key.\n");
104 goto end;
105 }
106 ret = RegOpenKeyExW(OglKey, DrvInfo.DriverName, 0, KEY_READ, &DrvKey);
107 if(ret != ERROR_SUCCESS)
108 {
109 /* Some driver installer just provide the DLL name, like the Matrox G400 */
110 TRACE("No driver subkey for %S, trying to get DLL name directly.\n", DrvInfo.DriverName);
111 dwInput = sizeof(DllName);
112 ret = RegQueryValueExW(OglKey, DrvInfo.DriverName, 0, &dwValueType, (LPBYTE)DllName, &dwInput);
113 if((ret != ERROR_SUCCESS) || (dwValueType != REG_SZ))
114 {
115 ERR("Unable to get ICD DLL name!.\n");
116 RegCloseKey(OglKey);
117 goto end;
118 }
119 Version = DriverVersion = Flags = 0;
120 TRACE("DLL name is %S.\n", DllName);
121 }
122 else
123 {
124 /* The driver have a subkey for the ICD */
125 TRACE("Querying details from registry for %S.\n", DrvInfo.DriverName);
126 dwInput = sizeof(DllName);
127 ret = RegQueryValueExW(DrvKey, L"Dll", 0, &dwValueType, (LPBYTE)DllName, &dwInput);
128 if((ret != ERROR_SUCCESS) || (dwValueType != REG_SZ))
129 {
130 ERR("Unable to get ICD DLL name!.\n");
131 RegCloseKey(DrvKey);
132 RegCloseKey(OglKey);
133 goto end;
134 }
135
136 dwInput = sizeof(Version);
137 ret = RegQueryValueExW(DrvKey, L"Version", 0, &dwValueType, (LPBYTE)&Version, &dwInput);
138 if((ret != ERROR_SUCCESS) || (dwValueType != REG_DWORD))
139 {
140 WARN("No version in driver subkey\n");
141 }
142 else if(Version != DrvInfo.Version)
143 {
144 ERR("Version mismatch between registry (%lu) and display driver (%lu).\n", Version, DrvInfo.Version);
145 RegCloseKey(DrvKey);
146 RegCloseKey(OglKey);
147 goto end;
148 }
149
150 dwInput = sizeof(DriverVersion);
151 ret = RegQueryValueExW(DrvKey, L"DriverVersion", 0, &dwValueType, (LPBYTE)&DriverVersion, &dwInput);
152 if((ret != ERROR_SUCCESS) || (dwValueType != REG_DWORD))
153 {
154 WARN("No driver version in driver subkey\n");
155 }
156 else if(DriverVersion != DrvInfo.DriverVersion)
157 {
158 ERR("Driver version mismatch between registry (%lu) and display driver (%lu).\n", DriverVersion, DrvInfo.DriverVersion);
159 RegCloseKey(DrvKey);
160 RegCloseKey(OglKey);
161 goto end;
162 }
163
164 dwInput = sizeof(Flags);
165 ret = RegQueryValueExW(DrvKey, L"Flags", 0, &dwValueType, (LPBYTE)&Flags, &dwInput);
166 if((ret != ERROR_SUCCESS) || (dwValueType != REG_DWORD))
167 {
168 WARN("No driver version in driver subkey\n");
169 Flags = 0;
170 }
171
172 /* We're done */
173 RegCloseKey(DrvKey);
174 TRACE("DLL name is %S, Version %lx, DriverVersion %lx, Flags %lx.\n", DllName, Version, DriverVersion, Flags);
175 }
176 /* No need for this anymore */
177 RegCloseKey(OglKey);
178
179 /* So far so good, allocate data */
180 data = HeapAlloc(GetProcessHeap(), 0, sizeof(*data));
181 if(!data)
182 {
183 ERR("Unable to allocate ICD data!\n");
184 goto end;
185 }
186
187 /* Load the library */
188 data->hModule = LoadLibraryW(DllName);
189 if(!data->hModule)
190 {
191 ERR("Could not load the ICD DLL: %S.\n", DllName);
192 HeapFree(GetProcessHeap(), 0, data);
193 data = NULL;
194 goto end;
195 }
196
197 /*
198 * Validate version, if needed.
199 * Some drivers (at least VBOX), initialize stuff upon this call.
200 */
201 DrvValidateVersion = (void*)GetProcAddress(data->hModule, "DrvValidateVersion");
202 if(DrvValidateVersion)
203 {
204 if(!DrvValidateVersion(DrvInfo.DriverVersion))
205 {
206 ERR("DrvValidateVersion failed!.\n");
207 goto fail;
208 }
209 }
210
211 /* Pass the callbacks */
212 DrvSetCallbackProcs = (void*)GetProcAddress(data->hModule, "DrvSetCallbackProcs");
213 if(DrvSetCallbackProcs)
214 {
215 PROC callbacks[] = {(PROC)wglGetCurrentValue,
216 (PROC)wglSetCurrentValue,
217 (PROC)wglGetDHGLRC};
218 DrvSetCallbackProcs(3, callbacks);
219 }
220
221 /* Get the DLL exports */
222 #define DRV_LOAD(x) do \
223 { \
224 data->x = (void*)GetProcAddress(data->hModule, #x); \
225 if(!data->x) { \
226 ERR("%S lacks " #x "!\n", DllName); \
227 goto fail; \
228 } \
229 } while(0)
230 DRV_LOAD(DrvCopyContext);
231 DRV_LOAD(DrvCreateContext);
232 DRV_LOAD(DrvCreateLayerContext);
233 DRV_LOAD(DrvDeleteContext);
234 DRV_LOAD(DrvDescribeLayerPlane);
235 DRV_LOAD(DrvDescribePixelFormat);
236 DRV_LOAD(DrvGetLayerPaletteEntries);
237 DRV_LOAD(DrvGetProcAddress);
238 DRV_LOAD(DrvReleaseContext);
239 DRV_LOAD(DrvRealizeLayerPalette);
240 DRV_LOAD(DrvSetContext);
241 DRV_LOAD(DrvSetLayerPaletteEntries);
242 DRV_LOAD(DrvSetPixelFormat);
243 DRV_LOAD(DrvShareLists);
244 DRV_LOAD(DrvSwapBuffers);
245 DRV_LOAD(DrvSwapLayerBuffers);
246 #undef DRV_LOAD
247
248 /* Copy the DriverName */
249 wcscpy(data->DriverName, DrvInfo.DriverName);
250
251 /* Push the list */
252 data->next = ICD_Data_List;
253 ICD_Data_List = data;
254
255 TRACE("Returning %p.\n", data);
256
257 end:
258 /* Unlock and return */
259 LeaveCriticalSection(&icdload_cs);
260 return data;
261
262 fail:
263 LeaveCriticalSection(&icdload_cs);
264 FreeLibrary(data->hModule);
265 HeapFree(GetProcessHeap(), 0, data);
266 return NULL;
267 }