1 /* GDK - The GIMP Drawing Kit
2  *
3  * gdkglcontext-glx.c: GLX specific wrappers
4  *
5  * SPDX-FileCopyrightText: 2014  Emmanuele Bassi
6  * SPDX-FileCopyrightText: 2021  GNOME Foundation
7  *
8  * SPDX-License-Identifier: LGPL-2.1-or-later
9  */
10 
11 #include "config.h"
12 
13 #include "gdkglcontext-x11.h"
14 #include "gdkdisplay-x11.h"
15 #include "gdkprivate-x11.h"
16 #include "gdkscreen-x11.h"
17 
18 #include "gdkx11display.h"
19 #include "gdkx11glcontext.h"
20 #include "gdkx11screen.h"
21 #include "gdkx11surface.h"
22 #include "gdkx11property.h"
23 #include <X11/Xatom.h>
24 
25 #include "gdkinternals.h"
26 #include "gdkprofilerprivate.h"
27 #include "gdkintl.h"
28 
29 #include <cairo-xlib.h>
30 
31 #include <epoxy/glx.h>
32 
33 struct _GdkX11GLContextGLX
34 {
35   GdkX11GLContext parent_instance;
36 
37   GLXContext glx_context;
38 
39 #ifdef HAVE_XDAMAGE
40   GLsync frame_fence;
41   Damage xdamage;
42 #endif
43 
44   guint do_frame_sync : 1;
45 };
46 
47 typedef struct _GdkX11GLContextClass    GdkX11GLContextGLXClass;
48 
G_DEFINE_TYPE(GdkX11GLContextGLX,gdk_x11_gl_context_glx,GDK_TYPE_X11_GL_CONTEXT)49 G_DEFINE_TYPE (GdkX11GLContextGLX, gdk_x11_gl_context_glx, GDK_TYPE_X11_GL_CONTEXT)
50 
51 static GLXDrawable
52 gdk_x11_surface_get_glx_drawable (GdkSurface *surface)
53 {
54   GdkX11Surface *self = GDK_X11_SURFACE (surface);
55   GdkDisplay *display = gdk_surface_get_display (GDK_SURFACE (self));
56   GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
57 
58   if (self->glx_drawable)
59     return self->glx_drawable;
60 
61   self->glx_drawable = glXCreateWindow (gdk_x11_display_get_xdisplay (display),
62                                         display_x11->glx_config,
63                                         gdk_x11_surface_get_xid (surface),
64                                         NULL);
65 
66   return self->glx_drawable;
67 }
68 
69 void
gdk_x11_surface_destroy_glx_drawable(GdkX11Surface * self)70 gdk_x11_surface_destroy_glx_drawable (GdkX11Surface *self)
71 {
72   if (self->glx_drawable == None)
73     return;
74 
75   glXDestroyWindow (gdk_x11_display_get_xdisplay (gdk_surface_get_display (GDK_SURFACE (self))),
76                     self->glx_drawable);
77 
78   self->glx_drawable = None;
79 }
80 
81 static void
maybe_wait_for_vblank(GdkDisplay * display,GLXDrawable drawable)82 maybe_wait_for_vblank (GdkDisplay  *display,
83                        GLXDrawable  drawable)
84 {
85   GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
86   Display *dpy = gdk_x11_display_get_xdisplay (display);
87 
88   if (display_x11->has_glx_sync_control)
89     {
90       gint64 ust, msc, sbc;
91 
92       glXGetSyncValuesOML (dpy, drawable, &ust, &msc, &sbc);
93       glXWaitForMscOML (dpy, drawable,
94                         0, 2, (msc + 1) % 2,
95                         &ust, &msc, &sbc);
96     }
97   else if (display_x11->has_glx_video_sync)
98     {
99       guint32 current_count;
100 
101       glXGetVideoSyncSGI (&current_count);
102       glXWaitVideoSyncSGI (2, (current_count + 1) % 2, &current_count);
103     }
104 }
105 
106 static GLXDrawable
gdk_x11_gl_context_glx_get_drawable(GdkX11GLContextGLX * self)107 gdk_x11_gl_context_glx_get_drawable (GdkX11GLContextGLX *self)
108 {
109   GdkDrawContext *draw_context = GDK_DRAW_CONTEXT (self);
110   GdkSurface *surface;
111 
112   if (gdk_draw_context_is_in_frame (draw_context))
113     surface = gdk_draw_context_get_surface (draw_context);
114   else
115     surface = GDK_X11_DISPLAY (gdk_draw_context_get_display (draw_context))->leader_gdk_surface;
116 
117   return gdk_x11_surface_get_glx_drawable (surface);
118 }
119 
120 static void
gdk_x11_gl_context_glx_end_frame(GdkDrawContext * draw_context,cairo_region_t * painted)121 gdk_x11_gl_context_glx_end_frame (GdkDrawContext *draw_context,
122                                   cairo_region_t *painted)
123 {
124   GdkX11GLContextGLX *self = GDK_X11_GL_CONTEXT_GLX (draw_context);
125   GdkGLContext *context = GDK_GL_CONTEXT (draw_context);
126   GdkSurface *surface = gdk_gl_context_get_surface (context);
127   GdkX11Surface *x11_surface = GDK_X11_SURFACE (surface);
128   GdkDisplay *display = gdk_gl_context_get_display (context);
129   Display *dpy = gdk_x11_display_get_xdisplay (display);
130   GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
131   GLXDrawable drawable;
132 
133   GDK_DRAW_CONTEXT_CLASS (gdk_x11_gl_context_glx_parent_class)->end_frame (draw_context, painted);
134 
135   gdk_gl_context_make_current (context);
136 
137   drawable = gdk_x11_surface_get_glx_drawable (surface);
138 
139   GDK_DISPLAY_NOTE (display, OPENGL,
140             g_message ("Flushing GLX buffers for drawable %lu (window: %lu), frame sync: %s",
141                        (unsigned long) drawable,
142                        (unsigned long) gdk_x11_surface_get_xid (surface),
143                        self->do_frame_sync ? "yes" : "no"));
144 
145   gdk_profiler_add_mark (GDK_PROFILER_CURRENT_TIME, 0, "x11", "swap buffers");
146 
147   /* if we are going to wait for the vertical refresh manually
148    * we need to flush pending redraws, and we also need to wait
149    * for that to finish, otherwise we are going to tear.
150    *
151    * obviously, this condition should not be hit if we have
152    * GLX_SGI_swap_control, and we ask the driver to do the right
153    * thing.
154    */
155   if (self->do_frame_sync)
156     {
157       guint32 end_frame_counter = 0;
158       gboolean has_counter = display_x11->has_glx_video_sync;
159       gboolean can_wait = display_x11->has_glx_video_sync || display_x11->has_glx_sync_control;
160 
161       if (display_x11->has_glx_video_sync)
162         glXGetVideoSyncSGI (&end_frame_counter);
163 
164       if (self->do_frame_sync && !display_x11->has_glx_swap_interval)
165         {
166           glFinish ();
167 
168           if (has_counter && can_wait)
169             {
170               if (x11_surface->glx_frame_counter == end_frame_counter)
171                 maybe_wait_for_vblank (display, drawable);
172             }
173           else if (can_wait)
174             maybe_wait_for_vblank (display, drawable);
175         }
176     }
177 
178   gdk_x11_surface_pre_damage (surface);
179 
180 #ifdef HAVE_XDAMAGE
181   if (self->xdamage != 0 && _gdk_x11_surface_syncs_frames (surface))
182     {
183       g_assert (self->frame_fence == 0);
184 
185       self->frame_fence = glFenceSync (GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
186 
187       /* We consider the frame still getting painted until the GL operation is
188        * finished, and the window gets damage reported from the X server.
189        * It's only at this point the compositor can be sure it has full
190        * access to the new updates.
191        */
192       _gdk_x11_surface_set_frame_still_painting (surface, TRUE);
193     }
194 #endif
195 
196   glXSwapBuffers (dpy, drawable);
197 
198   if (self->do_frame_sync && display_x11->has_glx_video_sync)
199     glXGetVideoSyncSGI (&x11_surface->glx_frame_counter);
200 }
201 
202 static gboolean
gdk_x11_gl_context_glx_clear_current(GdkGLContext * context)203 gdk_x11_gl_context_glx_clear_current (GdkGLContext *context)
204 {
205   GdkDisplay *display = gdk_gl_context_get_display (context);
206   Display *dpy = gdk_x11_display_get_xdisplay (display);
207 
208   glXMakeContextCurrent (dpy, None, None, NULL);
209   return TRUE;
210 }
211 
212 static gboolean
gdk_x11_gl_context_glx_make_current(GdkGLContext * context,gboolean surfaceless)213 gdk_x11_gl_context_glx_make_current (GdkGLContext *context,
214                                      gboolean      surfaceless)
215 
216 {
217   GdkX11GLContextGLX *self = GDK_X11_GL_CONTEXT_GLX (context);
218   GdkDisplay *display = gdk_gl_context_get_display (context);
219   Display *dpy = gdk_x11_display_get_xdisplay (display);
220   gboolean do_frame_sync = FALSE;
221   GdkSurface *surface;
222   GLXWindow drawable;
223 
224   drawable = gdk_x11_gl_context_glx_get_drawable (self);
225 
226   if (!surfaceless)
227     surface = gdk_gl_context_get_surface (context);
228   else
229     surface = GDK_X11_DISPLAY (display)->leader_gdk_surface;
230   drawable = gdk_x11_surface_get_glx_drawable (surface);
231 
232   GDK_DISPLAY_NOTE (display, OPENGL,
233                     g_message ("Making GLX context %p current to drawable %lu",
234                                context, (unsigned long) drawable));
235 
236   if (!glXMakeContextCurrent (dpy, drawable, drawable, self->glx_context))
237     return FALSE;
238 
239   if (!surfaceless && GDK_X11_DISPLAY (display)->has_glx_swap_interval)
240     {
241       /* If the WM is compositing there is no particular need to delay
242        * the swap when drawing on the offscreen, rendering to the screen
243        * happens later anyway, and its up to the compositor to sync that
244        * to the vblank. */
245       do_frame_sync = ! gdk_display_is_composited (display);
246 
247       if (do_frame_sync != self->do_frame_sync)
248         {
249           self->do_frame_sync = do_frame_sync;
250 
251           if (do_frame_sync)
252             glXSwapIntervalSGI (1);
253           else
254             glXSwapIntervalSGI (0);
255         }
256     }
257 
258   return TRUE;
259 }
260 
261 static cairo_region_t *
gdk_x11_gl_context_glx_get_damage(GdkGLContext * context)262 gdk_x11_gl_context_glx_get_damage (GdkGLContext *context)
263 {
264   GdkDisplay *display = gdk_draw_context_get_display (GDK_DRAW_CONTEXT (context));
265   GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
266   Display *dpy = gdk_x11_display_get_xdisplay (display);
267   unsigned int buffer_age = 0;
268 
269   if (display_x11->has_glx_buffer_age)
270     {
271       GdkX11GLContextGLX *self = GDK_X11_GL_CONTEXT_GLX (context);
272 
273       gdk_gl_context_make_current (context);
274       glXQueryDrawable (dpy, gdk_x11_gl_context_glx_get_drawable (self),
275                         GLX_BACK_BUFFER_AGE_EXT, &buffer_age);
276 
277       switch (buffer_age)
278         {
279           case 1:
280             return cairo_region_create ();
281             break;
282 
283           case 2:
284             if (context->old_updated_area[0])
285               return cairo_region_copy (context->old_updated_area[0]);
286             break;
287 
288           case 3:
289             if (context->old_updated_area[0] &&
290                 context->old_updated_area[1])
291               {
292                 cairo_region_t *damage = cairo_region_copy (context->old_updated_area[0]);
293                 cairo_region_union (damage, context->old_updated_area[1]);
294                 return damage;
295               }
296             break;
297 
298           default:
299             ;
300         }
301     }
302 
303   return GDK_GL_CONTEXT_CLASS (gdk_x11_gl_context_glx_parent_class)->get_damage (context);
304 }
305 
306 static GLXContext
create_gl3_context(GdkDisplay * display,GLXFBConfig config,GdkGLContext * share,int profile,int flags,int major,int minor)307 create_gl3_context (GdkDisplay   *display,
308                     GLXFBConfig   config,
309                     GdkGLContext *share,
310                     int           profile,
311                     int           flags,
312                     int           major,
313                     int           minor)
314 {
315   int attrib_list[] = {
316     GLX_CONTEXT_PROFILE_MASK_ARB, profile,
317     GLX_CONTEXT_MAJOR_VERSION_ARB, major,
318     GLX_CONTEXT_MINOR_VERSION_ARB, minor,
319     GLX_CONTEXT_FLAGS_ARB, flags,
320     None,
321   };
322   GLXContext res;
323 
324   GdkX11GLContextGLX *share_glx = NULL;
325 
326   if (share != NULL)
327     share_glx = GDK_X11_GL_CONTEXT_GLX (share);
328 
329   gdk_x11_display_error_trap_push (display);
330 
331   res = glXCreateContextAttribsARB (gdk_x11_display_get_xdisplay (display),
332                                     config,
333                                     share_glx != NULL ? share_glx->glx_context : NULL,
334                                     True,
335                                     attrib_list);
336 
337   if (gdk_x11_display_error_trap_pop (display))
338     return NULL;
339 
340   return res;
341 }
342 
343 static GLXContext
create_legacy_context(GdkDisplay * display,GLXFBConfig config,GdkGLContext * share)344 create_legacy_context (GdkDisplay   *display,
345                        GLXFBConfig   config,
346                        GdkGLContext *share)
347 {
348   GdkX11GLContextGLX *share_glx = NULL;
349   GLXContext res;
350 
351   if (share != NULL)
352     share_glx = GDK_X11_GL_CONTEXT_GLX (share);
353 
354   gdk_x11_display_error_trap_push (display);
355 
356   res = glXCreateNewContext (gdk_x11_display_get_xdisplay (display),
357                              config,
358                              GLX_RGBA_TYPE,
359                              share_glx != NULL ? share_glx->glx_context : NULL,
360                              TRUE);
361 
362   if (gdk_x11_display_error_trap_pop (display))
363     return NULL;
364 
365   return res;
366 }
367 
368 #ifdef HAVE_XDAMAGE
369 static void
bind_context_for_frame_fence(GdkX11GLContextGLX * self)370 bind_context_for_frame_fence (GdkX11GLContextGLX *self)
371 {
372   GdkX11GLContextGLX *current_context_glx;
373   GLXContext current_glx_context = NULL;
374   GdkGLContext *current_context;
375   gboolean needs_binding = TRUE;
376 
377   /* We don't care if the passed context is the current context,
378    * necessarily, but we do care that *some* context that can
379    * see the sync object is bound.
380    *
381    * If no context is bound at all, the GL dispatch layer will
382    * make glClientWaitSync() silently return 0.
383    */
384   current_glx_context = glXGetCurrentContext ();
385 
386   if (current_glx_context == NULL)
387     goto out;
388 
389   current_context = gdk_gl_context_get_current ();
390 
391   if (current_context == NULL)
392     goto out;
393 
394   current_context_glx = GDK_X11_GL_CONTEXT_GLX (current_context);
395 
396   /* If the GLX context was changed out from under GDK, then
397    * that context may not be one that is able to see the
398    * created fence object.
399    */
400   if (current_context_glx->glx_context != current_glx_context)
401     goto out;
402 
403   needs_binding = FALSE;
404 
405 out:
406   if (needs_binding)
407     gdk_gl_context_make_current (GDK_GL_CONTEXT (self));
408 }
409 
410 static void
finish_frame(GdkGLContext * context)411 finish_frame (GdkGLContext *context)
412 {
413   GdkX11GLContextGLX *context_glx = GDK_X11_GL_CONTEXT_GLX (context);
414   GdkSurface *surface = gdk_gl_context_get_surface (context);
415 
416   if (context_glx->xdamage == 0)
417     return;
418 
419   if (context_glx->frame_fence == 0)
420     return;
421 
422   glDeleteSync (context_glx->frame_fence);
423   context_glx->frame_fence = 0;
424 
425   _gdk_x11_surface_set_frame_still_painting (surface, FALSE);
426 }
427 
428 static gboolean
on_gl_surface_xevent(GdkGLContext * context,XEvent * xevent,GdkX11Display * display_x11)429 on_gl_surface_xevent (GdkGLContext   *context,
430                       XEvent         *xevent,
431                       GdkX11Display  *display_x11)
432 {
433   GdkX11GLContextGLX *context_glx = GDK_X11_GL_CONTEXT_GLX (context);
434   XDamageNotifyEvent *damage_xevent;
435 
436   if (xevent->type != (display_x11->damage_event_base + XDamageNotify))
437     return FALSE;
438 
439   damage_xevent = (XDamageNotifyEvent *) xevent;
440 
441   if (damage_xevent->damage != context_glx->xdamage)
442     return FALSE;
443 
444   if (context_glx->frame_fence)
445     {
446       GLenum wait_result;
447 
448       bind_context_for_frame_fence (context_glx);
449 
450       wait_result = glClientWaitSync (context_glx->frame_fence, 0, 0);
451 
452       switch (wait_result)
453         {
454           /* We assume that if the fence has been signaled, that this damage
455            * event is the damage event that was triggered by the GL drawing
456            * associated with the fence. That's, technically, not necessarly
457            * always true. The X server could have generated damage for
458            * an unrelated event (say the size of the window changing), at
459            * just the right moment such that we're picking it up instead.
460            *
461            * We're choosing not to handle this edge case, but if it does ever
462            * happen in the wild, it could lead to slight underdrawing by
463            * the compositor for one frame. In the future, if we find out
464            * this edge case is noticeable, we can compensate by copying the
465            * painted region from gdk_x11_gl_context_end_frame and subtracting
466            * damaged areas from the copy as they come in. Once the copied
467            * region goes empty, we know that there won't be any underdraw,
468            * and can mark painting has finished. It's not worth the added
469            * complexity and resource usage to do this bookkeeping, however,
470            * unless the problem is practically visible.
471            */
472           case GL_ALREADY_SIGNALED:
473           case GL_CONDITION_SATISFIED:
474           case GL_WAIT_FAILED:
475             if (wait_result == GL_WAIT_FAILED)
476               g_warning ("failed to wait on GL fence associated with last swap buffers call");
477             finish_frame (context);
478             break;
479 
480           /* We assume that if the fence hasn't been signaled, that this
481            * damage event is not the damage event that was triggered by the
482            * GL drawing associated with the fence. That's only true for
483            * the Nvidia vendor driver. When using open source drivers, damage
484            * is emitted immediately on swap buffers, before the fence ever
485            * has a chance to signal.
486            */
487           case GL_TIMEOUT_EXPIRED:
488             break;
489           default:
490             g_error ("glClientWaitSync returned unexpected result: %x", (guint) wait_result);
491         }
492     }
493 
494   return FALSE;
495 }
496 
497 static void
on_surface_state_changed(GdkGLContext * context)498 on_surface_state_changed (GdkGLContext *context)
499 {
500   GdkSurface *surface = gdk_gl_context_get_surface (context);
501 
502   if (GDK_SURFACE_IS_MAPPED (surface))
503     return;
504 
505   /* If we're about to withdraw the surface, then we don't care if the frame is
506    * still getting rendered by the GPU. The compositor is going to remove the surface
507    * from the scene anyway, so wrap up the frame.
508    */
509   finish_frame (context);
510 }
511 #endif
512 
513 static gboolean
gdk_x11_gl_context_glx_realize(GdkGLContext * context,GError ** error)514 gdk_x11_gl_context_glx_realize (GdkGLContext  *context,
515                                 GError       **error)
516 {
517   GdkX11Display *display_x11;
518   GdkDisplay *display;
519   GdkX11GLContextGLX *context_glx;
520   Display *dpy;
521   GdkSurface *surface;
522   GdkGLContext *share;
523   gboolean debug_bit, compat_bit, legacy_bit, es_bit;
524   int major, minor, flags;
525 
526   display = gdk_gl_context_get_display (context);
527   dpy = gdk_x11_display_get_xdisplay (display);
528   context_glx = GDK_X11_GL_CONTEXT_GLX (context);
529   display_x11 = GDK_X11_DISPLAY (display);
530   share = gdk_display_get_gl_context (display);
531   surface = gdk_gl_context_get_surface (context);
532 
533   gdk_gl_context_get_required_version (context, &major, &minor);
534   debug_bit = gdk_gl_context_get_debug_enabled (context);
535   compat_bit = gdk_gl_context_get_forward_compatible (context);
536 
537   /* If there is no glXCreateContextAttribsARB() then we default to legacy */
538   legacy_bit = !display_x11->has_glx_create_context || GDK_DISPLAY_DEBUG_CHECK (display, GL_LEGACY);
539 
540   es_bit = (GDK_DISPLAY_DEBUG_CHECK (display, GL_GLES) || (share != NULL && gdk_gl_context_get_use_es (share))) &&
541            (display_x11->has_glx_create_context && display_x11->has_glx_create_es2_context);
542 
543   /* We cannot share legacy contexts with core profile ones, so the
544    * shared context is the one that decides if we're going to create
545    * a legacy context or not.
546    */
547   if (share != NULL && gdk_gl_context_is_legacy (share))
548     legacy_bit = TRUE;
549 
550   flags = 0;
551   if (debug_bit)
552     flags |= GLX_CONTEXT_DEBUG_BIT_ARB;
553   if (compat_bit)
554     flags |= GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
555 
556   GDK_DISPLAY_NOTE (display, OPENGL,
557             g_message ("Creating GLX context (GL version:%d.%d, debug:%s, forward:%s, legacy:%s, es:%s)",
558                        major, minor,
559                        debug_bit ? "yes" : "no",
560                        compat_bit ? "yes" : "no",
561                        legacy_bit ? "yes" : "no",
562                        es_bit ? "yes" : "no"));
563 
564   /* If we have access to GLX_ARB_create_context_profile then we can ask for
565    * a compatibility profile; if we don't, then we have to fall back to the
566    * old GLX 1.3 API.
567    */
568   if (legacy_bit && !GDK_X11_DISPLAY (display)->has_glx_create_context)
569     {
570       GDK_DISPLAY_NOTE (display, OPENGL, g_message ("Creating legacy GL context on request"));
571       context_glx->glx_context = create_legacy_context (display, display_x11->glx_config, share);
572     }
573   else
574     {
575       int profile;
576 
577       if (es_bit)
578         profile = GLX_CONTEXT_ES2_PROFILE_BIT_EXT;
579       else
580         profile = legacy_bit ? GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB
581                              : GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
582 
583       /* We need to tweak the version, otherwise we may end up requesting
584        * a compatibility context with a minimum version of 3.2, which is
585        * an error
586        */
587       if (legacy_bit)
588         {
589           major = 3;
590           minor = 0;
591         }
592 
593       GDK_DISPLAY_NOTE (display, OPENGL, g_message ("Creating GL3 context"));
594       context_glx->glx_context = create_gl3_context (display,
595                                                      display_x11->glx_config,
596                                                      share,
597                                                      profile, flags, major, minor);
598 
599       /* Fall back to legacy in case the GL3 context creation failed */
600       if (context_glx->glx_context == NULL)
601         {
602           GDK_DISPLAY_NOTE (display, OPENGL, g_message ("Creating fallback legacy context"));
603           context_glx->glx_context = create_legacy_context (display, display_x11->glx_config, share);
604           legacy_bit = TRUE;
605           es_bit = FALSE;
606         }
607     }
608 
609   if (context_glx->glx_context == NULL)
610     {
611       g_set_error_literal (error, GDK_GL_ERROR,
612                            GDK_GL_ERROR_NOT_AVAILABLE,
613                            _("Unable to create a GL context"));
614       return FALSE;
615     }
616 
617   /* Ensure that any other context is created with a legacy bit set */
618   gdk_gl_context_set_is_legacy (context, legacy_bit);
619 
620   /* Ensure that any other context is created with an ES bit set */
621   gdk_gl_context_set_use_es (context, es_bit);
622 
623   GDK_DISPLAY_NOTE (display, OPENGL,
624             g_message ("Realized GLX context[%p], %s, version: %d.%d",
625                        context_glx->glx_context,
626                        glXIsDirect (dpy, context_glx->glx_context) ? "direct" : "indirect",
627                        display_x11->glx_version / 10,
628                        display_x11->glx_version % 10));
629 
630 #ifdef HAVE_XDAMAGE
631   if (display_x11->have_damage &&
632       display_x11->has_async_glx_swap_buffers)
633     {
634       gdk_x11_display_error_trap_push (display);
635       context_glx->xdamage = XDamageCreate (dpy,
636                                             gdk_x11_surface_get_xid (surface),
637                                             XDamageReportRawRectangles);
638       if (gdk_x11_display_error_trap_pop (display))
639         {
640           context_glx->xdamage = 0;
641         }
642       else
643         {
644           g_signal_connect_object (G_OBJECT (display),
645                                    "xevent",
646                                    G_CALLBACK (on_gl_surface_xevent),
647                                    context,
648                                    G_CONNECT_SWAPPED);
649           g_signal_connect_object (G_OBJECT (surface),
650                                    "notify::state",
651                                    G_CALLBACK (on_surface_state_changed),
652                                    context,
653                                    G_CONNECT_SWAPPED);
654 
655         }
656     }
657 #endif
658 
659   return TRUE;
660 }
661 
662 static void
gdk_x11_gl_context_glx_dispose(GObject * gobject)663 gdk_x11_gl_context_glx_dispose (GObject *gobject)
664 {
665   GdkX11GLContextGLX *context_glx = GDK_X11_GL_CONTEXT_GLX (gobject);
666 
667 #ifdef HAVE_XDAMAGE
668   context_glx->xdamage = 0;
669 #endif
670 
671   if (context_glx->glx_context != NULL)
672     {
673       GdkGLContext *context = GDK_GL_CONTEXT (gobject);
674       GdkDisplay *display = gdk_gl_context_get_display (context);
675       Display *dpy = gdk_x11_display_get_xdisplay (display);
676 
677       if (glXGetCurrentContext () == context_glx->glx_context)
678         glXMakeContextCurrent (dpy, None, None, NULL);
679 
680       GDK_DISPLAY_NOTE (display, OPENGL, g_message ("Destroying GLX context"));
681       glXDestroyContext (dpy, context_glx->glx_context);
682       context_glx->glx_context = NULL;
683     }
684 
685   G_OBJECT_CLASS (gdk_x11_gl_context_glx_parent_class)->dispose (gobject);
686 }
687 
688 static void
gdk_x11_gl_context_glx_class_init(GdkX11GLContextGLXClass * klass)689 gdk_x11_gl_context_glx_class_init (GdkX11GLContextGLXClass *klass)
690 {
691   GdkGLContextClass *context_class = GDK_GL_CONTEXT_CLASS (klass);
692   GdkDrawContextClass *draw_context_class = GDK_DRAW_CONTEXT_CLASS (klass);
693   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
694 
695   context_class->backend_type = GDK_GL_GLX;
696 
697   context_class->realize = gdk_x11_gl_context_glx_realize;
698   context_class->make_current = gdk_x11_gl_context_glx_make_current;
699   context_class->clear_current = gdk_x11_gl_context_glx_clear_current;
700   context_class->get_damage = gdk_x11_gl_context_glx_get_damage;
701 
702   draw_context_class->end_frame = gdk_x11_gl_context_glx_end_frame;
703 
704   gobject_class->dispose = gdk_x11_gl_context_glx_dispose;
705 }
706 
707 static void
gdk_x11_gl_context_glx_init(GdkX11GLContextGLX * self)708 gdk_x11_gl_context_glx_init (GdkX11GLContextGLX *self)
709 {
710   self->do_frame_sync = TRUE;
711 }
712 
713 static gboolean
visual_is_rgba(XVisualInfo * visinfo)714 visual_is_rgba (XVisualInfo *visinfo)
715 {
716   return
717     visinfo->depth == 32 &&
718     visinfo->visual->red_mask   == 0xff0000 &&
719     visinfo->visual->green_mask == 0x00ff00 &&
720     visinfo->visual->blue_mask  == 0x0000ff;
721 }
722 
723 #define MAX_GLX_ATTRS   30
724 
725 static gboolean
gdk_x11_display_create_glx_config(GdkX11Display * self,Visual ** out_visual,int * out_depth,GError ** error)726 gdk_x11_display_create_glx_config (GdkX11Display  *self,
727                                    Visual        **out_visual,
728                                    int            *out_depth,
729                                    GError        **error)
730 {
731   GdkDisplay *display = GDK_DISPLAY (self);
732   Display *dpy = gdk_x11_display_get_xdisplay (display);
733   int attrs[MAX_GLX_ATTRS];
734   GLXFBConfig *configs;
735   int count;
736   enum {
737     NO_VISUAL_FOUND,
738     WITH_MULTISAMPLING,
739     WITH_STENCIL_AND_DEPTH_BUFFER,
740     NO_ALPHA,
741     NO_ALPHA_VISUAL,
742     PERFECT
743   } best_features;
744   int i = 0;
745 
746   attrs[i++] = GLX_DRAWABLE_TYPE;
747   attrs[i++] = GLX_WINDOW_BIT;
748 
749   attrs[i++] = GLX_RENDER_TYPE;
750   attrs[i++] = GLX_RGBA_BIT;
751 
752   attrs[i++] = GLX_DOUBLEBUFFER;
753   attrs[i++] = GL_TRUE;
754 
755   attrs[i++] = GLX_RED_SIZE;
756   attrs[i++] = 1;
757   attrs[i++] = GLX_GREEN_SIZE;
758   attrs[i++] = 1;
759   attrs[i++] = GLX_BLUE_SIZE;
760   attrs[i++] = 1;
761   attrs[i++] = GLX_ALPHA_SIZE;
762   attrs[i++] = 1;
763 
764   attrs[i++] = None;
765   g_assert (i < MAX_GLX_ATTRS);
766 
767   configs = glXChooseFBConfig (dpy, DefaultScreen (dpy), attrs, &count);
768   if (configs == NULL || count == 0)
769     {
770       g_set_error_literal (error, GDK_GL_ERROR,
771                            GDK_GL_ERROR_NOT_AVAILABLE,
772                            _("No GLX configurations available"));
773       return FALSE;
774     }
775 
776   best_features = NO_VISUAL_FOUND;
777 
778   for (i = 0; i < count; i++)
779     {
780       XVisualInfo *visinfo;
781       int tmp;
782 
783       visinfo = glXGetVisualFromFBConfig (dpy, configs[i]);
784       if (visinfo == NULL)
785         continue;
786 
787       if (glXGetFBConfigAttrib (dpy, configs[i], GLX_SAMPLE_BUFFERS_ARB, &tmp) != Success || tmp != 0)
788         {
789           if (best_features < WITH_MULTISAMPLING)
790             {
791               GDK_NOTE (OPENGL, g_message ("Best GLX config is %u for visual 0x%lX with multisampling", i, visinfo->visualid));
792               best_features = WITH_MULTISAMPLING;
793               *out_visual = visinfo->visual;
794               *out_depth = visinfo->depth;
795               self->glx_config = configs[i];
796             }
797           XFree (visinfo);
798           continue;
799         }
800 
801       if (glXGetFBConfigAttrib (dpy, configs[i], GLX_DEPTH_SIZE, &tmp) != Success || tmp != 0 ||
802           glXGetFBConfigAttrib (dpy, configs[i], GLX_STENCIL_SIZE, &tmp) != Success || tmp != 0)
803         {
804           if (best_features < WITH_STENCIL_AND_DEPTH_BUFFER)
805             {
806               GDK_NOTE (OPENGL, g_message ("Best GLX config is %u for visual 0x%lX with a stencil or depth buffer", i, visinfo->visualid));
807               best_features = WITH_STENCIL_AND_DEPTH_BUFFER;
808               *out_visual = visinfo->visual;
809               *out_depth = visinfo->depth;
810               self->glx_config = configs[i];
811             }
812           XFree (visinfo);
813           continue;
814         }
815 
816       if (!visual_is_rgba (visinfo))
817         {
818           if (best_features < NO_ALPHA_VISUAL)
819             {
820               GDK_NOTE (OPENGL, g_message ("Best GLX config is %u for visual 0x%lX with no RGBA Visual", i, visinfo->visualid));
821               best_features = NO_ALPHA_VISUAL;
822               *out_visual = visinfo->visual;
823               *out_depth = visinfo->depth;
824               self->glx_config = configs[i];
825             }
826           XFree (visinfo);
827           continue;
828         }
829 
830       GDK_NOTE (OPENGL, g_message ("GLX config %u for visual 0x%lX is the perfect choice", i, visinfo->visualid));
831       best_features = PERFECT;
832       *out_visual = visinfo->visual;
833       *out_depth = visinfo->depth;
834       self->glx_config = configs[i];
835       XFree (visinfo);
836       break;
837     }
838 
839   XFree (configs);
840 
841   if (best_features == NO_VISUAL_FOUND)
842     {
843       g_set_error_literal (error, GDK_GL_ERROR,
844                            GDK_GL_ERROR_NOT_AVAILABLE,
845                            _("No GLX configuration with required features found"));
846       return FALSE;
847     }
848 
849   return TRUE;
850 }
851 
852 #undef MAX_GLX_ATTRS
853 
854 /**
855  * gdk_x11_display_get_glx_version:
856  * @display: (type GdkX11Display): a `GdkDisplay`
857  * @major: (out): return location for the GLX major version
858  * @minor: (out): return location for the GLX minor version
859  *
860  * Retrieves the version of the GLX implementation.
861  *
862  * Returns: %TRUE if GLX is available
863  */
864 gboolean
gdk_x11_display_get_glx_version(GdkDisplay * display,int * major,int * minor)865 gdk_x11_display_get_glx_version (GdkDisplay *display,
866                                  int        *major,
867                                  int        *minor)
868 {
869   g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
870 
871   if (!GDK_IS_X11_DISPLAY (display))
872     return FALSE;
873 
874   GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
875 
876   if (display_x11->glx_config == NULL)
877     return FALSE;
878 
879   if (major != NULL)
880     *major = display_x11->glx_version / 10;
881   if (minor != NULL)
882     *minor = display_x11->glx_version % 10;
883 
884   return TRUE;
885 }
886 
887 /*< private >
888  * gdk_x11_display_init_glx:
889  * @display_x11: an X11 display that has not been inited yet.
890  * @out_visual: set to the Visual to be used with the returned config
891  * @out_depth: set to the depth to be used with the returned config
892  * @error: Return location for error
893  *
894  * Initializes the cached GLX state for the given @screen.
895  *
896  * This function must be called exactly once during initialization.
897  *
898  * Returns: %TRUE if GLX was initialized
899  */
900 gboolean
gdk_x11_display_init_glx(GdkX11Display * display_x11,Visual ** out_visual,int * out_depth,GError ** error)901 gdk_x11_display_init_glx (GdkX11Display  *display_x11,
902                           Visual        **out_visual,
903                           int            *out_depth,
904                           GError        **error)
905 {
906   GdkDisplay *display = GDK_DISPLAY (display_x11);
907   Display *dpy;
908   int screen_num;
909 
910   if (!gdk_gl_backend_can_be_used (GDK_GL_GLX, error))
911     return FALSE;
912 
913   dpy = gdk_x11_display_get_xdisplay (display);
914 
915   if (!epoxy_has_glx (dpy))
916     {
917       g_set_error_literal (error, GDK_GL_ERROR,
918                            GDK_GL_ERROR_NOT_AVAILABLE,
919                            _("GLX is not supported"));
920       return FALSE;
921     }
922 
923   screen_num = display_x11->screen->screen_num;
924 
925   display_x11->glx_version = epoxy_glx_version (dpy, screen_num);
926 
927   display_x11->has_glx_create_context =
928     epoxy_has_glx_extension (dpy, screen_num, "GLX_ARB_create_context_profile");
929   display_x11->has_glx_create_es2_context =
930     epoxy_has_glx_extension (dpy, screen_num, "GLX_EXT_create_context_es2_profile");
931   display_x11->has_glx_swap_interval =
932     epoxy_has_glx_extension (dpy, screen_num, "GLX_SGI_swap_control");
933   display_x11->has_glx_texture_from_pixmap =
934     epoxy_has_glx_extension (dpy, screen_num, "GLX_EXT_texture_from_pixmap");
935   display_x11->has_glx_video_sync =
936     epoxy_has_glx_extension (dpy, screen_num, "GLX_SGI_video_sync");
937   display_x11->has_glx_buffer_age =
938     epoxy_has_glx_extension (dpy, screen_num, "GLX_EXT_buffer_age");
939   display_x11->has_glx_sync_control =
940     epoxy_has_glx_extension (dpy, screen_num, "GLX_OML_sync_control");
941   display_x11->has_glx_multisample =
942     epoxy_has_glx_extension (dpy, screen_num, "GLX_ARB_multisample");
943   display_x11->has_glx_visual_rating =
944     epoxy_has_glx_extension (dpy, screen_num, "GLX_EXT_visual_rating");
945 
946   if (g_strcmp0 (glXGetClientString (dpy, GLX_VENDOR), "NVIDIA Corporation") == 0)
947     {
948       Atom type;
949       int format;
950       gulong nitems;
951       gulong bytes_after;
952       guchar *data = NULL;
953 
954       /* With the mesa based drivers, we can safely assume the compositor can
955        * access the updated surface texture immediately after glXSwapBuffers is
956        * run, because the kernel ensures there is an implicit synchronization
957        * operation upon texture access. This is not true with the Nvidia vendor
958        * driver. There is a window of time after glXSwapBuffers before other
959        * processes can see the updated drawing. We need to take special care,
960        * in that case, to defer telling the compositor our latest frame is
961        * ready until after the GPU has completed all issued commands related
962        * to the frame, and that the X server says the frame has been drawn.
963        *
964        * As this can cause deadlocks, we want to make sure to only enable it for Xorg,
965        * but not for XWayland, Xnest or whatever other X servers exist.
966        */
967 
968       gdk_x11_display_error_trap_push (display);
969       if (XGetWindowProperty (dpy, DefaultRootWindow (dpy),
970                               gdk_x11_get_xatom_by_name_for_display (display, "XFree86_VT"),
971                               0, 1, False, AnyPropertyType,
972                               &type, &format, &nitems, &bytes_after, &data) == Success)
973         {
974           if (type != None)
975             display_x11->has_async_glx_swap_buffers = TRUE;
976         }
977       gdk_x11_display_error_trap_pop_ignored (display);
978 
979       if (data)
980         XFree (data);
981     }
982 
983   if (!gdk_x11_display_create_glx_config (display_x11, out_visual, out_depth, error))
984     return FALSE;
985 
986   GDK_DISPLAY_NOTE (display, OPENGL,
987             g_message ("GLX version %d.%d found\n"
988                        " - Vendor: %s\n"
989                        " - Checked extensions:\n"
990                        "\t* GLX_ARB_create_context_profile: %s\n"
991                        "\t* GLX_EXT_create_context_es2_profile: %s\n"
992                        "\t* GLX_SGI_swap_control: %s\n"
993                        "\t* GLX_EXT_texture_from_pixmap: %s\n"
994                        "\t* GLX_SGI_video_sync: %s\n"
995                        "\t* GLX_EXT_buffer_age: %s\n"
996                        "\t* GLX_OML_sync_control: %s"
997                        "\t* GLX_ARB_multisample: %s"
998                        "\t* GLX_EXT_visual_rating: %s",
999                      display_x11->glx_version / 10,
1000                      display_x11->glx_version % 10,
1001                      glXGetClientString (dpy, GLX_VENDOR),
1002                      display_x11->has_glx_create_context ? "yes" : "no",
1003                      display_x11->has_glx_create_es2_context ? "yes" : "no",
1004                      display_x11->has_glx_swap_interval ? "yes" : "no",
1005                      display_x11->has_glx_texture_from_pixmap ? "yes" : "no",
1006                      display_x11->has_glx_video_sync ? "yes" : "no",
1007                      display_x11->has_glx_buffer_age ? "yes" : "no",
1008                      display_x11->has_glx_sync_control ? "yes" : "no",
1009                      display_x11->has_glx_multisample ? "yes" : "no",
1010                      display_x11->has_glx_visual_rating ? "yes" : "no"));
1011 
1012   return TRUE;
1013 }
1014