2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: lib/opengl32/opengl32.c
5 * PURPOSE: OpenGL32 lib
6 * PROGRAMMER: Anich Gregor (blight), Royce Mitchell III
13 /* function prototypes */
14 static void OPENGL32_AppendICD( GLDRIVERDATA
*icd
);
15 static void OPENGL32_RemoveICD( GLDRIVERDATA
*icd
);
16 static GLDRIVERDATA
*OPENGL32_LoadDriver( LPCWSTR regKey
);
17 static DWORD
OPENGL32_InitializeDriver( GLDRIVERDATA
*icd
);
18 static BOOL
OPENGL32_UnloadDriver( GLDRIVERDATA
*icd
);
19 static DWORD
OPENGL32_RegGetDriverInfo( LPCWSTR driver
, GLDRIVERDATA
*icd
);
23 GLPROCESSDATA OPENGL32_processdata
;
27 OPENGL32_ThreadAttach( void )
29 PROC
*dispatchTable
= NULL
;
32 dispatchTable
= (PROC
*)HeapAlloc( GetProcessHeap(),
33 HEAP_GENERATE_EXCEPTIONS
| HEAP_ZERO_MEMORY
,
34 DISPATCH_TABLE_SIZE
);
35 if (dispatchTable
== NULL
)
37 DBGPRINT( "Error: Couldn't allocate GL dispatch table" );
43 /* initialize dispatch table with empty functions */
44 #define X(func, ret, typeargs, args, icdidx, tebidx, stack) \
45 dispatchTable[icdidx] = (PROC)glEmptyFunc##stack; \
47 teb->glDispatchTable[tebidx] = (PVOID)glEmptyFunc##stack;
51 teb
->glTable
= dispatchTable
;
52 /* At first we have no context */
53 teb
->glCurrentRC
= NULL
;
60 OPENGL32_ThreadDetach( void )
62 TEB
* teb
= NtCurrentTeb();
64 rosglMakeCurrent( NULL
, NULL
);
66 if (teb
->glTable
!= NULL
)
68 if (!HeapFree( GetProcessHeap(), 0, teb
->glTable
))
70 DBGPRINT( "Warning: HeapFree() on dispatch table failed (%d)",
73 /* NULL-ify it. Even if something went wrong, it's not a good idea to keep it non NULL */
80 OPENGL32_ProcessAttach( void )
82 SECURITY_ATTRIBUTES attrib
= { sizeof (SECURITY_ATTRIBUTES
), /* nLength */
83 NULL
, /* lpSecurityDescriptor */
84 TRUE
/* bInheritHandle */ };
86 memset( &OPENGL32_processdata
, 0, sizeof (OPENGL32_processdata
) );
88 /* create driver, glrc & dcdata 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)",
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)",
103 OPENGL32_processdata
.dcdata_mutex
= CreateMutex( &attrib
, FALSE
, NULL
);
104 if (OPENGL32_processdata
.dcdata_mutex
== NULL
)
106 DBGPRINT( "Error: Couldn't create dcdata_list mutex (%d)",
116 OPENGL32_ProcessDetach( void )
118 GLDRIVERDATA
*icd
, *icd2
;
119 GLDCDATA
*dcdata
, *dcdata2
;
123 for (dcdata
= OPENGL32_processdata
.dcdata_list
; dcdata
!= NULL
;)
126 dcdata
= dcdata
->next
;
127 if (!HeapFree( GetProcessHeap(), 0, dcdata2
))
128 DBGPRINT( "Warning: HeapFree() on DCDATA 0x%08x failed (%d)",
129 dcdata2
, GetLastError() );
132 for (glrc
= OPENGL32_processdata
.glrc_list
; glrc
!= NULL
;)
136 if (!HeapFree( GetProcessHeap(), 0, glrc2
))
137 DBGPRINT( "Warning: HeapFree() on GLRC 0x%08x failed (%d)",
138 glrc2
, GetLastError() );
141 for (icd
= OPENGL32_processdata
.driver_list
; icd
!= NULL
;)
145 if (!HeapFree( GetProcessHeap(), 0, icd2
))
146 DBGPRINT( "Warning: HeapFree() on DRIVERDATA 0x%08x failed (%d)",
147 icd2
, GetLastError() );
151 if (OPENGL32_processdata
.driver_mutex
!= NULL
)
152 CloseHandle( OPENGL32_processdata
.driver_mutex
);
153 if (OPENGL32_processdata
.glrc_mutex
!= NULL
)
154 CloseHandle( OPENGL32_processdata
.glrc_mutex
);
155 if (OPENGL32_processdata
.dcdata_mutex
!= NULL
)
156 CloseHandle( OPENGL32_processdata
.dcdata_mutex
);
161 DllMain(HINSTANCE hInstance
, DWORD Reason
, LPVOID Reserved
)
163 DBGPRINT( "Info: Called!" );
166 /* The DLL is loading due to process
167 * initialization or a call to LoadLibrary.
169 case DLL_PROCESS_ATTACH
:
170 DBGTRACE( "Process attach" );
171 if (!OPENGL32_ProcessAttach())
173 /* No break: Initialize the index for first thread. */
175 /* The attached process creates a new thread. */
176 case DLL_THREAD_ATTACH
:
177 DBGTRACE( "Thread attach" );
178 if (!OPENGL32_ThreadAttach())
182 /* The thread of the attached process terminates. */
183 case DLL_THREAD_DETACH
:
184 DBGTRACE( "Thread detach" );
185 /* Release the allocated memory for this thread.*/
186 OPENGL32_ThreadDetach();
189 /* DLL unload due to process termination or FreeLibrary. */
190 case DLL_PROCESS_DETACH
:
191 DBGTRACE( "Process detach" );
192 OPENGL32_ThreadDetach();
193 OPENGL32_ProcessDetach();
201 /*! \brief Append ICD to linked list.
203 * \param icd GLDRIVERDATA to append to list
205 * \note Only call this when you hold the driver_mutex.
208 OPENGL32_AppendICD( GLDRIVERDATA
*icd
)
210 if (OPENGL32_processdata
.driver_list
== NULL
)
211 OPENGL32_processdata
.driver_list
= icd
;
214 GLDRIVERDATA
*p
= OPENGL32_processdata
.driver_list
;
215 while (p
->next
!= NULL
)
222 /*! \brief Remove ICD from linked list.
224 * \param icd GLDRIVERDATA to remove from list
226 * \note Only call this when you hold the driver_mutex.
229 OPENGL32_RemoveICD( GLDRIVERDATA
*icd
)
231 if (icd
== OPENGL32_processdata
.driver_list
)
232 OPENGL32_processdata
.driver_list
= icd
->next
;
235 GLDRIVERDATA
*p
= OPENGL32_processdata
.driver_list
;
245 DBGPRINT( "Error: ICD 0x%08x not found in list!", icd
);
250 /*! \brief Load an ICD.
252 * \param driver Name of installable client driver.
254 * \return Pointer to an allocated GLDRIVERDATA struct.
255 * \retval NULL Failure.
257 * \todo Call SetLastError() where appropriate.
259 static GLDRIVERDATA
*
260 OPENGL32_LoadDriver( LPCWSTR driver
)
265 DBGPRINT( "Info: Loading driver %ws...", driver
);
267 /* allocate driver data */
268 icd
= (GLDRIVERDATA
*)HeapAlloc( GetProcessHeap(),
269 HEAP_GENERATE_EXCEPTIONS
| HEAP_ZERO_MEMORY
,
270 sizeof (GLDRIVERDATA
) );
273 DBGPRINT( "Error: Couldn't allocate GLDRIVERDATA! (%d)", GetLastError() );
277 ret
= OPENGL32_RegGetDriverInfo( driver
, icd
);
278 if (ret
!= ERROR_SUCCESS
)
280 DBGPRINT( "Error: Couldn't query driver information (%d)", ret
);
281 if (!HeapFree( GetProcessHeap(), 0, icd
))
282 DBGPRINT( "Error: HeapFree() returned false, error code = %d",
287 DBGPRINT( "Info: Dll = %ws", icd
->dll
);
288 DBGPRINT( "Info: Version = 0x%08x", icd
->version
);
289 DBGPRINT( "Info: DriverVersion = 0x%08x", icd
->driver_version
);
290 DBGPRINT( "Info: Flags = 0x%08x", icd
->flags
);
292 /* load/initialize ICD */
293 ret
= OPENGL32_InitializeDriver( icd
);
294 if (ret
!= ERROR_SUCCESS
)
296 DBGPRINT( "Error: Couldnt initialize ICD!" );
297 if (!HeapFree( GetProcessHeap(), 0, icd
))
298 DBGPRINT( "Error: HeapFree() returned false, error code = %d",
303 /* append ICD to list */
304 OPENGL32_AppendICD( icd
);
305 DBGPRINT( "Info: ICD loaded." );
311 /*! \brief Initialize a driver (Load DLL and DrvXxx procs)
313 * \param icd ICD to initialize with the dll, version, driverVersion
314 * and flags already filled.
315 * \return Error code.
316 * \retval ERROR_SUCCESS Success
318 #define LOAD_DRV_PROC( icd, proc, required ) \
319 *(char**)&icd->proc = (char*)GetProcAddress( icd->handle, #proc ); \
320 if (required && icd->proc == NULL) { \
321 DBGPRINT( "Error: GetProcAddress(\"%s\") failed!", #proc ); \
322 FreeLibrary( icd->handle ); \
323 return GetLastError(); \
327 OPENGL32_InitializeDriver( GLDRIVERDATA
*icd
)
330 if (icd
->version
> 2)
331 DBGPRINT( "Warning: ICD version > 2 (%d)", icd
->version
);
334 icd
->handle
= LoadLibraryW( icd
->dll
);
335 if (icd
->handle
== NULL
)
337 DWORD err
= GetLastError();
338 DBGPRINT( "Error: Couldn't load DLL! (%d)", err
);
342 /* validate version */
343 if (icd
->driver_version
> 1)
345 LOAD_DRV_PROC(icd
, DrvValidateVersion
, FALSE
);
346 if (icd
->DrvValidateVersion
!= NULL
)
348 if (!icd
->DrvValidateVersion( icd
->driver_version
))
350 DBGPRINT( "Error: DrvValidateVersion failed!" );
352 FreeLibrary( icd
->handle
);
353 return ERROR_INVALID_FUNCTION
; /* FIXME: use better error code */
357 DBGPRINT( "Info: DrvValidateVersion not exported by ICD" );
360 /* load DrvXXX procs */
361 LOAD_DRV_PROC(icd
, DrvCopyContext
, TRUE
);
362 LOAD_DRV_PROC(icd
, DrvCreateContext
, FALSE
);
363 LOAD_DRV_PROC(icd
, DrvCreateLayerContext
, FALSE
);
364 LOAD_DRV_PROC(icd
, DrvDeleteContext
, TRUE
);
365 LOAD_DRV_PROC(icd
, DrvDescribeLayerPlane
, TRUE
);
366 LOAD_DRV_PROC(icd
, DrvDescribePixelFormat
, TRUE
);
367 LOAD_DRV_PROC(icd
, DrvGetLayerPaletteEntries
, TRUE
);
368 LOAD_DRV_PROC(icd
, DrvGetProcAddress
, TRUE
);
369 LOAD_DRV_PROC(icd
, DrvReleaseContext
, TRUE
);
370 LOAD_DRV_PROC(icd
, DrvRealizeLayerPalette
, TRUE
);
371 LOAD_DRV_PROC(icd
, DrvSetContext
, TRUE
);
372 LOAD_DRV_PROC(icd
, DrvSetLayerPaletteEntries
, TRUE
);
373 LOAD_DRV_PROC(icd
, DrvSetPixelFormat
, TRUE
);
374 LOAD_DRV_PROC(icd
, DrvShareLists
, TRUE
);
375 LOAD_DRV_PROC(icd
, DrvSwapBuffers
, TRUE
);
376 LOAD_DRV_PROC(icd
, DrvSwapLayerBuffers
, TRUE
);
378 /* we require at least one of DrvCreateContext and DrvCreateLayerContext */
379 if (icd
->DrvCreateContext
== NULL
&& icd
->DrvCreateLayerContext
== NULL
)
381 DBGPRINT( "Error: One of DrvCreateContext/DrvCreateLayerContext is required!" );
382 FreeLibrary( icd
->handle
);
383 return ERROR_INVALID_FUNCTION
; /* FIXME: use better error code... */
386 return ERROR_SUCCESS
;
390 /*! \brief Unload ICD.
392 * \retval TRUE Success.
393 * \retval FALSE Failure.
396 OPENGL32_UnloadDriver( GLDRIVERDATA
*icd
)
400 DBGPRINT( "Info: Unloading driver %ws...", icd
->driver_name
);
401 if (icd
->refcount
!= 0)
402 DBGPRINT( "Warning: ICD refcount = %d (should be 0)", icd
->refcount
);
405 if (!FreeLibrary( icd
->handle
))
408 DBGPRINT( "Warning: FreeLibrary on ICD %ws failed! (%d)", icd
->dll
,
413 OPENGL32_RemoveICD( icd
);
414 if (!HeapFree( GetProcessHeap(), 0, icd
))
417 DBGPRINT( "Warning: HeapFree() returned FALSE, error code = %d",
425 /*! \brief Load ICD (shared ICD data)
427 * \return Pointer to an allocated GLDRIVERDATA on success.
428 * \retval NULL Failure.
431 OPENGL32_LoadICD( LPCWSTR driver
)
436 if (WaitForSingleObject( OPENGL32_processdata
.driver_mutex
, INFINITE
) ==
439 DBGPRINT( "Error: WaitForSingleObject() failed (%d)", GetLastError() );
440 return NULL
; /* FIXME: do we have to expect such an error and handle it? */
443 /* look if ICD is already loaded */
444 for (icd
= OPENGL32_processdata
.driver_list
; icd
; icd
= icd
->next
)
446 if (!_wcsicmp( driver
, icd
->driver_name
)) /* found */
449 if (!ReleaseMutex( OPENGL32_processdata
.driver_mutex
))
450 DBGPRINT( "Error: ReleaseMutex() failed (%d)", GetLastError() );
456 /* not found - try to load */
457 icd
= OPENGL32_LoadDriver( driver
);
460 if (!ReleaseMutex( OPENGL32_processdata
.driver_mutex
))
461 DBGPRINT( "Error: ReleaseMutex() failed (%d)", GetLastError() );
467 /*! \brief Unload ICD (shared ICD data)
469 * \retval TRUE Success.
470 * \retval FALSE Failure.
473 OPENGL32_UnloadICD( GLDRIVERDATA
*icd
)
478 if (WaitForSingleObject( OPENGL32_processdata
.driver_mutex
, INFINITE
) ==
481 DBGPRINT( "Error: WaitForSingleObject() failed (%d)", GetLastError() );
482 return FALSE
; /* FIXME: do we have to expect such an error and handle it? */
485 if (icd
->refcount
== 0)
486 ret
= OPENGL32_UnloadDriver( icd
);
489 if (!ReleaseMutex( OPENGL32_processdata
.driver_mutex
))
490 DBGPRINT( "Error: ReleaseMutex() failed (%d)", GetLastError() );
496 /*! \brief Enumerate OpenGLDrivers (from registry)
498 * \param idx Index of the driver to get information about.
499 * \param name Pointer to an array of WCHARs (can be NULL)
500 * \param cName Pointer to a DWORD. Input is len of name array.
501 * Output is length of the drivername.
502 * Can be NULL if name is NULL.
505 * \retval ERROR_NO_MORE_ITEMS End of driver list.
506 * \retval ERROR_SUCCESS Success.
510 OPENGL32_RegEnumDrivers( DWORD idx
, LPWSTR name
, LPDWORD cName
)
513 LPCWSTR subKey
= OPENGL_DRIVERS_SUBKEY
;
519 return ERROR_SUCCESS
; /* nothing to do */
522 return ERROR_INVALID_FUNCTION
; /* we need cName when name is given */
524 /* open OpenGLDrivers registry key */
525 ret
= RegOpenKeyExW( HKEY_LOCAL_MACHINE
, subKey
, 0, KEY_READ
, &hKey
);
526 if (ret
!= ERROR_SUCCESS
)
528 DBGPRINT( "Error: Couldn't open registry key '%ws'", subKey
);
532 /* get subkey name */
533 size
= sizeof (driver
) / sizeof (driver
[0]);
534 ret
= RegEnumKeyW( hKey
, idx
, name
, *cName
);
535 if (ret
!= ERROR_SUCCESS
)
537 DBGPRINT( "Error: Couldn't get OpenGLDrivers subkey name (%d)", ret
);
541 *cName
= wcslen( name
);
545 return ERROR_SUCCESS
;
547 #endif /* 0 -- unused */
550 /*! \brief Get registry values for a driver given a name.
552 * \param driver Name of the driver to get information about.
553 * \param icd Pointer to GLDRIVERDATA.
555 * \return Error code.
556 * \retval ERROR_SUCCESS Success.
558 * \note On success the following fields of \a icd are filled: \a driver_name,
559 * \a dll, \a version, \a driver_version and \a flags.
562 OPENGL32_RegGetDriverInfo( LPCWSTR driver
, GLDRIVERDATA
*icd
)
565 WCHAR subKey
[1024] = OPENGL_DRIVERS_SUBKEY2
;
569 /* drivers registry values */
570 DWORD version
= 1, driverVersion
= 0, flags
= 0;
573 /* open driver registry key */
574 wcsncat( subKey
, driver
, 1024 );
575 ret
= RegOpenKeyExW( HKEY_LOCAL_MACHINE
, subKey
, 0, KEY_READ
, &hKey
);
576 if (ret
!= ERROR_SUCCESS
)
578 DBGPRINT( "Error: Couldn't open registry key '%ws'", subKey
);
584 ret
= RegQueryValueExW( hKey
, L
"Dll", 0, &type
, (LPBYTE
)dll
, &size
);
585 if (ret
!= ERROR_SUCCESS
|| type
!= REG_SZ
)
587 DBGPRINT( "Error: Couldn't query Dll value or not a string" );
592 size
= sizeof (DWORD
);
593 ret
= RegQueryValueExW( hKey
, L
"Version", 0, &type
, (LPBYTE
)&version
, &size
);
594 if (ret
!= ERROR_SUCCESS
|| type
!= REG_DWORD
)
595 DBGPRINT( "Warning: Couldn't query Version value or not a DWORD" );
597 size
= sizeof (DWORD
);
598 ret
= RegQueryValueExW( hKey
, L
"DriverVersion", 0, &type
,
599 (LPBYTE
)&driverVersion
, &size
);
600 if (ret
!= ERROR_SUCCESS
|| type
!= REG_DWORD
)
601 DBGPRINT( "Warning: Couldn't query DriverVersion value or not a DWORD" );
603 size
= sizeof (DWORD
);
604 ret
= RegQueryValueExW( hKey
, L
"Flags", 0, &type
, (LPBYTE
)&flags
, &size
);
605 if (ret
!= ERROR_SUCCESS
|| type
!= REG_DWORD
)
606 DBGPRINT( "Warning: Couldn't query Flags value or not a DWORD" );
612 /* FIXME: NUL-terminate strings? */
613 wcsncpy( icd
->driver_name
, driver
,
614 sizeof (icd
->driver_name
) / sizeof (icd
->driver_name
[0]) - 1 );
615 wcsncpy( icd
->dll
, dll
,
616 sizeof (icd
->dll
) / sizeof (icd
->dll
[0]) );
617 icd
->version
= version
;
618 icd
->driver_version
= driverVersion
;
621 return ERROR_SUCCESS
;