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
This commit is contained in:
Emmanuele Bassi
2014-03-23 17:37:54 +00:00
parent a6ee04781f
commit 5052aa4a9a
20 changed files with 2132 additions and 2 deletions

View File

@@ -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 \

View File

@@ -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>

View File

@@ -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);
}

View File

@@ -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__ */

View File

@@ -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__ */

489
gdk/gdkglcontext.c Normal file
View File

@@ -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;
}

67
gdk/gdkglcontext.h Normal file
View File

@@ -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__ */

53
gdk/gdkglcontextprivate.h Normal file
View File

@@ -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__ */

439
gdk/gdkglpixelformat.c Normal file
View File

@@ -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;
}

55
gdk/gdkglpixelformat.h Normal file
View File

@@ -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__ */

View File

@@ -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__ */

View File

@@ -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 {

View File

@@ -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__ */

View File

@@ -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 \

View File

@@ -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 ();
}

View File

@@ -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

691
gdk/x11/gdkglcontext-x11.c Normal file
View File

@@ -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;
}

View File

@@ -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__ */

View File

@@ -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>

24
gdk/x11/gdkx11glcontext.h Normal file
View File

@@ -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__ */