[OPENGL]
[reactos.git] / dll / opengl / opengl32 / wgl.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS
4 * FILE: dll/opengl/opengl32/wgl.c
5 * PURPOSE: OpenGL32 DLL, WGL functions
6 */
7
8 #include "opengl32.h"
9
10 #include <pseh/pseh2.h>
11
12 WINE_DEFAULT_DEBUG_CHANNEL(wgl);
13
14 static CRITICAL_SECTION dc_data_cs = {NULL, -1, 0, 0, 0, 0};
15 static struct wgl_dc_data* dc_data_list = NULL;
16
17 LIST_ENTRY ContextListHead;
18
19 /* FIXME: suboptimal */
20 static
21 struct wgl_dc_data*
22 get_dc_data(HDC hdc)
23 {
24 HWND hwnd = NULL;
25 struct wgl_dc_data* data;
26 DWORD objType = GetObjectType(hdc);
27 ULONG flags = 0;
28 union
29 {
30 HWND hwnd;
31 HDC hdc;
32 HANDLE u;
33 } id;
34
35 /* Look for the right data identifier */
36 if(objType == OBJ_DC)
37 {
38 hwnd = WindowFromDC(hdc);
39 if(!hwnd)
40 return NULL;
41 id.hwnd = hwnd;
42 flags = WGL_DC_OBJ_DC;
43 }
44 else if(objType == OBJ_MEMDC)
45 {
46 id.hdc = hdc;
47 }
48 else
49 {
50 return NULL;
51 }
52
53 EnterCriticalSection(&dc_data_cs);
54 data = dc_data_list;
55 while(data)
56 {
57 if(data->owner.u == id.u)
58 {
59 LeaveCriticalSection(&dc_data_cs);
60 return data;
61 }
62 data = data->next;
63 }
64 data= HeapAlloc(GetProcessHeap(), 0, sizeof(*data));
65 if(!data)
66 {
67 LeaveCriticalSection(&dc_data_cs);
68 return NULL;
69 }
70 /* initialize the structure */
71 data->owner.u = id.u;
72 data->flags = flags;
73 data->pixelformat = 0;
74 data->sw_data = NULL;
75 /* Load the driver */
76 data->icd_data = IntGetIcdData(hdc);
77 /* Get the number of available formats for this DC once and for all */
78 if(data->icd_data)
79 data->nb_icd_formats = data->icd_data->DrvDescribePixelFormat(hdc, 0, 0, NULL);
80 else
81 data->nb_icd_formats = 0;
82 TRACE("ICD %S has %u formats for HDC %x.\n", data->icd_data ? data->icd_data->DriverName : NULL, data->nb_icd_formats, hdc);
83 data->nb_sw_formats = sw_DescribePixelFormat(hdc, 0, 0, NULL);
84 data->next = dc_data_list;
85 dc_data_list = data;
86 LeaveCriticalSection(&dc_data_cs);
87 return data;
88 }
89
90 void release_dc_data(struct wgl_dc_data* dc_data)
91 {
92 (void)dc_data;
93 }
94
95 struct wgl_context* get_context(HGLRC hglrc)
96 {
97 struct wgl_context* context = (struct wgl_context*)hglrc;
98
99 if(!hglrc)
100 return NULL;
101
102 _SEH2_TRY
103 {
104 if(context->magic != 'GLRC')
105 context = NULL;
106 }
107 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
108 {
109 context = NULL;
110 }
111 _SEH2_END;
112
113 return context;
114 }
115
116 INT WINAPI wglDescribePixelFormat(HDC hdc, INT format, UINT size, PIXELFORMATDESCRIPTOR *descr )
117 {
118 struct wgl_dc_data* dc_data = get_dc_data(hdc);
119 INT ret;
120
121 if(!dc_data)
122 {
123 SetLastError(ERROR_INVALID_HANDLE);
124 return 0;
125 }
126
127 ret = dc_data->nb_icd_formats + dc_data->nb_sw_formats;
128
129 if(!descr)
130 {
131 release_dc_data(dc_data);
132 return ret;
133 }
134 if((format == 0) || (format > ret) || (size != sizeof(*descr)))
135 {
136 release_dc_data(dc_data);
137 SetLastError(ERROR_INVALID_PARAMETER);
138 return 0;
139 }
140
141 /* Query ICD if needed */
142 if(format <= dc_data->nb_icd_formats)
143 {
144 struct ICD_Data* icd_data = dc_data->icd_data;
145 /* SetPixelFormat may have NULLified this */
146 if (!icd_data)
147 icd_data = IntGetIcdData(hdc);
148 if(!icd_data->DrvDescribePixelFormat(hdc, format, size, descr))
149 {
150 ret = 0;
151 }
152 }
153 else
154 {
155 /* This is a software format */
156 format -= dc_data->nb_icd_formats;
157 if(!sw_DescribePixelFormat(hdc, format, size, descr))
158 {
159 ret = 0;
160 }
161 }
162
163 release_dc_data(dc_data);
164 return ret;
165 }
166
167 INT WINAPI wglChoosePixelFormat(HDC hdc, const PIXELFORMATDESCRIPTOR* ppfd)
168 {
169 PIXELFORMATDESCRIPTOR format, best;
170 int i, count, best_format;
171 int bestDBuffer = -1, bestStereo = -1;
172
173 TRACE_(wgl)( "%p %p: size %u version %u flags %u type %u color %u %u,%u,%u,%u "
174 "accum %u depth %u stencil %u aux %u\n",
175 hdc, ppfd, ppfd->nSize, ppfd->nVersion, ppfd->dwFlags, ppfd->iPixelType,
176 ppfd->cColorBits, ppfd->cRedBits, ppfd->cGreenBits, ppfd->cBlueBits, ppfd->cAlphaBits,
177 ppfd->cAccumBits, ppfd->cDepthBits, ppfd->cStencilBits, ppfd->cAuxBuffers );
178
179 count = wglDescribePixelFormat( hdc, 0, 0, NULL );
180 if (!count) return 0;
181
182 best_format = 0;
183 best.dwFlags = PFD_GENERIC_FORMAT;
184 best.cAlphaBits = -1;
185 best.cColorBits = -1;
186 best.cDepthBits = -1;
187 best.cStencilBits = -1;
188 best.cAuxBuffers = -1;
189
190 for (i = 1; i <= count; i++)
191 {
192 if (!wglDescribePixelFormat( hdc, i, sizeof(format), &format )) continue;
193
194 if (ppfd->iPixelType != format.iPixelType)
195 {
196 TRACE( "pixel type mismatch for iPixelFormat=%d\n", i );
197 continue;
198 }
199
200 /* only use bitmap capable formats for bitmap rendering */
201 if ((ppfd->dwFlags & PFD_DRAW_TO_BITMAP) != (format.dwFlags & PFD_DRAW_TO_BITMAP))
202 {
203 TRACE( "PFD_DRAW_TO_BITMAP mismatch for iPixelFormat=%d\n", i );
204 continue;
205 }
206
207 /* only use window capable formats for window rendering */
208 if ((ppfd->dwFlags & PFD_DRAW_TO_WINDOW) != (format.dwFlags & PFD_DRAW_TO_WINDOW))
209 {
210 TRACE( "PFD_DRAW_TO_WINDOW mismatch for iPixelFormat=%d\n", i );
211 continue;
212 }
213
214 /* only use opengl capable formats for opengl rendering */
215 if ((ppfd->dwFlags & PFD_SUPPORT_OPENGL) != (format.dwFlags & PFD_SUPPORT_OPENGL))
216 {
217 TRACE( "PFD_SUPPORT_OPENGL mismatch for iPixelFormat=%d\n", i );
218 continue;
219 }
220
221 /* only use GDI capable formats for GDI rendering */
222 if ((ppfd->dwFlags & PFD_SUPPORT_GDI) != (format.dwFlags & PFD_SUPPORT_GDI))
223 {
224 TRACE( "PFD_SUPPORT_GDI mismatch for iPixelFormat=%d\n", i );
225 continue;
226 }
227
228 /* The behavior of PDF_STEREO/PFD_STEREO_DONTCARE and PFD_DOUBLEBUFFER / PFD_DOUBLEBUFFER_DONTCARE
229 * is not very clear on MSDN. They specify that ChoosePixelFormat tries to match pixel formats
230 * with the flag (PFD_STEREO / PFD_DOUBLEBUFFERING) set. Otherwise it says that it tries to match
231 * formats without the given flag set.
232 * A test on Windows using a Radeon 9500pro on WinXP (the driver doesn't support Stereo)
233 * has indicated that a format without stereo is returned when stereo is unavailable.
234 * So in case PFD_STEREO is set, formats that support it should have priority above formats
235 * without. In case PFD_STEREO_DONTCARE is set, stereo is ignored.
236 *
237 * To summarize the following is most likely the correct behavior:
238 * stereo not set -> prefer non-stereo formats, but also accept stereo formats
239 * stereo set -> prefer stereo formats, but also accept non-stereo formats
240 * stereo don't care -> it doesn't matter whether we get stereo or not
241 *
242 * In Wine we will treat non-stereo the same way as don't care because it makes
243 * format selection even more complicated and second drivers with Stereo advertise
244 * each format twice anyway.
245 */
246
247 /* Doublebuffer, see the comments above */
248 if (!(ppfd->dwFlags & PFD_DOUBLEBUFFER_DONTCARE))
249 {
250 if (((ppfd->dwFlags & PFD_DOUBLEBUFFER) != bestDBuffer) &&
251 ((format.dwFlags & PFD_DOUBLEBUFFER) == (ppfd->dwFlags & PFD_DOUBLEBUFFER)))
252 goto found;
253
254 if (bestDBuffer != -1 && (format.dwFlags & PFD_DOUBLEBUFFER) != bestDBuffer) continue;
255 }
256
257 /* Stereo, see the comments above. */
258 if (!(ppfd->dwFlags & PFD_STEREO_DONTCARE))
259 {
260 if (((ppfd->dwFlags & PFD_STEREO) != bestStereo) &&
261 ((format.dwFlags & PFD_STEREO) == (ppfd->dwFlags & PFD_STEREO)))
262 goto found;
263
264 if (bestStereo != -1 && (format.dwFlags & PFD_STEREO) != bestStereo) continue;
265 }
266
267 /* Below we will do a number of checks to select the 'best' pixelformat.
268 * We assume the precedence cColorBits > cAlphaBits > cDepthBits > cStencilBits -> cAuxBuffers.
269 * The code works by trying to match the most important options as close as possible.
270 * When a reasonable format is found, we will try to match more options.
271 * It appears (see the opengl32 test) that Windows opengl drivers ignore options
272 * like cColorBits, cAlphaBits and friends if they are set to 0, so they are considered
273 * as DONTCARE. At least Serious Sam TSE relies on this behavior. */
274
275 if (ppfd->cColorBits)
276 {
277 if (((ppfd->cColorBits > best.cColorBits) && (format.cColorBits > best.cColorBits)) ||
278 ((format.cColorBits >= ppfd->cColorBits) && (format.cColorBits < best.cColorBits)))
279 goto found;
280
281 if (best.cColorBits != format.cColorBits) /* Do further checks if the format is compatible */
282 {
283 TRACE( "color mismatch for iPixelFormat=%d\n", i );
284 continue;
285 }
286 }
287 if (ppfd->cAlphaBits)
288 {
289 if (((ppfd->cAlphaBits > best.cAlphaBits) && (format.cAlphaBits > best.cAlphaBits)) ||
290 ((format.cAlphaBits >= ppfd->cAlphaBits) && (format.cAlphaBits < best.cAlphaBits)))
291 goto found;
292
293 if (best.cAlphaBits != format.cAlphaBits)
294 {
295 TRACE( "alpha mismatch for iPixelFormat=%d\n", i );
296 continue;
297 }
298 }
299 if (ppfd->cDepthBits)
300 {
301 if (((ppfd->cDepthBits > best.cDepthBits) && (format.cDepthBits > best.cDepthBits)) ||
302 ((format.cDepthBits >= ppfd->cDepthBits) && (format.cDepthBits < best.cDepthBits)))
303 goto found;
304
305 if (best.cDepthBits != format.cDepthBits)
306 {
307 TRACE( "depth mismatch for iPixelFormat=%d\n", i );
308 continue;
309 }
310 }
311 if (ppfd->cStencilBits)
312 {
313 if (((ppfd->cStencilBits > best.cStencilBits) && (format.cStencilBits > best.cStencilBits)) ||
314 ((format.cStencilBits >= ppfd->cStencilBits) && (format.cStencilBits < best.cStencilBits)))
315 goto found;
316
317 if (best.cStencilBits != format.cStencilBits)
318 {
319 TRACE( "stencil mismatch for iPixelFormat=%d\n", i );
320 continue;
321 }
322 }
323 if (ppfd->cAuxBuffers)
324 {
325 if (((ppfd->cAuxBuffers > best.cAuxBuffers) && (format.cAuxBuffers > best.cAuxBuffers)) ||
326 ((format.cAuxBuffers >= ppfd->cAuxBuffers) && (format.cAuxBuffers < best.cAuxBuffers)))
327 goto found;
328
329 if (best.cAuxBuffers != format.cAuxBuffers)
330 {
331 TRACE( "aux mismatch for iPixelFormat=%d\n", i );
332 continue;
333 }
334 }
335 continue;
336
337 found:
338 /* Prefer HW accelerated formats */
339 if ((format.dwFlags & PFD_GENERIC_FORMAT) && !(best.dwFlags & PFD_GENERIC_FORMAT))
340 continue;
341 best_format = i;
342 best = format;
343 bestDBuffer = format.dwFlags & PFD_DOUBLEBUFFER;
344 bestStereo = format.dwFlags & PFD_STEREO;
345 }
346
347 TRACE( "returning %u\n", best_format );
348 return best_format;
349 }
350
351 BOOL WINAPI wglCopyContext(HGLRC hglrcSrc, HGLRC hglrcDst, UINT mask)
352 {
353 struct wgl_context* ctx_src = get_context(hglrcSrc);
354 struct wgl_context* ctx_dst = get_context(hglrcDst);
355
356 if(!ctx_src || !ctx_dst)
357 {
358 SetLastError(ERROR_INVALID_HANDLE);
359 return FALSE;
360 }
361
362 /* Check this is the same pixel format */
363 if((ctx_dst->icd_data != ctx_src->icd_data) ||
364 (ctx_dst->pixelformat != ctx_src->pixelformat))
365 {
366 SetLastError(ERROR_INVALID_PIXEL_FORMAT);
367 return FALSE;
368 }
369
370 if(ctx_src->icd_data)
371 return ctx_src->icd_data->DrvCopyContext(ctx_src->dhglrc, ctx_dst->dhglrc, mask);
372
373 return sw_CopyContext(ctx_src->dhglrc, ctx_dst->dhglrc, mask);
374 }
375
376 HGLRC WINAPI wglCreateContext(HDC hdc)
377 {
378 struct wgl_dc_data* dc_data = get_dc_data(hdc);
379 struct wgl_context* context;
380 DHGLRC dhglrc;
381
382 TRACE("Creating context for %p.\n", hdc);
383
384 if(!dc_data)
385 {
386 WARN("Not a DC handle!\n");
387 SetLastError(ERROR_INVALID_HANDLE);
388 return NULL;
389 }
390
391 if(!dc_data->pixelformat)
392 {
393 WARN("Pixel format not set!\n");
394 SetLastError(ERROR_INVALID_PIXEL_FORMAT);
395 return NULL;
396 }
397
398 if(!dc_data->icd_data)
399 {
400 TRACE("Calling SW implementation.\n");
401 dhglrc = sw_CreateContext(dc_data);
402 TRACE("done\n");
403 }
404 else
405 {
406 TRACE("Calling ICD.\n");
407 dhglrc = dc_data->icd_data->DrvCreateContext(hdc);
408 }
409
410 if(!dhglrc)
411 {
412 WARN("Failed!\n");
413 SetLastError(ERROR_INVALID_PIXEL_FORMAT);
414 return NULL;
415 }
416
417 context = HeapAlloc(GetProcessHeap(), 0, sizeof(*context));
418 if(!context)
419 {
420 WARN("Failed to allocate a context!\n");
421 if(!dc_data->icd_data)
422 sw_DeleteContext(dhglrc);
423 else
424 dc_data->icd_data->DrvDeleteContext(dhglrc);
425 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
426 return NULL;
427 }
428 /* Copy info from the DC data */
429 context->dhglrc = dhglrc;
430 context->icd_data = dc_data->icd_data;
431 context->pixelformat = dc_data->pixelformat;
432 context->thread_id = 0;
433
434 /* Insert into the list */
435 InsertTailList(&ContextListHead, &context->ListEntry);
436
437 context->magic = 'GLRC';
438 TRACE("Success!\n");
439 return (HGLRC)context;
440 }
441
442 HGLRC WINAPI wglCreateLayerContext(HDC hdc, int iLayerPlane)
443 {
444 struct wgl_dc_data* dc_data = get_dc_data(hdc);
445 struct wgl_context* context;
446 DHGLRC dhglrc;
447
448 if(!dc_data)
449 {
450 SetLastError(ERROR_INVALID_HANDLE);
451 return NULL;
452 }
453
454 if(!dc_data->pixelformat)
455 {
456 release_dc_data(dc_data);
457 SetLastError(ERROR_INVALID_PIXEL_FORMAT);
458 return NULL;
459 }
460
461 if(!dc_data->icd_data)
462 {
463 if(iLayerPlane != 0)
464 {
465 /* Not supported in SW implementation */
466 release_dc_data(dc_data);
467 SetLastError(ERROR_INVALID_PIXEL_FORMAT);
468 return NULL;
469 }
470 dhglrc = sw_CreateContext(dc_data);
471 }
472 else
473 {
474 dhglrc = dc_data->icd_data->DrvCreateLayerContext(hdc, iLayerPlane);
475 }
476
477 if(!dhglrc)
478 {
479 release_dc_data(dc_data);
480 SetLastError(ERROR_INVALID_PIXEL_FORMAT);
481 return NULL;
482 }
483
484 context = HeapAlloc(GetProcessHeap(), 0, sizeof(*context));
485 if(!context)
486 {
487 if(!dc_data->icd_data)
488 sw_DeleteContext(dhglrc);
489 else
490 dc_data->icd_data->DrvDeleteContext(dhglrc);
491 release_dc_data(dc_data);
492 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
493 return NULL;
494 }
495 /* Copy info from the DC data */
496 context->dhglrc = dhglrc;
497 context->icd_data = dc_data->icd_data;
498 context->pixelformat = dc_data->pixelformat;
499 context->thread_id = 0;
500
501 context->magic = 'GLRC';
502
503 release_dc_data(dc_data);
504 return (HGLRC)context;
505 }
506
507 BOOL WINAPI wglDeleteContext(HGLRC hglrc)
508 {
509 struct wgl_context* context = get_context(hglrc);
510 LONG thread_id = GetCurrentThreadId();
511
512 if(!context)
513 {
514 SetLastError(ERROR_INVALID_HANDLE);
515 return FALSE;
516 }
517
518 /* Own this context before touching it */
519 if(InterlockedCompareExchange(&context->thread_id, thread_id, 0) != 0)
520 {
521 /* We can't delete a context current to another thread */
522 if(context->thread_id != thread_id)
523 {
524 SetLastError(ERROR_BUSY);
525 return FALSE;
526 }
527
528 /* This is in our thread. Release and try again */
529 if(!wglMakeCurrent(NULL, NULL))
530 return FALSE;
531 return wglDeleteContext(hglrc);
532 }
533
534 if(context->icd_data)
535 context->icd_data->DrvDeleteContext(context->dhglrc);
536 else
537 sw_DeleteContext(context->dhglrc);
538
539 context->magic = 0;
540 RemoveEntryList(&context->ListEntry);
541 HeapFree(GetProcessHeap(), 0, context);
542
543 return TRUE;
544 }
545
546 BOOL WINAPI wglDescribeLayerPlane(HDC hdc,
547 int iPixelFormat,
548 int iLayerPlane,
549 UINT nBytes,
550 LPLAYERPLANEDESCRIPTOR plpd)
551 {
552 struct wgl_dc_data* dc_data = get_dc_data(hdc);
553
554 if(!dc_data)
555 {
556 SetLastError(ERROR_INVALID_HANDLE);
557 return FALSE;
558 }
559
560 if(iPixelFormat <= dc_data->nb_icd_formats)
561 return dc_data->icd_data->DrvDescribeLayerPlane(hdc, iPixelFormat, iLayerPlane, nBytes, plpd);
562
563 /* SW implementation doesn't support this */
564 return FALSE;
565 }
566
567 HGLRC WINAPI wglGetCurrentContext(void)
568 {
569 return IntGetCurrentRC();
570 }
571
572 HDC WINAPI wglGetCurrentDC(void)
573 {
574 return IntGetCurrentDC();
575 }
576
577 PROC WINAPI wglGetDefaultProcAddress(LPCSTR lpszProc)
578 {
579 /* undocumented... */
580 return NULL;
581 }
582
583 int WINAPI wglGetLayerPaletteEntries(HDC hdc, int iLayerPlane, int iStart, int cEntries, COLORREF* pcr )
584 {
585 struct wgl_dc_data* dc_data = get_dc_data(hdc);
586
587 if(!dc_data)
588 {
589 SetLastError(ERROR_INVALID_HANDLE);
590 return 0;
591 }
592
593 if(!dc_data->pixelformat)
594 {
595 SetLastError(ERROR_INVALID_PIXEL_FORMAT);
596 return 0;
597 }
598
599 if(dc_data->icd_data)
600 return dc_data->icd_data->DrvGetLayerPaletteEntries(hdc, iLayerPlane, iStart, cEntries, pcr);
601
602 /* SW implementation doesn't support this */
603 return 0;
604 }
605
606 INT WINAPI wglGetPixelFormat(HDC hdc)
607 {
608 INT ret;
609 struct wgl_dc_data* dc_data = get_dc_data(hdc);
610
611 if(!dc_data)
612 {
613 SetLastError(ERROR_INVALID_HANDLE);
614 return 0;
615 }
616
617 ret = dc_data->pixelformat;
618 release_dc_data(dc_data);
619 return ret;
620 }
621
622 PROC WINAPI wglGetProcAddress(LPCSTR name)
623 {
624 struct wgl_context* context = get_context(IntGetCurrentRC());
625 if(!context)
626 return NULL;
627
628 /* This shall fail for opengl 1.1 functions */
629 #define USE_GL_FUNC(func, w, x, y, z) if(!strcmp(name, "gl" #func)) return NULL;
630 #include "glfuncs.h"
631
632 /* Forward */
633 if(context->icd_data)
634 return context->icd_data->DrvGetProcAddress(name);
635 return sw_GetProcAddress(name);
636 }
637
638 void APIENTRY set_api_table(const GLCLTPROCTABLE* table)
639 {
640 IntSetCurrentDispatchTable(&table->glDispatchTable);
641 }
642
643 BOOL WINAPI wglMakeCurrent(HDC hdc, HGLRC hglrc)
644 {
645 struct wgl_context* ctx = get_context(hglrc);
646 struct wgl_context* old_ctx = get_context(IntGetCurrentRC());
647 const GLCLTPROCTABLE* apiTable;
648 LONG thread_id = (LONG)GetCurrentThreadId();
649
650 if(ctx)
651 {
652 struct wgl_dc_data* dc_data = get_dc_data(hdc);
653 if(!dc_data)
654 {
655 ERR("wglMakeCurrent was passed an invalid DC handle.\n");
656 SetLastError(ERROR_INVALID_HANDLE);
657 return FALSE;
658 }
659
660 /* Check compatibility */
661 if((ctx->icd_data != dc_data->icd_data) || (ctx->pixelformat != dc_data->pixelformat))
662 {
663 /* That's bad, man */
664 ERR("HGLRC %p and HDC %p are not compatible.\n", hglrc, hdc);
665 release_dc_data(dc_data);
666 SetLastError(ERROR_INVALID_HANDLE);
667 return FALSE;
668 }
669
670 /* Set the thread ID */
671 if(InterlockedCompareExchange(&ctx->thread_id, thread_id, 0) != 0)
672 {
673 /* Already current for a thread. Maybe it's us ? */
674 release_dc_data(dc_data);
675 if(ctx->thread_id != thread_id)
676 SetLastError(ERROR_BUSY);
677 return (ctx->thread_id == thread_id);
678 }
679
680 if(old_ctx)
681 {
682 /* Unset it */
683 if(old_ctx->icd_data)
684 old_ctx->icd_data->DrvReleaseContext(old_ctx->dhglrc);
685 else
686 sw_ReleaseContext(old_ctx->dhglrc);
687 InterlockedExchange(&old_ctx->thread_id, 0);
688 }
689
690 /* Call the ICD or SW implementation */
691 if(ctx->icd_data)
692 {
693 apiTable = ctx->icd_data->DrvSetContext(hdc, ctx->dhglrc, set_api_table);
694 if(!apiTable)
695 {
696 ERR("DrvSetContext failed!\n");
697 /* revert */
698 InterlockedExchange(&ctx->thread_id, 0);
699 IntSetCurrentDispatchTable(&StubTable.glDispatchTable);
700 SetLastError(ERROR_INVALID_PARAMETER);
701 return FALSE;
702 }
703 set_api_table(apiTable);
704 /* Make it current */
705 IntMakeCurrent(hglrc, hdc, dc_data);
706 }
707 else
708 {
709 /* We must set current before, SW implementation relies on it */
710 IntMakeCurrent(hglrc, hdc, dc_data);
711 if(!sw_SetContext(dc_data, ctx->dhglrc))
712 {
713 ERR("sw_SetContext failed!\n");
714 /* revert */
715 IntMakeCurrent(NULL, NULL, NULL);
716 InterlockedExchange(&ctx->thread_id, 0);
717 SetLastError(ERROR_INVALID_PARAMETER);
718 return FALSE;
719 }
720 }
721 }
722 else if(old_ctx)
723 {
724 if(old_ctx->icd_data)
725 old_ctx->icd_data->DrvReleaseContext(old_ctx->dhglrc);
726 else
727 sw_ReleaseContext(old_ctx->dhglrc);
728 InterlockedExchange(&old_ctx->thread_id, 0);
729 /* Unset it */
730 IntMakeCurrent(NULL, NULL, NULL);
731 /* Reset the no-op table */
732 set_api_table(&StubTable);
733 /* Test conformance (extreme cases) */
734 return hglrc == NULL;
735 }
736 else
737 {
738 /* Winetest conformance */
739 if (GetObjectType( hdc ) != OBJ_DC && GetObjectType( hdc ) != OBJ_MEMDC)
740 {
741 ERR( "Error: hdc is not a DC handle!\n");
742 SetLastError( ERROR_INVALID_HANDLE );
743 return FALSE;
744 }
745 }
746
747 return TRUE;
748 }
749
750 BOOL WINAPI wglRealizeLayerPalette(HDC hdc,
751 int iLayerPlane,
752 BOOL bRealize)
753 {
754 struct wgl_dc_data* dc_data = get_dc_data(hdc);
755
756 if(!dc_data)
757 {
758 SetLastError(ERROR_INVALID_HANDLE);
759 return FALSE;
760 }
761
762 if(!dc_data->pixelformat)
763 {
764 SetLastError(ERROR_INVALID_PIXEL_FORMAT);
765 return FALSE;
766 }
767
768 if(dc_data->icd_data)
769 return dc_data->icd_data->DrvRealizeLayerPalette(hdc, iLayerPlane, bRealize);
770
771 /* SW implementation doesn't support this */
772 return FALSE;
773 }
774
775 int WINAPI wglSetLayerPaletteEntries(HDC hdc,
776 int iLayerPlane,
777 int iStart,
778 int cEntries,
779 const COLORREF *pcr)
780 {
781 struct wgl_dc_data* dc_data = get_dc_data(hdc);
782
783 if(!dc_data)
784 {
785 SetLastError(ERROR_INVALID_HANDLE);
786 return 0;
787 }
788
789 if(!dc_data->pixelformat)
790 {
791 SetLastError(ERROR_INVALID_PIXEL_FORMAT);
792 return 0;
793 }
794
795 if(dc_data->icd_data)
796 return dc_data->icd_data->DrvSetLayerPaletteEntries(hdc, iLayerPlane, iStart, cEntries, pcr);
797
798 /* SW implementation doesn't support this */
799 return 0;
800 }
801
802 BOOL WINAPI wglSetPixelFormat(HDC hdc, INT format, const PIXELFORMATDESCRIPTOR *descr)
803 {
804 struct wgl_dc_data* dc_data = get_dc_data(hdc);
805 INT sw_format;
806 BOOL ret;
807
808 TRACE("HDC %p, format %i.\n", hdc, format);
809
810 if(!dc_data)
811 {
812 WARN("Not a valid DC!.\n");
813 SetLastError(ERROR_INVALID_HANDLE);
814 return FALSE;
815 }
816
817 if(!format)
818 {
819 WARN("format == 0!\n");
820 SetLastError(ERROR_INVALID_PARAMETER);
821 return FALSE;
822 }
823
824 if(dc_data->pixelformat)
825 {
826 TRACE("DC format already set, %i.\n", dc_data->pixelformat);
827 return (format == dc_data->pixelformat);
828 }
829
830 if(format <= dc_data->nb_icd_formats)
831 {
832 TRACE("Calling ICD.\n");
833 ret = dc_data->icd_data->DrvSetPixelFormat(hdc, format);
834 if(ret)
835 {
836 TRACE("Success!\n");
837 dc_data->pixelformat = format;
838 }
839 return ret;
840 }
841
842 sw_format = format - dc_data->nb_icd_formats;
843 if(sw_format <= dc_data->nb_sw_formats)
844 {
845 TRACE("Calling SW implementation.\n");
846 ret = sw_SetPixelFormat(hdc, dc_data, sw_format);
847 if(ret)
848 {
849 TRACE("Success!\n");
850 /* This is now officially a software-only HDC */
851 dc_data->icd_data = NULL;
852 dc_data->pixelformat = format;
853 }
854 return ret;
855 }
856
857 TRACE("Invalid pixel format!\n");
858 SetLastError(ERROR_INVALID_PARAMETER);
859 return FALSE;
860 }
861
862 BOOL WINAPI wglShareLists(HGLRC hglrcSrc, HGLRC hglrcDst)
863 {
864 struct wgl_context* ctx_src = get_context(hglrcSrc);
865 struct wgl_context* ctx_dst = get_context(hglrcDst);
866
867 if(!ctx_src || !ctx_dst)
868 {
869 SetLastError(ERROR_INVALID_HANDLE);
870 return FALSE;
871 }
872
873 /* Check this is the same pixel format */
874 if((ctx_dst->icd_data != ctx_src->icd_data) ||
875 (ctx_dst->pixelformat != ctx_src->pixelformat))
876 {
877 SetLastError(ERROR_INVALID_PIXEL_FORMAT);
878 return FALSE;
879 }
880
881 if(ctx_src->icd_data)
882 return ctx_src->icd_data->DrvShareLists(ctx_src->dhglrc, ctx_dst->dhglrc);
883
884 return sw_ShareLists(ctx_src->dhglrc, ctx_dst->dhglrc);
885 }
886
887 BOOL WINAPI DECLSPEC_HOTPATCH wglSwapBuffers(HDC hdc)
888 {
889 struct wgl_dc_data* dc_data = get_dc_data(hdc);
890
891 if(!dc_data)
892 {
893 SetLastError(ERROR_INVALID_HANDLE);
894 return FALSE;
895 }
896
897 if(!dc_data->pixelformat)
898 {
899 SetLastError(ERROR_INVALID_PIXEL_FORMAT);
900 return FALSE;
901 }
902
903 if(dc_data->icd_data)
904 return dc_data->icd_data->DrvSwapBuffers(hdc);
905
906 return sw_SwapBuffers(hdc, dc_data);
907 }
908
909 BOOL WINAPI wglSwapLayerBuffers(HDC hdc, UINT fuPlanes)
910 {
911 return FALSE;
912 }
913
914 DWORD WINAPI wglSwapMultipleBuffers(UINT count, CONST WGLSWAP * toSwap)
915 {
916 return 0;
917 }
918
919 /* Clean up on DLL unload */
920 void
921 IntDeleteAllContexts(void)
922 {
923 struct wgl_context* context;
924 LIST_ENTRY* Entry = ContextListHead.Flink;
925
926 while (Entry != &ContextListHead)
927 {
928 context = CONTAINING_RECORD(Entry, struct wgl_context, ListEntry);
929 wglDeleteContext((HGLRC)context);
930 Entry = Entry->Flink;
931 }
932 }