[gtk+/wip/gdk-gl: 27/31] gl: Rework pixel format validation



commit 19a0a6196bc7cc488a95f421bed19fe3f3e800e0
Author: Emmanuele Bassi <ebassi gnome org>
Date:   Thu Aug 14 11:10:00 2014 +0100

    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.

 gdk/gdkdisplay.c           |   84 ++++++++++++++++++++++++++----------------
 gdk/gdkdisplay.h           |    9 +++-
 gdk/gdkdisplayprivate.h    |    6 +--
 gdk/gdkglcontext.c         |   88 +++++++++++++++++++++++++++++++++++++++++++-
 gdk/gdkglpixelformat.c     |    7 ++-
 gdk/x11/gdkglcontext-x11.c |   33 ++++++++++++----
 gdk/x11/gdkglcontext-x11.h |    1 +
 gtk/gtkglarea.c            |   12 ++++--
 8 files changed, 187 insertions(+), 53 deletions(-)
---
diff --git a/gdk/gdkdisplay.c b/gdk/gdkdisplay.c
index 0b564b5..71ef3c9 100644
--- a/gdk/gdkdisplay.c
+++ b/gdk/gdkdisplay.c
@@ -2227,27 +2227,6 @@ gdk_error_trap_pop (void)
 }
 
 /*< 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
  * @context: a #GdkGLContext
@@ -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,23 +2310,57 @@ 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.
+ *
+ * Returns: (transfer full): the newly created #GdkGLContext, or
+ *   %NULL on error
+ *
+ * Since: 3.14
+ */
+GdkGLContext *
+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 (error == NULL || *error == NULL, NULL);
+
+  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.
@@ -2353,15 +2371,17 @@ 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_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 (share == NULL || GDK_IS_GL_CONTEXT (share), 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_create_gl_context (display, format, share, error);
+  return GDK_DISPLAY_GET_CLASS (display)->create_gl_context (display, format,
+                                                             shared_context,
+                                                             error);
 }
diff --git a/gdk/gdkdisplay.h b/gdk/gdkdisplay.h
index 290c881..1002b2f 100644
--- a/gdk/gdkdisplay.h
+++ b/gdk/gdkdisplay.h
@@ -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
diff --git a/gdk/gdkdisplayprivate.h b/gdk/gdkdisplayprivate.h
index 01e1f4a..81d9066 100644
--- a/gdk/gdkdisplayprivate.h
+++ b/gdk/gdkdisplayprivate.h
@@ -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);
diff --git a/gdk/gdkglcontext.c b/gdk/gdkglcontext.c
index 0764344..cff8c79 100644
--- a/gdk/gdkglcontext.c
+++ b/gdk/gdkglcontext.c
@@ -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
    */
diff --git a/gdk/gdkglpixelformat.c b/gdk/gdkglpixelformat.c
index 0f57faf..2ca08a2 100644
--- a/gdk/gdkglpixelformat.c
+++ b/gdk/gdkglpixelformat.c
@@ -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
diff --git a/gdk/x11/gdkglcontext-x11.c b/gdk/x11/gdkglcontext-x11.c
index 86c8d6d..9a22c1f 100644
--- a/gdk/x11/gdkglcontext-x11.c
+++ b/gdk/x11/gdkglcontext-x11.c
@@ -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;
 }
diff --git a/gdk/x11/gdkglcontext-x11.h b/gdk/x11/gdkglcontext-x11.h
index 8b5f234..d17c433 100644
--- a/gdk/x11/gdkglcontext-x11.h
+++ b/gdk/x11/gdkglcontext-x11.h
@@ -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,
diff --git a/gtk/gtkglarea.c b/gtk/gtkglarea.c
index 94cd7e2..c2f9b58 100644
--- a/gtk/gtkglarea.c
+++ b/gtk/gtkglarea.c
@@ -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] =


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