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
13 #define WIN32_NO_STATUS
22 /* function prototypes */
23 static void OPENGL32_AppendICD( GLDRIVERDATA
*icd
);
24 static void OPENGL32_RemoveICD( GLDRIVERDATA
*icd
);
25 static GLDRIVERDATA
*OPENGL32_LoadDriver( LPCWSTR regKey
);
26 static DWORD
OPENGL32_InitializeDriver( GLDRIVERDATA
*icd
);
27 static BOOL
OPENGL32_UnloadDriver( GLDRIVERDATA
*icd
);
28 static DWORD
OPENGL32_RegGetDriverInfo( LPCWSTR driver
, GLDRIVERDATA
*icd
);
33 GLPROCESSDATA OPENGL32_processdata
;
37 OPENGL32_ThreadAttach()
39 GLTHREADDATA
* lpData
= NULL
;
40 PROC
*dispatchTable
= NULL
;
43 dispatchTable
= (PROC
*)HeapAlloc( GetProcessHeap(),
44 HEAP_GENERATE_EXCEPTIONS
| HEAP_ZERO_MEMORY
,
45 sizeof (((ICDTable
*)(0))->dispatch_table
) );
46 if (dispatchTable
== NULL
)
48 DBGPRINT( "Error: Couldn't allocate GL dispatch table" );
52 lpData
= (GLTHREADDATA
*)HeapAlloc( GetProcessHeap(),
53 HEAP_GENERATE_EXCEPTIONS
| HEAP_ZERO_MEMORY
,
54 sizeof (GLTHREADDATA
) );
57 DBGPRINT( "Error: Couldn't allocate GLTHREADDATA" );
58 HeapFree( GetProcessHeap(), 0, dispatchTable
);
64 /* initialize dispatch table with empty functions */
65 #define X(func, ret, typeargs, args, icdidx, tebidx, stack) \
66 dispatchTable[icdidx] = (PROC)glEmptyFunc##stack; \
68 teb->glDispatchTable[tebidx] = (PVOID)glEmptyFunc##stack;
72 teb
->glTable
= dispatchTable
;
73 TlsSetValue( OPENGL32_tls
, lpData
);
80 OPENGL32_ThreadDetach()
82 GLTHREADDATA
* lpData
= NULL
;
83 PROC
*dispatchTable
= NULL
;
85 rosglMakeCurrent( NULL
, NULL
);
87 lpData
= (GLTHREADDATA
*)TlsGetValue( OPENGL32_tls
);
90 if (!HeapFree( GetProcessHeap(), 0, lpData
))
91 DBGPRINT( "Warning: HeapFree() on GLTHREADDATA failed (%d)",
95 dispatchTable
= NtCurrentTeb()->glTable
;
96 if (dispatchTable
!= NULL
)
98 if (!HeapFree( GetProcessHeap(), 0, dispatchTable
))
99 DBGPRINT( "Warning: HeapFree() on dispatch table failed (%d)",
106 OPENGL32_ProcessAttach()
108 SECURITY_ATTRIBUTES attrib
= { sizeof (SECURITY_ATTRIBUTES
), /* nLength */
109 NULL
, /* lpSecurityDescriptor */
110 TRUE
/* bInheritHandle */ };
112 OPENGL32_tls
= TlsAlloc();
113 if (0xFFFFFFFF == OPENGL32_tls
)
116 memset( &OPENGL32_processdata
, 0, sizeof (OPENGL32_processdata
) );
118 /* create driver, glrc & dcdata list mutex */
119 OPENGL32_processdata
.driver_mutex
= CreateMutex( &attrib
, FALSE
, NULL
);
120 if (OPENGL32_processdata
.driver_mutex
== NULL
)
122 DBGPRINT( "Error: Couldn't create driver_list mutex (%d)",
126 OPENGL32_processdata
.glrc_mutex
= CreateMutex( &attrib
, FALSE
, NULL
);
127 if (OPENGL32_processdata
.glrc_mutex
== NULL
)
129 DBGPRINT( "Error: Couldn't create glrc_list mutex (%d)",
133 OPENGL32_processdata
.dcdata_mutex
= CreateMutex( &attrib
, FALSE
, NULL
);
134 if (OPENGL32_processdata
.dcdata_mutex
== NULL
)
136 DBGPRINT( "Error: Couldn't create dcdata_list mutex (%d)",
146 OPENGL32_ProcessDetach()
148 GLDRIVERDATA
*icd
, *icd2
;
149 GLDCDATA
*dcdata
, *dcdata2
;
153 for (dcdata
= OPENGL32_processdata
.dcdata_list
; dcdata
!= NULL
;)
156 dcdata
= dcdata
->next
;
157 if (!HeapFree( GetProcessHeap(), 0, dcdata
))
158 DBGPRINT( "Warning: HeapFree() on DCDATA 0x%08x failed (%d)",
159 dcdata
, GetLastError() );
162 for (glrc
= OPENGL32_processdata
.glrc_list
; glrc
!= NULL
;)
166 if (!HeapFree( GetProcessHeap(), 0, glrc
))
167 DBGPRINT( "Warning: HeapFree() on GLRC 0x%08x failed (%d)",
168 glrc
, GetLastError() );
171 for (icd
= OPENGL32_processdata
.driver_list
; icd
!= NULL
;)
175 if (!HeapFree( GetProcessHeap(), 0, icd
))
176 DBGPRINT( "Warning: HeapFree() on DRIVERDATA 0x%08x failed (%d)",
177 icd
, GetLastError() );
181 if (OPENGL32_processdata
.driver_mutex
!= NULL
)
182 CloseHandle( OPENGL32_processdata
.driver_mutex
);
183 if (OPENGL32_processdata
.glrc_mutex
!= NULL
)
184 CloseHandle( OPENGL32_processdata
.glrc_mutex
);
185 if (OPENGL32_processdata
.dcdata_mutex
!= NULL
)
186 CloseHandle( OPENGL32_processdata
.dcdata_mutex
);
189 if (OPENGL32_tls
!= 0xffffffff)
190 TlsFree(OPENGL32_tls
);
195 DllMain(HINSTANCE hInstance
, DWORD Reason
, LPVOID Reserved
)
197 DBGPRINT( "Info: Called!" );
200 /* The DLL is loading due to process
201 * initialization or a call to LoadLibrary.
203 case DLL_PROCESS_ATTACH
:
204 DBGTRACE( "Process attach" );
205 if (!OPENGL32_ProcessAttach())
207 /* No break: Initialize the index for first thread. */
209 /* The attached process creates a new thread. */
210 case DLL_THREAD_ATTACH
:
211 DBGTRACE( "Thread attach" );
212 if (!OPENGL32_ThreadAttach())
216 /* The thread of the attached process terminates. */
217 case DLL_THREAD_DETACH
:
218 DBGTRACE( "Thread detach" );
219 /* Release the allocated memory for this thread.*/
220 OPENGL32_ThreadDetach();
223 /* DLL unload due to process termination or FreeLibrary. */
224 case DLL_PROCESS_DETACH
:
225 DBGTRACE( "Process detach" );
226 OPENGL32_ThreadDetach();
227 OPENGL32_ProcessDetach();
235 /*! \brief Append ICD to linked list.
237 * \param icd GLDRIVERDATA to append to list
239 * \note Only call this when you hold the driver_mutex.
242 OPENGL32_AppendICD( GLDRIVERDATA
*icd
)
244 if (OPENGL32_processdata
.driver_list
== NULL
)
245 OPENGL32_processdata
.driver_list
= icd
;
248 GLDRIVERDATA
*p
= OPENGL32_processdata
.driver_list
;
249 while (p
->next
!= NULL
)
256 /*! \brief Remove ICD from linked list.
258 * \param icd GLDRIVERDATA to remove from list
260 * \note Only call this when you hold the driver_mutex.
263 OPENGL32_RemoveICD( GLDRIVERDATA
*icd
)
265 if (icd
== OPENGL32_processdata
.driver_list
)
266 OPENGL32_processdata
.driver_list
= icd
->next
;
269 GLDRIVERDATA
*p
= OPENGL32_processdata
.driver_list
;
279 DBGPRINT( "Error: ICD 0x%08x not found in list!", icd
);
284 /*! \brief Load an ICD.
286 * \param driver Name of installable client driver.
288 * \return Pointer to an allocated GLDRIVERDATA struct.
289 * \retval NULL Failure.
291 * \todo Call SetLastError() where appropriate.
293 static GLDRIVERDATA
*
294 OPENGL32_LoadDriver( LPCWSTR driver
)
299 DBGPRINT( "Info: Loading driver %ws...", driver
);
301 /* allocate driver data */
302 icd
= (GLDRIVERDATA
*)HeapAlloc( GetProcessHeap(),
303 HEAP_GENERATE_EXCEPTIONS
| HEAP_ZERO_MEMORY
,
304 sizeof (GLDRIVERDATA
) );
307 DBGPRINT( "Error: Couldn't allocate GLDRIVERDATA! (%d)", GetLastError() );
311 ret
= OPENGL32_RegGetDriverInfo( driver
, icd
);
312 if (ret
!= ERROR_SUCCESS
)
314 DBGPRINT( "Error: Couldn't query driver information (%d)", ret
);
315 if (!HeapFree( GetProcessHeap(), 0, icd
))
316 DBGPRINT( "Error: HeapFree() returned false, error code = %d",
321 DBGPRINT( "Info: Dll = %ws", icd
->dll
);
322 DBGPRINT( "Info: Version = 0x%08x", icd
->version
);
323 DBGPRINT( "Info: DriverVersion = 0x%08x", icd
->driver_version
);
324 DBGPRINT( "Info: Flags = 0x%08x", icd
->flags
);
326 /* load/initialize ICD */
327 ret
= OPENGL32_InitializeDriver( icd
);
328 if (ret
!= ERROR_SUCCESS
)
330 DBGPRINT( "Error: Couldnt initialize ICD!" );
331 if (!HeapFree( GetProcessHeap(), 0, icd
))
332 DBGPRINT( "Error: HeapFree() returned false, error code = %d",
337 /* append ICD to list */
338 OPENGL32_AppendICD( icd
);
339 DBGPRINT( "Info: ICD loaded." );
345 /*! \brief Initialize a driver (Load DLL and DrvXxx procs)
347 * \param icd ICD to initialize with the dll, version, driverVersion
348 * and flags already filled.
349 * \return Error code.
350 * \retval ERROR_SUCCESS Success
352 #define LOAD_DRV_PROC( icd, proc, required ) \
353 *(char**)&icd->proc = (char*)GetProcAddress( icd->handle, #proc ); \
354 if (required && icd->proc == NULL) { \
355 DBGPRINT( "Error: GetProcAddress(\"%s\") failed!", #proc ); \
356 FreeLibrary( icd->handle ); \
357 return GetLastError(); \
361 OPENGL32_InitializeDriver( GLDRIVERDATA
*icd
)
364 if (icd
->version
> 2)
365 DBGPRINT( "Warning: ICD version > 2 (%d)", icd
->version
);
368 icd
->handle
= LoadLibraryW( icd
->dll
);
369 if (icd
->handle
== NULL
)
371 DWORD err
= GetLastError();
372 DBGPRINT( "Error: Couldn't load DLL! (%d)", err
);
376 /* validate version */
377 if (icd
->driver_version
> 1)
379 LOAD_DRV_PROC(icd
, DrvValidateVersion
, FALSE
);
380 if (icd
->DrvValidateVersion
!= NULL
)
382 if (!icd
->DrvValidateVersion( icd
->driver_version
))
384 DBGPRINT( "Error: DrvValidateVersion failed!" );
386 FreeLibrary( icd
->handle
);
387 return ERROR_INVALID_FUNCTION
; /* FIXME: use better error code */
391 DBGPRINT( "Info: DrvValidateVersion not exported by ICD" );
394 /* load DrvXXX procs */
395 LOAD_DRV_PROC(icd
, DrvCopyContext
, TRUE
);
396 LOAD_DRV_PROC(icd
, DrvCreateContext
, FALSE
);
397 LOAD_DRV_PROC(icd
, DrvCreateLayerContext
, FALSE
);
398 LOAD_DRV_PROC(icd
, DrvDeleteContext
, TRUE
);
399 LOAD_DRV_PROC(icd
, DrvDescribeLayerPlane
, TRUE
);
400 LOAD_DRV_PROC(icd
, DrvDescribePixelFormat
, TRUE
);
401 LOAD_DRV_PROC(icd
, DrvGetLayerPaletteEntries
, TRUE
);
402 LOAD_DRV_PROC(icd
, DrvGetProcAddress
, TRUE
);
403 LOAD_DRV_PROC(icd
, DrvReleaseContext
, TRUE
);
404 LOAD_DRV_PROC(icd
, DrvRealizeLayerPalette
, TRUE
);
405 LOAD_DRV_PROC(icd
, DrvSetContext
, TRUE
);
406 LOAD_DRV_PROC(icd
, DrvSetLayerPaletteEntries
, TRUE
);
407 LOAD_DRV_PROC(icd
, DrvSetPixelFormat
, TRUE
);
408 LOAD_DRV_PROC(icd
, DrvShareLists
, TRUE
);
409 LOAD_DRV_PROC(icd
, DrvSwapBuffers
, TRUE
);
410 LOAD_DRV_PROC(icd
, DrvSwapLayerBuffers
, TRUE
);
412 /* we require at least one of DrvCreateContext and DrvCreateLayerContext */
413 if (icd
->DrvCreateContext
== NULL
&& icd
->DrvCreateLayerContext
== NULL
)
415 DBGPRINT( "Error: One of DrvCreateContext/DrvCreateLayerContext is required!" );
416 FreeLibrary( icd
->handle
);
417 return ERROR_INVALID_FUNCTION
; /* FIXME: use better error code... */
420 return ERROR_SUCCESS
;
424 /*! \brief Unload ICD.
426 * \retval TRUE Success.
427 * \retval FALSE Failure.
430 OPENGL32_UnloadDriver( GLDRIVERDATA
*icd
)
434 DBGPRINT( "Info: Unloading driver %ws...", icd
->driver_name
);
435 if (icd
->refcount
!= 0)
436 DBGPRINT( "Warning: ICD refcount = %d (should be 0)", icd
->refcount
);
439 if (!FreeLibrary( icd
->handle
))
442 DBGPRINT( "Warning: FreeLibrary on ICD %ws failed! (%d)", icd
->dll
,
447 OPENGL32_RemoveICD( icd
);
448 if (!HeapFree( GetProcessHeap(), 0, icd
))
451 DBGPRINT( "Warning: HeapFree() returned FALSE, error code = %d",
459 /*! \brief Load ICD (shared ICD data)
461 * \return Pointer to an allocated GLDRIVERDATA on success.
462 * \retval NULL Failure.
465 OPENGL32_LoadICD( LPCWSTR driver
)
470 if (WaitForSingleObject( OPENGL32_processdata
.driver_mutex
, INFINITE
) ==
473 DBGPRINT( "Error: WaitForSingleObject() failed (%d)", GetLastError() );
474 return NULL
; /* FIXME: do we have to expect such an error and handle it? */
477 /* look if ICD is already loaded */
478 for (icd
= OPENGL32_processdata
.driver_list
; icd
; icd
= icd
->next
)
480 if (!_wcsicmp( driver
, icd
->driver_name
)) /* found */
485 if (!ReleaseMutex( OPENGL32_processdata
.driver_mutex
))
486 DBGPRINT( "Error: ReleaseMutex() failed (%d)", GetLastError() );
492 /* not found - try to load */
493 icd
= OPENGL32_LoadDriver( driver
);
498 if (!ReleaseMutex( OPENGL32_processdata
.driver_mutex
))
499 DBGPRINT( "Error: ReleaseMutex() failed (%d)", GetLastError() );
505 /*! \brief Unload ICD (shared ICD data)
507 * \retval TRUE Success.
508 * \retval FALSE Failure.
511 OPENGL32_UnloadICD( GLDRIVERDATA
*icd
)
516 if (WaitForSingleObject( OPENGL32_processdata
.driver_mutex
, INFINITE
) ==
519 DBGPRINT( "Error: WaitForSingleObject() failed (%d)", GetLastError() );
520 return FALSE
; /* FIXME: do we have to expect such an error and handle it? */
524 if (icd
->refcount
== 0)
526 ret
= OPENGL32_UnloadDriver( icd
);
527 /* FIXME: InitializeICD crashes when called a second time */
530 if (!ReleaseMutex( OPENGL32_processdata
.driver_mutex
))
531 DBGPRINT( "Error: ReleaseMutex() failed (%d)", GetLastError() );
537 /*! \brief Enumerate OpenGLDrivers (from registry)
539 * \param idx Index of the driver to get information about.
540 * \param name Pointer to an array of WCHARs (can be NULL)
541 * \param cName Pointer to a DWORD. Input is len of name array.
542 * Output is length of the drivername.
543 * Can be NULL if name is NULL.
546 * \retval ERROR_NO_MORE_ITEMS End of driver list.
547 * \retval ERROR_SUCCESS Success.
551 OPENGL32_RegEnumDrivers( DWORD idx
, LPWSTR name
, LPDWORD cName
)
554 LPCWSTR subKey
= OPENGL_DRIVERS_SUBKEY
;
560 return ERROR_SUCCESS
; /* nothing to do */
563 return ERROR_INVALID_FUNCTION
; /* we need cName when name is given */
565 /* open OpenGLDrivers registry key */
566 ret
= RegOpenKeyExW( HKEY_LOCAL_MACHINE
, subKey
, 0, KEY_READ
, &hKey
);
567 if (ret
!= ERROR_SUCCESS
)
569 DBGPRINT( "Error: Couldn't open registry key '%ws'", subKey
);
573 /* get subkey name */
574 size
= sizeof (driver
) / sizeof (driver
[0]);
575 ret
= RegEnumKeyW( hKey
, idx
, name
, *cName
);
576 if (ret
!= ERROR_SUCCESS
)
578 DBGPRINT( "Error: Couldn't get OpenGLDrivers subkey name (%d)", ret
);
582 *cName
= wcslen( name
);
586 return ERROR_SUCCESS
;
588 #endif /* 0 -- unused */
591 /*! \brief Get registry values for a driver given a name.
593 * \param driver Name of the driver to get information about.
594 * \param icd Pointer to GLDRIVERDATA.
596 * \return Error code.
597 * \retval ERROR_SUCCESS Success.
599 * \note On success the following fields of \a icd are filled: \a driver_name,
600 * \a dll, \a version, \a driver_version and \a flags.
603 OPENGL32_RegGetDriverInfo( LPCWSTR driver
, GLDRIVERDATA
*icd
)
606 WCHAR subKey
[1024] = OPENGL_DRIVERS_SUBKEY
"\\";
610 /* drivers registry values */
611 DWORD version
= 1, driverVersion
= 0, flags
= 0;
614 /* open driver registry key */
615 wcsncat( subKey
, driver
, 1024 );
616 ret
= RegOpenKeyExW( HKEY_LOCAL_MACHINE
, subKey
, 0, KEY_READ
, &hKey
);
617 if (ret
!= ERROR_SUCCESS
)
619 DBGPRINT( "Error: Couldn't open registry key '%ws'", subKey
);
625 ret
= RegQueryValueExW( hKey
, L
"Dll", 0, &type
, (LPBYTE
)dll
, &size
);
626 if (ret
!= ERROR_SUCCESS
|| type
!= REG_SZ
)
628 DBGPRINT( "Error: Couldn't query Dll value or not a string" );
633 size
= sizeof (DWORD
);
634 ret
= RegQueryValueExW( hKey
, L
"Version", 0, &type
, (LPBYTE
)&version
, &size
);
635 if (ret
!= ERROR_SUCCESS
|| type
!= REG_DWORD
)
636 DBGPRINT( "Warning: Couldn't query Version value or not a DWORD" );
638 size
= sizeof (DWORD
);
639 ret
= RegQueryValueExW( hKey
, L
"DriverVersion", 0, &type
,
640 (LPBYTE
)&driverVersion
, &size
);
641 if (ret
!= ERROR_SUCCESS
|| type
!= REG_DWORD
)
642 DBGPRINT( "Warning: Couldn't query DriverVersion value or not a DWORD" );
644 size
= sizeof (DWORD
);
645 ret
= RegQueryValueExW( hKey
, L
"Flags", 0, &type
, (LPBYTE
)&flags
, &size
);
646 if (ret
!= ERROR_SUCCESS
|| type
!= REG_DWORD
)
647 DBGPRINT( "Warning: Couldn't query Flags value or not a DWORD" );
653 /* FIXME: NUL-terminate strings? */
654 wcsncpy( icd
->driver_name
, driver
,
655 sizeof (icd
->driver_name
) / sizeof (icd
->driver_name
[0]) - 1 );
656 wcsncpy( icd
->dll
, dll
,
657 sizeof (icd
->dll
) / sizeof (icd
->dll
[0]) );
658 icd
->version
= version
;
659 icd
->driver_version
= driverVersion
;
662 return ERROR_SUCCESS
;