gdk: Make GdkGLPixelFormat less smart

We use GdkGLPixelFormat only as a storage for GL configuration options.
The validation is only made when creating a GdkGLContext.

Validation for feature discovery and fallback code paths can be done
directly using gdk_display_validate_gl_pixel_format() instead.
This commit is contained in:
Emmanuele Bassi
2014-08-11 20:09:41 +01:00
parent 5052aa4a9a
commit a5da2eff7d
11 changed files with 172 additions and 208 deletions

View File

@@ -2230,7 +2230,8 @@ gdk_error_trap_pop (void)
* gdk_display_create_gl_context:
* @display: a #GdkDisplay
* @format: a #GdkGLPixelFormat
* @share: (optional): an optional shared #GdkGLContext
* @share: (optional): an optional shared #GdkGLContext
* @error: return location for a #GError
*
* Creates a new platform-specific #GdkGLContext for the
* given @display and @format.
@@ -2238,11 +2239,12 @@ gdk_error_trap_pop (void)
* Returns: (transfer full): the newly created #GdkGLContext
*/
GdkGLContext *
gdk_display_create_gl_context (GdkDisplay *display,
GdkGLPixelFormat *format,
GdkGLContext *share)
gdk_display_create_gl_context (GdkDisplay *display,
GdkGLPixelFormat *format,
GdkGLContext *share,
GError **error)
{
return GDK_DISPLAY_GET_CLASS (display)->create_gl_context (display, format, share);
return GDK_DISPLAY_GET_CLASS (display)->create_gl_context (display, format, share, error);
}
/*< private >
@@ -2307,7 +2309,7 @@ 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
@@ -2318,6 +2320,8 @@ gdk_display_get_current_gl_context (GdkDisplay *display)
* If the pixel format is invalid, @error will be set.
*
* Returns: %TRUE if the pixel format is valid
*
* Since: 3.14
*/
gboolean
gdk_display_validate_gl_pixel_format (GdkDisplay *display,
@@ -2332,6 +2336,7 @@ gdk_display_validate_gl_pixel_format (GdkDisplay *display,
* @display: a #GdkDisplay
* @format: a #GdkGLPixelFormat
* @share: (optional): a shared #GdkGLContext, or %NULL
* @error: return location for a #GError
*
* Creates a new #GdkGLContext for the given display, with the given
* pixel format.
@@ -2339,19 +2344,24 @@ gdk_display_validate_gl_pixel_format (GdkDisplay *display,
* If @share is not %NULL then the newly created #GdkGLContext will
* share resources with it.
*
* If the @format is invalid, or in case the creation of the #GdkGLContext
* failed, @error will be set.
*
* 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)
gdk_display_get_gl_context (GdkDisplay *display,
GdkGLPixelFormat *format,
GdkGLContext *share,
GError **error)
{
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);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
return gdk_display_create_gl_context (display, format, share);
return gdk_display_create_gl_context (display, format, share, error);
}

View File

@@ -172,9 +172,14 @@ 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);
gboolean gdk_display_validate_gl_pixel_format (GdkDisplay *display,
GdkGLPixelFormat *format,
GError **error);
GDK_AVAILABLE_IN_3_14
GdkGLContext * gdk_display_get_gl_context (GdkDisplay *display,
GdkGLPixelFormat *format,
GdkGLContext *share,
GError **error);
G_END_DECLS

View File

