[gtk+/wip/gdk-gl: 2/31] Implement GdkGLContext and GdkGLPixelFormat



commit 5052aa4a9acd18b2cd06d543542ec7f5dce58ef1
Author: Emmanuele Bassi <ebassi gnome org>
Date:   Sun Mar 23 17:37:54 2014 +0000

    Implement GdkGLContext and GdkGLPixelFormat
    
    GdkGLPixelFormat is an ancillary class to specify pixel formats, buffer
    types, and buffer sizes for GL context.
    
    GdkGLContext is the wrapper around platform-specific GL context API.
    
    This commit adds the base classes, and an implementation on X11.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=119189

 gdk/Makefile.am               |    6 +
 gdk/gdk.h                     |    2 +
 gdk/gdkdisplay.c              |  130 ++++++++
 gdk/gdkdisplay.h              |    5 +
 gdk/gdkdisplayprivate.h       |   25 ++
 gdk/gdkglcontext.c            |  489 +++++++++++++++++++++++++++++
 gdk/gdkglcontext.h            |   67 ++++
 gdk/gdkglcontextprivate.h     |   53 ++++
 gdk/gdkglpixelformat.c        |  439 ++++++++++++++++++++++++++
 gdk/gdkglpixelformat.h        |   55 ++++
 gdk/gdkglpixelformatprivate.h |   43 +++
 gdk/gdkinternals.h            |    3 +-
 gdk/gdktypes.h                |   22 ++-
 gdk/x11/Makefile.am           |    3 +
 gdk/x11/gdkdisplay-x11.c      |    6 +
 gdk/x11/gdkdisplay-x11.h      |   14 +
 gdk/x11/gdkglcontext-x11.c    |  691 +++++++++++++++++++++++++++++++++++++++++
 gdk/x11/gdkglcontext-x11.h    |   56 ++++
 gdk/x11/gdkx.h                |    1 +
 gdk/x11/gdkx11glcontext.h     |   24 ++
 20 files changed, 2132 insertions(+), 2 deletions(-)
---
diff --git a/gdk/Makefile.am b/gdk/Makefile.am
index d52fdd2..fd60da1 100644
--- a/gdk/Makefile.am
+++ b/gdk/Makefile.am
@@ -75,6 +75,8 @@ gdk_public_h_sources =                                \
        gdkdnd.h                                \
        gdkevents.h                             \
        gdkframetimings.h                       \
+       gdkglcontext.h                          \
+       gdkglpixelformat.h                      \
        gdkkeys.h                               \
        gdkkeysyms.h                            \
        gdkkeysyms-compat.h                     \
@@ -111,6 +113,8 @@ gdk_private_headers =                               \
        gdkdndprivate.h                         \
        gdkframeclockidle.h                     \
        gdkframeclockprivate.h                  \
+       gdkglcontextprivate.h                   \
+       gdkglpixelformatprivate.h               \
        gdkscreenprivate.h                      \
        gdkinternals.h                          \
        gdkintl.h                               \
@@ -135,6 +139,8 @@ gdk_c_sources =                             \
        gdkdnd.c                                \
        gdkevents.c                             \
        gdkframetimings.c                       \
+       gdkglcontext.c                          \
+       gdkglpixelformat.c                      \
        gdkglobals.c                            \
        gdkkeys.c                               \
        gdkkeyuni.c                             \
diff --git a/gdk/gdk.h b/gdk/gdk.h
index 5761fa1..3fc297b 100644
--- a/gdk/gdk.h
+++ b/gdk/gdk.h
@@ -41,6 +41,8 @@
 #include <gdk/gdkevents.h>
 #include <gdk/gdkframeclock.h>
 #include <gdk/gdkframetimings.h>
+#include <gdk/gdkglpixelformat.h>
+#include <gdk/gdkglcontext.h>
 #include <gdk/gdkkeys.h>
 #include <gdk/gdkkeysyms.h>
 #include <gdk/gdkmain.h>
diff --git a/gdk/gdkdisplay.c b/gdk/gdkdisplay.c
index 34b6cab..2797803 100644
--- a/gdk/gdkdisplay.c
+++ b/gdk/gdkdisplay.c
@@ -2225,3 +2225,133 @@ gdk_error_trap_pop (void)
 {
   return gdk_error_trap_pop_internal (TRUE);
 }
+
+/*< private >
+ * gdk_display_create_gl_context:
+ * @display: a #GdkDisplay
+ * @format: a #GdkGLPixelFormat
+ * @share: (optional): an optional shared #GdkGLContext 
+ *
+ * Creates a new platform-specific #GdkGLContext for the
+ * given @display and @format.
+ *
+ * Returns: (transfer full): the newly created #GdkGLContext
+ */
+GdkGLContext *
+gdk_display_create_gl_context (GdkDisplay       *display,
+                               GdkGLPixelFormat *format,
+                               GdkGLContext     *share)
+{
+  return GDK_DISPLAY_GET_CLASS (display)->create_gl_context (display, format, share);
+}
+
+/*< private >
+ * gdk_display_destroy_gl_context:
+ * @display: a #GdkDisplay
+ * @context: a #GdkGLContext
+ *
+ * Destroys the platform-specific parts of the @context.
+ *
+ * The @context instance is still valid, though inert, after
+ * this functionr returns.
+ */
+void
+gdk_display_destroy_gl_context (GdkDisplay   *display,
+                                GdkGLContext *context)
+{
+  GDK_DISPLAY_GET_CLASS (display)->destroy_gl_context (display, context);
+}
+
+/*< private >
+ * gdk_display_make_gl_context_current:
+ * @display: a #GdkDisplay
+ * @context: (optional): a #GdkGLContext, or %NULL
+ * @window: (optional): a #GdkWindow, or %NULL
+ *
+ * Makes the given @context the current GL context, or unsets
+ * the current GL context if @context is %NULL.
+ *
+ * Returns: %TRUE if successful
+ */
+gboolean
+gdk_display_make_gl_context_current (GdkDisplay   *display,
+                                     GdkGLContext *context,
+                                     GdkWindow    *window)
+{
+  GdkGLContext *current = gdk_display_get_current_gl_context (display);
+
+  if (current == context)
+    return TRUE;
+
+  if (context == NULL)
+    g_object_set_data (G_OBJECT (display), "-gdk-gl-current-context", NULL);
+  else
+    g_object_set_data_full (G_OBJECT (display), "-gdk-gl-current-context",
+                            g_object_ref (context),
+                            (GDestroyNotify) g_object_unref);
+
+  return GDK_DISPLAY_GET_CLASS (display)->make_gl_context_current (display, context, window);
+}
+
+/*< private >
+ * gdk_display_get_current_gl_context:
+ * @display: a #GdkDisplay
+ *
+ * Retrieves the current #GdkGLContext associated with @display.
+ *
+ * Returns: (transfer none): the current #GdkGLContext or %NULL
+ */
+GdkGLContext *
+gdk_display_get_current_gl_context (GdkDisplay *display)
+{
+  return g_object_get_data (G_OBJECT (display), "-gdk-gl-current-context");
+}
+
+/*< private >
+ * gdk_display_validate_gl_pixel_format:
+ * @display: a #GdkDisplay
+ * @format: a #GdkGLPixelFormat
+ * @error: return location for a #GError
+ *
+ * Validates a #GdkGLPixelFormat for the given display.
+ *
+ * If the pixel format is invalid, @error will be set.
+ *
+ * Returns: %TRUE if the pixel format is valid
+ */
+gboolean
+gdk_display_validate_gl_pixel_format (GdkDisplay        *display,
+                                      GdkGLPixelFormat  *format,
+                                      GError           **error)
+{
+  return GDK_DISPLAY_GET_CLASS (display)->validate_gl_pixel_format (display, format, error);
+}
+
+/**
+ * gdk_display_get_gl_context:
+ * @display: a #GdkDisplay
+ * @format: a #GdkGLPixelFormat
+ * @share: (optional): a shared #GdkGLContext, or %NULL
+ *
+ * Creates a new #GdkGLContext for the given display, with the given
+ * pixel format.
+ *
+ * If @share is not %NULL then the newly created #GdkGLContext will
+ * share resources with it.
+ *
+ * Returns: (transfer full): the newly created #GdkGLContext, or
+ *   %NULL on error
+ *
+ * Since: 3.14
+ */
+GdkGLContext *
+gdk_display_get_gl_context (GdkDisplay       *display,
+                            GdkGLPixelFormat *format,
+                            GdkGLContext     *share)
+{
+  g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
+  g_return_val_if_fail (GDK_IS_GL_PIXEL_FORMAT (format), NULL);
+  g_return_val_if_fail (share == NULL || GDK_IS_GL_CONTEXT (share), NULL);
+
+  return gdk_display_create_gl_context (display, format, share);
+}
diff --git a/gdk/gdkdisplay.h b/gdk/gdkdisplay.h
index 5595cb9..a457d89 100644
--- a/gdk/gdkdisplay.h
+++ b/gdk/gdkdisplay.h
@@ -171,6 +171,11 @@ GdkDeviceManager * gdk_display_get_device_manager (GdkDisplay *display);
 GDK_AVAILABLE_IN_ALL
 GdkAppLaunchContext *gdk_display_get_app_launch_context (GdkDisplay *display);
 
+GDK_AVAILABLE_IN_3_14
+GdkGLContext *gdk_display_get_gl_context (GdkDisplay       *display,
+                                          GdkGLPixelFormat *format,
+                                          GdkGLContext     *share);
+
 G_END_DECLS
 
 #endif  /* __GDK_DISPLAY_H__ */
diff --git a/gdk/gdkdisplayprivate.h b/gdk/gdkdisplayprivate.h
index 7911d25..c7fdb71 100644
--- a/gdk/gdkdisplayprivate.h
+++ b/gdk/gdkdisplayprivate.h
@@ -225,6 +225,18 @@ struct _GdkDisplayClass
   gchar *                (*utf8_to_string_target)      (GdkDisplay     *display,
                                                         const gchar    *text);
 
