[mutter] cogl/glx: Move onscreen code to a separate file



commit a057432e3d889bf1e0a9daee7292f3b550f9ebc0
Author: Jonas Ådahl <jadahl gmail com>
Date:   Sat Oct 17 17:58:35 2020 +0200

    cogl/glx: Move onscreen code to a separate file
    
    Mostly in order to untangle it from the rest, preparing turning it into
    a GObject.
    
    Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1514>

 cogl/cogl/meson.build                      |    2 +
 cogl/cogl/winsys/cogl-onscreen-glx.c       | 1129 ++++++++++++++++++++++++++++
 cogl/cogl/winsys/cogl-onscreen-glx.h       |   87 +++
 cogl/cogl/winsys/cogl-winsys-glx-private.h |   13 +
 cogl/cogl/winsys/cogl-winsys-glx.c         | 1127 ++-------------------------
 src/backends/x11/meta-renderer-x11.c       |    9 +-
 6 files changed, 1287 insertions(+), 1080 deletions(-)
---
diff --git a/cogl/cogl/meson.build b/cogl/cogl/meson.build
index d973a4cf7a..9bf5e04fb0 100644
--- a/cogl/cogl/meson.build
+++ b/cogl/cogl/meson.build
@@ -380,6 +380,8 @@ if have_glx
   cogl_sources += [
     'winsys/cogl-glx-display-private.h',
     'winsys/cogl-glx-renderer-private.h',
+    'winsys/cogl-onscreen-glx.c',
+    'winsys/cogl-onscreen-glx.h',
     'winsys/cogl-winsys-glx-feature-functions.h',
     'winsys/cogl-winsys-glx-private.h',
     'winsys/cogl-winsys-glx.c',
diff --git a/cogl/cogl/winsys/cogl-onscreen-glx.c b/cogl/cogl/winsys/cogl-onscreen-glx.c
new file mode 100644
index 0000000000..01d70af4f8
--- /dev/null
+++ b/cogl/cogl/winsys/cogl-onscreen-glx.c
@@ -0,0 +1,1129 @@
+/*
+ * Copyright (C) 2007,2008,2009,2010,2011,2013 Intel Corporation.
+ * Copyright (C) 2020 Red Hat
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "cogl-config.h"
+
+#include "winsys/cogl-onscreen-glx.h"
+
+#include <GL/glx.h>
+#include <sys/time.h>
+
+#include "cogl-context-private.h"
+#include "cogl-frame-info-private.h"
+#include "cogl-renderer-private.h"
+#include "cogl-xlib-renderer-private.h"
+#include "winsys/cogl-glx-display-private.h"
+#include "winsys/cogl-glx-renderer-private.h"
+#include "winsys/cogl-winsys-glx-private.h"
+
+typedef struct _CoglOnscreenGLX
+{
+  Window xwin;
+  int x, y;
+  CoglOutput *output;
+
+  GLXDrawable glxwin;
+  uint32_t last_swap_vsync_counter;
+  uint32_t pending_sync_notify;
+  uint32_t pending_complete_notify;
+  uint32_t pending_resize_notify;
+} CoglOnscreenGLX;
+
+#define COGL_ONSCREEN_X11_EVENT_MASK (StructureNotifyMask | ExposureMask)
+
+gboolean
+_cogl_winsys_onscreen_glx_init (CoglOnscreen  *onscreen,
+                                GError       **error)
+{
+  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
+  CoglContext *context = cogl_framebuffer_get_context (framebuffer);
+  CoglDisplay *display = context->display;
+  CoglGLXDisplay *glx_display = display->winsys;
+  CoglXlibRenderer *xlib_renderer =
+    _cogl_xlib_renderer_get_data (display->renderer);
+  CoglGLXRenderer *glx_renderer = display->renderer->winsys;
+  Window xwin;
+  CoglOnscreenGLX *glx_onscreen;
+  const CoglFramebufferConfig *config;
+  GLXFBConfig fbconfig;
+  GError *fbconfig_error = NULL;
+  CoglOnscreenGLX *winsys;
+
+  g_return_val_if_fail (glx_display->glx_context, FALSE);
+
+  config = cogl_framebuffer_get_config (framebuffer);
+  if (!cogl_display_glx_find_fbconfig (display, config,
+                                       &fbconfig,
+                                       &fbconfig_error))
+    {
+      g_set_error (error, COGL_WINSYS_ERROR,
+                   COGL_WINSYS_ERROR_CREATE_CONTEXT,
+                   "Unable to find suitable fbconfig for the GLX context: %s",
+                   fbconfig_error->message);
+      g_error_free (fbconfig_error);
+      return FALSE;
+    }
+
+  /* Update the real number of samples_per_pixel now that we have
+   * found an fbconfig... */
+  if (config->samples_per_pixel)
+    {
+      int samples;
+      int status = glx_renderer->glXGetFBConfigAttrib (xlib_renderer->xdpy,
+                                                       fbconfig,
+                                                       GLX_SAMPLES,
+                                                       &samples);
+      g_return_val_if_fail (status == Success, TRUE);
+      cogl_framebuffer_update_samples_per_pixel (framebuffer, samples);
+    }
+
+  /* FIXME: We need to explicitly Select for ConfigureNotify events.
+   * We need to document that for windows we create then toolkits
+   * must be careful not to clear event mask bits that we select.
+   */
+    {
+      int width;
+      int height;
+      CoglXlibTrapState state;
+      XVisualInfo *xvisinfo;
+      XSetWindowAttributes xattr;
+      unsigned long mask;
+      int xerror;
+
+      width = cogl_framebuffer_get_width (framebuffer);
+      height = cogl_framebuffer_get_height (framebuffer);
+
+      _cogl_xlib_renderer_trap_errors (display->renderer, &state);
+
+      xvisinfo = glx_renderer->glXGetVisualFromFBConfig (xlib_renderer->xdpy,
+                                                         fbconfig);
+      if (xvisinfo == NULL)
+        {
+          g_set_error_literal (error, COGL_WINSYS_ERROR,
+                               COGL_WINSYS_ERROR_CREATE_ONSCREEN,
+                               "Unable to retrieve the X11 visual of context's "
+                               "fbconfig");
+          return FALSE;
+        }
+
+      /* window attributes */
+      xattr.background_pixel = WhitePixel (xlib_renderer->xdpy,
+                                           DefaultScreen (xlib_renderer->xdpy));
+      xattr.border_pixel = 0;
+      /* XXX: is this an X resource that we are leaking‽... */
+      xattr.colormap = XCreateColormap (xlib_renderer->xdpy,
+                                        DefaultRootWindow (xlib_renderer->xdpy),
+                                        xvisinfo->visual,
+                                        AllocNone);
+      xattr.event_mask = COGL_ONSCREEN_X11_EVENT_MASK;
+
+      mask = CWBorderPixel | CWColormap | CWEventMask;
+
+      xwin = XCreateWindow (xlib_renderer->xdpy,
+                            DefaultRootWindow (xlib_renderer->xdpy),
+                            0, 0,
+                            width, height,
+                            0,
+                            xvisinfo->depth,
+                            InputOutput,
+                            xvisinfo->visual,
+                            mask, &xattr);
+
+      XFree (xvisinfo);
+
+      XSync (xlib_renderer->xdpy, False);
+      xerror = _cogl_xlib_renderer_untrap_errors (display->renderer, &state);
+      if (xerror)
+        {
+          char message[1000];
+          XGetErrorText (xlib_renderer->xdpy, xerror,
+                         message, sizeof (message));
+          g_set_error (error, COGL_WINSYS_ERROR,
+                       COGL_WINSYS_ERROR_CREATE_ONSCREEN,
+                       "X error while creating Window for CoglOnscreen: %s",
+                       message);
+          return FALSE;
+        }
+    }
+
+  winsys = g_slice_new0 (CoglOnscreenGLX);
+  cogl_onscreen_set_winsys (onscreen, winsys);
+  glx_onscreen = cogl_onscreen_get_winsys (onscreen);
+
+  glx_onscreen->xwin = xwin;
+
+  /* Try and create a GLXWindow to use with extensions dependent on
+   * GLX versions >= 1.3 that don't accept regular X Windows as GLX
+   * drawables. */
+  if (glx_renderer->glx_major == 1 && glx_renderer->glx_minor >= 3)
+    {
+      glx_onscreen->glxwin =
+        glx_renderer->glXCreateWindow (xlib_renderer->xdpy,
+                                       fbconfig,
+                                       glx_onscreen->xwin,
+                                       NULL);
+    }
+
+#ifdef GLX_INTEL_swap_event
+  if (_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT))
+    {
+      GLXDrawable drawable =
+        glx_onscreen->glxwin ? glx_onscreen->glxwin : glx_onscreen->xwin;
+
+      /* similarly to above, we unconditionally select this event
+       * because we rely on it to advance the master clock, and
+       * drive redraw/relayout, animations and event handling.
+       */
+      glx_renderer->glXSelectEvent (xlib_renderer->xdpy,
+                                    drawable,
+                                    GLX_BUFFER_SWAP_COMPLETE_INTEL_MASK);
+    }
+#endif /* GLX_INTEL_swap_event */
+
+  return TRUE;
+}
+
+void
+_cogl_winsys_onscreen_glx_deinit (CoglOnscreen *onscreen)
+{
+  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
+  CoglContext *context = cogl_framebuffer_get_context (framebuffer);
+  CoglGLXDisplay *glx_display = context->display->winsys;
+  CoglXlibRenderer *xlib_renderer =
+    _cogl_xlib_renderer_get_data (context->display->renderer);
+  CoglGLXRenderer *glx_renderer = context->display->renderer->winsys;
+  CoglXlibTrapState old_state;
+  CoglOnscreenGLX *glx_onscreen = cogl_onscreen_get_winsys (onscreen);
+  GLXDrawable drawable;
+
+  /* If we never successfully allocated then there's nothing to do */
+  if (glx_onscreen == NULL)
+    return;
+
+  cogl_clear_object (&glx_onscreen->output);
+
+  _cogl_xlib_renderer_trap_errors (context->display->renderer, &old_state);
+
+  drawable =
+    glx_onscreen->glxwin == None ? glx_onscreen->xwin : glx_onscreen->glxwin;
+
+  /* Cogl always needs a valid context bound to something so if we are
+   * destroying the onscreen that is currently bound we'll switch back
+   * to the dummy drawable. Although the documentation for
+   * glXDestroyWindow states that a currently bound window won't
+   * actually be destroyed until it is unbound, it looks like this
+   * doesn't work if the X window itself is destroyed */
+  if (drawable == cogl_context_glx_get_current_drawable (context))
+    {
+      GLXDrawable dummy_drawable = (glx_display->dummy_glxwin == None ?
+                                    glx_display->dummy_xwin :
+                                    glx_display->dummy_glxwin);
+
+      glx_renderer->glXMakeContextCurrent (xlib_renderer->xdpy,
+                                           dummy_drawable,
+                                           dummy_drawable,
+                                           glx_display->glx_context);
+      cogl_context_glx_set_current_drawable (context, dummy_drawable);
+    }
+
+  if (glx_onscreen->glxwin != None)
+    {
+      glx_renderer->glXDestroyWindow (xlib_renderer->xdpy,
+                                      glx_onscreen->glxwin);
+      glx_onscreen->glxwin = None;
+    }
+
+  if (glx_onscreen->xwin != None)
+    {
+      XDestroyWindow (xlib_renderer->xdpy, glx_onscreen->xwin);
+      glx_onscreen->xwin = None;
+    }
+  else
+    {
+      glx_onscreen->xwin = None;
+    }
+
+  XSync (xlib_renderer->xdpy, False);
+
+  _cogl_xlib_renderer_untrap_errors (context->display->renderer, &old_state);
+
+  g_slice_free (CoglOnscreenGLX, cogl_onscreen_get_winsys (onscreen));
+  cogl_onscreen_set_winsys (onscreen, NULL);
+}
+
+void
+_cogl_winsys_onscreen_glx_bind (CoglOnscreen *onscreen)
+{
+  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
+  CoglContext *context = cogl_framebuffer_get_context (framebuffer);
+  CoglGLXDisplay *glx_display = context->display->winsys;
+  CoglXlibRenderer *xlib_renderer =
+    _cogl_xlib_renderer_get_data (context->display->renderer);
+  CoglGLXRenderer *glx_renderer = context->display->renderer->winsys;
+  CoglOnscreenGLX *glx_onscreen = cogl_onscreen_get_winsys (onscreen);
+  CoglXlibTrapState old_state;
+  GLXDrawable drawable;
+
+  drawable =
+    glx_onscreen->glxwin ? glx_onscreen->glxwin : glx_onscreen->xwin;
+
+  if (cogl_context_glx_get_current_drawable (context) == drawable)
+    return;
+
+  _cogl_xlib_renderer_trap_errors (context->display->renderer, &old_state);
+
+  COGL_NOTE (WINSYS,
+             "MakeContextCurrent dpy: %p, window: 0x%x, context: %p",
+             xlib_renderer->xdpy,
+             (unsigned int) drawable,
+             glx_display->glx_context);
+
+  glx_renderer->glXMakeContextCurrent (xlib_renderer->xdpy,
+                                       drawable,
+                                       drawable,
+                                       glx_display->glx_context);
+
+  /* In case we are using GLX_SGI_swap_control for vblank syncing
+   * we need call glXSwapIntervalSGI here to make sure that it
+   * affects the current drawable.
+   *
+   * Note: we explicitly set to 0 when we aren't using the swap
+   * interval to synchronize since some drivers have a default
+   * swap interval of 1. Sadly some drivers even ignore requests
+   * to disable the swap interval.
+   *
+   * NB: glXSwapIntervalSGI applies to the context not the
+   * drawable which is why we can't just do this once when the
+   * framebuffer is allocated.
+   *
+   * FIXME: We should check for GLX_EXT_swap_control which allows
+   * per framebuffer swap intervals. GLX_MESA_swap_control also
+   * allows per-framebuffer swap intervals but the semantics tend
+   * to be more muddled since Mesa drivers tend to expose both the
+   * MESA and SGI extensions which should technically be mutually
+   * exclusive.
+   */
+  if (glx_renderer->glXSwapInterval)
+    glx_renderer->glXSwapInterval (1);
+
+  XSync (xlib_renderer->xdpy, False);
+
+  /* FIXME: We should be reporting a GError here */
+  if (_cogl_xlib_renderer_untrap_errors (context->display->renderer,
+                                         &old_state))
+    {
+      g_warning ("X Error received while making drawable 0x%08lX current",
+                 drawable);
+      return;
+    }
+
+  cogl_context_glx_set_current_drawable (context, drawable);
+}
+
+static void
+_cogl_winsys_wait_for_gpu (CoglOnscreen *onscreen)
+{
+  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
+  CoglContext *ctx = cogl_framebuffer_get_context (framebuffer);
+
+  ctx->glFinish ();
+}
+
+static int64_t
+get_monotonic_time_ns (void)
+{
+  struct timespec ts;
+
+  clock_gettime (CLOCK_MONOTONIC, &ts);
+  return ts.tv_sec * G_GINT64_CONSTANT (1000000000) + ts.tv_nsec;
+}
+
+static void
+ensure_ust_type (CoglRenderer *renderer,
+                 GLXDrawable   drawable)
+{
+  CoglGLXRenderer *glx_renderer =  renderer->winsys;
+  CoglXlibRenderer *xlib_renderer = _cogl_xlib_renderer_get_data (renderer);
+  int64_t ust;
+  int64_t msc;
+  int64_t sbc;
+  struct timeval tv;
+  int64_t current_system_time;
+  int64_t current_monotonic_time;
+
+  if (glx_renderer->ust_type != COGL_GLX_UST_IS_UNKNOWN)
+    return;
+
+  glx_renderer->ust_type = COGL_GLX_UST_IS_OTHER;
+
+  if (glx_renderer->glXGetSyncValues == NULL)
+    goto out;
+
+  if (!glx_renderer->glXGetSyncValues (xlib_renderer->xdpy, drawable,
+                                       &ust, &msc, &sbc))
+    goto out;
+
+  /* This is the time source that existing (buggy) linux drm drivers
+   * use */
+  gettimeofday (&tv, NULL);
+  current_system_time = (tv.tv_sec * G_GINT64_CONSTANT (1000000)) + tv.tv_usec;
+
+  if (current_system_time > ust - 1000000 &&
+      current_system_time < ust + 1000000)
+    {
+      glx_renderer->ust_type = COGL_GLX_UST_IS_GETTIMEOFDAY;
+      goto out;
+    }
+
+  /* This is the time source that the newer (fixed) linux drm
+   * drivers use (Linux >= 3.8) */
+  current_monotonic_time = get_monotonic_time_ns () / 1000;
+
+  if (current_monotonic_time > ust - 1000000 &&
+      current_monotonic_time < ust + 1000000)
+    {
+      glx_renderer->ust_type = COGL_GLX_UST_IS_MONOTONIC_TIME;
+      goto out;
+    }
+
+ out:
+  COGL_NOTE (WINSYS, "Classified OML system time as: %s",
+             glx_renderer->ust_type == COGL_GLX_UST_IS_GETTIMEOFDAY ? "gettimeofday" :
+             (glx_renderer->ust_type == COGL_GLX_UST_IS_MONOTONIC_TIME ? "monotonic" :
+              "other"));
+  return;
+}
+
+static int64_t
+ust_to_nanoseconds (CoglRenderer *renderer,
+                    GLXDrawable   drawable,
+                    int64_t       ust)
+{
+  CoglGLXRenderer *glx_renderer =  renderer->winsys;
+
+  ensure_ust_type (renderer, drawable);
+
+  switch (glx_renderer->ust_type)
+    {
+    case COGL_GLX_UST_IS_UNKNOWN:
+      g_assert_not_reached ();
+      break;
+    case COGL_GLX_UST_IS_GETTIMEOFDAY:
+    case COGL_GLX_UST_IS_MONOTONIC_TIME:
+      return 1000 * ust;
+    case COGL_GLX_UST_IS_OTHER:
+      /* In this case the scale of UST is undefined so we can't easily
+       * scale to nanoseconds.
+       *
+       * For example the driver may be reporting the rdtsc CPU counter
+       * as UST values and so the scale would need to be determined
+       * empirically.
+       *
+       * Potentially we could block for a known duration within
+       * ensure_ust_type() to measure the timescale of UST but for now
+       * we just ignore unknown time sources */
+      return 0;
+    }
+
+  return 0;
+}
+
+static void
+_cogl_winsys_wait_for_vblank (CoglOnscreen *onscreen)
+{
+  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
+  CoglContext *ctx = cogl_framebuffer_get_context (framebuffer);
+  CoglGLXRenderer *glx_renderer;
+  CoglXlibRenderer *xlib_renderer;
+  CoglGLXDisplay *glx_display;
+
+  glx_renderer = ctx->display->renderer->winsys;
+  xlib_renderer = _cogl_xlib_renderer_get_data (ctx->display->renderer);
+  glx_display = ctx->display->winsys;
+
+  if (glx_display->can_vblank_wait)
+    {
+      CoglFrameInfo *info = cogl_onscreen_peek_tail_frame_info (onscreen);
+
+      if (glx_renderer->glXWaitForMsc)
+        {
+          CoglOnscreenGLX *glx_onscreen = cogl_onscreen_get_winsys (onscreen);
+          Drawable drawable = glx_onscreen->glxwin;
+          int64_t ust;
+          int64_t msc;
+          int64_t sbc;
+
+          glx_renderer->glXWaitForMsc (xlib_renderer->xdpy, drawable,
+                                       0, 1, 0,
+                                       &ust, &msc, &sbc);
+          info->presentation_time = ust_to_nanoseconds (ctx->display->renderer,
+                                                        drawable,
+                                                        ust);
+        }
+      else
+        {
+          uint32_t current_count;
+
+          glx_renderer->glXGetVideoSync (&current_count);
+          glx_renderer->glXWaitVideoSync (2,
+                                          (current_count + 1) % 2,
+                                          &current_count);
+
+          info->presentation_time = get_monotonic_time_ns ();
+        }
+    }
+}
+
+static uint32_t
+_cogl_winsys_get_vsync_counter (CoglContext *ctx)
+{
+  uint32_t video_sync_count;
+  CoglGLXRenderer *glx_renderer;
+
+  glx_renderer = ctx->display->renderer->winsys;
+
+  glx_renderer->glXGetVideoSync (&video_sync_count);
+
+  return video_sync_count;
+}
+
+#ifndef GLX_BACK_BUFFER_AGE_EXT
+#define GLX_BACK_BUFFER_AGE_EXT 0x20F4
+#endif
+
+int
+_cogl_winsys_onscreen_glx_get_buffer_age (CoglOnscreen *onscreen)
+{
+  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
+  CoglContext *context = cogl_framebuffer_get_context (framebuffer);
+  CoglXlibRenderer *xlib_renderer = _cogl_xlib_renderer_get_data (context->display->renderer);
+  CoglGLXRenderer *glx_renderer = context->display->renderer->winsys;
+  CoglOnscreenGLX *glx_onscreen = cogl_onscreen_get_winsys (onscreen);
+  GLXDrawable drawable;
+  unsigned int age;
+
+  if (!_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_BUFFER_AGE))
+    return 0;
+
+  drawable = glx_onscreen->glxwin ? glx_onscreen->glxwin : glx_onscreen->xwin;
+  glx_renderer->glXQueryDrawable (xlib_renderer->xdpy, drawable, GLX_BACK_BUFFER_AGE_EXT, &age);
+
+  return age;
+}
+
+static void
+set_frame_info_output (CoglOnscreen *onscreen,
+                       CoglOutput   *output)
+{
+  CoglFrameInfo *info = cogl_onscreen_peek_tail_frame_info (onscreen);
+
+  if (output)
+    {
+      float refresh_rate = cogl_output_get_refresh_rate (output);
+      if (refresh_rate != 0.0)
+        info->refresh_rate = refresh_rate;
+    }
+}
+
+static void
+cogl_onscreen_glx_flush_notification (CoglOnscreen *onscreen)
+{
+  CoglOnscreenGLX *glx_onscreen = cogl_onscreen_get_winsys (onscreen);
+
+  while (glx_onscreen->pending_sync_notify > 0 ||
+         glx_onscreen->pending_complete_notify > 0 ||
+         glx_onscreen->pending_resize_notify > 0)
+    {
+      if (glx_onscreen->pending_sync_notify > 0)
+        {
+          CoglFrameInfo *info;
+
+          info = cogl_onscreen_peek_head_frame_info (onscreen);
+          _cogl_onscreen_notify_frame_sync (onscreen, info);
+          glx_onscreen->pending_sync_notify--;
+        }
+
+      if (glx_onscreen->pending_complete_notify > 0)
+        {
+          CoglFrameInfo *info;
+
+          info = cogl_onscreen_pop_head_frame_info (onscreen);
+          _cogl_onscreen_notify_complete (onscreen, info);
+          cogl_object_unref (info);
+          glx_onscreen->pending_complete_notify--;
+        }
+
+      if (glx_onscreen->pending_resize_notify > 0)
+        {
+          _cogl_onscreen_notify_resize (onscreen);
+          glx_onscreen->pending_resize_notify--;
+        }
+    }
+}
+
+static void
+flush_pending_notifications_cb (void *data,
+                                void *user_data)
+{
+  CoglFramebuffer *framebuffer = data;
+
+  if (COGL_IS_ONSCREEN (framebuffer))
+    {
+      CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
+
+      cogl_onscreen_glx_flush_notification (onscreen);
+    }
+}
+
+static void
+flush_pending_notifications_idle (void *user_data)
+{
+  CoglContext *context = user_data;
+  CoglRenderer *renderer = context->display->renderer;
+  CoglGLXRenderer *glx_renderer = renderer->winsys;
+
+  /* This needs to be disconnected before invoking the callbacks in
+   * case the callbacks cause it to be queued again */
+  _cogl_closure_disconnect (glx_renderer->flush_notifications_idle);
+  glx_renderer->flush_notifications_idle = NULL;
+
+  g_list_foreach (context->framebuffers,
+                  flush_pending_notifications_cb,
+                  NULL);
+}
+
+static void
+set_sync_pending (CoglOnscreen *onscreen)
+{
+  CoglOnscreenGLX *glx_onscreen = cogl_onscreen_get_winsys (onscreen);
+  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
+  CoglContext *context = cogl_framebuffer_get_context (framebuffer);
+  CoglRenderer *renderer = context->display->renderer;
+  CoglGLXRenderer *glx_renderer = renderer->winsys;
+
+  /* We only want to dispatch sync events when the application calls
+   * cogl_context_dispatch so instead of immediately notifying we
+   * queue an idle callback */
+  if (!glx_renderer->flush_notifications_idle)
+    {
+      glx_renderer->flush_notifications_idle =
+        _cogl_poll_renderer_add_idle (renderer,
+                                      flush_pending_notifications_idle,
+                                      context,
+                                      NULL);
+    }
+
+  glx_onscreen->pending_sync_notify++;
+}
+
+static void
+set_complete_pending (CoglOnscreen *onscreen)
+{
+  CoglOnscreenGLX *glx_onscreen = cogl_onscreen_get_winsys (onscreen);
+  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
+  CoglContext *context = cogl_framebuffer_get_context (framebuffer);
+  CoglRenderer *renderer = context->display->renderer;
+  CoglGLXRenderer *glx_renderer = renderer->winsys;
+
+  /* We only want to notify swap completion when the application calls
+   * cogl_context_dispatch so instead of immediately notifying we
+   * queue an idle callback */
+  if (!glx_renderer->flush_notifications_idle)
+    {
+      glx_renderer->flush_notifications_idle =
+        _cogl_poll_renderer_add_idle (renderer,
+                                      flush_pending_notifications_idle,
+                                      context,
+                                      NULL);
+    }
+
+  glx_onscreen->pending_complete_notify++;
+}
+
+void
+_cogl_winsys_onscreen_glx_swap_region (CoglOnscreen  *onscreen,
+                                       const int     *user_rectangles,
+                                       int            n_rectangles,
+                                       CoglFrameInfo *info,
+                                       gpointer       user_data)
+{
+  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
+  CoglContext *context = cogl_framebuffer_get_context (framebuffer);
+  CoglXlibRenderer *xlib_renderer =
+    _cogl_xlib_renderer_get_data (context->display->renderer);
+  CoglGLXRenderer *glx_renderer = context->display->renderer->winsys;
+  CoglGLXDisplay *glx_display = context->display->winsys;
+  CoglOnscreenGLX *glx_onscreen = cogl_onscreen_get_winsys (onscreen);
+  uint32_t end_frame_vsync_counter = 0;
+  gboolean have_counter;
+  gboolean can_wait;
+  int x_min = 0, x_max = 0, y_min = 0, y_max = 0;
+
+  /*
+   * We assume that glXCopySubBuffer is synchronized which means it won't prevent multiple
+   * blits per retrace if they can all be performed in the blanking period. If that's the
+   * case then we still want to use the vblank sync menchanism but
+   * we only need it to throttle redraws.
+   */
+  gboolean blit_sub_buffer_is_synchronized =
+     _cogl_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_REGION_SYNCHRONIZED);
+
+  int framebuffer_width =  cogl_framebuffer_get_width (framebuffer);
+  int framebuffer_height =  cogl_framebuffer_get_height (framebuffer);
+  int *rectangles = g_alloca (sizeof (int) * n_rectangles * 4);
+  int i;
+
+  /* glXCopySubBuffer expects rectangles relative to the bottom left corner but
+   * we are given rectangles relative to the top left so we need to flip
+   * them... */
+  memcpy (rectangles, user_rectangles, sizeof (int) * n_rectangles * 4);
+  for (i = 0; i < n_rectangles; i++)
+    {
+      int *rect = &rectangles[4 * i];
+
+      if (i == 0)
+        {
+          x_min = rect[0];
+          x_max = rect[0] + rect[2];
+          y_min = rect[1];
+          y_max = rect[1] + rect[3];
+        }
+      else
+        {
+          x_min = MIN (x_min, rect[0]);
+          x_max = MAX (x_max, rect[0] + rect[2]);
+          y_min = MIN (y_min, rect[1]);
+          y_max = MAX (y_max, rect[1] + rect[3]);
+        }
+
+      rect[1] = framebuffer_height - rect[1] - rect[3];
+
+    }
+
+  _cogl_framebuffer_flush_state (framebuffer,
+                                 framebuffer,
+                                 COGL_FRAMEBUFFER_STATE_BIND);
+
+  have_counter = glx_display->have_vblank_counter;
+  can_wait = glx_display->can_vblank_wait;
+
+  /* We need to ensure that all the rendering is done, otherwise
+   * redraw operations that are slower than the framerate can
+   * queue up in the pipeline during a heavy animation, causing a
+   * larger and larger backlog of rendering visible as lag to the
+   * user.
+   *
+   * For an exaggerated example consider rendering at 60fps (so 16ms
+   * per frame) and you have a really slow frame that takes 160ms to
+   * render, even though painting the scene and issuing the commands
+   * to the GPU takes no time at all. If all we did was use the
+   * video_sync extension to throttle the painting done by the CPU
+   * then every 16ms we would have another frame queued up even though
+   * the GPU has only rendered one tenth of the current frame. By the
+   * time the GPU would get to the 2nd frame there would be 9 frames
+   * waiting to be rendered.
+   *
+   * The problem is that we don't currently have a good way to throttle
+   * the GPU, only the CPU so we have to resort to synchronizing the
+   * GPU with the CPU to throttle it.
+   *
+   * Note: since calling glFinish() and synchronizing the CPU with
+   * the GPU is far from ideal, we hope that this is only a short
+   * term solution.
+   * - One idea is to using sync objects to track render
+   *   completion so we can throttle the backlog (ideally with an
+   *   additional extension that lets us get notifications in our
+   *   mainloop instead of having to busy wait for the
+   *   completion.)
+   * - Another option is to support clipped redraws by reusing the
+   *   contents of old back buffers such that we can flip instead
+   *   of using a blit and then we can use GLX_INTEL_swap_events
+   *   to throttle. For this though we would still probably want an
+   *   additional extension so we can report the limited region of
+   *   the window damage to X/compositors.
+   */
+  _cogl_winsys_wait_for_gpu (onscreen);
+
+  if (blit_sub_buffer_is_synchronized && have_counter && can_wait)
+    {
+      end_frame_vsync_counter = _cogl_winsys_get_vsync_counter (context);
+
+      /* If we have the GLX_SGI_video_sync extension then we can
+       * be a bit smarter about how we throttle blits by avoiding
+       * any waits if we can see that the video sync count has
+       * already progressed. */
+      if (glx_onscreen->last_swap_vsync_counter == end_frame_vsync_counter)
+        _cogl_winsys_wait_for_vblank (onscreen);
+    }
+  else if (can_wait)
+    _cogl_winsys_wait_for_vblank (onscreen);
+
+  if (glx_renderer->glXCopySubBuffer)
+    {
+      Display *xdpy = xlib_renderer->xdpy;
+      GLXDrawable drawable;
+
+      drawable =
+        glx_onscreen->glxwin ? glx_onscreen->glxwin : glx_onscreen->xwin;
+      int i;
+      for (i = 0; i < n_rectangles; i++)
+        {
+          int *rect = &rectangles[4 * i];
+          glx_renderer->glXCopySubBuffer (xdpy, drawable,
+                                          rect[0], rect[1], rect[2], rect[3]);
+        }
+    }
+  else if (context->glBlitFramebuffer)
+    {
+      int i;
+      /* XXX: checkout how this state interacts with the code to use
+       * glBlitFramebuffer in Neil's texture atlasing branch */
+
+      /* glBlitFramebuffer is affected by the scissor so we need to
+       * ensure we have flushed an empty clip stack to get rid of it.
+       * We also mark that the clip state is dirty so that it will be
+       * flushed to the correct state the next time something is
+       * drawn */
+      _cogl_clip_stack_flush (NULL, framebuffer);
+      context->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_CLIP;
+
+      context->glDrawBuffer (GL_FRONT);
+      for (i = 0; i < n_rectangles; i++)
+        {
+          int *rect = &rectangles[4 * i];
+          int x2 = rect[0] + rect[2];
+          int y2 = rect[1] + rect[3];
+          context->glBlitFramebuffer (rect[0], rect[1], x2, y2,
+                                      rect[0], rect[1], x2, y2,
+                                      GL_COLOR_BUFFER_BIT, GL_NEAREST);
+        }
+      context->glDrawBuffer (context->current_gl_draw_buffer);
+    }
+
+  /* NB: unlike glXSwapBuffers, glXCopySubBuffer and
+   * glBlitFramebuffer don't issue an implicit glFlush() so we
+   * have to flush ourselves if we want the request to complete in
+   * a finite amount of time since otherwise the driver can batch
+   * the command indefinitely. */
+  context->glFlush ();
+
+  /* NB: It's important we save the counter we read before acting on
+   * the swap request since if we are mixing and matching different
+   * swap methods between frames we don't want to read the timer e.g.
+   * after calling glFinish() some times and not for others.
+   *
+   * In other words; this way we consistently save the time at the end
+   * of the applications frame such that the counter isn't muddled by
+   * the varying costs of different swap methods.
+   */
+  if (have_counter)
+    glx_onscreen->last_swap_vsync_counter = end_frame_vsync_counter;
+
+  {
+    CoglOutput *output;
+
+    x_min = CLAMP (x_min, 0, framebuffer_width);
+    x_max = CLAMP (x_max, 0, framebuffer_width);
+    y_min = CLAMP (y_min, 0, framebuffer_width);
+    y_max = CLAMP (y_max, 0, framebuffer_height);
+
+    output =
+      _cogl_xlib_renderer_output_for_rectangle (context->display->renderer,
+                                                glx_onscreen->x + x_min,
+                                                glx_onscreen->y + y_min,
+                                                x_max - x_min,
+                                                y_max - y_min);
+
+    set_frame_info_output (onscreen, output);
+  }
+
+  /* XXX: we don't get SwapComplete events based on how we implement
+   * the _swap_region() API but if cogl-onscreen.c knows we are
+   * handling _SYNC and _COMPLETE events in the winsys then we need to
+   * send fake events in this case.
+   */
+  if (_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT))
+    {
+      set_sync_pending (onscreen);
+      set_complete_pending (onscreen);
+    }
+}
+
+void
+_cogl_winsys_onscreen_glx_swap_buffers_with_damage (CoglOnscreen  *onscreen,
+                                                    const int     *rectangles,
+                                                    int            n_rectangles,
+                                                    CoglFrameInfo *info,
+                                                    gpointer       user_data)
+{
+  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
+  CoglContext *context = cogl_framebuffer_get_context (framebuffer);
+  CoglXlibRenderer *xlib_renderer =
+    _cogl_xlib_renderer_get_data (context->display->renderer);
+  CoglGLXRenderer *glx_renderer = context->display->renderer->winsys;
+  CoglGLXDisplay *glx_display = context->display->winsys;
+  CoglOnscreenGLX *glx_onscreen = cogl_onscreen_get_winsys (onscreen);
+  gboolean have_counter;
+  GLXDrawable drawable;
+
+  /* XXX: theoretically this shouldn't be necessary but at least with
+   * the Intel drivers we have see that if we don't call
+   * glXMakeContextCurrent for the drawable we are swapping then
+   * we get a BadDrawable error from the X server. */
+  _cogl_framebuffer_flush_state (framebuffer,
+                                 framebuffer,
+                                 COGL_FRAMEBUFFER_STATE_BIND);
+
+  drawable = glx_onscreen->glxwin ? glx_onscreen->glxwin : glx_onscreen->xwin;
+
+  have_counter = glx_display->have_vblank_counter;
+
+  if (!glx_renderer->glXSwapInterval)
+    {
+      gboolean can_wait = have_counter || glx_display->can_vblank_wait;
+
+      uint32_t end_frame_vsync_counter = 0;
+
+      /* If the swap_region API is also being used then we need to track
+       * the vsync counter for each swap request so we can manually
+       * throttle swap_region requests. */
+      if (have_counter)
+        end_frame_vsync_counter = _cogl_winsys_get_vsync_counter (context);
+
+      /* If we are going to wait for VBLANK manually, we not only
+       * need to flush out pending drawing to the GPU before we
+       * sleep, we need to wait for it to finish. Otherwise, we
+       * may end up with the situation:
+       *
+       *        - We finish drawing      - GPU drawing continues
+       *        - We go to sleep         - GPU drawing continues
+       * VBLANK - We call glXSwapBuffers - GPU drawing continues
+       *                                 - GPU drawing continues
+       *                                 - Swap buffers happens
+       *
+       * Producing a tear. Calling glFinish() first will cause us
+       * to properly wait for the next VBLANK before we swap. This
+       * obviously does not happen when we use _GLX_SWAP and let
+       * the driver do the right thing
+       */
+      _cogl_winsys_wait_for_gpu (onscreen);
+
+      if (have_counter && can_wait)
+        {
+          if (glx_onscreen->last_swap_vsync_counter ==
+              end_frame_vsync_counter)
+            _cogl_winsys_wait_for_vblank (onscreen);
+        }
+      else if (can_wait)
+        _cogl_winsys_wait_for_vblank (onscreen);
+    }
+
+  glx_renderer->glXSwapBuffers (xlib_renderer->xdpy, drawable);
+
+  if (have_counter)
+    glx_onscreen->last_swap_vsync_counter =
+      _cogl_winsys_get_vsync_counter (context);
+
+  set_frame_info_output (onscreen, glx_onscreen->output);
+}
+
+uint32_t
+_cogl_winsys_onscreen_glx_get_window_xid (CoglOnscreen *onscreen)
+{
+  CoglOnscreenGLX *glx_onscreen = cogl_onscreen_get_winsys (onscreen);
+
+  return glx_onscreen->xwin;
+}
+
+void
+_cogl_winsys_onscreen_glx_set_visibility (CoglOnscreen *onscreen,
+                                          gboolean      visibility)
+{
+  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
+  CoglContext *context = cogl_framebuffer_get_context (framebuffer);
+  CoglXlibRenderer *xlib_renderer =
+    _cogl_xlib_renderer_get_data (context->display->renderer);
+  CoglOnscreenGLX *glx_onscreen = cogl_onscreen_get_winsys (onscreen);
+
+  if (visibility)
+    XMapWindow (xlib_renderer->xdpy, glx_onscreen->xwin);
+  else
+    XUnmapWindow (xlib_renderer->xdpy, glx_onscreen->xwin);
+}
+
+void
+_cogl_winsys_onscreen_glx_set_resizable (CoglOnscreen *onscreen,
+                                         gboolean      resizable)
+{
+  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
+  CoglContext *context = cogl_framebuffer_get_context (framebuffer);
+  CoglXlibRenderer *xlib_renderer =
+    _cogl_xlib_renderer_get_data (context->display->renderer);
+  CoglOnscreenGLX *glx_onscreen = cogl_onscreen_get_winsys (onscreen);
+
+  XSizeHints *size_hints = XAllocSizeHints ();
+
+  if (resizable)
+    {
+      /* TODO: Add cogl_onscreen_request_minimum_size () */
+      size_hints->min_width = 1;
+      size_hints->min_height = 1;
+
+      size_hints->max_width = INT_MAX;
+      size_hints->max_height = INT_MAX;
+    }
+  else
+    {
+      int width = cogl_framebuffer_get_width (framebuffer);
+      int height = cogl_framebuffer_get_height (framebuffer);
+
+      size_hints->min_width = width;
+      size_hints->min_height = height;
+
+      size_hints->max_width = width;
+      size_hints->max_height = height;
+    }
+
+  XSetWMNormalHints (xlib_renderer->xdpy, glx_onscreen->xwin, size_hints);
+
+  XFree (size_hints);
+}
+
+void
+cogl_onscreen_glx_notify_swap_buffers (CoglOnscreen          *onscreen,
+                                       GLXBufferSwapComplete *swap_event)
+{
+  CoglOnscreenGLX *glx_onscreen;
+
+  glx_onscreen = cogl_onscreen_get_winsys (onscreen);
+
+  /* We only want to notify that the swap is complete when the
+     application calls cogl_context_dispatch so instead of immediately
+     notifying we'll set a flag to remember to notify later */
+  set_sync_pending (onscreen);
+
+  if (swap_event->ust != 0)
+    {
+      CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
+      CoglContext *context = cogl_framebuffer_get_context (framebuffer);
+      CoglFrameInfo *info;
+
+      info = cogl_onscreen_peek_head_frame_info (onscreen);
+      info->presentation_time =
+        ust_to_nanoseconds (context->display->renderer,
+                            glx_onscreen->glxwin,
+                            swap_event->ust);
+    }
+
+  set_complete_pending (onscreen);
+}
+
+void
+cogl_onscreen_glx_update_output (CoglOnscreen *onscreen)
+{
+  CoglOnscreenGLX *glx_onscreen = cogl_onscreen_get_winsys (onscreen);
+  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
+  CoglContext *context = cogl_framebuffer_get_context (framebuffer);
+  CoglDisplay *display = context->display;
+  CoglOutput *output;
+  int width, height;
+
+  width = cogl_framebuffer_get_width (framebuffer);
+  height = cogl_framebuffer_get_height (framebuffer);
+  output = _cogl_xlib_renderer_output_for_rectangle (display->renderer,
+                                                     glx_onscreen->x,
+                                                     glx_onscreen->y,
+                                                     width, height);
+  if (glx_onscreen->output != output)
+    {
+      if (glx_onscreen->output)
+        cogl_object_unref (glx_onscreen->output);
+
+      glx_onscreen->output = output;
+
+      if (output)
+        cogl_object_ref (glx_onscreen->output);
+    }
+}
+
+void
+cogl_onscreen_glx_resize (CoglOnscreen    *onscreen,
+                          XConfigureEvent *configure_event)
+{
+  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
+  CoglContext *context = cogl_framebuffer_get_context (framebuffer);
+  CoglRenderer *renderer = context->display->renderer;
+  CoglGLXRenderer *glx_renderer = renderer->winsys;
+  CoglOnscreenGLX *glx_onscreen;
+  int x, y;
+
+  glx_onscreen = cogl_onscreen_get_winsys (onscreen);
+
+  _cogl_framebuffer_winsys_update_size (framebuffer,
+                                        configure_event->width,
+                                        configure_event->height);
+
+  /* We only want to notify that a resize happened when the
+   * application calls cogl_context_dispatch so instead of immediately
+   * notifying we queue an idle callback */
+  if (!glx_renderer->flush_notifications_idle)
+    {
+      glx_renderer->flush_notifications_idle =
+        _cogl_poll_renderer_add_idle (renderer,
+                                      flush_pending_notifications_idle,
+                                      context,
+                                      NULL);
+    }
+
+  glx_onscreen->pending_resize_notify++;
+
+  if (configure_event->send_event)
+    {
+      x = configure_event->x;
+      y = configure_event->y;
+    }
+  else
+    {
+      Window child;
+      XTranslateCoordinates (configure_event->display,
+                             configure_event->window,
+                             DefaultRootWindow (configure_event->display),
+                             0, 0, &x, &y, &child);
+    }
+
+  glx_onscreen->x = x;
+  glx_onscreen->y = y;
+
+  cogl_onscreen_glx_update_output (onscreen);
+}
+
+gboolean
+cogl_onscreen_glx_is_for_window (CoglOnscreen *onscreen,
+                                 Window        window)
+{
+  CoglOnscreenGLX *onscreen_glx = cogl_onscreen_get_winsys (onscreen);
+
+  return onscreen_glx->xwin == window;
+}
diff --git a/cogl/cogl/winsys/cogl-onscreen-glx.h b/cogl/cogl/winsys/cogl-onscreen-glx.h
new file mode 100644
index 0000000000..e218a6a964
--- /dev/null
+++ b/cogl/cogl/winsys/cogl-onscreen-glx.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2007,2008,2009,2010,2011,2013 Intel Corporation.
+ * Copyright (C) 2020 Red Hat
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef COGL_ONSCREEN_GLX_H
+#define COGL_ONSCREEN_GLX_H
+
+#include <GL/glx.h>
+#include <X11/Xlib.h>
+
+#include "cogl-onscreen.h"
+
+gboolean
+_cogl_winsys_onscreen_glx_init (CoglOnscreen  *onscreen,
+                                GError       **error);
+
+void
+_cogl_winsys_onscreen_glx_deinit (CoglOnscreen *onscreen);
+
+void
+_cogl_winsys_onscreen_glx_bind (CoglOnscreen *onscreen);
+
+int
+_cogl_winsys_onscreen_glx_get_buffer_age (CoglOnscreen *onscreen);
+
+void
+_cogl_winsys_onscreen_glx_swap_region (CoglOnscreen  *onscreen,
+                                       const int     *user_rectangles,
+                                       int            n_rectangles,
+                                       CoglFrameInfo *info,
+                                       gpointer       user_data);
+
+void
+_cogl_winsys_onscreen_glx_swap_buffers_with_damage (CoglOnscreen  *onscreen,
+                                                    const int     *rectangles,
+                                                    int            n_rectangles,
+                                                    CoglFrameInfo *info,
+                                                    gpointer       user_data);
+
+uint32_t
+_cogl_winsys_onscreen_glx_get_window_xid (CoglOnscreen *onscreen);
+
+void
+_cogl_winsys_onscreen_glx_set_visibility (CoglOnscreen *onscreen,
+                                          gboolean      visibility);
+
+void
+_cogl_winsys_onscreen_glx_set_resizable (CoglOnscreen *onscreen,
+                                         gboolean      resizable);
+
+void
+cogl_onscreen_glx_resize (CoglOnscreen    *onscreen,
+                          XConfigureEvent *configure_event);
+
+void
+cogl_onscreen_glx_update_output (CoglOnscreen *onscreen);
+
+void
+cogl_onscreen_glx_notify_swap_buffers (CoglOnscreen          *onscreen,
+                                       GLXBufferSwapComplete *swap_event);
+
+gboolean
+cogl_onscreen_glx_is_for_window (CoglOnscreen *onscreen,
+                                 Window        window);
+
+#endif /* COGL_ONSCREEN_GLX_H */
diff --git a/cogl/cogl/winsys/cogl-winsys-glx-private.h b/cogl/cogl/winsys/cogl-winsys-glx-private.h
index 15e7f988d3..7151a8efeb 100644
--- a/cogl/cogl/winsys/cogl-winsys-glx-private.h
+++ b/cogl/cogl/winsys/cogl-winsys-glx-private.h
@@ -34,4 +34,17 @@
 COGL_EXPORT const CoglWinsysVtable *
 _cogl_winsys_glx_get_vtable (void);
 
