gl: Rework pixel format validation

Instead of modifying the pixel format in place, we allow separating the
pixel format from the effective pixel format we found.

This means that caller code can keep a reference to the pixel format it
creates, and re-use it to create new contexts on different displays,
while the GL context can keep a reference to a valid pixel format to let
the use query it.

This allows GtkGLArea to keep its own user-supplied pixel format and
reuse it without adding additional constraints as a result of a
validation on a specific GdkDisplay.
This commit is contained in:
Emmanuele Bassi
2014-08-14 11:10:00 +01:00
parent 3398e2ea87
commit 19a0a6196b
8 changed files with 188 additions and 54 deletions

View File

@@ -2226,27 +2226,6 @@ 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
* @error: return location for a #GError
*
* 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,
GError **error)
{
return GDK_DISPLAY_GET_CLASS (display)->create_gl_context (display, format, share, error);
}
/*< private >
* gdk_display_destroy_gl_context:
* @display: a #GdkDisplay
@@ -2313,10 +2292,15 @@ gdk_display_get_current_gl_context (GdkDisplay *display)
* gdk_display_validate_gl_pixel_format:
* @display: a #GdkDisplay
* @format: a #GdkGLPixelFormat
* @validated_format: (out callee-allocates) (transfer full) (optional): return location for
* the validated #GdkGLPixelFormat
* @error: return location for a #GError
*
* Validates a #GdkGLPixelFormat for the given display.
*
* If the pixel format is valid, and @validated_format is not %NULL, the
* validated pixel format will be stored into @validated_format.
*
* If the pixel format is invalid, @error will be set.
*
* Returns: %TRUE if the pixel format is valid
@@ -2326,24 +2310,27 @@ gdk_display_get_current_gl_context (GdkDisplay *display)
gboolean
gdk_display_validate_gl_pixel_format (GdkDisplay *display,
GdkGLPixelFormat *format,
GdkGLPixelFormat **validated_format,
GError **error)
{
return GDK_DISPLAY_GET_CLASS (display)->validate_gl_pixel_format (display, format, error);
g_return_val_if_fail (GDK_IS_DISPLAY (display), FALSE);
g_return_val_if_fail (GDK_IS_GL_PIXEL_FORMAT (format), FALSE);
g_return_val_if_fail (validated_format == NULL || *validated_format == NULL, FALSE);
return GDK_DISPLAY_GET_CLASS (display)->validate_gl_pixel_format (display,
format, validated_format,
error);
}
/**
* gdk_display_get_gl_context:
* gdk_display_create_gl_context:
* @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.
*
* 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.
*
@@ -2353,15 +2340,48 @@ gdk_display_validate_gl_pixel_format (GdkDisplay *display,
* Since: 3.14
*/
GdkGLContext *
gdk_display_get_gl_context (GdkDisplay *display,
GdkGLPixelFormat *format,
GdkGLContext *share,
GError **error)
gdk_display_create_gl_context (GdkDisplay *display,
GdkGLPixelFormat *format,
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, error);
return GDK_DISPLAY_GET_CLASS (display)->create_gl_context (display, format, NULL, error);
}
/**
* gdk_display_create_shared_gl_context:
* @display: a #GdkDisplay
* @format: a #GdkGLPixelFormat
* @shared_context: shared #GdkGLContext
* @error: return location for a #GError
*
* Creates a new #GdkGLContext for the given display, with the given
* pixel format; the newly created #GdkGLContext will share resources
* like the texture namespace and display lists with @shared_context.
*
* 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_create_shared_gl_context (GdkDisplay *display,
GdkGLPixelFormat *format,
GdkGLContext *shared_context,
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 (GDK_IS_GL_CONTEXT (shared_context), NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
return GDK_DISPLAY_GET_CLASS (display)->create_gl_context (display, format,
shared_context,
error);
}

View File

@@ -174,11 +174,16 @@ GdkAppLaunchContext *gdk_display_get_app_launch_context (GdkDisplay *display);
GDK_AVAILABLE_IN_3_14
gboolean gdk_display_validate_gl_pixel_format (GdkDisplay *display,
GdkGLPixelFormat *format,
GdkGLPixelFormat **validated_format,
GError **error);
GDK_AVAILABLE_IN_3_14
GdkGLContext * gdk_display_get_gl_context (GdkDisplay *display,
GdkGLContext * gdk_display_create_gl_context (GdkDisplay *display,
GdkGLPixelFormat *format,
GdkGLContext *share,
GError **error);
GDK_AVAILABLE_IN_3_14
GdkGLContext * gdk_display_create_shared_gl_context (GdkDisplay *display,
GdkGLPixelFormat *format,
GdkGLContext *shared_context,
GError **error);
G_END_DECLS

View File

@@ -236,6 +236,7 @@ struct _GdkDisplayClass
GdkGLContext *context);
gboolean (*validate_gl_pixel_format) (GdkDisplay *display,
GdkGLPixelFormat *format,
GdkGLPixelFormat **valid_format,
GError **error);
/* Signals */
@@ -318,10 +319,7 @@ 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,
GdkGLPixelFormat **validated_format,
GError **error);
void gdk_display_destroy_gl_context (GdkDisplay *display,
GdkGLContext *context);