+  GdkGLContext *        (*create_gl_context)        (GdkDisplay        *display,
+                                                     GdkGLPixelFormat  *format,
+                                                     GdkGLContext      *share);
+  gboolean              (*make_gl_context_current)  (GdkDisplay        *display,
+                                                     GdkGLContext      *context,
+                                                     GdkWindow         *drawable);
+  void                  (*destroy_gl_context)       (GdkDisplay        *display,
+                                                     GdkGLContext      *context);
+  gboolean              (*validate_gl_pixel_format) (GdkDisplay        *display,
+                                                     GdkGLPixelFormat  *format,
+                                                     GError           **error);
+
   /* Signals */
   void                   (*opened)                     (GdkDisplay     *display);
   void (*closed) (GdkDisplay *display,
@@ -303,6 +315,19 @@ void                _gdk_display_create_window_impl   (GdkDisplay       *display
                                                        gint              attributes_mask);
 GdkWindow *         _gdk_display_create_window        (GdkDisplay       *display);
 
+gboolean            gdk_display_validate_gl_pixel_format (GdkDisplay        *display,
+                                                          GdkGLPixelFormat  *format,
+                                                          GError           **error);
+GdkGLContext *      gdk_display_create_gl_context        (GdkDisplay        *display,
+                                                          GdkGLPixelFormat  *format,
+                                                          GdkGLContext      *share);
+void                gdk_display_destroy_gl_context       (GdkDisplay        *display,
+                                                          GdkGLContext      *context);
+gboolean            gdk_display_make_gl_context_current  (GdkDisplay        *display,
+                                                          GdkGLContext      *context,
+                                                          GdkWindow         *window);
+GdkGLContext *      gdk_display_get_current_gl_context   (GdkDisplay        *display);
+
 G_END_DECLS
 
 #endif  /* __GDK_DISPLAY_PRIVATE_H__ */
diff --git a/gdk/gdkglcontext.c b/gdk/gdkglcontext.c
new file mode 100644
index 0000000..014e7fa
--- /dev/null
+++ b/gdk/gdkglcontext.c
@@ -0,0 +1,489 @@
+/* GDK - The GIMP Drawing Kit
+ *
+ * gdkglcontext.c: GL context abstraction
+ * 
+ * Copyright © 2014  Emmanuele Bassi
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * SECTION:gdkglcontext
+ * @Title: GdkGLContext
+ * @Short_description: GL contexts
+ *
+ * #GdkGLContext is an object representing the platform-specific
+ * GL drawing context.
+ *
+ * #GdkGLContexts are created via a #GdkDisplay by specifying a
+ * #GdkGLPixelFormat to be used by the GL context.
+ *
+ * Support for #GdkGLContext is platform specific.
+ */
+
+#include "config.h"
+
+#include "gdkglcontextprivate.h"
+#include "gdkdisplayprivate.h"
+#include "gdkglpixelformat.h"
+#include "gdkvisual.h"
+
+#include "gdkintl.h"
+
+typedef struct {
+  GdkDisplay *display;
+  GdkGLPixelFormat *pixel_format;
+  GdkWindow *window;
+  GdkVisual *visual;
+
+  guint swap_interval;
+} GdkGLContextPrivate;
+
+enum {
+  PROP_0,
+
+  PROP_DISPLAY,
+  PROP_PIXEL_FORMAT,
+  PROP_WINDOW,
+  PROP_VISUAL,
+
+  PROP_SWAP_INTERVAL,
+
+  LAST_PROP
+};
+
+static GParamSpec *obj_pspecs[LAST_PROP] = { NULL, };
+
+G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GdkGLContext, gdk_gl_context, G_TYPE_OBJECT)
+
+static void
+gdk_gl_context_dispose (GObject *gobject)
+{
+  GdkGLContext *context = GDK_GL_CONTEXT (gobject);
+  GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
+
+  gdk_display_destroy_gl_context (priv->display, context);
+
+  g_clear_object (&priv->display);
+  g_clear_object (&priv->pixel_format);
+  g_clear_object (&priv->window);
+  g_clear_object (&priv->visual);
+
+  G_OBJECT_CLASS (gdk_gl_context_parent_class)->dispose (gobject);
+}
+
+static void
+gdk_gl_context_set_property (GObject      *gobject,
+                             guint         prop_id,
+                             const GValue *value,
+                             GParamSpec   *pspec)
+{
+  GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private ((GdkGLContext *) gobject);
+
+  switch (prop_id)
+    {
+    case PROP_DISPLAY:
+      priv->display = g_object_ref (g_value_get_object (value));
+      break;
+
+    case PROP_PIXEL_FORMAT:
+      priv->pixel_format = g_object_ref (g_value_get_object (value));
+      break;
+
+    case PROP_WINDOW:
+      {
+        GdkGLContext *context = GDK_GL_CONTEXT (gobject);
+        GdkWindow *window = g_value_get_object (value);
+
+        gdk_gl_context_set_window (context, window);
+      }
+      break;
+
+    case PROP_VISUAL:
+      {
+        GdkVisual *visual = g_value_get_object (value);
+
+        if (visual != NULL)
+          priv->visual = g_object_ref (visual);
+      }
+      break;
+
+    case PROP_SWAP_INTERVAL:
+      priv->swap_interval = g_value_get_uint (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+    }
+}
+
+static void
+gdk_gl_context_get_property (GObject    *gobject,
+                             guint       prop_id,
+                             GValue     *value,
+                             GParamSpec *pspec)
+{
+  GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private ((GdkGLContext *) gobject);
+
+  switch (prop_id)
+    {
+    case PROP_DISPLAY:
+      g_value_set_object (value, priv->display);
+      break;
+
+    case PROP_PIXEL_FORMAT:
+      g_value_set_object (value, priv->pixel_format);
+      break;
+
+    case PROP_WINDOW:
+      g_value_set_object (value, priv->window);
+      break;
+
+    case PROP_VISUAL:
+      g_value_set_object (value, priv->visual);
+      break;
+
+    case PROP_SWAP_INTERVAL:
+      g_value_set_uint (value, priv->swap_interval);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+    }
+}
+
+static void
+gdk_gl_context_class_init (GdkGLContextClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  /**
+   * GdkGLContext:display:
+   *
+   * The #GdkDisplay used by the GL context.
+   *
+   * Since: 3.14
+   */
+  obj_pspecs[PROP_DISPLAY] =
+    g_param_spec_object ("display",
+                         "Display",
+                         "The GDK display used by the GL context",
+                         GDK_TYPE_DISPLAY,
+                         G_PARAM_READWRITE |
+                         G_PARAM_CONSTRUCT_ONLY |
+                         G_PARAM_STATIC_STRINGS);
+
+  /**
+   * GdkGLContext:pixel-format:
+   *
+   * The #GdkGLPixelFormat used to create the GL context.
+   *
+   * Since: 3.14
+   */
+  obj_pspecs[PROP_PIXEL_FORMAT] =
+    g_param_spec_object ("pixel-format",
+                         "Pixel Format",
+                         "The GDK pixel format used by the GL context",
+                         GDK_TYPE_GL_PIXEL_FORMAT,
+                         G_PARAM_READWRITE |
+                         G_PARAM_CONSTRUCT_ONLY |
+                         G_PARAM_STATIC_STRINGS);
+
+  /**
+   * GdkGLContext:window:
+   *
+   * The #GdkWindow currently bound to the GL context.
+   *
+   * You typically need to bind a #GdkWindow to a #GdkGLContext prior
+   * to calling gdk_gl_context_make_current().
+   *
+   * Since: 3.14
+   */
+  obj_pspecs[PROP_WINDOW] =
+    g_param_spec_object ("window",
+                         P_("Window"),
+                         P_("The GDK window currently bound to the GL context"),
+                         GDK_TYPE_WINDOW,
+                         G_PARAM_READWRITE |
+                         G_PARAM_STATIC_STRINGS);
+
+  /**
+   * GdkGLContext:visual:
+   *
+   * The #GdkVisual used by the GL context.
+   *
+   * Since: 3.14
+   */
+  obj_pspecs[PROP_VISUAL] =
+    g_param_spec_object ("visual",
+                         P_("Visual"),
+                         P_("The GDK visual used by the GL context"),
+                         GDK_TYPE_VISUAL,
+                         G_PARAM_READWRITE |
+                         G_PARAM_CONSTRUCT_ONLY |
+                         G_PARAM_STATIC_STRINGS);
+
+  /**
+   * GdkGLContext:swap-interval:
+   *
+   * The swap interval of the GL context.
+   *
+   * If set to 0 (the default), gdk_gl_context_flush_buffer() will execute
+   * the buffer flush as soon as possible.
+   *
+   * If set to 1, calls buffers will be flushed only during the vertical
+   * refresh of the display.
+   *
+   * Since: 3.14
+   */
+  obj_pspecs[PROP_SWAP_INTERVAL] =
+    g_param_spec_uint ("swap-interval",
+                       P_("Swap Interval"),
+                       P_("The swap interval of the GL context"),
+                       0, G_MAXUINT, 0,
+                       G_PARAM_READWRITE |
+                       G_PARAM_STATIC_STRINGS);
+
+  gobject_class->set_property = gdk_gl_context_set_property;
+  gobject_class->get_property = gdk_gl_context_get_property;
+  gobject_class->dispose = gdk_gl_context_dispose;
+
+  g_object_class_install_properties (gobject_class, LAST_PROP, obj_pspecs);
+}
+
+static void
+gdk_gl_context_init (GdkGLContext *self)
+{
+}
+
+/**
+ * gdk_gl_context_get_display:
+ * @context: a #GdkGLContext
+ *
+ * Retrieves the #GdkDisplay associated with the @context.
+ *
+ * Returns: (transfer none): the #GdkDisplay
+ *
+ * Since: 3.14
+ */
+GdkDisplay *
+gdk_gl_context_get_display (GdkGLContext *context)
+{
+  GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
+
+  g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), NULL);
+
+  return priv->display;
+}
+
+/**
+ * gdk_gl_context_get_pixel_format:
+ * @context: a #GdkGLContext
+ *
+ * Retrieves the #GdkGLPixelFormat associated with the @context.
+ *
+ * Returns: (transfer none): the #GdkDisplay
+ *
+ * Since: 3.14
+ */
+GdkGLPixelFormat *
+gdk_gl_context_get_pixel_format (GdkGLContext *context)
+{
+  GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
+
+  g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), NULL);
+
+  return priv->pixel_format;
+}
+
+/**
+ * gdk_gl_context_get_visual:
+ * @context: a #GdkGLContext
+ *
+ * Retrieves the #GdkVisual associated with the @context.
+ *
+ * Returns: (transfer none): the #GdkVisual
+ *
+ * Since: 3.14
+ */
+GdkVisual *
+gdk_gl_context_get_visual (GdkGLContext *context)
+{
+  GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
+
+  g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), NULL);
+
+  return priv->visual;
+}
+
+/**
+ * gdk_gl_context_flush_buffer:
+ * @context: a #GdkGLContext
+ *
+ * Copies the back buffer to the front buffer.
+ *
+ * If the #GdkGLContext is not double buffered, this function does not
+ * do anything.
+ *
+ * Depending on the value of the #GdkGLContext:swap-interval property,
+ * the copy may take place during the vertical refresh of the display
+ * rather than immediately.
+ *
+ * This function calls `glFlush()` implicitly before returning.
+ *
+ * Since: 3.14
+ */
+void
+gdk_gl_context_flush_buffer (GdkGLContext *context)
+{
+  g_return_if_fail (GDK_IS_GL_CONTEXT (context));
+
+  GDK_GL_CONTEXT_GET_CLASS (context)->flush_buffer (context);
+}
+
+/**
+ * gdk_gl_context_make_current:
+ * @context: a #GdkGLContext
+ *
+ * Makes the @context the current one.
+ *
+ * Returns: %TRUE if the context is current
+ *
+ * Since: 3.14
+ */
+gboolean
+gdk_gl_context_make_current (GdkGLContext *context)
+{
+  GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
+
+  g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), FALSE);
+
+  return gdk_display_make_gl_context_current (priv->display, context, priv->window);
+}
+
+/**
+ * gdk_gl_context_set_window:
+ * @context: a #GdkGLContext
+ * @window: (optional): a #GdkWindow, or %NULL
+ *
+ * Sets the #GdkWindow used to display the draw commands.
+ *
+ * If @window is %NULL, the @context is detached from the window.
+ *
+ * Since: 3.14
+ */
+void
+gdk_gl_context_set_window (GdkGLContext *context,
+                           GdkWindow    *window)
+{
+  GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
+
+  g_return_if_fail (GDK_IS_GL_CONTEXT (context));
+  g_return_if_fail (window == NULL || GDK_IS_WINDOW (window));
+
+  if (priv->window == window)
+    return;
+
+  g_clear_object (&priv->window);
+
+  if (window != NULL)
+    priv->window = g_object_ref (window);
+
+  GDK_GL_CONTEXT_GET_CLASS (context)->set_window (context, window);
+}
+
+/**
+ * gdk_gl_context_get_window:
+ * @context: a #GdkGLContext
+ *
+ * Retrieves the #GdkWindow used by the @context.
+ *
+ * Returns: (transfer none): a #GdkWindow or %NULL
+ *
+ * Since: 3.14
+ */
+GdkWindow *
+gdk_gl_context_get_window (GdkGLContext *context)
+{
+  GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
+
+  g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), NULL);
+
+  return priv->window;
+}
+
+/**
+ * gdk_gl_context_update:
+ * @context: a #GdkGLContext
+ *
+ * Updates the @context when the #GdkWindow used to display the
+ * rendering changes size or position.
+ *
+ * Since: 3.14
+ */
+void
+gdk_gl_context_update (GdkGLContext *context)
+{
+  g_return_if_fail (GDK_IS_GL_CONTEXT (context));
+
+  GDK_GL_CONTEXT_GET_CLASS (context)->update (context);
+}
+
+/**
+ * gdk_gl_context_clear_current:
+ *
+ * Clears the current #GdkGLContext.
+ *
+ * Since: 3.14
+ */
+void
+gdk_gl_context_clear_current (void)
+{
+  GdkDisplay *display = gdk_display_get_default ();
+
+  gdk_display_make_gl_context_current (display, NULL, NULL);
+}
+
+/**
+ * gdk_gl_context_get_current:
+ *
+ * Retrieves the current #GdkGLContext.
+ *
+ * Returns: (transfer none): the current #GdkGLContext, or %NULL
+ *
+ * Since: 3.14
+ */
+GdkGLContext *
+gdk_gl_context_get_current (void)
+{
+  GdkDisplay *display = gdk_display_get_default ();
+
+  return gdk_display_get_current_gl_context (display);
+}
+
+/*< private >
+ * gdk_gl_context_get_swap_interval:
+ * @context: a #GdkGLContext
+ *
+ * Retrieves the swap interval of the context.
+ *
+ * Returns: the swap interval
+ */
+guint
+gdk_gl_context_get_swap_interval (GdkGLContext *context)
+{
+  GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
+
+  return priv->swap_interval;
+}
diff --git a/gdk/gdkglcontext.h b/gdk/gdkglcontext.h
new file mode 100644
index 0000000..ff8853d
--- /dev/null
+++ b/gdk/gdkglcontext.h
@@ -0,0 +1,67 @@
+/* GDK - The GIMP Drawing Kit
+ *
+ * gdkglcontext.h: GL context abstraction
+ * 
+ * Copyright © 2014  Emmanuele Bassi
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GDK_GL_CONTEXT_H__
+#define __GDK_GL_CONTEXT_H__
+
+#if !defined (__GDK_H_INSIDE__) && !defined (GDK_COMPILATION)
+#error "Only <gdk/gdk.h> can be included directly."
+#endif
+
+#include <gdk/gdkversionmacros.h>
+#include <gdk/gdktypes.h>
+
+G_BEGIN_DECLS
+
+#define GDK_TYPE_GL_CONTEXT             (gdk_gl_context_get_type ())
+#define GDK_GL_CONTEXT(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_GL_CONTEXT, 
GdkGLContext))
+#define GDK_IS_GL_CONTEXT(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_GL_CONTEXT))
+
+GDK_AVAILABLE_IN_3_14
+GType gdk_gl_context_get_type (void) G_GNUC_CONST;
+
+GDK_AVAILABLE_IN_3_14
+GdkDisplay *            gdk_gl_context_get_display      (GdkGLContext *context);
+
+GDK_AVAILABLE_IN_3_14
+GdkGLPixelFormat *      gdk_gl_context_get_pixel_format (GdkGLContext *context);
+
+GDK_AVAILABLE_IN_3_14
+void                    gdk_gl_context_clear_window     (GdkGLContext *context);
+GDK_AVAILABLE_IN_3_14
+void                    gdk_gl_context_flush_buffer     (GdkGLContext *context);
+GDK_AVAILABLE_IN_3_14
+gboolean                gdk_gl_context_make_current     (GdkGLContext *context);
+GDK_AVAILABLE_IN_3_14
+void                    gdk_gl_context_set_window       (GdkGLContext *context,
+                                                         GdkWindow    *window);
+GDK_AVAILABLE_IN_3_14
+GdkWindow *             gdk_gl_context_get_window       (GdkGLContext *context);
+GDK_AVAILABLE_IN_3_14
+void                    gdk_gl_context_update           (GdkGLContext *context);
+
+GDK_AVAILABLE_IN_3_14
+void                    gdk_gl_context_clear_current    (void);
+GDK_AVAILABLE_IN_3_14
+GdkGLContext *          gdk_gl_context_get_current      (void);
+
+G_END_DECLS
+
+#endif /* __GDK_GL_CONTEXT_H__ */
diff --git a/gdk/gdkglcontextprivate.h b/gdk/gdkglcontextprivate.h
new file mode 100644
index 0000000..6551adb
--- /dev/null
+++ b/gdk/gdkglcontextprivate.h
@@ -0,0 +1,53 @@
+/* GDK - The GIMP Drawing Kit
+ *
+ * gdkglcontextprivate.h: GL context abstraction
+ * 
+ * Copyright © 2014  Emmanuele Bassi
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GDK_GL_CONTEXT_PRIVATE_H__
+#define __GDK_GL_CONTEXT_PRIVATE_H__
+
+#include "gdkglcontext.h"
+
+G_BEGIN_DECLS
+
+#define GDK_GL_CONTEXT_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_GL_CONTEXT, 
GdkGLContextClass))
+#define GDK_IS_GL_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_GL_CONTEXT))
+#define GDK_GL_CONTEXT_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_GL_CONTEXT, 
GdkGLContextClass))
+
+typedef struct _GdkGLContextClass       GdkGLContextClass;
+
+struct _GdkGLContext
+{
+  GObject parent_instance;
+};
+
+struct _GdkGLContextClass
+{
+  GObjectClass parent_class;
+
+  void (* set_window)   (GdkGLContext *context,
+                         GdkWindow    *window);
+  void (* update)       (GdkGLContext *context);
+  void (* flush_buffer) (GdkGLContext *context);
+};
+
+guint   gdk_gl_context_get_swap_interval        (GdkGLContext *context);
+
+G_END_DECLS
+
+#endif /* __GDK_GL_CONTEXT_PRIVATE_H__ */
diff --git a/gdk/gdkglpixelformat.c b/gdk/gdkglpixelformat.c
new file mode 100644
index 0000000..10986e2
--- /dev/null
+++ b/gdk/gdkglpixelformat.c
@@ -0,0 +1,439 @@
+/* GDK - The GIMP Drawing Kit
+ *
+ * gdkglpixelformat.c: GL pixel formats
+ * 
+ * Copyright © 2014  Emmanuele Bassi
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * SECTION:gdkglpixelformat
+ * @Title: GdkGLPixelFormat
+ * @Short_description: Specify the pixel format for GL contexts
+ *
+ * The #GdkGLPixelFormat class is used to specify the types and sizes of
+ * buffers to be used by a #GdkGLContext, as well as other configuration
+ * parameters.
+ *
+ * You should typically try to create a #GdkGLPixelFormat for a given
+ * configuration, and if the creation fails, you can either opt to
+ * show an error, or change the configuration until you find a suitable
+ * pixel format.
+ *
+ * For instance, the following example creates a #GdkGLPixelFormat with
+ * double buffering enabled, and a 32-bit depth buffer:
+ *
+ * |[<!-- language="C" -->
+ *   GdkGLPixelFormat *format;
+ *   GError *error = NULL;
+ *
+ *   format = gdk_gl_pixel_format_new (&error,
+ *                                     "double-buffer", TRUE,
+ *                                     "depth-size", 32,
+ *                                     NULL);
+ *   if (format == NULL)
+ *     {
+ *       // creation failed; try again with a different set
+ *       // of attributes
+ *     }
+ * ]|
+ */
+
+#include "config.h"
+
+#include <gio/gio.h>
+
+#include "gdkglpixelformatprivate.h"
+
+#include "gdkdisplayprivate.h"
+#include "gdkenumtypes.h"
+
+#include "gdkintl.h"
+
+enum {
+  PROP_0,
+
+  PROP_DISPLAY,
+
+  /* bool */
+  PROP_DOUBLE_BUFFER,
+  PROP_MULTI_SAMPLE,
+
+  /* uint */
+  PROP_AUX_BUFFERS,
+  PROP_COLOR_SIZE,
+  PROP_ALPHA_SIZE,
+  PROP_DEPTH_SIZE,
+  PROP_STENCIL_SIZE,
+  PROP_ACCUM_SIZE,
+  PROP_SAMPLE_BUFFERS,
+  PROP_SAMPLES,
+
+  /* enum */
+  PROP_PROFILE,
+
+  LAST_PROP
+};
+
+static GParamSpec *obj_props[LAST_PROP] = { NULL, };
+
+static void initable_iface_init (GInitableIface *init);
+
+G_DEFINE_QUARK (gdk-gl-pixel-format-error-quark, gdk_gl_pixel_format_error)
+
+G_DEFINE_TYPE_WITH_CODE (GdkGLPixelFormat, gdk_gl_pixel_format, G_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
+                                                initable_iface_init))
+
+static gboolean
+gdk_gl_pixel_format_init_internal (GInitable     *initable,
+                                   GCancellable  *cancellable,
+                                   GError       **error)
+{
+  GdkGLPixelFormat *self = GDK_GL_PIXEL_FORMAT (initable);
+
+  /* use the default display */
+  if (self->display == NULL)
+    self->display = g_object_ref (gdk_display_get_default ());
+
+  self->is_valid = gdk_display_validate_gl_pixel_format (self->display, self, error);
+  self->is_validated = TRUE;
+
+  return self->is_valid;
+}
+
+static void
+initable_iface_init (GInitableIface *iface)
+{
+  iface->init = gdk_gl_pixel_format_init_internal;
+}
+
+static void
+gdk_gl_pixel_format_dispose (GObject *gobject)
+{
+  GdkGLPixelFormat *self = GDK_GL_PIXEL_FORMAT (gobject);
+
+  g_clear_object (&self->display);
+
+  G_OBJECT_CLASS (gdk_gl_pixel_format_parent_class)->dispose (gobject);
+}
+
+static void
+gdk_gl_pixel_format_set_property (GObject      *gobject,
+                                  guint         prop_id,
+                                  const GValue *value,
+                                  GParamSpec   *pspec)
+{
+  GdkGLPixelFormat *self = GDK_GL_PIXEL_FORMAT (gobject);
+
+  switch (prop_id)
+    {
+    case PROP_DISPLAY:
+      {
+        GdkDisplay *display = g_value_get_object (value);
+
+        if (display != NULL)
+          self->display = g_object_ref (display);
+      }
+      break;
+
+    case PROP_DOUBLE_BUFFER:
+      self->double_buffer = g_value_get_boolean (value);
+      break;
+
+    case PROP_MULTI_SAMPLE:
+      self->multi_sample = g_value_get_boolean (value);
+      break;
+
+    case PROP_AUX_BUFFERS:
+      self->aux_buffers = g_value_get_int (value);
+      break;
+
+    case PROP_COLOR_SIZE:
+      self->color_size = g_value_get_int (value);
+      break;
+
+    case PROP_ALPHA_SIZE:
+      self->alpha_size = g_value_get_int (value);
+      break;
+
+    case PROP_DEPTH_SIZE:
+      self->depth_size = g_value_get_int (value);
+      break;
+
+    case PROP_STENCIL_SIZE:
+      self->stencil_size = g_value_get_int (value);
+      break;
+
+    case PROP_ACCUM_SIZE:
+      self->accum_size = g_value_get_int (value);
+      break;
+
+    case PROP_SAMPLE_BUFFERS:
+      self->sample_buffers = g_value_get_int (value);
+      break;
+
+    case PROP_SAMPLES:
+      self->samples = g_value_get_int (value);
+      break;
+
+    case PROP_PROFILE:
+      self->profile = g_value_get_enum (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+    }
+}
+
+static void
+gdk_gl_pixel_format_get_property (GObject    *gobject,
+                                  guint       prop_id,
+                                  GValue     *value,
+                                  GParamSpec *pspec)
+{
+  GdkGLPixelFormat *self = GDK_GL_PIXEL_FORMAT (gobject);
+
+  switch (prop_id)
+    {
+    case PROP_DISPLAY:
+      g_value_set_object (value, self->display);
+      break;
+
+    case PROP_DOUBLE_BUFFER:
+      g_value_set_boolean (value, self->double_buffer);
+      break;
+
+    case PROP_MULTI_SAMPLE:
+      g_value_set_boolean (value, self->multi_sample);
+      break;
+
+    case PROP_AUX_BUFFERS:
+      g_value_set_int (value, self->aux_buffers);
+      break;
+
+    case PROP_COLOR_SIZE:
+      g_value_set_int (value, self->color_size);
+      break;
+
+    case PROP_ALPHA_SIZE:
+      g_value_set_int (value, self->alpha_size);
+      break;
+
+    case PROP_DEPTH_SIZE:
+      g_value_set_int (value, self->depth_size);
+      break;
+
+    case PROP_STENCIL_SIZE:
+      g_value_set_int (value, self->stencil_size);
+      break;
+
+    case PROP_ACCUM_SIZE:
+      g_value_set_int (value, self->accum_size);
+      break;
+
+    case PROP_SAMPLE_BUFFERS:
+      g_value_set_int (value, self->sample_buffers);
+      break;
+
+    case PROP_SAMPLES:
+      g_value_set_int (value, self->samples);
+      break;
+
+    case PROP_PROFILE:
+      g_value_set_enum (value, self->profile);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
+    }
+}
+
+static void
+gdk_gl_pixel_format_class_init (GdkGLPixelFormatClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->set_property = gdk_gl_pixel_format_set_property;
+  gobject_class->get_property = gdk_gl_pixel_format_get_property;
+  gobject_class->dispose = gdk_gl_pixel_format_dispose;
+
+  obj_props[PROP_DISPLAY] =
+    g_param_spec_object ("display",
+                         P_("Display"),
+                         P_("The GDK display associated with the pixel format"),
+                         GDK_TYPE_DISPLAY,
+                         G_PARAM_READWRITE |
+                         G_PARAM_CONSTRUCT_ONLY |
+                         G_PARAM_STATIC_STRINGS);
+
+  obj_props[PROP_DOUBLE_BUFFER] =
+    g_param_spec_boolean ("double-buffer",
+                          P_("Double Buffer"),
+                          P_(""),
+                          FALSE,
+                          G_PARAM_READWRITE |
+                          G_PARAM_CONSTRUCT_ONLY |
+                          G_PARAM_STATIC_STRINGS);
+
+  obj_props[PROP_MULTI_SAMPLE] =
+    g_param_spec_boolean ("multi-sample",
+                          P_("Multi Sample"),
+                          P_(""),
+                          FALSE,
+                          G_PARAM_READWRITE |
+                          G_PARAM_CONSTRUCT_ONLY |
+                          G_PARAM_STATIC_STRINGS);
+
+  obj_props[PROP_AUX_BUFFERS] =
+    g_param_spec_int ("aux-buffers",
+                      P_("Auxiliary Buffers"),
+                      P_(""),
+                      -1, G_MAXINT, -1,
+                      G_PARAM_READWRITE |
+                      G_PARAM_CONSTRUCT_ONLY |
+                      G_PARAM_STATIC_STRINGS);
+
+  obj_props[PROP_COLOR_SIZE] =
+    g_param_spec_int ("color-size",
+                      P_("Color Size"),
+                      P_(""),
+                      -1, G_MAXINT, -1,
+                      G_PARAM_READWRITE |
+                      G_PARAM_CONSTRUCT_ONLY |
+                      G_PARAM_STATIC_STRINGS);
+
+  obj_props[PROP_ALPHA_SIZE] =
+    g_param_spec_int ("alpha-size",
+                      P_("Alpha Size"),
+                      P_(""),
+                      -1, G_MAXINT, -1,
+                      G_PARAM_READWRITE |
+                      G_PARAM_CONSTRUCT_ONLY |
+                      G_PARAM_STATIC_STRINGS);
+
+  obj_props[PROP_DEPTH_SIZE] =
+    g_param_spec_int ("depth-size",
+                      P_("Depth Size"),
+                      P_(""),
+                      -1, G_MAXINT, -1,
+                      G_PARAM_READWRITE |
+                      G_PARAM_CONSTRUCT_ONLY |
+                      G_PARAM_STATIC_STRINGS);
+
+  obj_props[PROP_STENCIL_SIZE] =
+    g_param_spec_int ("stencil-size",
+                      P_("Stencil Size"),
+                      P_(""),
+                      -1, G_MAXINT, -1,
+                      G_PARAM_READWRITE |
+                      G_PARAM_CONSTRUCT_ONLY |
+                      G_PARAM_STATIC_STRINGS);
+
+  obj_props[PROP_ACCUM_SIZE] =
+    g_param_spec_int ("accum-size",
+                      P_("Accumulation Size"),
+                      P_(""),
+                      -1, G_MAXINT, -1,
+                      G_PARAM_READWRITE |
+                      G_PARAM_CONSTRUCT_ONLY |
+                      G_PARAM_STATIC_STRINGS);
+
+  obj_props[PROP_SAMPLE_BUFFERS] =
+    g_param_spec_int ("sample-buffers",
+                      P_("Sample Buffers"),
+                      P_(""),
+                      -1, G_MAXINT, -1,
+                      G_PARAM_READWRITE |
+                      G_PARAM_CONSTRUCT_ONLY |
+                      G_PARAM_STATIC_STRINGS);
+
+  obj_props[PROP_SAMPLES] =
+    g_param_spec_int ("samples",
+                      P_("Samples"),
+                      P_(""),
+                      -1, G_MAXINT, -1,
+                      G_PARAM_READWRITE |
+                      G_PARAM_CONSTRUCT_ONLY |
+                      G_PARAM_STATIC_STRINGS);
+
+  obj_props[PROP_PROFILE] =
+    g_param_spec_enum ("profile",
+                       P_("Profile"),
+                       P_(""),
+                       GDK_TYPE_GL_PIXEL_FORMAT_PROFILE,
+                       GDK_GL_PIXEL_FORMAT_PROFILE_DEFAULT,
+                       G_PARAM_READWRITE |
+                       G_PARAM_CONSTRUCT_ONLY |
+                       G_PARAM_STATIC_STRINGS);
+
+  g_object_class_install_properties (gobject_class, LAST_PROP, obj_props);
+}
+
+static void
+gdk_gl_pixel_format_init (GdkGLPixelFormat *self)
+{
+}
+
+/**
+ * gdk_gl_pixel_format_new:
+ * @error: return location for a #GError, or %NULL
+ * @first_property: the first property to set
+ * @...: the value of the @first_property, followed by a %NULL terminated
+ *   set of property, value pairs
+ *
+ * Creates a new #GdkGLPixelFormat with the given list of properties.
+ *
+ * If the pixel format is not valid, then this function will return
+ * a %NULL value, and @error will be set.
+ *
+ * Returns: the newly created #GdkGLPixelFormat, or %NULL
+ *
+ * Since: 3.14
+ */
+GdkGLPixelFormat *
+gdk_gl_pixel_format_new (GError     **error,
+                         const char  *first_property,
+                         ...)
+{
+  gpointer res;
+  va_list args;
+
+  g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+  va_start (args, first_property);
+  res = g_initable_new_valist (GDK_TYPE_GL_PIXEL_FORMAT, first_property, args, NULL, error);
+  va_end (args);
+
+  return res;
+}
+
+/**
+ * gdk_gl_pixel_format_get_display:
+ * @format: a #GdkGLPixelFormat
+ *
+ * Retrieves the #GdkDisplay used to validate the pixel format.
+ *
+ * Returns: (transfer none): the #GdkDisplay
+ *
+ * Since: 3.14
+ */
+GdkDisplay *
+gdk_gl_pixel_format_get_display (GdkGLPixelFormat *format)
+{
+  g_return_val_if_fail (GDK_IS_GL_PIXEL_FORMAT (format), NULL);
+
+  return format->display;
+}
diff --git a/gdk/gdkglpixelformat.h b/gdk/gdkglpixelformat.h
new file mode 100644
index 0000000..9aa9882
--- /dev/null
+++ b/gdk/gdkglpixelformat.h
@@ -0,0 +1,55 @@
+/* GDK - The GIMP Drawing Kit
+ *
+ * gdkglpixelformat.h: GL pixel formats
+ * 
+ * Copyright © 2014  Emmanuele Bassi
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GDK_GL_PIXEL_FORMAT_H__
+#define __GDK_GL_PIXEL_FORMAT_H__
+
+#if !defined (__GDK_H_INSIDE__) && !defined (GDK_COMPILATION)
+#error "Only <gdk/gdk.h> can be included directly."
+#endif
+
+#include <gdk/gdkversionmacros.h>
+#include <gdk/gdktypes.h>
+
+G_BEGIN_DECLS
+
+#define GDK_TYPE_GL_PIXEL_FORMAT        (gdk_gl_pixel_format_get_type ())
+#define GDK_GL_PIXEL_FORMAT(obj)        (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_GL_PIXEL_FORMAT, 
GdkGLPixelFormat))
+#define GDK_IS_GL_PIXEL_FORMAT(obj)     (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_GL_PIXEL_FORMAT))
+
+#define GDK_GL_PIXEL_FORMAT_ERROR       (gdk_gl_pixel_format_error_quark ())
+
+typedef struct _GdkGLPixelFormatClass   GdkGLPixelFormatClass;
+
+GDK_AVAILABLE_IN_3_14
+GType gdk_gl_pixel_format_get_type (void) G_GNUC_CONST;
+GDK_AVAILABLE_IN_3_14
+GQuark gdk_gl_pixel_format_error_quark (void);
+
+GDK_AVAILABLE_IN_3_14
+GdkGLPixelFormat *      gdk_gl_pixel_format_new         (GError **error,
+                                                         const char *first_property,
+                                                         ...);
+GDK_AVAILABLE_IN_3_14
+GdkDisplay *            gdk_gl_pixel_format_get_display (GdkGLPixelFormat *format);
+
+G_END_DECLS
+
+#endif /* __GDK_GL_PIXEL_FORMAT_H__ */
diff --git a/gdk/gdkglpixelformatprivate.h b/gdk/gdkglpixelformatprivate.h
new file mode 100644
index 0000000..fd9e614
--- /dev/null
+++ b/gdk/gdkglpixelformatprivate.h
@@ -0,0 +1,43 @@
+#ifndef __GDK_GL_PIXEL_FORMAT_PRIVATE_H__
+#define __GDK_GL_PIXEL_FORMAT_PRIVATE_H__
+
+#include "gdkglpixelformat.h"
+
+G_BEGIN_DECLS
+
+#define GDK_GL_PIXEL_FORMAT_CLASS(klass)        (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_GL_PIXEL_FORMAT, 
GdkGLPixelFormatClass))
+#define GDK_IS_GL_PIXEL_FORMAT_CLASS(klass)     (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_GL_PIXEL_FORMAT))
+#define GDK_GL_PIXEL_FORMAT_GET_CLASS(obj)      (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_GL_PIXEL_FORMAT, 
GdkGLPixelFormatClass))
+
+struct _GdkGLPixelFormat
+{
+  GObject parent_instance;
+
+  gboolean is_validated;
+  gboolean is_valid;
+
+  GdkDisplay *display;
+
+  gboolean double_buffer;
+  gboolean multi_sample;
+
+  int aux_buffers;
+  int color_size;
+  int alpha_size;
+  int depth_size;
+  int stencil_size;
+  int accum_size;
+  int sample_buffers;
+  int samples;
+
+  GdkGLPixelFormatProfile profile;
+};
+
+struct _GdkGLPixelFormatClass
+{
+  GObjectClass parent_class;
+};
+
+G_END_DECLS
+
+#endif /* __GDK_GL_PIXEL_FORMAT_PRIVATE_H__ */
diff --git a/gdk/gdkinternals.h b/gdk/gdkinternals.h
index f58ccb0..791fa87 100644
--- a/gdk/gdkinternals.h
+++ b/gdk/gdkinternals.h
@@ -84,7 +84,8 @@ typedef enum {
   GDK_DEBUG_DRAW          = 1 <<  9,
   GDK_DEBUG_EVENTLOOP     = 1 << 10,
   GDK_DEBUG_FRAMES        = 1 << 11,
-  GDK_DEBUG_SETTINGS      = 1 << 12
+  GDK_DEBUG_SETTINGS      = 1 << 12,
+  GDK_DEBUG_OPENGL        = 1 << 13
 } GdkDebugFlag;
 
 typedef enum {
diff --git a/gdk/gdktypes.h b/gdk/gdktypes.h
index be768a7..4d6e8cc 100644
--- a/gdk/gdktypes.h
+++ b/gdk/gdktypes.h
@@ -128,6 +128,9 @@ typedef struct _GdkWindow             GdkWindow;
 typedef struct _GdkKeymap             GdkKeymap;
 typedef struct _GdkAppLaunchContext   GdkAppLaunchContext;
 
+typedef struct _GdkGLPixelFormat      GdkGLPixelFormat;
+typedef struct _GdkGLContext          GdkGLContext;
+
 /**
  * GdkByteOrder:
  * @GDK_LSB_FIRST: The values are stored with the least-significant byte
@@ -429,8 +432,25 @@ struct _GdkPoint
   gint y;
 };
 
+/**
+ * GdkGLPixelFormatProfile:
+ * @GDK_GL_PIXEL_FORMAT_PROFILE_DEFAULT: ...
+ * @GDK_GL_PIXEL_FORMAT_PROFILE_LEGACY: ...
+ * @GDK_GL_PIXEL_FORMAT_PROFILE_3_2_CORE: ...
+ *
+ * ...
+ */
+typedef enum {
+  GDK_GL_PIXEL_FORMAT_PROFILE_DEFAULT,
+  GDK_GL_PIXEL_FORMAT_PROFILE_LEGACY,
+  GDK_GL_PIXEL_FORMAT_PROFILE_3_2_CORE
+} GdkGLPixelFormatProfile;
+
+typedef enum {
+  GDK_GL_PIXEL_FORMAT_ERROR_INVALID_FORMAT,
+  GDK_GL_PIXEL_FORMAT_ERROR_NOT_AVAILABLE
+} GdkGLPixelFormatError;
 
 G_END_DECLS
 
-
 #endif /* __GDK_TYPES_H__ */
diff --git a/gdk/x11/Makefile.am b/gdk/x11/Makefile.am
index 5930f7e..36e39f0 100644
--- a/gdk/x11/Makefile.am
+++ b/gdk/x11/Makefile.am
@@ -39,6 +39,8 @@ libgdk_x11_la_SOURCES =       \
        gdkeventtranslator.c    \
        gdkeventtranslator.h    \
        gdkgeometry-x11.c       \
+       gdkglcontext-x11.c      \
+       gdkglcontext-x11.h      \
        gdkkeys-x11.c           \
        gdkmain-x11.c           \
        gdkproperty-x11.c       \
@@ -71,6 +73,7 @@ libgdkx11include_HEADERS =    \
        gdkx11display.h         \
        gdkx11displaymanager.h  \
        gdkx11dnd.h             \
+       gdkx11glcontext.h       \
        gdkx11keys.h            \
        gdkx11property.h        \
        gdkx11screen.h          \
diff --git a/gdk/x11/gdkdisplay-x11.c b/gdk/x11/gdkdisplay-x11.c
index 1db4742..1837347 100644
--- a/gdk/x11/gdkdisplay-x11.c
+++ b/gdk/x11/gdkdisplay-x11.c
@@ -37,6 +37,7 @@
 #include "gdkdisplay-x11.h"
 #include "gdkprivate-x11.h"
 #include "gdkscreen-x11.h"
+#include "gdkglcontext-x11.h"
 
 #include <glib.h>
 #include <glib/gprintf.h>
@@ -2903,5 +2904,10 @@ gdk_x11_display_class_init (GdkX11DisplayClass * class)
   display_class->text_property_to_utf8_list = _gdk_x11_display_text_property_to_utf8_list;
   display_class->utf8_to_string_target = _gdk_x11_display_utf8_to_string_target;
 
+  display_class->validate_gl_pixel_format = gdk_x11_display_validate_gl_pixel_format;
+  display_class->create_gl_context = gdk_x11_display_create_gl_context;
+  display_class->destroy_gl_context = gdk_x11_display_destroy_gl_context;
+  display_class->make_gl_context_current = gdk_x11_display_make_gl_context_current;
+
   _gdk_x11_windowing_init ();
 }