+gboolean
+cogl_display_glx_find_fbconfig (CoglDisplay                  *display,
+                                const CoglFramebufferConfig  *config,
+                                GLXFBConfig                  *config_ret,
+                                GError                      **error);
+
+void
+cogl_context_glx_set_current_drawable (CoglContext *context,
+                                       GLXDrawable  drawable);
+
+GLXDrawable
+cogl_context_glx_get_current_drawable (CoglContext *context);
+
 #endif /* __COGL_WINSYS_GLX_PRIVATE_H */
diff --git a/cogl/cogl/winsys/cogl-winsys-glx.c b/cogl/cogl/winsys/cogl-winsys-glx.c
index 8e15dee001..87867aed4e 100644
--- a/cogl/cogl/winsys/cogl-winsys-glx.c
+++ b/cogl/cogl/winsys/cogl-winsys-glx.c
@@ -54,6 +54,7 @@
 #include "cogl-version.h"
 #include "cogl-glx.h"
 #include "driver/gl/cogl-pipeline-opengl-private.h"
+#include "winsys/cogl-onscreen-glx.h"
 #include "winsys/cogl-winsys-private.h"
 #include "winsys/cogl-winsys-glx-private.h"
 
@@ -76,27 +77,15 @@
 #define GLX_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV 0x20F7
 #endif
 
