1 /* $Id: opengl32.c,v 1.14 2004/02/09 08:00:15 vizzini Exp $
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
12 #define WIN32_LEAN_AND_MEAN
20 #define EXT_GET_DRIVERINFO 0x1101 /* ExtEscape code to get driver info */
21 typedef struct tagEXTDRIVERINFO
23 DWORD version
; /* driver interface version */
24 DWORD driver_version
; /* driver version */
25 WCHAR driver_name
[256]; /* driver name */
28 /* function prototypes */
29 /*static BOOL OPENGL32_LoadDrivers();*/
30 static void OPENGL32_AppendICD( GLDRIVERDATA
*icd
);
31 static void OPENGL32_RemoveICD( GLDRIVERDATA
*icd
);
32 static GLDRIVERDATA
*OPENGL32_LoadDriver( LPCWSTR regKey
);
33 static DWORD
OPENGL32_InitializeDriver( GLDRIVERDATA
*icd
);
34 static BOOL
OPENGL32_UnloadDriver( GLDRIVERDATA
*icd
);
37 /*const char* OPENGL32_funcnames[GLIDX_COUNT] SHARED =
39 #define X(func, ret, typeargs, args) #func,
45 GLPROCESSDATA OPENGL32_processdata
;
50 OPENGL32_ThreadDetach()
52 /* FIXME - do we need to release some HDC or something? */
53 GLTHREADDATA
* lpData
= NULL
;
54 lpData
= (GLTHREADDATA
*)TlsGetValue( OPENGL32_tls
);
57 if (!HeapFree( GetProcessHeap(), 0, lpData
))
58 DBGPRINT( "Warning: HeapFree() on GLTHREADDATA failed (%d)",
66 DllMain(HINSTANCE hInstance
, DWORD Reason
, LPVOID Reserved
)
68 GLTHREADDATA
* lpData
= NULL
;
69 ICDTable
*dispatchTable
= NULL
;
71 SECURITY_ATTRIBUTES attrib
= { sizeof (SECURITY_ATTRIBUTES
), /* nLength */
72 NULL
, /* lpSecurityDescriptor */
73 TRUE
/* bInheritHandle */ };
75 DBGPRINT( "Info: Called!" );
78 /* The DLL is loading due to process
79 * initialization or a call to LoadLibrary.
81 case DLL_PROCESS_ATTACH
:
82 OPENGL32_tls
= TlsAlloc();
83 if ( 0xFFFFFFFF == OPENGL32_tls
)
86 memset( &OPENGL32_processdata
, 0, sizeof (OPENGL32_processdata
) );
88 /* create driver & glrc list mutex */
89 OPENGL32_processdata
.driver_mutex
= CreateMutex( &attrib
, FALSE
, NULL
);
90 if (OPENGL32_processdata
.driver_mutex
== NULL
)
92 DBGPRINT( "Error: Couldn't create driver_list mutex (%d)",
94 TlsFree( OPENGL32_tls
);
96 OPENGL32_processdata
.glrc_mutex
= CreateMutex( &attrib
, FALSE
, NULL
);
97 if (OPENGL32_processdata
.glrc_mutex
== NULL
)
99 DBGPRINT( "Error: Couldn't create glrc_list mutex (%d)",
101 CloseHandle( OPENGL32_processdata
.driver_mutex
);
102 TlsFree( OPENGL32_tls
);
105 /* No break: Initialize the index for first thread. */
107 /* The attached process creates a new thread. */
108 case DLL_THREAD_ATTACH
:
109 dispatchTable
= (ICDTable
*)HeapAlloc( GetProcessHeap(),
110 HEAP_GENERATE_EXCEPTIONS
| HEAP_ZERO_MEMORY
,
112 if (dispatchTable
== NULL
)
114 DBGPRINT( "Error: Couldn't allocate GL dispatch table" );
118 lpData
= (GLTHREADDATA
*)HeapAlloc( GetProcessHeap(),
119 HEAP_GENERATE_EXCEPTIONS
| HEAP_ZERO_MEMORY
,
120 sizeof (GLTHREADDATA
) );
123 DBGPRINT( "Error: Couldn't allocate GLTHREADDATA" );
124 HeapFree( GetProcessHeap(), 0, dispatchTable
);
128 teb
= NtCurrentTeb();
130 /* initialize dispatch table with empty functions */
131 #define X(func, ret, typeargs, args, icdidx, tebidx, stack) \
132 dispatchTable->dispatch_table[icdidx] = (PROC)glEmptyFunc##stack; \
134 teb->glDispatchTable[tebidx] = (PVOID)glEmptyFunc##stack;
138 teb
->glTable
= dispatchTable
->dispatch_table
;
139 TlsSetValue( OPENGL32_tls
, lpData
);
142 /* The thread of the attached process terminates. */
143 case DLL_THREAD_DETACH
:
144 /* Release the allocated memory for this thread.*/
145 OPENGL32_ThreadDetach();
148 /* DLL unload due to process termination or FreeLibrary. */
149 case DLL_PROCESS_DETACH
:
150 OPENGL32_ThreadDetach();
152 /* FIXME: free resources (driver list, glrc list) */
153 CloseHandle( OPENGL32_processdata
.driver_mutex
);
154 CloseHandle( OPENGL32_processdata
.glrc_mutex
);
155 TlsFree(OPENGL32_tls
);
162 /* FUNCTION: Append ICD to linked list.
163 * ARGUMENTS: [IN] icd: GLDRIVERDATA to append to list
164 * NOTES: Only call this when you hold the driver_mutex
168 OPENGL32_AppendICD( GLDRIVERDATA
*icd
)
170 if (OPENGL32_processdata
.driver_list
== NULL
)
171 OPENGL32_processdata
.driver_list
= icd
;
174 GLDRIVERDATA
*p
= OPENGL32_processdata
.driver_list
;
175 while (p
->next
!= NULL
)
182 /* FUNCTION: Remove ICD from linked list.
183 * ARGUMENTS: [IN] icd: GLDRIVERDATA to remove from list
184 * NOTES: Only call this when you hold the driver_mutex
188 OPENGL32_RemoveICD( GLDRIVERDATA
*icd
)
190 if (icd
== OPENGL32_processdata
.driver_list
)
191 OPENGL32_processdata
.driver_list
= icd
->next
;
194 GLDRIVERDATA
*p
= OPENGL32_processdata
.driver_list
;
204 DBGPRINT( "Error: ICD 0x%08x not found in list!", icd
);
209 /* FUNCTION: Load an ICD.
210 * ARGUMENTS: [IN] driver: Name of display driver.
211 * RETURNS: error code; ERROR_SUCCESS on success
213 * TODO: call SetLastError() where appropriate
217 OPENGL32_LoadDriver( LPCWSTR driver
)
222 DBGPRINT( "Info: Loading driver %ws...", driver
);
224 /* allocate driver data */
225 icd
= (GLDRIVERDATA
*)HeapAlloc( GetProcessHeap(),
226 HEAP_GENERATE_EXCEPTIONS
| HEAP_ZERO_MEMORY
,
227 sizeof (GLDRIVERDATA
) );
230 DBGPRINT( "Error: Couldn't allocate GLDRIVERDATA! (%d)", GetLastError() );
234 ret
= OPENGL32_RegGetDriverInfo( driver
, icd
);
235 if (ret
!= ERROR_SUCCESS
)
237 DBGPRINT( "Error: Couldn't query driver information (%d)", ret
);
238 if (!HeapFree( GetProcessHeap(), 0, icd
))
239 DBGPRINT( "Error: HeapFree() returned false, error code = %d",
244 DBGPRINT( "Info: Dll = %ws", icd
->dll
);
245 DBGPRINT( "Info: Version = 0x%08x", icd
->version
);
246 DBGPRINT( "Info: DriverVersion = 0x%08x", icd
->driver_version
);
247 DBGPRINT( "Info: Flags = 0x%08x", icd
->flags
);
249 /* load/initialize ICD */
250 ret
= OPENGL32_InitializeDriver( icd
);
251 if (ret
!= ERROR_SUCCESS
)
253 DBGPRINT( "Error: Couldnt initialize ICD!" );
254 if (!HeapFree( GetProcessHeap(), 0, icd
))
255 DBGPRINT( "Error: HeapFree() returned false, error code = %d",
260 /* append ICD to list */
261 OPENGL32_AppendICD( icd
);
262 DBGPRINT( "Info: ICD loaded." );
268 /* FUNCTION: Initialize a driver (Load DLL, DrvXXX and glXXX procs)
269 * ARGUMENTS: [IN] icd: ICD to initialize with the dll, version, driverVersion
270 * and flags already filled.
271 * RETURNS: error code; ERROR_SUCCESS on success
273 #define LOAD_DRV_PROC( icd, proc, required ) \
274 *(char**)&icd->proc = (char*)GetProcAddress( icd->handle, #proc ); \
275 if (required && icd->proc == NULL) { \
276 DBGPRINT( "Error: GetProcAddress(\"%s\") failed!", #proc ); \
277 FreeLibrary( icd->handle ); \
278 return GetLastError(); \
283 OPENGL32_InitializeDriver( GLDRIVERDATA
*icd
)
286 if (icd
->version
> 2)
287 DBGPRINT( "Warning: ICD version > 2 (%d)", icd
->version
);
290 icd
->handle
= LoadLibraryW( icd
->dll
);
291 if (icd
->handle
== NULL
)
293 DWORD err
= GetLastError();
294 DBGPRINT( "Error: Couldn't load DLL! (%d)", err
);
298 /* validate version */
299 if (icd
->driver_version
> 1)
301 LOAD_DRV_PROC(icd
, DrvValidateVersion
, FALSE
);
302 if (icd
->DrvValidateVersion
!= NULL
)
304 if (!icd
->DrvValidateVersion( icd
->driver_version
))
306 DBGPRINT( "Error: DrvValidateVersion failed!" );
308 FreeLibrary( icd
->handle
);
309 return ERROR_INVALID_FUNCTION
; /* FIXME: use better error code */
313 DBGPRINT( "Info: DrvValidateVersion not exported by ICD" );
316 /* load DrvXXX procs */
317 LOAD_DRV_PROC(icd
, DrvCopyContext
, TRUE
);
318 LOAD_DRV_PROC(icd
, DrvCreateContext
, FALSE
);
319 LOAD_DRV_PROC(icd
, DrvCreateLayerContext
, FALSE
);
320 LOAD_DRV_PROC(icd
, DrvDeleteContext
, TRUE
);
321 LOAD_DRV_PROC(icd
, DrvDescribeLayerPlane
, TRUE
);
322 LOAD_DRV_PROC(icd
, DrvDescribePixelFormat
, TRUE
);
323 LOAD_DRV_PROC(icd
, DrvGetLayerPaletteEntries
, TRUE
);
324 LOAD_DRV_PROC(icd
, DrvGetProcAddress
, TRUE
);
325 LOAD_DRV_PROC(icd
, DrvReleaseContext
, TRUE
);
326 LOAD_DRV_PROC(icd
, DrvRealizeLayerPalette
, TRUE
);
327 LOAD_DRV_PROC(icd
, DrvSetContext
, TRUE
);
328 LOAD_DRV_PROC(icd
, DrvSetLayerPaletteEntries
, TRUE
);
329 LOAD_DRV_PROC(icd
, DrvSetPixelFormat
, TRUE
);
330 LOAD_DRV_PROC(icd
, DrvShareLists
, TRUE
);
331 LOAD_DRV_PROC(icd
, DrvSwapBuffers
, TRUE
);
332 LOAD_DRV_PROC(icd
, DrvSwapLayerBuffers
, TRUE
);
334 /* we require at least one of DrvCreateContext and DrvCreateLayerContext */
335 if (icd
->DrvCreateContext
== NULL
|| icd
->DrvCreateLayerContext
== NULL
)
337 DBGPRINT( "Error: One of DrvCreateContext/DrvCreateLayerContext is required!" );
338 FreeLibrary( icd
->handle
);
339 return ERROR_INVALID_FUNCTION
; /* FIXME: use better error code... */
342 return ERROR_SUCCESS
;
346 /* FUNCTION: Unload loaded ICD.
347 * RETURNS: TRUE on success, FALSE otherwise.
351 OPENGL32_UnloadDriver( GLDRIVERDATA
*icd
)
355 DBGPRINT( "Info: Unloading driver %ws...", icd
->driver_name
);
356 if (icd
->refcount
!= 0)
357 DBGPRINT( "Warning: ICD refcount = %d (should be 0)", icd
->refcount
);
360 if (!FreeLibrary( icd
->handle
))
363 DBGPRINT( "Warning: FreeLibrary on ICD %ws failed! (%d)", icd
->dll
,
368 OPENGL32_RemoveICD( icd
);
369 if (!HeapFree( GetProcessHeap(), 0, icd
))
372 DBGPRINT( "Warning: HeapFree() returned FALSE, error code = %d",
380 /* FUNCTION: Load ICD from HDC (shared ICD data)
381 * RETURNS: GLDRIVERDATA pointer on success, NULL otherwise.
382 * NOTES: Make sure the handle you pass in is one for a DC!
383 * Increases the refcount of the ICD - use
384 * OPENGL32_UnloadICD to release the ICD.
386 GLDRIVERDATA
*OPENGL32_LoadICDForHDC( HDC hdc
)
392 /* get driver name */
393 ret
= ExtEscape( hdc
, EXT_GET_DRIVERINFO
, sizeof (dwInput
), (LPCSTR
)&dwInput
,
394 sizeof (EXTDRIVERINFO
), (LPSTR
)&info
);
397 DBGPRINT( "Warning: ExtEscape to get the drivername failed!!! (%d)", GetLastError() );
401 /* load driver (or get a reference) */
402 return OPENGL32_LoadICD( info
.driver_name
);
406 /* FUNCTION: Load ICD (shared ICD data)
407 * RETURNS: GLDRIVERDATA pointer on success, NULL otherwise.
410 OPENGL32_LoadICD ( LPCWSTR driver
)
415 if (WaitForSingleObject( OPENGL32_processdata
.driver_mutex
, INFINITE
) ==
418 DBGPRINT( "Error: WaitForSingleObject() failed (%d)", GetLastError() );
419 return NULL
; /* FIXME: do we have to expect such an error and handle it? */
422 /* look if ICD is already loaded */
423 for (icd
= OPENGL32_processdata
.driver_list
; icd
; icd
= icd
->next
)
425 if (!_wcsicmp( driver
, icd
->driver_name
)) /* found */
430 if (!ReleaseMutex( OPENGL32_processdata
.driver_mutex
))
431 DBGPRINT( "Error: ReleaseMutex() failed (%d)", GetLastError() );
437 /* not found - try to load */
438 icd
= OPENGL32_LoadDriver( driver
);
443 if (!ReleaseMutex( OPENGL32_processdata
.driver_mutex
))
444 DBGPRINT( "Error: ReleaseMutex() failed (%d)", GetLastError() );
450 /* FUNCTION: Unload ICD (shared ICD data)
451 * RETURNS: TRUE on success, FALSE otherwise.
454 OPENGL32_UnloadICD( GLDRIVERDATA
*icd
)
459 if (WaitForSingleObject( OPENGL32_processdata
.driver_mutex
, INFINITE
) ==
462 DBGPRINT( "Error: WaitForSingleObject() failed (%d)", GetLastError() );
463 return FALSE
; /* FIXME: do we have to expect such an error and handle it? */
467 if (icd
->refcount
== 0)
468 ret
= OPENGL32_UnloadDriver( icd
);
471 if (!ReleaseMutex( OPENGL32_processdata
.driver_mutex
))
472 DBGPRINT( "Error: ReleaseMutex() failed (%d)", GetLastError() );
478 /* FUNCTION: Enumerate OpenGLDrivers (from registry)
479 * ARGUMENTS: [IN] idx Index of the driver to get information about
480 * [OUT] name Pointer to an array of WCHARs (can be NULL)
481 * [I,O] cName Pointer to a DWORD. Input is len of name array;
482 * Output is length of the drivername.
483 * Can be NULL if name is NULL.
484 * RETURNS: Error code (ERROR_NO_MORE_ITEMS at end of list); On failure all
485 * OUT vars are left untouched.
488 OPENGL32_RegEnumDrivers( DWORD idx
, LPWSTR name
, LPDWORD cName
)
492 L
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\OpenGLDrivers\\";
498 return ERROR_SUCCESS
; /* nothing to do */
501 return ERROR_INVALID_FUNCTION
; /* we need cName when name is given */
503 /* open OpenGLDrivers registry key */
504 ret
= RegOpenKeyExW( HKEY_LOCAL_MACHINE
, subKey
, 0, KEY_READ
, &hKey
);
505 if (ret
!= ERROR_SUCCESS
)
507 DBGPRINT( "Error: Couldn't open registry key '%ws'", subKey
);
511 /* get subkey name */
512 size
= sizeof (driver
) / sizeof (driver
[0]);
513 ret
= RegEnumKeyW( hKey
, idx
, name
, *cName
);
514 if (ret
!= ERROR_SUCCESS
)
516 DBGPRINT( "Error: Couldn't get OpenGLDrivers subkey name (%d)", ret
);
520 *cName
= wcslen( name
);
524 return ERROR_SUCCESS
;
528 /* FUNCTION: Get registry values for a driver given a name
529 * ARGUMENTS: [IN] idx Index of the driver to get information about
530 * [OUT] icd Pointer to GLDRIVERDATA. On success the following
531 * fields are filled: driver_name, dll, version,
532 * driver_version and flags.
533 * RETURNS: Error code; On failure all OUT vars are left untouched.
537 OPENGL32_RegGetDriverInfo( LPCWSTR driver
, GLDRIVERDATA
*icd
)
541 L
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\OpenGLDrivers\\";
545 /* drivers registry values */
546 DWORD version
= 1, driverVersion
= 0, flags
= 0;
549 /* open driver registry key */
550 wcsncat( subKey
, driver
, 1024 );
551 ret
= RegOpenKeyExW( HKEY_LOCAL_MACHINE
, subKey
, 0, KEY_READ
, &hKey
);
552 if (ret
!= ERROR_SUCCESS
)
554 DBGPRINT( "Error: Couldn't open registry key '%ws'", subKey
);
560 ret
= RegQueryValueExW( hKey
, L
"Dll", 0, &type
, (LPBYTE
)dll
, &size
);
561 if (ret
!= ERROR_SUCCESS
|| type
!= REG_SZ
)
563 DBGPRINT( "Error: Couldn't query Dll value or not a string" );
568 size
= sizeof (DWORD
);
569 ret
= RegQueryValueExW( hKey
, L
"Version", 0, &type
, (LPBYTE
)&version
, &size
);
570 if (ret
!= ERROR_SUCCESS
|| type
!= REG_DWORD
)
571 DBGPRINT( "Warning: Couldn't query Version value or not a DWORD" );
573 size
= sizeof (DWORD
);
574 ret
= RegQueryValueExW( hKey
, L
"DriverVersion", 0, &type
,
575 (LPBYTE
)&driverVersion
, &size
);
576 if (ret
!= ERROR_SUCCESS
|| type
!= REG_DWORD
)
577 DBGPRINT( "Warning: Couldn't query DriverVersion value or not a DWORD" );
579 size
= sizeof (DWORD
);
580 ret
= RegQueryValueExW( hKey
, L
"Flags", 0, &type
, (LPBYTE
)&flags
, &size
);
581 if (ret
!= ERROR_SUCCESS
|| type
!= REG_DWORD
)
582 DBGPRINT( "Warning: Couldn't query Flags value or not a DWORD" );
588 /* FIXME: NUL-terminate strings? */
589 wcsncpy( icd
->driver_name
, driver
,
590 sizeof (icd
->driver_name
) / sizeof (icd
->driver_name
[0]) - 1 );
591 wcsncpy( icd
->dll
, dll
,
592 sizeof (icd
->dll
) / sizeof (icd
->dll
[0]) );
593 icd
->version
= version
;
594 icd
->driver_version
= driverVersion
;
597 return ERROR_SUCCESS
;