diff --git a/gdk/x11/gdkdisplay-x11.h b/gdk/x11/gdkdisplay-x11.h
index 69ba890..07d2cb9 100644
--- a/gdk/x11/gdkdisplay-x11.h
+++ b/gdk/x11/gdkdisplay-x11.h
@@ -124,6 +124,20 @@ struct _GdkX11Display
   GSList *error_traps;
 
   gint wm_moveresize_button;
+
+  /* GLX information */
+  guint have_glx : 1;
+  gint glx_version;
+  gint glx_error_base;
+  gint glx_event_base;
+
+  /* GLX extensions we check */
+  guint has_glx_swap_interval : 1;
+  guint has_glx_create_context : 1;
+  guint has_glx_texture_from_pixmap : 1;
+  guint has_glx_video_sync : 1;
+  guint has_glx_buffer_age : 1;
+  guint has_glx_sync_control : 1;
 };
 
 struct _GdkX11DisplayClass
diff --git a/gdk/x11/gdkglcontext-x11.c b/gdk/x11/gdkglcontext-x11.c
new file mode 100644
index 0000000..aee0bf8
--- /dev/null
+++ b/gdk/x11/gdkglcontext-x11.c
@@ -0,0 +1,691 @@
+#include "config.h"
+
+#include "gdkglcontext-x11.h"
+#include "gdkdisplay-x11.h"
+#include "gdkscreen-x11.h"
+
+#include "gdkx11display.h"
+#include "gdkx11glcontext.h"
+#include "gdkx11screen.h"
+#include "gdkx11window.h"
+#include "gdkx11visual.h"
+
+#include "gdkintl.h"
+
+#include <GL/glx.h>
+
+G_DEFINE_TYPE (GdkX11GLContext, gdk_x11_gl_context, GDK_TYPE_GL_CONTEXT)
+
+typedef struct {
+  GLXDrawable drawable;
+
+  GdkDisplay *display;
+  GdkGLContext *context;
+  GdkWindow *window;
+} DrawableInfo;
+
+static void
+drawable_info_free (gpointer data_)
+{
+  DrawableInfo *data = data_;
+
+  glXDestroyWindow (gdk_x11_display_get_xdisplay (data->display), data->drawable);
+
+  g_slice_free (DrawableInfo, data);
+}
+
+static DrawableInfo *
+get_glx_drawable_info (GdkWindow *window)
+{
+  return g_object_get_data (G_OBJECT (window), "-gdk-x11-window-glx-info");
+}
+
+static void
+set_glx_drawable_info (GdkWindow    *window,
+                       DrawableInfo *info)
+{
+  g_object_set_data_full (G_OBJECT (window), "-gdk-x11-window-glx-info",
+                          info,
+                          drawable_info_free);
+}
+
+static void
+gdk_x11_gl_context_set_window (GdkGLContext *context,
+                               GdkWindow    *window)
+{
+  GdkX11GLContext *context_x11 = GDK_X11_GL_CONTEXT (context);
+  GdkDisplay *display = gdk_gl_context_get_display (context);
+  DrawableInfo *info;
+
+  if (window == NULL)
+    {
+      gdk_x11_display_make_gl_context_current (display, context, NULL);
+      return;
+    }
+
+  /* we need to make sure that the GdkWindow is backed by
+   * an actual native surface
+   */
+  gdk_window_ensure_native (window);
+
+  /* GLX < 1.3 accepts X11 drawables, so there's no need to
+   * go through the creation of a GLX drawable
+   */
+  if (GDK_X11_DISPLAY (display)->glx_version < 13)
+    return;
+
+  info = get_glx_drawable_info (window);
+  if (info != NULL)
+    return;
+
+  gdk_x11_display_error_trap_push (display);
+
+  info = g_slice_new (DrawableInfo);
+  info->window = window;
+  info->context = context;
+  info->display = display;
+  info->drawable = glXCreateWindow (gdk_x11_display_get_xdisplay (display),
+                                    context_x11->glx_config,
+                                    gdk_x11_window_get_xid (window),
+                                    NULL);
+
+  gdk_x11_display_error_trap_pop_ignored (display);
+
+  set_glx_drawable_info (window, info);
+}
+
+static void
+gdk_x11_gl_context_update (GdkGLContext *context)
+{
+  GdkWindow *window = gdk_gl_context_get_window (context);
+  int x, y, width, height;
+
+  if (window == NULL)
+    return;
+
+  if (!gdk_gl_context_make_current (context))
+    return;
+
+  gdk_window_get_geometry (window, &x, &y, &width, &height);
+  glViewport (0, 0, width, height);
+}
+
+static void
+gdk_x11_gl_context_flush_buffer (GdkGLContext *context)
+{
+  GdkDisplay *display = gdk_gl_context_get_display (context);
+  GdkWindow *window = gdk_gl_context_get_window (context);
+  DrawableInfo *info;
+  GLXDrawable drawable;
+
+  if (window == NULL)
+    return;
+
+  info = get_glx_drawable_info (window);
+  if (info != NULL && info->drawable != None)
+    drawable = info->drawable;
+  else
+    drawable = gdk_x11_window_get_xid (window);
+
+  GDK_NOTE (OPENGL, g_print ("Flushing GLX buffers for %lu\n", (unsigned long) drawable));
+
+  glFinish ();
+
+  glXSwapBuffers (gdk_x11_display_get_xdisplay (display), drawable);
+}
+
+static void
+gdk_x11_gl_context_class_init (GdkX11GLContextClass *klass)
+{
+  GdkGLContextClass *context_class = GDK_GL_CONTEXT_CLASS (klass);
+
+  context_class->set_window = gdk_x11_gl_context_set_window;
+  context_class->update = gdk_x11_gl_context_update;
+  context_class->flush_buffer = gdk_x11_gl_context_flush_buffer;
+}
+
+static void
+gdk_x11_gl_context_init (GdkX11GLContext *self)
+{
+}
+
+gboolean
+gdk_x11_display_init_gl (GdkDisplay *display)
+{
+  GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
+  GdkScreen *screen;
+  Display *dpy;
+  int error_base, event_base;
+  int screen_num;
+
+  if (display_x11->have_glx)
+    return TRUE;
+
+  dpy = gdk_x11_display_get_xdisplay (display);
+
+  if (!glXQueryExtension (dpy, &error_base, &event_base))
+    return FALSE;
+
+  screen = gdk_display_get_default_screen (display);
+  screen_num = GDK_X11_SCREEN (screen)->screen_num;
+
+  display_x11->have_glx = TRUE;
+
+  display_x11->glx_version = epoxy_glx_version (dpy, screen_num);
+  display_x11->glx_error_base = error_base;
+  display_x11->glx_event_base = event_base;
+
+  display_x11->has_glx_create_context =
+    epoxy_has_glx_extension (dpy, screen_num, "GLX_ARB_create_context_profile");
+  display_x11->has_glx_swap_interval =
+    epoxy_has_glx_extension (dpy, screen_num, "GLX_SGI_swap_control");
+  display_x11->has_glx_texture_from_pixmap =
+    epoxy_has_glx_extension (dpy, screen_num, "GLX_EXT_texture_from_pixmap");
+  display_x11->has_glx_video_sync =
+    epoxy_has_glx_extension (dpy, screen_num, "GLX_SGI_video_sync");
+  display_x11->has_glx_buffer_age =
+    epoxy_has_glx_extension (dpy, screen_num, "GLX_EXT_buffer_age");
+  display_x11->has_glx_sync_control =
+    epoxy_has_glx_extension (dpy, screen_num, "GLX_OML_sync_control");
+
+  GDK_NOTE (OPENGL,
+            g_print ("GLX version %d.%d found\n"
+                     " - Vendor: %s\n"
+                     " - Checked extensions:\n"
+                     "\t* GLX_ARB_create_context_profile: %s\n"
+                     "\t* GLX_SGI_swap_control: %s\n"
+                     "\t* GLX_EXT_texture_from_pixmap: %s\n"
+                     "\t* GLX_SGI_video_sync: %s\n"
+                     "\t* GLX_EXT_buffer_age: %s\n"
+                     "\t* GLX_OML_sync_control: %s\n",
+                     display_x11->glx_version / 10,
+                     display_x11->glx_version % 10,
+                     glXGetClientString (dpy, GLX_VENDOR),
+                     display_x11->has_glx_create_context ? "yes" : "no",
+                     display_x11->has_glx_swap_interval ? "yes" : "no",
+                     display_x11->has_glx_texture_from_pixmap ? "yes" : "no",
+                     display_x11->has_glx_video_sync ? "yes" : "no",
+                     display_x11->has_glx_buffer_age ? "yes" : "no",
+                     display_x11->has_glx_sync_control ? "yes" : "no"));
+
+  return TRUE;
+}
+
+#define MAX_GLX_ATTRS   30
+
+static void
+get_glx_attributes_for_pixel_format (GdkGLPixelFormat *format,
+                                     int              *attrs)
+{
+  GdkX11Display *display_x11;
+  int i = 0;
+
+  attrs[i++] = GLX_DRAWABLE_TYPE;
+  attrs[i++] = GLX_WINDOW_BIT;
+
+  attrs[i++] = GLX_RENDER_TYPE;
+  attrs[i++] = GLX_RGBA_BIT;
+
+  if (format->double_buffer)
+    {
+      attrs[i++] = GLX_DOUBLEBUFFER;
+      attrs[i++] = GL_TRUE;
+    }
+
+  if (format->color_size < 0)
+    {
+      attrs[i++] = GLX_RED_SIZE;
+      attrs[i++] = 1;
+      attrs[i++] = GLX_GREEN_SIZE;
+      attrs[i++] = 1;
+      attrs[i++] = GLX_BLUE_SIZE;
+      attrs[i++] = 1;
+    }
+  else
+    {
+      int channel_size = format->color_size / 4;
+
+      attrs[i++] = GLX_RED_SIZE;
+      attrs[i++] = channel_size;
+      attrs[i++] = GLX_GREEN_SIZE;
+      attrs[i++] = channel_size;
+      attrs[i++] = GLX_BLUE_SIZE;
+      attrs[i++] = channel_size;
+    }
+
+  if (format->alpha_size < 0)
+    {
+      attrs[i++] = GLX_ALPHA_SIZE;
+      attrs[i++] = 1;
+    }
+  else if (format->alpha_size == 0)
+    {
+      attrs[i++] = GLX_ALPHA_SIZE;
+      attrs[i++] = GLX_DONT_CARE;
+    }
+  else
+    {
+      attrs[i++] = GLX_ALPHA_SIZE;
+      attrs[i++] = format->alpha_size;
+    }
+
+  if (format->depth_size < 0)
+    {
+      attrs[i++] = GLX_DEPTH_SIZE;
+      attrs[i++] = 1;
+    }
+  else
+    {
+      attrs[i++] = GLX_DEPTH_SIZE;
+      attrs[i++] = format->depth_size;
+    }
+
+  if (format->stencil_size < 0)
+    {
+      attrs[i++] = GLX_STENCIL_SIZE;
+      attrs[i++] = GLX_DONT_CARE;
+    }
+  else
+    {
+      attrs[i++] = GLX_STENCIL_SIZE;
+      attrs[i++] = format->stencil_size;
+    }
+
+  display_x11 = GDK_X11_DISPLAY (format->display);
+  if (display_x11->glx_version >= 14 && format->multi_sample)
+    {
+      attrs[i++] = GLX_SAMPLE_BUFFERS;
+      attrs[i++] = format->sample_buffers > 0 ? format->sample_buffers : 1;
+
+      attrs[i++] = GLX_SAMPLES;
+      attrs[i++] = format->samples;
+    }
+
+  attrs[i++] = None;
+
+  g_assert (i < MAX_GLX_ATTRS);
+}
+
+static gboolean
+find_fbconfig_for_pixel_format (GdkDisplay        *display,
+                                GdkGLPixelFormat  *format,
+                                GLXFBConfig       *fb_config_out,
+                                XVisualInfo      **visinfo_out,
+                                GError           **error)
+{
+  static int attrs[MAX_GLX_ATTRS];
+
+  Display *dpy = gdk_x11_display_get_xdisplay (display);
+  GLXFBConfig *configs;
+  int n_configs, i;
+  gboolean use_rgba;
+  gboolean retval = FALSE;
+
+  if (format->display == NULL)
+    return retval;
+
+  get_glx_attributes_for_pixel_format (format, attrs);
+
+  use_rgba = format->alpha_size != 0;
+
+  configs = glXChooseFBConfig (dpy, DefaultScreen (dpy), attrs, &n_configs);
+  if (configs == NULL || n_configs == 0)
+    {
+      g_set_error_literal (error, GDK_GL_PIXEL_FORMAT_ERROR,
+                           GDK_GL_PIXEL_FORMAT_ERROR_NOT_AVAILABLE,
+                           _("No available configurations for the given pixel format"));
+      return FALSE;
+    }
+
+  /* if we don't care about an alpha channel, then the first
+   * valid configuration is the one we give back
+   */
+  if (!use_rgba)
+    {
+      if (fb_config_out != NULL)
+        *fb_config_out = configs[0];
+
+      if (visinfo_out != NULL)
+        *visinfo_out = glXGetVisualFromFBConfig (dpy, configs[0]);
+
+      retval = TRUE;
+      goto out;
+    }
+
+  for (i = 0; i < n_configs; i++)
+    {
+      XVisualInfo *visinfo;
+      unsigned long mask;
+
+      visinfo = glXGetVisualFromFBConfig (dpy, configs[i]);
+      if (visinfo == NULL)
+        continue;
+
+      mask = visinfo->red_mask | visinfo->green_mask | visinfo->blue_mask;
+      if (visinfo->depth == 32 && mask != 0xffffffff)
+        {
+          if (fb_config_out != NULL)
+            *fb_config_out = configs[i];
+
+          if (visinfo_out != NULL)
+            *visinfo_out = visinfo;
+
+          retval = TRUE;
+          goto out;
+        }
+    }
+    
+  g_set_error (error, GDK_GL_PIXEL_FORMAT_ERROR,
+               GDK_GL_PIXEL_FORMAT_ERROR_NOT_AVAILABLE,
+               _("No available configurations for the given RGBA pixel format"));
+
+out:
+  XFree (configs);
+
+  return retval;
+}
+
+static GLXContext
+create_gl3_context (GdkDisplay   *display,
+                    GLXFBConfig   config,
+                    GdkGLContext *share)
+{
+  static const int attrib_list[] = {
+    GLX_CONTEXT_PROFILE_MASK_ARB,  GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
+    GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
+    GLX_CONTEXT_MAJOR_VERSION_ARB, 2,
+    None,
+  };
+
+  GdkX11GLContext *context_x11 = NULL;
+
+  if (share != NULL)
+    context_x11 = GDK_X11_GL_CONTEXT (share);
+
+  return glXCreateContextAttribsARB (gdk_x11_display_get_xdisplay (display),
+                                     config,
+                                     context_x11 != NULL ? context_x11->glx_context : NULL,
+                                     True,
+                                     attrib_list);
+}
+
+static GLXContext
+create_gl_context (GdkDisplay   *display,
+                   GLXFBConfig   config,
+                   GdkGLContext *share)
+{
+  GdkX11GLContext *context_x11 = NULL;
+
+  if (share != NULL)
+    context_x11 = GDK_X11_GL_CONTEXT (share);
+
+  return glXCreateNewContext (gdk_x11_display_get_xdisplay (display),
+                              config,
+                              GLX_RGBA_TYPE,
+                              context_x11 != NULL ? context_x11->glx_context : NULL,
+                              True);
+}
+
+GdkGLContext *
+gdk_x11_display_create_gl_context (GdkDisplay       *display,
+                                   GdkGLPixelFormat *format,
+                                   GdkGLContext     *share)
+{
+  GdkX11GLContext *context;
+  GdkVisual *gdk_visual;
+  GLXFBConfig config;
+  GLXContext glx_context;
+  Window dummy_xwin;
+  GLXWindow dummy_glx;
+  GLXWindow dummy_drawable;
+  gboolean is_direct;
+  XVisualInfo *xvisinfo;
+  XSetWindowAttributes attrs;
+  unsigned long mask;
+  Display *dpy;
+  GError *error;
+
+  if (!gdk_x11_display_init_gl (display))
+    return NULL;
+
+  if (G_UNLIKELY (!format->is_validated))
+    {
+      /* force a validation */
+      format->is_valid = gdk_x11_display_validate_gl_pixel_format (display, format, NULL);
+      format->is_validated = TRUE;
+    }
+
+  if (!format->is_valid)
+    {
+      g_critical ("The GdkGLPixelFormat is not valid.");
+      return NULL;
+    }
+
+  dpy = gdk_x11_display_get_xdisplay (display);
+
+  error = NULL;
+  find_fbconfig_for_pixel_format (display, format, &config, &xvisinfo, &error);
+  if (error != NULL)
+    {
+      g_critical ("%s", error->message);
+      g_error_free (error);
+      return NULL;
+    }
+
+  /* we check for the GLX_ARB_create_context_profile extension
+   * while validating the PixelFormat
+   */
+  if (format->profile == GDK_GL_PIXEL_FORMAT_PROFILE_3_2_CORE)
+    glx_context = create_gl3_context (display, config, share);
+  else
+    glx_context = create_gl_context (display, config, share);
+
+  if (glx_context == NULL)
+    {
+      g_critical ("Unable to create a GLX context");
+      return NULL;
+    }
+
+  is_direct = glXIsDirect (dpy, glx_context);
+
+  gdk_x11_display_error_trap_push (display);
+
+  /* create a dummy window; this is needed because GLX does not allow
+   * us to query the context until it's bound to a drawable; we simply
+   * create a small OR window, put it off screen, and never map it. in
+   * order to keep the GL machinery in a sane state, we always make
+   * the dummy window the current drawable if the user unsets the
+   * GdkWindow bound to the GdkGLContext.
+   */
+  attrs.override_redirect = True;
+  attrs.colormap = XCreateColormap (dpy, DefaultRootWindow (dpy), xvisinfo->visual, AllocNone);
+  attrs.border_pixel = 0;
+  mask = CWOverrideRedirect | CWColormap | CWBorderPixel;
+
+  dummy_xwin = XCreateWindow (dpy, DefaultRootWindow (dpy),
+                              -100, -100, 1, 1,
+                              0,
+                              xvisinfo->depth,
+                              CopyFromParent,
+                              xvisinfo->visual,
+                              mask,
+                              &attrs);
+
+  /* GLX API introduced in 1.3 expects GLX drawables */
+  if (GDK_X11_DISPLAY (display)->glx_version >= 13)
+    dummy_glx = glXCreateWindow (dpy, config, dummy_xwin, NULL);
+  else
+    dummy_glx = None;
+
+  dummy_drawable = dummy_glx != None
+                 ? dummy_glx
+                 : dummy_xwin;
+
+  glXMakeContextCurrent (dpy, dummy_drawable, dummy_drawable, glx_context);
+
+  gdk_visual = gdk_x11_screen_lookup_visual (gdk_display_get_default_screen (display),
+                                             xvisinfo->visualid);
+
+  XFree (xvisinfo);
+
+  if (gdk_x11_display_error_trap_pop (display))
+    return NULL;
+
+  GDK_NOTE (OPENGL,
+            g_print ("Created GLX context[%p], %s, dummy drawable: %lu\n",
+                     glx_context,
+                     is_direct ? "direct" : "indirect",
+                     (unsigned long) dummy_xwin));
+
+  context = g_object_new (GDK_X11_TYPE_GL_CONTEXT,
+                          "display", display,
+                          "pixel-format", format,
+                          "visual", gdk_visual,
+                          NULL);
+
+  context->glx_config = config;
+  context->glx_context = glx_context;
+  context->dummy_drawable = dummy_xwin;
+  context->dummy_glx_drawable = dummy_glx;
+  context->current_drawable = dummy_drawable;
+  context->is_direct = is_direct;
+
+  return GDK_GL_CONTEXT (context);
+}
+
+void
+gdk_x11_display_destroy_gl_context (GdkDisplay   *display,
+                                    GdkGLContext *context)
+{
+  GdkX11GLContext *context_x11 = GDK_X11_GL_CONTEXT (context);
+  Display *dpy = gdk_x11_display_get_xdisplay (display);
+
+  if (context_x11->glx_context != NULL)
+    {
+      if (glXGetCurrentContext () == context_x11->glx_context)
+        glXMakeContextCurrent (dpy, None, None, NULL);
+
+      GDK_NOTE (OPENGL, g_print ("Destroying GLX context\n"));
+      glXDestroyContext (dpy, context_x11->glx_context);
+      context_x11->glx_context = NULL;
+    }
+
+  if (context_x11->dummy_glx_drawable)
+    {
+      GDK_NOTE (OPENGL, g_print ("Destroying dummy GLX drawable\n"));
+      glXDestroyWindow (dpy, context_x11->dummy_glx_drawable);
+      context_x11->dummy_glx_drawable = None;
+    }
+
+  if (context_x11->dummy_drawable)
+    {
+      GDK_NOTE (OPENGL, g_print ("Destroying dummy drawable\n"));
+      XDestroyWindow (dpy, context_x11->dummy_drawable);
+      context_x11->dummy_drawable = None;
+    }
+}
+
+gboolean
+gdk_x11_display_make_gl_context_current (GdkDisplay   *display,
+                                         GdkGLContext *context,
+                                         GdkWindow    *window)
+{
+  GdkX11GLContext *context_x11 = GDK_X11_GL_CONTEXT (context);
+  GLXDrawable drawable = None;
+
+  if (context_x11->glx_context == NULL)
+    return FALSE;
+
+  if (window == NULL)
+    {
+      /* we re-bind our dummy drawable, so that the context
+       * can still be used for queries
+       */
+      drawable = context_x11->dummy_glx_drawable != None
+               ? context_x11->dummy_glx_drawable
+               : context_x11->dummy_drawable;
+    }
+  else
+    {
+      DrawableInfo *info = get_glx_drawable_info (window);
+
+      if (info != NULL && info->drawable != None)
+        drawable = info->drawable;
+      else
+        drawable = gdk_x11_window_get_xid (window);
+    }
+
+  if (G_UNLIKELY (drawable == None))
+    return FALSE;
+
+  GDK_NOTE (OPENGL,
+            g_print ("Making GLX context current to drawable %lu (dummy: %s)\n",
+                     (unsigned long) drawable,
+                     drawable == context_x11->dummy_drawable ? "yes" : "no"));
+
+  if (drawable == context_x11->current_drawable)
+    return TRUE;
+
+  gdk_x11_display_error_trap_push (display);
+
+  glXMakeContextCurrent (gdk_x11_display_get_xdisplay (display),
+                         drawable, drawable,
+                         context_x11->glx_context);
+
+  XSync (gdk_x11_display_get_xdisplay (display), False);
+
+  if (gdk_x11_display_error_trap_pop (display))
+    {
+      g_critical ("X Error received while calling glXMakeContextCurrent()");
+      return FALSE;
+    }
+
+  context_x11->current_drawable = drawable;
+
+  return TRUE;
+}
+
+gboolean
+gdk_x11_display_validate_gl_pixel_format (GdkDisplay        *display,
+                                          GdkGLPixelFormat  *format,
+                                          GError           **error)
+{
+  /* shortcut in case we already validated this PixelFormat */
+  if (format->is_validated)
+    {
+      if (!format->is_valid)
+        {
+          g_set_error_literal (error, GDK_GL_PIXEL_FORMAT_ERROR,
+                               GDK_GL_PIXEL_FORMAT_ERROR_INVALID_FORMAT,
+                               _("Invalid pixel format"));
+        }
+
+      return format->is_valid;
+    }
+
+  if (!gdk_x11_display_init_gl (display))
+    {
+      g_set_error_literal (error, GDK_GL_PIXEL_FORMAT_ERROR,
+                           GDK_GL_PIXEL_FORMAT_ERROR_NOT_AVAILABLE,
+                           _("No GL implementation is available"));
+      return FALSE;
+    }
+
+  if (format->profile == GDK_GL_PIXEL_FORMAT_PROFILE_3_2_CORE)
+    {
+      if (!GDK_X11_DISPLAY (display)->has_glx_create_context)
+        {
+          g_set_error_literal (error, GDK_GL_PIXEL_FORMAT_ERROR,
+                               GDK_GL_PIXEL_FORMAT_ERROR_NOT_AVAILABLE,
+                               _("The GLX_ARB_create_context_profile extension "
+                                 "needed to create 3.2 core profiles is not "
+                                 "available"));
+          return FALSE;
+        }
+    }
+
+  if (!find_fbconfig_for_pixel_format (display, format, NULL, NULL, error))
+    return FALSE;
+
+  return TRUE;
+}
diff --git a/gdk/x11/gdkglcontext-x11.h b/gdk/x11/gdkglcontext-x11.h
new file mode 100644
index 0000000..3c83548
--- /dev/null
+++ b/gdk/x11/gdkglcontext-x11.h
@@ -0,0 +1,56 @@
+#ifndef __GDK_X11_GL_CONTEXT__
+#define __GDK_X11_GL_CONTEXT__
+
+#include <X11/X.h>
+#include <X11/Xlib.h>
+
+#include <epoxy/gl.h>
+#include <epoxy/glx.h>
+
+#include "gdkglcontextprivate.h"
+#include "gdkglpixelformatprivate.h"
+#include "gdkdisplayprivate.h"
+#include "gdkglpixelformat.h"
+#include "gdkvisual.h"
+#include "gdkwindow.h"
+#include "gdkinternals.h"
+#include "gdkmain.h"
+
+G_BEGIN_DECLS
+
+struct _GdkX11GLContext
+{
+  GdkGLContext parent_instance;
+
+  GLXContext glx_context;
+  GLXFBConfig glx_config;
+
+  GLXDrawable current_drawable;
+
+  Window dummy_drawable;
+  GLXWindow dummy_glx_drawable;
+
+  guint is_direct : 1;
+};
+
+struct _GdkX11GLContextClass
+{
+  GdkGLContextClass parent_class;
+};
+
+gboolean        gdk_x11_display_init_gl                         (GdkDisplay        *display);
+gboolean        gdk_x11_display_validate_gl_pixel_format        (GdkDisplay        *display,
+                                                                 GdkGLPixelFormat  *format,
+                                                                 GError           **error);
+GdkGLContext *  gdk_x11_display_create_gl_context               (GdkDisplay        *display,
+                                                                 GdkGLPixelFormat  *format,
+                                                                 GdkGLContext      *share);
+void            gdk_x11_display_destroy_gl_context              (GdkDisplay        *display,
+                                                                 GdkGLContext      *context);
+gboolean        gdk_x11_display_make_gl_context_current         (GdkDisplay        *display,
+                                                                 GdkGLContext      *context,
+                                                                 GdkWindow         *window);
+
+G_END_DECLS
+
+#endif /* __GDK_X11_GL_CONTEXT__ */
diff --git a/gdk/x11/gdkx.h b/gdk/x11/gdkx.h
index b28580d..1aa5f7e 100644
--- a/gdk/x11/gdkx.h
+++ b/gdk/x11/gdkx.h
@@ -43,6 +43,7 @@
 #include <gdk/x11/gdkx11display.h>
 #include <gdk/x11/gdkx11displaymanager.h>
 #include <gdk/x11/gdkx11dnd.h>