-#define COGL_ONSCREEN_X11_EVENT_MASK (StructureNotifyMask | ExposureMask)
 #define MAX_GLX_CONFIG_ATTRIBS 30
 
+typedef struct _CoglOnscreenGLX CoglOnscreenGLX;
+
 typedef struct _CoglContextGLX
 {
   GLXDrawable current_drawable;
 } CoglContextGLX;
 
-typedef struct _CoglOnscreenGLX
-{
-  Window xwin;
-  int x, y;
-  CoglOutput *output;
-
-  GLXDrawable glxwin;
-  uint32_t last_swap_vsync_counter;
-  uint32_t pending_sync_notify;
-  uint32_t pending_complete_notify;
-  uint32_t pending_resize_notify;
-} CoglOnscreenGLX;
-
 typedef struct _CoglPixmapTextureEyeGLX
 {
   CoglTexture *glx_tex;
@@ -172,15 +161,17 @@ find_onscreen_for_xid (CoglContext *context, uint32_t xid)
   for (l = context->framebuffers; l; l = l->next)
     {
       CoglFramebuffer *framebuffer = l->data;
+      CoglOnscreen *onscreen;
       CoglOnscreenGLX *onscreen_glx;
 
       if (!COGL_IS_ONSCREEN (framebuffer))
         continue;
 
-      /* Does the GLXEvent have the GLXDrawable or the X Window? */
-      onscreen_glx = cogl_onscreen_get_winsys (COGL_ONSCREEN (framebuffer));
-      if (onscreen_glx && onscreen_glx->xwin == (Window)xid)
-        return COGL_ONSCREEN (framebuffer);
+      onscreen = COGL_ONSCREEN (framebuffer);
+      onscreen_glx = cogl_onscreen_get_winsys (onscreen);
+      if (onscreen_glx &&
+          cogl_onscreen_glx_is_for_window (onscreen, (Window) xid))
+        return onscreen;
     }
 
   return NULL;
@@ -195,96 +186,6 @@ get_monotonic_time_ns (void)
   return ts.tv_sec * G_GINT64_CONSTANT (1000000000) + ts.tv_nsec;
 }
 