View File

@@ -35,6 +35,92 @@
*
* A #GdkGLContext has to be associated with a #GdkWindow and
* made "current", otherwise any OpenGL call will be ignored.
*
* ## Creating a new OpenGL context ##
*
* In order to create a new #GdkGLContext instance you need a
* #GdkGLPixelFormat instance and a #GdkDisplay.
*
* The #GdkGLPixelFormat class contains configuration option that
* you require from the windowing system to be available on the
* #GdkGLContext.
*
* |[<!-- language="C" -->
* GdkGLPixelFormat *format;
*
* format = gdk_gl_pixel_format_new ("double-buffer", TRUE,
* "depth-size", 32,
* NULL);
* ]|
*
* The example above will create a pixel format with double buffering
* and a depth buffer size of 32 bits.
*
* You can either choose to validate the pixel format, in case you
* have the ability to change your drawing code depending on it, or
* just ask the #GdkDisplay to create the #GdkGLContext with it, which
* will implicitly validate the pixel format and return an error if it
* could not find an OpenGL context that satisfied the requirements
* of the pixel format:
*
* |[<!-- language="C" -->
* GError *error = NULL;
*
* // the "display" variable has been set elsewhere
* GdkGLContext *context =
* gdk_display_create_gl_context (display, format, &error);
*
* if (error != NULL)
* {
* // handle error condition
* }
*
* // you can release the reference on the pixel format at
* // this point
* g_object_unref (format);
* ]|
*
* ## Using a GdkGLContext ##
*
* In order to use a #GdkGLContext to draw with OpenGL commands
* on a #GdkWindow, it's necessary to bind the context to the
* window:
*
* |[<!-- language="C" -->
* // associates the window to the context
* gdk_gl_context_set_window (context, window);
* ]|
*
* This ensures that the #GdkGLContext can refer to the #GdkWindow,
* as well as the #GdkWindow can present the result of the OpenGL
* commands.
*
* You will also need to make the #GdkGLContext the current context
* before issuing OpenGL calls; the system sends OpenGL commands to
* whichever context is current. It is possible to have multiple
* contexts, so you always need to ensure that the one which you
* want to draw with is the current one before issuing commands:
*
* |[<!-- language="C" -->
* gdk_gl_context_make_current (context);
* ]|
*
* You can now perform your drawing using OpenGL commands.
*
* Once you finished drawing your frame, and you want to present the
* result on the window bound to the #GdkGLContext, you should call
* gdk_gl_context_flush_buffer().
*
* If the #GdkWindow bound to the #GdkGLContext changes size, you
* will need to call gdk_gl_context_update() to ensure that the OpenGL
* viewport is kept in sync with the size of the window.
*
* You can detach the currently bound #GdkWindow from a #GdkGLContext
* by using gdk_gl_context_set_window() with a %NULL argument.
*
* You can check which #GdkGLContext is the current one by using
* gdk_gl_context_get_current(); you can also unset any #GdkGLContext
* that is currently set by calling gdk_gl_context_clear_current().
*/
#include "config.h"
@@ -229,7 +315,7 @@ gdk_gl_context_class_init (GdkGLContextClass *klass)
/**
* GdkGLContext:visual:
*
* The #GdkVisual used by the context.
* The #GdkVisual matching the #GdkGLPixelFormat used by the context.
*
* Since: 3.14
*/

View File

@@ -56,10 +56,11 @@
*
* |[<!-- language="C" -->
* GError *error = NULL;
* GdkGLPixelFormat *valid = NULL;
*
* // The "display" variable is set elsewhere.
* // The "format" variable is the one we set previously.
* if (!gdk_display_validate_gl_pixel_format (display, format, &error))
* if (!gdk_display_validate_gl_pixel_format (display, format, &valid, &error))
* {
* // print "error" or create a new pixel format to validate
* }
@@ -72,11 +73,13 @@
* GdkGLContext *context;
* GError *error = NULL;
*
* context = gdk_display_get_gl_context (display, format, NULL, &error);
* context = gdk_display_create_gl_context (display, format, &error);
* if (error != NULL)
* {
* // print error
* }
*
* g_object_unref (format);
* ]|
*
* Once a #GdkGLContext has been created with a #GdkGLPixelFormat, the

