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