-static void
-ensure_ust_type (CoglRenderer *renderer,
-                 GLXDrawable drawable)
-{
-  CoglGLXRenderer *glx_renderer =  renderer->winsys;
-  CoglXlibRenderer *xlib_renderer = _cogl_xlib_renderer_get_data (renderer);
-  int64_t ust;
-  int64_t msc;
-  int64_t sbc;
-  struct timeval tv;
-  int64_t current_system_time;
-  int64_t current_monotonic_time;
-
-  if (glx_renderer->ust_type != COGL_GLX_UST_IS_UNKNOWN)
-    return;
-
-  glx_renderer->ust_type = COGL_GLX_UST_IS_OTHER;
-
-  if (glx_renderer->glXGetSyncValues == NULL)
-    goto out;
-
-  if (!glx_renderer->glXGetSyncValues (xlib_renderer->xdpy, drawable,
-                                       &ust, &msc, &sbc))
-    goto out;
-
-  /* This is the time source that existing (buggy) linux drm drivers
-   * use */
-  gettimeofday (&tv, NULL);
-  current_system_time = (tv.tv_sec * G_GINT64_CONSTANT (1000000)) + tv.tv_usec;
-
-  if (current_system_time > ust - 1000000 &&
-      current_system_time < ust + 1000000)
-    {
-      glx_renderer->ust_type = COGL_GLX_UST_IS_GETTIMEOFDAY;
-      goto out;
-    }
-
-  /* This is the time source that the newer (fixed) linux drm
-   * drivers use (Linux >= 3.8) */
-  current_monotonic_time = get_monotonic_time_ns () / 1000;
-
-  if (current_monotonic_time > ust - 1000000 &&
-      current_monotonic_time < ust + 1000000)
-    {
-      glx_renderer->ust_type = COGL_GLX_UST_IS_MONOTONIC_TIME;
-      goto out;
-    }
-
- out:
-  COGL_NOTE (WINSYS, "Classified OML system time as: %s",
-             glx_renderer->ust_type == COGL_GLX_UST_IS_GETTIMEOFDAY ? "gettimeofday" :
-             (glx_renderer->ust_type == COGL_GLX_UST_IS_MONOTONIC_TIME ? "monotonic" :
-              "other"));
-  return;
-}
-
-static int64_t
-ust_to_nanoseconds (CoglRenderer *renderer,
-                    GLXDrawable drawable,
-                    int64_t ust)
-{
-  CoglGLXRenderer *glx_renderer =  renderer->winsys;
-
-  ensure_ust_type (renderer, drawable);
-
-  switch (glx_renderer->ust_type)
-    {
-    case COGL_GLX_UST_IS_UNKNOWN:
-      g_assert_not_reached ();
-      break;
-    case COGL_GLX_UST_IS_GETTIMEOFDAY:
-    case COGL_GLX_UST_IS_MONOTONIC_TIME:
-      return 1000 * ust;
-    case COGL_GLX_UST_IS_OTHER:
-      /* In this case the scale of UST is undefined so we can't easily
-       * scale to nanoseconds.
-       *
-       * For example the driver may be reporting the rdtsc CPU counter
-       * as UST values and so the scale would need to be determined
-       * empirically.
-       *
-       * Potentially we could block for a known duration within
-       * ensure_ust_type() to measure the timescale of UST but for now
-       * we just ignore unknown time sources */
-      return 0;
-    }
-
-  return 0;
-}
-
 static int64_t
 _cogl_winsys_get_clock_time (CoglContext *context)
 {
@@ -321,226 +222,28 @@ _cogl_winsys_get_clock_time (CoglContext *context)
   return 0;
 }
 
