1 /* GDK - The GIMP Drawing Kit
2 *
3 * gdkglcontext-win32.c: Win32 specific OpenGL wrappers
4 *
5 * Copyright © 2014 Emmanuele Bassi
6 * Copyright © 2014 Alexander Larsson
7 * Copyright © 2014 Chun-wei Fan
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
18 *
19 * You should have received a copy of the GNU Library General Public
20 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "config.h"
24
25 #include "gdkprivate-win32.h"
26 #include "gdkwindow-win32.h"
27 #include "gdkglcontext-win32.h"
28 #include "gdkdisplay-win32.h"
29
30 #include "gdkwin32display.h"
31 #include "gdkwin32glcontext.h"
32 #include "gdkwin32misc.h"
33 #include "gdkwin32screen.h"
34 #include "gdkwin32window.h"
35
36 #include "gdkglcontext.h"
37 #include "gdkwindow.h"
38 #include "gdkinternals.h"
39 #include "gdkintl.h"
40
41 #include <cairo.h>
42 #include <epoxy/wgl.h>
43
44 #ifdef GDK_WIN32_ENABLE_EGL
45 # include <epoxy/egl.h>
46 #endif
47
48 struct _GdkWin32GLContext
49 {
50 GdkGLContext parent_instance;
51
52 HDC gl_hdc;
53 guint need_alpha_bits : 1;
54 guint is_attached : 1;
55 guint do_frame_sync : 1;
56 guint do_blit_swap : 1;
57 };
58
59 struct _GdkWin32GLContextClass
60 {
61 GdkGLContextClass parent_class;
62 };
63
G_DEFINE_TYPE(GdkWin32GLContext,gdk_win32_gl_context,GDK_TYPE_GL_CONTEXT)64 G_DEFINE_TYPE (GdkWin32GLContext, gdk_win32_gl_context, GDK_TYPE_GL_CONTEXT)
65
66 static void
67 gdk_win32_gl_context_cleanup (GdkGLContext *context)
68 {
69 GdkWindow *window = gdk_gl_context_get_window (context);
70
71 if (window != NULL)
72 {
73 GdkWindowImplWin32 *impl = NULL;
74
75 ReleaseDC (GDK_WINDOW_HWND (window), GDK_WIN32_GL_CONTEXT(context)->gl_hdc);
76 impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
77
78 if (impl->suppress_layered > 0)
79 impl->suppress_layered--;
80
81 /* If we don't have any window that forces layered windows off,
82 * trigger update_style_bits() to enable layered windows again
83 */
84 if (impl->suppress_layered == 0)
85 _gdk_win32_window_update_style_bits (window);
86 }
87 }
88
89 static void
gdk_gl_blit_region(GdkWindow * window,cairo_region_t * region,gboolean use_intel_workaround)90 gdk_gl_blit_region (GdkWindow *window,
91 cairo_region_t *region,
92 gboolean use_intel_workaround)
93 {
94 int n_rects, i, j;
95 int scale = gdk_window_get_scale_factor (window);
96 int wh = gdk_window_get_height (window);
97 cairo_rectangle_int_t rect;
98 int retries = 0;
99
100 if (use_intel_workaround)
101 retries = 1;
102
103 n_rects = cairo_region_num_rectangles (region);
104
105 for (i = 0; i <= retries; i ++)
106 {
107 for (j = 0; j < n_rects; j++)
108 {
109 cairo_region_get_rectangle (region, j, &rect);
110 glScissor (rect.x * scale, (wh - rect.y - rect.height) * scale, rect.width * scale, rect.height * scale);
111 glBlitFramebuffer (rect.x * scale, (wh - rect.y - rect.height) * scale, (rect.x + rect.width) * scale, (wh - rect.y) * scale,
112 rect.x * scale, (wh - rect.y - rect.height) * scale, (rect.x + rect.width) * scale, (wh - rect.y) * scale,
113 GL_COLOR_BUFFER_BIT, GL_NEAREST);
114 }
115
116 if (retries > 0 && i < retries)
117 glFlush ();
118 }
119 }
120
121 /* Section on WGL usage */
122 struct _GdkWin32GLContextWGL
123 {
124 GdkWin32GLContext parent_instance;
125
126 HGLRC wgl_context;
127 };
128
129 typedef struct _GdkWin32GLContextClass GdkWin32GLContextWGLClass;
130 typedef struct _GdkWin32GLContextWGL GdkWin32GLContextWGL;
131
132 G_DEFINE_TYPE (GdkWin32GLContextWGL, gdk_win32_gl_context_wgl, GDK_TYPE_WIN32_GL_CONTEXT)
133
134 #define GDK_TYPE_WIN32_GL_CONTEXT_WGL (gdk_win32_gl_context_wgl_get_type())
135 #define GDK_WIN32_GL_CONTEXT_WGL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_WIN32_GL_CONTEXT_WGL, GdkWin32GLContextWGL))
136 #define GDK_IS_WIN32_GL_CONTEXT_WGL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_WIN32_GL_CONTEXT_WGL))
137
138 typedef struct
139 {
140 ATOM wc_atom;
141 HWND hwnd;
142 HDC hdc;
143 HGLRC hglrc;
144 gboolean inited;
145 } GdkWGLDummy;
146
147 static void
destroy_dummy_gl_context(GdkWGLDummy dummy)148 destroy_dummy_gl_context (GdkWGLDummy dummy)
149 {
150 if (dummy.hglrc != NULL)
151 {
152 wglDeleteContext (dummy.hglrc);
153 dummy.hglrc = NULL;
154 }
155 if (dummy.hdc != NULL)
156 {
157 DeleteDC (dummy.hdc);
158 dummy.hdc = NULL;
159 }
160 if (dummy.hwnd != NULL)
161 {
162 DestroyWindow (dummy.hwnd);
163 dummy.hwnd = NULL;
164 }
165 if (dummy.wc_atom != 0)
166 {
167 UnregisterClass (MAKEINTATOM (dummy.wc_atom), GetModuleHandle (NULL));
168 dummy.wc_atom = 0;
169 }
170 dummy.inited = FALSE;
171 }
172
173 /* Yup, we need to create a dummy window for the dummy WGL context */
174 static void
get_dummy_window_hwnd(GdkWGLDummy * dummy)175 get_dummy_window_hwnd (GdkWGLDummy *dummy)
176 {
177 WNDCLASSEX dummy_wc;
178
179 memset (&dummy_wc, 0, sizeof (WNDCLASSEX));
180
181 dummy_wc.cbSize = sizeof( WNDCLASSEX );
182 dummy_wc.style = CS_OWNDC;
183 dummy_wc.lpfnWndProc = (WNDPROC) DefWindowProc;
184 dummy_wc.cbClsExtra = 0;
185 dummy_wc.cbWndExtra = 0;
186 dummy_wc.hInstance = GetModuleHandle( NULL );
187 dummy_wc.hIcon = 0;
188 dummy_wc.hCursor = NULL;
189 dummy_wc.hbrBackground = 0;
190 dummy_wc.lpszMenuName = 0;
191 dummy_wc.lpszClassName = "dummy";
192 dummy_wc.hIconSm = 0;
193
194 dummy->wc_atom = RegisterClassEx (&dummy_wc);
195
196 dummy->hwnd =
197 CreateWindowEx (WS_EX_APPWINDOW,
198 MAKEINTATOM (dummy->wc_atom),
199 "",
200 WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
201 0,
202 0,
203 0,
204 0,
205 NULL,
206 NULL,
207 GetModuleHandle (NULL),
208 NULL);
209 }
210
211 static gint
212 gdk_init_dummy_context (GdkWGLDummy *dummy,
213 const gboolean need_alpha_bits);
214
215 #define PIXEL_ATTRIBUTES 19
216
217 static gint
get_wgl_pfd(HDC hdc,const gboolean need_alpha_bits,PIXELFORMATDESCRIPTOR * pfd,GdkWin32Display * display)218 get_wgl_pfd (HDC hdc,
219 const gboolean need_alpha_bits,
220 PIXELFORMATDESCRIPTOR *pfd,
221 GdkWin32Display *display)
222 {
223 gint best_pf = 0;
224
225 pfd->nSize = sizeof (PIXELFORMATDESCRIPTOR);
226
227 if (display != NULL && display->hasWglARBPixelFormat)
228 {
229 GdkWGLDummy dummy;
230 UINT num_formats;
231 gint colorbits = GetDeviceCaps (hdc, BITSPIXEL);
232 guint extra_fields = 1;
233 gint i = 0;
234 int pixelAttribs[PIXEL_ATTRIBUTES];
235 int alpha_idx = 0;
236
237 /* Save up the HDC and HGLRC that we are currently using, to restore back to it when we are done here */
238 HDC hdc_current = wglGetCurrentDC ();
239 HGLRC hglrc_current = wglGetCurrentContext ();
240
241 if (display->hasWglARBmultisample)
242 {
243 /* 2 pairs of values needed for multisampling/AA support */
244 extra_fields += 2 * 2;
245 }
246
247 /* Update PIXEL_ATTRIBUTES above if any groups are added here! */
248 /* one group contains a value pair for both pixelAttribs and pixelAttribsNoAlpha */
249 pixelAttribs[i] = WGL_DRAW_TO_WINDOW_ARB;
250 pixelAttribs[i++] = GL_TRUE;
251
252 pixelAttribs[i++] = WGL_SUPPORT_OPENGL_ARB;
253 pixelAttribs[i++] = GL_TRUE;
254
255 pixelAttribs[i++] = WGL_DOUBLE_BUFFER_ARB;
256 pixelAttribs[i++] = GL_TRUE;
257
258 pixelAttribs[i++] = WGL_ACCELERATION_ARB;
259 pixelAttribs[i++] = WGL_FULL_ACCELERATION_ARB;
260
261 pixelAttribs[i++] = WGL_PIXEL_TYPE_ARB;
262 pixelAttribs[i++] = WGL_TYPE_RGBA_ARB;
263
264 pixelAttribs[i++] = WGL_COLOR_BITS_ARB;
265 pixelAttribs[i++] = colorbits;
266
267 /* end of "Update PIXEL_ATTRIBUTES above if any groups are added here!" */
268
269 if (display->hasWglARBmultisample)
270 {
271 pixelAttribs[i++] = WGL_SAMPLE_BUFFERS_ARB;
272 pixelAttribs[i++] = 1;
273
274 pixelAttribs[i++] = WGL_SAMPLES_ARB;
275 pixelAttribs[i++] = 8;
276 }
277
278 pixelAttribs[i++] = WGL_ALPHA_BITS_ARB;
279
280 /* track the spot where the alpha bits are, so that we can clear it if needed */
281 alpha_idx = i;
282
283 pixelAttribs[i++] = 8;
284 pixelAttribs[i++] = 0; /* end of pixelAttribs */
285
286 memset (&dummy, 0, sizeof (GdkWGLDummy));
287
288 /* acquire and cache dummy Window (HWND & HDC) and
289 * dummy GL Context, we need it for wglChoosePixelFormatARB()
290 */
291 best_pf = gdk_init_dummy_context (&dummy, need_alpha_bits);
292
293 if (best_pf == 0 || !wglMakeCurrent (dummy.hdc, dummy.hglrc))
294 {
295 wglMakeCurrent (hdc_current, hglrc_current);
296 return 0;
297 }
298
299 wglChoosePixelFormatARB (hdc,
300 pixelAttribs,
301 NULL,
302 1,
303 &best_pf,
304 &num_formats);
305
306 if (best_pf == 0)
307 {
308 if (!need_alpha_bits)
309 {
310 pixelAttribs[alpha_idx] = 0;
311 pixelAttribs[alpha_idx + 1] = 0;
312
313 /* give another chance if need_alpha_bits is FALSE,
314 * meaning we prefer to have an alpha channel anyways
315 */
316 wglChoosePixelFormatARB (hdc,
317 pixelAttribs,
318 NULL,
319 1,
320 &best_pf,
321 &num_formats);
322
323 }
324 }
325
326 /* Go back to the HDC that we were using, since we are done with the dummy HDC and GL Context */
327 wglMakeCurrent (hdc_current, hglrc_current);
328 destroy_dummy_gl_context (dummy);
329 }
330 else
331 {
332 pfd->nVersion = 1;
333 pfd->dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER;
334 pfd->iPixelType = PFD_TYPE_RGBA;
335 pfd->cColorBits = GetDeviceCaps (hdc, BITSPIXEL);
336 pfd->cAlphaBits = 8;
337 pfd->dwLayerMask = PFD_MAIN_PLANE;
338
339 best_pf = ChoosePixelFormat (hdc, pfd);
340
341 if (best_pf == 0)
342 /* give another chance if need_alpha_bits is FALSE,
343 * meaning we prefer to have an alpha channel anyways
344 */
345 if (!need_alpha_bits)
346 {
347 pfd->cAlphaBits = 0;
348 best_pf = ChoosePixelFormat (hdc, pfd);
349 }
350 }
351
352 return best_pf;
353 }
354
355 /* in WGL, for many OpenGL items, we need a dummy WGL context, so create
356 * one and cache it for later use
357 */
358 static gint
gdk_init_dummy_context(GdkWGLDummy * dummy,const gboolean need_alpha_bits)359 gdk_init_dummy_context (GdkWGLDummy *dummy,
360 const gboolean need_alpha_bits)
361 {
362 PIXELFORMATDESCRIPTOR pfd;
363 gboolean set_pixel_format_result = FALSE;
364 gint best_idx = 0;
365
366 get_dummy_window_hwnd (dummy);
367
368 dummy->hdc = GetDC (dummy->hwnd);
369 memset (&pfd, 0, sizeof (PIXELFORMATDESCRIPTOR));
370
371 best_idx = get_wgl_pfd (dummy->hdc, need_alpha_bits, &pfd, NULL);
372
373 if (best_idx != 0)
374 set_pixel_format_result = SetPixelFormat (dummy->hdc,
375 best_idx,
376 &pfd);
377
378 if (best_idx == 0 || !set_pixel_format_result)
379 return 0;
380
381 dummy->hglrc = wglCreateContext (dummy->hdc);
382 if (dummy->hglrc == NULL)
383 return 0;
384
385 dummy->inited = TRUE;
386
387 return best_idx;
388 }
389
390 static void
gdk_win32_gl_context_dispose_wgl(GObject * gobject)391 gdk_win32_gl_context_dispose_wgl (GObject *gobject)
392 {
393 GdkGLContext *context = GDK_GL_CONTEXT (gobject);
394 GdkWin32GLContextWGL *context_wgl = GDK_WIN32_GL_CONTEXT_WGL (context);
395
396 if (context_wgl->wgl_context != NULL)
397 {
398 GdkWindow *window = gdk_gl_context_get_window (context);
399
400 if (wglGetCurrentContext () == context_wgl->wgl_context)
401 wglMakeCurrent (NULL, NULL);
402
403 GDK_NOTE (OPENGL, g_print ("Destroying WGL context\n"));
404
405 wglDeleteContext (context_wgl->wgl_context);
406 context_wgl->wgl_context = NULL;
407
408 gdk_win32_gl_context_cleanup (context);
409 }
410
411 G_OBJECT_CLASS (gdk_win32_gl_context_parent_class)->dispose (gobject);
412 }
413
414 static void
gdk_win32_gl_context_end_frame_wgl(GdkGLContext * context,cairo_region_t * painted,cairo_region_t * damage)415 gdk_win32_gl_context_end_frame_wgl (GdkGLContext *context,
416 cairo_region_t *painted,
417 cairo_region_t *damage)
418 {
419 GdkWin32Display *display_win32 = (GDK_WIN32_DISPLAY (gdk_gl_context_get_display (context)));
420 GdkWin32GLContext *context_win32 = GDK_WIN32_GL_CONTEXT (context);
421
422 gdk_gl_context_make_current (context);
423
424 if (context_win32->do_frame_sync)
425 {
426 glFinish ();
427
428 if (display_win32->hasWglOMLSyncControl)
429 {
430 gint64 ust, msc, sbc;
431
432 wglGetSyncValuesOML (context_win32->gl_hdc, &ust, &msc, &sbc);
433 wglWaitForMscOML (context_win32->gl_hdc,
434 0,
435 2,
436 (msc + 1) % 2,
437 &ust, &msc, &sbc);
438 }
439 }
440
441 if (context_win32->do_blit_swap)
442 {
443 GdkWindow *window = gdk_gl_context_get_window (context);
444
445 glDrawBuffer(GL_FRONT);
446 glReadBuffer(GL_BACK);
447 gdk_gl_blit_region (window, painted, display_win32->needIntelGLWorkaround);
448 glDrawBuffer(GL_BACK);
449 glFlush();
450
451 if (gdk_gl_context_has_frame_terminator (context))
452 glFrameTerminatorGREMEDY ();
453 }
454 else
455 SwapBuffers (context_win32->gl_hdc);
456 }
457
458 /*
459 * We need to check whether the OpenGL driver is capable of delvering
460 * what we need to use in GdkGLContext. This function in the future
461 * will also check for blacklisted drivers, if needed. If things fail
462 * here, we can try falling back to OpenGL/ES (libANGLE) if that is enabled.
463 */
464 static gboolean
gdk_win32_gl_context_wgl_check_capabilities(GdkWin32Display * display_win32,GdkWGLDummy dummy)465 gdk_win32_gl_context_wgl_check_capabilities (GdkWin32Display *display_win32,
466 GdkWGLDummy dummy)
467 {
468 if (!wglMakeCurrent (dummy.hdc, dummy.hglrc))
469 return FALSE;
470
471 display_win32->gl_version = epoxy_gl_version ();
472
473 /* We must have OpenGL/WGL 2.0 or later, or have the GL_ARB_shader_objects extension */
474 if (display_win32->gl_version < 20 && !epoxy_has_gl_extension ("GL_ARB_shader_objects"))
475 return FALSE;
476
477 return TRUE;
478 }
479
480 static void
gdk_win32_display_init_wgl(GdkWin32Display * display_win32,const gboolean need_alpha_bits)481 gdk_win32_display_init_wgl (GdkWin32Display *display_win32,
482 const gboolean need_alpha_bits)
483 {
484 /* acquire and cache dummy Window (HWND & HDC) and
485 * dummy GL Context, it is used to query functions
486 * and used for other stuff as well
487 */
488 GdkWGLDummy dummy;
489 gint best_idx = 0;
490 gboolean proceed = TRUE;
491
492 memset (&dummy, 0, sizeof (GdkWGLDummy));
493
494 best_idx = gdk_init_dummy_context (&dummy, need_alpha_bits);
495
496 if (best_idx != 0)
497 proceed = gdk_win32_gl_context_wgl_check_capabilities (display_win32, dummy);
498
499 if (best_idx != 0 && proceed)
500 {
501 display_win32->hasWglARBCreateContext =
502 epoxy_has_wgl_extension (dummy.hdc, "WGL_ARB_create_context");
503 display_win32->hasWglEXTSwapControl =
504 epoxy_has_wgl_extension (dummy.hdc, "WGL_EXT_swap_control");
505 display_win32->hasWglOMLSyncControl =
506 epoxy_has_wgl_extension (dummy.hdc, "WGL_OML_sync_control");
507 display_win32->hasWglARBPixelFormat =
508 epoxy_has_wgl_extension (dummy.hdc, "WGL_ARB_pixel_format");
509 display_win32->hasWglARBmultisample =
510 epoxy_has_wgl_extension (dummy.hdc, "WGL_ARB_multisample");
511 display_win32->needIntelGLWorkaround =
512 (g_ascii_strcasecmp (glGetString (GL_VENDOR), "intel") == 0);
513
514 GDK_NOTE (OPENGL,
515 g_print ("WGL API version %d.%d found\n"
516 " - Vendor: %s\n"
517 " - Intel OpenGL workaround: %s\n"
518 " - Checked extensions:\n"
519 "\t* WGL_ARB_pixel_format: %s\n"
520 "\t* WGL_ARB_create_context: %s\n"
521 "\t* WGL_EXT_swap_control: %s\n"
522 "\t* WGL_OML_sync_control: %s\n"
523 "\t* WGL_ARB_multisample: %s\n",
524 display_win32->gl_version / 10,
525 display_win32->gl_version % 10,
526 glGetString (GL_VENDOR),
527 display_win32->needIntelGLWorkaround ? "yes" : "no",
528 display_win32->hasWglARBPixelFormat ? "yes" : "no",
529 display_win32->hasWglARBCreateContext ? "yes" : "no",
530 display_win32->hasWglEXTSwapControl ? "yes" : "no",
531 display_win32->hasWglOMLSyncControl ? "yes" : "no",
532 display_win32->hasWglARBmultisample ? "yes" : "no"));
533
534 display_win32->gl_type = GDK_WIN32_GL_WGL;
535 }
536 else
537 display_win32->gl_type = GDK_WIN32_GL_NONE;
538
539 /* clean up things if we indeed created our dummy WGL context */
540 if (best_idx != 0)
541 {
542 wglMakeCurrent (NULL, NULL);
543 destroy_dummy_gl_context (dummy);
544 }
545 }
546
547 /* Setup the legacy WGL context after creating it */
548 static gboolean
ensure_legacy_wgl_context(HDC hdc,HGLRC hglrc_legacy,GdkGLContext * share)549 ensure_legacy_wgl_context (HDC hdc,
550 HGLRC hglrc_legacy,
551 GdkGLContext *share)
552 {
553 if (!wglMakeCurrent (hdc, hglrc_legacy))
554 return FALSE;
555
556 if (share != NULL)
557 {
558 GdkWin32GLContextWGL *context_wgl = GDK_WIN32_GL_CONTEXT_WGL (share);
559
560 return wglShareLists (hglrc_legacy, context_wgl->wgl_context);
561 }
562
563 return TRUE;
564 }
565
566 static HGLRC
create_wgl_context_with_attribs(HDC hdc,HGLRC hglrc_base,GdkGLContext * share,int flags,int major,int minor,gboolean * is_legacy)567 create_wgl_context_with_attribs (HDC hdc,
568 HGLRC hglrc_base,
569 GdkGLContext *share,
570 int flags,
571 int major,
572 int minor,
573 gboolean *is_legacy)
574 {
575 HGLRC hglrc;
576 GdkWin32GLContextWGL *context_wgl;
577
578 /* if we have wglCreateContextAttribsARB(), create a
579 * context with the compatibility profile if a legacy
580 * context is requested, or when we go into fallback mode
581 */
582 int profile = *is_legacy ? WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB :
583 WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
584
585 int attribs[] = {
586 WGL_CONTEXT_PROFILE_MASK_ARB, profile,
587 WGL_CONTEXT_MAJOR_VERSION_ARB, *is_legacy ? 3 : major,
588 WGL_CONTEXT_MINOR_VERSION_ARB, *is_legacy ? 0 : minor,
589 WGL_CONTEXT_FLAGS_ARB, flags,
590 0
591 };
592
593 if (share != NULL)
594 context_wgl= GDK_WIN32_GL_CONTEXT_WGL (share);
595
596 hglrc = wglCreateContextAttribsARB (hdc,
597 share != NULL ? context_wgl->wgl_context : NULL,
598 attribs);
599
600 return hglrc;
601 }
602
603 static HGLRC
create_wgl_context(HDC hdc,GdkGLContext * share,int flags,int major,int minor,gboolean * is_legacy,gboolean hasWglARBCreateContext)604 create_wgl_context (HDC hdc,
605 GdkGLContext *share,
606 int flags,
607 int major,
608 int minor,
609 gboolean *is_legacy,
610 gboolean hasWglARBCreateContext)
611 {
612 /* We need a legacy WGL context for *all* cases */
613 HGLRC hglrc_base = wglCreateContext (hdc);
614 gboolean success = TRUE;
615
616 /* Save up the HDC and HGLRC that we are currently using, to restore back to it when we are done here */
617 HDC hdc_current = wglGetCurrentDC ();
618 HGLRC hglrc_current = wglGetCurrentContext ();
619
620 /* if we have no wglCreateContextAttribsARB(), return the legacy context when all is set */
621 if (*is_legacy && !hasWglARBCreateContext)
622 {
623 if (ensure_legacy_wgl_context (hdc, hglrc_base, share))
624 {
625 wglMakeCurrent (hdc_current, hglrc_current);
626 return hglrc_base;
627 }
628
629 success = FALSE;
630 goto gl_fail;
631 }
632 else
633 {
634 HGLRC hglrc;
635
636 if (!wglMakeCurrent (hdc, hglrc_base))
637 {
638 success = FALSE;
639 goto gl_fail;
640 }
641
642 hglrc = create_wgl_context_with_attribs (hdc,
643 hglrc_base,
644 share,
645 flags,
646 major,
647 minor,
648 is_legacy);
649
650 /* return the legacy context we have if it could be setup properly, in case the 3.0+ context creation failed */
651 if (hglrc == NULL)
652 {
653 if (!(*is_legacy))
654 {
655 /* If we aren't using a legacy context in the beginning, try again with a compatibility profile 3.0 context */
656 hglrc = create_wgl_context_with_attribs (hdc,
657 hglrc_base,
658 share,
659 flags,
660 0, 0,
661 is_legacy);
662
663 *is_legacy = TRUE;
664 }
665
666 if (hglrc == NULL)
667 {
668 if (!ensure_legacy_wgl_context (hdc, hglrc_base, share))
669 success = FALSE;
670 }
671
672 if (success)
673 GDK_NOTE (OPENGL, g_print ("Using legacy context as fallback\n"));
674 }
675
676 gl_fail:
677
678 if (!success)
679 {
680 wglMakeCurrent (NULL, NULL);
681 wglDeleteContext (hglrc_base);
682 return NULL;
683 }
684
685 wglMakeCurrent (hdc_current, hglrc_current);
686
687 if (hglrc != NULL)
688 {
689 wglDeleteContext (hglrc_base);
690 return hglrc;
691 }
692
693 return hglrc_base;
694 }
695 }
696
697 static gboolean
set_pixformat_for_hdc(HDC hdc,gint * best_idx,const gboolean need_alpha_bits,GdkWin32Display * display)698 set_pixformat_for_hdc (HDC hdc,
699 gint *best_idx,
700 const gboolean need_alpha_bits,
701 GdkWin32Display *display)
702 {
703 gboolean already_checked = TRUE;
704 *best_idx = GetPixelFormat (hdc);
705
706 /* one is only allowed to call SetPixelFormat(), and so ChoosePixelFormat()
707 * one single time per window HDC
708 */
709 if (*best_idx == 0)
710 {
711 PIXELFORMATDESCRIPTOR pfd;
712 gboolean set_pixel_format_result = FALSE;
713
714 GDK_NOTE (OPENGL, g_print ("requesting pixel format...\n"));
715 already_checked = FALSE;
716 *best_idx = get_wgl_pfd (hdc, need_alpha_bits, &pfd, display);
717
718 if (*best_idx != 0)
719 set_pixel_format_result = SetPixelFormat (hdc, *best_idx, &pfd);
720
721 /* ChoosePixelFormat() or SetPixelFormat() failed, bail out */
722 if (*best_idx == 0 || !set_pixel_format_result)
723 return FALSE;
724 }
725
726 GDK_NOTE (OPENGL, g_print ("%s""requested and set pixel format: %d\n", already_checked ? "already " : "", *best_idx));
727
728 return TRUE;
729 }
730
731 static gboolean
gdk_win32_gl_context_realize_wgl(GdkGLContext * context,GError ** error)732 gdk_win32_gl_context_realize_wgl (GdkGLContext *context,
733 GError **error)
734 {
735 GdkGLContext *share = gdk_gl_context_get_shared_context (context);
736 GdkWin32GLContext *context_win32 = GDK_WIN32_GL_CONTEXT (context);
737 GdkWindow *window = gdk_gl_context_get_window (context);
738 GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
739 GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (gdk_window_get_display (window));
740
741 /* These are the real WGL context items that we will want to use later */
742 gboolean debug_bit, compat_bit;
743 gboolean legacy_bit = FALSE;
744 HGLRC hglrc;
745 gint pixel_format;
746
747 /* request flags and specific versions for core (3.2+) WGL context */
748 gint flags = 0;
749 gint major = 0;
750 gint minor = 0;
751
752 /*
753 * A legacy context cannot be shared with core profile ones, this means we
754 * must stick to a legacy context if the shared context is a legacy context. We
755 * also use a legacy context if we use GDK_GL=legacy or if we do not have
756 * the WGL_ARB_create_context extension
757 */
758 if ((_gdk_gl_flags & GDK_GL_LEGACY) != 0 ||
759 !display_win32->hasWglARBCreateContext ||
760 share != NULL && gdk_gl_context_is_legacy (share))
761 legacy_bit = TRUE;
762
763 /* say early enough that we are not using GLES, so that we acquire the correct versions */
764 gdk_gl_context_set_use_es (context, FALSE);
765
766 gdk_gl_context_get_required_version (context, &major, &minor);
767 debug_bit = gdk_gl_context_get_debug_enabled (context);
768 compat_bit = gdk_gl_context_get_forward_compatible (context);
769
770 if (!set_pixformat_for_hdc (context_win32->gl_hdc,
771 &pixel_format,
772 context_win32->need_alpha_bits,
773 display_win32))
774 {
775 g_set_error_literal (error, GDK_GL_ERROR,
776 GDK_GL_ERROR_UNSUPPORTED_FORMAT,
777 _("No available configurations for the given pixel format"));
778
779 return FALSE;
780 }
781
782 if (debug_bit)
783 flags |= WGL_CONTEXT_DEBUG_BIT_ARB;
784 if (compat_bit)
785 flags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
786
787 GDK_NOTE (OPENGL,
788 g_print ("Creating %s WGL context (version:%d.%d, debug:%s, forward:%s, legacy: %s)\n",
789 compat_bit ? "core" : "compat",
790 major,
791 minor,
792 debug_bit ? "yes" : "no",
793 compat_bit ? "yes" : "no",
794 legacy_bit ? "yes" : "no"));
795
796 hglrc = create_wgl_context (context_win32->gl_hdc,
797 share,
798 flags,
799 major,
800 minor,
801 &legacy_bit,
802 display_win32->hasWglARBCreateContext);
803
804 if (hglrc == NULL)
805 {
806 g_set_error_literal (error, GDK_GL_ERROR,
807 GDK_GL_ERROR_NOT_AVAILABLE,
808 _("Unable to create a GL context"));
809 return FALSE;
810 }
811
812 GDK_NOTE (OPENGL,
813 g_print ("Created WGL context[%p], pixel_format=%d\n",
814 hglrc,
815 pixel_format));
816
817 GDK_WIN32_GL_CONTEXT_WGL (context)->wgl_context = hglrc;
818
819 /* OpenGL does not work with WS_EX_LAYERED enabled, so we need to
820 * disable WS_EX_LAYERED when we acquire a valid HGLRC
821 */
822 impl->suppress_layered++;
823
824 /* if this is the first time a GL context is acquired for the window,
825 * disable layered windows by triggering update_style_bits()
826 */
827 if (impl->suppress_layered == 1)
828 _gdk_win32_window_update_style_bits (window);
829
830 /* Ensure that any other context is created with a legacy bit set */
831 gdk_gl_context_set_is_legacy (context, legacy_bit);
832
833 return TRUE;
834 }
835
836 static gboolean
gdk_win32_display_make_wgl_context_current(GdkDisplay * display,GdkGLContext * context)837 gdk_win32_display_make_wgl_context_current (GdkDisplay *display,
838 GdkGLContext *context)
839 {
840 GdkWin32GLContext *context_win32;
841 GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (display);
842 GdkWindow *window;
843
844 if (context == NULL)
845 {
846 wglMakeCurrent(NULL, NULL);
847
848 return TRUE;
849 }
850
851 context_win32 = GDK_WIN32_GL_CONTEXT (context);
852 window = gdk_gl_context_get_window (context);
853
854 if (!wglMakeCurrent (context_win32->gl_hdc,
855 GDK_WIN32_GL_CONTEXT_WGL (context)->wgl_context))
856 {
857 GDK_NOTE (OPENGL, g_print ("Making WGL context current failed\n"));
858 return FALSE;
859 }
860
861 if (context_win32->is_attached)
862 {
863 if (display_win32->hasWglEXTSwapControl)
864 {
865 /* If there is compositing there is no particular need to delay
866 * the swap when drawing on the offscreen, rendering to the screen
867 * happens later anyway, and its up to the compositor to sync that
868 * to the vblank. */
869 gboolean do_frame_sync = !gdk_screen_is_composited (gdk_window_get_screen (window));
870
871 if (do_frame_sync != context_win32->do_frame_sync)
872 {
873 context_win32->do_frame_sync = do_frame_sync;
874
875 if (do_frame_sync)
876 wglSwapIntervalEXT (1);
877 else
878 wglSwapIntervalEXT (0);
879 }
880 }
881 }
882
883 return TRUE;
884 }
885
886 static void
gdk_win32_gl_context_wgl_class_init(GdkWin32GLContextWGLClass * klass)887 gdk_win32_gl_context_wgl_class_init (GdkWin32GLContextWGLClass *klass)
888 {
889 GdkGLContextClass *context_class = GDK_GL_CONTEXT_CLASS (klass);
890 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
891
892 context_class->end_frame = gdk_win32_gl_context_end_frame_wgl;
893 context_class->realize = gdk_win32_gl_context_realize_wgl;
894
895 gobject_class->dispose = gdk_win32_gl_context_dispose_wgl;
896 }
897
898 static void
gdk_win32_gl_context_wgl_init(GdkWin32GLContextWGL * wgl_context)899 gdk_win32_gl_context_wgl_init (GdkWin32GLContextWGL *wgl_context)
900 {
901 }
902
903 /* End section on WGL support */
904 /* Section on EGL/libANGLE support */
905 #ifdef GDK_WIN32_ENABLE_EGL
906
907 #ifndef EGL_PLATFORM_ANGLE_ANGLE
908 #define EGL_PLATFORM_ANGLE_ANGLE 0x3202
909 #endif
910
911 #ifndef EGL_PLATFORM_ANGLE_TYPE_ANGLE
912 #define EGL_PLATFORM_ANGLE_TYPE_ANGLE 0x3203
913 #endif
914
915 #ifndef EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE
916 #define EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE 0x3208
917 #endif
918
919 struct _GdkWin32GLContextEGL
920 {
921 GdkWin32GLContext parent_instance;
922
923 EGLContext egl_context;
924 };
925
926 #define GDK_TYPE_WIN32_GL_CONTEXT_EGL (gdk_win32_gl_context_egl_get_type())
927 #define GDK_WIN32_GL_CONTEXT_EGL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_WIN32_GL_CONTEXT_EGL, GdkWin32GLContextEGL))
928 #define GDK_IS_WIN32_GL_CONTEXT_EGL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_WIN32_GL_CONTEXT_EGL))
929
930 typedef struct _GdkWin32GLContextClass GdkWin32GLContextEGLClass;
931 typedef struct _GdkWin32GLContextEGL GdkWin32GLContextEGL;
932
G_DEFINE_TYPE(GdkWin32GLContextEGL,gdk_win32_gl_context_egl,GDK_TYPE_WIN32_GL_CONTEXT)933 G_DEFINE_TYPE (GdkWin32GLContextEGL, gdk_win32_gl_context_egl, GDK_TYPE_WIN32_GL_CONTEXT)
934
935 static EGLDisplay
936 gdk_win32_get_egl_display (GdkWin32Display *display)
937 {
938 EGLDisplay disp;
939 gboolean success = FALSE;
940
941 if (epoxy_has_egl_extension (NULL, "EGL_EXT_platform_base"))
942 {
943 PFNEGLGETPLATFORMDISPLAYEXTPROC getPlatformDisplay = (void *) eglGetProcAddress ("eglGetPlatformDisplayEXT");
944 if (getPlatformDisplay)
945 {
946 EGLint disp_attr[] = {EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, EGL_NONE};
947
948 disp = getPlatformDisplay (EGL_PLATFORM_ANGLE_ANGLE, display->hdc_egl_temp, disp_attr);
949
950 if (disp != EGL_NO_DISPLAY)
951 return disp;
952 }
953 }
954
955 return eglGetDisplay (display->hdc_egl_temp);
956 }
957
958 static void
gdk_win32_gl_context_dispose_egl(GObject * gobject)959 gdk_win32_gl_context_dispose_egl (GObject *gobject)
960 {
961 GdkGLContext *context = GDK_GL_CONTEXT (gobject);
962 GdkWin32GLContextEGL *context_egl = GDK_WIN32_GL_CONTEXT_EGL (context);
963
964 if (context_egl->egl_context != EGL_NO_CONTEXT)
965 {
966 GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (gdk_gl_context_get_display (context));
967
968 if (eglGetCurrentContext () == context_egl->egl_context)
969 eglMakeCurrent(display_win32->egl_disp, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
970
971 GDK_NOTE (OPENGL, g_message ("Destroying EGL (ANGLE) context"));
972
973 eglDestroyContext (display_win32->egl_disp, context_egl->egl_context);
974 context_egl->egl_context = EGL_NO_CONTEXT;
975
976 gdk_win32_gl_context_cleanup (context);
977 }
978
979 G_OBJECT_CLASS (gdk_win32_gl_context_parent_class)->dispose (gobject);
980 }
981
982 static gboolean
get_is_egl_force_redraw(GdkWindow * window)983 get_is_egl_force_redraw (GdkWindow *window)
984 {
985 /* We only need to call gdk_window_invalidate_rect () if necessary */
986 if (window->gl_paint_context != NULL && gdk_gl_context_get_use_es (window->gl_paint_context))
987 {
988 GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
989
990 return impl->egl_force_redraw_all;
991 }
992
993 return FALSE;
994 }
995
996 static void
reset_egl_force_redraw(GdkWindow * window)997 reset_egl_force_redraw (GdkWindow *window)
998 {
999 if (window->gl_paint_context != NULL && gdk_gl_context_get_use_es (window->gl_paint_context))
1000 {
1001 GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
1002
1003 if (impl->egl_force_redraw_all)
1004 impl->egl_force_redraw_all = FALSE;
1005 }
1006 }
1007
1008 static void
gdk_win32_gl_context_end_frame_egl(GdkGLContext * context,cairo_region_t * painted,cairo_region_t * damage)1009 gdk_win32_gl_context_end_frame_egl (GdkGLContext *context,
1010 cairo_region_t *painted,
1011 cairo_region_t *damage)
1012 {
1013 GdkWindow *window = gdk_gl_context_get_window (context);
1014 GdkWin32Display *display_win32 = (GDK_WIN32_DISPLAY (gdk_gl_context_get_display (context)));
1015 GdkWin32GLContext *context_win32 = GDK_WIN32_GL_CONTEXT (context);
1016
1017 EGLSurface egl_surface = _gdk_win32_window_get_egl_surface (window, display_win32->egl_config, FALSE);
1018 gboolean force_egl_redraw_all = get_is_egl_force_redraw (window);
1019
1020 gdk_gl_context_make_current (context);
1021
1022 if (context_win32->do_blit_swap && !force_egl_redraw_all)
1023 gdk_gl_blit_region (window, painted, FALSE);
1024 else if (force_egl_redraw_all)
1025 {
1026 GdkRectangle rect = {0, 0, gdk_window_get_width (window), gdk_window_get_height (window)};
1027
1028 /* We need to do gdk_window_invalidate_rect() so that we don't get glitches after maximizing or
1029 * restoring or using aerosnap
1030 */
1031 gdk_window_invalidate_rect (window, &rect, TRUE);
1032 reset_egl_force_redraw (window);
1033 }
1034
1035 eglSwapBuffers (display_win32->egl_disp, egl_surface);
1036 }
1037
1038 static void
gdk_win32_display_init_egl(GdkWin32Display * display_win32)1039 gdk_win32_display_init_egl (GdkWin32Display *display_win32)
1040 {
1041 EGLDisplay egl_disp;
1042
1043 if (display_win32->gl_type == GDK_WIN32_GL_NONE)
1044 GDK_NOTE (OPENGL, g_message ("Falling back to GLES..."));
1045
1046 egl_disp = gdk_win32_get_egl_display (display_win32);
1047
1048 if (egl_disp == EGL_NO_DISPLAY ||
1049 !eglInitialize (egl_disp, NULL, NULL))
1050 {
1051 if (egl_disp != EGL_NO_DISPLAY)
1052 {
1053 eglTerminate (egl_disp);
1054 egl_disp = EGL_NO_DISPLAY;
1055 }
1056
1057 display_win32->gl_type = GDK_WIN32_GL_NONE;
1058 return;
1059 }
1060
1061 display_win32->egl_disp = egl_disp;
1062 display_win32->gl_version = epoxy_egl_version (egl_disp);
1063
1064 eglBindAPI(EGL_OPENGL_ES_API);
1065
1066 display_win32->hasEglSurfacelessContext =
1067 epoxy_has_egl_extension (egl_disp, "EGL_KHR_surfaceless_context");
1068
1069 GDK_NOTE (OPENGL,
1070 g_print ("EGL API version %d.%d found\n"
1071 " - Vendor: %s\n"
1072 " - Checked extensions:\n"
1073 "\t* EGL_KHR_surfaceless_context: %s\n",
1074 display_win32->gl_version / 10,
1075 display_win32->gl_version % 10,
1076 eglQueryString (display_win32->egl_disp, EGL_VENDOR),
1077 display_win32->hasEglSurfacelessContext ? "yes" : "no"));
1078
1079 display_win32->gl_type = GDK_WIN32_GL_EGL;
1080 }
1081
1082 #define MAX_EGL_ATTRS 30
1083
1084 static gboolean
find_eglconfig_for_window(GdkWin32Display * display_win32,gboolean need_alpha_bits,GError ** error)1085 find_eglconfig_for_window (GdkWin32Display *display_win32,
1086 gboolean need_alpha_bits,
1087 GError **error)
1088 {
1089 EGLint attrs[MAX_EGL_ATTRS];
1090 EGLint count;
1091 EGLConfig *configs, chosen_config;
1092
1093 int i = 0;
1094
1095 EGLDisplay egl_disp;
1096
1097 if (display_win32->egl_min_swap_interval != 0 &&
1098 display_win32->egl_config != NULL)
1099 return TRUE;
1100
1101 egl_disp = display_win32->egl_disp;
1102
1103 attrs[i++] = EGL_CONFORMANT;
1104 attrs[i++] = EGL_OPENGL_ES2_BIT;
1105 attrs[i++] = EGL_SURFACE_TYPE;
1106 attrs[i++] = EGL_WINDOW_BIT;
1107
1108 attrs[i++] = EGL_COLOR_BUFFER_TYPE;
1109 attrs[i++] = EGL_RGB_BUFFER;
1110
1111 attrs[i++] = EGL_RED_SIZE;
1112 attrs[i++] = 1;
1113 attrs[i++] = EGL_GREEN_SIZE;
1114 attrs[i++] = 1;
1115 attrs[i++] = EGL_BLUE_SIZE;
1116 attrs[i++] = 1;
1117
1118 if (need_alpha_bits)
1119 {
1120 attrs[i++] = EGL_ALPHA_SIZE;
1121 attrs[i++] = 1;
1122 }
1123 else
1124 {
1125 attrs[i++] = EGL_ALPHA_SIZE;
1126 attrs[i++] = EGL_DONT_CARE;
1127 }
1128
1129 attrs[i++] = EGL_NONE;
1130 g_assert (i < MAX_EGL_ATTRS);
1131
1132 if (!eglChooseConfig (display_win32->egl_disp, attrs, NULL, 0, &count) || count < 1)
1133 {
1134 g_set_error_literal (error, GDK_GL_ERROR,
1135 GDK_GL_ERROR_UNSUPPORTED_FORMAT,
1136 _("No available configurations for the given pixel format"));
1137 return FALSE;
1138 }
1139
1140 configs = g_new (EGLConfig, count);
1141
1142 if (!eglChooseConfig (display_win32->egl_disp, attrs, configs, count, &count) || count < 1)
1143 {
1144 g_set_error_literal (error, GDK_GL_ERROR,
1145 GDK_GL_ERROR_UNSUPPORTED_FORMAT,
1146 _("No available configurations for the given pixel format"));
1147 return FALSE;
1148 }
1149
1150 /* Pick first valid configuration i guess? */
1151 chosen_config = configs[0];
1152
1153 if (!eglGetConfigAttrib (display_win32->egl_disp, chosen_config,
1154 EGL_MIN_SWAP_INTERVAL, &display_win32->egl_min_swap_interval))
1155 {
1156 g_set_error_literal (error, GDK_GL_ERROR,
1157 GDK_GL_ERROR_NOT_AVAILABLE,
1158 "Could not retrieve the minimum swap interval");
1159 g_free (configs);
1160 return FALSE;
1161 }
1162
1163 display_win32->egl_config = chosen_config;
1164
1165 g_free (configs);
1166
1167 return TRUE;
1168 }
1169
1170 #define N_EGL_ATTRS 16
1171
1172 static EGLContext
create_egl_context(EGLDisplay display,EGLConfig config,GdkGLContext * share,int flags,int major,int minor)1173 create_egl_context (EGLDisplay display,
1174 EGLConfig config,
1175 GdkGLContext *share,
1176 int flags,
1177 int major,
1178 int minor)
1179 {
1180 EGLContext ctx;
1181 EGLint context_attribs[N_EGL_ATTRS];
1182 int i = 0;
1183
1184 /*
1185 * ANGLE does not support the GL_OES_vertex_array_object extension, so we need to use ES3 directly
1186 * if we do not request for ES3 or later
1187 */
1188 if (major < 3)
1189 {
1190 context_attribs[i++] = EGL_CONTEXT_CLIENT_VERSION;
1191 context_attribs[i++] = 3;
1192 }
1193
1194 /* Specify the flags */
1195 context_attribs[i++] = EGL_CONTEXT_FLAGS_KHR;
1196 context_attribs[i++] = flags;
1197
1198 context_attribs[i++] = EGL_NONE;
1199 g_assert (i < N_EGL_ATTRS);
1200
1201 ctx = eglCreateContext (display,
1202 config,
1203 share != NULL ? GDK_WIN32_GL_CONTEXT_EGL (share)->egl_context
1204 : EGL_NO_CONTEXT,
1205 context_attribs);
1206
1207 return ctx;
1208 }
1209
1210 static gboolean
gdk_win32_gl_context_realize_egl(GdkGLContext * context,GError ** error)1211 gdk_win32_gl_context_realize_egl (GdkGLContext *context,
1212 GError **error)
1213 {
1214 GdkGLContext *share = gdk_gl_context_get_shared_context (context);
1215 GdkWin32GLContext *context_win32 = GDK_WIN32_GL_CONTEXT (context);
1216 GdkWindow *window = gdk_gl_context_get_window (context);
1217 GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
1218 GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (gdk_window_get_display (window));
1219
1220 /* These are the real EGL context items that we will want to use later */
1221 EGLContext ctx;
1222 gboolean debug_bit, compat_bit;
1223 gboolean legacy_bit = FALSE;
1224
1225 /* request flags and specific versions for EGL context */
1226 gint flags = 0;
1227 gint major = 0;
1228 gint minor = 0;
1229
1230 /* we are using GLES, so set early so that we get the correct GLES versions to request */
1231 gdk_gl_context_set_use_es (context, TRUE);
1232
1233 gdk_gl_context_get_required_version (context, &major, &minor);
1234 debug_bit = gdk_gl_context_get_debug_enabled (context);
1235 compat_bit = gdk_gl_context_get_forward_compatible (context);
1236
1237 if (debug_bit)
1238 flags |= EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR;
1239 if (compat_bit)
1240 flags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR;
1241
1242 GDK_NOTE (OPENGL, g_message ("Creating EGL context version %d.%d (debug:%s, forward:%s, legacy:%s)",
1243 major, minor,
1244 debug_bit ? "yes" : "no",
1245 compat_bit ? "yes" : "no"));
1246
1247 ctx = create_egl_context (display_win32->egl_disp,
1248 display_win32->egl_config,
1249 share,
1250 flags,
1251 major,
1252 minor);
1253
1254 if (ctx == EGL_NO_CONTEXT)
1255 {
1256 g_set_error_literal (error, GDK_GL_ERROR,
1257 GDK_GL_ERROR_NOT_AVAILABLE,
1258 _("Unable to create a GL context"));
1259
1260 return FALSE;
1261 }
1262
1263 GDK_NOTE (OPENGL,
1264 g_print ("Created EGL context[%p]\n",
1265 ctx));
1266
1267 GDK_WIN32_GL_CONTEXT_EGL (context)->egl_context = ctx;
1268
1269 /* OpenGL does not work with WS_EX_LAYERED enabled, so we need to
1270 * disable WS_EX_LAYERED when we acquire a valid HGLRC
1271 */
1272 impl->suppress_layered++;
1273
1274 /* if this is the first time a GL context is acquired for the window,
1275 * disable layered windows by triggering update_style_bits()
1276 */
1277 if (impl->suppress_layered == 1)
1278 _gdk_win32_window_update_style_bits (window);
1279
1280 /* Ensure that any other context is created with a legacy bit set */
1281 gdk_gl_context_set_is_legacy (context, legacy_bit);
1282
1283 return TRUE;
1284 }
1285
1286 void
gdk_win32_window_invalidate_egl_framebuffer(GdkWindow * window)1287 gdk_win32_window_invalidate_egl_framebuffer (GdkWindow *window)
1288 {
1289 /* If we are using ANGLE, we need to force redraw of the whole Window and its child windows
1290 * as we need to re-acquire the EGL surfaces that we rendered to upload to Cairo explicitly,
1291 * using gdk_window_invalidate_rect (), when we maximize or restore or use aerosnap
1292 */
1293 if (window->gl_paint_context != NULL && gdk_gl_context_get_use_es (window->gl_paint_context))
1294 {
1295 GdkWindowImplWin32 *impl = GDK_WINDOW_IMPL_WIN32 (window->impl);
1296
1297 impl->egl_force_redraw_all = TRUE;
1298 }
1299 }
1300
1301 static gboolean
gdk_win32_display_make_egl_context_current(GdkDisplay * display,GdkGLContext * context)1302 gdk_win32_display_make_egl_context_current (GdkDisplay *display,
1303 GdkGLContext *context)
1304 {
1305 GdkWin32GLContext *context_win32;
1306 GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (display);
1307 GdkWindow *window;
1308 EGLSurface egl_surface;
1309
1310 if (context == NULL)
1311 {
1312 eglMakeCurrent (display_win32->egl_disp, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
1313
1314 return TRUE;
1315 }
1316
1317 context_win32 = GDK_WIN32_GL_CONTEXT (context);
1318 window = gdk_gl_context_get_window (context);
1319
1320 if (context_win32->is_attached || !display_win32->hasEglSurfacelessContext)
1321 egl_surface = _gdk_win32_window_get_egl_surface (window,
1322 display_win32->egl_config,
1323 !context_win32->is_attached);
1324 else
1325 egl_surface = EGL_NO_SURFACE;
1326
1327 if (!eglMakeCurrent (display_win32->egl_disp,
1328 egl_surface,
1329 egl_surface,
1330 GDK_WIN32_GL_CONTEXT_EGL (context)->egl_context))
1331 {
1332 g_warning ("eglMakeCurrent failed");
1333 return FALSE;
1334 }
1335
1336 if (display_win32->egl_min_swap_interval == 0)
1337 eglSwapInterval (display_win32->egl_disp, 0);
1338 else
1339 g_debug ("Can't disable GL swap interval");
1340
1341 return TRUE;
1342 }
1343
1344 static void
gdk_win32_gl_context_egl_class_init(GdkWin32GLContextEGLClass * klass)1345 gdk_win32_gl_context_egl_class_init (GdkWin32GLContextEGLClass *klass)
1346 {
1347 GdkGLContextClass *context_class = GDK_GL_CONTEXT_CLASS (klass);
1348 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1349
1350 context_class->end_frame = gdk_win32_gl_context_end_frame_egl;
1351 context_class->realize = gdk_win32_gl_context_realize_egl;
1352
1353 gobject_class->dispose = gdk_win32_gl_context_dispose_egl;
1354 }
1355
1356 static void
gdk_win32_gl_context_egl_init(GdkWin32GLContextEGL * egl_context)1357 gdk_win32_gl_context_egl_init (GdkWin32GLContextEGL *egl_context)
1358 {
1359 }
1360 #else /* GDK_WIN32_ENABLE_EGL */
1361 /* define EGL stuff as no-op macros or functions if it is not enabled */
1362
1363 static void
gdk_win32_display_init_egl(GdkWin32Display * display_win32)1364 gdk_win32_display_init_egl (GdkWin32Display *display_win32)
1365 {
1366 GDK_NOTE (OPENGL, g_message ("Cannot %s GLES contexts: no GLES support",
1367 display_win32->gl_type == GDK_WIN32_GL_PENDING ?
1368 "create" : "fallback to"));
1369 display_win32->gl_type = GDK_WIN32_GL_NONE;
1370 }
1371
1372 #define gdk_win32_display_make_egl_context_current(disp,ctx) FALSE
1373
1374 void
gdk_win32_window_invalidate_egl_framebuffer(GdkWindow * window)1375 gdk_win32_window_invalidate_egl_framebuffer (GdkWindow *window)
1376 {
1377 }
1378
1379 static gboolean
find_eglconfig_for_window(GdkWin32Display * display_win32,gboolean need_alpha_bits,GError ** error)1380 find_eglconfig_for_window (GdkWin32Display *display_win32,
1381 gboolean need_alpha_bits,
1382 GError **error)
1383 {
1384 return FALSE;
1385 }
1386 #endif /* !GDK_WIN32_ENABLE_EGL */
1387
1388 static void
gdk_win32_gl_context_class_init(GdkWin32GLContextClass * klass)1389 gdk_win32_gl_context_class_init (GdkWin32GLContextClass *klass)
1390 {
1391 GdkGLContextClass *context_class = GDK_GL_CONTEXT_CLASS (klass);
1392 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1393 }
1394
1395 static void
gdk_win32_gl_context_init(GdkWin32GLContext * self)1396 gdk_win32_gl_context_init (GdkWin32GLContext *self)
1397 {
1398 }
1399
1400 void
gdk_win32_window_invalidate_for_new_frame(GdkWindow * window,cairo_region_t * update_area)1401 gdk_win32_window_invalidate_for_new_frame (GdkWindow *window,
1402 cairo_region_t *update_area)
1403 {
1404 cairo_rectangle_int_t window_rect;
1405 gboolean invalidate_all = FALSE;
1406 GdkWin32GLContext *context_win32;
1407 cairo_rectangle_int_t whole_window = { 0, 0, gdk_window_get_width (window), gdk_window_get_height (window) };
1408
1409 /* Minimal update is ok if we're not drawing with gl */
1410 if (window->gl_paint_context == NULL)
1411 return;
1412
1413 context_win32 = GDK_WIN32_GL_CONTEXT (window->gl_paint_context);
1414 context_win32->do_blit_swap = FALSE;
1415
1416 if (gdk_gl_context_has_framebuffer_blit (window->gl_paint_context) &&
1417 cairo_region_contains_rectangle (update_area, &whole_window) != CAIRO_REGION_OVERLAP_IN)
1418 {
1419 context_win32->do_blit_swap = TRUE;
1420 }
1421 else
1422 invalidate_all = TRUE;
1423
1424 if (invalidate_all)
1425 {
1426 window_rect.x = 0;
1427 window_rect.y = 0;
1428 window_rect.width = gdk_window_get_width (window);
1429 window_rect.height = gdk_window_get_height (window);
1430
1431 /* If nothing else is known, repaint everything so that the back
1432 buffer is fully up-to-date for the swapbuffer */
1433 cairo_region_union_rectangle (update_area, &window_rect);
1434 }
1435 }
1436
1437 static void
gdk_win32_display_init_gl(GdkDisplay * display,GdkGLContext * share,const gboolean need_alpha_bits)1438 gdk_win32_display_init_gl (GdkDisplay *display,
1439 GdkGLContext *share,
1440 const gboolean need_alpha_bits)
1441 {
1442 GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (display);
1443 gint best_idx = 0;
1444 gboolean disable_wgl = FALSE;
1445
1446 if (display_win32->gl_type == GDK_WIN32_GL_WGL ||
1447 display_win32->gl_type == GDK_WIN32_GL_EGL)
1448 return;
1449
1450 /*
1451 * We must disable WGL if we are using GDK_GL=gles or if the
1452 * existing shared GLContext is a GLES context
1453 */
1454 disable_wgl = ((_gdk_gl_flags & GDK_GL_GLES) != 0) ||
1455 (share != NULL && gdk_gl_context_get_use_es (share));
1456
1457 if (!disable_wgl)
1458 gdk_win32_display_init_wgl (display_win32, need_alpha_bits);
1459
1460 if (display_win32->gl_type == GDK_WIN32_GL_PENDING ||
1461 display_win32->gl_type == GDK_WIN32_GL_NONE)
1462 gdk_win32_display_init_egl (display_win32);
1463 }
1464
1465 GdkGLContext *
gdk_win32_window_create_gl_context(GdkWindow * window,gboolean attached,GdkGLContext * share,GError ** error)1466 gdk_win32_window_create_gl_context (GdkWindow *window,
1467 gboolean attached,
1468 GdkGLContext *share,
1469 GError **error)
1470 {
1471 GdkDisplay *display = gdk_window_get_display (window);
1472 GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (gdk_window_get_display (window));
1473 GdkWin32GLContext *context_win32 = NULL;
1474 GdkVisual *visual = gdk_window_get_visual (window);
1475
1476 gboolean need_alpha_bits = (visual == gdk_screen_get_rgba_visual (gdk_display_get_default_screen (display)));
1477
1478 /* Acquire and store up the Windows-specific HWND and HDC */
1479 HDC hdc = GetDC (GDK_WINDOW_HWND (window));
1480
1481 /* display_win32->hdc_egl_temp should *not* be destroyed here! It is destroyed at dispose()! */
1482 display_win32->hdc_egl_temp = hdc;
1483 gdk_win32_display_init_gl (display,
1484 share,
1485 need_alpha_bits);
1486
1487 if (display_win32->gl_type == GDK_WIN32_GL_NONE)
1488 {
1489 g_set_error_literal (error, GDK_GL_ERROR,
1490 GDK_GL_ERROR_NOT_AVAILABLE,
1491 _("No GL implementation is available"));
1492 return NULL;
1493 }
1494
1495 if (display_win32->gl_type == GDK_WIN32_GL_EGL &&
1496 !find_eglconfig_for_window (display_win32, need_alpha_bits, error))
1497 {
1498 display_win32->gl_type = GDK_WIN32_GL_NONE;
1499 return NULL;
1500 }
1501
1502 if (display_win32->gl_type == GDK_WIN32_GL_WGL)
1503 context_win32 = GDK_WIN32_GL_CONTEXT (g_object_new (GDK_TYPE_WIN32_GL_CONTEXT_WGL,
1504 "display", display,
1505 "window", window,
1506 "shared-context", share,
1507 NULL));
1508 #ifdef GDK_WIN32_ENABLE_EGL
1509 else if (display_win32->gl_type == GDK_WIN32_GL_EGL)
1510 context_win32 = GDK_WIN32_GL_CONTEXT (g_object_new (GDK_TYPE_WIN32_GL_CONTEXT_EGL,
1511 "display", display,
1512 "window", window,
1513 "shared-context", share,
1514 NULL));
1515 #endif
1516
1517 context_win32->need_alpha_bits = need_alpha_bits;
1518 context_win32->gl_hdc = hdc;
1519 context_win32->is_attached = attached;
1520
1521 return GDK_GL_CONTEXT (context_win32);
1522 }
1523
1524 gboolean
gdk_win32_display_make_gl_context_current(GdkDisplay * display,GdkGLContext * context)1525 gdk_win32_display_make_gl_context_current (GdkDisplay *display,
1526 GdkGLContext *context)
1527 {
1528 GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (display);
1529
1530 if (display_win32->gl_type == GDK_WIN32_GL_WGL)
1531 return gdk_win32_display_make_wgl_context_current (display, context);
1532
1533 if (display_win32->gl_type == GDK_WIN32_GL_EGL)
1534 return gdk_win32_display_make_egl_context_current (display, context);
1535
1536 g_assert_not_reached ();
1537 return FALSE;
1538 }
1539
1540 /**
1541 * gdk_win32_display_get_wgl_version:
1542 * @display: a #GdkDisplay
1543 * @major: (out): return location for the WGL major version
1544 * @minor: (out): return location for the WGL minor version
1545 *
1546 * Retrieves the version of the WGL implementation.
1547 *
1548 * Returns: %TRUE if WGL is available
1549 *
1550 * Since: 3.16
1551 */
1552 gboolean
gdk_win32_display_get_wgl_version(GdkDisplay * display,gint * major,gint * minor)1553 gdk_win32_display_get_wgl_version (GdkDisplay *display,
1554 gint *major,
1555 gint *minor)
1556 {
1557 GdkWin32Display *display_win32 = NULL;
1558 g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
1559
1560 if (!GDK_IS_WIN32_DISPLAY (display))
1561 return FALSE;
1562
1563 display_win32 = GDK_WIN32_DISPLAY (display);
1564
1565 if (display_win32->gl_type == GDK_WIN32_GL_PENDING)
1566 gdk_win32_display_init_gl (display, NULL, FALSE);
1567
1568 if (display_win32->gl_type == GDK_WIN32_GL_NONE)
1569 return FALSE;
1570
1571 if (major != NULL)
1572 *major = GDK_WIN32_DISPLAY (display)->gl_version / 10;
1573 if (minor != NULL)
1574 *minor = GDK_WIN32_DISPLAY (display)->gl_version % 10;
1575
1576 return TRUE;
1577 }
1578