@@ -227,7 +227,8 @@ struct _GdkDisplayClass
GdkGLContext * (*create_gl_context) (GdkDisplay *display,
GdkGLPixelFormat *format,
GdkGLContext *share);
GdkGLContext *share,
GError **error);
gboolean (*make_gl_context_current) (GdkDisplay *display,
GdkGLContext *context,
GdkWindow *drawable);
@@ -320,7 +321,8 @@ gboolean gdk_display_validate_gl_pixel_format (GdkDisplay *dis
GError **error);
GdkGLContext * gdk_display_create_gl_context (GdkDisplay *display,
GdkGLPixelFormat *format,
GdkGLContext *share);
GdkGLContext *share,
GError **error);
void gdk_display_destroy_gl_context (GdkDisplay *display,
GdkGLContext *context);
gboolean gdk_display_make_gl_context_current (GdkDisplay *display,

View File

@@ -47,7 +47,7 @@ typedef struct {
GdkWindow *window;
GdkVisual *visual;
guint swap_interval;
gboolean swap_interval;
} GdkGLContextPrivate;
enum {
@@ -120,7 +120,7 @@ gdk_gl_context_set_property (GObject *gobject,
break;
case PROP_SWAP_INTERVAL:
priv->swap_interval = g_value_get_uint (value);
priv->swap_interval = g_value_get_boolean (value);
break;
default:
@@ -155,7 +155,7 @@ gdk_gl_context_get_property (GObject *gobject,
break;
case PROP_SWAP_INTERVAL:
g_value_set_uint (value, priv->swap_interval);
g_value_set_boolean (value, priv->swap_interval);
break;
default:
@@ -239,21 +239,21 @@ gdk_gl_context_class_init (GdkGLContextClass *klass)
*
* 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 %TRUE (the default), buffers will be flushed only during
* the vertical refresh of the display.
*
* If set to 1, calls buffers will be flushed only during the vertical
* refresh of the display.
* If set to %FALSE, gdk_gl_context_flush_buffer() will execute
* the buffer flush as soon as possible.
*
* 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);
g_param_spec_boolean ("swap-interval",
P_("Swap Interval"),
P_("The swap interval of the GL context"),
TRUE,
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;
@@ -265,6 +265,9 @@ gdk_gl_context_class_init (GdkGLContextClass *klass)
static void
gdk_gl_context_init (GdkGLContext *self)
{
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (self);
priv->swap_interval = TRUE;
}
/**
@@ -480,7 +483,7 @@ gdk_gl_context_get_current (void)
*
* Returns: the swap interval
*/
guint
gboolean
gdk_gl_context_get_swap_interval (GdkGLContext *context)
{
GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);

View File

@@ -39,9 +39,10 @@ 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
GdkVisual * gdk_gl_context_get_visual (GdkGLContext *context);
GDK_AVAILABLE_IN_3_14
void gdk_gl_context_clear_window (GdkGLContext *context);

View File

@@ -46,7 +46,7 @@ struct _GdkGLContextClass
void (* flush_buffer) (GdkGLContext *context);
};
guint gdk_gl_context_get_swap_interval (GdkGLContext *context);
gboolean gdk_gl_context_get_swap_interval (GdkGLContext *context);
G_END_DECLS

View File

@@ -26,29 +26,6 @@
* 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"
@@ -65,8 +42,6 @@
enum {
PROP_0,
PROP_DISPLAY,
/* bool */
PROP_DOUBLE_BUFFER,
PROP_MULTI_SAMPLE,
@@ -89,46 +64,9 @@ enum {
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);
}
G_DEFINE_TYPE (GdkGLPixelFormat, gdk_gl_pixel_format, G_TYPE_OBJECT)
static void
gdk_gl_pixel_format_set_property (GObject *gobject,
@@ -140,15 +78,6 @@ gdk_gl_pixel_format_set_property (GObject *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;
@@ -208,10 +137,6 @@ gdk_gl_pixel_format_get_property (GObject *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;
@@ -268,16 +193,6 @@ gdk_gl_pixel_format_class_init (GdkGLPixelFormatClass *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",
@@ -389,51 +304,28 @@ 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
* Returns: the newly created #GdkGLPixelFormat
*
* Since: 3.14
*/
GdkGLPixelFormat *
gdk_gl_pixel_format_new (GError **error,
const char *first_property,
gdk_gl_pixel_format_new (const char *first_property,
...)
{
gpointer res;
GdkGLPixelFormat *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);
res = (GdkGLPixelFormat *) g_object_new_valist (GDK_TYPE_GL_PIXEL_FORMAT, first_property, args);
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;
}

View File

@@ -44,12 +44,8 @@ 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,
GdkGLPixelFormat * gdk_gl_pixel_format_new (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

@@ -13,11 +13,6 @@ struct _GdkGLPixelFormat
{
GObject parent_instance;
gboolean is_validated;
gboolean is_valid;
GdkDisplay *display;
gboolean double_buffer;
gboolean multi_sample;

View File

@@ -22,6 +22,8 @@ typedef struct {
GdkDisplay *display;
GdkGLContext *context;
GdkWindow *window;
guint32 last_frame_counter;
} DrawableInfo;
static void
@@ -110,11 +112,38 @@ gdk_x11_gl_context_update (GdkGLContext *context)
glViewport (0, 0, width, height);
}
static void
maybe_wait_for_vblank (GdkDisplay *display,
GLXDrawable drawable)
{
GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
Display *dpy = gdk_x11_display_get_xdisplay (display);
if (display_x11->has_glx_sync_control)
{
gint64 ust, msc, sbc;
glXGetSyncValuesOML (dpy, drawable, &ust, &msc, &sbc);
glXWaitForMscOML (dpy, drawable,
0, 2, (msc + 1) % 2,
&ust, &msc, &sbc);
}
else if (display_x11->has_glx_video_sync)
{
guint32 current_count;
glXGetVideoSyncSGI (&current_count);
glXWaitVideoSyncSGI (2, (current_count + 1) % 2, &current_count);
}
}
static void
gdk_x11_gl_context_flush_buffer (GdkGLContext *context)
{
GdkDisplay *display = gdk_gl_context_get_display (context);
GdkWindow *window = gdk_gl_context_get_window (context);
Display *dpy = gdk_x11_display_get_xdisplay (display);
GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
DrawableInfo *info;
GLXDrawable drawable;
@@ -129,9 +158,43 @@ gdk_x11_gl_context_flush_buffer (GdkGLContext *context)
GDK_NOTE (OPENGL, g_print ("Flushing GLX buffers for %lu\n", (unsigned long) drawable));
glFinish ();
/* if we are going to wait for the vertical refresh manually
* we need to flush pending redraws, and we also need to wait
* for that to finish, otherwise we are going to tear.
*
* obviously, this condition should not be hit if we have
* GLX_SGI_swap_control, and we ask the driver to do the right
* thing.
*/
{
guint32 end_frame_counter = 0;
gboolean has_counter = display_x11->has_glx_video_sync;
gboolean can_wait = display_x11->has_glx_video_sync ||
display_x11->has_glx_sync_control;
glXSwapBuffers (gdk_x11_display_get_xdisplay (display), drawable);
if (display_x11->has_glx_video_sync)
glXGetVideoSyncSGI (&end_frame_counter);
if (!display_x11->has_glx_swap_interval)
{
glFinish ();
if (has_counter && can_wait)
{
guint32 last_counter = info != NULL ? info->last_frame_counter : 0;
if (last_counter == end_frame_counter)
maybe_wait_for_vblank (display, drawable);
}
else if (can_wait)
maybe_wait_for_vblank (display, drawable);
}
}
glXSwapBuffers (dpy, drawable);
if (info != NULL && display_x11->has_glx_video_sync)
glXGetVideoSyncSGI (&info->last_frame_counter);
}
static void
@@ -214,7 +277,8 @@ gdk_x11_display_init_gl (GdkDisplay *display)
#define MAX_GLX_ATTRS 30
static void
get_glx_attributes_for_pixel_format (GdkGLPixelFormat *format,
get_glx_attributes_for_pixel_format (GdkDisplay *display,
GdkGLPixelFormat *format,
int *attrs)
{
GdkX11Display *display_x11;
@@ -291,7 +355,7 @@ get_glx_attributes_for_pixel_format (GdkGLPixelFormat *format,
attrs[i++] = format->stencil_size;
}
display_x11 = GDK_X11_DISPLAY (format->display);
display_x11 = GDK_X11_DISPLAY (display);
if (display_x11->glx_version >= 14 && format->multi_sample)
{
attrs[i++] = GLX_SAMPLE_BUFFERS;
@@ -321,10 +385,7 @@ find_fbconfig_for_pixel_format (GdkDisplay *display,
gboolean use_rgba;
gboolean retval = FALSE;
if (format->display == NULL)
return retval;
get_glx_attributes_for_pixel_format (format, attrs);
get_glx_attributes_for_pixel_format (display, format, attrs);
use_rgba = format->alpha_size != 0;
@@ -427,9 +488,10 @@ create_gl_context (GdkDisplay *display,
}
GdkGLContext *
gdk_x11_display_create_gl_context (GdkDisplay *display,
GdkGLPixelFormat *format,
GdkGLContext *share)
gdk_x11_display_create_gl_context (GdkDisplay *display,
GdkGLPixelFormat *format,
GdkGLContext *share,
GError **error)
{
GdkX11GLContext *context;
GdkVisual *gdk_visual;
@@ -443,46 +505,35 @@ gdk_x11_display_create_gl_context (GdkDisplay *display,
XSetWindowAttributes attrs;
unsigned long mask;
Display *dpy;
GError *error;
if (!gdk_x11_display_init_gl (display))
if (!gdk_x11_display_validate_gl_pixel_format (display, format, error))
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;
}
/* if validation succeeded, then we don't need to check for the result
* here
*/
find_fbconfig_for_pixel_format (display, format, &config, &xvisinfo, 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
* 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);
{
/* GDK_GL_PIXEL_FORMAT_PROFILE_DEFAULT is currently
* equivalent to the LEGACY profile
*/
glx_context = create_gl_context (display, config, share);
}
if (glx_context == NULL)
{
g_critical ("Unable to create a GLX context");
g_set_error_literal (error, GDK_GL_PIXEL_FORMAT_ERROR,
GDK_GL_PIXEL_FORMAT_ERROR_NOT_AVAILABLE,
_("Unable to create a GL context"));
return NULL;
}
@@ -529,7 +580,20 @@ gdk_x11_display_create_gl_context (GdkDisplay *display,
XFree (xvisinfo);
if (gdk_x11_display_error_trap_pop (display))
return NULL;
{
g_set_error_literal (error, GDK_GL_PIXEL_FORMAT_ERROR,
GDK_GL_PIXEL_FORMAT_ERROR_NOT_AVAILABLE,
_("Unable to create a GL context"));
glXDestroyContext (dpy, glx_context);
if (dummy_xwin)
XDestroyWindow (dpy, dummy_xwin);
if (dummy_glx)
glXDestroyWindow (dpy, dummy_glx);
return NULL;
}
GDK_NOTE (OPENGL,
g_print ("Created GLX context[%p], %s, dummy drawable: %lu\n",
@@ -632,6 +696,14 @@ gdk_x11_display_make_gl_context_current (GdkDisplay *display,
drawable, drawable,
context_x11->glx_context);
if (GDK_X11_DISPLAY (display)->has_glx_swap_interval)
{
if (gdk_gl_context_get_swap_interval (context))
glXSwapIntervalSGI (1);
else
glXSwapIntervalSGI (0);
}
XSync (gdk_x11_display_get_xdisplay (display), False);
if (gdk_x11_display_error_trap_pop (display))
@@ -650,19 +722,6 @@ 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,

View File

@@ -44,7 +44,8 @@ gboolean gdk_x11_display_validate_gl_pixel_format (GdkDisplay
GError **error);
GdkGLContext * gdk_x11_display_create_gl_context (GdkDisplay *display,
GdkGLPixelFormat *format,
GdkGLContext *share);
GdkGLContext *share,
GError **error);
void gdk_x11_display_destroy_gl_context (GdkDisplay *display,
GdkGLContext *context);
gboolean gdk_x11_display_make_gl_context_current (GdkDisplay *display,