-static void
-flush_pending_notifications_cb (void *data,
-                                void *user_data)
-{
-  CoglFramebuffer *framebuffer = data;
-
-  if (COGL_IS_ONSCREEN (framebuffer))
-    {
-      CoglOnscreen *onscreen = COGL_ONSCREEN (framebuffer);
-      CoglOnscreenGLX *glx_onscreen = cogl_onscreen_get_winsys (onscreen);
-
-      while (glx_onscreen->pending_sync_notify > 0 ||
-             glx_onscreen->pending_complete_notify > 0 ||
-             glx_onscreen->pending_resize_notify > 0)
-        {
-          if (glx_onscreen->pending_sync_notify > 0)
-            {
-              CoglFrameInfo *info;
-
-              info = cogl_onscreen_peek_head_frame_info (onscreen);
-              _cogl_onscreen_notify_frame_sync (onscreen, info);
-              glx_onscreen->pending_sync_notify--;
-            }
-
-          if (glx_onscreen->pending_complete_notify > 0)
-            {
-              CoglFrameInfo *info;
-
-              info = cogl_onscreen_pop_head_frame_info (onscreen);
-              _cogl_onscreen_notify_complete (onscreen, info);
-              cogl_object_unref (info);
-              glx_onscreen->pending_complete_notify--;
-            }
-
-          if (glx_onscreen->pending_resize_notify > 0)
-            {
-              _cogl_onscreen_notify_resize (onscreen);
-              glx_onscreen->pending_resize_notify--;
-            }
-        }
-    }
-}
-
-static void
-flush_pending_notifications_idle (void *user_data)
-{
-  CoglContext *context = user_data;
-  CoglRenderer *renderer = context->display->renderer;
-  CoglGLXRenderer *glx_renderer = renderer->winsys;
-
-  /* This needs to be disconnected before invoking the callbacks in
-   * case the callbacks cause it to be queued again */
-  _cogl_closure_disconnect (glx_renderer->flush_notifications_idle);
-  glx_renderer->flush_notifications_idle = NULL;
-
-  g_list_foreach (context->framebuffers,
-                  flush_pending_notifications_cb,
-                  NULL);
-}
-
-static void
-set_sync_pending (CoglOnscreen *onscreen)
-{
-  CoglOnscreenGLX *glx_onscreen = cogl_onscreen_get_winsys (onscreen);
-  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
-  CoglContext *context = cogl_framebuffer_get_context (framebuffer);
-  CoglRenderer *renderer = context->display->renderer;
-  CoglGLXRenderer *glx_renderer = renderer->winsys;
-
-  /* We only want to dispatch sync events when the application calls
-   * cogl_context_dispatch so instead of immediately notifying we
-   * queue an idle callback */
-  if (!glx_renderer->flush_notifications_idle)
-    {
-      glx_renderer->flush_notifications_idle =
-        _cogl_poll_renderer_add_idle (renderer,
-                                      flush_pending_notifications_idle,
-                                      context,
-                                      NULL);
-    }
-
-  glx_onscreen->pending_sync_notify++;
-}
-
-static void
-set_complete_pending (CoglOnscreen *onscreen)
-{
-  CoglOnscreenGLX *glx_onscreen = cogl_onscreen_get_winsys (onscreen);
-  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
-  CoglContext *context = cogl_framebuffer_get_context (framebuffer);
-  CoglRenderer *renderer = context->display->renderer;
-  CoglGLXRenderer *glx_renderer = renderer->winsys;
-
-  /* We only want to notify swap completion when the application calls
-   * cogl_context_dispatch so instead of immediately notifying we
-   * queue an idle callback */
-  if (!glx_renderer->flush_notifications_idle)
-    {
-      glx_renderer->flush_notifications_idle =
-        _cogl_poll_renderer_add_idle (renderer,
-                                      flush_pending_notifications_idle,
-                                      context,
-                                      NULL);
-    }
-
-  glx_onscreen->pending_complete_notify++;
-}
-
 static void
 notify_swap_buffers (CoglContext *context, GLXBufferSwapComplete *swap_event)
 {
   CoglOnscreen *onscreen = find_onscreen_for_xid (context, (uint32_t)swap_event->drawable);
-  CoglOnscreenGLX *glx_onscreen;
 
   if (!onscreen)
     return;
-  glx_onscreen = cogl_onscreen_get_winsys (onscreen);
-
-  /* We only want to notify that the swap is complete when the
-     application calls cogl_context_dispatch so instead of immediately
-     notifying we'll set a flag to remember to notify later */
-  set_sync_pending (onscreen);
-
-  if (swap_event->ust != 0)
-    {
-      CoglFrameInfo *info = cogl_onscreen_peek_head_frame_info (onscreen);
 
-      info->presentation_time =
-        ust_to_nanoseconds (context->display->renderer,
-                            glx_onscreen->glxwin,
-                            swap_event->ust);
-    }
-
-  set_complete_pending (onscreen);
-}
-
-static void
-update_output (CoglOnscreen *onscreen)
-{
-  CoglOnscreenGLX *onscreen_glx = cogl_onscreen_get_winsys (onscreen);
-  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
-  CoglContext *context = cogl_framebuffer_get_context (framebuffer);
-  CoglDisplay *display = context->display;
-  CoglOutput *output;
-  int width, height;
-
-  width = cogl_framebuffer_get_width (framebuffer);
-  height = cogl_framebuffer_get_height (framebuffer);
-  output = _cogl_xlib_renderer_output_for_rectangle (display->renderer,
-                                                     onscreen_glx->x,
-                                                     onscreen_glx->y,
-                                                     width, height);
-  if (onscreen_glx->output != output)
-    {
-      if (onscreen_glx->output)
-        cogl_object_unref (onscreen_glx->output);
-
-      onscreen_glx->output = output;
-
-      if (output)
-        cogl_object_ref (onscreen_glx->output);
-    }
+  cogl_onscreen_glx_notify_swap_buffers (onscreen, swap_event);
 }
 
 static void
 notify_resize (CoglContext *context,
                XConfigureEvent *configure_event)
 {
-  CoglOnscreen *onscreen = find_onscreen_for_xid (context,
-                                                  configure_event->window);
-  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
-  CoglRenderer *renderer = context->display->renderer;
-  CoglGLXRenderer *glx_renderer = renderer->winsys;
-  CoglOnscreenGLX *glx_onscreen;
+  CoglOnscreen *onscreen;
 
+  onscreen = find_onscreen_for_xid (context, configure_event->window);
   if (!onscreen)
     return;
 
-  glx_onscreen = cogl_onscreen_get_winsys (onscreen);
-
-  _cogl_framebuffer_winsys_update_size (framebuffer,
-                                        configure_event->width,
-                                        configure_event->height);
-
-  /* We only want to notify that a resize happened when the
-   * application calls cogl_context_dispatch so instead of immediately
-   * notifying we queue an idle callback */
-  if (!glx_renderer->flush_notifications_idle)
-    {
-      glx_renderer->flush_notifications_idle =
-        _cogl_poll_renderer_add_idle (renderer,
-                                      flush_pending_notifications_idle,
-                                      context,
-                                      NULL);
-    }
-
-  glx_onscreen->pending_resize_notify++;
-
-    {
-      int x, y;
-
-      if (configure_event->send_event)
-        {
-          x = configure_event->x;
-          y = configure_event->y;
-        }
-      else
-        {
-          Window child;
-          XTranslateCoordinates (configure_event->display,
-                                 configure_event->window,
-                                 DefaultRootWindow (configure_event->display),
-                                 0, 0, &x, &y, &child);
-        }
-
-      glx_onscreen->x = x;
-      glx_onscreen->y = y;
-
-      update_output (onscreen);
-    }
+  cogl_onscreen_glx_resize (onscreen, configure_event);
 }
 
 static CoglFilterReturn