View File

@@ -540,6 +540,7 @@ gdk_x11_display_create_gl_context (GdkDisplay *display,
GdkGLContext *share,
GError **error)
{
GdkGLPixelFormat *valid_format;
GdkX11GLContext *context;
GdkVisual *gdk_visual;
GLXFBConfig config;
@@ -553,11 +554,11 @@ gdk_x11_display_create_gl_context (GdkDisplay *display,
unsigned long mask;
Display *dpy;
if (!gdk_x11_display_validate_gl_pixel_format (display, format, error))
if (!gdk_x11_display_validate_gl_pixel_format (display, format, NULL, error))
return NULL;
/* if validation succeeded, then we don't need to check for the result
* here
/* if validation succeeded, then we don't need to check for the
* result here: we know the pixel format has a valid GLXFBConfig
*/
find_fbconfig_for_pixel_format (display, format, &config, &xvisinfo, NULL);
@@ -648,9 +649,17 @@ gdk_x11_display_create_gl_context (GdkDisplay *display,
is_direct ? "direct" : "indirect",
(unsigned long) dummy_xwin));
/* the GdkGLContext holds a reference on the pixel format
* that is used to create it, not the one that the user
* passed; this allows the user to query the pixel format
* attributes
*/
valid_format = g_object_new (GDK_TYPE_GL_PIXEL_FORMAT, NULL);
update_pixel_format (display, valid_format, config);
context = g_object_new (GDK_X11_TYPE_GL_CONTEXT,
"display", display,
"pixel-format", format,
"pixel-format", valid_format,
"visual", gdk_visual,
NULL);
@@ -767,6 +776,7 @@ gdk_x11_display_make_gl_context_current (GdkDisplay *display,
gboolean
gdk_x11_display_validate_gl_pixel_format (GdkDisplay *display,
GdkGLPixelFormat *format,
GdkGLPixelFormat **validated_format,
GError **error)
{
GLXFBConfig config;
@@ -795,10 +805,17 @@ gdk_x11_display_validate_gl_pixel_format (GdkDisplay *display,
if (!find_fbconfig_for_pixel_format (display, format, &config, NULL, error))
return FALSE;
/* update the pixel format with the values of the
* configuration we found
*/
update_pixel_format (display, format, config);
if (validated_format != NULL)
{
GdkGLPixelFormat *valid = g_object_new (GDK_TYPE_GL_PIXEL_FORMAT, NULL);
/* update the pixel format with the values of the
* configuration we found
*/
update_pixel_format (display, valid, config);
*validated_format = valid;
}
return TRUE;
}

View File

@@ -61,6 +61,7 @@ struct _GdkX11GLContextClass
gboolean gdk_x11_display_init_gl (GdkDisplay *display);
gboolean gdk_x11_display_validate_gl_pixel_format (GdkDisplay *display,
GdkGLPixelFormat *format,
GdkGLPixelFormat **validated_format,
GError **error);
GdkGLContext * gdk_x11_display_create_gl_context (GdkDisplay *display,
GdkGLPixelFormat *format,

View File

@@ -143,9 +143,9 @@
*
* // create a GdkGLContext that has shared texture namespace
* // and display lists with a given context
* return gdk_display_get_gl_context (display, format,
* shared_context,
* NULL);
* return gdk_display_create_shared_gl_context (display, format,
* shared_context,
* NULL);
* }
* ]|
*
@@ -375,7 +375,7 @@ gtk_gl_area_real_create_context (GtkGLArea *area,
if (display == NULL)
display = gdk_display_get_default ();
retval = gdk_display_get_gl_context (display, format, NULL, &error);
retval = gdk_display_create_gl_context (display, format, &error);
if (error != NULL)
{
g_critical ("Unable to create a GdkGLContext: %s", error->message);
@@ -420,6 +420,10 @@ gtk_gl_area_class_init (GtkGLAreaClass *klass)
* The #GdkGLPixelFormat used for creating the #GdkGLContext
* to be used by the #GtkGLArea widget.
*
* If you want to query the effective pixel format used by
* the #GdkGLContext, you should get the #GtkGLArea:context and
* call gdk_gl_context_get_pixel_format().
*
* Since: 3.14
*/
obj_props[PROP_PIXEL_FORMAT] =