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