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