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 "gdksurface-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 "gdkwin32surface.h"
35 
36 #include "gdkglcontext.h"
37 #include "gdkprofilerprivate.h"
38 #include "gdkinternals.h"
39 #include "gdkintl.h"
40 #include "gdksurface.h"
41 
42 #include <cairo.h>
43 #include <epoxy/wgl.h>
44 
45 struct _GdkWin32GLContextWGL
46 {
47   GdkWin32GLContext parent_instance;
48 
49   HGLRC wgl_context;
50   guint do_frame_sync : 1;
51 };
52 
53 typedef struct _GdkWin32GLContextClass    GdkWin32GLContextWGLClass;
54 
G_DEFINE_TYPE(GdkWin32GLContextWGL,gdk_win32_gl_context_wgl,GDK_TYPE_WIN32_GL_CONTEXT)55 G_DEFINE_TYPE (GdkWin32GLContextWGL, gdk_win32_gl_context_wgl, GDK_TYPE_WIN32_GL_CONTEXT)
56 
57 static void
58 gdk_win32_gl_context_wgl_dispose (GObject *gobject)
59 {
60   GdkWin32GLContextWGL *context_wgl = GDK_WIN32_GL_CONTEXT_WGL (gobject);
61 
62   if (context_wgl->wgl_context != NULL)
63     {
64       if (wglGetCurrentContext () == context_wgl->wgl_context)
65         wglMakeCurrent (NULL, NULL);
66 
67       GDK_NOTE (OPENGL, g_print ("Destroying WGL context\n"));
68 
69       wglDeleteContext (context_wgl->wgl_context);
70       context_wgl->wgl_context = NULL;
71     }
72 
73   G_OBJECT_CLASS (gdk_win32_gl_context_wgl_parent_class)->dispose (gobject);
74 }
75 
76 static void
gdk_win32_gl_context_wgl_end_frame(GdkDrawContext * draw_context,cairo_region_t * painted)77 gdk_win32_gl_context_wgl_end_frame (GdkDrawContext *draw_context,
78                                     cairo_region_t *painted)
79 {
80   GdkGLContext *context = GDK_GL_CONTEXT (draw_context);
81   GdkWin32GLContextWGL *context_wgl = GDK_WIN32_GL_CONTEXT_WGL (context);
82   GdkSurface *surface = gdk_gl_context_get_surface (context);
83   GdkWin32Display *display_win32 = (GDK_WIN32_DISPLAY (gdk_gl_context_get_display (context)));
84   cairo_rectangle_int_t whole_window;
85   gboolean can_wait = display_win32->hasWglOMLSyncControl;
86   HDC hdc;
87 
88   GDK_DRAW_CONTEXT_CLASS (gdk_win32_gl_context_wgl_parent_class)->end_frame (draw_context, painted);
89 
90   gdk_gl_context_make_current (context);
91   whole_window = (GdkRectangle) { 0, 0, gdk_surface_get_width (surface), gdk_surface_get_height (surface) };
92 
93   gdk_profiler_add_mark (GDK_PROFILER_CURRENT_TIME, 0, "win32", "swap buffers");
94 
95   if (surface != NULL)
96     hdc = GDK_WIN32_SURFACE (surface)->hdc;
97   else
98     hdc = display_win32->dummy_context_wgl.hdc;
99 
100   if (context_wgl->do_frame_sync)
101     {
102 
103       glFinish ();
104 
105       if (can_wait)
106         {
107           gint64 ust, msc, sbc;
108 
109           wglGetSyncValuesOML (hdc, &ust, &msc, &sbc);
110           wglWaitForMscOML (hdc,
111                             0,
112                             2,
113                             (msc + 1) % 2,
114                            &ust, &msc, &sbc);
115         }
116 
117     }
118 
119   SwapBuffers (hdc);
120 }
121 
122 static void
gdk_win32_gl_context_wgl_begin_frame(GdkDrawContext * draw_context,cairo_region_t * update_area)123 gdk_win32_gl_context_wgl_begin_frame (GdkDrawContext *draw_context,
124                                       cairo_region_t *update_area)
125 {
126   GdkGLContext *context = GDK_GL_CONTEXT (draw_context);
127   GdkSurface *surface;
128 
129   surface = gdk_gl_context_get_surface (context);
130 
131   gdk_win32_surface_handle_queued_move_resize (draw_context);
132 
133   GDK_DRAW_CONTEXT_CLASS (gdk_win32_gl_context_wgl_parent_class)->begin_frame (draw_context, update_area);
134 }
135 
136 static int
137 gdk_init_dummy_wgl_context (GdkWin32Display *display_win32);
138 
139 #define PIXEL_ATTRIBUTES 17
140 
141 static int
get_wgl_pfd(HDC hdc,PIXELFORMATDESCRIPTOR * pfd,GdkWin32Display * display_win32)142 get_wgl_pfd (HDC                    hdc,
143              PIXELFORMATDESCRIPTOR *pfd,
144              GdkWin32Display       *display_win32)
145 {
146   int best_pf = 0;
147 
148   pfd->nSize = sizeof (PIXELFORMATDESCRIPTOR);
149 
150   if (display_win32 != NULL && display_win32->hasWglARBPixelFormat)
151     {
152       UINT num_formats;
153       int colorbits = GetDeviceCaps (hdc, BITSPIXEL);
154       int i = 0;
155       int pixelAttribs[PIXEL_ATTRIBUTES];
156 
157       /* Save up the HDC and HGLRC that we are currently using, to restore back to it when we are done here */
158       HDC hdc_current = wglGetCurrentDC ();
159       HGLRC hglrc_current = wglGetCurrentContext ();
160 
161       /* Update PIXEL_ATTRIBUTES above if any groups are added here! */
162       pixelAttribs[i] = WGL_DRAW_TO_WINDOW_ARB;
163       pixelAttribs[i++] = GL_TRUE;
164 
165       pixelAttribs[i++] = WGL_SUPPORT_OPENGL_ARB;
166       pixelAttribs[i++] = GL_TRUE;
167 
168       pixelAttribs[i++] = WGL_DOUBLE_BUFFER_ARB;
169       pixelAttribs[i++] = GL_TRUE;
170 
171       pixelAttribs[i++] = WGL_ACCELERATION_ARB;
172       pixelAttribs[i++] = WGL_FULL_ACCELERATION_ARB;
173 
174       pixelAttribs[i++] = WGL_PIXEL_TYPE_ARB;
175       pixelAttribs[i++] = WGL_TYPE_RGBA_ARB;
176 
177       pixelAttribs[i++] = WGL_COLOR_BITS_ARB;
178       pixelAttribs[i++] = colorbits;
179 
180       /* end of "Update PIXEL_ATTRIBUTES above if any groups are added here!" */
181 
182       if (display_win32->hasWglARBmultisample)
183         {
184           pixelAttribs[i++] = WGL_SAMPLE_BUFFERS_ARB;
185           pixelAttribs[i++] = 1;
186 
187           pixelAttribs[i++] = WGL_SAMPLES_ARB;
188           pixelAttribs[i++] = 8;
189         }
190 
191       pixelAttribs[i++] = 0; /* end of pixelAttribs */
192       best_pf = gdk_init_dummy_wgl_context (display_win32);
193 
194       if (!wglMakeCurrent (display_win32->dummy_context_wgl.hdc,
195                            display_win32->dummy_context_wgl.hglrc))
196         {
197           wglMakeCurrent (hdc_current, hglrc_current);
198           return 0;
199         }
200 
201       wglChoosePixelFormatARB (hdc,
202                                pixelAttribs,
203                                NULL,
204                                1,
205                               &best_pf,
206                               &num_formats);
207 
208       /* Go back to the HDC that we were using, since we are done with the dummy HDC and GL Context */
209       wglMakeCurrent (hdc_current, hglrc_current);
210     }
211   else
212     {
213       pfd->nVersion = 1;
214       pfd->dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_DOUBLEBUFFER;
215       pfd->iPixelType = PFD_TYPE_RGBA;
216       pfd->cColorBits = GetDeviceCaps (hdc, BITSPIXEL);
217       pfd->cAlphaBits = 8;
218       pfd->dwLayerMask = PFD_MAIN_PLANE;
219 
220       best_pf = ChoosePixelFormat (hdc, pfd);
221     }
222 
223   return best_pf;
224 }
225 
226 /* in WGL, for many OpenGL items, we need a dummy WGL context, so create
227  * one and cache it for later use
228  */
229 static int
gdk_init_dummy_wgl_context(GdkWin32Display * display_win32)230 gdk_init_dummy_wgl_context (GdkWin32Display *display_win32)
231 {
232   PIXELFORMATDESCRIPTOR pfd;
233   gboolean set_pixel_format_result = FALSE;
234   int best_idx = 0;
235 
236   if (display_win32->dummy_context_wgl.hdc == NULL)
237     display_win32->dummy_context_wgl.hdc = GetDC (display_win32->hwnd);
238 
239   memset (&pfd, 0, sizeof (PIXELFORMATDESCRIPTOR));
240 
241   best_idx = get_wgl_pfd (display_win32->dummy_context_wgl.hdc, &pfd, NULL);
242 
243   if (best_idx != 0)
244     set_pixel_format_result = SetPixelFormat (display_win32->dummy_context_wgl.hdc,
245                                               best_idx,
246                                              &pfd);
247 
248   if (best_idx == 0 || !set_pixel_format_result)
249     return 0;
250 
251   display_win32->dummy_context_wgl.hglrc =
252     wglCreateContext (display_win32->dummy_context_wgl.hdc);
253 
254   if (display_win32->dummy_context_wgl.hglrc == NULL)
255     return 0;
256 
257   return best_idx;
258 }
259 
260 gboolean
gdk_win32_display_init_wgl(GdkDisplay * display,GError ** error)261 gdk_win32_display_init_wgl (GdkDisplay  *display,
262                             GError     **error)
263 {
264   int best_idx = 0;
265   GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (display);
266   HDC hdc;
267 
268   if (!gdk_gl_backend_can_be_used (GDK_GL_WGL, error))
269     return FALSE;
270 
271   if (display_win32->wgl_pixel_format != 0)
272     return TRUE;
273 
274   /* acquire and cache dummy Window (HWND & HDC) and
275    * dummy GL Context, it is used to query functions
276    * and used for other stuff as well
277    */
278   best_idx = gdk_init_dummy_wgl_context (display_win32);
279   hdc = display_win32->dummy_context_wgl.hdc;
280 
281   if (best_idx == 0 ||
282      !wglMakeCurrent (hdc, display_win32->dummy_context_wgl.hglrc))
283     {
284       if (display_win32->dummy_context_wgl.hglrc != NULL)
285         wglDeleteContext (display_win32->dummy_context_wgl.hglrc);
286 
287       g_set_error_literal (error, GDK_GL_ERROR,
288                            GDK_GL_ERROR_NOT_AVAILABLE,
289                            _("No GL implementation is available"));
290 
291       return FALSE;
292     }
293 
294   display_win32->gl_version = epoxy_gl_version ();
295 
296   /* We must have OpenGL/WGL 2.0 or later, or have the GL_ARB_shader_objects extension */
297   if (display_win32->gl_version < 20)
298     {
299       if (!epoxy_has_gl_extension ("GL_ARB_shader_objects"))
300         {
301           wglMakeCurrent (NULL, NULL);
302           wglDeleteContext (display_win32->dummy_context_wgl.hglrc);
303 
304           g_set_error_literal (error, GDK_GL_ERROR,
305                                GDK_GL_ERROR_NOT_AVAILABLE,
306                                _("No GL implementation is available"));
307 
308           return FALSE;
309         }
310     }
311 
312   display_win32->wgl_pixel_format = best_idx;
313 
314   display_win32->hasWglARBCreateContext =
315     epoxy_has_wgl_extension (hdc, "WGL_ARB_create_context");
316   display_win32->hasWglEXTSwapControl =
317     epoxy_has_wgl_extension (hdc, "WGL_EXT_swap_control");
318   display_win32->hasWglOMLSyncControl =
319     epoxy_has_wgl_extension (hdc, "WGL_OML_sync_control");
320   display_win32->hasWglARBPixelFormat =
321     epoxy_has_wgl_extension (hdc, "WGL_ARB_pixel_format");
322   display_win32->hasWglARBmultisample =
323     epoxy_has_wgl_extension (hdc, "WGL_ARB_multisample");
324 
325   GDK_NOTE (OPENGL,
326             g_print ("WGL API version %d.%d found\n"
327                      " - Vendor: %s\n"
328                      " - Checked extensions:\n"
329                      "\t* WGL_ARB_pixel_format: %s\n"
330                      "\t* WGL_ARB_create_context: %s\n"
331                      "\t* WGL_EXT_swap_control: %s\n"
332                      "\t* WGL_OML_sync_control: %s\n"
333                      "\t* WGL_ARB_multisample: %s\n",
334                      display_win32->gl_version / 10,
335                      display_win32->gl_version % 10,
336                      glGetString (GL_VENDOR),
337                      display_win32->hasWglARBPixelFormat ? "yes" : "no",
338                      display_win32->hasWglARBCreateContext ? "yes" : "no",
339                      display_win32->hasWglEXTSwapControl ? "yes" : "no",
340                      display_win32->hasWglOMLSyncControl ? "yes" : "no",
341                      display_win32->hasWglARBmultisample ? "yes" : "no"));
342 
343   wglMakeCurrent (NULL, NULL);
344 
345   return TRUE;
346 }
347 
348 /* Setup the legacy context after creating it */
349 static gboolean
ensure_legacy_wgl_context(HDC hdc,HGLRC hglrc_legacy,GdkGLContext * share)350 ensure_legacy_wgl_context (HDC           hdc,
351                            HGLRC         hglrc_legacy,
352                            GdkGLContext *share)
353 {
354   GdkWin32GLContextWGL *context_wgl;
355 
356   if (!wglMakeCurrent (hdc, hglrc_legacy))
357     return FALSE;
358 
359   if (share != NULL)
360     {
361       context_wgl = GDK_WIN32_GL_CONTEXT_WGL (share);
362 
363       return wglShareLists (hglrc_legacy, context_wgl->wgl_context);
364     }
365 
366   return TRUE;
367 }
368 
369 static HGLRC
create_wgl_context_with_attribs(HDC hdc,HGLRC hglrc_base,GdkGLContext * share,int flags,int major,int minor,gboolean * is_legacy)370 create_wgl_context_with_attribs (HDC           hdc,
371                                  HGLRC         hglrc_base,
372                                  GdkGLContext *share,
373                                  int           flags,
374                                  int           major,
375                                  int           minor,
376                                  gboolean     *is_legacy)
377 {
378   HGLRC hglrc;
379   GdkWin32GLContextWGL *context_wgl;
380 
381   /* if we have wglCreateContextAttribsARB(), create a
382   * context with the compatibility profile if a legacy
383   * context is requested, or when we go into fallback mode
384   */
385   int profile = *is_legacy ? WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB :
386                              WGL_CONTEXT_CORE_PROFILE_BIT_ARB;
387 
388   int attribs[] = {
389     WGL_CONTEXT_PROFILE_MASK_ARB,   profile,
390     WGL_CONTEXT_MAJOR_VERSION_ARB, *is_legacy ? 3 : major,
391     WGL_CONTEXT_MINOR_VERSION_ARB, *is_legacy ? 0 : minor,
392     WGL_CONTEXT_FLAGS_ARB,          flags,
393     0
394   };
395 
396   if (share != NULL)
397     context_wgl = GDK_WIN32_GL_CONTEXT_WGL (share);
398 
399   hglrc = wglCreateContextAttribsARB (hdc,
400                                       share != NULL ? context_wgl->wgl_context : NULL,
401                                       attribs);
402 
403   return hglrc;
404 }
405 
406 static HGLRC
create_wgl_context(HDC hdc,GdkGLContext * share,int flags,int major,int minor,gboolean * is_legacy,gboolean hasWglARBCreateContext)407 create_wgl_context (HDC           hdc,
408                     GdkGLContext *share,
409                     int           flags,
410                     int           major,
411                     int           minor,
412                     gboolean     *is_legacy,
413                     gboolean      hasWglARBCreateContext)
414 {
415   /* We need a legacy context for *all* cases */
416   HGLRC hglrc_base = wglCreateContext (hdc);
417   gboolean success = TRUE;
418 
419   /* Save up the HDC and HGLRC that we are currently using, to restore back to it when we are done here  */
420   HDC hdc_current = wglGetCurrentDC ();
421   HGLRC hglrc_current = wglGetCurrentContext ();
422 
423   /* if we have no wglCreateContextAttribsARB(), return the legacy context when all is set */
424   if (*is_legacy && !hasWglARBCreateContext)
425     {
426       if (ensure_legacy_wgl_context (hdc, hglrc_base, share))
427         {
428           wglMakeCurrent (hdc_current, hglrc_current);
429           return hglrc_base;
430         }
431 
432       success = FALSE;
433       goto gl_fail;
434     }
435   else
436     {
437       HGLRC hglrc = NULL;
438 
439       if (!wglMakeCurrent (hdc, hglrc_base))
440         {
441           success = FALSE;
442           goto gl_fail;
443         }
444 
445       /*
446        * We need a Core GL 4.1 context in order to use the GL support in
447        * the GStreamer media widget backend, but wglCreateContextAttribsARB()
448        * may only give us the GL context version that we ask for here, and
449        * nothing more.  So, if we are asking for a pre-GL 4.1 context,
450        * try to ask for a 4.1 context explicitly first.  If that is not supported,
451        * then we fall back to whatever version that we were asking for (or, even a
452        * legacy context if that fails), at a price of not able to have GL support
453        * for the media GStreamer backend.
454        */
455       if (major < 4 || (major == 4 && minor < 1))
456         hglrc = create_wgl_context_with_attribs (hdc,
457                                                  hglrc_base,
458                                                  share,
459                                                  flags,
460                                                  4,
461                                                  1,
462                                                  is_legacy);
463 
464       if (hglrc == NULL)
465         hglrc = create_wgl_context_with_attribs (hdc,
466                                                  hglrc_base,
467                                                  share,
468                                                  flags,
469                                                  major,
470                                                  minor,
471                                                  is_legacy);
472 
473       /* return the legacy context we have if it could be setup properly, in case the 3.0+ context creation failed */
474       if (hglrc == NULL)
475         {
476           if (!(*is_legacy))
477             {
478               /* If we aren't using a legacy context in the beginning, try again with a compatibility profile 3.0 context */
479               hglrc = create_wgl_context_with_attribs (hdc,
480                                                        hglrc_base,
481                                                        share,
482                                                        flags,
483                                                        0, 0,
484                                                        is_legacy);
485 
486               *is_legacy = TRUE;
487             }
488 
489           if (hglrc == NULL)
490             {
491               if (!ensure_legacy_wgl_context (hdc, hglrc_base, share))
492                 success = FALSE;
493             }
494 
495           if (success)
496             GDK_NOTE (OPENGL, g_print ("Using legacy context as fallback\n"));
497         }
498 
499 gl_fail:
500 
501       if (!success)
502         {
503           wglMakeCurrent (NULL, NULL);
504           wglDeleteContext (hglrc_base);
505           return NULL;
506         }
507 
508       wglMakeCurrent (hdc_current, hglrc_current);
509 
510       if (hglrc != NULL)
511         {
512           wglDeleteContext (hglrc_base);
513           return hglrc;
514         }
515 
516       return hglrc_base;
517   }
518 }
519 
520 static gboolean
set_wgl_pixformat_for_hdc(HDC hdc,int * best_idx,GdkWin32Display * display_win32)521 set_wgl_pixformat_for_hdc (HDC              hdc,
522                            int             *best_idx,
523                            GdkWin32Display *display_win32)
524 {
525   gboolean already_checked = TRUE;
526   *best_idx = GetPixelFormat (hdc);
527 
528   /* one is only allowed to call SetPixelFormat(), and so ChoosePixelFormat()
529    * one single time per window HDC
530    */
531   if (*best_idx == 0)
532     {
533       PIXELFORMATDESCRIPTOR pfd;
534       gboolean set_pixel_format_result = FALSE;
535 
536       GDK_NOTE (OPENGL, g_print ("requesting pixel format...\n"));
537 	  already_checked = FALSE;
538       *best_idx = get_wgl_pfd (hdc, &pfd, display_win32);
539 
540       if (*best_idx != 0)
541         set_pixel_format_result = SetPixelFormat (hdc, *best_idx, &pfd);
542 
543       /* ChoosePixelFormat() or SetPixelFormat() failed, bail out */
544       if (*best_idx == 0 || !set_pixel_format_result)
545         return FALSE;
546     }
547 
548   GDK_NOTE (OPENGL, g_print ("%s""requested and set pixel format: %d\n", already_checked ? "already " : "", *best_idx));
549 
550   return TRUE;
551 }
552 
553 static gboolean
gdk_win32_gl_context_wgl_realize(GdkGLContext * context,GError ** error)554 gdk_win32_gl_context_wgl_realize (GdkGLContext *context,
555                                   GError **error)
556 {
557   GdkWin32GLContextWGL *context_wgl = GDK_WIN32_GL_CONTEXT_WGL (context);
558 
559   gboolean debug_bit, compat_bit, legacy_bit;
560 
561   /* request flags and specific versions for core (3.2+) WGL context */
562   int flags = 0;
563   int major = 0;
564   int minor = 0;
565   HGLRC hglrc;
566   int pixel_format;
567   HDC hdc;
568   HWND hwnd;
569 
570   GdkSurface *surface = gdk_gl_context_get_surface (context);
571   GdkDisplay *display = gdk_gl_context_get_display (context);
572   GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (display);
573   GdkGLContext *share = gdk_display_get_gl_context (display);
574 
575   gdk_gl_context_get_required_version (context, &major, &minor);
576   debug_bit = gdk_gl_context_get_debug_enabled (context);
577   compat_bit = gdk_gl_context_get_forward_compatible (context);
578 
579   if (surface != NULL)
580     hdc = GDK_WIN32_SURFACE (surface)->hdc;
581   else
582     hdc = display_win32->dummy_context_wgl.hdc;
583 
584   /*
585    * A legacy context cannot be shared with core profile ones, so this means we
586    * must stick to a legacy context if the shared context is a legacy context
587    */
588   legacy_bit = GDK_DISPLAY_DEBUG_CHECK (display, GL_LEGACY) ?
589                TRUE :
590 			   share != NULL && gdk_gl_context_is_legacy (share);
591 
592   if (!set_wgl_pixformat_for_hdc (hdc,
593                                  &pixel_format,
594                                   display_win32))
595     {
596       g_set_error_literal (error, GDK_GL_ERROR,
597                            GDK_GL_ERROR_UNSUPPORTED_FORMAT,
598                            _("No available configurations for the given pixel format"));
599 
600       return FALSE;
601     }
602 
603   /* if there isn't wglCreateContextAttribsARB() on WGL, use a legacy context */
604   if (!legacy_bit)
605     legacy_bit = !display_win32->hasWglARBCreateContext;
606   if (debug_bit)
607     flags |= WGL_CONTEXT_DEBUG_BIT_ARB;
608   if (compat_bit)
609     flags |= WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
610 
611   GDK_NOTE (OPENGL,
612             g_print ("Creating %s WGL context (version:%d.%d, debug:%s, forward:%s, legacy: %s)\n",
613                       compat_bit ? "core" : "compat",
614                       major,
615                       minor,
616                       debug_bit ? "yes" : "no",
617                       compat_bit ? "yes" : "no",
618                       legacy_bit ? "yes" : "no"));
619 
620   hglrc = create_wgl_context (hdc,
621                               share,
622                               flags,
623                               major,
624                               minor,
625                              &legacy_bit,
626                               display_win32->hasWglARBCreateContext);
627 
628   if (hglrc == NULL)
629     {
630       g_set_error_literal (error, GDK_GL_ERROR,
631                            GDK_GL_ERROR_NOT_AVAILABLE,
632                            _("Unable to create a GL context"));
633       return FALSE;
634     }
635 
636   GDK_NOTE (OPENGL,
637             g_print ("Created WGL context[%p], pixel_format=%d\n",
638                      hglrc,
639                      pixel_format));
640 
641   context_wgl->wgl_context = hglrc;
642 
643   /* No GLES, WGL does not support using EGL contexts */
644   gdk_gl_context_set_use_es (context, FALSE);
645 
646   /* Ensure that any other context is created with a legacy bit set */
647   gdk_gl_context_set_is_legacy (context, legacy_bit);
648 
649   return TRUE;
650 }
651 
652 static gboolean
gdk_win32_gl_context_wgl_clear_current(GdkGLContext * context)653 gdk_win32_gl_context_wgl_clear_current (GdkGLContext *context)
654 {
655   return wglMakeCurrent (NULL, NULL);
656 }
657 
658 static gboolean
gdk_win32_gl_context_wgl_make_current(GdkGLContext * context,gboolean surfaceless)659 gdk_win32_gl_context_wgl_make_current (GdkGLContext *context,
660                                        gboolean      surfaceless)
661 {
662   GdkWin32GLContextWGL *context_wgl = GDK_WIN32_GL_CONTEXT_WGL (context);
663   GdkDisplay *display = gdk_gl_context_get_display (context);
664   GdkWin32Display *display_win32 = GDK_WIN32_DISPLAY (display);
665   GdkSurface *surface = gdk_gl_context_get_surface (context);
666   HDC hdc;
667 
668   if (surfaceless || surface == NULL)
669     hdc = display_win32->dummy_context_wgl.hdc;
670   else
671     hdc = GDK_WIN32_SURFACE (surface)->hdc;
672 
673   if (!wglMakeCurrent (hdc, context_wgl->wgl_context))
674     return FALSE;
675 
676   if (!surfaceless && display_win32->hasWglEXTSwapControl)
677     {
678       gboolean do_frame_sync = FALSE;
679 
680       /* If there is compositing there is no particular need to delay
681        * the swap when drawing on the offscreen, rendering to the screen
682        * happens later anyway, and its up to the compositor to sync that
683        * to the vblank. */
684       do_frame_sync = ! gdk_display_is_composited (display);
685 
686       if (do_frame_sync != context_wgl->do_frame_sync)
687         {
688           context_wgl->do_frame_sync = do_frame_sync;
689 
690           wglSwapIntervalEXT (do_frame_sync ? 1 : 0);
691         }
692     }
693 
694   return TRUE;
695 }
696 
697 static void
gdk_win32_gl_context_wgl_class_init(GdkWin32GLContextWGLClass * klass)698 gdk_win32_gl_context_wgl_class_init (GdkWin32GLContextWGLClass *klass)
699 {
700   GdkGLContextClass *context_class = GDK_GL_CONTEXT_CLASS (klass);
701   GdkDrawContextClass *draw_context_class = GDK_DRAW_CONTEXT_CLASS (klass);
702   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
703 
704   context_class->backend_type = GDK_GL_WGL;
705 
706   context_class->realize = gdk_win32_gl_context_wgl_realize;
707   context_class->make_current = gdk_win32_gl_context_wgl_make_current;
708   context_class->clear_current = gdk_win32_gl_context_wgl_clear_current;
709 
710   draw_context_class->begin_frame = gdk_win32_gl_context_wgl_begin_frame;
711   draw_context_class->end_frame = gdk_win32_gl_context_wgl_end_frame;
712   gobject_class->dispose = gdk_win32_gl_context_wgl_dispose;
713 }
714 
715 static void
gdk_win32_gl_context_wgl_init(GdkWin32GLContextWGL * wgl_context)716 gdk_win32_gl_context_wgl_init (GdkWin32GLContextWGL *wgl_context)
717 {
718 }
719 
720 
721 /**
722  * gdk_win32_display_get_wgl_version:
723  * @display: a `GdkDisplay`
724  * @major: (out): return location for the WGL major version
725  * @minor: (out): return location for the WGL minor version
726  *
727  * Retrieves the version of the WGL implementation.
728  *
729  * Returns: %TRUE if WGL is available
730  */
731 gboolean
gdk_win32_display_get_wgl_version(GdkDisplay * display,int * major,int * minor)732 gdk_win32_display_get_wgl_version (GdkDisplay *display,
733                                    int *major,
734                                    int *minor)
735 {
736   GdkWin32Display *display_win32;
737   g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
738 
739   if (!GDK_IS_WIN32_DISPLAY (display))
740     return FALSE;
741 
742   display_win32 = GDK_WIN32_DISPLAY (display);
743   if (display_win32->wgl_pixel_format == 0)
744     return FALSE;
745 
746   if (major != NULL)
747     *major = display_win32->gl_version / 10;
748   if (minor != NULL)
749     *minor = display_win32->gl_version % 10;
750 
751   return TRUE;
752 }
753