summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEmmanuele Bassi <ebassi@gnome.org>2014-03-23 17:37:54 +0000
committerEmmanuele Bassi <ebassi@gnome.org>2014-08-12 10:39:28 +0100
commit5052aa4a9acd18b2cd06d543542ec7f5dce58ef1 (patch)
tree3be6ceb7ca5d2e746f3cbf5727d3d18374d37602
parenta6ee04781fa85aae13c4c64583c36a79b787cfef (diff)
downloadgtk+-5052aa4a9acd18b2cd06d543542ec7f5dce58ef1.tar.gz
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
-rw-r--r--gdk/Makefile.am6
-rw-r--r--gdk/gdk.h2
-rw-r--r--gdk/gdkdisplay.c130
-rw-r--r--gdk/gdkdisplay.h5
-rw-r--r--gdk/gdkdisplayprivate.h25
-rw-r--r--gdk/gdkglcontext.c489
-rw-r--r--gdk/gdkglcontext.h67
-rw-r--r--gdk/gdkglcontextprivate.h53
-rw-r--r--gdk/gdkglpixelformat.c439
-rw-r--r--gdk/gdkglpixelformat.h55
-rw-r--r--gdk/gdkglpixelformatprivate.h43
-rw-r--r--gdk/gdkinternals.h3
-rw-r--r--gdk/gdktypes.h22
-rw-r--r--gdk/x11/Makefile.am3
-rw-r--r--gdk/x11/gdkdisplay-x11.c6
-rw-r--r--gdk/x11/gdkdisplay-x11.h14
-rw-r--r--gdk/x11/gdkglcontext-x11.c691
-rw-r--r--gdk/x11/gdkglcontext-x11.h56
-rw-r--r--gdk/x11/gdkx.h1
-rw-r--r--gdk/x11/gdkx11glcontext.h24
20 files changed, 2132 insertions, 2 deletions
diff --git a/gdk/Makefile.am b/gdk/Makefile.am
index d52fdd292b..fd60da1647 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 5761fa1db5..3fc297b593 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 34b6cab8ad..2797803ffd 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 5595cb9fb7..a457d890e7 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 7911d25f4f..c7fdb7124d 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 0000000000..014e7fa826
--- /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 0000000000..ff8853d89c
--- /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 0000000000..6551adb81a
--- /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 0000000000..10986e2537
--- /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 0000000000..9aa9882d6b
--- /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 0000000000..fd9e614600
--- /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 f58ccb0084..791fa87b22 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 be768a794e..4d6e8ccbc1 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 5930f7e7e4..36e39f0842 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 1db4742f71..1837347b61 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 69ba890ca4..07d2cb9f99 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 0000000000..aee0bf85d5
--- /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 0000000000..3c8354827c
--- /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 b28580dc24..1aa5f7e33d 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 0000000000..36ed984ecb
--- /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__ */