+#include <gdk/x11/gdkx11glcontext.h>
 #include <gdk/x11/gdkx11keys.h>
 #include <gdk/x11/gdkx11property.h>
 #include <gdk/x11/gdkx11screen.h>
diff --git a/gdk/x11/gdkx11glcontext.h b/gdk/x11/gdkx11glcontext.h
new file mode 100644
index 0000000..36ed984
--- /dev/null
+++ b/gdk/x11/gdkx11glcontext.h
@@ -0,0 +1,24 @@
+#ifndef __GDK_X11_GL_CONTEXT_H__
+#define __GDK_X11_GL_CONTEXT_H__
+
+#if !defined (__GDKX_H_INSIDE__) && !defined (GDK_COMPILATION)
+#error "Only <gdk/gdkx.h> can be included directly."
+#endif
+
+#include <gdk/gdk.h>
+
+G_BEGIN_DECLS
+
+#define GDK_X11_TYPE_GL_CONTEXT                (gdk_x11_gl_context_get_type ())
+#define GDK_X11_GL_CONTEXT(obj)                (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_X11_TYPE_GL_CONTEXT, 
GdkX11GLContext))
+#define GDK_X11_IS_GL_CONTEXT(obj)     (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_X11_TYPE_GL_CONTEXT))
+
+typedef struct _GdkX11GLContext                GdkX11GLContext;
+typedef struct _GdkX11GLContextClass   GdkX11GLContextClass;
+
+GDK_AVAILABLE_IN_3_14
+GType gdk_x11_gl_context_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __GDK_X11_GL_CONTEXT_H__ */


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