Compilation fixes.
[reactos.git] / reactos / lib / opengl32 / opengl32.c
1 /* $Id: opengl32.c,v 1.6 2004/02/02 17:59:23 navaraf Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: lib/opengl32/opengl32.c
6 * PURPOSE: OpenGL32 lib
7 * PROGRAMMER: Anich Gregor (blight), Royce Mitchell III
8 * UPDATE HISTORY:
9 * Feb 1, 2004: Created
10 */
11
12 #define WIN32_LEAN_AND_MEAN
13 #include <windows.h>
14 #include <winreg.h>
15
16 #include <string.h>
17 //#include <GL/gl.h>
18 #include "opengl32.h"
19
20 #define EXPORT __declspec(dllexport)
21 #define NAKED __attribute__((naked))
22
23 /* function prototypes */
24 static BOOL OPENGL32_LoadDrivers();
25 static void OPENGL32_AppendICD( GLDRIVERDATA *icd );
26 static void OPENGL32_RemoveICD( GLDRIVERDATA *icd );
27 static GLDRIVERDATA *OPENGL32_LoadDriver ( LPCWSTR regKey );
28 static DWORD OPENGL32_InitializeDriver( GLDRIVERDATA *icd );
29 static BOOL OPENGL32_UnloadDriver( GLDRIVERDATA *icd );
30
31 /* global vars */
32 const char* OPENGL32_funcnames[GLIDX_COUNT]
33 __attribute__((section("shared"), shared)) =
34 {
35 #define X(X) #X,
36 GLFUNCS_MACRO
37 #undef X
38 };
39
40 GLPROCESSDATA OPENGL32_processdata;
41 DWORD OPENGL32_tls;
42
43 static void OPENGL32_ThreadDetach()
44 {
45 GLTHREADDATA *lpvData;
46
47 /* FIXME - do we need to release some HDC or something? */
48 lpvData = (GLTHREADDATA *)TlsGetValue ( OPENGL32_tls );
49 if ( lpvData != NULL )
50 LocalFree((HLOCAL) lpvData );
51 }
52
53
54 BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD Reason, LPVOID Reserved)
55 {
56 GLTHREADDATA* lpData = NULL;
57 DBGPRINT( "DllMain called!\n" );
58
59 switch ( Reason )
60 {
61 /* The DLL is loading due to process
62 * initialization or a call to LoadLibrary.
63 */
64 case DLL_PROCESS_ATTACH:
65 OPENGL32_tls = TlsAlloc();
66 if ( 0xFFFFFFFF == OPENGL32_tls )
67 return FALSE;
68
69 memset( &OPENGL32_processdata, 0, sizeof (OPENGL32_processdata) );
70
71 /* get list of ICDs from registry: */
72 OPENGL32_LoadDrivers();
73 /* No break: Initialize the index for first thread. */
74
75 /* The attached process creates a new thread. */
76 case DLL_THREAD_ATTACH:
77 lpData = (GLTHREADDATA*)LocalAlloc(LPTR, sizeof(GLTHREADDATA));
78 if ( lpData != NULL )
79 {
80 memset ( lpData, 0, sizeof(GLTHREADDATA) );
81 (void)TlsSetValue ( OPENGL32_tls, lpData );
82 }
83 #if 0
84 lpData->hdc = NULL;
85 /* FIXME - defaulting to mesa3d, but shouldn't */
86 lpData->list = OPENGL32_processdata.list[0];
87 #endif
88 break;
89
90 /* The thread of the attached process terminates. */
91 case DLL_THREAD_DETACH:
92 /* Release the allocated memory for this thread.*/
93 OPENGL32_ThreadDetach();
94 break;
95
96 /* DLL unload due to process termination or FreeLibrary. */
97 case DLL_PROCESS_DETACH:
98 OPENGL32_ThreadDetach();
99 /* FIXME: free resources */
100 TlsFree(OPENGL32_tls);
101 break;
102 }
103 return TRUE;
104 }
105
106
107 /* FUNCTION: Append ICD to linked list.
108 * ARGUMENTS: [IN] icd: GLDRIVERDATA to append to list
109 * TODO: protect from race conditions
110 */
111 static void OPENGL32_AppendICD( GLDRIVERDATA *icd )
112 {
113 if (!OPENGL32_processdata.driver_list)
114 OPENGL32_processdata.driver_list = icd;
115 else
116 {
117 GLDRIVERDATA *p = OPENGL32_processdata.driver_list;
118 while (p->next)
119 p = p->next;
120 p->next = icd;
121 }
122 }
123
124
125 /* FUNCTION: Remove ICD from linked list.
126 * ARGUMENTS: [IN] icd: GLDRIVERDATA to remove from list
127 * TODO: protect from race conditions
128 */
129 static void OPENGL32_RemoveICD( GLDRIVERDATA *icd )
130 {
131 if (icd == OPENGL32_processdata.driver_list)
132 OPENGL32_processdata.driver_list = icd->next;
133 else
134 {
135 GLDRIVERDATA *p = OPENGL32_processdata.driver_list;
136 while (p)
137 {
138 if (p->next == icd)
139 {
140 p->next = icd->next;
141 return;
142 }
143 p = p->next;
144 }
145 DBGPRINT( "RemoveICD: ICD 0x%08x not found in list!\n" );
146 }
147 }
148
149 /* FIXME - I'm assuming we want to return TRUE if we find at least *one* ICD */
150 static BOOL OPENGL32_LoadDrivers()
151 {
152 const WCHAR* OpenGLDrivers = L"SOFTWARE\\Microsoft\\Windows NT\\"
153 "CurrentVersion\\OpenGLDrivers\\";
154 HKEY hkey;
155 WCHAR name[1024];
156 int i;
157
158 /* FIXME - detect if we've already done this from another process */
159 /* FIXME - special-case load of MESA3D as generic implementation ICD. */
160
161 if ( ERROR_SUCCESS != RegOpenKeyW( HKEY_LOCAL_MACHINE, OpenGLDrivers, &hkey ) )
162 return FALSE;
163 for ( i = 0; RegEnumKeyW(hkey,i,name,sizeof(name)/sizeof(name[0])) == ERROR_SUCCESS; i++ )
164 {
165 /* ignoring return value, because OPENGL32_LoadICD() is doing *all* the work... */
166 /* GLDRIVERDATA* gldd =*/ OPENGL32_LoadICD ( name );
167 }
168 RegCloseKey ( hkey );
169 if ( i > 0 )
170 return TRUE;
171 else
172 return FALSE;
173 }
174
175 /* FUNCTION: Load an ICD.
176 * ARGUMENTS: [IN] driver: Name of display driver.
177 * RETURNS: error code; ERROR_SUCCESS on success
178 *
179 * TODO: call SetLastError() where appropriate
180 */
181 static GLDRIVERDATA *OPENGL32_LoadDriver ( LPCWSTR driver )
182 {
183 HKEY hKey;
184 WCHAR subKey[1024] = L"SOFTWARE\\Microsoft\\Windows NT\\"
185 "CurrentVersion\\OpenGLDrivers\\";
186 LONG ret;
187 DWORD type, size;
188
189 DWORD version, driverVersion, flags; /* registry values */
190 WCHAR dll[256];
191 GLDRIVERDATA *icd;
192
193 DBGPRINT( "Loading driver %ws...\n", driver );
194
195 /* open registry key */
196 wcsncat( subKey, driver, 1024 );
197 ret = RegOpenKeyExW( HKEY_LOCAL_MACHINE, subKey, 0, KEY_READ, &hKey );
198 if (ret != ERROR_SUCCESS)
199 {
200 DBGPRINT( "Error: Couldn't open registry key '%ws'\n", subKey );
201 return 0;
202 }
203
204 /* query values */
205 size = sizeof (dll);
206 ret = RegQueryValueExW( hKey, L"Dll", 0, &type, (LPBYTE)dll, &size );
207 if (ret != ERROR_SUCCESS || type != REG_SZ)
208 {
209 DBGPRINT( "Error: Couldn't query Dll value or not a string\n" );
210 RegCloseKey( hKey );
211 return 0;
212 }
213
214 size = sizeof (DWORD);
215 ret = RegQueryValueExW( hKey, L"Version", 0, &type, (LPBYTE)&version, &size );
216 if (ret != ERROR_SUCCESS || type != REG_DWORD)
217 {
218 DBGPRINT( "Warning: Couldn't query Version value or not a DWORD\n" );
219 version = 0;
220 }
221
222 size = sizeof (DWORD);
223 ret = RegQueryValueExW( hKey, L"DriverVersion", 0, &type,
224 (LPBYTE)&driverVersion, &size );
225 if (ret != ERROR_SUCCESS || type != REG_DWORD)
226 {
227 DBGPRINT( "Warning: Couldn't query DriverVersion value or not a DWORD\n" );
228 driverVersion = 0;
229 }
230
231 size = sizeof (DWORD);
232 ret = RegQueryValueExW( hKey, L"Flags", 0, &type, (LPBYTE)&flags, &size );
233 if (ret != ERROR_SUCCESS || type != REG_DWORD)
234 {
235 DBGPRINT( "Warning: Couldn't query Flags value or not a DWORD\n" );
236 flags = 0;
237 }
238
239 /* close key */
240 RegCloseKey( hKey );
241
242 DBGPRINT( "Dll = %ws\n", dll );
243 DBGPRINT( "Version = 0x%08x\n", version );
244 DBGPRINT( "DriverVersion = 0x%08x\n", driverVersion );
245 DBGPRINT( "Flags = 0x%08x\n", flags );
246
247 /* allocate driver data */
248 icd = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof (GLDRIVERDATA) );
249 if (!icd)
250 {
251 DBGPRINT( "Error: Couldnt allocate GLDRIVERDATA!\n" );
252 return 0;
253 }
254 wcsncpy( icd->driver_name, driver, 256 );
255 wcsncpy( icd->dll, dll, 256 );
256 icd->version = version;
257 icd->driver_version = driverVersion;
258 icd->flags = flags;
259
260 /* load ICD */
261 ret = OPENGL32_InitializeDriver( icd );
262 if (ret != ERROR_SUCCESS)
263 {
264 if (!HeapFree( GetProcessHeap(), 0, icd ))
265 DBGPRINT( "Error: HeapFree() returned false, error code = %d\n",
266 GetLastError() );
267 DBGPRINT( "Error: Couldnt initialize ICD!\n" );
268 return 0;
269 }
270
271 /* append ICD to list */
272 OPENGL32_AppendICD( icd );
273 DBGPRINT( "ICD loaded.\n" );
274
275 return icd;
276 }
277
278
279 /* FUNCTION: Initialize a driver (Load DLL, DrvXXX and glXXX procs)
280 * ARGUMENTS: [IN] icd: ICD to initialize with the dll, version, driverVersion
281 * and flags already filled.
282 * RETURNS: error code; ERROR_SUCCESS on success
283 */
284 #define LOAD_DRV_PROC( icd, proc, required ) \
285 icd->proc = GetProcAddress( icd->handle, #proc ); \
286 if (required && !icd->proc) { \
287 DBGPRINT( "Error: GetProcAddress(\"%s\") failed!", #proc ); \
288 return GetLastError(); \
289 }
290
291 static DWORD OPENGL32_InitializeDriver( GLDRIVERDATA *icd )
292 {
293 UINT i;
294
295 /* load dll */
296 icd->handle = LoadLibraryW( icd->dll );
297 if (!icd->handle)
298 {
299 DBGPRINT( "Error: Couldn't load DLL! (%d)\n", GetLastError() );
300 return GetLastError();
301 }
302
303 /* load DrvXXX procs */
304 LOAD_DRV_PROC(icd, DrvCopyContext, TRUE);
305 LOAD_DRV_PROC(icd, DrvCreateContext, TRUE);
306 LOAD_DRV_PROC(icd, DrvCreateLayerContext, TRUE);
307 LOAD_DRV_PROC(icd, DrvDeleteContext, TRUE);
308 LOAD_DRV_PROC(icd, DrvDescribeLayerPlane, TRUE);
309 LOAD_DRV_PROC(icd, DrvDescribePixelFormat, TRUE);
310 LOAD_DRV_PROC(icd, DrvGetLayerPaletteEntries, TRUE);
311 LOAD_DRV_PROC(icd, DrvGetProcAddress, TRUE);
312 LOAD_DRV_PROC(icd, DrvReleaseContext, TRUE);
313 LOAD_DRV_PROC(icd, DrvRealizeLayerPalette, TRUE);
314 LOAD_DRV_PROC(icd, DrvSetContext, TRUE);
315 LOAD_DRV_PROC(icd, DrvSetLayerPaletteEntries, TRUE);
316 LOAD_DRV_PROC(icd, DrvSetPixelFormat, TRUE);
317 LOAD_DRV_PROC(icd, DrvShareLists, TRUE);
318 LOAD_DRV_PROC(icd, DrvSwapBuffers, TRUE);
319 LOAD_DRV_PROC(icd, DrvSwapLayerBuffers, TRUE);
320 LOAD_DRV_PROC(icd, DrvValidateVersion, TRUE);
321
322 /* now load the glXXX functions */
323 for (i = 0; i < GLIDX_COUNT; i++)
324 {
325 icd->func_list[i] = icd->DrvGetProcAddress( OPENGL32_funcnames[i] );
326 #ifdef DEBUG_OPENGL32_ICD_EXPORTS
327 if ( icd->func_list[i] )
328 {
329 DBGPRINT( "Found function %s in ICD.\n", OPENGL32_funcnames[i] );
330 }
331 #endif
332 }
333
334 return ERROR_SUCCESS;
335 }
336
337
338 /* FUNCTION: Unload loaded ICD.
339 * RETURNS: TRUE on success, FALSE otherwise.
340 */
341 static BOOL OPENGL32_UnloadDriver( GLDRIVERDATA *icd )
342 {
343 BOOL allOk = TRUE;
344
345 DBGPRINT( "Unloading driver %ws...\n", icd->driver_name );
346 if (icd->refcount)
347 DBGPRINT( "Warning: ICD refcount = %d (should be 0)\n", icd->refcount );
348
349 /* unload dll */
350 if (!FreeLibrary( icd->handle ))
351 {
352 allOk = FALSE;
353 DBGPRINT( "Warning: FreeLibrary on ICD %ws failed!\n", icd->dll );
354 }
355
356 /* free resources */
357 OPENGL32_RemoveICD( icd );
358 HeapFree( GetProcessHeap(), 0, icd );
359
360 return allOk;
361 }
362
363
364 /* FUNCTION: Load ICD (shared ICD data)
365 * RETURNS: GLDRIVERDATA pointer on success, NULL otherwise.
366 */
367 GLDRIVERDATA *OPENGL32_LoadICD ( LPCWSTR driver )
368 {
369 GLDRIVERDATA *icd;
370
371 /* look if ICD is already loaded */
372 for (icd = OPENGL32_processdata.driver_list; icd; icd = icd->next)
373 {
374 if (!_wcsicmp( driver, icd->driver_name )) /* found */
375 {
376 icd->refcount++;
377 return icd;
378 }
379 }
380
381 /* not found - try to load */
382 icd = OPENGL32_LoadDriver ( driver );
383 if (icd)
384 icd->refcount = 1;
385 return icd;
386 }
387
388
389 /* FUNCTION: Unload ICD (shared ICD data)
390 * RETURNS: TRUE on success, FALSE otherwise.
391 */
392 BOOL OPENGL32_UnloadICD( GLDRIVERDATA *icd )
393 {
394 icd->refcount--;
395 if (icd->refcount == 0)
396 return OPENGL32_UnloadDriver( icd );
397
398 return TRUE;
399 }
400