@@ -630,7 +333,7 @@ update_all_outputs (CoglRenderer *renderer)
       if (!COGL_IS_ONSCREEN (framebuffer))
         continue;
 
-      update_output (COGL_ONSCREEN (framebuffer));
+      cogl_onscreen_glx_update_output (COGL_ONSCREEN (framebuffer));
     }
 
   return TRUE;
@@ -902,11 +605,11 @@ glx_attributes_from_framebuffer_config (CoglDisplay                 *display,
 /* It seems the GLX spec never defined an invalid GLXFBConfig that
  * we could overload as an indication of error, so we have to return
  * an explicit boolean status. */
-static gboolean
-find_fbconfig (CoglDisplay                  *display,
-               const CoglFramebufferConfig  *config,
-               GLXFBConfig                  *config_ret,
-               GError                      **error)
+gboolean
+cogl_display_glx_find_fbconfig (CoglDisplay                  *display,
+                                const CoglFramebufferConfig  *config,
+                                GLXFBConfig                  *config_ret,
+                                GError                      **error)
 {
   CoglXlibRenderer *xlib_renderer =
     _cogl_xlib_renderer_get_data (display->renderer);
@@ -1026,8 +729,10 @@ create_context (CoglDisplay *display, GError **error)
   g_return_val_if_fail (glx_display->glx_context == NULL, TRUE);
 
   glx_display->found_fbconfig =
-    find_fbconfig (display, &display->onscreen_template->config, &config,
-                   &fbconfig_error);
+    cogl_display_glx_find_fbconfig (display,
+                                    &display->onscreen_template->config,
+                                    &config,
+                                    &fbconfig_error);
   if (!glx_display->found_fbconfig)
     {
       g_set_error (error, COGL_WINSYS_ERROR,
@@ -1226,757 +931,6 @@ _cogl_winsys_context_deinit (CoglContext *context)
   g_free (context->winsys);
 }
 
-static gboolean
-_cogl_winsys_onscreen_init (CoglOnscreen *onscreen,
-                            GError **error)
-{
-  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
-  CoglContext *context = cogl_framebuffer_get_context (framebuffer);
-  CoglDisplay *display = context->display;
-  CoglGLXDisplay *glx_display = display->winsys;
-  CoglXlibRenderer *xlib_renderer =
-    _cogl_xlib_renderer_get_data (display->renderer);
-  CoglGLXRenderer *glx_renderer = display->renderer->winsys;
-  Window xwin;
-  CoglOnscreenGLX *glx_onscreen;
-  const CoglFramebufferConfig *config;
-  GLXFBConfig fbconfig;
-  GError *fbconfig_error = NULL;
-  CoglOnscreenGLX *winsys;
-
-  g_return_val_if_fail (glx_display->glx_context, FALSE);
-
-  config = cogl_framebuffer_get_config (framebuffer);
-  if (!find_fbconfig (display, config,
-                      &fbconfig,
-                      &fbconfig_error))
-    {
-      g_set_error (error, COGL_WINSYS_ERROR,
-                   COGL_WINSYS_ERROR_CREATE_CONTEXT,
-                   "Unable to find suitable fbconfig for the GLX context: %s",
-                   fbconfig_error->message);
-      g_error_free (fbconfig_error);
-      return FALSE;
-    }
-
-  /* Update the real number of samples_per_pixel now that we have
-   * found an fbconfig... */
-  if (config->samples_per_pixel)
-    {
-      int samples;
-      int status = glx_renderer->glXGetFBConfigAttrib (xlib_renderer->xdpy,
-                                                       fbconfig,
-                                                       GLX_SAMPLES,
-                                                       &samples);
-      g_return_val_if_fail (status == Success, TRUE);
-      cogl_framebuffer_update_samples_per_pixel (framebuffer, samples);
-    }
-
-  /* FIXME: We need to explicitly Select for ConfigureNotify events.
-   * We need to document that for windows we create then toolkits
-   * must be careful not to clear event mask bits that we select.
-   */
-    {
-      int width;
-      int height;
-      CoglXlibTrapState state;
-      XVisualInfo *xvisinfo;
-      XSetWindowAttributes xattr;
-      unsigned long mask;
-      int xerror;
-
-      width = cogl_framebuffer_get_width (framebuffer);
-      height = cogl_framebuffer_get_height (framebuffer);
-
-      _cogl_xlib_renderer_trap_errors (display->renderer, &state);
-
-      xvisinfo = glx_renderer->glXGetVisualFromFBConfig (xlib_renderer->xdpy,
-                                                         fbconfig);
-      if (xvisinfo == NULL)
-        {
-          g_set_error_literal (error, COGL_WINSYS_ERROR,
-                               COGL_WINSYS_ERROR_CREATE_ONSCREEN,
-                               "Unable to retrieve the X11 visual of context's "
-                               "fbconfig");
-          return FALSE;
-        }
-
-      /* window attributes */
-      xattr.background_pixel = WhitePixel (xlib_renderer->xdpy,
-                                           DefaultScreen (xlib_renderer->xdpy));
-      xattr.border_pixel = 0;
-      /* XXX: is this an X resource that we are leaking‽... */
-      xattr.colormap = XCreateColormap (xlib_renderer->xdpy,
-                                        DefaultRootWindow (xlib_renderer->xdpy),
-                                        xvisinfo->visual,
-                                        AllocNone);
-      xattr.event_mask = COGL_ONSCREEN_X11_EVENT_MASK;
-
-      mask = CWBorderPixel | CWColormap | CWEventMask;
-
-      xwin = XCreateWindow (xlib_renderer->xdpy,
-                            DefaultRootWindow (xlib_renderer->xdpy),
-                            0, 0,
-                            width, height,
-                            0,
-                            xvisinfo->depth,
-                            InputOutput,
-                            xvisinfo->visual,
-                            mask, &xattr);
-
-      XFree (xvisinfo);
-
-      XSync (xlib_renderer->xdpy, False);
-      xerror = _cogl_xlib_renderer_untrap_errors (display->renderer, &state);
-      if (xerror)
-        {
-          char message[1000];
-          XGetErrorText (xlib_renderer->xdpy, xerror,
-                         message, sizeof (message));
-          g_set_error (error, COGL_WINSYS_ERROR,
-                       COGL_WINSYS_ERROR_CREATE_ONSCREEN,
-                       "X error while creating Window for CoglOnscreen: %s",
-                       message);
-          return FALSE;
-        }
-    }
-
-  winsys = g_slice_new0 (CoglOnscreenGLX);
-  cogl_onscreen_set_winsys (onscreen, winsys);
-  glx_onscreen = cogl_onscreen_get_winsys (onscreen);
-
-  glx_onscreen->xwin = xwin;
-
-  /* Try and create a GLXWindow to use with extensions dependent on
-   * GLX versions >= 1.3 that don't accept regular X Windows as GLX
-   * drawables. */
-  if (glx_renderer->glx_major == 1 && glx_renderer->glx_minor >= 3)
-    {
-      glx_onscreen->glxwin =
-        glx_renderer->glXCreateWindow (xlib_renderer->xdpy,
-                                       fbconfig,
-                                       glx_onscreen->xwin,
-                                       NULL);
-    }
-
-#ifdef GLX_INTEL_swap_event
-  if (_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT))
-    {
-      GLXDrawable drawable =
-        glx_onscreen->glxwin ? glx_onscreen->glxwin : glx_onscreen->xwin;
-
-      /* similarly to above, we unconditionally select this event
-       * because we rely on it to advance the master clock, and
-       * drive redraw/relayout, animations and event handling.
-       */
-      glx_renderer->glXSelectEvent (xlib_renderer->xdpy,
-                                    drawable,
-                                    GLX_BUFFER_SWAP_COMPLETE_INTEL_MASK);
-    }
-#endif /* GLX_INTEL_swap_event */
-
-  return TRUE;
-}
-
-static void
-_cogl_winsys_onscreen_deinit (CoglOnscreen *onscreen)
-{
-  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
-  CoglContext *context = cogl_framebuffer_get_context (framebuffer);
-  CoglContextGLX *glx_context = context->winsys;
-  CoglGLXDisplay *glx_display = context->display->winsys;
-  CoglXlibRenderer *xlib_renderer =
-    _cogl_xlib_renderer_get_data (context->display->renderer);
-  CoglGLXRenderer *glx_renderer = context->display->renderer->winsys;
-  CoglXlibTrapState old_state;
-  CoglOnscreenGLX *glx_onscreen = cogl_onscreen_get_winsys (onscreen);
-  GLXDrawable drawable;
-
-  /* If we never successfully allocated then there's nothing to do */
-  if (glx_onscreen == NULL)
-    return;
-
-  if (glx_onscreen->output != NULL)
-    {
-      cogl_object_unref (glx_onscreen->output);
-      glx_onscreen->output = NULL;
-    }
-
-  _cogl_xlib_renderer_trap_errors (context->display->renderer, &old_state);
-
-  drawable =
-    glx_onscreen->glxwin == None ? glx_onscreen->xwin : glx_onscreen->glxwin;
-
-  /* Cogl always needs a valid context bound to something so if we are
-   * destroying the onscreen that is currently bound we'll switch back
-   * to the dummy drawable. Although the documentation for
-   * glXDestroyWindow states that a currently bound window won't
-   * actually be destroyed until it is unbound, it looks like this
-   * doesn't work if the X window itself is destroyed */
-  if (drawable == glx_context->current_drawable)
-    {
-      GLXDrawable dummy_drawable = (glx_display->dummy_glxwin == None ?
-                                    glx_display->dummy_xwin :
-                                    glx_display->dummy_glxwin);
-
-      glx_renderer->glXMakeContextCurrent (xlib_renderer->xdpy,
-                                           dummy_drawable,
-                                           dummy_drawable,
-                                           glx_display->glx_context);
-      glx_context->current_drawable = dummy_drawable;
-    }
-
-  if (glx_onscreen->glxwin != None)
-    {
-      glx_renderer->glXDestroyWindow (xlib_renderer->xdpy,
-                                      glx_onscreen->glxwin);
-      glx_onscreen->glxwin = None;
-    }
-
-  if (glx_onscreen->xwin != None)
-    {
-      XDestroyWindow (xlib_renderer->xdpy, glx_onscreen->xwin);
-      glx_onscreen->xwin = None;
-    }
-  else
-    {
-      glx_onscreen->xwin = None;
-    }
-
-  XSync (xlib_renderer->xdpy, False);
-
-  _cogl_xlib_renderer_untrap_errors (context->display->renderer, &old_state);
-
-  g_slice_free (CoglOnscreenGLX, cogl_onscreen_get_winsys (onscreen));
-  cogl_onscreen_set_winsys (onscreen, NULL);
-}
-
-static void
-_cogl_winsys_onscreen_bind (CoglOnscreen *onscreen)
-{
-  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
-  CoglContext *context = cogl_framebuffer_get_context (framebuffer);
-  CoglContextGLX *glx_context = context->winsys;
-  CoglGLXDisplay *glx_display = context->display->winsys;
-  CoglXlibRenderer *xlib_renderer =
-    _cogl_xlib_renderer_get_data (context->display->renderer);
-  CoglGLXRenderer *glx_renderer = context->display->renderer->winsys;
-  CoglOnscreenGLX *glx_onscreen = cogl_onscreen_get_winsys (onscreen);
-  CoglXlibTrapState old_state;
-  GLXDrawable drawable;
-
-  drawable =
-    glx_onscreen->glxwin ? glx_onscreen->glxwin : glx_onscreen->xwin;
-
-  if (glx_context->current_drawable == drawable)
-    return;
-
-  _cogl_xlib_renderer_trap_errors (context->display->renderer, &old_state);
-
-  COGL_NOTE (WINSYS,
-             "MakeContextCurrent dpy: %p, window: 0x%x, context: %p",
-             xlib_renderer->xdpy,
-             (unsigned int) drawable,
-             glx_display->glx_context);
-
-  glx_renderer->glXMakeContextCurrent (xlib_renderer->xdpy,
-                                       drawable,
-                                       drawable,
-                                       glx_display->glx_context);
-
-  /* In case we are using GLX_SGI_swap_control for vblank syncing
-   * we need call glXSwapIntervalSGI here to make sure that it
-   * affects the current drawable.
-   *
-   * Note: we explicitly set to 0 when we aren't using the swap
-   * interval to synchronize since some drivers have a default
-   * swap interval of 1. Sadly some drivers even ignore requests
-   * to disable the swap interval.
-   *
-   * NB: glXSwapIntervalSGI applies to the context not the
-   * drawable which is why we can't just do this once when the
-   * framebuffer is allocated.
-   *
-   * FIXME: We should check for GLX_EXT_swap_control which allows
-   * per framebuffer swap intervals. GLX_MESA_swap_control also
-   * allows per-framebuffer swap intervals but the semantics tend
-   * to be more muddled since Mesa drivers tend to expose both the
-   * MESA and SGI extensions which should technically be mutually
-   * exclusive.
-   */
-  if (glx_renderer->glXSwapInterval)
-    glx_renderer->glXSwapInterval (1);
-
-  XSync (xlib_renderer->xdpy, False);
-
-  /* FIXME: We should be reporting a GError here */
-  if (_cogl_xlib_renderer_untrap_errors (context->display->renderer,
-                                         &old_state))
-    {
-      g_warning ("X Error received while making drawable 0x%08lX current",
-                 drawable);
-      return;
-    }
-
-  glx_context->current_drawable = drawable;
-}
-
-static void
-_cogl_winsys_wait_for_gpu (CoglOnscreen *onscreen)
-{
-  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
-  CoglContext *ctx = cogl_framebuffer_get_context (framebuffer);
-
-  ctx->glFinish ();
-}
-
-static void
-_cogl_winsys_wait_for_vblank (CoglOnscreen *onscreen)
-{
-  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
-  CoglContext *ctx = cogl_framebuffer_get_context (framebuffer);
-  CoglGLXRenderer *glx_renderer;
-  CoglXlibRenderer *xlib_renderer;
-  CoglGLXDisplay *glx_display;
-
-  glx_renderer = ctx->display->renderer->winsys;
-  xlib_renderer = _cogl_xlib_renderer_get_data (ctx->display->renderer);
-  glx_display = ctx->display->winsys;
-
-  if (glx_display->can_vblank_wait)
-    {
-      CoglFrameInfo *info = cogl_onscreen_peek_tail_frame_info (onscreen);
-
-      if (glx_renderer->glXWaitForMsc)
-        {
-          CoglOnscreenGLX *glx_onscreen = cogl_onscreen_get_winsys (onscreen);
-          Drawable drawable = glx_onscreen->glxwin;
-          int64_t ust;
-          int64_t msc;
-          int64_t sbc;
-
-          glx_renderer->glXWaitForMsc (xlib_renderer->xdpy, drawable,
-                                       0, 1, 0,
-                                       &ust, &msc, &sbc);
-          info->presentation_time = ust_to_nanoseconds (ctx->display->renderer,
-                                                        drawable,
-                                                        ust);
-        }
-      else
-        {
-          uint32_t current_count;
-
-          glx_renderer->glXGetVideoSync (&current_count);
-          glx_renderer->glXWaitVideoSync (2,
-                                          (current_count + 1) % 2,
-                                          &current_count);
-
-          info->presentation_time = get_monotonic_time_ns ();
-        }
-    }
-}
-
-static uint32_t
-_cogl_winsys_get_vsync_counter (CoglContext *ctx)
-{
-  uint32_t video_sync_count;
-  CoglGLXRenderer *glx_renderer;
-
-  glx_renderer = ctx->display->renderer->winsys;
-
-  glx_renderer->glXGetVideoSync (&video_sync_count);
-
-  return video_sync_count;
-}
-
-#ifndef GLX_BACK_BUFFER_AGE_EXT
-#define GLX_BACK_BUFFER_AGE_EXT 0x20F4
-#endif
-
-static int
-_cogl_winsys_onscreen_get_buffer_age (CoglOnscreen *onscreen)
-{
-  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
-  CoglContext *context = cogl_framebuffer_get_context (framebuffer);
-  CoglXlibRenderer *xlib_renderer = _cogl_xlib_renderer_get_data (context->display->renderer);
-  CoglGLXRenderer *glx_renderer = context->display->renderer->winsys;
-  CoglOnscreenGLX *glx_onscreen = cogl_onscreen_get_winsys (onscreen);
-  GLXDrawable drawable;
-  unsigned int age;
-
-  if (!_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_BUFFER_AGE))
-    return 0;
-
-  drawable = glx_onscreen->glxwin ? glx_onscreen->glxwin : glx_onscreen->xwin;
-  glx_renderer->glXQueryDrawable (xlib_renderer->xdpy,
-                                  drawable,
-                                  GLX_BACK_BUFFER_AGE_EXT,
-                                  &age);
-
-  return age;
-}
-
-static void
-set_frame_info_output (CoglOnscreen *onscreen,
-                       CoglOutput *output)
-{
-  CoglFrameInfo *info = cogl_onscreen_peek_tail_frame_info (onscreen);
-
-  if (output)
-    {
-      float refresh_rate = cogl_output_get_refresh_rate (output);
-      if (refresh_rate != 0.0)
-        info->refresh_rate = refresh_rate;
-    }
-}
-
-static void
-_cogl_winsys_onscreen_swap_region (CoglOnscreen *onscreen,
-                                   const int *user_rectangles,
-                                   int n_rectangles,
-                                   CoglFrameInfo *info,
-                                   gpointer user_data)
-{
-  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
-  CoglContext *context = cogl_framebuffer_get_context (framebuffer);
-  CoglXlibRenderer *xlib_renderer =
-    _cogl_xlib_renderer_get_data (context->display->renderer);
-  CoglGLXRenderer *glx_renderer = context->display->renderer->winsys;
-  CoglGLXDisplay *glx_display = context->display->winsys;
-  CoglOnscreenGLX *glx_onscreen = cogl_onscreen_get_winsys (onscreen);
-  GLXDrawable drawable =
-    glx_onscreen->glxwin ? glx_onscreen->glxwin : glx_onscreen->xwin;
-  uint32_t end_frame_vsync_counter = 0;
-  gboolean have_counter;
-  gboolean can_wait;
-  int x_min = 0, x_max = 0, y_min = 0, y_max = 0;
-
-  /*
-   * We assume that glXCopySubBuffer is synchronized which means it won't prevent multiple
-   * blits per retrace if they can all be performed in the blanking period. If that's the
-   * case then we still want to use the vblank sync menchanism but
-   * we only need it to throttle redraws.
-   */
-  gboolean blit_sub_buffer_is_synchronized =
-     _cogl_winsys_has_feature (COGL_WINSYS_FEATURE_SWAP_REGION_SYNCHRONIZED);
-
-  int framebuffer_width =  cogl_framebuffer_get_width (framebuffer);
-  int framebuffer_height =  cogl_framebuffer_get_height (framebuffer);
-  int *rectangles = g_alloca (sizeof (int) * n_rectangles * 4);
-  int i;
-
-  /* glXCopySubBuffer expects rectangles relative to the bottom left corner but
-   * we are given rectangles relative to the top left so we need to flip
-   * them... */
-  memcpy (rectangles, user_rectangles, sizeof (int) * n_rectangles * 4);
-  for (i = 0; i < n_rectangles; i++)
-    {
-      int *rect = &rectangles[4 * i];
-
-      if (i == 0)
-        {
-          x_min = rect[0];
-          x_max = rect[0] + rect[2];
-          y_min = rect[1];
-          y_max = rect[1] + rect[3];
-        }
-      else
-        {
-          x_min = MIN (x_min, rect[0]);
-          x_max = MAX (x_max, rect[0] + rect[2]);
-          y_min = MIN (y_min, rect[1]);
-          y_max = MAX (y_max, rect[1] + rect[3]);
-        }
-
-      rect[1] = framebuffer_height - rect[1] - rect[3];
-
-    }
-
-  _cogl_framebuffer_flush_state (framebuffer,
-                                 framebuffer,
-                                 COGL_FRAMEBUFFER_STATE_BIND);
-
-  have_counter = glx_display->have_vblank_counter;
-  can_wait = glx_display->can_vblank_wait;
-
-  /* We need to ensure that all the rendering is done, otherwise
-   * redraw operations that are slower than the framerate can
-   * queue up in the pipeline during a heavy animation, causing a
-   * larger and larger backlog of rendering visible as lag to the
-   * user.
-   *
-   * For an exaggerated example consider rendering at 60fps (so 16ms
-   * per frame) and you have a really slow frame that takes 160ms to
-   * render, even though painting the scene and issuing the commands
-   * to the GPU takes no time at all. If all we did was use the
-   * video_sync extension to throttle the painting done by the CPU
-   * then every 16ms we would have another frame queued up even though
-   * the GPU has only rendered one tenth of the current frame. By the
-   * time the GPU would get to the 2nd frame there would be 9 frames
-   * waiting to be rendered.
-   *
-   * The problem is that we don't currently have a good way to throttle
-   * the GPU, only the CPU so we have to resort to synchronizing the
-   * GPU with the CPU to throttle it.
-   *
-   * Note: since calling glFinish() and synchronizing the CPU with
-   * the GPU is far from ideal, we hope that this is only a short
-   * term solution.
-   * - One idea is to using sync objects to track render
-   *   completion so we can throttle the backlog (ideally with an
-   *   additional extension that lets us get notifications in our
-   *   mainloop instead of having to busy wait for the
-   *   completion.)
-   * - Another option is to support clipped redraws by reusing the
-   *   contents of old back buffers such that we can flip instead
-   *   of using a blit and then we can use GLX_INTEL_swap_events
-   *   to throttle. For this though we would still probably want an
-   *   additional extension so we can report the limited region of
-   *   the window damage to X/compositors.
-   */
-  _cogl_winsys_wait_for_gpu (onscreen);
-
-  if (blit_sub_buffer_is_synchronized && have_counter && can_wait)
-    {
-      end_frame_vsync_counter = _cogl_winsys_get_vsync_counter (context);
-
-      /* If we have the GLX_SGI_video_sync extension then we can
-       * be a bit smarter about how we throttle blits by avoiding
-       * any waits if we can see that the video sync count has
-       * already progressed. */
-      if (glx_onscreen->last_swap_vsync_counter == end_frame_vsync_counter)
-        _cogl_winsys_wait_for_vblank (onscreen);
-    }
-  else if (can_wait)
-    _cogl_winsys_wait_for_vblank (onscreen);
-
-  if (glx_renderer->glXCopySubBuffer)
-    {
-      Display *xdpy = xlib_renderer->xdpy;
-      int i;
-      for (i = 0; i < n_rectangles; i++)
-        {
-          int *rect = &rectangles[4 * i];
-          glx_renderer->glXCopySubBuffer (xdpy, drawable,
-                                          rect[0], rect[1], rect[2], rect[3]);
-        }
-    }
-  else if (context->glBlitFramebuffer)
-    {
-      int i;
-      /* XXX: checkout how this state interacts with the code to use
-       * glBlitFramebuffer in Neil's texture atlasing branch */
-
-      /* glBlitFramebuffer is affected by the scissor so we need to
-       * ensure we have flushed an empty clip stack to get rid of it.
-       * We also mark that the clip state is dirty so that it will be
-       * flushed to the correct state the next time something is
-       * drawn */
-      _cogl_clip_stack_flush (NULL, framebuffer);
-      context->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_CLIP;
-
-      context->glDrawBuffer (GL_FRONT);
-      for (i = 0; i < n_rectangles; i++)
-        {
-          int *rect = &rectangles[4 * i];
-          int x2 = rect[0] + rect[2];
-          int y2 = rect[1] + rect[3];
-          context->glBlitFramebuffer (rect[0], rect[1], x2, y2,
-                                      rect[0], rect[1], x2, y2,
-                                      GL_COLOR_BUFFER_BIT, GL_NEAREST);
-        }
-      context->glDrawBuffer (context->current_gl_draw_buffer);
-    }
-
-  /* NB: unlike glXSwapBuffers, glXCopySubBuffer and
-   * glBlitFramebuffer don't issue an implicit glFlush() so we
-   * have to flush ourselves if we want the request to complete in
-   * a finite amount of time since otherwise the driver can batch
-   * the command indefinitely. */
-  context->glFlush ();
-
-  /* NB: It's important we save the counter we read before acting on
-   * the swap request since if we are mixing and matching different
-   * swap methods between frames we don't want to read the timer e.g.
-   * after calling glFinish() some times and not for others.
-   *
-   * In other words; this way we consistently save the time at the end
-   * of the applications frame such that the counter isn't muddled by
-   * the varying costs of different swap methods.
-   */
-  if (have_counter)
-    glx_onscreen->last_swap_vsync_counter = end_frame_vsync_counter;
-
-  {
-    CoglOutput *output;
-
-    x_min = CLAMP (x_min, 0, framebuffer_width);
-    x_max = CLAMP (x_max, 0, framebuffer_width);
-    y_min = CLAMP (y_min, 0, framebuffer_width);
-    y_max = CLAMP (y_max, 0, framebuffer_height);
-
-    output =
-      _cogl_xlib_renderer_output_for_rectangle (context->display->renderer,
-                                                glx_onscreen->x + x_min,
-                                                glx_onscreen->y + y_min,
-                                                x_max - x_min,
-                                                y_max - y_min);
-
-    set_frame_info_output (onscreen, output);
-  }
-
-  /* XXX: we don't get SwapComplete events based on how we implement
-   * the _swap_region() API but if cogl-onscreen.c knows we are
-   * handling _SYNC and _COMPLETE events in the winsys then we need to
-   * send fake events in this case.
-   */
-  if (_cogl_winsys_has_feature (COGL_WINSYS_FEATURE_SYNC_AND_COMPLETE_EVENT))
-    {
-      set_sync_pending (onscreen);
-      set_complete_pending (onscreen);
-    }
-}
-
-static void
-_cogl_winsys_onscreen_swap_buffers_with_damage (CoglOnscreen *onscreen,
-                                                const int *rectangles,
-                                                int n_rectangles,
-                                                CoglFrameInfo *info,
-                                                gpointer user_data)
-{
-  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
-  CoglContext *context = cogl_framebuffer_get_context (framebuffer);
-  CoglXlibRenderer *xlib_renderer =
-    _cogl_xlib_renderer_get_data (context->display->renderer);
-  CoglGLXRenderer *glx_renderer = context->display->renderer->winsys;
-  CoglGLXDisplay *glx_display = context->display->winsys;
-  CoglOnscreenGLX *glx_onscreen = cogl_onscreen_get_winsys (onscreen);
-  gboolean have_counter;
-  GLXDrawable drawable;
-
-  /* XXX: theoretically this shouldn't be necessary but at least with
-   * the Intel drivers we have see that if we don't call
-   * glXMakeContextCurrent for the drawable we are swapping then
-   * we get a BadDrawable error from the X server. */
-  _cogl_framebuffer_flush_state (framebuffer,
-                                 framebuffer,
-                                 COGL_FRAMEBUFFER_STATE_BIND);
-
-  drawable = glx_onscreen->glxwin ? glx_onscreen->glxwin : glx_onscreen->xwin;
-
-  have_counter = glx_display->have_vblank_counter;
-
-  if (!glx_renderer->glXSwapInterval)
-    {
-      gboolean can_wait = have_counter || glx_display->can_vblank_wait;
-
-      uint32_t end_frame_vsync_counter = 0;
-
-      /* If the swap_region API is also being used then we need to track
-       * the vsync counter for each swap request so we can manually
-       * throttle swap_region requests. */
-      if (have_counter)
-        end_frame_vsync_counter = _cogl_winsys_get_vsync_counter (context);
-
-      /* If we are going to wait for VBLANK manually, we not only
-       * need to flush out pending drawing to the GPU before we
-       * sleep, we need to wait for it to finish. Otherwise, we
-       * may end up with the situation:
-       *
-       *        - We finish drawing      - GPU drawing continues
-       *        - We go to sleep         - GPU drawing continues
-       * VBLANK - We call glXSwapBuffers - GPU drawing continues
-       *                                 - GPU drawing continues
-       *                                 - Swap buffers happens
-       *
-       * Producing a tear. Calling glFinish() first will cause us
-       * to properly wait for the next VBLANK before we swap. This
-       * obviously does not happen when we use _GLX_SWAP and let
-       * the driver do the right thing
-       */
-      _cogl_winsys_wait_for_gpu (onscreen);
-
-      if (have_counter && can_wait)
-        {
-          if (glx_onscreen->last_swap_vsync_counter ==
-              end_frame_vsync_counter)
-            _cogl_winsys_wait_for_vblank (onscreen);
-        }
-      else if (can_wait)
-        _cogl_winsys_wait_for_vblank (onscreen);
-    }
-
-  glx_renderer->glXSwapBuffers (xlib_renderer->xdpy, drawable);
-
-  if (have_counter)
-    glx_onscreen->last_swap_vsync_counter =
-      _cogl_winsys_get_vsync_counter (context);
-
-  set_frame_info_output (onscreen, glx_onscreen->output);
-}
-
-static uint32_t
-_cogl_winsys_onscreen_x11_get_window_xid (CoglOnscreen *onscreen)
-{
-  CoglOnscreenGLX *glx_onscreen = cogl_onscreen_get_winsys (onscreen);
-
-  return glx_onscreen->xwin;
-}
-
-static void
-_cogl_winsys_onscreen_set_visibility (CoglOnscreen *onscreen,
-                                      gboolean visibility)
-{
-  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
-  CoglContext *context = cogl_framebuffer_get_context (framebuffer);
-  CoglXlibRenderer *xlib_renderer =
-    _cogl_xlib_renderer_get_data (context->display->renderer);
-  CoglOnscreenGLX *glx_onscreen = cogl_onscreen_get_winsys (onscreen);
-
-  if (visibility)
-    XMapWindow (xlib_renderer->xdpy, glx_onscreen->xwin);
-  else
-    XUnmapWindow (xlib_renderer->xdpy, glx_onscreen->xwin);
-}
-
-static void
-_cogl_winsys_onscreen_set_resizable (CoglOnscreen *onscreen,
-                                     gboolean resizable)
-{
-  CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (onscreen);
-  CoglContext *context = cogl_framebuffer_get_context (framebuffer);
-  CoglXlibRenderer *xlib_renderer =
-    _cogl_xlib_renderer_get_data (context->display->renderer);
-  CoglOnscreenGLX *glx_onscreen = cogl_onscreen_get_winsys (onscreen);
-
-  XSizeHints *size_hints = XAllocSizeHints ();
-
-  if (resizable)
-    {
-      /* TODO: Add cogl_onscreen_request_minimum_size () */
-      size_hints->min_width = 1;
-      size_hints->min_height = 1;
-
-      size_hints->max_width = INT_MAX;
-      size_hints->max_height = INT_MAX;
-    }
-  else
-    {
-      int width = cogl_framebuffer_get_width (framebuffer);
-      int height = cogl_framebuffer_get_height (framebuffer);
-
-      size_hints->min_width = width;
-      size_hints->min_height = height;
-
-      size_hints->max_width = width;
-      size_hints->max_height = height;
-    }
-
-  XSetWMNormalHints (xlib_renderer->xdpy, glx_onscreen->xwin, size_hints);
-
-  XFree (size_hints);
-}
-
 static gboolean
 get_fbconfig_for_depth (CoglContext *context,
                         unsigned int depth,
@@ -2485,6 +1439,23 @@ _cogl_winsys_texture_pixmap_x11_get_texture (CoglTexturePixmapX11 *tex_pixmap,
     return glx_tex_pixmap->left.glx_tex;
 }
 
+void
+cogl_context_glx_set_current_drawable (CoglContext *context,
+                                       GLXDrawable  drawable)
+{
+  CoglContextGLX *glx_context = context->winsys;
+
+  glx_context->current_drawable = drawable;
+}
+
+GLXDrawable
+cogl_context_glx_get_current_drawable (CoglContext *context)
+{
+  CoglContextGLX *glx_context = context->winsys;
+
+  return glx_context->current_drawable;
+}
+
 static CoglWinsysVtable _cogl_winsys_vtable =
   {
     .id = COGL_WINSYS_ID_GLX,
@@ -2501,18 +1472,18 @@ static CoglWinsysVtable _cogl_winsys_vtable =
     .context_init = _cogl_winsys_context_init,
     .context_deinit = _cogl_winsys_context_deinit,
     .context_get_clock_time = _cogl_winsys_get_clock_time,
-    .onscreen_init = _cogl_winsys_onscreen_init,
-    .onscreen_deinit = _cogl_winsys_onscreen_deinit,
-    .onscreen_bind = _cogl_winsys_onscreen_bind,
+    .onscreen_init = _cogl_winsys_onscreen_glx_init,
+    .onscreen_deinit = _cogl_winsys_onscreen_glx_deinit,
+    .onscreen_bind = _cogl_winsys_onscreen_glx_bind,
     .onscreen_swap_buffers_with_damage =
-      _cogl_winsys_onscreen_swap_buffers_with_damage,
-    .onscreen_swap_region = _cogl_winsys_onscreen_swap_region,
-    .onscreen_get_buffer_age = _cogl_winsys_onscreen_get_buffer_age,
+      _cogl_winsys_onscreen_glx_swap_buffers_with_damage,
+    .onscreen_swap_region = _cogl_winsys_onscreen_glx_swap_region,
+    .onscreen_get_buffer_age = _cogl_winsys_onscreen_glx_get_buffer_age,
     .onscreen_x11_get_window_xid =
-      _cogl_winsys_onscreen_x11_get_window_xid,
-    .onscreen_set_visibility = _cogl_winsys_onscreen_set_visibility,
+      _cogl_winsys_onscreen_glx_get_window_xid,
+    .onscreen_set_visibility = _cogl_winsys_onscreen_glx_set_visibility,
     .onscreen_set_resizable =
-      _cogl_winsys_onscreen_set_resizable,
+      _cogl_winsys_onscreen_glx_set_resizable,
 
     /* X11 tfp support... */
     /* XXX: instead of having a rather monolithic winsys vtable we could
diff --git a/src/backends/x11/meta-renderer-x11.c b/src/backends/x11/meta-renderer-x11.c
index 96beb4eb86..82f70f0eae 100644
--- a/src/backends/x11/meta-renderer-x11.c
+++ b/src/backends/x11/meta-renderer-x11.c
@@ -34,12 +34,17 @@
 #include "clutter/x11/clutter-x11.h"
 #include "cogl/cogl-xlib.h"
 #include "cogl/cogl.h"
-#include "cogl/winsys/cogl-winsys-egl-x11-private.h"
-#include "cogl/winsys/cogl-winsys-glx-private.h"
 #include "core/boxes-private.h"
 #include "meta/meta-backend.h"
 #include "meta/util.h"
 
+#ifdef COGL_HAS_EGL_SUPPORT
+#include "cogl/winsys/cogl-winsys-egl-x11-private.h"
+#endif
+#ifdef COGL_HAS_GLX_SUPPORT
+#include "cogl/winsys/cogl-winsys-glx-private.h"
+#endif
+
 G_DEFINE_TYPE (MetaRendererX11, meta_renderer_x11, META_TYPE_RENDERER)
 
 static const CoglWinsysVtable *


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