[gtk/ebassi/egl-x11: 1/4] x11: Decouple GLX from GdkX11GLContext




commit 59711a270ec51a317c4579e3fac090cd19868195
Author: Emmanuele Bassi <ebassi gnome org>
Date:   Mon May 10 15:07:08 2021 +0100

    x11: Decouple GLX from GdkX11GLContext
    
    If we want to add an EGL implementation for the X11 backend, we are
    going to need to move the GLX bits into their own class. The first step
    is to declare GdkX11GLContext as an abstract type, and then subclass it
    into a GdkX11GLContextGLX type, which includes the whole GLX
    implementation.

 gdk/x11/gdkglcontext-glx.c | 1168 ++++++++++++++++++++++++++++++++++++++++++++
 gdk/x11/gdkglcontext-x11.c | 1084 ++--------------------------------------
 gdk/x11/gdkglcontext-x11.h |   45 +-
 gdk/x11/meson.build        |    1 +
 4 files changed, 1243 insertions(+), 1055 deletions(-)
---
diff --git a/gdk/x11/gdkglcontext-glx.c b/gdk/x11/gdkglcontext-glx.c
new file mode 100644
index 0000000000..5b56cf7b76
--- /dev/null
+++ b/gdk/x11/gdkglcontext-glx.c
@@ -0,0 +1,1168 @@
+/* GDK - The GIMP Drawing Kit
+ *
+ * gdkglcontext-glx.c: GLX specific wrappers
+ *
+ * SPDX-FileCopyrightText: 2014  Emmanuele Bassi
+ * SPDX-FileCopyrightText: 2021  GNOME Foundation
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "config.h"
+
+#include "gdkglcontext-x11.h"
+#include "gdkdisplay-x11.h"
+#include "gdkprivate-x11.h"
+#include "gdkscreen-x11.h"
+
+#include "gdkx11display.h"
+#include "gdkx11glcontext.h"
+#include "gdkx11screen.h"
+#include "gdkx11surface.h"
+#include "gdkvisual-x11.h"
+#include "gdkx11property.h"
+#include <X11/Xatom.h>
+
+#include "gdkinternals.h"
+
+#include "gdkintl.h"
+
+#include <cairo-xlib.h>
+
+#include <epoxy/glx.h>
+
+struct _GdkX11GLContextGLX
+{
+  GdkX11GLContext parent_instance;
+
+  GLXContext glx_context;
+  GLXFBConfig glx_config;
+  GLXDrawable attached_drawable;
+  GLXDrawable unattached_drawable;
+
+  guint is_direct : 1;
+};
+
+typedef struct _GdkX11GLContextClass    GdkX11GLContextGLXClass;
+
+typedef struct {
+  GdkDisplay *display;
+
+  GLXDrawable glx_drawable;
+
+  Window dummy_xwin;
+  GLXWindow dummy_glx;
+
+  guint32 last_frame_counter;
+} DrawableInfo;
+
+G_DEFINE_TYPE (GdkX11GLContextGLX, gdk_x11_gl_context_glx, GDK_TYPE_X11_GL_CONTEXT)
+
+static void
+drawable_info_free (gpointer data_)
+{
+  DrawableInfo *data = data_;
+  Display *dpy;
+
+  gdk_x11_display_error_trap_push (data->display);
+
+  dpy = gdk_x11_display_get_xdisplay (data->display);
+
+  if (data->glx_drawable)
+    glXDestroyWindow (dpy, data->glx_drawable);
+
+  if (data->dummy_glx)
+    glXDestroyWindow (dpy, data->dummy_glx);
+
+  if (data->dummy_xwin)
+    XDestroyWindow (dpy, data->dummy_xwin);
+
+  gdk_x11_display_error_trap_pop_ignored (data->display);
+
+  g_slice_free (DrawableInfo, data);
+}
+
+static DrawableInfo *
+get_glx_drawable_info (GdkSurface *surface)
+{
+  return g_object_get_data (G_OBJECT (surface), "-gdk-x11-surface-glx-info");
+}
+
+static void
+set_glx_drawable_info (GdkSurface    *surface,
+                       DrawableInfo *info)
+{
+  g_object_set_data_full (G_OBJECT (surface), "-gdk-x11-surface-glx-info",
+                          info,
+                          drawable_info_free);
+}
+
+static void
+gdk_x11_gl_context_glx_bind_for_frame_fence (GdkX11GLContext *context_x11)
+{
+  GdkX11GLContextGLX *self = GDK_X11_GL_CONTEXT_GLX (context_x11);
+  GdkX11GLContextGLX *current_context_glx;
+  GLXContext current_glx_context = NULL;
+  GdkGLContext *current_context;
+  gboolean needs_binding = TRUE;
+
+  /* We don't care if the passed context is the current context,
+   * necessarily, but we do care that *some* context that can
+   * see the sync object is bound.
+   *
+   * If no context is bound at all, the GL dispatch layer will
+   * make glClientWaitSync() silently return 0.
+   */
+  current_glx_context = glXGetCurrentContext ();
+
+  if (current_glx_context == NULL)
+    goto out;
+
+  current_context = gdk_gl_context_get_current ();
+
+  if (current_context == NULL)
+    goto out;
+
+  current_context_glx = GDK_X11_GL_CONTEXT_GLX (current_context);
+
+  /* If the GLX context was changed out from under GDK, then
+   * that context may not be one that is able to see the
+   * created fence object.
+   */
+  if (current_context_glx->glx_context != current_glx_context)
+    goto out;
+
+  needs_binding = FALSE;
+
+out:
+  if (needs_binding)
+    gdk_gl_context_make_current (GDK_GL_CONTEXT (self));
+}
+
+static void
+maybe_wait_for_vblank (GdkDisplay  *display,
+                       GLXDrawable  drawable)
+{
+  GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
+  Display *dpy = gdk_x11_display_get_xdisplay (display);
+
+  if (display_x11->has_glx_sync_control)
+    {
+      gint64 ust, msc, sbc;
+
+      glXGetSyncValuesOML (dpy, drawable, &ust, &msc, &sbc);
+      glXWaitForMscOML (dpy, drawable,
+                        0, 2, (msc + 1) % 2,
+                        &ust, &msc, &sbc);
+    }
+  else if (display_x11->has_glx_video_sync)
+    {
+      guint32 current_count;
+
+      glXGetVideoSyncSGI (&current_count);
+      glXWaitVideoSyncSGI (2, (current_count + 1) % 2, &current_count);
+    }
+}
+
+static void
+gdk_x11_gl_context_glx_end_frame (GdkDrawContext *draw_context,
+                                  cairo_region_t *painted)
+{
+  GdkGLContext *context = GDK_GL_CONTEXT (draw_context);
+  GdkX11GLContext *context_x11 = GDK_X11_GL_CONTEXT (context);
+  GdkX11GLContextGLX *context_glx = GDK_X11_GL_CONTEXT_GLX (context);
+  GdkSurface *surface = gdk_gl_context_get_surface (context);
+  GdkDisplay *display = gdk_gl_context_get_display (context);
+  Display *dpy = gdk_x11_display_get_xdisplay (display);
+  GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
+  DrawableInfo *info;
+  GLXDrawable drawable;
+
+  GDK_DRAW_CONTEXT_CLASS (gdk_x11_gl_context_glx_parent_class)->end_frame (draw_context, painted);
+  if (gdk_gl_context_get_shared_context (context) != NULL)
+    return;
+
+  gdk_gl_context_make_current (context);
+
+  info = get_glx_drawable_info (surface);
+
+  drawable = context_glx->attached_drawable;
+
+  GDK_DISPLAY_NOTE (display, OPENGL,
+            g_message ("Flushing GLX buffers for drawable %lu (window: %lu), frame sync: %s",
+                       (unsigned long) drawable,
+                       (unsigned long) gdk_x11_surface_get_xid (surface),
+                       context_x11->do_frame_sync ? "yes" : "no"));
+
+  /* if we are going to wait for the vertical refresh manually
+   * we need to flush pending redraws, and we also need to wait
+   * for that to finish, otherwise we are going to tear.
+   *
+   * obviously, this condition should not be hit if we have
+   * GLX_SGI_swap_control, and we ask the driver to do the right
+   * thing.
+   */
+  if (context_x11->do_frame_sync)
+    {
+      guint32 end_frame_counter = 0;
+      gboolean has_counter = display_x11->has_glx_video_sync;
+      gboolean can_wait = display_x11->has_glx_video_sync || display_x11->has_glx_sync_control;
+
+      if (display_x11->has_glx_video_sync)
+        glXGetVideoSyncSGI (&end_frame_counter);
+
+      if (context_x11->do_frame_sync && !display_x11->has_glx_swap_interval)
+        {
+          glFinish ();
+
+          if (has_counter && can_wait)
+            {
+              guint32 last_counter = info != NULL ? info->last_frame_counter : 0;
+
+              if (last_counter == end_frame_counter)
+                maybe_wait_for_vblank (display, drawable);
+            }
+          else if (can_wait)
+            maybe_wait_for_vblank (display, drawable);
+        }
+    }
+
+  gdk_x11_surface_pre_damage (surface);
+
+#ifdef HAVE_XDAMAGE
+  if (context_x11->xdamage != 0 && _gdk_x11_surface_syncs_frames (surface))
+    {
+      g_assert (context_x11->frame_fence == 0);
+
+      context_x11->frame_fence = glFenceSync (GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+
+      /* We consider the frame still getting painted until the GL operation is
+       * finished, and the window gets damage reported from the X server.
+       * It's only at this point the compositor can be sure it has full
+       * access to the new updates.
+       */
+      _gdk_x11_surface_set_frame_still_painting (surface, TRUE);
+    }
+#endif
+
+  glXSwapBuffers (dpy, drawable);
+
+  if (context_x11->do_frame_sync && info != NULL && display_x11->has_glx_video_sync)
+    glXGetVideoSyncSGI (&info->last_frame_counter);
+}
+
+static cairo_region_t *
+gdk_x11_gl_context_glx_get_damage (GdkGLContext *context)
+{
+  GdkDisplay *display = gdk_draw_context_get_display (GDK_DRAW_CONTEXT (context));
+  GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
+  Display *dpy = gdk_x11_display_get_xdisplay (display);
+  unsigned int buffer_age = 0;
+
+  if (display_x11->has_glx_buffer_age)
+    {
+      GdkGLContext *shared;
+      GdkX11GLContextGLX *shared_glx;
+
+      shared = gdk_gl_context_get_shared_context (context);
+      if (shared == NULL)
+        shared = context;
+
+      shared_glx = GDK_X11_GL_CONTEXT_GLX (shared);
+
+      gdk_gl_context_make_current (shared);
+      glXQueryDrawable (dpy, shared_glx->attached_drawable,
+                        GLX_BACK_BUFFER_AGE_EXT, &buffer_age);
+
+      switch (buffer_age)
+        {
+          case 1:
+            return cairo_region_create ();
+            break;
+
+          case 2:
+            if (context->old_updated_area[0])
+              return cairo_region_copy (context->old_updated_area[0]);
+            break;
+
+          case 3:
+            if (context->old_updated_area[0] &&
+                context->old_updated_area[1])
+              {
+                cairo_region_t *damage = cairo_region_copy (context->old_updated_area[0]);
+                cairo_region_union (damage, context->old_updated_area[1]);
+                return damage;
+              }
+            break;
+
+          default:
+            ;
+        }
+    }
+
+  return GDK_GL_CONTEXT_CLASS (gdk_x11_gl_context_glx_parent_class)->get_damage (context);
+}
+
+static XVisualInfo *
+find_xvisinfo_for_fbconfig (GdkDisplay  *display,
+                            GLXFBConfig  config)
+{
+  Display *dpy = gdk_x11_display_get_xdisplay (display);
+
+  return glXGetVisualFromFBConfig (dpy, config);
+}
+
+static GLXContext
+create_gl3_context (GdkDisplay   *display,
+                    GLXFBConfig   config,
+                    GdkGLContext *share,
+                    int           profile,
+                    int           flags,
+                    int           major,
+                    int           minor)
+{
+  int attrib_list[] = {
+    GLX_CONTEXT_PROFILE_MASK_ARB, profile,
+    GLX_CONTEXT_MAJOR_VERSION_ARB, major,
+    GLX_CONTEXT_MINOR_VERSION_ARB, minor,
+    GLX_CONTEXT_FLAGS_ARB, flags,
+    None,
+  };
+  GLXContext res;
+
+  GdkX11GLContextGLX *share_glx = NULL;
+
+  if (share != NULL)
+    share_glx = GDK_X11_GL_CONTEXT_GLX (share);
+
+  gdk_x11_display_error_trap_push (display);
+
+  res = glXCreateContextAttribsARB (gdk_x11_display_get_xdisplay (display),
+                                    config,
+                                    share_glx != NULL ? share_glx->glx_context : NULL,
+                                    True,
+                                    attrib_list);
+
+  if (gdk_x11_display_error_trap_pop (display))
+    return NULL;
+
+  return res;
+}
+
+static GLXContext
+create_legacy_context (GdkDisplay   *display,
+                       GLXFBConfig   config,
+                       GdkGLContext *share)
+{
+  GdkX11GLContextGLX *share_glx = NULL;
+  GLXContext res;
+
+  if (share != NULL)
+    share_glx = GDK_X11_GL_CONTEXT_GLX (share);
+
+  gdk_x11_display_error_trap_push (display);
+
+  res = glXCreateNewContext (gdk_x11_display_get_xdisplay (display),
+                             config,
+                             GLX_RGBA_TYPE,
+                             share_glx != NULL ? share_glx->glx_context : NULL,
+                             TRUE);
+
+  if (gdk_x11_display_error_trap_pop (display))
+    return NULL;
+
+  return res;
+}
+
+static gboolean
+gdk_x11_gl_context_glx_realize (GdkGLContext  *context,
+                                GError       **error)
+{
+  GdkX11Display *display_x11;
+  GdkDisplay *display;
+  GdkX11GLContextGLX *context_glx;
+  XVisualInfo *xvisinfo;
+  Display *dpy;
+  DrawableInfo *info;
+  GdkGLContext *share;
+  GdkGLContext *shared_data_context;
+  GdkSurface *surface;
+  gboolean debug_bit, compat_bit, legacy_bit, es_bit;
+  int major, minor, flags;
+
+  surface = gdk_gl_context_get_surface (context);
+  display = gdk_surface_get_display (surface);
+  dpy = gdk_x11_display_get_xdisplay (display);
+  context_glx = GDK_X11_GL_CONTEXT_GLX (context);
+  display_x11 = GDK_X11_DISPLAY (display);
+  share = gdk_gl_context_get_shared_context (context);
+  shared_data_context = gdk_surface_get_shared_data_gl_context (surface);
+
+  gdk_gl_context_get_required_version (context, &major, &minor);
+  debug_bit = gdk_gl_context_get_debug_enabled (context);
+  compat_bit = gdk_gl_context_get_forward_compatible (context);
+
+  /* If there is no glXCreateContextAttribsARB() then we default to legacy */
+  legacy_bit = !display_x11->has_glx_create_context || GDK_DISPLAY_DEBUG_CHECK (display, GL_LEGACY);
+
+  es_bit = (GDK_DISPLAY_DEBUG_CHECK (display, GL_GLES) || (share != NULL && gdk_gl_context_get_use_es 
(share))) &&
+           (display_x11->has_glx_create_context && display_x11->has_glx_create_es2_context);
+
+  /* We cannot share legacy contexts with core profile ones, so the
+   * shared context is the one that decides if we're going to create
+   * a legacy context or not.
+   */
+  if (share != NULL && gdk_gl_context_is_legacy (share))
+    legacy_bit = TRUE;
+
+  flags = 0;
+  if (debug_bit)
+    flags |= GLX_CONTEXT_DEBUG_BIT_ARB;
+  if (compat_bit)
+    flags |= GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
+
+  GDK_DISPLAY_NOTE (display, OPENGL,
+            g_message ("Creating GLX context (GL version:%d.%d, debug:%s, forward:%s, legacy:%s, es:%s)",
+                       major, minor,
+                       debug_bit ? "yes" : "no",
+                       compat_bit ? "yes" : "no",
+                       legacy_bit ? "yes" : "no",
+                       es_bit ? "yes" : "no"));
+
+  /* If we have access to GLX_ARB_create_context_profile then we can ask for
+   * a compatibility profile; if we don't, then we have to fall back to the
+   * old GLX 1.3 API.
+   */
+  if (legacy_bit && !GDK_X11_DISPLAY (display)->has_glx_create_context)
+    {
+      GDK_DISPLAY_NOTE (display, OPENGL, g_message ("Creating legacy GL context on request"));
+      context_glx->glx_context = create_legacy_context (display, context_glx->glx_config, share ? share : 
shared_data_context);
+    }
+  else
+    {
+      int profile;
+
+      if (es_bit)
+        profile = GLX_CONTEXT_ES2_PROFILE_BIT_EXT;
+      else
+        profile = legacy_bit ? GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB
+                             : GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
+
+      /* We need to tweak the version, otherwise we may end up requesting
+       * a compatibility context with a minimum version of 3.2, which is
+       * an error
+       */
+      if (legacy_bit)
+        {
+          major = 3;
+          minor = 0;
+        }
+
+      GDK_DISPLAY_NOTE (display, OPENGL, g_message ("Creating GL3 context"));
+      context_glx->glx_context = create_gl3_context (display,
+                                                     context_glx->glx_config,
+                                                     share ? share : shared_data_context,
+                                                     profile, flags, major, minor);
+
+      /* Fall back to legacy in case the GL3 context creation failed */
+      if (context_glx->glx_context == NULL)
+        {
+          GDK_DISPLAY_NOTE (display, OPENGL, g_message ("Creating fallback legacy context"));
+          context_glx->glx_context = create_legacy_context (display, context_glx->glx_config, share ? share 
: shared_data_context);
+          legacy_bit = TRUE;
+          es_bit = FALSE;
+        }
+    }
+
+  if (context_glx->glx_context == NULL)
+    {
+      g_set_error_literal (error, GDK_GL_ERROR,
+                           GDK_GL_ERROR_NOT_AVAILABLE,
+                           _("Unable to create a GL context"));
+      return FALSE;
+    }
+
+  /* Ensure that any other context is created with a legacy bit set */
+  gdk_gl_context_set_is_legacy (context, legacy_bit);
+
+  /* Ensure that any other context is created with an ES bit set */
+  gdk_gl_context_set_use_es (context, es_bit);
+
+  xvisinfo = find_xvisinfo_for_fbconfig (display, context_glx->glx_config);
+
+  info = get_glx_drawable_info (surface);
+  if (info == NULL)
+    {
+      XSetWindowAttributes attrs;
+      unsigned long mask;
+
+      gdk_x11_display_error_trap_push (display);
+
+      info = g_slice_new0 (DrawableInfo);
+      info->display = display;
+      info->last_frame_counter = 0;
+
+      attrs.override_redirect = True;
+      attrs.colormap = XCreateColormap (dpy, DefaultRootWindow (dpy), xvisinfo->visual, AllocNone);
+      attrs.border_pixel = 0;
+      mask = CWOverrideRedirect | CWColormap | CWBorderPixel;
+      info->dummy_xwin = XCreateWindow (dpy, DefaultRootWindow (dpy),
+                                        -100, -100, 1, 1,
+                                        0,
+                                        xvisinfo->depth,
+                                        CopyFromParent,
+                                        xvisinfo->visual,
+                                        mask,
+                                        &attrs);
+      XMapWindow(dpy, info->dummy_xwin);
+
+      if (display_x11->glx_version >= 13)
+        {
+          info->glx_drawable = glXCreateWindow (dpy, context_glx->glx_config,
+                                                gdk_x11_surface_get_xid (surface),
+                                                NULL);
+          info->dummy_glx = glXCreateWindow (dpy, context_glx->glx_config, info->dummy_xwin, NULL);
+        }
+
+      if (gdk_x11_display_error_trap_pop (display))
+        {
+          g_set_error_literal (error, GDK_GL_ERROR,
+                               GDK_GL_ERROR_NOT_AVAILABLE,
+                               _("Unable to create a GL context"));
+
+          XFree (xvisinfo);
+          drawable_info_free (info);
+          glXDestroyContext (dpy, context_glx->glx_context);
+          context_glx->glx_context = NULL;
+
+          return FALSE;
+        }
+
+      set_glx_drawable_info (surface, info);
+    }
+
+  XFree (xvisinfo);
+
+  context_glx->attached_drawable = info->glx_drawable ? info->glx_drawable : gdk_x11_surface_get_xid 
(surface);
+  context_glx->unattached_drawable = info->dummy_glx ? info->dummy_glx : info->dummy_xwin;
+
+  context_glx->is_direct = glXIsDirect (dpy, context_glx->glx_context);
+
+  GDK_DISPLAY_NOTE (display, OPENGL,
+            g_message ("Realized GLX context[%p], %s, version: %d.%d",
+                       context_glx->glx_context,
+                       context_glx->is_direct ? "direct" : "indirect",
+                       display_x11->glx_version / 10,
+                       display_x11->glx_version % 10));
+
+  /* Handle damage tracking in the parent class */
+  return GDK_GL_CONTEXT_CLASS (gdk_x11_gl_context_glx_parent_class)->realize (context, error);
+}
+
+static void
+gdk_x11_gl_context_glx_dispose (GObject *gobject)
+{
+  GdkX11GLContextGLX *context_glx = GDK_X11_GL_CONTEXT_GLX (gobject);
+
+  if (context_glx->glx_context != NULL)
+    {
+      GdkGLContext *context = GDK_GL_CONTEXT (gobject);
+      GdkDisplay *display = gdk_gl_context_get_display (context);
+      Display *dpy = gdk_x11_display_get_xdisplay (display);
+
+      if (glXGetCurrentContext () == context_glx->glx_context)
+        glXMakeContextCurrent (dpy, None, None, NULL);
+
+      GDK_DISPLAY_NOTE (display, OPENGL, g_message ("Destroying GLX context"));
+      glXDestroyContext (dpy, context_glx->glx_context);
+      context_glx->glx_context = NULL;
+    }
+
+  G_OBJECT_CLASS (gdk_x11_gl_context_glx_parent_class)->dispose (gobject);
+}
+
+static void
+gdk_x11_gl_context_glx_class_init (GdkX11GLContextGLXClass *klass)
+{
+  GdkX11GLContextClass *context_x11_class = GDK_X11_GL_CONTEXT_CLASS (klass);
+  GdkGLContextClass *context_class = GDK_GL_CONTEXT_CLASS (klass);
+  GdkDrawContextClass *draw_context_class = GDK_DRAW_CONTEXT_CLASS (klass);
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  context_x11_class->bind_for_frame_fence = gdk_x11_gl_context_glx_bind_for_frame_fence;
+
+  context_class->realize = gdk_x11_gl_context_glx_realize;
+  context_class->get_damage = gdk_x11_gl_context_glx_get_damage;
+
+  draw_context_class->end_frame = gdk_x11_gl_context_glx_end_frame;
+
+  gobject_class->dispose = gdk_x11_gl_context_glx_dispose;
+}
+
+static void
+gdk_x11_gl_context_glx_init (GdkX11GLContextGLX *self)
+{
+}
+
+#define MAX_GLX_ATTRS   30
+
+static gboolean
+find_fbconfig (GdkDisplay   *display,
+               GLXFBConfig  *fb_config_out,
+               GError      **error)
+{
+  static int attrs[MAX_GLX_ATTRS];
+  Display *dpy = gdk_x11_display_get_xdisplay (display);
+  GLXFBConfig *configs;
+  int n_configs, i;
+  gboolean retval = FALSE;
+  VisualID xvisual_id = XVisualIDFromVisual (gdk_x11_display_get_window_visual (GDK_X11_DISPLAY (display)));
+
+  i = 0;
+  attrs[i++] = GLX_DRAWABLE_TYPE;
+  attrs[i++] = GLX_WINDOW_BIT;
+
+  attrs[i++] = GLX_RENDER_TYPE;
+  attrs[i++] = GLX_RGBA_BIT;
+
+  attrs[i++] = GLX_DOUBLEBUFFER;
+  attrs[i++] = GL_TRUE;
+
+  attrs[i++] = GLX_RED_SIZE;
+  attrs[i++] = 1;
+  attrs[i++] = GLX_GREEN_SIZE;
+  attrs[i++] = 1;
+  attrs[i++] = GLX_BLUE_SIZE;
+  attrs[i++] = 1;
+
+  if (gdk_display_is_rgba (display))
+    {
+      attrs[i++] = GLX_ALPHA_SIZE;
+      attrs[i++] = 1;
+    }
+  else
+    {
+      attrs[i++] = GLX_ALPHA_SIZE;
+      attrs[i++] = GLX_DONT_CARE;
+    }
+
+  attrs[i++] = None;
+
+  g_assert (i < MAX_GLX_ATTRS);
+
+  configs = glXChooseFBConfig (dpy, DefaultScreen (dpy), attrs, &n_configs);
+  if (configs == NULL || n_configs == 0)
+    {
+      g_set_error_literal (error, GDK_GL_ERROR,
+                           GDK_GL_ERROR_UNSUPPORTED_FORMAT,
+                           _("No available configurations for the given pixel format"));
+      return FALSE;
+    }
+
+  for (i = 0; i < n_configs; i++)
+    {
+      XVisualInfo *visinfo;
+
+      visinfo = glXGetVisualFromFBConfig (dpy, configs[i]);
+      if (visinfo == NULL)
+        continue;
+
+      if (visinfo->visualid != xvisual_id)
+        {
+          XFree (visinfo);
+          continue;
+        }
+
+      if (fb_config_out != NULL)
+        *fb_config_out = configs[i];
+
+      XFree (visinfo);
+      retval = TRUE;
+      goto out;
+    }
+
+  g_set_error (error, GDK_GL_ERROR,
+               GDK_GL_ERROR_UNSUPPORTED_FORMAT,
+               _("No available configurations for the given RGBA pixel format"));
+
+out:
+  XFree (configs);
+
+  return retval;
+}
+
+#undef MAX_GLX_ATTRS
+
+struct glvisualinfo {
+  int supports_gl;
+  int double_buffer;
+  int stereo;
+  int alpha_size;
+  int depth_size;
+  int stencil_size;
+  int num_multisample;
+  int visual_caveat;
+};
+
+static gboolean
+visual_compatible (const GdkX11Visual *a, const GdkX11Visual *b)
+{
+  return a->type == b->type &&
+    a->depth == b->depth &&
+    a->red_mask == b->red_mask &&
+    a->green_mask == b->green_mask &&
+    a->blue_mask == b->blue_mask &&
+    a->colormap_size == b->colormap_size &&
+    a->bits_per_rgb == b->bits_per_rgb;
+}
+
+static gboolean
+visual_is_rgba (const GdkX11Visual *visual)
+{
+  return
+    visual->depth == 32 &&
+    visual->red_mask   == 0xff0000 &&
+    visual->green_mask == 0x00ff00 &&
+    visual->blue_mask  == 0x0000ff;
+}
+
+/* This picks a compatible (as in has the same X visual details) visual
+   that has "better" characteristics on the GL side */
+static GdkX11Visual *
+pick_better_visual_for_gl (GdkX11Screen *x11_screen,
+                           struct glvisualinfo *gl_info,
+                           GdkX11Visual *compatible)
+{
+  GdkX11Visual *visual;
+  int i;
+  gboolean want_alpha = visual_is_rgba (compatible);
+
+  /* First look for "perfect match", i.e:
+   * supports gl
+   * double buffer
+   * alpha iff visual is an rgba visual
+   * no unnecessary stuff
+   */
+  for (i = 0; i < x11_screen->nvisuals; i++)
+    {
+      visual = x11_screen->visuals[i];
+      if (visual_compatible (visual, compatible) &&
+          gl_info[i].supports_gl &&
+          gl_info[i].double_buffer &&
+          !gl_info[i].stereo &&
+          (want_alpha ? (gl_info[i].alpha_size > 0) : (gl_info[i].alpha_size == 0)) &&
+          (gl_info[i].depth_size == 0) &&
+          (gl_info[i].stencil_size == 0) &&
+          (gl_info[i].num_multisample == 0) &&
+          (gl_info[i].visual_caveat == GLX_NONE_EXT))
+        return visual;
+    }
+
+  if (!want_alpha)
+    {
+      /* Next, allow alpha even if we don't want it: */
+      for (i = 0; i < x11_screen->nvisuals; i++)
+        {
+          visual = x11_screen->visuals[i];
+          if (visual_compatible (visual, compatible) &&
+              gl_info[i].supports_gl &&
+              gl_info[i].double_buffer &&
+              !gl_info[i].stereo &&
+              (gl_info[i].depth_size == 0) &&
+              (gl_info[i].stencil_size == 0) &&
+              (gl_info[i].num_multisample == 0) &&
+              (gl_info[i].visual_caveat == GLX_NONE_EXT))
+            return visual;
+        }
+    }
+
+  /* Next, allow depth and stencil buffers: */
+  for (i = 0; i < x11_screen->nvisuals; i++)
+    {
+      visual = x11_screen->visuals[i];
+      if (visual_compatible (visual, compatible) &&
+          gl_info[i].supports_gl &&
+          gl_info[i].double_buffer &&
+          !gl_info[i].stereo &&
+          (gl_info[i].num_multisample == 0) &&
+          (gl_info[i].visual_caveat == GLX_NONE_EXT))
+        return visual;
+    }
+
+  /* Next, allow multisample: */
+  for (i = 0; i < x11_screen->nvisuals; i++)
+    {
+      visual = x11_screen->visuals[i];
+      if (visual_compatible (visual, compatible) &&
+          gl_info[i].supports_gl &&
+          gl_info[i].double_buffer &&
+          !gl_info[i].stereo &&
+          (gl_info[i].visual_caveat == GLX_NONE_EXT))
+        return visual;
+    }
+
+  return compatible;
+}
+
+static gboolean
+get_cached_gl_visuals (GdkDisplay *display, int *system, int *rgba)
+{
+  gboolean found;
+  Atom type_return;
+  int format_return;
+  gulong nitems_return;
+  gulong bytes_after_return;
+  guchar *data = NULL;
+  Display *dpy;
+
+  dpy = gdk_x11_display_get_xdisplay (display);
+
+  found = FALSE;
+
+  gdk_x11_display_error_trap_push (display);
+  if (XGetWindowProperty (dpy, DefaultRootWindow (dpy),
+                          gdk_x11_get_xatom_by_name_for_display (display, "GDK_VISUALS"),
+                          0, 2, False, XA_INTEGER, &type_return,
+                          &format_return, &nitems_return,
+                          &bytes_after_return, &data) == Success)
+    {
+      if (type_return == XA_INTEGER &&
+          format_return == 32 &&
+          nitems_return == 2 &&
+          data != NULL)
+        {
+          long *visuals = (long *) data;
+
+          *system = (int)visuals[0];
+          *rgba = (int)visuals[1];
+          found = TRUE;
+        }
+    }
+  gdk_x11_display_error_trap_pop_ignored (display);
+
+  if (data)
+    XFree (data);
+
+  return found;
+}
+
+static void
+save_cached_gl_visuals (GdkDisplay *display, int system, int rgba)
+{
+  long visualdata[2];
+  Display *dpy;
+
+  dpy = gdk_x11_display_get_xdisplay (display);
+
+  visualdata[0] = system;
+  visualdata[1] = rgba;
+
+  gdk_x11_display_error_trap_push (display);
+  XChangeProperty (dpy, DefaultRootWindow (dpy),
+                   gdk_x11_get_xatom_by_name_for_display (display, "GDK_VISUALS"),
+                   XA_INTEGER, 32, PropModeReplace,
+                   (unsigned char *)visualdata, 2);
+  gdk_x11_display_error_trap_pop_ignored (display);
+}
+
+void
+_gdk_x11_screen_update_visuals_for_gl (GdkX11Screen *x11_screen)
+{
+  GdkDisplay *display;
+  GdkX11Display *display_x11;
+  Display *dpy;
+  struct glvisualinfo *gl_info;
+  int i;
+  int system_visual_id, rgba_visual_id;
+
+  display = x11_screen->display;
+  display_x11 = GDK_X11_DISPLAY (display);
+  dpy = gdk_x11_display_get_xdisplay (display);
+
+  /* We save the default visuals as a property on the root window to avoid
+     having to initialize GL each time, as it may not be used later. */
+  if (get_cached_gl_visuals (display, &system_visual_id, &rgba_visual_id))
+    {
+      for (i = 0; i < x11_screen->nvisuals; i++)
+        {
+          GdkX11Visual *visual = x11_screen->visuals[i];
+          int visual_id = gdk_x11_visual_get_xvisual (visual)->visualid;
+
+          if (visual_id == system_visual_id)
+            x11_screen->system_visual = visual;
+          if (visual_id == rgba_visual_id)
+            x11_screen->rgba_visual = visual;
+        }
+
+      return;
+    }
+
+  if (!gdk_x11_screen_init_glx (x11_screen))
+    return;
+
+  gl_info = g_new0 (struct glvisualinfo, x11_screen->nvisuals);
+
+  for (i = 0; i < x11_screen->nvisuals; i++)
+    {
+      XVisualInfo *visual_list;
+      XVisualInfo visual_template;
+      int nxvisuals;
+
+      visual_template.screen = x11_screen->screen_num;
+      visual_template.visualid = gdk_x11_visual_get_xvisual (x11_screen->visuals[i])->visualid;
+      visual_list = XGetVisualInfo (x11_screen->xdisplay, VisualIDMask| VisualScreenMask, &visual_template, 
&nxvisuals);
+
+      if (visual_list == NULL)
+        continue;
+
+      glXGetConfig (dpy, &visual_list[0], GLX_USE_GL, &gl_info[i].supports_gl);
+      glXGetConfig (dpy, &visual_list[0], GLX_DOUBLEBUFFER, &gl_info[i].double_buffer);
+      glXGetConfig (dpy, &visual_list[0], GLX_STEREO, &gl_info[i].stereo);
+      glXGetConfig (dpy, &visual_list[0], GLX_ALPHA_SIZE, &gl_info[i].alpha_size);
+      glXGetConfig (dpy, &visual_list[0], GLX_DEPTH_SIZE, &gl_info[i].depth_size);
+      glXGetConfig (dpy, &visual_list[0], GLX_STENCIL_SIZE, &gl_info[i].stencil_size);
+
+      if (display_x11->has_glx_multisample)
+        glXGetConfig(dpy, &visual_list[0], GLX_SAMPLE_BUFFERS_ARB, &gl_info[i].num_multisample);
+
+      if (display_x11->has_glx_visual_rating)
+        glXGetConfig(dpy, &visual_list[0], GLX_VISUAL_CAVEAT_EXT, &gl_info[i].visual_caveat);
+      else
+        gl_info[i].visual_caveat = GLX_NONE_EXT;
+
+      XFree (visual_list);
+    }
+
+  x11_screen->system_visual = pick_better_visual_for_gl (x11_screen, gl_info, x11_screen->system_visual);
+  if (x11_screen->rgba_visual)
+    x11_screen->rgba_visual = pick_better_visual_for_gl (x11_screen, gl_info, x11_screen->rgba_visual);
+
+  g_free (gl_info);
+
+  save_cached_gl_visuals (display,
+                          gdk_x11_visual_get_xvisual (x11_screen->system_visual)->visualid,
+                          x11_screen->rgba_visual
+                            ? gdk_x11_visual_get_xvisual (x11_screen->rgba_visual)->visualid
+                            : 0);
+}
+
+GdkX11GLContext *
+gdk_x11_gl_context_glx_new (GdkSurface    *surface,
+                            gboolean       attached,
+                            GdkGLContext  *share,
+                            GError       **error)
+{
+  GdkDisplay *display;
+  GdkX11GLContextGLX *context;
+  GLXFBConfig config;
+
+  display = gdk_surface_get_display (surface);
+  if (!find_fbconfig (display, &config, error))
+    return NULL;
+
+  context = g_object_new (GDK_TYPE_X11_GL_CONTEXT_GLX,
+                          "surface", surface,
+                          "shared-context", share,
+                          NULL);
+
+  context->glx_config = config;
+
+  return GDK_X11_GL_CONTEXT (context);
+}
+
+gboolean
+gdk_x11_gl_context_glx_make_current (GdkDisplay   *display,
+                                     GdkGLContext *context)
+{
+  GdkX11GLContextGLX *context_glx;
+  GdkX11GLContext *context_x11;
+  Display *dpy = gdk_x11_display_get_xdisplay (display);
+  gboolean do_frame_sync = FALSE;
+  GLXWindow drawable;
+
+  if (context == NULL)
+    {
+      glXMakeContextCurrent (dpy, None, None, NULL);
+      return TRUE;
+    }
+
+  context_glx = GDK_X11_GL_CONTEXT_GLX (context);
+  if (context_glx->glx_context == NULL)
+    {
+      g_critical ("No GLX context associated to the GdkGLContext; you must "
+                  "call gdk_gl_context_realize() first.");
+      return FALSE;
+    }
+
+  context_x11 = GDK_X11_GL_CONTEXT (context);
+  if (context_x11->is_attached || gdk_draw_context_is_in_frame (GDK_DRAW_CONTEXT (context)))
+    drawable = context_glx->attached_drawable;
+  else
+    drawable = context_glx->unattached_drawable;
+
+  GDK_DISPLAY_NOTE (display, OPENGL,
+                    g_message ("Making GLX context %p current to drawable %lu",
+                               context, (unsigned long) drawable));
+
+  if (!glXMakeContextCurrent (dpy, drawable, drawable, context_glx->glx_context))
+    {
+      GDK_DISPLAY_NOTE (display, OPENGL,
+                        g_message ("Making GLX context current failed"));
+      return FALSE;
+    }
+
+  if (context_x11->is_attached && GDK_X11_DISPLAY (display)->has_glx_swap_interval)
+    {
+      /* If the WM is compositing there is no particular need to delay
+       * the swap when drawing on the offscreen, rendering to the screen
+       * happens later anyway, and its up to the compositor to sync that
+       * to the vblank. */
+      do_frame_sync = ! gdk_display_is_composited (display);
+
+      if (do_frame_sync != context_x11->do_frame_sync)
+        {
+          context_x11->do_frame_sync = do_frame_sync;
+
+          if (do_frame_sync)
+            glXSwapIntervalSGI (1);
+          else
+            glXSwapIntervalSGI (0);
+        }
+    }
+
+  return TRUE;
+}
+
+/**
+ * gdk_x11_display_get_glx_version:
+ * @display: (type GdkX11Display): a #GdkDisplay
+ * @major: (out): return location for the GLX major version
+ * @minor: (out): return location for the GLX minor version
+ *
+ * Retrieves the version of the GLX implementation.
+ *
+ * Returns: %TRUE if GLX is available
+ */
+gboolean
+gdk_x11_display_get_glx_version (GdkDisplay *display,
+                                 int        *major,
+                                 int        *minor)
+{
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
+
+  if (!GDK_IS_X11_DISPLAY (display))
+    return FALSE;
+
+  GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
+
+  if (!gdk_x11_screen_init_glx (display_x11->screen))
+    return FALSE;
+
+  if (major != NULL)
+    *major = display_x11->glx_version / 10;
+  if (minor != NULL)
+    *minor = display_x11->glx_version % 10;
+
+  return TRUE;
+}
+
+/*< private >
+ * gdk_x11_screen_init_glx:
+ * @screen: an X11 screen
+ *
+ * Initializes the cached GLX state for the given @screen.
+ *
+ * It's safe to call this function multiple times.
+ *
+ * Returns: %TRUE if GLX was initialized
+ */
+gboolean
+gdk_x11_screen_init_glx (GdkX11Screen *screen)
+{
+  GdkDisplay *display = GDK_SCREEN_DISPLAY (screen);
+  GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
+  Display *dpy;
+  int error_base, event_base;
+  int screen_num;
+
+  if (display_x11->have_glx)
+    return TRUE;
+
+  dpy = gdk_x11_display_get_xdisplay (display);
+
+  if (!epoxy_has_glx (dpy))
+    return FALSE;
+
+  if (!glXQueryExtension (dpy, &error_base, &event_base))
+    return FALSE;
+
+  screen_num = screen->screen_num;
+
+  display_x11->have_glx = TRUE;
+
+  display_x11->glx_version = epoxy_glx_version (dpy, screen_num);
+  display_x11->glx_error_base = error_base;
+  display_x11->glx_event_base = event_base;
+
+  display_x11->has_glx_create_context =
+    epoxy_has_glx_extension (dpy, screen_num, "GLX_ARB_create_context_profile");
+  display_x11->has_glx_create_es2_context =
+    epoxy_has_glx_extension (dpy, screen_num, "GLX_EXT_create_context_es2_profile");
+  display_x11->has_glx_swap_interval =
+    epoxy_has_glx_extension (dpy, screen_num, "GLX_SGI_swap_control");
+  display_x11->has_glx_texture_from_pixmap =
+    epoxy_has_glx_extension (dpy, screen_num, "GLX_EXT_texture_from_pixmap");
+  display_x11->has_glx_video_sync =
+    epoxy_has_glx_extension (dpy, screen_num, "GLX_SGI_video_sync");
+  display_x11->has_glx_buffer_age =
+    epoxy_has_glx_extension (dpy, screen_num, "GLX_EXT_buffer_age");
+  display_x11->has_glx_sync_control =
+    epoxy_has_glx_extension (dpy, screen_num, "GLX_OML_sync_control");
+  display_x11->has_glx_multisample =
+    epoxy_has_glx_extension (dpy, screen_num, "GLX_ARB_multisample");
+  display_x11->has_glx_visual_rating =
+    epoxy_has_glx_extension (dpy, screen_num, "GLX_EXT_visual_rating");
+
+  if (g_strcmp0 (glXGetClientString (dpy, GLX_VENDOR), "NVIDIA Corporation") == 0)
+    {
+      /* With the mesa based drivers, we can safely assume the compositor can
+       * access the updated surface texture immediately after glXSwapBuffers is
+       * run, because the kernel ensures there is an implicit synchronization
+       * operation upon texture access. This is not true with the Nvidia vendor
+       * driver. There is a window of time after glXSwapBuffers before other
+       * processes can see the updated drawing. We need to take special care,
+       * in that case, to defer telling the compositor our latest frame is
+       * ready until after the GPU has completed all issued commands related
+       * to the frame, and that the X server says the frame has been drawn.
+       */
+      display_x11->has_async_glx_swap_buffers = TRUE;
+    }
+
+  GDK_DISPLAY_NOTE (display, OPENGL,
+            g_message ("GLX version %d.%d found\n"
+                       " - Vendor: %s\n"
+                       " - Checked extensions:\n"
+                       "\t* GLX_ARB_create_context_profile: %s\n"
+                       "\t* GLX_EXT_create_context_es2_profile: %s\n"
+                       "\t* GLX_SGI_swap_control: %s\n"
+                       "\t* GLX_EXT_texture_from_pixmap: %s\n"
+                       "\t* GLX_SGI_video_sync: %s\n"
+                       "\t* GLX_EXT_buffer_age: %s\n"
+                       "\t* GLX_OML_sync_control: %s"
+                       "\t* GLX_ARB_multisample: %s"
+                       "\t* GLX_EXT_visual_rating: %s",
+                     display_x11->glx_version / 10,
+                     display_x11->glx_version % 10,
+                     glXGetClientString (dpy, GLX_VENDOR),
+                     display_x11->has_glx_create_context ? "yes" : "no",
+                     display_x11->has_glx_create_es2_context ? "yes" : "no",
+                     display_x11->has_glx_swap_interval ? "yes" : "no",
+                     display_x11->has_glx_texture_from_pixmap ? "yes" : "no",
+                     display_x11->has_glx_video_sync ? "yes" : "no",
+                     display_x11->has_glx_buffer_age ? "yes" : "no",
+                     display_x11->has_glx_sync_control ? "yes" : "no",
+                     display_x11->has_glx_multisample ? "yes" : "no",
+                     display_x11->has_glx_visual_rating ? "yes" : "no"));
+
+  return TRUE;
+}
diff --git a/gdk/x11/gdkglcontext-x11.c b/gdk/x11/gdkglcontext-x11.c
index 018860bae8..7e73a66956 100644
--- a/gdk/x11/gdkglcontext-x11.c
+++ b/gdk/x11/gdkglcontext-x11.c
@@ -41,292 +41,7 @@
 
 #include <epoxy/glx.h>
 
-G_DEFINE_TYPE (GdkX11GLContext, gdk_x11_gl_context, GDK_TYPE_GL_CONTEXT)
-
-typedef struct {
-  GdkDisplay *display;
-
-  GLXDrawable glx_drawable;
-
-  Window dummy_xwin;
-  GLXWindow dummy_glx;
-
-  guint32 last_frame_counter;
-} DrawableInfo;
-
-static void
-drawable_info_free (gpointer data_)
-{
-  DrawableInfo *data = data_;
-  Display *dpy;
-
-  gdk_x11_display_error_trap_push (data->display);
-
-  dpy = gdk_x11_display_get_xdisplay (data->display);
-
-  if (data->glx_drawable)
-    glXDestroyWindow (dpy, data->glx_drawable);
-
-  if (data->dummy_glx)
-    glXDestroyWindow (dpy, data->dummy_glx);
-
-  if (data->dummy_xwin)
-    XDestroyWindow (dpy, data->dummy_xwin);
-
-  gdk_x11_display_error_trap_pop_ignored (data->display);
-
-  g_slice_free (DrawableInfo, data);
-}
-
-static DrawableInfo *
-get_glx_drawable_info (GdkSurface *surface)
-{
-  return g_object_get_data (G_OBJECT (surface), "-gdk-x11-surface-glx-info");
-}
-
-static void
-set_glx_drawable_info (GdkSurface    *surface,
-                       DrawableInfo *info)
-{
-  g_object_set_data_full (G_OBJECT (surface), "-gdk-x11-surface-glx-info",
-                          info,
-                          drawable_info_free);
-}
-
-static void
-maybe_wait_for_vblank (GdkDisplay  *display,
-                       GLXDrawable  drawable)
-{
-  GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
-  Display *dpy = gdk_x11_display_get_xdisplay (display);
-
-  if (display_x11->has_glx_sync_control)
-    {
-      gint64 ust, msc, sbc;
-
-      glXGetSyncValuesOML (dpy, drawable, &ust, &msc, &sbc);
-      glXWaitForMscOML (dpy, drawable,
-                        0, 2, (msc + 1) % 2,
-                        &ust, &msc, &sbc);
-    }
-  else if (display_x11->has_glx_video_sync)
-    {
-      guint32 current_count;
-
-      glXGetVideoSyncSGI (&current_count);
-      glXWaitVideoSyncSGI (2, (current_count + 1) % 2, &current_count);
-    }
-}
-
-static void
-gdk_x11_gl_context_end_frame (GdkDrawContext *draw_context,
-                              cairo_region_t *painted)
-{
-  GdkGLContext *context = GDK_GL_CONTEXT (draw_context);
-  GdkX11GLContext *context_x11 = GDK_X11_GL_CONTEXT (context);
-  GdkSurface *surface = gdk_gl_context_get_surface (context);
-  GdkDisplay *display = gdk_gl_context_get_display (context);
-  Display *dpy = gdk_x11_display_get_xdisplay (display);
-  GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
-  //GdkRectangle whole_window;
-  DrawableInfo *info;
-  GLXDrawable drawable;
-
-  GDK_DRAW_CONTEXT_CLASS (gdk_x11_gl_context_parent_class)->end_frame (draw_context, painted);
-  if (gdk_gl_context_get_shared_context (context))
-    return;
-
-  gdk_gl_context_make_current (context);
-
-  info = get_glx_drawable_info (surface);
-
-  drawable = context_x11->attached_drawable;
-
-  GDK_DISPLAY_NOTE (display, OPENGL,
-            g_message ("Flushing GLX buffers for drawable %lu (window: %lu), frame sync: %s",
-                       (unsigned long) drawable,
-                       (unsigned long) gdk_x11_surface_get_xid (surface),
-                       context_x11->do_frame_sync ? "yes" : "no"));
-
-  /* if we are going to wait for the vertical refresh manually
-   * we need to flush pending redraws, and we also need to wait
-   * for that to finish, otherwise we are going to tear.
-   *
-   * obviously, this condition should not be hit if we have
-   * GLX_SGI_swap_control, and we ask the driver to do the right
-   * thing.
-   */
-  if (context_x11->do_frame_sync)
-    {
-      guint32 end_frame_counter = 0;
-      gboolean has_counter = display_x11->has_glx_video_sync;
-      gboolean can_wait = display_x11->has_glx_video_sync || display_x11->has_glx_sync_control;
-
-      if (display_x11->has_glx_video_sync)
-        glXGetVideoSyncSGI (&end_frame_counter);
-
-      if (context_x11->do_frame_sync && !display_x11->has_glx_swap_interval)
-        {
-          glFinish ();
-
-          if (has_counter && can_wait)
-            {
-              guint32 last_counter = info != NULL ? info->last_frame_counter : 0;
-
-              if (last_counter == end_frame_counter)
-                maybe_wait_for_vblank (display, drawable);
-            }
-          else if (can_wait)
-            maybe_wait_for_vblank (display, drawable);
-        }
-    }
-
-  gdk_x11_surface_pre_damage (surface);
-
-#ifdef HAVE_XDAMAGE
-  if (context_x11->xdamage != 0 && _gdk_x11_surface_syncs_frames (surface))
-    {
-      g_assert (context_x11->frame_fence == 0);
-
-      context_x11->frame_fence = glFenceSync (GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
-
-      /* We consider the frame still getting painted until the GL operation is
-       * finished, and the window gets damage reported from the X server.
-       * It's only at this point the compositor can be sure it has full
-       * access to the new updates.
-       */
-      _gdk_x11_surface_set_frame_still_painting (surface, TRUE);
-    }
-#endif
-
-  glXSwapBuffers (dpy, drawable);
-
-  if (context_x11->do_frame_sync && info != NULL && display_x11->has_glx_video_sync)
-    glXGetVideoSyncSGI (&info->last_frame_counter);
-}
-
-static cairo_region_t *
-gdk_x11_gl_context_get_damage (GdkGLContext *context)
-{
-  GdkDisplay *display = gdk_draw_context_get_display (GDK_DRAW_CONTEXT (context));
-  GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
-  Display *dpy = gdk_x11_display_get_xdisplay (display);
-  unsigned int buffer_age = 0;
-
-  if (display_x11->has_glx_buffer_age)
-    {
-      GdkGLContext *shared;
-      GdkX11GLContext *shared_x11;
-
-      shared = gdk_gl_context_get_shared_context (context);
-      if (shared == NULL)
-        shared = context;
-      shared_x11 = GDK_X11_GL_CONTEXT (shared);
-
-      gdk_gl_context_make_current (shared);
-      glXQueryDrawable (dpy, shared_x11->attached_drawable,
-                        GLX_BACK_BUFFER_AGE_EXT, &buffer_age);
-
-      switch (buffer_age)
-        {
-          case 1:
-            return cairo_region_create ();
-            break;
-
-          case 2:
-            if (context->old_updated_area[0])
-              return cairo_region_copy (context->old_updated_area[0]);
-            break;
-
-          case 3:
-            if (context->old_updated_area[0] &&
-                context->old_updated_area[1])
-              {
-                cairo_region_t *damage = cairo_region_copy (context->old_updated_area[0]);
-                cairo_region_union (damage, context->old_updated_area[1]);
-                return damage;
-              }
-            break;
-
-          default:
-            ;
-        }
-
-    }
-
-  return GDK_GL_CONTEXT_CLASS (gdk_x11_gl_context_parent_class)->get_damage (context);
-}
-
-static XVisualInfo *
-find_xvisinfo_for_fbconfig (GdkDisplay  *display,
-                            GLXFBConfig  config)
-{
-  Display *dpy = gdk_x11_display_get_xdisplay (display);
-
-  return glXGetVisualFromFBConfig (dpy, config);
-}
-
-static GLXContext
-create_gl3_context (GdkDisplay   *display,
-                    GLXFBConfig   config,
-                    GdkGLContext *share,
-                    int           profile,
-                    int           flags,
-                    int           major,
-                    int           minor)
-{
-  int attrib_list[] = {
-    GLX_CONTEXT_PROFILE_MASK_ARB, profile,
-    GLX_CONTEXT_MAJOR_VERSION_ARB, major,
-    GLX_CONTEXT_MINOR_VERSION_ARB, minor,
-    GLX_CONTEXT_FLAGS_ARB, flags,
-    None,
-  };
-  GLXContext res;
-
-  GdkX11GLContext *share_x11 = NULL;
-
-  if (share != NULL)
-    share_x11 = GDK_X11_GL_CONTEXT (share);
-
-  gdk_x11_display_error_trap_push (display);
-
-  res = glXCreateContextAttribsARB (gdk_x11_display_get_xdisplay (display),
-                                    config,
-                                    share_x11 != NULL ? share_x11->glx_context : NULL,
-                                    True,
-                                    attrib_list);
-
-  if (gdk_x11_display_error_trap_pop (display))
-    return NULL;
-
-  return res;
-}
-
-static GLXContext
-create_legacy_context (GdkDisplay   *display,
-                       GLXFBConfig   config,
-                       GdkGLContext *share)
-{
-  GdkX11GLContext *share_x11 = NULL;
-  GLXContext res;
-
-  if (share != NULL)
-    share_x11 = GDK_X11_GL_CONTEXT (share);
-
-  gdk_x11_display_error_trap_push (display);
-
-  res = glXCreateNewContext (gdk_x11_display_get_xdisplay (display),
-                             config,
-                             GLX_RGBA_TYPE,
-                             share_x11 != NULL ? share_x11->glx_context : NULL,
-                             TRUE);
-
-  if (gdk_x11_display_error_trap_pop (display))
-    return NULL;
-
-  return res;
-}
+G_DEFINE_ABSTRACT_TYPE (GdkX11GLContext, gdk_x11_gl_context, GDK_TYPE_GL_CONTEXT)
 
 #ifdef HAVE_XDAMAGE
 static void
@@ -346,46 +61,6 @@ finish_frame (GdkGLContext *context)
   _gdk_x11_surface_set_frame_still_painting (surface, FALSE);
 }
 
-static void
-bind_context_for_frame_fence (GdkGLContext *context)
-{
-  GdkGLContext *current_context;
-  GdkX11GLContext *current_context_x11;
-  GLXContext current_glx_context = NULL;
-  gboolean needs_binding = TRUE;
-
-  /* We don't care if the passed context is the current context,
-   * necessarily, but we do care that *some* context that can
-   * see the sync object is bound.
-   *
-   * If no context is bound at all, the GL dispatch layer will
-   * make glClientWaitSync() silently return 0.
-   */
-  current_glx_context = glXGetCurrentContext ();
-
-  if (current_glx_context == NULL)
-    goto out;
-
-  current_context = gdk_gl_context_get_current ();
-
-  if (current_context == NULL)
-    goto out;
-
-  current_context_x11 = GDK_X11_GL_CONTEXT (current_context);
-
-  /* If the GLX context was changed out from under GDK, then
-   * that context may not be one that is able to see the
-   * created fence object.
-   */
-  if (current_context_x11->glx_context != current_glx_context)
-    goto out;
-
-  needs_binding = FALSE;
-out:
-  if (needs_binding)
-    gdk_gl_context_make_current (context);
-}
-
 static gboolean
 on_gl_surface_xevent (GdkGLContext   *context,
                       XEvent         *xevent,
@@ -407,9 +82,10 @@ on_gl_surface_xevent (GdkGLContext   *context,
 
   if (context_x11->frame_fence)
     {
+      GdkX11GLContextClass *context_class = GDK_X11_GL_CONTEXT_GET_CLASS (context);
       GLenum wait_result;
 
-      bind_context_for_frame_fence (context);
+      context_class->bind_for_frame_fence (context_x11);
 
       wait_result = glClientWaitSync (context_x11->frame_fence, 0, 0);
 
@@ -478,176 +154,17 @@ static gboolean
 gdk_x11_gl_context_realize (GdkGLContext  *context,
                             GError       **error)
 {
-  GdkX11Display *display_x11;
-  GdkDisplay *display;
-  GdkX11GLContext *context_x11;
-  XVisualInfo *xvisinfo;
-  Display *dpy;
-  DrawableInfo *info;
-  GdkGLContext *share;
-  GdkGLContext *shared_data_context;
-  GdkSurface *surface;
-  gboolean debug_bit, compat_bit, legacy_bit, es_bit;
-  int major, minor, flags;
-
-  surface = gdk_gl_context_get_surface (context);
-  display = gdk_surface_get_display (surface);
-  dpy = gdk_x11_display_get_xdisplay (display);
-  context_x11 = GDK_X11_GL_CONTEXT (context);
-  display_x11 = GDK_X11_DISPLAY (display);
-  share = gdk_gl_context_get_shared_context (context);
-  shared_data_context = gdk_surface_get_shared_data_gl_context (surface);
-
-  gdk_gl_context_get_required_version (context, &major, &minor);
-  debug_bit = gdk_gl_context_get_debug_enabled (context);
-  compat_bit = gdk_gl_context_get_forward_compatible (context);
-
-  /* If there is no glXCreateContextAttribsARB() then we default to legacy */
-  legacy_bit = !display_x11->has_glx_create_context || GDK_DISPLAY_DEBUG_CHECK (display, GL_LEGACY);
-
-  es_bit = (GDK_DISPLAY_DEBUG_CHECK (display, GL_GLES) || (share != NULL && gdk_gl_context_get_use_es 
(share))) &&
-           (display_x11->has_glx_create_context && display_x11->has_glx_create_es2_context);
-
-  /* We cannot share legacy contexts with core profile ones, so the
-   * shared context is the one that decides if we're going to create
-   * a legacy context or not.
-   */
-  if (share != NULL && gdk_gl_context_is_legacy (share))
-    legacy_bit = TRUE;
-
-  flags = 0;
-  if (debug_bit)
-    flags |= GLX_CONTEXT_DEBUG_BIT_ARB;
-  if (compat_bit)
-    flags |= GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
-
-  GDK_DISPLAY_NOTE (display, OPENGL,
-            g_message ("Creating GLX context (version:%d.%d, debug:%s, forward:%s, legacy:%s, es:%s)",
-                       major, minor,
-                       debug_bit ? "yes" : "no",
-                       compat_bit ? "yes" : "no",
-                       legacy_bit ? "yes" : "no",
-                       es_bit ? "yes" : "no"));
-
-  /* If we have access to GLX_ARB_create_context_profile then we can ask for
-   * a compatibility profile; if we don't, then we have to fall back to the
-   * old GLX 1.3 API.
-   */
-  if (legacy_bit && !GDK_X11_DISPLAY (display)->has_glx_create_context)
-    {
-      GDK_DISPLAY_NOTE (display, OPENGL, g_message ("Creating legacy GL context on request"));
-      context_x11->glx_context = create_legacy_context (display, context_x11->glx_config, share ? share : 
shared_data_context);
-    }
-  else
-    {
-      int profile;
-
-      if (es_bit)
-        profile = GLX_CONTEXT_ES2_PROFILE_BIT_EXT;
-      else
-        profile = legacy_bit ? GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB
-                             : GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
-
-      /* We need to tweak the version, otherwise we may end up requesting
-       * a compatibility context with a minimum version of 3.2, which is
-       * an error
-       */
-      if (legacy_bit)
-        {
-          major = 3;
-          minor = 0;
-        }
-
-      GDK_DISPLAY_NOTE (display, OPENGL, g_message ("Creating GL3 context"));
-      context_x11->glx_context = create_gl3_context (display,
-                                                     context_x11->glx_config,
-                                                     share ? share : shared_data_context,
-                                                     profile, flags, major, minor);
-
-      /* Fall back to legacy in case the GL3 context creation failed */
-      if (context_x11->glx_context == NULL)
-        {
-          GDK_DISPLAY_NOTE (display, OPENGL, g_message ("Creating fallback legacy context"));
-          context_x11->glx_context = create_legacy_context (display, context_x11->glx_config, share ? share 
: shared_data_context);
-          legacy_bit = TRUE;
-          es_bit = FALSE;
-        }
-    }
-
-  if (context_x11->glx_context == NULL)
-    {
-      g_set_error_literal (error, GDK_GL_ERROR,
-                           GDK_GL_ERROR_NOT_AVAILABLE,
-                           _("Unable to create a GL context"));
-      return FALSE;
-    }
-
-  /* Ensure that any other context is created with a legacy bit set */
-  gdk_gl_context_set_is_legacy (context, legacy_bit);
-
-  /* Ensure that any other context is created with an ES bit set */
-  gdk_gl_context_set_use_es (context, es_bit);
-
-  xvisinfo = find_xvisinfo_for_fbconfig (display, context_x11->glx_config);
-
-  info = get_glx_drawable_info (surface);
-  if (info == NULL)
-    {
-      XSetWindowAttributes attrs;
-      unsigned long mask;
-
-      gdk_x11_display_error_trap_push (display);
-
-      info = g_slice_new0 (DrawableInfo);
-      info->display = display;
-      info->last_frame_counter = 0;
-
-      attrs.override_redirect = True;
-      attrs.colormap = XCreateColormap (dpy, DefaultRootWindow (dpy), xvisinfo->visual, AllocNone);
-      attrs.border_pixel = 0;
-      mask = CWOverrideRedirect | CWColormap | CWBorderPixel;
-      info->dummy_xwin = XCreateWindow (dpy, DefaultRootWindow (dpy),
-                                        -100, -100, 1, 1,
-                                        0,
-                                        xvisinfo->depth,
-                                        CopyFromParent,
-                                        xvisinfo->visual,
-                                        mask,
-                                        &attrs);
-      XMapWindow(dpy, info->dummy_xwin);
-
-      if (GDK_X11_DISPLAY (display)->glx_version >= 13)
-        {
-          info->glx_drawable = glXCreateWindow (dpy, context_x11->glx_config,
-                                                gdk_x11_surface_get_xid (surface),
-                                                NULL);
-          info->dummy_glx = glXCreateWindow (dpy, context_x11->glx_config, info->dummy_xwin, NULL);
-        }
-
-      if (gdk_x11_display_error_trap_pop (display))
-        {
-          g_set_error_literal (error, GDK_GL_ERROR,
-                               GDK_GL_ERROR_NOT_AVAILABLE,
-                               _("Unable to create a GL context"));
-
-          XFree (xvisinfo);
-          drawable_info_free (info);
-          glXDestroyContext (dpy, context_x11->glx_context);
-          context_x11->glx_context = NULL;
-
-          return FALSE;
-        }
-
-      set_glx_drawable_info (surface, info);
-    }
-
-  XFree (xvisinfo);
+#ifdef HAVE_XDAMAGE
+  GdkDisplay *display = gdk_gl_context_get_display (context);
+  GdkSurface *surface = gdk_gl_context_get_surface (context);
+  GdkX11GLContext *context_x11 = GDK_X11_GL_CONTEXT (context);
+  GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
 
-  context_x11->attached_drawable = info->glx_drawable ? info->glx_drawable : gdk_x11_surface_get_xid 
(surface);
-  context_x11->unattached_drawable = info->dummy_glx ? info->dummy_glx : info->dummy_xwin;
+  Display *dpy = gdk_x11_display_get_xdisplay (display);
 
-#ifdef HAVE_XDAMAGE
-  if (display_x11->have_damage && display_x11->has_async_glx_swap_buffers)
+  if (display_x11->have_damage &&
+      display_x11->have_glx &&
+      display_x11->has_async_glx_swap_buffers)
     {
       gdk_x11_display_error_trap_push (display);
       context_x11->xdamage = XDamageCreate (dpy,
@@ -674,55 +191,37 @@ gdk_x11_gl_context_realize (GdkGLContext  *context,
     }
 #endif
 
-  context_x11->is_direct = glXIsDirect (dpy, context_x11->glx_context);
-
-  GDK_DISPLAY_NOTE (display, OPENGL,
-            g_message ("Realized GLX context[%p], %s",
-                       context_x11->glx_context,
-                       context_x11->is_direct ? "direct" : "indirect"));
-
   return TRUE;
 }
 
 static void
 gdk_x11_gl_context_dispose (GObject *gobject)
 {
-  GdkX11GLContext *context_x11 = GDK_X11_GL_CONTEXT (gobject);
-
-  if (context_x11->glx_context != NULL)
-    {
-      GdkGLContext *context = GDK_GL_CONTEXT (gobject);
-      GdkDisplay *display = gdk_gl_context_get_display (context);
-      Display *dpy = gdk_x11_display_get_xdisplay (display);
-
-      if (glXGetCurrentContext () == context_x11->glx_context)
-        glXMakeContextCurrent (dpy, None, None, NULL);
-
-      GDK_DISPLAY_NOTE (display, OPENGL, g_message ("Destroying GLX context"));
-      glXDestroyContext (dpy, context_x11->glx_context);
-      context_x11->glx_context = NULL;
-    }
+  GdkX11GLContext *self = GDK_X11_GL_CONTEXT (gobject);
 
 #ifdef HAVE_XDAMAGE
-  context_x11->xdamage = 0;
+  self->xdamage = 0;
 #endif
 
   G_OBJECT_CLASS (gdk_x11_gl_context_parent_class)->dispose (gobject);
 }
 
+static void
+gdk_x11_gl_context_real_bind_for_frame_fence (GdkX11GLContext *self)
+{
+}
+
 static void
 gdk_x11_gl_context_class_init (GdkX11GLContextClass *klass)
 {
-  GdkGLContextClass *context_class = GDK_GL_CONTEXT_CLASS (klass);
-  GdkDrawContextClass *draw_context_class = GDK_DRAW_CONTEXT_CLASS (klass);
   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GdkGLContextClass *context_class = GDK_GL_CONTEXT_CLASS (klass);
 
-  context_class->realize = gdk_x11_gl_context_realize;
-  context_class->get_damage = gdk_x11_gl_context_get_damage;
+  gobject_class->dispose = gdk_x11_gl_context_dispose;
 
-  draw_context_class->end_frame = gdk_x11_gl_context_end_frame;
+  context_class->realize = gdk_x11_gl_context_realize;
 
-  gobject_class->dispose = gdk_x11_gl_context_dispose;
+  klass->bind_for_frame_fence = gdk_x11_gl_context_real_bind_for_frame_fence;
 }
 
 static void
@@ -735,443 +234,25 @@ gboolean
 gdk_x11_screen_init_gl (GdkX11Screen *screen)
 {
   GdkDisplay *display = GDK_SCREEN_DISPLAY (screen);
-  GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
-  Display *dpy;
-  int error_base, event_base;
-  int screen_num;
-
-  if (display_x11->have_glx)
-    return TRUE;
 
   if (GDK_DISPLAY_DEBUG_CHECK (display, GL_DISABLE))
     return FALSE;
 
-  dpy = gdk_x11_display_get_xdisplay (display);
-
-  if (!epoxy_has_glx (dpy))
-    return FALSE;
-
-  if (!glXQueryExtension (dpy, &error_base, &event_base))
-    return FALSE;
-
-  screen_num = screen->screen_num;
-
-  display_x11->have_glx = TRUE;
-
-  display_x11->glx_version = epoxy_glx_version (dpy, screen_num);
-  display_x11->glx_error_base = error_base;
-  display_x11->glx_event_base = event_base;
-
-  display_x11->has_glx_create_context =
-    epoxy_has_glx_extension (dpy, screen_num, "GLX_ARB_create_context_profile");
-  display_x11->has_glx_create_es2_context =
-    epoxy_has_glx_extension (dpy, screen_num, "GLX_EXT_create_context_es2_profile");
-  display_x11->has_glx_swap_interval =
-    epoxy_has_glx_extension (dpy, screen_num, "GLX_SGI_swap_control");
-  display_x11->has_glx_texture_from_pixmap =
-    epoxy_has_glx_extension (dpy, screen_num, "GLX_EXT_texture_from_pixmap");
-  display_x11->has_glx_video_sync =
-    epoxy_has_glx_extension (dpy, screen_num, "GLX_SGI_video_sync");
-  display_x11->has_glx_buffer_age =
-    epoxy_has_glx_extension (dpy, screen_num, "GLX_EXT_buffer_age");
-  display_x11->has_glx_sync_control =
-    epoxy_has_glx_extension (dpy, screen_num, "GLX_OML_sync_control");
-  display_x11->has_glx_multisample =
-    epoxy_has_glx_extension (dpy, screen_num, "GLX_ARB_multisample");
-  display_x11->has_glx_visual_rating =
-    epoxy_has_glx_extension (dpy, screen_num, "GLX_EXT_visual_rating");
-
-  if (g_strcmp0 (glXGetClientString (dpy, GLX_VENDOR), "NVIDIA Corporation") == 0)
-    {
-      /* With the mesa based drivers, we can safely assume the compositor can
-       * access the updated surface texture immediately after glXSwapBuffers is
-       * run, because the kernel ensures there is an implicit synchronization
-       * operation upon texture access. This is not true with the Nvidia vendor
-       * driver. There is a window of time after glXSwapBuffers before other
-       * processes can see the updated drawing. We need to take special care,
-       * in that case, to defer telling the compositor our latest frame is
-       * ready until after the GPU has completed all issued commands related
-       * to the frame, and that the X server says the frame has been drawn.
-       */
-      display_x11->has_async_glx_swap_buffers = TRUE;
-    }
-
-  GDK_DISPLAY_NOTE (display, OPENGL,
-            g_message ("GLX version %d.%d found\n"
-                       " - Vendor: %s\n"
-                       " - Checked extensions:\n"
-                       "\t* GLX_ARB_create_context_profile: %s\n"
-                       "\t* GLX_EXT_create_context_es2_profile: %s\n"
-                       "\t* GLX_SGI_swap_control: %s\n"
-                       "\t* GLX_EXT_texture_from_pixmap: %s\n"
-                       "\t* GLX_SGI_video_sync: %s\n"
-                       "\t* GLX_EXT_buffer_age: %s\n"
-                       "\t* GLX_OML_sync_control: %s"
-                       "\t* GLX_ARB_multisample: %s"
-                       "\t* GLX_EXT_visual_rating: %s",
-                     display_x11->glx_version / 10,
-                     display_x11->glx_version % 10,
-                     glXGetClientString (dpy, GLX_VENDOR),
-                     display_x11->has_glx_create_context ? "yes" : "no",
-                     display_x11->has_glx_create_es2_context ? "yes" : "no",
-                     display_x11->has_glx_swap_interval ? "yes" : "no",
-                     display_x11->has_glx_texture_from_pixmap ? "yes" : "no",
-                     display_x11->has_glx_video_sync ? "yes" : "no",
-                     display_x11->has_glx_buffer_age ? "yes" : "no",
-                     display_x11->has_glx_sync_control ? "yes" : "no",
-                     display_x11->has_glx_multisample ? "yes" : "no",
-                     display_x11->has_glx_visual_rating ? "yes" : "no"));
-
-  return TRUE;
-}
-
-#define MAX_GLX_ATTRS   30
-
-static gboolean
-find_fbconfig (GdkDisplay   *display,
-               GLXFBConfig  *fb_config_out,
-               GError      **error)
-{
-  static int attrs[MAX_GLX_ATTRS];
-  Display *dpy = gdk_x11_display_get_xdisplay (display);
-  GLXFBConfig *configs;
-  int n_configs, i;
-  gboolean retval = FALSE;
-  VisualID xvisual_id = XVisualIDFromVisual (gdk_x11_display_get_window_visual (GDK_X11_DISPLAY (display)));
-
-  i = 0;
-  attrs[i++] = GLX_DRAWABLE_TYPE;
-  attrs[i++] = GLX_WINDOW_BIT;
-
-  attrs[i++] = GLX_RENDER_TYPE;
-  attrs[i++] = GLX_RGBA_BIT;
-
-  attrs[i++] = GLX_DOUBLEBUFFER;
-  attrs[i++] = GL_TRUE;
-
-  attrs[i++] = GLX_RED_SIZE;
-  attrs[i++] = 1;
-  attrs[i++] = GLX_GREEN_SIZE;
-  attrs[i++] = 1;
-  attrs[i++] = GLX_BLUE_SIZE;
-  attrs[i++] = 1;
-
-  if (gdk_display_is_rgba (display))
-    {
-      attrs[i++] = GLX_ALPHA_SIZE;
-      attrs[i++] = 1;
-    }
-  else
-    {
-      attrs[i++] = GLX_ALPHA_SIZE;
-      attrs[i++] = GLX_DONT_CARE;
-    }
-
-  attrs[i++] = None;
-
-  g_assert (i < MAX_GLX_ATTRS);
-
-  configs = glXChooseFBConfig (dpy, DefaultScreen (dpy), attrs, &n_configs);
-  if (configs == NULL || n_configs == 0)
-    {
-      g_set_error_literal (error, GDK_GL_ERROR,
-                           GDK_GL_ERROR_UNSUPPORTED_FORMAT,
-                           _("No available configurations for the given pixel format"));
-      return FALSE;
-    }
-
-  for (i = 0; i < n_configs; i++)
-    {
-      XVisualInfo *visinfo;
-
-      visinfo = glXGetVisualFromFBConfig (dpy, configs[i]);
-      if (visinfo == NULL)
-        continue;
-
-      if (visinfo->visualid != xvisual_id)
-        {
-          XFree (visinfo);
-          continue;
-        }
-
-      if (fb_config_out != NULL)
-        *fb_config_out = configs[i];
-
-      XFree (visinfo);
-      retval = TRUE;
-      goto out;
-    }
-
-  g_set_error (error, GDK_GL_ERROR,
-               GDK_GL_ERROR_UNSUPPORTED_FORMAT,
-               _("No available configurations for the given RGBA pixel format"));
-
-out:
-  XFree (configs);
-
-  return retval;
-}
-
-struct glvisualinfo {
-  int supports_gl;
-  int double_buffer;
-  int stereo;
-  int alpha_size;
-  int depth_size;
-  int stencil_size;
-  int num_multisample;
-  int visual_caveat;
-};
-
-static gboolean
-visual_compatible (const GdkX11Visual *a, const GdkX11Visual *b)
-{
-  return a->type == b->type &&
-    a->depth == b->depth &&
-    a->red_mask == b->red_mask &&
-    a->green_mask == b->green_mask &&
-    a->blue_mask == b->blue_mask &&
-    a->colormap_size == b->colormap_size &&
-    a->bits_per_rgb == b->bits_per_rgb;
-}
-
-static gboolean
-visual_is_rgba (const GdkX11Visual *visual)
-{
-  return
-    visual->depth == 32 &&
-    visual->red_mask   == 0xff0000 &&
-    visual->green_mask == 0x00ff00 &&
-    visual->blue_mask  == 0x0000ff;
-}
-
-/* This picks a compatible (as in has the same X visual details) visual
-   that has "better" characteristics on the GL side */
-static GdkX11Visual *
-pick_better_visual_for_gl (GdkX11Screen *x11_screen,
-                           struct glvisualinfo *gl_info,
-                           GdkX11Visual *compatible)
-{
-  GdkX11Visual *visual;
-  int i;
-  gboolean want_alpha = visual_is_rgba (compatible);
-
-  /* First look for "perfect match", i.e:
-   * supports gl
-   * double buffer
-   * alpha iff visual is an rgba visual
-   * no unnecessary stuff
-   */
-  for (i = 0; i < x11_screen->nvisuals; i++)
-    {
-      visual = x11_screen->visuals[i];
-      if (visual_compatible (visual, compatible) &&
-          gl_info[i].supports_gl &&
-          gl_info[i].double_buffer &&
-          !gl_info[i].stereo &&
-          (want_alpha ? (gl_info[i].alpha_size > 0) : (gl_info[i].alpha_size == 0)) &&
-          (gl_info[i].depth_size == 0) &&
-          (gl_info[i].stencil_size == 0) &&
-          (gl_info[i].num_multisample == 0) &&
-          (gl_info[i].visual_caveat == GLX_NONE_EXT))
-        return visual;
-    }
-
-  if (!want_alpha)
-    {
-      /* Next, allow alpha even if we don't want it: */
-      for (i = 0; i < x11_screen->nvisuals; i++)
-        {
-          visual = x11_screen->visuals[i];
-          if (visual_compatible (visual, compatible) &&
-              gl_info[i].supports_gl &&
-              gl_info[i].double_buffer &&
-              !gl_info[i].stereo &&
-              (gl_info[i].depth_size == 0) &&
-              (gl_info[i].stencil_size == 0) &&
-              (gl_info[i].num_multisample == 0) &&
-              (gl_info[i].visual_caveat == GLX_NONE_EXT))
-            return visual;
-        }
-    }
-
-  /* Next, allow depth and stencil buffers: */
-  for (i = 0; i < x11_screen->nvisuals; i++)
-    {
-      visual = x11_screen->visuals[i];
-      if (visual_compatible (visual, compatible) &&
-          gl_info[i].supports_gl &&
-          gl_info[i].double_buffer &&
-          !gl_info[i].stereo &&
-          (gl_info[i].num_multisample == 0) &&
-          (gl_info[i].visual_caveat == GLX_NONE_EXT))
-        return visual;
-    }
-
-  /* Next, allow multisample: */
-  for (i = 0; i < x11_screen->nvisuals; i++)
-    {
-      visual = x11_screen->visuals[i];
-      if (visual_compatible (visual, compatible) &&
-          gl_info[i].supports_gl &&
-          gl_info[i].double_buffer &&
-          !gl_info[i].stereo &&
-          (gl_info[i].visual_caveat == GLX_NONE_EXT))
-        return visual;
-    }
-
-  return compatible;
-}
-
-static gboolean
-get_cached_gl_visuals (GdkDisplay *display, int *system, int *rgba)
-{
-  gboolean found;
-  Atom type_return;
-  int format_return;
-  gulong nitems_return;
-  gulong bytes_after_return;
-  guchar *data = NULL;
-  Display *dpy;
-
-  dpy = gdk_x11_display_get_xdisplay (display);
-
-  found = FALSE;
-
-  gdk_x11_display_error_trap_push (display);
-  if (XGetWindowProperty (dpy, DefaultRootWindow (dpy),
-                          gdk_x11_get_xatom_by_name_for_display (display, "GDK_VISUALS"),
-                          0, 2, False, XA_INTEGER, &type_return,
-                          &format_return, &nitems_return,
-                          &bytes_after_return, &data) == Success)
-    {
-      if (type_return == XA_INTEGER &&
-          format_return == 32 &&
-          nitems_return == 2 &&
-          data != NULL)
-        {
-          long *visuals = (long *) data;
-
-          *system = (int)visuals[0];
-          *rgba = (int)visuals[1];
-          found = TRUE;
-        }
-    }
-  gdk_x11_display_error_trap_pop_ignored (display);
-
-  if (data)
-    XFree (data);
-
-  return found;
-}
-
-static void
-save_cached_gl_visuals (GdkDisplay *display, int system, int rgba)
-{
-  long visualdata[2];
-  Display *dpy;
-
-  dpy = gdk_x11_display_get_xdisplay (display);
-
-  visualdata[0] = system;
-  visualdata[1] = rgba;
-
-  gdk_x11_display_error_trap_push (display);
-  XChangeProperty (dpy, DefaultRootWindow (dpy),
-                   gdk_x11_get_xatom_by_name_for_display (display, "GDK_VISUALS"),
-                   XA_INTEGER, 32, PropModeReplace,
-                   (unsigned char *)visualdata, 2);
-  gdk_x11_display_error_trap_pop_ignored (display);
-}
-
-void
-_gdk_x11_screen_update_visuals_for_gl (GdkX11Screen *x11_screen)
-{
-  GdkDisplay *display;
-  GdkX11Display *display_x11;
-  Display *dpy;
-  struct glvisualinfo *gl_info;
-  int i;
-  int system_visual_id, rgba_visual_id;
-
-  display = x11_screen->display;
-  display_x11 = GDK_X11_DISPLAY (display);
-  dpy = gdk_x11_display_get_xdisplay (display);
-
-  /* We save the default visuals as a property on the root window to avoid
-     having to initialize GL each time, as it may not be used later. */
-  if (get_cached_gl_visuals (display, &system_visual_id, &rgba_visual_id))
-    {
-      for (i = 0; i < x11_screen->nvisuals; i++)
-        {
-          GdkX11Visual *visual = x11_screen->visuals[i];
-          int visual_id = gdk_x11_visual_get_xvisual (visual)->visualid;
-
-          if (visual_id == system_visual_id)
-            x11_screen->system_visual = visual;
-          if (visual_id == rgba_visual_id)
-            x11_screen->rgba_visual = visual;
-        }
-
-      return;
-    }
-
-  if (!gdk_x11_screen_init_gl (x11_screen))
-    return;
-
-  gl_info = g_new0 (struct glvisualinfo, x11_screen->nvisuals);
-
-  for (i = 0; i < x11_screen->nvisuals; i++)
-    {
-      XVisualInfo *visual_list;
-      XVisualInfo visual_template;
-      int nxvisuals;
-
-      visual_template.screen = x11_screen->screen_num;
-      visual_template.visualid = gdk_x11_visual_get_xvisual (x11_screen->visuals[i])->visualid;
-      visual_list = XGetVisualInfo (x11_screen->xdisplay, VisualIDMask| VisualScreenMask, &visual_template, 
&nxvisuals);
-
-      if (visual_list == NULL)
-        continue;
-
-      glXGetConfig (dpy, &visual_list[0], GLX_USE_GL, &gl_info[i].supports_gl);
-      glXGetConfig (dpy, &visual_list[0], GLX_DOUBLEBUFFER, &gl_info[i].double_buffer);
-      glXGetConfig (dpy, &visual_list[0], GLX_STEREO, &gl_info[i].stereo);
-      glXGetConfig (dpy, &visual_list[0], GLX_ALPHA_SIZE, &gl_info[i].alpha_size);
-      glXGetConfig (dpy, &visual_list[0], GLX_DEPTH_SIZE, &gl_info[i].depth_size);
-      glXGetConfig (dpy, &visual_list[0], GLX_STENCIL_SIZE, &gl_info[i].stencil_size);
-
-      if (display_x11->has_glx_multisample)
-        glXGetConfig(dpy, &visual_list[0], GLX_SAMPLE_BUFFERS_ARB, &gl_info[i].num_multisample);
-
-      if (display_x11->has_glx_visual_rating)
-        glXGetConfig(dpy, &visual_list[0], GLX_VISUAL_CAVEAT_EXT, &gl_info[i].visual_caveat);
-      else
-        gl_info[i].visual_caveat = GLX_NONE_EXT;
-
-      XFree (visual_list);
-    }
-
-  x11_screen->system_visual = pick_better_visual_for_gl (x11_screen, gl_info, x11_screen->system_visual);
-  if (x11_screen->rgba_visual)
-    x11_screen->rgba_visual = pick_better_visual_for_gl (x11_screen, gl_info, x11_screen->rgba_visual);
-
-  g_free (gl_info);
+  if (gdk_x11_screen_init_glx (screen))
+    return TRUE;
 
-  save_cached_gl_visuals (display,
-                          gdk_x11_visual_get_xvisual (x11_screen->system_visual)->visualid,
-                          x11_screen->rgba_visual ? gdk_x11_visual_get_xvisual 
(x11_screen->rgba_visual)->visualid : 0);
+  return FALSE;
 }
 
 GdkGLContext *
 gdk_x11_surface_create_gl_context (GdkSurface    *surface,
-                                  gboolean      attached,
-                                  GdkGLContext *share,
-                                  GError      **error)
+                                   gboolean       attached,
+                                   GdkGLContext  *share,
+                                   GError       **error)
 {
-  GdkDisplay *display;
+  GdkX11Display *display_x11;
   GdkX11GLContext *context;
-  GLXFBConfig config;
+  GdkDisplay *display;
 
   display = gdk_surface_get_display (surface);
 
@@ -1183,15 +264,15 @@ gdk_x11_surface_create_gl_context (GdkSurface    *surface,
       return NULL;
     }
 
-  if (!find_fbconfig (display, &config, error))
-    return NULL;
+  display_x11 = GDK_X11_DISPLAY (display);
+  if (display_x11->have_glx)
+    context = gdk_x11_gl_context_glx_new (surface, attached, share, error);
+  else
+    g_assert_not_reached ();
 
-  context = g_object_new (GDK_TYPE_X11_GL_CONTEXT,
-                          "surface", surface,
-                          "shared-context", share,
-                          NULL);
+  if (context == NULL)
+    return NULL;
 
-  context->glx_config = config;
   context->is_attached = attached;
 
   return GDK_GL_CONTEXT (context);
@@ -1201,91 +282,10 @@ gboolean
 gdk_x11_display_make_gl_context_current (GdkDisplay   *display,
                                          GdkGLContext *context)
 {
-  GdkX11GLContext *context_x11;
-  Display *dpy = gdk_x11_display_get_xdisplay (display);
-  gboolean do_frame_sync = FALSE;
-  GLXWindow drawable;
-
-  if (context == NULL)
-    {
-      glXMakeContextCurrent (dpy, None, None, NULL);
-      return TRUE;
-    }
-
-  context_x11 = GDK_X11_GL_CONTEXT (context);
-  if (context_x11->glx_context == NULL)
-    {
-      g_critical ("No GLX context associated to the GdkGLContext; you must "
-                  "call gdk_gl_context_realize() first.");
-      return FALSE;
-    }
-
-  if (context_x11->is_attached || gdk_draw_context_is_in_frame (GDK_DRAW_CONTEXT (context)))
-    drawable = context_x11->attached_drawable;
-  else
-    drawable = context_x11->unattached_drawable;
-
-  GDK_DISPLAY_NOTE (display, OPENGL,
-            g_message ("Making GLX context %p current to drawable %lu",
-                       context, (unsigned long) drawable));
-
-  if (!glXMakeContextCurrent (dpy, drawable, drawable,
-                              context_x11->glx_context))
-    {
-      GDK_DISPLAY_NOTE (display, OPENGL,
-                g_message ("Making GLX context current failed"));
-      return FALSE;
-    }
-
-  if (context_x11->is_attached && GDK_X11_DISPLAY (display)->has_glx_swap_interval)
-    {
-      /* If the WM is compositing there is no particular need to delay
-       * the swap when drawing on the offscreen, rendering to the screen
-       * happens later anyway, and its up to the compositor to sync that
-       * to the vblank. */
-      do_frame_sync = ! gdk_display_is_composited (display);
-
-      if (do_frame_sync != context_x11->do_frame_sync)
-        {
-          context_x11->do_frame_sync = do_frame_sync;
-
-          if (do_frame_sync)
-            glXSwapIntervalSGI (1);
-          else
-            glXSwapIntervalSGI (0);
-        }
-    }
-
-  return TRUE;
-}
-
-/**
- * gdk_x11_display_get_glx_version:
- * @display: (type GdkX11Display): a #GdkDisplay
- * @major: (out): return location for the GLX major version
- * @minor: (out): return location for the GLX minor version
- *
- * Retrieves the version of the GLX implementation.
- *
- * Returns: %TRUE if GLX is available
- */
-gboolean
-gdk_x11_display_get_glx_version (GdkDisplay *display,
-                                 int        *major,
-                                 int        *minor)
-{
-  g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
-
-  if (!GDK_IS_X11_DISPLAY (display))
-    return FALSE;
-
-  if (!gdk_x11_screen_init_gl (GDK_X11_DISPLAY (display)->screen))
-    return FALSE;
+  GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
 
-  if (major != NULL)
-    *major = GDK_X11_DISPLAY (display)->glx_version / 10;
-  if (minor != NULL)
-    *minor = GDK_X11_DISPLAY (display)->glx_version % 10;
+  if (display_x11->have_glx)
+    return gdk_x11_gl_context_glx_make_current (display, context);
 
-  return TRUE;
+  return FALSE;
 }
diff --git a/gdk/x11/gdkglcontext-x11.h b/gdk/x11/gdkglcontext-x11.h
index b17ed2956e..6b1c0a5cec 100644
--- a/gdk/x11/gdkglcontext-x11.h
+++ b/gdk/x11/gdkglcontext-x11.h
@@ -21,6 +21,8 @@
 #ifndef __GDK_X11_GL_CONTEXT__
 #define __GDK_X11_GL_CONTEXT__
 
+#include "gdkx11glcontext.h"
+
 #include <X11/X.h>
 #include <X11/Xlib.h>
 
@@ -39,37 +41,54 @@
 
 G_BEGIN_DECLS
 
+#define GDK_X11_GL_CONTEXT_CLASS(klass)         (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_X11_GL_CONTEXT, 
GdkX11GLContextClass))
+#define GDK_X11_GL_CONTEXT_GET_CLASS(obj)       (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_X11_GL_CONTEXT, 
GdkX11GLContextClass))
+#define GDK_X11_IS_GL_CONTEXT_CLASS(klass)      (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_X11_GL_CONTEXT))
+
 struct _GdkX11GLContext
 {
   GdkGLContext parent_instance;
 
-  GLXContext glx_context;
-  GLXFBConfig glx_config;
-  GLXDrawable attached_drawable;
-  GLXDrawable unattached_drawable;
-
 #ifdef HAVE_XDAMAGE
   GLsync frame_fence;
   Damage xdamage;
 #endif
 
   guint is_attached : 1;
-  guint is_direct : 1;
   guint do_frame_sync : 1;
 };
 
 struct _GdkX11GLContextClass
 {
   GdkGLContextClass parent_class;
+
+  void (* bind_for_frame_fence) (GdkX11GLContext *self);
 };
 
-gboolean        gdk_x11_screen_init_gl                          (GdkX11Screen      *screen);
-GdkGLContext *  gdk_x11_surface_create_gl_context                (GdkSurface         *window,
-                                                                gboolean           attached,
-                                                                 GdkGLContext      *share,
-                                                                 GError           **error);
-gboolean        gdk_x11_display_make_gl_context_current         (GdkDisplay        *display,
-                                                                 GdkGLContext      *context);
+#define GDK_TYPE_X11_GL_CONTEXT_GLX     (gdk_x11_gl_context_glx_get_type())
+#define GDK_X11_GL_CONTEXT_GLX(obj)     (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_X11_GL_CONTEXT_GLX, 
GdkX11GLContextGLX))
+#define GDK_IS_X11_GL_CONTEXT_GLX(obj)  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_X11_GL_CONTEXT_GLX))
+
+typedef struct _GdkX11GLContextGLX      GdkX11GLContextGLX;
+
+gboolean        gdk_x11_screen_init_gl                  (GdkX11Screen  *screen);
+gboolean        gdk_x11_screen_init_glx                 (GdkX11Screen  *screen);
+
+GdkGLContext *  gdk_x11_surface_create_gl_context       (GdkSurface    *window,
+                                                         gboolean       attached,
+                                                         GdkGLContext  *share,
+                                                         GError       **error);
+gboolean        gdk_x11_display_make_gl_context_current (GdkDisplay    *display,
+                                                         GdkGLContext  *context);
+
+GType                   gdk_x11_gl_context_glx_get_type         (void) G_GNUC_CONST;
+GdkX11GLContext *       gdk_x11_gl_context_glx_new              (GdkSurface    *surface,
+                                                                 gboolean       attached,
+                                                                 GdkGLContext  *share,
+                                                                 GError       **error);
+gboolean                gdk_x11_gl_context_glx_make_current     (GdkDisplay    *display,
+                                                                 GdkGLContext  *context);
+
 
 G_END_DECLS
 
diff --git a/gdk/x11/meson.build b/gdk/x11/meson.build
index ec7d0ef78f..dde50f2169 100644
--- a/gdk/x11/meson.build
+++ b/gdk/x11/meson.build
@@ -8,6 +8,7 @@ gdk_x11_public_sources = files([
   'gdkdevicemanager-x11.c',
   'gdkdevicemanager-xi2.c',
   'gdkdisplay-x11.c',
+  'gdkglcontext-glx.c',
   'gdkglcontext-x11.c',
   'gdkkeys-x11.c',
   'gdkmonitor-x11.c',


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]