[OPENGL32]
[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, DISPATCH_TABLE_SIZE - size );
458 }
459 else
460 {
461 DBGPRINT( "Unsetting current context" );
462 memset( tebTable, 0, DISPATCH_TABLE_SIZE );
463 }
464
465 /* put in empty functions as long as we dont have a fallback */
466 #define X(func, ret, typeargs, args, icdidx, tebidx, stack) \
467 if (tebTable[icdidx] == NULL) \
468 { \
469 if (table != NULL) \
470 DBGPRINT( "Warning: GL proc '%s' is NULL", #func ); \
471 tebTable[icdidx] = (PROC)glEmptyFunc##stack; \
472 }
473 GLFUNCS_MACRO
474 #undef X
475
476 /* fill teb->glDispatchTable for fast calls */
477 #define X(func, ret, typeargs, args, icdidx, tebidx, stack) \
478 if (tebidx >= 0) \
479 tebDispatchTable[tebidx] = tebTable[icdidx];
480 GLFUNCS_MACRO
481 #undef X
482
483 DBGPRINT( "Done." );
484
485 return ERROR_SUCCESS;
486 }
487
488
489 /*! \brief Attempts to find the best matching pixel format for HDC
490 *
491 * This function is comparing each available format with the preferred one
492 * and returns the one which is closest to it.
493 * If PFD_DOUBLEBUFFER, PFD_STEREO or one of PFD_DRAW_TO_WINDOW,
494 * PFD_DRAW_TO_BITMAP, PFD_SUPPORT_GDI and PDF_SUPPORT_OPENGL is given then
495 * only formats which also support those will be enumerated (unless
496 * PFD_DOUBLEBUFFER_DONTCARE or PFD_STEREO_DONTCARE is also set)
497 *
498 * \param hdc [IN] Handle to DC for which to get a pixel format index
499 * \param pfd [IN] PFD describing what kind of format you want
500 *
501 * \return Pixel format index
502 * \retval 0 Failed to find a suitable format
503 */
504 #define BUFFERDEPTH_SCORE(want, have) \
505 ((want == 0) ? (0) : ((want < have) ? (1) : ((want > have) ? (3) : (0))))
506
507 /* Score if we want and not have it */
508 #define FLAG_SCORE(want, have, flag) \
509 (((want & ~have) & flag) ? (1) : (0))
510
511 /* Score if what we want is different than what we have, except when
512 _DONTCARE was set */
513 #define FLAG_SCORE_DONTCARE(want, have, flag) \
514 ((!(have & flag ## _DONTCARE)) && ((want & flag) != (have & flag)) ? (1) : (0))
515
516 int
517 APIENTRY
518 rosglChoosePixelFormat( HDC hdc, CONST PIXELFORMATDESCRIPTOR *pfd )
519 {
520 GLDRIVERDATA *icd;
521 PIXELFORMATDESCRIPTOR icdPfd;
522 int i;
523 int best = 0;
524 int score, bestScore = 0x7fff; /* used to choose a pfd if no exact match */
525 int icdNumFormats;
526
527 DBGTRACE( "Called!" );
528
529 /* load ICD */
530 icd = ROSGL_ICDForHDC( hdc );
531 if (icd == NULL)
532 return 0;
533
534 /* check input */
535 if (pfd->nSize != sizeof (PIXELFORMATDESCRIPTOR) || pfd->nVersion != 1)
536 {
537 SetLastError( ERROR_INVALID_PARAMETER );
538 return 0;
539 }
540
541 /* get number of formats */
542 icdNumFormats = icd->DrvDescribePixelFormat( hdc, 1,
543 sizeof (PIXELFORMATDESCRIPTOR), &icdPfd );
544 if (icdNumFormats == 0)
545 {
546 DBGPRINT( "Error: DrvDescribePixelFormat failed (%d)", GetLastError() );
547 return 0;
548 }
549 DBGPRINT( "Info: Enumerating %d pixelformats", icdNumFormats );
550
551 /* try to find best format */
552 for (i = 0; i < icdNumFormats; i++)
553 {
554 if (icd->DrvDescribePixelFormat( hdc, i + 1,
555 sizeof (PIXELFORMATDESCRIPTOR), &icdPfd ) == 0)
556 {
557 DBGPRINT( "Warning: DrvDescribePixelFormat failed (%d)",
558 GetLastError() );
559 break;
560 }
561
562 if ((pfd->dwFlags & PFD_GENERIC_ACCELERATED) != 0) /* we do not support such kind of drivers */
563 {
564 continue;
565 }
566
567 score = 0; /* higher is worse */
568
569 /* compare flags */
570 score += FLAG_SCORE(pfd->dwFlags, icdPfd.dwFlags, PFD_DRAW_TO_WINDOW);
571 score += FLAG_SCORE(pfd->dwFlags, icdPfd.dwFlags, PFD_DRAW_TO_BITMAP);
572 score += FLAG_SCORE(pfd->dwFlags, icdPfd.dwFlags, PFD_SUPPORT_GDI);
573 score += FLAG_SCORE(pfd->dwFlags, icdPfd.dwFlags, PFD_SUPPORT_OPENGL);
574 score += FLAG_SCORE_DONTCARE(pfd->dwFlags, icdPfd.dwFlags, PFD_DOUBLEBUFFER);
575 score += FLAG_SCORE_DONTCARE(pfd->dwFlags, icdPfd.dwFlags, PFD_STEREO);
576
577 /* check other attribs */
578 if (pfd->iPixelType != icdPfd.iPixelType)
579 score += 5; /* this is really bad i think */
580 if (pfd->iLayerType != icdPfd.iLayerType)
581 score += 15; /* this is very very bad ;) */
582
583 score += BUFFERDEPTH_SCORE(pfd->cAlphaBits, icdPfd.cAlphaBits);
584 score += BUFFERDEPTH_SCORE(pfd->cAccumBits, icdPfd.cAccumBits);
585 score += BUFFERDEPTH_SCORE(pfd->cDepthBits, icdPfd.cDepthBits);
586 score += BUFFERDEPTH_SCORE(pfd->cStencilBits, icdPfd.cStencilBits);
587 score += BUFFERDEPTH_SCORE(pfd->cAuxBuffers, icdPfd.cAuxBuffers);
588
589 /* check score */
590 if (score < bestScore)
591 {
592 bestScore = score;
593 best = i + 1;
594 if (bestScore == 0)
595 break;
596 }
597 }
598
599 if (best == 0)
600 SetLastError( 0 ); /* FIXME: set appropriate error */
601
602 DBGPRINT( "Info: Suggesting pixelformat %d", best );
603 return best;
604 }
605
606
607 /*! \brief Copy data specified by mask from one GLRC to another.
608 *
609 * \param src [IN] Source GLRC
610 * \param src [OUT] Destination GLRC
611 * \param mask [IN] Bitfield like given to glPushAttrib()
612 *
613 * \retval TRUE Success
614 * \retval FALSE Failure
615 */
616 BOOL
617 APIENTRY
618 rosglCopyContext( HGLRC hsrc, HGLRC hdst, UINT mask )
619 {
620 GLRC *src = (GLRC *)hsrc;
621 GLRC *dst = (GLRC *)hdst;
622
623 /* check glrcs */
624 if (!ROSGL_ContainsContext( src ))
625 {
626 DBGPRINT( "Error: src GLRC not found!" );
627 SetLastError( ERROR_INVALID_HANDLE );
628 return FALSE;
629 }
630 if (!ROSGL_ContainsContext( dst ))
631 {
632 DBGPRINT( "Error: dst GLRC not found!" );
633 SetLastError( ERROR_INVALID_HANDLE );
634 return FALSE;
635 }
636
637 /* I think this is only possible within one ICD */
638 if (src->icd != dst->icd)
639 {
640 DBGPRINT( "Error: src and dst GLRC use different ICDs!" );
641 SetLastError( ERROR_INVALID_HANDLE );
642 return FALSE;
643 }
644
645 /* copy data (call ICD) */
646 return src->icd->DrvCopyContext( src->hglrc, dst->hglrc, mask );
647 }
648
649
650 /*! \brief Create a new GL Rendering Context.
651 *
652 * This function can create over- or underlay surfaces.
653 *
654 * \param hdc [IN] Handle for DC for which to create context
655 * \param layer [IN] Layer number to bind (draw?) to
656 *
657 * \return Handle for the created GLRC
658 * \retval NULL Failure
659 */
660 HGLRC
661 APIENTRY
662 rosglCreateLayerContext( HDC hdc, int layer )
663 {
664 GLDRIVERDATA *icd = NULL;
665 GLRC *glrc;
666 HGLRC drvHglrc = NULL;
667
668 DBGTRACE( "Called!" );
669
670 /* if (GetObjectType( hdc ) != OBJ_DC)
671 {
672 DBGPRINT( "Error: hdc is not a DC handle!" );
673 return NULL;
674 }
675 */
676 /* create new GLRC */
677 glrc = ROSGL_NewContext();
678 if (glrc == NULL)
679 return NULL;
680
681 /* load ICD */
682 icd = ROSGL_ICDForHDC( hdc );
683 if (icd == NULL)
684 {
685 ROSGL_DeleteContext( glrc );
686 DBGPRINT( "Couldn't get ICD by HDC :-(" );
687 /* FIXME: fallback? */
688 return NULL;
689 }
690 /* Don't forget to refcount it, icd will be released when last context is deleted */
691 InterlockedIncrement((LONG*)&icd->refcount);
692
693
694 /* create context */
695 if (icd->DrvCreateLayerContext != NULL)
696 drvHglrc = icd->DrvCreateLayerContext( hdc, layer );
697 if (drvHglrc == NULL)
698 {
699 if (layer == 0 && icd->DrvCreateContext != NULL)
700 drvHglrc = icd->DrvCreateContext( hdc );
701 else
702 DBGPRINT( "Warning: CreateLayerContext not supported by ICD!" );
703 }
704
705 if (drvHglrc == NULL)
706 {
707 /* FIXME: fallback to mesa? */
708 DBGPRINT( "Error: DrvCreate[Layer]Context failed! (%d)", GetLastError() );
709 ROSGL_DeleteContext( glrc );
710 return NULL;
711 }
712
713 /* we have our GLRC in glrc and the ICD's GLRC in drvHglrc */
714 glrc->hglrc = drvHglrc;
715 glrc->icd = icd;
716
717 return (HGLRC)glrc;
718 }
719
720
721 /*! \brief Create a new GL Rendering Context.
722 *
723 * \param hdc [IN] Handle for DC for which to create context
724 *
725 * \return Handle for the created GLRC
726 * \retval NULL Failure
727 */
728 HGLRC
729 APIENTRY
730 rosglCreateContext( HDC hdc )
731 {
732 return rosglCreateLayerContext( hdc, 0 );
733 }
734
735
736 /*! \brief Delete an OpenGL context
737 *
738 * \param hglrc [IN] Handle to GLRC to delete; must not be a threads current RC!
739 *
740 * \retval TRUE Success
741 * \retval FALSE Failure (i.e. GLRC is current for a thread)
742 */
743 BOOL
744 APIENTRY
745 rosglDeleteContext( HGLRC hglrc )
746 {
747 GLRC *glrc = (GLRC *)hglrc;
748
749 /* check if we know about this context */
750 if (!ROSGL_ContainsContext( glrc ))
751 {
752 DBGPRINT( "Error: hglrc not found!" );
753 SetLastError( ERROR_INVALID_HANDLE );
754 return FALSE;
755 }
756
757 /* make sure GLRC is not current for some thread */
758 if (glrc->is_current)
759 {
760 DBGPRINT( "Error: GLRC is current for DC 0x%08x", glrc->hdc );
761 SetLastError( ERROR_INVALID_FUNCTION );
762 return FALSE;
763 }
764
765 /* release ICD's context */
766 if (glrc->hglrc != NULL)
767 {
768 if (!glrc->icd->DrvDeleteContext( glrc->hglrc ))
769 {
770 DBGPRINT( "Warning: DrvDeleteContext() failed (%d)", GetLastError() );
771 return FALSE;
772 }
773 }
774
775 /* free resources */
776 return ROSGL_DeleteContext( glrc );
777 }
778
779
780 BOOL
781 APIENTRY
782 rosglDescribeLayerPlane( HDC hdc, int iPixelFormat, int iLayerPlane,
783 UINT nBytes, LPLAYERPLANEDESCRIPTOR plpd )
784 {
785 UNIMPLEMENTED;
786 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
787 return FALSE;
788 }
789
790
791 /*! \brief Gets information about a pixelformat.
792 *
793 * \param hdc [IN] Handle to DC
794 * \param iFormat [IN] Pixelformat index
795 * \param nBytes [IN] sizeof (pfd) - at most nBytes are copied into pfd
796 * \param pfd [OUT] Pointer to a PIXELFORMATDESCRIPTOR
797 *
798 * \return Maximum pixelformat index/number of formats
799 * \retval 0 Failure
800 */
801 int
802 APIENTRY
803 rosglDescribePixelFormat( HDC hdc, int iFormat, UINT nBytes,
804 LPPIXELFORMATDESCRIPTOR pfd )
805 {
806 int ret = 0;
807 GLDRIVERDATA *icd = ROSGL_ICDForHDC( hdc );
808
809 if (icd != NULL)
810 {
811 ret = icd->DrvDescribePixelFormat( hdc, iFormat, nBytes, pfd );
812 if (ret == 0)
813 DBGPRINT( "Error: DrvDescribePixelFormat(format=%d) failed (%d)", iFormat, GetLastError() );
814 }
815 else
816 {
817 SetLastError( ERROR_INVALID_FUNCTION );
818 }
819
820 return ret;
821 }
822
823
824 /*! \brief Return the thread's current GLRC
825 *
826 * \return Handle for thread's current GLRC
827 * \retval NULL No current GLRC set
828 */
829 HGLRC
830 APIENTRY
831 rosglGetCurrentContext()
832 {
833 return (HGLRC)(OPENGL32_threaddata->glrc);
834 }
835
836
837 /*! \brief Return the thread's current DC
838 *
839 * \return Handle for thread's current DC
840 * \retval NULL No current DC/GLRC set
841 */
842 HDC
843 APIENTRY
844 rosglGetCurrentDC()
845 {
846 /* FIXME: is it correct to return NULL when there is no current GLRC or
847 is there another way to find out the wanted HDC? */
848 if (OPENGL32_threaddata->glrc == NULL)
849 return NULL;
850 return (HDC)(OPENGL32_threaddata->glrc->hdc);
851 }
852
853
854 int
855 APIENTRY
856 rosglGetLayerPaletteEntries( HDC hdc, int iLayerPlane, int iStart,
857 int cEntries, COLORREF *pcr )
858 {
859 UNIMPLEMENTED;
860 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
861 return 0;
862 }
863
864
865 /*! \brief Returns the current pixelformat.
866 *
867 * \param hdc [IN] Handle to DC to get the pixelformat from
868 *
869 * \return Pixelformat index
870 * \retval 0 Failure
871 */
872 int
873 WINAPI
874 rosglGetPixelFormat( HDC hdc )
875 {
876 GLDCDATA *dcdata;
877
878 DBGTRACE( "Called!" );
879
880 dcdata = ROSGL_GetPrivateDCData( hdc );
881 if (dcdata == NULL)
882 {
883 DBGPRINT( "Error: ROSGL_GetPrivateDCData failed!" );
884 return 0;
885 }
886
887 return dcdata->pixel_format;
888 }
889
890
891 /*! \brief Get the address for an OpenGL extension function.
892 *
893 * The addresses this function returns are only valid within the same thread
894 * which it was called from.
895 *
896 * \param proc [IN] Name of the function to look for
897 *
898 * \return The address of the proc
899 * \retval NULL Failure
900 */
901 PROC
902 APIENTRY
903 rosglGetProcAddress( LPCSTR proc )
904 {
905 PROC func;
906 GLDRIVERDATA *icd;
907
908 /* FIXME we should Flush the gl here */
909
910 if (OPENGL32_threaddata->glrc == NULL)
911 {
912 DBGPRINT( "Error: No current GLRC!" );
913 SetLastError( ERROR_INVALID_FUNCTION );
914 return NULL;
915 }
916
917 icd = OPENGL32_threaddata->glrc->icd;
918 func = icd->DrvGetProcAddress( proc );
919 if (func != NULL)
920 {
921 DBGPRINT( "Info: Proc \"%s\" loaded from ICD.", proc );
922 return func;
923 }
924
925 /* FIXME: Should we return wgl/gl 1.1 functions? */
926 SetLastError( ERROR_PROC_NOT_FOUND );
927 return NULL;
928 }
929
930 PROC
931 APIENTRY
932 rosglGetDefaultProcAddress( LPCSTR proc )
933 {
934 PROC func;
935 GLDRIVERDATA *icd;
936
937 /* wglGetDefaultProcAddress does not flush the gl */
938
939 if (OPENGL32_threaddata->glrc == NULL)
940 {
941 DBGPRINT( "Error: No current GLRC!" );
942 SetLastError( ERROR_INVALID_FUNCTION );
943 return NULL;
944 }
945
946 icd = OPENGL32_threaddata->glrc->icd;
947 func = icd->DrvGetProcAddress( proc );
948 if (func != NULL)
949 {
950 DBGPRINT( "Info: Proc \"%s\" loaded from ICD.", proc );
951 return func;
952 }
953
954 /* FIXME: Should we return wgl/gl 1.1 functions? */
955 SetLastError( ERROR_PROC_NOT_FOUND );
956 return NULL;
957 }
958
959
960 /*! \brief Make the given GLRC the threads current GLRC for hdc
961 *
962 * \param hdc [IN] Handle for a DC to be drawn on
963 * \param hglrc [IN] Handle for a GLRC to make current
964 *
965 * \retval TRUE Success
966 * \retval FALSE Failure
967 */
968 BOOL
969 APIENTRY
970 rosglMakeCurrent( HDC hdc, HGLRC hglrc )
971 {
972 GLRC *glrc = (GLRC *)hglrc;
973 ICDTable *icdTable = NULL;
974
975 DBGTRACE( "Called!" );
976
977 if (OPENGL32_threaddata == NULL)
978 return FALSE;
979
980 /* flush current context */
981 if (OPENGL32_threaddata->glrc != NULL)
982 {
983 glFlush();
984 }
985
986 /* check if current context is unset */
987 if (glrc == NULL)
988 {
989 if (OPENGL32_threaddata->glrc != NULL)
990 {
991 glrc = OPENGL32_threaddata->glrc;
992 glrc->icd->DrvReleaseContext( glrc->hglrc );
993 glrc->is_current = FALSE;
994 OPENGL32_threaddata->glrc = NULL;
995 }
996 }
997 else
998 {
999 /* check hdc */
1000 if (GetObjectType( hdc ) != OBJ_DC && GetObjectType( hdc ) != OBJ_MEMDC)
1001 {
1002 DBGPRINT( "Error: hdc is not a DC handle!" );
1003 SetLastError( ERROR_INVALID_HANDLE );
1004 return FALSE;
1005 }
1006
1007 /* check if we know about this glrc */
1008 if (!ROSGL_ContainsContext( glrc ))
1009 {
1010 DBGPRINT( "Error: hglrc not found!" );
1011 SetLastError( ERROR_INVALID_HANDLE );
1012 return FALSE;
1013 }
1014
1015 /* check if it is available */
1016 if (glrc->is_current && glrc->thread_id != GetCurrentThreadId()) /* used by another thread */
1017 {
1018 DBGPRINT( "Error: hglrc is current for thread 0x%08x", glrc->thread_id );
1019 SetLastError( ERROR_INVALID_HANDLE );
1020 return FALSE;
1021 }
1022
1023 /* call the ICD */
1024 if (glrc->hglrc != NULL)
1025 {
1026 DBGPRINT( "Info: Calling DrvSetContext!" );
1027 SetLastError( ERROR_SUCCESS );
1028 icdTable = glrc->icd->DrvSetContext( hdc, glrc->hglrc,
1029 (void *)ROSGL_SetContextCallBack );
1030 if (icdTable == NULL)
1031 {
1032 DBGPRINT( "Error: DrvSetContext failed (%d)\n", GetLastError() );
1033 return FALSE;
1034 }
1035 DBGPRINT( "Info: DrvSetContext succeeded!" );
1036 }
1037
1038 /* make it current */
1039 if (OPENGL32_threaddata->glrc != NULL)
1040 OPENGL32_threaddata->glrc->is_current = FALSE;
1041 glrc->is_current = TRUE;
1042 glrc->thread_id = GetCurrentThreadId();
1043 glrc->hdc = hdc;
1044 OPENGL32_threaddata->glrc = glrc;
1045 }
1046
1047 if (ROSGL_SetContextCallBack( icdTable ) != ERROR_SUCCESS && icdTable == NULL)
1048 {
1049 DBGPRINT( "Warning: ROSGL_SetContextCallBack failed!" );
1050 }
1051
1052 return TRUE;
1053 }
1054
1055
1056 BOOL
1057 APIENTRY
1058 rosglRealizeLayerPalette( HDC hdc, int iLayerPlane, BOOL bRealize )
1059 {
1060 UNIMPLEMENTED;
1061 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
1062 return FALSE;
1063 }
1064
1065
1066 int
1067 APIENTRY
1068 rosglSetLayerPaletteEntries( HDC hdc, int iLayerPlane, int iStart,
1069 int cEntries, CONST COLORREF *pcr )
1070 {
1071 UNIMPLEMENTED;
1072 SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
1073 return 0;
1074 }
1075
1076
1077 /*! \brief Set a DCs pixelformat
1078 *
1079 * \param hdc [IN] Handle to DC for which to set the format
1080 * \param iFormat [IN] Index of the pixelformat to set
1081 * \param pfd [IN] Not sure what this is for
1082 *
1083 * \retval TRUE Success
1084 * \retval FALSE Failure
1085 */
1086 BOOL
1087 WINAPI
1088 rosglSetPixelFormat( HDC hdc, int iFormat, CONST PIXELFORMATDESCRIPTOR *pfd )
1089 {
1090 GLDRIVERDATA *icd;
1091 GLDCDATA *dcdata;
1092
1093 DBGTRACE( "Called!" );
1094
1095 /* load ICD */
1096 icd = ROSGL_ICDForHDC( hdc );
1097 if (icd == NULL)
1098 {
1099 DBGPRINT( "Warning: ICDForHDC() failed" );
1100 return FALSE;
1101 }
1102
1103 /* call ICD */
1104 if (!icd->DrvSetPixelFormat( hdc, iFormat, pfd ))
1105 {
1106 DBGPRINT( "Warning: DrvSetPixelFormat(format=%d) failed (%d)",
1107 iFormat, GetLastError() );
1108 return FALSE;
1109 }
1110
1111 /* store format in private DC data */
1112 dcdata = ROSGL_GetPrivateDCData( hdc );
1113 if (dcdata == NULL)
1114 {
1115 DBGPRINT( "Error: ROSGL_GetPrivateDCData() failed!" );
1116 return FALSE;
1117 }
1118 dcdata->pixel_format = iFormat;
1119
1120 return TRUE;
1121 }
1122
1123
1124 /*! \brief Enable display-list sharing between multiple GLRCs
1125 *
1126 * This will only work if both GLRCs are from the same driver.
1127 *
1128 * \param hglrc1 [IN] GLRC number 1
1129 * \param hglrc2 [IN] GLRC number 2
1130 *
1131 * \retval TRUE Success
1132 * \retval FALSE Failure
1133 */
1134 BOOL
1135 APIENTRY
1136 rosglShareLists( HGLRC hglrc1, HGLRC hglrc2 )
1137 {
1138 GLRC *glrc1 = (GLRC *)hglrc1;
1139 GLRC *glrc2 = (GLRC *)hglrc2;
1140
1141 /* check glrcs */
1142 if (!ROSGL_ContainsContext( glrc1 ))
1143 {
1144 DBGPRINT( "Error: hglrc1 not found!" );
1145 SetLastError( ERROR_INVALID_HANDLE );
1146 return FALSE;
1147 }
1148 if (!ROSGL_ContainsContext( glrc2 ))
1149 {
1150 DBGPRINT( "Error: hglrc2 not found!" );
1151 SetLastError( ERROR_INVALID_HANDLE );
1152 return FALSE;
1153 }
1154
1155 /* I think this is only possible within one ICD */
1156 if (glrc1->icd != glrc2->icd)
1157 {
1158 DBGPRINT( "Error: hglrc1 and hglrc2 use different ICDs!" );
1159 SetLastError( ERROR_INVALID_HANDLE );
1160 return FALSE;
1161 }
1162
1163 /* share lists (call ICD) */
1164 return glrc1->icd->DrvShareLists( glrc1->hglrc, glrc2->hglrc );
1165 }
1166
1167
1168 /*! \brief Flushes GL and swaps front/back buffer if appropriate
1169 *
1170 * \param hdc [IN] Handle to device context to swap buffers for
1171 *
1172 * \retval TRUE Success
1173 * \retval FALSE Failure
1174 */
1175 BOOL
1176 APIENTRY
1177 rosglSwapBuffers( HDC hdc )
1178 {
1179 GLDRIVERDATA *icd = ROSGL_ICDForHDC( hdc );
1180 DBGTRACE( "Called!" );
1181 if (icd != NULL)
1182 {
1183 DBGPRINT( "Swapping buffers!" );
1184 if (!icd->DrvSwapBuffers( hdc ))
1185 {
1186 DBGPRINT( "Error: DrvSwapBuffers failed (%d)", GetLastError() );
1187 return FALSE;
1188 }
1189 return TRUE;
1190 }
1191
1192 /* FIXME: implement own functionality? */
1193 SetLastError( ERROR_INVALID_FUNCTION );
1194 return FALSE;
1195 }
1196
1197
1198 BOOL
1199 APIENTRY
1200 rosglSwapLayerBuffers( HDC hdc, UINT fuPlanes )
1201 {
1202 BOOL ret = FALSE;
1203
1204 if(fuPlanes & WGL_SWAP_MAIN_PLANE)
1205 ret = rosglSwapBuffers(hdc);
1206
1207 if(fuPlanes &~WGL_SWAP_MAIN_PLANE)
1208 DBGTRACE("wglSwapLayerBuffers is not fully implemented\n");
1209
1210 return ret;
1211 }
1212
1213
1214 BOOL
1215 APIENTRY
1216 rosglUseFontBitmapsA( HDC hdc, DWORD first, DWORD count, DWORD listBase )
1217 {
1218 return IntUseFontBitmapsA(hdc, first, count, listBase);
1219 }
1220
1221
1222 BOOL
1223 APIENTRY
1224 rosglUseFontBitmapsW( HDC hdc, DWORD first, DWORD count, DWORD listBase )
1225 {
1226 return IntUseFontBitmapsW(hdc, first, count, listBase);
1227 }
1228
1229 BOOL
1230 APIENTRY
1231 rosglUseFontOutlinesA( HDC hdc, DWORD first, DWORD count, DWORD listBase,
1232 FLOAT deviation, FLOAT extrusion, int format,
1233 GLYPHMETRICSFLOAT *pgmf )
1234 {
1235 return IntUseFontOutlinesA(hdc, first, count, listBase, deviation, extrusion, format, pgmf);
1236 }
1237
1238
1239 BOOL
1240 APIENTRY
1241 rosglUseFontOutlinesW( HDC hdc, DWORD first, DWORD count, DWORD listBase,
1242 FLOAT deviation, FLOAT extrusion, int format,
1243 GLYPHMETRICSFLOAT *pgmf )
1244 {
1245 return IntUseFontOutlinesW(hdc, first, count, listBase, deviation, extrusion, format, pgmf);
1246 }
1247
1248 #ifdef __cplusplus
1249 }; /* extern "C" */
1250 #endif /* __cplusplus */
1251
1252 /* EOF */