[KS]
[reactos.git] / reactos / dll / win32 / opengl32 / wgl.c
1 /*
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)
7 * UPDATE HISTORY:
8 * Feb 2, 2004: Created
9 */
10
11 #define OPENGL32_GL_FUNC_PROTOTYPES
12 #include "opengl32.h"
13
14 #ifdef __cplusplus
15 extern "C" {
16 #endif /* __cplusplus */
17
18 #if !defined(UNIMPLEMENTED)
19 # define UNIMPLEMENTED DBGPRINT( "UNIMPLEMENTED" )
20 #endif
21
22
23 typedef struct _OPENGL_INFO
24 {
25 DWORD Version; /*!< Driver interface version */
26 DWORD DriverVersion; /*!< Driver version */
27 WCHAR DriverName[256]; /*!< Driver name */
28 } OPENGL_INFO, *POPENGL_INFO;
29
30 /*! \brief Append OpenGL Rendering Context (GLRC) to list
31 *
32 * \param glrc [IN] Pointer to GLRC to append to list
33 */
34 static
35 void
36 ROSGL_AppendContext( GLRC *glrc )
37 {
38 /* synchronize */
39 if (WaitForSingleObject( OPENGL32_processdata.glrc_mutex, INFINITE ) ==
40 WAIT_FAILED)
41 {
42 DBGPRINT( "Error: WaitForSingleObject() failed (%d)", GetLastError() );
43 return; /* FIXME: do we have to expect such an error and handle it? */
44 }
45
46 if (OPENGL32_processdata.glrc_list == NULL)
47 OPENGL32_processdata.glrc_list = glrc;
48 else
49 {
50 GLRC *p = OPENGL32_processdata.glrc_list;
51 while (p->next != NULL)
52 p = p->next;
53 p->next = glrc;
54 }
55
56 /* release mutex */
57 if (!ReleaseMutex( OPENGL32_processdata.glrc_mutex ))
58 DBGPRINT( "Error: ReleaseMutex() failed (%d)", GetLastError() );
59 }
60
61
62 /*! \brief Remove OpenGL Rendering Context (GLRC) from list
63 *
64 * \param glrc [IN] Pointer to GLRC to remove from list
65 */
66 static
67 void
68 ROSGL_RemoveContext( GLRC *glrc )
69 {
70 /* synchronize */
71 if (WaitForSingleObject( OPENGL32_processdata.glrc_mutex, INFINITE ) ==
72 WAIT_FAILED)
73 {
74 DBGPRINT( "Error: WaitForSingleObject() failed (%d)", GetLastError() );
75 return; /* FIXME: do we have to expect such an error and handle it? */
76 }
77
78 if (glrc == OPENGL32_processdata.glrc_list)
79 OPENGL32_processdata.glrc_list = glrc->next;
80 else
81 {
82 GLRC *p = OPENGL32_processdata.glrc_list;
83 while (p != NULL)
84 {
85 if (p->next == glrc)
86 {
87 p->next = glrc->next;
88 break;
89 }
90 p = p->next;
91 }
92 if (p == NULL)
93 DBGPRINT( "Error: GLRC 0x%08x not found in list!", glrc );
94 }
95
96 /* release mutex */
97 if (!ReleaseMutex( OPENGL32_processdata.glrc_mutex ))
98 DBGPRINT( "Error: ReleaseMutex() failed (%d)", GetLastError() );
99 }
100
101
102 /*! \brief Create a new GL Context (GLRC) and append it to the list
103 *
104 * \return Pointer to new GLRC on success
105 * \retval NULL Returned on failure (i.e. Out of memory)
106 */
107 static
108 GLRC *
109 ROSGL_NewContext(void)
110 {
111 GLRC *glrc;
112
113 /* allocate GLRC */
114 glrc = (GLRC*)HeapAlloc( GetProcessHeap(),
115 HEAP_ZERO_MEMORY | HEAP_GENERATE_EXCEPTIONS, sizeof (GLRC) );
116
117 /* append to list */
118 ROSGL_AppendContext( glrc );
119
120 return glrc;
121 }
122
123 /*! \brief Delete all GLDCDATA with this IDC
124 *
125 * \param icd [IN] Pointer to a ICD
126 */
127 static
128 VOID
129 ROSGL_DeleteDCDataForICD( GLDRIVERDATA *icd )
130 {
131 GLDCDATA *p, **pptr;
132
133 /* synchronize */
134 if (WaitForSingleObject( OPENGL32_processdata.dcdata_mutex, INFINITE ) ==
135 WAIT_FAILED)
136 {
137 DBGPRINT( "Error: WaitForSingleObject() failed (%d)", GetLastError() );
138 return;
139 }
140
141 p = OPENGL32_processdata.dcdata_list;
142 pptr = &OPENGL32_processdata.dcdata_list;
143 while (p != NULL)
144 {
145 if (p->icd == icd)
146 {
147 *pptr = p->next;
148 OPENGL32_UnloadICD( p->icd );
149
150 if (!HeapFree( GetProcessHeap(), 0, p ))
151 DBGPRINT( "Warning: HeapFree() on GLDCDATA failed (%d)",
152 GetLastError() );
153
154 p = *pptr;
155 }
156 else
157 {
158 pptr = &p->next;
159 p = p->next;
160 }
161 }
162
163 /* release mutex */
164 if (!ReleaseMutex( OPENGL32_processdata.dcdata_mutex ))
165 DBGPRINT( "Error: ReleaseMutex() failed (%d)", GetLastError() );
166 }
167
168
169 /*! \brief Delete a GL Context (GLRC) and remove it from the list
170 *
171 * \param glrc [IN] Pointer to GLRC to delete
172 *
173 * \retval TRUE Success
174 * \retval FALSE Failure
175 */
176 static
177 BOOL
178 ROSGL_DeleteContext( GLRC *glrc )
179 {
180 /* unload icd */
181 if ((glrc->icd != NULL) && (!InterlockedDecrement((LONG*)&glrc->icd->refcount)))
182 {
183 /* This is the last context, remove the ICD*/
184 ROSGL_DeleteDCDataForICD( glrc->icd );
185 }
186
187 /* remove from list */
188 ROSGL_RemoveContext( glrc );
189
190 /* free memory */
191 HeapFree( GetProcessHeap(), 0, glrc );
192
193 return TRUE;
194 }
195
196
197 /*! \brief Check wether a GLRC is in the list
198 *
199 * \param glrc [IN] Pointer to GLRC to look for in the list
200 *
201 * \retval TRUE GLRC was found
202 * \retval FALSE GLRC was not found
203 */
204 static
205 BOOL
206 ROSGL_ContainsContext( GLRC *glrc )
207 {
208 GLRC *p;
209 BOOL found = FALSE;
210
211 /* synchronize */
212 if (WaitForSingleObject( OPENGL32_processdata.glrc_mutex, INFINITE ) ==
213 WAIT_FAILED)
214 {
215 DBGPRINT( "Error: WaitForSingleObject() failed (%d)", GetLastError() );
216 return FALSE; /* FIXME: do we have to expect such an error and handle it? */
217 }
218
219 p = OPENGL32_processdata.glrc_list;
220 while (p != NULL)
221 {
222 if (p == glrc)
223 {
224 found = TRUE;
225 break;
226 }
227 p = p->next;
228 }
229
230 /* release mutex */
231 if (!ReleaseMutex( OPENGL32_processdata.glrc_mutex ))
232 DBGPRINT( "Error: ReleaseMutex() failed (%d)", GetLastError() );
233
234 return found;
235 }
236
237
238 /*! \brief Get GL private DC data.
239 *
240 * This function adds an empty GLDCDATA to the list if there is no data for the
241 * given DC yet.
242 *
243 * \param hdc [IN] Handle to a Device Context for which to get the data
244 *
245 * \return Pointer to GLDCDATA on success
246 * \retval NULL on failure
247 */
248 static
249 GLDCDATA *
250 ROSGL_GetPrivateDCData( HDC hdc )
251 {
252 GLDCDATA *data;
253
254 /* check hdc */
255 if (GetObjectType( hdc ) != OBJ_DC && GetObjectType( hdc ) != OBJ_MEMDC)
256 {
257 DBGPRINT( "Error: hdc is not a DC handle!" );
258 SetLastError( ERROR_INVALID_HANDLE );
259 return FALSE;
260 }
261
262 /* synchronize */
263 if (WaitForSingleObject( OPENGL32_processdata.dcdata_mutex, INFINITE ) ==
264 WAIT_FAILED)
265 {
266 DBGPRINT( "Error: WaitForSingleObject() failed (%d)", GetLastError() );
267 return NULL; /* FIXME: do we have to expect such an error and handle it? */
268 }
269
270 /* look for data in list */
271 data = OPENGL32_processdata.dcdata_list;
272 while (data != NULL)
273 {
274 if (data->hdc == hdc) /* found */
275 break;
276 data = data->next;
277 }
278
279 /* allocate new data if not found in list */
280 if (data == NULL)
281 {
282 data = HeapAlloc( GetProcessHeap(),
283 HEAP_ZERO_MEMORY | HEAP_GENERATE_EXCEPTIONS,
284 sizeof (GLDCDATA) );
285 if (data == NULL)
286 {
287 DBGPRINT( "Error: HeapAlloc() failed (%d)", GetLastError() );
288 }
289 else
290 {
291 data->hdc = hdc;
292
293 /* append data to list */
294 if (OPENGL32_processdata.dcdata_list == NULL)
295 OPENGL32_processdata.dcdata_list = data;
296 else
297 {
298 GLDCDATA *p = OPENGL32_processdata.dcdata_list;
299 while (p->next != NULL)
300 p = p->next;
301 p->next = data;
302 }
303 }
304 }
305
306 /* release mutex */
307 if (!ReleaseMutex( OPENGL32_processdata.dcdata_mutex ))
308 DBGPRINT( "Error: ReleaseMutex() failed (%d)", GetLastError() );
309
310 return data;
311 }
312
313
314 /*! \brief Get ICD from HDC.
315 *
316 * This function asks the display driver which OpenGL ICD to load for the given
317 * HDC, loads it and returns a pointer to a GLDRIVERDATA struct on success.
318 *
319 * \param hdc [IN] Handle for DC for which to load/get the ICD
320 *
321 * \return Pointer to GLDRIVERDATA
322 * \retval NULL Failure.
323 */
324 static
325 GLDRIVERDATA *
326 ROSGL_ICDForHDC( HDC hdc )
327 {
328 GLDCDATA *dcdata;
329 GLDRIVERDATA *drvdata;
330
331 dcdata = ROSGL_GetPrivateDCData( hdc );
332 if (dcdata == NULL)
333 return NULL;
334
335 if (dcdata->icd == NULL)
336 {
337 LPCWSTR driverName;
338 OPENGL_INFO info;
339
340 /* NOTE: This might be done by multiple threads simultaneously, but only the fastest
341 actually gets to set the ICD! */
342
343 driverName = _wgetenv( L"OPENGL32_DRIVER" );
344 if (driverName == NULL)
345 {
346 DWORD dwInput;
347 LONG ret;
348
349 /* get driver name */
350 dwInput = OPENGL_GETINFO;
351 ret = ExtEscape( hdc, QUERYESCSUPPORT, sizeof (dwInput), (LPCSTR)&dwInput, 0, NULL );
352 if (ret > 0)
353 {
354 dwInput = 0;
355 ret = ExtEscape( hdc, OPENGL_GETINFO, sizeof (dwInput),
356 (LPCSTR)&dwInput, sizeof (OPENGL_INFO),
357 (LPSTR)&info );
358 }
359 if (ret <= 0)
360 {
361 HKEY hKey;
362 DWORD type, size;
363
364 if (ret < 0)
365 {
366 DBGPRINT( "Warning: ExtEscape to get the drivername failed! (%d)", GetLastError() );
367 if (MessageBox( WindowFromDC( hdc ), L"Couldn't get installable client driver name!\nUsing default driver.",
368 L"OPENGL32.dll: Warning", MB_OKCANCEL | MB_ICONWARNING ) == IDCANCEL)
369 {
370 return NULL;
371 }
372 }
373
374 /* open registry key */
375 ret = RegOpenKeyExW( HKEY_LOCAL_MACHINE, OPENGL_DRIVERS_SUBKEY, 0, KEY_QUERY_VALUE, &hKey );
376 if (ret != ERROR_SUCCESS)
377 {
378 DBGPRINT( "Error: Couldn't open registry key '%ws'", OPENGL_DRIVERS_SUBKEY );
379 SetLastError( ret );
380 return NULL;
381 }
382
383 /* query value */
384 size = sizeof (info.DriverName);
385 ret = RegQueryValueExW( hKey, L"DefaultDriver", 0, &type, (LPBYTE)info.DriverName, &size );
386 RegCloseKey( hKey );
387 if (ret != ERROR_SUCCESS || type != REG_SZ)
388 {
389 DBGPRINT( "Error: Couldn't query DefaultDriver value or not a string" );
390 SetLastError( ret );
391 return NULL;
392 }
393 }
394 }
395 else
396 {
397 wcsncpy( info.DriverName, driverName, sizeof (info.DriverName) / sizeof (info.DriverName[0]) );
398 }
399 /* load driver (or get a reference) */
400 drvdata = OPENGL32_LoadICD( info.DriverName );
401 if (drvdata == NULL)
402 {
403 WCHAR Buffer[256];
404 snwprintf(Buffer, sizeof(Buffer)/sizeof(WCHAR),
405 L"Couldn't load driver \"%s\".", info.DriverName);
406 MessageBox(WindowFromDC( hdc ), Buffer,
407 L"OPENGL32.dll: Warning",
408 MB_OK | MB_ICONWARNING);
409 }
410 else
411 {
412 /* Atomically set the ICD!!! */
413 if (InterlockedCompareExchangePointer((PVOID*)&dcdata->icd,
414 (PVOID)drvdata,
415 NULL) != NULL)
416 {
417 /* Too bad, somebody else was faster... */
418 DBGTRACE("ICD is already set!\n");
419 }
420 }
421 }
422
423 return dcdata->icd;
424 }
425
426
427 /*! \brief SetContextCallBack passed to DrvSetContext.
428 *
429 * This function gets called by the OpenGL driver whenever the current GL
430 * context (dispatch table) is to be changed.
431 *
432 * \param table [IN] Function pointer table (first DWORD is number of functions)
433 *
434 * \return unkown (maybe void? ERROR_SUCCESS at the moment)
435 */
436 DWORD
437 CALLBACK
438 ROSGL_SetContextCallBack( const ICDTable *table )
439 {
440 TEB *teb;
441 PROC *tebTable, *tebDispatchTable;
442 INT size;
443
444 teb = NtCurrentTeb();
445 tebTable = (PROC *)teb->glTable;
446 tebDispatchTable = (PROC *)teb->glDispatchTable;
447
448 DBGTRACE( "Called!" );
449
450 if (table != NULL)
451 {
452 DBGPRINT( "Function count: %d\n", table->num_funcs );
453
454 /* save table */
455 size = sizeof (PROC) * table->num_funcs;
456 memcpy( tebTable, table->dispatch_table, size );
457 memset( tebTable + table->num_funcs, 0,
458 sizeof (table->dispatch_table) - size );
459 }
460 else
461 {
462 DBGPRINT( "Unsetting current context" );
463 memset( tebTable, 0, sizeof (table->dispatch_table) );
464 }
465
466 /* put in empty functions as long as we dont have a fallback */
467 #define X(func, ret, typeargs, args, icdidx, tebidx, stack) \
468 if (tebTable[icdidx] == NULL) \
469 { \
470 if (table != NULL) \
471 DBGPRINT( "Warning: GL proc '%s' is NULL", #func ); \
472 tebTable[icdidx] = (PROC)glEmptyFunc##stack; \
473 }
474 GLFUNCS_MACRO
475 #undef X
476
477 /* fill teb->glDispatchTable for fast calls */
478 #define X(func, ret, typeargs, args, icdidx, tebidx, stack) \
479 if (tebidx >= 0) \
480 tebDispatchTable[tebidx] = tebTable[icdidx];
481 GLFUNCS_MACRO
482 #undef X
483
484 DBGPRINT( "Done." );
485
486 return ERROR_SUCCESS;
487 }
488
489
490 /*! \brief Attempts to find the best matching pixel format for HDC
491 *
492 * This function is comparing each available format with the preferred one
493 * and returns the one which is closest to it.
494 * If PFD_DOUBLEBUFFER, PFD_STEREO or one of PFD_DRAW_TO_WINDOW,
495 * PFD_DRAW_TO_BITMAP, PFD_SUPPORT_GDI and PDF_SUPPORT_OPENGL is given then
496 * only formats which also support those will be enumerated (unless
497 * PFD_DOUBLEBUFFER_DONTCARE or PFD_STEREO_DONTCARE is also set)
498 *
499 * \param hdc [IN] Handle to DC for which to get a pixel format index
500 * \param pfd [IN] PFD describing what kind of format you want
501 *
502 * \return Pixel format index
503 * \retval 0 Failed to find a suitable format
504 */
505 #define BUFFERDEPTH_SCORE(want, have) \
506 ((want == 0) ? (0) : ((want < have) ? (1) : ((want > have) ? (3) : (0))))
507
508 /* Score if we want and not have it */
509 #define FLAG_SCORE(want, have, flag) \
510 (((want & ~have) & flag) ? (1) : (0))
511
512 /* Score if what we want is different than what we have, except when
513 _DONTCARE was set */
514 #define FLAG_SCORE_DONTCARE(want, have, flag) \
515 ((!(have & flag ## _DONTCARE)) && ((want & flag) != (have & flag)) ? (1) : (0))
516
517 int
518 APIENTRY
519 rosglChoosePixelFormat( HDC hdc, CONST PIXELFORMATDESCRIPTOR *pfd )
520 {
521 GLDRIVERDATA *icd;
522 PIXELFORMATDESCRIPTOR icdPfd;
523 int i;
524 int best = 0;
525 int score, bestScore = 0x7fff; /* used to choose a pfd if no exact match */
526 int icdNumFormats;
527
528 DBGTRACE( "Called!" );
529
530 /* load ICD */
531 icd = ROSGL_ICDForHDC( hdc );
532 if (icd == NULL)
533 return 0;
534
535 /* check input */
536 if (pfd->nSize != sizeof (PIXELFORMATDESCRIPTOR) || pfd->nVersion != 1)
537 {
538 SetLastError( ERROR_INVALID_PARAMETER );
539 return 0;
540 }
541
542 /* get number of formats */
543 icdNumFormats = icd->DrvDescribePixelFormat( hdc, 1,
544 sizeof (PIXELFORMATDESCRIPTOR), &icdPfd );
545 if (icdNumFormats == 0)
546 {
547 DBGPRINT( "Error: DrvDescribePixelFormat failed (%d)", GetLastError() );
548 return 0;
549 }
550 DBGPRINT( "Info: Enumerating %d pixelformats", icdNumFormats );
551
552 /* try to find best format */
553 for (i = 0; i < icdNumFormats; i++)
554 {
555 if (icd->DrvDescribePixelFormat( hdc, i + 1,
556 sizeof (PIXELFORMATDESCRIPTOR), &icdPfd ) == 0)
557 {
558 DBGPRINT( "Warning: DrvDescribePixelFormat failed (%d)",
559 GetLastError() );
560 break;
561 }
562
563 if ((pfd->dwFlags & PFD_GENERIC_ACCELERATED) != 0) /* we do not support such kind of drivers */
564 {
565 continue;
566 }
567
568 score = 0; /* higher is worse */
569
570 /* compare flags */
571 score += FLAG_SCORE(pfd->dwFlags, icdPfd.dwFlags, PFD_DRAW_TO_WINDOW);
572 score += FLAG_SCORE(pfd->dwFlags, icdPfd.dwFlags, PFD_DRAW_TO_BITMAP);
573 score += FLAG_SCORE(pfd->dwFlags, icdPfd.dwFlags, PFD_SUPPORT_GDI);
574 score += FLAG_SCORE(pfd->dwFlags, icdPfd.dwFlags, PFD_SUPPORT_OPENGL);
575 score += FLAG_SCORE_DONTCARE(pfd->dwFlags, icdPfd.dwFlags, PFD_DOUBLEBUFFER);
576 score += FLAG_SCORE_DONTCARE(pfd->dwFlags, icdPfd.dwFlags, PFD_STEREO);
577
578 /* check other attribs */
579 if (pfd->iPixelType != icdPfd.iPixelType)
580 score += 5; /* this is really bad i think */
581 if (pfd->iLayerType != icdPfd.iLayerType)
582 score += 15; /* this is very very bad ;) */
583
584 score += BUFFERDEPTH_SCORE(pfd->cAlphaBits, icdPfd.cAlphaBits);
585 score += BUFFERDEPTH_SCORE(pfd->cAccumBits, icdPfd.cAccumBits);
586 score += BUFFERDEPTH_SCORE(pfd->cDepthBits, icdPfd.cDepthBits);
587 score += BUFFERDEPTH_SCORE(pfd->cStencilBits, icdPfd.cStencilBits);
588 score += BUFFERDEPTH_SCORE(pfd->cAuxBuffers, icdPfd.cAuxBuffers);
589
590 /* check score */
591 if (score < bestScore)
592 {
593 bestScore = score;
594 best = i + 1;
595 if (bestScore == 0)
596 break;
597 }
598 }
599
600 if (best == 0)
601 SetLastError( 0 ); /* FIXME: set appropriate error */
602
603 DBGPRINT( "Info: Suggesting pixelformat %d", best );
604 return best;
605 }
606
607
608 /*! \brief Copy data specified by mask from one GLRC to another.
609 *
610 * \param src [IN] Source GLRC
611 * \param src [OUT] Destination GLRC
612 * \param mask [IN] Bitfield like given to glPushAttrib()
613 *
614 * \retval TRUE Success
615 * \retval FALSE Failure
616 */
617 BOOL
618 APIENTRY
619 rosglCopyContext( HGLRC hsrc, HGLRC hdst, UINT mask )
620 {
621 GLRC *src = (GLRC *)hsrc;
622 GLRC *dst = (GLRC *)hdst;
623
624 /* check glrcs */
625 if (!ROSGL_ContainsContext( src ))
626 {
627 DBGPRINT( "Error: src GLRC not found!" );
628 SetLastError( ERROR_INVALID_HANDLE );
629 return FALSE;
630 }
631 if (!ROSGL_ContainsContext( dst ))
632 {
633 DBGPRINT( "Error: dst GLRC not found!" );
634 SetLastError( ERROR_INVALID_HANDLE );
635 return FALSE;
636 }
637
638 /* I think this is only possible within one ICD */
639 if (src->icd != dst->icd)
640 {
641 DBGPRINT( "Error: src and dst GLRC use different ICDs!" );
642 SetLastError( ERROR_INVALID_HANDLE );
643 return FALSE;
644 }
645
646 /* copy data (call ICD) */
647 return src->icd->DrvCopyContext( src->hglrc, dst->hglrc, mask );
648 }
649
650
651 /*! \brief Create a new GL Rendering Context.
652 *
653 * This function can create over- or underlay surfaces.
654 *
655 * \param hdc [IN] Handle for DC for which to create context
656 * \param layer [IN] Layer number to bind (draw?) to
657 *
658 * \return Handle for the created GLRC
659 * \retval NULL Failure
660 */
661 HGLRC
662 APIENTRY
663 rosglCreateLayerContext( HDC hdc, int layer )
664 {
665 GLDRIVERDATA *icd = NULL;
666 GLRC *glrc;
667 HGLRC drvHglrc = NULL;
668
669 DBGTRACE( "Called!" );
670
671 /* if (GetObjectType( hdc ) != OBJ_DC)
672 {
673 DBGPRINT( "Error: hdc is not a DC handle!" );
674 return NULL;
675 }
676 */
677 /* create new GLRC */
678 glrc = ROSGL_NewContext();
679 if (glrc == NULL)
680 return NULL;
681
682 /* load ICD */
683 icd = ROSGL_ICDForHDC( hdc );
684 if (icd == NULL)
685 {
686 ROSGL_DeleteContext( glrc );
687 DBGPRINT( "Couldn't get ICD by HDC :-(" );
688 /* FIXME: fallback? */
689 return NULL;
690 }
691 /* Don't forget to refcount it, icd will be released when last context is deleted */
692 InterlockedIncrement((LONG*)&icd->refcount);
693
694
695 /* create context */
696 if (icd->DrvCreateLayerContext != NULL)
697 drvHglrc = icd->DrvCreateLayerContext( hdc, layer );
698 if (drvHglrc == NULL)
699 {
700 if (layer == 0 && icd->DrvCreateContext != NULL)
701 drvHglrc = icd->DrvCreateContext( hdc );
702 else
703 DBGPRINT( "Warning: CreateLayerContext not supported by ICD!" );
704 }
705
706 if (drvHglrc == NULL)
707 {
708 /* FIXME: fallback to mesa? */
709 DBGPRINT( "Error: DrvCreate[Layer]Context failed! (%d)", GetLastError() );
710 ROSGL_DeleteContext( glrc );
711 return NULL;
712 }
713
714 /* we have our GLRC in glrc and the ICD's GLRC in drvHglrc */
715 glrc->hglrc = drvHglrc;
716 glrc->icd = icd;
717
718 return (HGLRC)glrc;
719 }
720
721
722 /*! \brief Create a new GL Rendering Context.
723 *
724 * \param hdc [IN] Handle for DC for which to create context
725 *
726 * \return Handle for the created GLRC
727 * \retval NULL Failure
728 */
729 HGLRC
730 APIENTRY
731 rosglCreateContext( HDC hdc )
732 {
733 return rosglCreateLayerContext( hdc, 0 );
734 }
735
736
737 /*! \brief Delete an OpenGL context
738 *
739 * \param hglrc [IN] Handle to GLRC to delete; must not be a threads current RC!
740 *
741 * \retval TRUE Success
742 * \retval FALSE Failure (i.e. GLRC is current for a thread)
743 */
744 BOOL
745 APIENTRY
746 rosglDeleteContext( HGLRC hglrc )
747 {
748 GLRC *glrc = (GLRC *)hglrc;
749
750 /* check if we know about this context */
751 if (!ROSGL_ContainsContext( glrc ))
752 {
753 DBGPRINT( "Error: hglrc not found!" );
754 SetLastError( ERROR_INVALID_HANDLE );
755 return FALSE;
756 }
757
758 /* make sure GLRC is not current for some thread */
759 if (glrc->is_current)
760 {
761 DBGPRINT( "Error: GLRC is current for DC 0x%08x", glrc->hdc );
762 SetLastError( ERROR_INVALID_FUNCTION );
763 return FALSE;
764 }
765
766 /* release ICD's context */
767 if (glrc->hglrc != NULL)
768 {
769 if (!glrc->icd->DrvDeleteContext( glrc->hglrc ))
770 {
771 DBGPRINT( "Warning: DrvDeleteContext() failed (%d)", GetLastError() );
772 return FALSE;
773 }
774 }
775
776 /* free resources */
777 return ROSGL_DeleteContext( glrc );
778 }
779
780
781 BOOL
782 APIENTRY
783 rosglDescribeLayerPlane( HDC hdc, int iPixelFormat, int iLayerPlane,
784 UINT nBytes, LPLAYERPLANEDESCRIPTOR plpd )
785 {
786 UNIMPLEMENTED;
787 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
788 return FALSE;
789 }
790
791
792 /*! \brief Gets information about a pixelformat.
793 *
794 * \param hdc [IN] Handle to DC
795 * \param iFormat [IN] Pixelformat index
796 * \param nBytes [IN] sizeof (pfd) - at most nBytes are copied into pfd
797 * \param pfd [OUT] Pointer to a PIXELFORMATDESCRIPTOR
798 *
799 * \return Maximum pixelformat index/number of formats
800 * \retval 0 Failure
801 */
802 int
803 APIENTRY
804 rosglDescribePixelFormat( HDC hdc, int iFormat, UINT nBytes,
805 LPPIXELFORMATDESCRIPTOR pfd )
806 {
807 int ret = 0;
808 GLDRIVERDATA *icd = ROSGL_ICDForHDC( hdc );
809
810 if (icd != NULL)
811 {
812 ret = icd->DrvDescribePixelFormat( hdc, iFormat, nBytes, pfd );
813 if (ret == 0)
814 DBGPRINT( "Error: DrvDescribePixelFormat(format=%d) failed (%d)", iFormat, GetLastError() );
815 }
816 else
817 {
818 SetLastError( ERROR_INVALID_FUNCTION );
819 }
820
821 return ret;
822 }
823
824
825 /*! \brief Return the thread's current GLRC
826 *
827 * \return Handle for thread's current GLRC
828 * \retval NULL No current GLRC set
829 */
830 HGLRC
831 APIENTRY
832 rosglGetCurrentContext()
833 {
834 return (HGLRC)(OPENGL32_threaddata->glrc);
835 }
836
837
838 /*! \brief Return the thread's current DC
839 *
840 * \return Handle for thread's current DC
841 * \retval NULL No current DC/GLRC set
842 */
843 HDC
844 APIENTRY
845 rosglGetCurrentDC()
846 {
847 /* FIXME: is it correct to return NULL when there is no current GLRC or
848 is there another way to find out the wanted HDC? */
849 if (OPENGL32_threaddata->glrc == NULL)
850 return NULL;
851 return (HDC)(OPENGL32_threaddata->glrc->hdc);
852 }
853
854
855 int
856 APIENTRY
857 rosglGetLayerPaletteEntries( HDC hdc, int iLayerPlane, int iStart,
858 int cEntries, COLORREF *pcr )
859 {
860 UNIMPLEMENTED;
861 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
862 return 0;
863 }
864
865
866 /*! \brief Returns the current pixelformat.
867 *
868 * \param hdc [IN] Handle to DC to get the pixelformat from
869 *
870 * \return Pixelformat index
871 * \retval 0 Failure
872 */
873 int
874 WINAPI
875 rosglGetPixelFormat( HDC hdc )
876 {
877 GLDCDATA *dcdata;
878
879 DBGTRACE( "Called!" );
880
881 dcdata = ROSGL_GetPrivateDCData( hdc );
882 if (dcdata == NULL)
883 {
884 DBGPRINT( "Error: ROSGL_GetPrivateDCData failed!" );
885 return 0;
886 }
887
888 return dcdata->pixel_format;
889 }
890
891
892 /*! \brief Get the address for an OpenGL extension function.
893 *
894 * The addresses this function returns are only valid within the same thread
895 * which it was called from.
896 *
897 * \param proc [IN] Name of the function to look for
898 *
899 * \return The address of the proc
900 * \retval NULL Failure
901 */
902 PROC
903 APIENTRY
904 rosglGetProcAddress( LPCSTR proc )
905 {
906 PROC func;
907 GLDRIVERDATA *icd;
908
909 /* FIXME we should Flush the gl here */
910
911 if (OPENGL32_threaddata->glrc == NULL)
912 {
913 DBGPRINT( "Error: No current GLRC!" );
914 SetLastError( ERROR_INVALID_FUNCTION );
915 return NULL;
916 }
917
918 icd = OPENGL32_threaddata->glrc->icd;
919 func = icd->DrvGetProcAddress( proc );
920 if (func != NULL)
921 {
922 DBGPRINT( "Info: Proc \"%s\" loaded from ICD.", proc );
923 return func;
924 }
925
926 /* FIXME: Should we return wgl/gl 1.1 functions? */
927 SetLastError( ERROR_PROC_NOT_FOUND );
928 return NULL;
929 }
930
931 PROC
932 APIENTRY
933 rosglGetDefaultProcAddress( LPCSTR proc )
934 {
935 PROC func;
936 GLDRIVERDATA *icd;
937
938 /* wglGetDefaultProcAddress does not flush the gl */
939
940 if (OPENGL32_threaddata->glrc == NULL)
941 {
942 DBGPRINT( "Error: No current GLRC!" );
943 SetLastError( ERROR_INVALID_FUNCTION );
944 return NULL;
945 }
946
947 icd = OPENGL32_threaddata->glrc->icd;
948 func = icd->DrvGetProcAddress( proc );
949 if (func != NULL)
950 {
951 DBGPRINT( "Info: Proc \"%s\" loaded from ICD.", proc );
952 return func;
953 }
954
955 /* FIXME: Should we return wgl/gl 1.1 functions? */
956 SetLastError( ERROR_PROC_NOT_FOUND );
957 return NULL;
958 }
959
960
961 /*! \brief Make the given GLRC the threads current GLRC for hdc
962 *
963 * \param hdc [IN] Handle for a DC to be drawn on
964 * \param hglrc [IN] Handle for a GLRC to make current
965 *
966 * \retval TRUE Success
967 * \retval FALSE Failure
968 */
969 BOOL
970 APIENTRY
971 rosglMakeCurrent( HDC hdc, HGLRC hglrc )
972 {
973 GLRC *glrc = (GLRC *)hglrc;
974 ICDTable *icdTable = NULL;
975
976 DBGTRACE( "Called!" );
977
978 if (OPENGL32_threaddata == NULL)
979 return FALSE;
980
981 /* flush current context */
982 if (OPENGL32_threaddata->glrc != NULL)
983 {
984 glFlush();
985 }
986
987 /* check if current context is unset */
988 if (glrc == NULL)
989 {
990 if (OPENGL32_threaddata->glrc != NULL)
991 {
992 glrc = OPENGL32_threaddata->glrc;
993 glrc->icd->DrvReleaseContext( glrc->hglrc );
994 glrc->is_current = FALSE;
995 OPENGL32_threaddata->glrc = NULL;
996 }
997 }
998 else
999 {
1000 /* check hdc */
1001 if (GetObjectType( hdc ) != OBJ_DC && GetObjectType( hdc ) != OBJ_MEMDC)
1002 {
1003 DBGPRINT( "Error: hdc is not a DC handle!" );
1004 SetLastError( ERROR_INVALID_HANDLE );
1005 return FALSE;
1006 }
1007
1008 /* check if we know about this glrc */
1009 if (!ROSGL_ContainsContext( glrc ))
1010 {
1011 DBGPRINT( "Error: hglrc not found!" );
1012 SetLastError( ERROR_INVALID_HANDLE );
1013 return FALSE;
1014 }
1015
1016 /* check if it is available */
1017 if (glrc->is_current && glrc->thread_id != GetCurrentThreadId()) /* used by another thread */
1018 {
1019 DBGPRINT( "Error: hglrc is current for thread 0x%08x", glrc->thread_id );
1020 SetLastError( ERROR_INVALID_HANDLE );
1021 return FALSE;
1022 }
1023
1024 /* call the ICD */
1025 if (glrc->hglrc != NULL)
1026 {
1027 DBGPRINT( "Info: Calling DrvSetContext!" );
1028 SetLastError( ERROR_SUCCESS );
1029 icdTable = glrc->icd->DrvSetContext( hdc, glrc->hglrc,
1030 (void *)ROSGL_SetContextCallBack );
1031 if (icdTable == NULL)
1032 {
1033 DBGPRINT( "Error: DrvSetContext failed (%d)\n", GetLastError() );
1034 return FALSE;
1035 }
1036 DBGPRINT( "Info: DrvSetContext succeeded!" );
1037 }
1038
1039 /* make it current */
1040 if (OPENGL32_threaddata->glrc != NULL)
1041 OPENGL32_threaddata->glrc->is_current = FALSE;
1042 glrc->is_current = TRUE;
1043 glrc->thread_id = GetCurrentThreadId();
1044 glrc->hdc = hdc;
1045 OPENGL32_threaddata->glrc = glrc;
1046 }
1047
1048 if (ROSGL_SetContextCallBack( icdTable ) != ERROR_SUCCESS && icdTable == NULL)
1049 {
1050 DBGPRINT( "Warning: ROSGL_SetContextCallBack failed!" );
1051 }
1052
1053 return TRUE;
1054 }
1055
1056
1057 BOOL
1058 APIENTRY
1059 rosglRealizeLayerPalette( HDC hdc, int iLayerPlane, BOOL bRealize )
1060 {
1061 UNIMPLEMENTED;
1062 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
1063 return FALSE;
1064 }
1065
1066
1067 int
1068 APIENTRY
1069 rosglSetLayerPaletteEntries( HDC hdc, int iLayerPlane, int iStart,
1070 int cEntries, CONST COLORREF *pcr )
1071 {
1072 UNIMPLEMENTED;
1073 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
1074 return 0;
1075 }
1076
1077
1078 /*! \brief Set a DCs pixelformat
1079 *
1080 * \param hdc [IN] Handle to DC for which to set the format
1081 * \param iFormat [IN] Index of the pixelformat to set
1082 * \param pfd [IN] Not sure what this is for
1083 *
1084 * \retval TRUE Success
1085 * \retval FALSE Failure
1086 */
1087 BOOL
1088 WINAPI
1089 rosglSetPixelFormat( HDC hdc, int iFormat, CONST PIXELFORMATDESCRIPTOR *pfd )
1090 {
1091 GLDRIVERDATA *icd;
1092 GLDCDATA *dcdata;
1093
1094 DBGTRACE( "Called!" );
1095
1096 /* load ICD */
1097 icd = ROSGL_ICDForHDC( hdc );
1098 if (icd == NULL)
1099 {
1100 DBGPRINT( "Warning: ICDForHDC() failed" );
1101 return FALSE;
1102 }
1103
1104 /* call ICD */
1105 if (!icd->DrvSetPixelFormat( hdc, iFormat, pfd ))
1106 {
1107 DBGPRINT( "Warning: DrvSetPixelFormat(format=%d) failed (%d)",
1108 iFormat, GetLastError() );
1109 return FALSE;
1110 }
1111
1112 /* store format in private DC data */
1113 dcdata = ROSGL_GetPrivateDCData( hdc );
1114 if (dcdata == NULL)
1115 {
1116 DBGPRINT( "Error: ROSGL_GetPrivateDCData() failed!" );
1117 return FALSE;
1118 }
1119 dcdata->pixel_format = iFormat;
1120
1121 return TRUE;
1122 }
1123
1124
1125 /*! \brief Enable display-list sharing between multiple GLRCs
1126 *
1127 * This will only work if both GLRCs are from the same driver.
1128 *
1129 * \param hglrc1 [IN] GLRC number 1
1130 * \param hglrc2 [IN] GLRC number 2
1131 *
1132 * \retval TRUE Success
1133 * \retval FALSE Failure
1134 */
1135 BOOL
1136 APIENTRY
1137 rosglShareLists( HGLRC hglrc1, HGLRC hglrc2 )
1138 {
1139 GLRC *glrc1 = (GLRC *)hglrc1;
1140 GLRC *glrc2 = (GLRC *)hglrc2;
1141
1142 /* check glrcs */
1143 if (!ROSGL_ContainsContext( glrc1 ))
1144 {
1145 DBGPRINT( "Error: hglrc1 not found!" );
1146 SetLastError( ERROR_INVALID_HANDLE );
1147 return FALSE;
1148 }
1149 if (!ROSGL_ContainsContext( glrc2 ))
1150 {
1151 DBGPRINT( "Error: hglrc2 not found!" );
1152 SetLastError( ERROR_INVALID_HANDLE );
1153 return FALSE;
1154 }
1155
1156 /* I think this is only possible within one ICD */
1157 if (glrc1->icd != glrc2->icd)
1158 {
1159 DBGPRINT( "Error: hglrc1 and hglrc2 use different ICDs!" );
1160 SetLastError( ERROR_INVALID_HANDLE );
1161 return FALSE;
1162 }
1163
1164 /* share lists (call ICD) */
1165 return glrc1->icd->DrvShareLists( glrc1->hglrc, glrc2->hglrc );
1166 }
1167
1168
1169 /*! \brief Flushes GL and swaps front/back buffer if appropriate
1170 *
1171 * \param hdc [IN] Handle to device context to swap buffers for
1172 *
1173 * \retval TRUE Success
1174 * \retval FALSE Failure
1175 */
1176 BOOL
1177 APIENTRY
1178 rosglSwapBuffers( HDC hdc )
1179 {
1180 GLDRIVERDATA *icd = ROSGL_ICDForHDC( hdc );
1181 DBGTRACE( "Called!" );
1182 if (icd != NULL)
1183 {
1184 DBGPRINT( "Swapping buffers!" );
1185 if (!icd->DrvSwapBuffers( hdc ))
1186 {
1187 DBGPRINT( "Error: DrvSwapBuffers failed (%d)", GetLastError() );
1188 return FALSE;
1189 }
1190 return TRUE;
1191 }
1192
1193 /* FIXME: implement own functionality? */
1194 SetLastError( ERROR_INVALID_FUNCTION );
1195 return FALSE;
1196 }
1197
1198
1199 BOOL
1200 APIENTRY
1201 rosglSwapLayerBuffers( HDC hdc, UINT fuPlanes )
1202 {
1203 BOOL ret = FALSE;
1204
1205 if(fuPlanes & WGL_SWAP_MAIN_PLANE)
1206 ret = rosglSwapBuffers(hdc);
1207
1208 if(fuPlanes &~WGL_SWAP_MAIN_PLANE)
1209 DBGTRACE("wglSwapLayerBuffers is not fully implemented\n");
1210
1211 return ret;
1212 }
1213
1214
1215 BOOL
1216 APIENTRY
1217 rosglUseFontBitmapsA( HDC hdc, DWORD first, DWORD count, DWORD listBase )
1218 {
1219 return IntUseFontBitmapsA(hdc, first, count, listBase);
1220 }
1221
1222
1223 BOOL
1224 APIENTRY
1225 rosglUseFontBitmapsW( HDC hdc, DWORD first, DWORD count, DWORD listBase )
1226 {
1227 return IntUseFontBitmapsW(hdc, first, count, listBase);
1228 }
1229
1230 BOOL
1231 APIENTRY
1232 rosglUseFontOutlinesA( HDC hdc, DWORD first, DWORD count, DWORD listBase,
1233 FLOAT deviation, FLOAT extrusion, int format,
1234 GLYPHMETRICSFLOAT *pgmf )
1235 {
1236 return IntUseFontOutlinesA(hdc, first, count, listBase, deviation, extrusion, format, pgmf);
1237 }
1238
1239
1240 BOOL
1241 APIENTRY
1242 rosglUseFontOutlinesW( HDC hdc, DWORD first, DWORD count, DWORD listBase,
1243 FLOAT deviation, FLOAT extrusion, int format,
1244 GLYPHMETRICSFLOAT *pgmf )
1245 {
1246 return IntUseFontOutlinesW(hdc, first, count, listBase, deviation, extrusion, format, pgmf);
1247 }
1248
1249 #ifdef __cplusplus
1250 }; /* extern "C" */
1251 #endif /* __cplusplus */
1252
1253 /* EOF */