[OPENGL32] Fix wglDescribePixelFormat
[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_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 if (GetObjectType( hdc ) != OBJ_DC && GetObjectType( hdc ) != OBJ_MEMDC)
746 {
747 ERR( "Error: hdc is not a DC handle!\n");
748 SetLastError( ERROR_INVALID_HANDLE );
749 return FALSE;
750 }
751 }
752
753 return TRUE;
754 }
755
756 BOOL WINAPI wglRealizeLayerPalette(HDC hdc,
757 int iLayerPlane,
758 BOOL bRealize)
759 {
760 struct wgl_dc_data* dc_data = get_dc_data(hdc);
761
762 if(!dc_data)
763 {
764 SetLastError(ERROR_INVALID_HANDLE);
765 return FALSE;
766 }
767
768 if(!dc_data->pixelformat)
769 {
770 SetLastError(ERROR_INVALID_PIXEL_FORMAT);
771 return FALSE;
772 }
773
774 if(dc_data->icd_data)
775 return dc_data->icd_data->DrvRealizeLayerPalette(hdc, iLayerPlane, bRealize);
776
777 /* SW implementation doesn't support this */
778 return FALSE;
779 }
780
781 int WINAPI wglSetLayerPaletteEntries(HDC hdc,
782 int iLayerPlane,
783 int iStart,
784 int cEntries,
785 const COLORREF *pcr)
786 {
787 struct wgl_dc_data* dc_data = get_dc_data(hdc);
788
789 if(!dc_data)
790 {
791 SetLastError(ERROR_INVALID_HANDLE);
792 return 0;
793 }
794
795 if(!dc_data->pixelformat)
796 {
797 SetLastError(ERROR_INVALID_PIXEL_FORMAT);
798 return 0;
799 }
800
801 if(dc_data->icd_data)
802 return dc_data->icd_data->DrvSetLayerPaletteEntries(hdc, iLayerPlane, iStart, cEntries, pcr);
803
804 /* SW implementation doesn't support this */
805 return 0;
806 }
807
808 BOOL WINAPI wglSetPixelFormat(HDC hdc, INT format, const PIXELFORMATDESCRIPTOR *descr)
809 {
810 struct wgl_dc_data* dc_data = get_dc_data(hdc);
811 INT sw_format;
812 BOOL ret;
813
814 TRACE("HDC %p, format %i.\n", hdc, format);
815
816 if(!dc_data)
817 {
818 WARN("Not a valid DC!.\n");
819 SetLastError(ERROR_INVALID_HANDLE);
820 return FALSE;
821 }
822
823 if(!format)
824 {
825 WARN("format == 0!\n");
826 SetLastError(ERROR_INVALID_PARAMETER);
827 return FALSE;
828 }
829
830 if(dc_data->pixelformat)
831 {
832 TRACE("DC format already set, %i.\n", dc_data->pixelformat);
833 return (format == dc_data->pixelformat);
834 }
835
836 if(format <= dc_data->nb_icd_formats)
837 {
838 TRACE("Calling ICD.\n");
839 ret = dc_data->icd_data->DrvSetPixelFormat(hdc, format);
840 if(ret)
841 {
842 TRACE("Success!\n");
843 dc_data->pixelformat = format;
844 }
845 return ret;
846 }
847
848 sw_format = format - dc_data->nb_icd_formats;
849 if(sw_format <= dc_data->nb_sw_formats)
850 {
851 TRACE("Calling SW implementation.\n");
852 ret = sw_SetPixelFormat(hdc, dc_data, sw_format);
853 if(ret)
854 {
855 TRACE("Success!\n");
856 /* This is now officially a software-only HDC */
857 dc_data->icd_data = NULL;
858 dc_data->pixelformat = format;
859 }
860 return ret;
861 }
862
863 TRACE("Invalid pixel format!\n");
864 SetLastError(ERROR_INVALID_PARAMETER);
865 return FALSE;
866 }
867
868 BOOL WINAPI wglShareLists(HGLRC hglrcSrc, HGLRC hglrcDst)
869 {
870 struct wgl_context* ctx_src = get_context(hglrcSrc);
871 struct wgl_context* ctx_dst = get_context(hglrcDst);
872
873 if(!ctx_src || !ctx_dst)
874 {
875 SetLastError(ERROR_INVALID_HANDLE);
876 return FALSE;
877 }
878
879 /* Check this is the same pixel format */
880 if((ctx_dst->icd_data != ctx_src->icd_data) ||
881 (ctx_dst->pixelformat != ctx_src->pixelformat))
882 {
883 SetLastError(ERROR_INVALID_PIXEL_FORMAT);
884 return FALSE;
885 }
886
887 if(ctx_src->icd_data)
888 return ctx_src->icd_data->DrvShareLists(ctx_src->dhglrc, ctx_dst->dhglrc);
889
890 return sw_ShareLists(ctx_src->dhglrc, ctx_dst->dhglrc);
891 }
892
893 BOOL WINAPI DECLSPEC_HOTPATCH wglSwapBuffers(HDC hdc)
894 {
895 struct wgl_dc_data* dc_data = get_dc_data(hdc);
896
897 if(!dc_data)
898 {
899 SetLastError(ERROR_INVALID_HANDLE);
900 return FALSE;
901 }
902
903 if(!dc_data->pixelformat)
904 {
905 SetLastError(ERROR_INVALID_PIXEL_FORMAT);
906 return FALSE;
907 }
908
909 if(dc_data->icd_data)
910 return dc_data->icd_data->DrvSwapBuffers(hdc);
911
912 return sw_SwapBuffers(hdc, dc_data);
913 }
914
915 BOOL WINAPI wglSwapLayerBuffers(HDC hdc, UINT fuPlanes)
916 {
917 return FALSE;
918 }
919
920 DWORD WINAPI wglSwapMultipleBuffers(UINT count, CONST WGLSWAP * toSwap)
921 {
922 return 0;
923 }
924
925 /* Clean up on DLL unload */
926 void
927 IntDeleteAllContexts(void)
928 {
929 struct wgl_context* context;
930 LIST_ENTRY* Entry = ContextListHead.Flink;
931
932 while (Entry != &ContextListHead)
933 {
934 context = CONTAINING_RECORD(Entry, struct wgl_context, ListEntry);
935 wglDeleteContext((HGLRC)context);
936 Entry = Entry->Flink;
937 }
938 }