xref: /reactos/dll/opengl/opengl32/wgl.c (revision c2c66aff)
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, format %i\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 }
933