2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: lib/opengl32/wgl.c
5 * PURPOSE: OpenGL32 lib, rosglXXX functions
6 * PROGRAMMER: Anich Gregor (blight)
11 #define WIN32_LEAN_AND_MEAN
21 #define UNIMPLEMENTED DBGPRINT( "UNIMPLEMENTED" )
24 /* FUNCTION: Append OpenGL Rendering Context (GLRC) to list
25 * ARGUMENTS: [IN] glrc: GLRC to append to list
29 WGL_AppendContext( GLRC
*glrc
)
32 if (WaitForSingleObject( OPENGL32_processdata
.glrc_mutex
, INFINITE
) ==
35 DBGPRINT( "Error: WaitForSingleObject() failed (%d)", GetLastError() );
36 return; /* FIXME: do we have to expect such an error and handle it? */
39 if (OPENGL32_processdata
.glrc_list
== NULL
)
40 OPENGL32_processdata
.glrc_list
= glrc
;
43 GLRC
*p
= OPENGL32_processdata
.glrc_list
;
44 while (p
->next
!= NULL
)
50 if (!ReleaseMutex( OPENGL32_processdata
.glrc_mutex
))
51 DBGPRINT( "Error: ReleaseMutex() failed (%d)", GetLastError() );
55 /* FUNCTION: Remove OpenGL Rendering Context (GLRC) from list
56 * ARGUMENTS: [IN] glrc: GLRC to remove from list
60 WGL_RemoveContext( GLRC
*glrc
)
63 if (WaitForSingleObject( OPENGL32_processdata
.glrc_mutex
, INFINITE
) ==
66 DBGPRINT( "Error: WaitForSingleObject() failed (%d)", GetLastError() );
67 return; /* FIXME: do we have to expect such an error and handle it? */
70 if (glrc
== OPENGL32_processdata
.glrc_list
)
71 OPENGL32_processdata
.glrc_list
= glrc
->next
;
74 GLRC
*p
= OPENGL32_processdata
.glrc_list
;
84 DBGPRINT( "Error: GLRC 0x%08x not found in list!", glrc
);
88 if (!ReleaseMutex( OPENGL32_processdata
.glrc_mutex
))
89 DBGPRINT( "Error: ReleaseMutex() failed (%d)", GetLastError() );
92 /* FUNCTION: Check wether a GLRC is in the list
93 * ARGUMENTS: [IN] glrc: GLRC to remove from list
97 WGL_ContainsContext( GLRC
*glrc
)
102 if (WaitForSingleObject( OPENGL32_processdata
.glrc_mutex
, INFINITE
) ==
105 DBGPRINT( "Error: WaitForSingleObject() failed (%d)", GetLastError() );
106 return FALSE
; /* FIXME: do we have to expect such an error and handle it? */
109 p
= OPENGL32_processdata
.glrc_list
;
118 if (!ReleaseMutex( OPENGL32_processdata
.glrc_mutex
))
119 DBGPRINT( "Error: ReleaseMutex() failed (%d)", GetLastError() );
125 /* FUNCTION: SetContextCallBack passed to DrvSetContext. Gets called whenever
126 * the current GL context (dispatch table) is to be changed - can
127 * be multiple times for one DrvSetContext call.
128 * ARGUMENTS: [IN] table Function pointer table (first DWORD is number of
134 WGL_SetContextCallBack( const ICDTable
*table
)
138 PROC
*tebTable
, *tebDispatchTable
;
140 teb
= NtCurrentTeb();
141 tebTable
= (PROC
*)teb
->glTable
;
142 tebDispatchTable
= (PROC
*)teb
->glDispatchTable
;
144 DBGPRINT( "Function count: %d\n", table
->num_funcs
);
147 memcpy( tebTable
, table
->dispatch_table
,
148 sizeof (PROC
) * table
->num_funcs
);
149 memset( tebTable
+ sizeof (PROC
) * table
->num_funcs
, 0,
150 (sizeof (table
->dispatch_table
) / sizeof (PROC
)) -
151 (sizeof (PROC
) * table
->num_funcs
) );
153 /* FIXME: pull in software fallbacks -- need mesa */
154 #if 0 /* unused atm */
155 for (i
= 0; i
< (sizeof (table
->dispatch_table
) / sizeof (PROC
)); i
++)
157 if (tebTable
[i
] == NULL
)
159 /* FIXME: fallback */
160 DBGPRINT( "Warning: GL proc #%d is NULL!", i
);
165 /* put in empty functions as long as we dont have a fallback */
166 #define X(func, ret, typeargs, args, icdidx, tebidx, stack) \
167 if (tebTable[icdidx] == NULL) \
169 DBGPRINT( "Warning: GL proc '%s' is NULL", #func ); \
170 tebTable[icdidx] = (PROC)glEmptyFunc##stack; \
175 /* fill teb->glDispatchTable for fast calls */
176 #define X(func, ret, typeargs, args, icdidx, tebidx, stack) \
178 tebDispatchTable[tebidx] = tebTable[icdidx];
182 return ERROR_SUCCESS
;
186 /* FUNCTION: Attempts to find the best matching pixel format for HDC
187 * ARGUMENTS: [IN] pdf PFD describing what kind of format you want
188 * RETURNS: one-based positive format index on success, 0 on failure
190 #define BUFFERDEPTH_SCORE(want, have) \
191 ((want == 0) ? (0) : ((want < have) ? (1) : ((want > have) ? (3) : (0))))
194 rosglChoosePixelFormat( HDC hdc
, CONST PIXELFORMATDESCRIPTOR
*pfd
)
197 PIXELFORMATDESCRIPTOR icdPfd
;
200 int score
, bestScore
= 0x7fff; /* used to choose a pfd if no exact match */
202 const DWORD compareFlags
= PFD_DRAW_TO_WINDOW
| PFD_DRAW_TO_BITMAP
|
203 PFD_SUPPORT_GDI
| PFD_SUPPORT_OPENGL
;
206 icd
= OPENGL32_LoadICDForHDC( hdc
);
211 if (pfd
->nSize
!= sizeof (PIXELFORMATDESCRIPTOR
) || pfd
->nVersion
!= 1)
213 SetLastError( 0 ); /* FIXME: use appropriate errorcode */
217 /* get number of formats -- FIXME: use 1 or 0 as index? */
218 icdNumFormats
= icd
->DrvDescribePixelFormat( hdc
, 1,
219 sizeof (PIXELFORMATDESCRIPTOR
), NULL
);
220 if (icdNumFormats
== 0)
222 DBGPRINT( "DrvDescribePixelFormat failed (%d)", GetLastError() );
226 /* try to find best format */
227 for (i
= 0; i
< icdNumFormats
; i
++)
229 if (icd
->DrvDescribePixelFormat( hdc
, i
+ 1,
230 sizeof (PIXELFORMATDESCRIPTOR
), &icdPfd
) == 0)
232 DBGPRINT( "Warning: DrvDescribePixelFormat failed (%d)",
238 if ((pfd
->dwFlags
& compareFlags
) != (icdPfd
.dwFlags
& compareFlags
))
240 if (!(pfd
->dwFlags
& PFD_DOUBLEBUFFER_DONTCARE
) &&
241 ((pfd
->dwFlags
& PFD_DOUBLEBUFFER
) != (icdPfd
.dwFlags
& PFD_DOUBLEBUFFER
)))
243 if (!(pfd
->dwFlags
& PFD_STEREO_DONTCARE
) &&
244 ((pfd
->dwFlags
& PFD_STEREO
) != (icdPfd
.dwFlags
& PFD_STEREO
)))
247 /* check other attribs */
248 score
= 0; /* higher is worse */
249 if (pfd
->iPixelType
!= icdPfd
.iPixelType
)
250 score
+= 5; /* this is really bad i think */
251 if (pfd
->iLayerType
!= icdPfd
.iLayerType
)
252 score
+= 15; /* this is very very bad ;) */
254 score
+= BUFFERDEPTH_SCORE(pfd
->cAlphaBits
, icdPfd
.cAlphaBits
);
255 score
+= BUFFERDEPTH_SCORE(pfd
->cAccumBits
, icdPfd
.cAccumBits
);
256 score
+= BUFFERDEPTH_SCORE(pfd
->cDepthBits
, icdPfd
.cDepthBits
);
257 score
+= BUFFERDEPTH_SCORE(pfd
->cStencilBits
, icdPfd
.cStencilBits
);
258 score
+= BUFFERDEPTH_SCORE(pfd
->cAuxBuffers
, icdPfd
.cAuxBuffers
);
261 if (score
< bestScore
)
272 SetLastError( 0 ); /* FIXME: set appropriate error */
280 /* FUNCTION: Copy data specified by mask from one GLRC to another.
281 * ARGUMENTS: [IN] src Source GLRC
282 * [OUT] dst Destination GLRC
283 * [IN] mask Bitfield like given to glPushAttrib()
284 * RETURN: TRUE on success, FALSE on failure
288 rosglCopyContext( HGLRC hsrc
, HGLRC hdst
, UINT mask
)
290 GLRC
*src
= (GLRC
*)hsrc
;
291 GLRC
*dst
= (GLRC
*)hdst
;
294 if (!WGL_ContainsContext( src
))
296 DBGPRINT( "Error: src GLRC not found!" );
297 return FALSE
; /* FIXME: SetLastError() */
299 if (!WGL_ContainsContext( dst
))
301 DBGPRINT( "Error: dst GLRC not found!" );
302 return FALSE
; /* FIXME: SetLastError() */
305 /* I think this is only possible within one ICD */
306 if (src
->icd
!= src
->icd
)
308 DBGPRINT( "Error: src and dst GLRC use different ICDs!" );
312 /* copy data (call ICD) */
313 return src
->icd
->DrvCopyContext( src
->hglrc
, dst
->hglrc
, mask
);
317 /* FUNCTION: Create a new GL Rendering Context for the given plane on
319 * ARGUMENTS: [IN] hdc Handle for DC for which to create context
320 * [IN] layer Layer number to bind (draw?) to
321 * RETURNS: NULL on failure, new GLRC on success
325 rosglCreateLayerContext( HDC hdc
, int layer
)
331 GLDRIVERDATA
*icd
= NULL
;
333 HGLRC drvHglrc
= NULL
;
335 /* if (GetObjectType( hdc ) != OBJ_DC)
337 DBGPRINT( "Error: hdc is not a DC handle!" );
341 /* allocate our GLRC */
342 glrc
= (GLRC
*)HeapAlloc( GetProcessHeap(),
343 HEAP_ZERO_MEMORY
| HEAP_GENERATE_EXCEPTIONS
, sizeof (GLRC
) );
348 /* try to find an ICD */
349 for (dw
= 0; drvHglrc
== NULL
; dw
++) /* enumerate values */
351 size
= sizeof (driver
) / sizeof (driver
[0]);
352 ret
= OPENGL32_RegEnumDrivers( dw
, driver
, &size
);
353 if (ret
!= ERROR_SUCCESS
)
356 icd
= OPENGL32_LoadICD( driver
);
357 if (icd
== NULL
) /* try next ICD */
360 if (icd
->DrvCreateLayerContext
)
361 drvHglrc
= icd
->DrvCreateLayerContext( hdc
, layer
);
362 if (drvHglrc
== NULL
)
365 drvHglrc
= icd
->DrvCreateContext( hdc
);
367 DBGPRINT( "Warning: CreateLayerContext not supported by ICD!" );
369 if (drvHglrc
== NULL
) /* try next ICD */
371 DBGPRINT( "Info: DrvCreateContext (driver = %ws) failed: %d",
372 icd
->driver_name
, GetLastError() );
373 OPENGL32_UnloadICD( icd
);
377 /* the ICD was loaded successfully and we got a HGLRC in drvHglrc */
381 if (drvHglrc
== NULL
|| icd
== NULL
) /* no ICD was found */
383 /* FIXME: fallback to mesa */
384 DBGPRINT( "Error: No working ICD found!" );
385 HeapFree( GetProcessHeap(), 0, glrc
);
391 icd
= OPENGL32_LoadICDForHDC( hdc
);
394 DBGPRINT( "Couldn't get ICD by HDC :-(" );
395 /* FIXME: fallback? */
400 if (icd
->DrvCreateLayerContext
!= NULL
)
401 drvHglrc
= icd
->DrvCreateLayerContext( hdc
, layer
);
402 if (drvHglrc
== NULL
)
404 if (layer
== 0 && icd
->DrvCreateContext
!= NULL
)
405 drvHglrc
= icd
->DrvCreateContext( hdc
);
407 DBGPRINT( "Warning: CreateLayerContext not supported by ICD!" );
410 if (drvHglrc
== NULL
)
412 /* FIXME: fallback to mesa? */
413 DBGPRINT( "Error: DrvCreate[Layer]Context failed! (%d)", GetLastError() );
414 OPENGL32_UnloadICD( icd
);
415 HeapFree( GetProcessHeap(), 0, glrc
);
419 /* we have our GLRC in glrc and the ICD's GLRC in drvHglrc */
420 glrc
->hglrc
= drvHglrc
;
423 /* append glrc to context list */
424 WGL_AppendContext( glrc
);
430 /* FUNCTION: Create a new GL Rendering Context for the given DC.
431 * ARGUMENTS: [IN] hdc Handle for DC for which to create context
432 * RETURNS: NULL on failure, new GLRC on success
436 rosglCreateContext( HDC hdc
)
438 return rosglCreateLayerContext( hdc
, 0 );
442 /* FUNCTION: Delete an OpenGL context
443 * ARGUMENTS: [IN] hglrc Handle to GLRC to delete; must not be a threads RC!
444 * RETURNS: TRUE on success, FALSE otherwise
448 rosglDeleteContext( HGLRC hglrc
)
450 GLRC
*glrc
= (GLRC
*)hglrc
;
452 /* check if we know about this context */
453 if (!WGL_ContainsContext( glrc
))
455 DBGPRINT( "Error: hglrc not found!" );
456 return FALSE
; /* FIXME: SetLastError() */
459 /* make sure GLRC is not current for some thread */
460 if (glrc
->is_current
)
462 DBGPRINT( "Error: GLRC is current for DC 0x%08x", glrc
->hdc
);
463 return FALSE
; /* FIXME: SetLastError() */
466 /* release ICD's context */
467 if (glrc
->hglrc
!= NULL
)
469 if (!glrc
->icd
->DrvDeleteContext( glrc
->hglrc
))
471 DBGPRINT( "Warning: DrvDeleteContext() failed (%d)", GetLastError() );
477 OPENGL32_UnloadICD( glrc
->icd
);
478 WGL_RemoveContext( glrc
);
479 HeapFree( GetProcessHeap(), 0, glrc
);
487 rosglDescribeLayerPlane( HDC hdc
, int iPixelFormat
, int iLayerPlane
,
488 UINT nBytes
, LPLAYERPLANEDESCRIPTOR plpd
)
497 rosglDescribePixelFormat( HDC hdc
, int iFormat
, UINT nBytes
,
498 LPPIXELFORMATDESCRIPTOR pfd
)
501 GLDRIVERDATA
*icd
= OPENGL32_LoadICDForHDC( hdc
);
505 ret
= icd
->DrvDescribePixelFormat( hdc
, iFormat
, nBytes
, pfd
);
507 DBGPRINT( "Error: DrvDescribePixelFormat failed (%d)", GetLastError() );
510 /* FIXME: implement own functionality? */
515 /* FUNCTION: Return the current GLRC
516 * RETURNS: Current GLRC (NULL if none was set current)
520 rosglGetCurrentContext()
522 return (HGLRC
)(OPENGL32_threaddata
->glrc
);
526 /* FUNCTION: Return the current DC
527 * RETURNS: NULL on failure, current DC otherwise
533 /* FIXME: is it correct to return NULL when there is no current GLRC or
534 is there another way to find out the wanted HDC? */
535 if (OPENGL32_threaddata
->glrc
== NULL
)
537 return (HDC
)(OPENGL32_threaddata
->glrc
->hdc
);
543 rosglGetLayerPaletteEntries( HDC hdc
, int iLayerPlane
, int iStart
,
544 int cEntries
, COLORREF
*pcr
)
553 rosglGetPixelFormat( HDC hdc
)
555 if (OPENGL32_processdata
.cachedHdc
== hdc
)
556 return OPENGL32_processdata
.cachedFormat
;
558 /* FIXME: create real implementation of this function */
559 DBGPRINT( "Warning: Pixel format not cached, returning 0" );
565 /* FUNCTION: Get the address for an OpenGL extension function from the current ICD.
566 * ARGUMENTS: [IN] proc: Name of the function to look for
567 * RETURNS: The address of the proc or NULL on failure.
571 rosglGetProcAddress( LPCSTR proc
)
573 if (OPENGL32_threaddata
->glrc
== NULL
)
575 DBGPRINT( "Error: No current GLRC!" );
579 if (proc
[0] == 'g' && proc
[1] == 'l') /* glXXX */
581 PROC glXXX
= OPENGL32_threaddata
->glrc
->icd
->DrvGetProcAddress( proc
);
584 DBGPRINT( "Info: Proc \"%s\" loaded from ICD.", proc
);
588 /* FIXME: go through own functions? */
589 DBGPRINT( "Warning: Unsupported GL extension: %s", proc
);
591 if (proc
[0] == 'w' && proc
[1] == 'g' && proc
[2] == 'l') /* wglXXX */
593 /* FIXME: support wgl extensions? (there are such IIRC) */
594 DBGPRINT( "Warning: Unsupported WGL extension: %s", proc
);
596 if (proc
[0] == 'g' && proc
[1] == 'l' && proc
[2] == 'u') /* gluXXX */
598 /* FIXME: do we support these as well? */
599 DBGPRINT( "Warning: GLU extension %s requested, returning NULL", proc
);
606 /* FUNCTION: make the given GLRC the threads current GLRC for hdc
607 * ARGUMENTS: [IN] hdc Handle for a DC to be drawn on
608 * [IN] hglrc Handle for a GLRC to make current
609 * RETURNS: TRUE on success, FALSE otherwise
613 rosglMakeCurrent( HDC hdc
, HGLRC hglrc
)
615 GLRC
*glrc
= (GLRC
*)hglrc
;
617 /* flush current context */
618 if (OPENGL32_threaddata
->glrc
!= NULL
)
624 if (GetObjectType( hdc
) != OBJ_DC
)
626 DBGPRINT( "Error: hdc is not a DC handle!" );
630 /* check if we know about this glrc */
631 if (!WGL_ContainsContext( glrc
))
633 DBGPRINT( "Error: hglrc not found!" );
634 return FALSE
; /* FIXME: SetLastError() */
637 /* check if it is available */
638 if (glrc
->is_current
) /* used by another thread */
640 DBGPRINT( "Error: hglrc is current for thread 0x%08x", glrc
->thread_id
);
641 return FALSE
; /* FIXME: SetLastError() */
645 if (glrc
->hglrc
!= NULL
)
647 if (!glrc
->icd
->DrvSetContext( hdc
, glrc
->hglrc
,
648 WGL_SetContextCallBack
))
650 DBGPRINT( "Error: DrvSetContext failed (%d)\n", GetLastError() );
653 DBGPRINT( "Info: DrvSetContext succeeded!" );
656 /* make it current */
657 if (OPENGL32_threaddata
->glrc
!= NULL
)
658 OPENGL32_threaddata
->glrc
->is_current
= FALSE
;
659 glrc
->is_current
= TRUE
;
660 glrc
->thread_id
= GetCurrentThreadId();
662 OPENGL32_threaddata
->glrc
= glrc
;
670 rosglRealizeLayerPalette( HDC hdc
, int iLayerPlane
, BOOL bRealize
)
679 rosglSetLayerPaletteEntries( HDC hdc
, int iLayerPlane
, int iStart
,
680 int cEntries
, CONST COLORREF
*pcr
)
689 rosglSetPixelFormat( HDC hdc
, int iFormat
, CONST PIXELFORMATDESCRIPTOR
*pfd
)
693 icd
= OPENGL32_LoadICDForHDC( hdc
);
697 if (!icd
->DrvSetPixelFormat( hdc
, iFormat
, pfd
))
699 DBGPRINT( "Warning: DrvSetPixelFormat failed (%d)", GetLastError() );
703 OPENGL32_processdata
.cachedHdc
= hdc
;
704 OPENGL32_processdata
.cachedFormat
= iFormat
;
710 /* FUNCTION: Enable display-list sharing between multiple GLRCs
711 * ARGUMENTS: [IN] hglrc1 GLRC number 1
712 * [IN] hglrc2 GLRC number 2
713 * RETURNS: TRUR on success, FALSE on failure
717 rosglShareLists( HGLRC hglrc1
, HGLRC hglrc2
)
719 GLRC
*glrc1
= (GLRC
*)hglrc1
;
720 GLRC
*glrc2
= (GLRC
*)hglrc2
;
723 if (!WGL_ContainsContext( glrc1
))
725 DBGPRINT( "Error: hglrc1 not found!" );
726 return FALSE
; /* FIXME: SetLastError() */
728 if (!WGL_ContainsContext( glrc2
))
730 DBGPRINT( "Error: hglrc2 not found!" );
731 return FALSE
; /* FIXME: SetLastError() */
734 /* I think this is only possible within one ICD */
735 if (glrc1
->icd
!= glrc2
->icd
)
737 DBGPRINT( "Error: hglrc1 and hglrc2 use different ICDs!" );
741 /* share lists (call ICD) */
742 return glrc1
->icd
->DrvShareLists( glrc1
->hglrc
, glrc2
->hglrc
);
746 /* FUNCTION: Flushes GL and swaps front/back buffer if appropriate
747 * ARGUMENTS: [IN] hdc Handle to device context to swap buffers for
748 * RETURNS: TRUE on success, FALSE on failure
752 rosglSwapBuffers( HDC hdc
)
755 /* check if there is a current GLRC */
756 if (OPENGL32_threaddata
->glrc
== NULL
)
758 DBGPRINT( "Error: No current GL context!" );
762 /* ask ICD to swap buffers */
763 /* FIXME: also ask ICD when we didnt use it to create the context/it couldnt? */
764 if (OPENGL32_threaddata
->glrc
->hglrc
!= NULL
)
766 if (!OPENGL32_threaddata
->glrc
->icd
->DrvSwapBuffers( hdc
))
768 DBGPRINT( "Error: DrvSwapBuffers failed (%d)", GetLastError() );
775 GLDRIVERDATA
*icd
= OPENGL32_LoadICDForHDC( hdc
);
778 if (!icd
->DrvSwapBuffers( hdc
))
780 DBGPRINT( "Error: DrvSwapBuffers failed (%d)", GetLastError() );
786 /* FIXME: implement own functionality? */
793 rosglSwapLayerBuffers( HDC hdc
, UINT fuPlanes
)
802 rosglUseFontBitmapsA( HDC hdc
, DWORD first
, DWORD count
, DWORD listBase
)
811 rosglUseFontBitmapsW( HDC hdc
, DWORD first
, DWORD count
, DWORD listBase
)
820 rosglUseFontOutlinesA( HDC hdc
, DWORD first
, DWORD count
, DWORD listBase
,
821 FLOAT deviation
, FLOAT extrusion
, int format
,
822 LPGLYPHMETRICSFLOAT lpgmf
)
831 rosglUseFontOutlinesW( HDC hdc
, DWORD first
, DWORD count
, DWORD listBase
,
832 FLOAT deviation
, FLOAT extrusion
, int format
,
833 LPGLYPHMETRICSFLOAT lpgmf
)