9068c6f8fb5469b4972f8b77de7306400080705d
[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
10 #include <winreg.h>
11
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 /* GDI entry points (win32k) */
41 extern INT APIENTRY GdiDescribePixelFormat(HDC hdc, INT ipfd, UINT cjpfd, PPIXELFORMATDESCRIPTOR ppfd);
42 extern BOOL APIENTRY GdiSetPixelFormat(HDC hdc, INT ipfd);
43 extern BOOL APIENTRY GdiSwapBuffers(HDC hdc);
44
45 /* Retrieves the ICD data (driver version + relevant DLL entry points) for a device context */
46 struct ICD_Data* IntGetIcdData(HDC hdc)
47 {
48 int ret;
49 DWORD dwInput, dwValueType, Version, DriverVersion, Flags;
50 struct Drv_Opengl_Info DrvInfo;
51 struct ICD_Data* data;
52 HKEY OglKey, DrvKey;
53 WCHAR DllName[MAX_PATH];
54 BOOL (WINAPI *DrvValidateVersion)(DWORD);
55 void (WINAPI *DrvSetCallbackProcs)(int nProcs, PROC* pProcs);
56
57 /* First, see if the driver supports this */
58 dwInput = OPENGL_GETINFO;
59 ret = ExtEscape(hdc,
60 QUERYESCSUPPORT,
61 sizeof(DWORD),
62 (LPCSTR)&dwInput,
63 0,
64 NULL);
65
66 if(ret <= 0)
67 {
68 /* Driver doesn't support opengl */
69 return NULL;
70 }
71
72 /* Query for the ICD DLL name and version */
73 dwInput = 0;
74 ret = ExtEscape(hdc,
75 OPENGL_GETINFO,
76 sizeof(DWORD),
77 (LPCSTR)&dwInput,
78 sizeof(DrvInfo),
79 (LPSTR)&DrvInfo);
80
81 if(ret <= 0)
82 {
83 ERR("Driver claims to support OPENGL_GETINFO escape code, but doesn't.\n");
84 return NULL;
85 }
86
87 /* Protect the list while we are loading*/
88 EnterCriticalSection(&icdload_cs);
89
90 /* Search for it in the list of already loaded modules */
91 data = ICD_Data_List;
92 while(data)
93 {
94 if(!_wcsicmp(data->DriverName, DrvInfo.DriverName))
95 {
96 /* Found it */
97 TRACE("Found already loaded %p.\n", data);
98 LeaveCriticalSection(&icdload_cs);
99 return data;
100 }
101 data = data->next;
102 }
103
104 /* It was still not loaded, look for it in the registry */
105 ret = RegOpenKeyExW(HKEY_LOCAL_MACHINE, OpenGLDrivers_Key, 0, KEY_READ, &OglKey);
106 if(ret != ERROR_SUCCESS)
107 {
108 ERR("Failed to open the OpenGLDrivers key.\n");
109 goto end;
110 }
111 ret = RegOpenKeyExW(OglKey, DrvInfo.DriverName, 0, KEY_READ, &DrvKey);
112 if(ret != ERROR_SUCCESS)
113 {
114 /* Some driver installer just provide the DLL name, like the Matrox G400 */
115 TRACE("No driver subkey for %S, trying to get DLL name directly.\n", DrvInfo.DriverName);
116 dwInput = sizeof(DllName);
117 ret = RegQueryValueExW(OglKey, DrvInfo.DriverName, 0, &dwValueType, (LPBYTE)DllName, &dwInput);
118 if((ret != ERROR_SUCCESS) || (dwValueType != REG_SZ))
119 {
120 ERR("Unable to get ICD DLL name!.\n");
121 RegCloseKey(OglKey);
122 goto end;
123 }
124 Version = DriverVersion = Flags = 0;
125 TRACE("DLL name is %S.\n", DllName);
126 }
127 else
128 {
129 /* The driver have a subkey for the ICD */
130 TRACE("Querying details from registry for %S.\n", DrvInfo.DriverName);
131 dwInput = sizeof(DllName);
132 ret = RegQueryValueExW(DrvKey, L"Dll", 0, &dwValueType, (LPBYTE)DllName, &dwInput);
133 if((ret != ERROR_SUCCESS) || (dwValueType != REG_SZ))
134 {
135 ERR("Unable to get ICD DLL name!.\n");
136 RegCloseKey(DrvKey);
137 RegCloseKey(OglKey);
138 goto end;
139 }
140
141 dwInput = sizeof(Version);
142 ret = RegQueryValueExW(DrvKey, L"Version", 0, &dwValueType, (LPBYTE)&Version, &dwInput);
143 if((ret != ERROR_SUCCESS) || (dwValueType != REG_DWORD))
144 {
145 WARN("No version in driver subkey\n");
146 }
147 else if(Version != DrvInfo.Version)
148 {
149 ERR("Version mismatch between registry (%lu) and display driver (%lu).\n", Version, DrvInfo.Version);
150 RegCloseKey(DrvKey);
151 RegCloseKey(OglKey);
152 goto end;
153 }
154
155 dwInput = sizeof(DriverVersion);
156 ret = RegQueryValueExW(DrvKey, L"DriverVersion", 0, &dwValueType, (LPBYTE)&DriverVersion, &dwInput);
157 if((ret != ERROR_SUCCESS) || (dwValueType != REG_DWORD))
158 {
159 WARN("No driver version in driver subkey\n");
160 }
161 else if(DriverVersion != DrvInfo.DriverVersion)
162 {
163 ERR("Driver version mismatch between registry (%lu) and display driver (%lu).\n", DriverVersion, DrvInfo.DriverVersion);
164 RegCloseKey(DrvKey);
165 RegCloseKey(OglKey);
166 goto end;
167 }
168
169 dwInput = sizeof(Flags);
170 ret = RegQueryValueExW(DrvKey, L"Flags", 0, &dwValueType, (LPBYTE)&Flags, &dwInput);
171 if((ret != ERROR_SUCCESS) || (dwValueType != REG_DWORD))
172 {
173 WARN("No driver version in driver subkey\n");
174 Flags = 0;
175 }
176
177 /* We're done */
178 RegCloseKey(DrvKey);
179 TRACE("DLL name is %S, Version %lx, DriverVersion %lx, Flags %lx.\n", DllName, Version, DriverVersion, Flags);
180 }
181 /* No need for this anymore */
182 RegCloseKey(OglKey);
183
184 /* So far so good, allocate data */
185 data = HeapAlloc(GetProcessHeap(), 0, sizeof(*data));
186 if(!data)
187 {
188 ERR("Unable to allocate ICD data!\n");
189 goto end;
190 }
191
192 /* Load the library */
193 data->hModule = LoadLibraryW(DllName);
194 if(!data->hModule)
195 {
196 ERR("Could not load the ICD DLL: %S.\n", DllName);
197 HeapFree(GetProcessHeap(), 0, data);
198 data = NULL;
199 goto end;
200 }
201
202 /*
203 * Validate version, if needed.
204 * Some drivers (at least VBOX), initialize stuff upon this call.
205 */
206 DrvValidateVersion = (void*)GetProcAddress(data->hModule, "DrvValidateVersion");
207 if(DrvValidateVersion)
208 {
209 if(!DrvValidateVersion(DrvInfo.DriverVersion))
210 {
211 ERR("DrvValidateVersion failed!.\n");
212 goto fail;
213 }
214 }
215
216 /* Pass the callbacks */
217 DrvSetCallbackProcs = (void*)GetProcAddress(data->hModule, "DrvSetCallbackProcs");
218 if(DrvSetCallbackProcs)
219 {
220 PROC callbacks[] = {(PROC)wglGetCurrentValue,
221 (PROC)wglSetCurrentValue,
222 (PROC)wglGetDHGLRC};
223 DrvSetCallbackProcs(3, callbacks);
224 }
225
226 /* Get the DLL exports */
227 #define DRV_LOAD(x) do \
228 { \
229 data->x = (void*)GetProcAddress(data->hModule, #x); \
230 if(!data->x) { \
231 ERR("%S lacks " #x "!\n", DllName); \
232 goto fail; \
233 } \
234 } while(0)
235 DRV_LOAD(DrvCopyContext);
236 DRV_LOAD(DrvCreateContext);
237 DRV_LOAD(DrvCreateLayerContext);
238 DRV_LOAD(DrvDeleteContext);
239 DRV_LOAD(DrvDescribeLayerPlane);
240 DRV_LOAD(DrvDescribePixelFormat);
241 DRV_LOAD(DrvGetLayerPaletteEntries);
242 DRV_LOAD(DrvGetProcAddress);
243 DRV_LOAD(DrvReleaseContext);
244 DRV_LOAD(DrvRealizeLayerPalette);
245 DRV_LOAD(DrvSetContext);
246 DRV_LOAD(DrvSetLayerPaletteEntries);
247 DRV_LOAD(DrvSetPixelFormat);
248 DRV_LOAD(DrvShareLists);
249 DRV_LOAD(DrvSwapBuffers);
250 DRV_LOAD(DrvSwapLayerBuffers);
251 #undef DRV_LOAD
252
253 /* Let's see if GDI should handle this instead of the ICD DLL */
254 // FIXME: maybe there is a better way
255 if (GdiDescribePixelFormat(hdc, 0, 0, NULL) != 0)
256 {
257 /* GDI knows what to do with that. Override */
258 TRACE("Forwarding WGL calls to win32k!\n");
259 data->DrvDescribePixelFormat = GdiDescribePixelFormat;
260 data->DrvSetPixelFormat = GdiSetPixelFormat;
261 data->DrvSwapBuffers = GdiSwapBuffers;
262 }
263
264 /* Copy the DriverName */
265 wcscpy(data->DriverName, DrvInfo.DriverName);
266
267 /* Push the list */
268 data->next = ICD_Data_List;
269 ICD_Data_List = data;
270
271 TRACE("Returning %p.\n", data);
272
273 end:
274 /* Unlock and return */
275 LeaveCriticalSection(&icdload_cs);
276 return data;
277
278 fail:
279 LeaveCriticalSection(&icdload_cs);
280 FreeLibrary(data->hModule);
281 HeapFree(GetProcessHeap(), 0, data);
282 return NULL;
283 }
284
285 void IntDeleteAllICDs(void)
286 {
287 struct ICD_Data* data;
288
289 EnterCriticalSection(&icdload_cs);
290
291 while (ICD_Data_List != NULL)
292 {
293 data = ICD_Data_List;
294 ICD_Data_List = data->next;
295
296 FreeLibrary(data->hModule);
297 HeapFree(GetProcessHeap(), 0, data);
298 }
299 }