[gtk+] GL: Split GL context creation in two phases



commit 22e6f37c9c00ca3e97fbd454774a178473a0c93e
Author: Emmanuele Bassi <ebassi gnome org>
Date:   Tue Jan 27 21:23:23 2015 +0000

    GL: Split GL context creation in two phases
    
    One of the major requests by OpenGL users has been the ability to
    specify settings when creating a GL context, like the version to use
    or whether the debug support should be enabled.
    
    We have a couple of requirements in terms of API:
    
     • avoid, if at all possible, the "C arrays of integers with
       attribute, value pairs", which are hard to write and hard
       to bind in non-C languages.
     • allow failing in a recoverable way.
     • do not make the GL context creation API a mess of arguments.
    
    Looking at prior art, it seems that a common pattern is to split the
    construction phase in two:
    
     • a first phase that creates a GL context wrapper object and
       does preliminary checks on the environment.
     • a second phase that creates the backend-specific GL object.
    
    We adopted a similar pattern:
    
     • gdk_window_create_gl_context() creates a GdkGLContext
     • gdk_gl_context_realize() creates the underlying resources
    
    Calling gdk_gl_context_make_current() also realizes the context, so
    simple GL users do not need to care. Advanced users will want to
    call gdk_window_create_gl_context(), set up the optional requirements,
    and then call gdk_gl_context_realize(). If either of these two steps
    fails, it's possible to recover by changing the requirements, or simply
    creating a new GdkGLContext instance.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=741946

 gdk/gdkglcontext.c                 |   59 +++++-
 gdk/gdkglcontext.h                 |   18 ++-
 gdk/gdkglcontextprivate.h          |    3 +
 gdk/gdkwindow.c                    |   31 +++-
 gdk/gdkwindow.h                    |    1 -
 gdk/gdkwindowimpl.h                |    4 +-
 gdk/wayland/gdkglcontext-wayland.c |   80 +++++---
 gdk/x11/gdkglcontext-x11.c         |  375 +++++++++++++++++++-----------------
 gtk/gtkglarea.c                    |   17 ++-
 9 files changed, 363 insertions(+), 225 deletions(-)
---
diff --git a/gdk/gdkglcontext.c b/gdk/gdkglcontext.c
index 829e302..0c3f564 100644
--- a/gdk/gdkglcontext.c
+++ b/gdk/gdkglcontext.c
@@ -89,6 +89,7 @@ typedef struct {
   guint use_texture_rectangle : 1;
   guint has_gl_framebuffer_blit : 1;
   guint has_frame_terminator : 1;
+  guint extensions_checked : 1;
 
   GdkGLContextPaintData *paint_data;
 } GdkGLContextPrivate;
@@ -389,19 +390,54 @@ gdk_gl_context_has_frame_terminator (GdkGLContext *context)
   return priv->has_frame_terminator;
 }
 
+/**
+ * gdk_gl_context_realize:
+ * @context: a #GdkGLContext
+ * @error: return location for a #GError
+ *
+ * Realizes the given #GdkGLContext.
+ *
+ * It is safe to call this function on a realized #GdkGLContext.
+ *
+ * Returns: %TRUE if the context is realized
+ *
+ * Since: 3.16
+ */
+gboolean
+gdk_gl_context_realize (GdkGLContext  *context,
+                        GError       **error)
+{
+  GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
+
+  g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), FALSE);
+
+  if (priv->realized)
+    return priv->realized;
+
+  priv->realized = GDK_GL_CONTEXT_GET_CLASS (context)->realize (context, error);
+
+  return priv->realized;
+}
+
 static void
-gdk_gl_context_realize (GdkGLContext *context)
+gdk_gl_context_check_extensions (GdkGLContext *context)
 {
   GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
   gboolean has_npot, has_texture_rectangle;
 
+  if (!priv->realized)
+    return;
+
+  if (priv->extensions_checked)
+    return;
+
   has_npot = epoxy_has_gl_extension ("GL_ARB_texture_non_power_of_two");
   has_texture_rectangle = epoxy_has_gl_extension ("GL_ARB_texture_rectangle");
 
   priv->has_gl_framebuffer_blit = epoxy_has_gl_extension ("GL_EXT_framebuffer_blit");
   priv->has_frame_terminator = epoxy_has_gl_extension ("GL_GREMEDY_frame_terminator");
 
-  if (_gdk_gl_flags & GDK_GL_TEXTURE_RECTANGLE)
+  if (G_UNLIKELY (_gdk_gl_flags & GDK_GL_TEXTURE_RECTANGLE))
     priv->use_texture_rectangle = TRUE;
   else if (has_npot)
     priv->use_texture_rectangle = FALSE;
@@ -410,7 +446,7 @@ gdk_gl_context_realize (GdkGLContext *context)
   else
     g_warning ("GL implementation doesn't support any form of non-power-of-two textures");
 
-  priv->realized = TRUE;
+  priv->extensions_checked = TRUE;
 }
 
 /**
@@ -433,11 +469,24 @@ gdk_gl_context_make_current (GdkGLContext *context)
   if (current == context)
     return;
 
+  /* we need to realize the GdkGLContext if it wasn't explicitly realized */
+  if (!priv->realized)
+    {
+      GError *error = NULL;
+
+      gdk_gl_context_realize (context, &error);
+      if (error != NULL)
+        {
+          g_critical ("Could not realize the GL context: %s", error->message);
+          g_error_free (error);
+          return;
+        }
+    }
+
   if (gdk_display_make_gl_context_current (priv->display, context))
     {
       g_private_replace (&thread_current_context, g_object_ref (context));
-      if (!priv->realized)
-        gdk_gl_context_realize (context);
+      gdk_gl_context_check_extensions (context);
     }
 }
 
diff --git a/gdk/gdkglcontext.h b/gdk/gdkglcontext.h
index be71ae4..3155948 100644
--- a/gdk/gdkglcontext.h
+++ b/gdk/gdkglcontext.h
@@ -43,18 +43,24 @@ GDK_AVAILABLE_IN_3_16
 GType gdk_gl_context_get_type (void) G_GNUC_CONST;
 
 GDK_AVAILABLE_IN_3_16
-GdkDisplay *            gdk_gl_context_get_display      (GdkGLContext *context);
+GdkDisplay *            gdk_gl_context_get_display              (GdkGLContext  *context);
 GDK_AVAILABLE_IN_3_16
-GdkWindow *             gdk_gl_context_get_window       (GdkGLContext *context);
+GdkWindow *             gdk_gl_context_get_window               (GdkGLContext  *context);
 GDK_AVAILABLE_IN_3_16
-GdkGLProfile            gdk_gl_context_get_profile      (GdkGLContext *context);
+GdkGLProfile            gdk_gl_context_get_profile              (GdkGLContext  *context);
+GDK_AVAILABLE_IN_3_16
+GdkGLContext *          gdk_gl_context_get_shared_context       (GdkGLContext  *context);
+
+GDK_AVAILABLE_IN_3_16
+gboolean                gdk_gl_context_realize                  (GdkGLContext  *context,
+                                                                 GError       **error);
 
 GDK_AVAILABLE_IN_3_16
-void                    gdk_gl_context_make_current     (GdkGLContext *context);
+void                    gdk_gl_context_make_current             (GdkGLContext  *context);
 GDK_AVAILABLE_IN_3_16
-GdkGLContext *          gdk_gl_context_get_current      (void);
+GdkGLContext *          gdk_gl_context_get_current              (void);
 GDK_AVAILABLE_IN_3_16
-void                    gdk_gl_context_clear_current    (void);
+void                    gdk_gl_context_clear_current            (void);
 
 G_END_DECLS
 
diff --git a/gdk/gdkglcontextprivate.h b/gdk/gdkglcontextprivate.h
index 4efface..f282539 100644
--- a/gdk/gdkglcontextprivate.h
+++ b/gdk/gdkglcontextprivate.h
@@ -40,6 +40,9 @@ struct _GdkGLContextClass
 {
   GObjectClass parent_class;
 
+  gboolean (* realize) (GdkGLContext *context,
+                        GError **error);
+
   void (* end_frame)    (GdkGLContext *context,
                          cairo_region_t *painted,
                          cairo_region_t *damage);
diff --git a/gdk/gdkwindow.c b/gdk/gdkwindow.c
index 3103367..9cc257b 100644
--- a/gdk/gdkwindow.c
+++ b/gdk/gdkwindow.c
@@ -2724,8 +2724,11 @@ gdk_window_ref_impl_surface (GdkWindow *window)
 }
 
 GdkGLContext *
-gdk_window_get_paint_gl_context (GdkWindow *window, GError **error)
+gdk_window_get_paint_gl_context (GdkWindow  *window,
+                                 GError    **error)
 {
+  GError *internal_error = NULL;
+
   if (_gdk_gl_flags & GDK_GL_DISABLE)
     {
       g_set_error_literal (error, GDK_GL_ERROR,
@@ -2741,21 +2744,36 @@ gdk_window_get_paint_gl_context (GdkWindow *window, GError **error)
                                                                      TRUE,
                                                                      GDK_GL_PROFILE_3_2_CORE,
                                                                      NULL,
-                                                                     error);
+                                                                     &internal_error);
       if (window->impl_window->gl_paint_context == NULL &&
-          g_error_matches (*error, GDK_GL_ERROR,
+          g_error_matches (internal_error, GDK_GL_ERROR,
                            GDK_GL_ERROR_UNSUPPORTED_PROFILE))
         {
-          g_clear_error (error);
+          g_clear_error (&internal_error);
           window->impl_window->gl_paint_context =
             GDK_WINDOW_IMPL_GET_CLASS (window->impl)->create_gl_context (window->impl_window,
                                                                          TRUE,
                                                                          GDK_GL_PROFILE_DEFAULT,
                                                                          NULL,
-                                                                         error);
+                                                                         &internal_error);
         }
     }
 
+  if (internal_error != NULL)
+    {
+      g_propagate_error (error, internal_error);
+      g_clear_object (&(window->impl_window->gl_paint_context));
+      return NULL;
+    }
+
+  gdk_gl_context_realize (window->impl_window->gl_paint_context, &internal_error);
+  if (internal_error != NULL)
+    {
+      g_propagate_error (error, internal_error);
+      g_clear_object (&(window->impl_window->gl_paint_context));
+      return NULL;
+    }
+
   return window->impl_window->gl_paint_context;
 }
 
@@ -2771,6 +2789,9 @@ gdk_window_get_paint_gl_context (GdkWindow *window, GError **error)
  *
  * If the creation of the #GdkGLContext failed, @error will be set.
  *
+ * Before using the returned #GdkGLContext, you will need to
+ * call gdk_gl_context_make_current().
+ *
  * Returns: (transfer full): the newly created #GdkGLContext, or
  * %NULL on error
  *
diff --git a/gdk/gdkwindow.h b/gdk/gdkwindow.h
index 74e23d2..85a8567 100644
--- a/gdk/gdkwindow.h
+++ b/gdk/gdkwindow.h
@@ -1116,7 +1116,6 @@ GdkGLContext * gdk_window_create_gl_context    (GdkWindow      *window,
                                                 GdkGLProfile    profile,
                                                 GError        **error);
 
-
 G_END_DECLS
 
 #endif /* __GDK_WINDOW_H__ */
diff --git a/gdk/gdkwindowimpl.h b/gdk/gdkwindowimpl.h
index efdaa1f..1ac327f 100644
--- a/gdk/gdkwindowimpl.h
+++ b/gdk/gdkwindowimpl.h
@@ -296,6 +296,9 @@ struct _GdkWindowImplClass
                                            GdkGLProfile    profile,
                                            GdkGLContext   *share,
                                            GError        **error);
+  gboolean     (* realize_gl_context)     (GdkWindow      *window,
+                                           GdkGLContext   *context,
+                                           GError        **error);
   void         (*invalidate_for_new_frame)(GdkWindow      *window,
                                            cairo_region_t *update_area);
 };
@@ -303,7 +306,6 @@ struct _GdkWindowImplClass
 /* Interface Functions */
 GType gdk_window_impl_get_type (void) G_GNUC_CONST;
 
-
 G_END_DECLS
 
 #endif /* __GDK_WINDOW_IMPL_H__ */
diff --git a/gdk/wayland/gdkglcontext-wayland.c b/gdk/wayland/gdkglcontext-wayland.c
index c8d4ed2..a5fa5df 100644
--- a/gdk/wayland/gdkglcontext-wayland.c
+++ b/gdk/wayland/gdkglcontext-wayland.c
@@ -100,6 +100,47 @@ gdk_wayland_window_invalidate_for_new_frame (GdkWindow      *window,
     }
 }
 
+static gboolean
+gdk_wayland_gl_context_realize (GdkGLContext *context,
+                                GError      **error)
+{
+  GdkWaylandGLContext *context_wayland = GDK_WAYLAND_GL_CONTEXT (context);
+  GdkDisplay *display = gdk_gl_context_get_display (context);
+  GdkGLContext *share = gdk_gl_context_get_shared_context (context);
+  GdkGLProfile profile = gdk_gl_context_get_profile (context);
+  GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
+  EGLContext ctx;
+  EGLint context_attribs[3];
+  int i;
+
+  i = 0;
+  if (profile == GDK_GL_PROFILE_3_2_CORE)
+    {
+      context_attribs[i++] = EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR;
+      context_attribs[i++] = EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR;
+    }
+  context_attribs[i++] = EGL_NONE;
+
+  ctx = eglCreateContext (display_wayland->egl_display,
+                          context_wayland->egl_config,
+                          share != NULL ? GDK_WAYLAND_GL_CONTEXT (share)->egl_context
+                                        : EGL_NO_CONTEXT,
+                          context_attribs);
+  if (ctx == NULL)
+    {
+      g_set_error_literal (error, GDK_GL_ERROR,
+                           GDK_GL_ERROR_NOT_AVAILABLE,
+                           _("Unable to create a GL context"));
+      return FALSE;
+    }
+
+  GDK_NOTE (OPENGL, g_print ("Created EGL context[%p]\n", ctx));
+
+  context_wayland->egl_context = ctx;
+
+  return TRUE;
+}
+
 static void
 gdk_wayland_gl_context_end_frame (GdkGLContext *context,
                                   cairo_region_t *painted,
@@ -142,11 +183,13 @@ gdk_wayland_gl_context_end_frame (GdkGLContext *context,
 static void
 gdk_wayland_gl_context_class_init (GdkWaylandGLContextClass *klass)
 {
-  GdkGLContextClass *context_class = GDK_GL_CONTEXT_CLASS (klass);
   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GdkGLContextClass *context_class = GDK_GL_CONTEXT_CLASS (klass);
 
-  context_class->end_frame = gdk_wayland_gl_context_end_frame;
   gobject_class->dispose = gdk_x11_gl_context_dispose;
+
+  context_class->realize = gdk_wayland_gl_context_realize;
+  context_class->end_frame = gdk_wayland_gl_context_end_frame;
 }
 
 static void
@@ -213,9 +256,9 @@ gdk_wayland_display_init_gl (GdkDisplay *display)
 #define MAX_EGL_ATTRS   30
 
 static gboolean
-find_eglconfig_for_window (GdkWindow        *window,
-                           EGLConfig         *egl_config_out,
-                           GError           **error)
+find_eglconfig_for_window (GdkWindow  *window,
+                           EGLConfig  *egl_config_out,
+                           GError    **error)
 {
   GdkDisplay *display = gdk_window_get_display (window);
   GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
@@ -294,10 +337,7 @@ gdk_wayland_window_create_gl_context (GdkWindow     *window,
   GdkDisplay *display = gdk_window_get_display (window);
   GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
   GdkWaylandGLContext *context;
-  EGLContext ctx;
   EGLConfig config;
-  int i;
-  EGLint context_attribs[3];
 
   if (!gdk_wayland_display_init_gl (display))
     {
@@ -322,29 +362,6 @@ gdk_wayland_window_create_gl_context (GdkWindow     *window,
   if (!find_eglconfig_for_window (window, &config, error))
     return NULL;
 
-  i = 0;
-  if (profile == GDK_GL_PROFILE_3_2_CORE)
-    {
-      context_attribs[i++] = EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR;
-      context_attribs[i++] = EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR;
-    }
-  context_attribs[i++] = EGL_NONE;
-
-  ctx = eglCreateContext (display_wayland->egl_display,
-                          config,
-                          share ? GDK_WAYLAND_GL_CONTEXT (share)->egl_context : EGL_NO_CONTEXT,
-                          context_attribs);
-  if (ctx == NULL)
-    {
-      g_set_error_literal (error, GDK_GL_ERROR,
-                           GDK_GL_ERROR_NOT_AVAILABLE,
-                           _("Unable to create a GL context"));
-      return NULL;
-    }
-
-  GDK_NOTE (OPENGL,
-            g_print ("Created EGL context[%p]\n", ctx));
-
   context = g_object_new (GDK_TYPE_WAYLAND_GL_CONTEXT,
                           "display", display,
                           "window", window,
@@ -353,7 +370,6 @@ gdk_wayland_window_create_gl_context (GdkWindow     *window,
                           NULL);
 
   context->egl_config = config;
-  context->egl_context = ctx;
   context->is_attached = attached;
 
   return GDK_GL_CONTEXT (context);
diff --git a/gdk/x11/gdkglcontext-x11.c b/gdk/x11/gdkglcontext-x11.c
index 6eed9f9..9f525ad 100644
--- a/gdk/x11/gdkglcontext-x11.c
+++ b/gdk/x11/gdkglcontext-x11.c
@@ -534,6 +534,185 @@ gdk_x11_gl_context_texture_from_surface (GdkGLContext *paint_context,
   return TRUE;
 }
 
+static XVisualInfo *
+find_xvisinfo_for_fbconfig (GdkDisplay  *display,
+                            GLXFBConfig  config)
+{
+  Display *dpy = gdk_x11_display_get_xdisplay (display);
+
+  return glXGetVisualFromFBConfig (dpy, config);
+}
+
+static GLXContext
+create_gl3_context (GdkDisplay   *display,
+                    GLXFBConfig   config,
+                    GdkGLContext *share)
+{
+  /* There are no profiles before OpenGL 3.2.
+   *
+   * The GLX_ARB_create_context_profile spec says:
+   *
+   *   If the requested OpenGL version is less than 3.2,
+   *   GLX_CONTEXT_PROFILE_MASK_ARB is ignored and the functionality
+   *   of the context is determined solely by the requested version.
+   *
+   * Which means we can ask for the CORE_PROFILE_BIT without asking for
+   * a 3.2 version.
+   */
+  static const int attrib_list[] = {
+    GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
+    GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
+    GLX_CONTEXT_MINOR_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);
+}
+
+static gboolean
+gdk_x11_gl_context_realize (GdkGLContext  *context,
+                            GError       **error)
+{
+  GdkDisplay *display;
+  GdkX11GLContext *context_x11;
+  GLXWindow drawable;
+  XVisualInfo *xvisinfo;
+  Display *dpy;
+  DrawableInfo *info;
+  GdkGLProfile profile;
+  GdkGLContext *share;
+  GdkWindow *window;
+
+  window = gdk_gl_context_get_window (context);
+  display = gdk_window_get_display (window);
+  dpy = gdk_x11_display_get_xdisplay (display);
+  context_x11 = GDK_X11_GL_CONTEXT (context);
+  profile = gdk_gl_context_get_profile (context);
+  share = gdk_gl_context_get_shared_context (context);
+
+  /* we check for the presence of the GLX_ARB_create_context_profile
+   * extension before checking for a GLXFBConfig.
+   */
+  if (profile == GDK_GL_PROFILE_3_2_CORE)
+    {
+      GDK_NOTE (OPENGL, g_print ("Creating core GLX context\n"));
+      context_x11->glx_context = create_gl3_context (display, context_x11->glx_config, share);
+    }
+  else
+    {
+      /* GDK_GL_PROFILE_DEFAULT is currently
+       * equivalent to the LEGACY profile
+       */
+      profile = GDK_GL_PROFILE_LEGACY;
+      GDK_NOTE (OPENGL, g_print ("Creating legacy GLX context\n"));
+      context_x11->glx_context = create_gl_context (display, context_x11->glx_config, share);
+    }
+
+  if (context_x11->glx_context == NULL)
+    {
+      g_set_error_literal (error, GDK_GL_ERROR,
+                           GDK_GL_ERROR_NOT_AVAILABLE,
+                           _("Unable to create a GL context"));
+      return FALSE;
+    }
+
+  xvisinfo = find_xvisinfo_for_fbconfig (display, context_x11->glx_config);
+
+  info = get_glx_drawable_info (window->impl_window);
+  if (info == NULL)
+    {
+      XSetWindowAttributes attrs;
+      unsigned long mask;
+
+      gdk_x11_display_error_trap_push (display);
+
+      info = g_slice_new0 (DrawableInfo);
+      info->display = display;
+      info->last_frame_counter = 0;
+
+      attrs.override_redirect = True;
+      attrs.colormap = XCreateColormap (dpy, DefaultRootWindow (dpy), xvisinfo->visual, AllocNone);
+      attrs.border_pixel = 0;
+      mask = CWOverrideRedirect | CWColormap | CWBorderPixel;
+      info->dummy_xwin = XCreateWindow (dpy, DefaultRootWindow (dpy),
+                                        -100, -100, 1, 1,
+                                        0,
+                                        xvisinfo->depth,
+                                        CopyFromParent,
+                                        xvisinfo->visual,
+                                        mask,
+                                        &attrs);
+      XMapWindow(dpy, info->dummy_xwin);
+
+      if (GDK_X11_DISPLAY (display)->glx_version >= 13)
+        {
+          info->glx_drawable = glXCreateWindow (dpy, context_x11->glx_config,
+                                                gdk_x11_window_get_xid (window->impl_window),
+                                                NULL);
+          info->dummy_glx = glXCreateWindow (dpy, context_x11->glx_config, info->dummy_xwin, NULL);
+        }
+
+      if (gdk_x11_display_error_trap_pop (display))
+        {
+          g_set_error_literal (error, GDK_GL_ERROR,
+                               GDK_GL_ERROR_NOT_AVAILABLE,
+                               _("Unable to create a GL context"));
+
+          XFree (xvisinfo);
+          drawable_info_free (info);
+          glXDestroyContext (dpy, context_x11->glx_context);
+          context_x11->glx_context = NULL;
+
+          return FALSE;
+        }
+
+      set_glx_drawable_info (window->impl_window, info);
+    }
+
+  XFree (xvisinfo);
+
+  if (context_x11->is_attached)
+    drawable = info->glx_drawable ? info->glx_drawable : gdk_x11_window_get_xid (window->impl_window);
+  else
+    drawable = info->dummy_glx ? info->dummy_glx : info->dummy_xwin;
+
+  context_x11->is_direct = glXIsDirect (dpy, context_x11->glx_context);
+  context_x11->drawable = drawable;
+
+  GDK_NOTE (OPENGL,
+            g_print ("Realized GLX context[%p], %s\n",
+                     context_x11->glx_context,
+                     context_x11->is_direct ? "direct" : "indirect"));
+
+  return TRUE;
+}
+
 static void
 gdk_x11_gl_context_dispose (GObject *gobject)
 {
@@ -562,6 +741,7 @@ gdk_x11_gl_context_class_init (GdkX11GLContextClass *klass)
   GdkGLContextClass *context_class = GDK_GL_CONTEXT_CLASS (klass);
   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 
+  context_class->realize = gdk_x11_gl_context_realize;
   context_class->end_frame = gdk_x11_gl_context_end_frame;
   context_class->texture_from_surface = gdk_x11_gl_context_texture_from_surface;
 
@@ -645,11 +825,10 @@ gdk_x11_screen_init_gl (GdkScreen *screen)
 #define MAX_GLX_ATTRS   30
 
 static gboolean
-find_fbconfig_for_visual (GdkDisplay        *display,
-                         GdkVisual         *visual,
-                          GLXFBConfig       *fb_config_out,
-                          XVisualInfo      **visinfo_out,
-                          GError           **error)
+find_fbconfig_for_visual (GdkDisplay   *display,
+                         GdkVisual    *visual,
+                          GLXFBConfig  *fb_config_out,
+                          GError      **error)
 {
   static int attrs[MAX_GLX_ATTRS];
   Display *dpy = gdk_x11_display_get_xdisplay (display);
@@ -710,16 +889,15 @@ find_fbconfig_for_visual (GdkDisplay        *display,
         continue;
 
       if (visinfo->visualid != xvisual_id)
-        continue;
+        {
+          XFree (visinfo);
+          continue;
+        }
 
       if (fb_config_out != NULL)
         *fb_config_out = configs[i];
 
-      if (visinfo_out != NULL)
-        *visinfo_out = visinfo;
-      else
-        XFree (visinfo);
-
+      XFree (visinfo);
       retval = TRUE;
       goto out;
     }
@@ -734,58 +912,6 @@ out:
   return retval;
 }
 
-static GLXContext
-create_gl3_context (GdkDisplay   *display,
-                    GLXFBConfig   config,
-                    GdkGLContext *share)
-{
-  /* There are no profiles before OpenGL 3.2.
-   *
-   * The GLX_ARB_create_context_profile spec says:
-   *
-   *   If the requested OpenGL version is less than 3.2,
-   *   GLX_CONTEXT_PROFILE_MASK_ARB is ignored and the functionality
-   *   of the context is determined solely by the requested version.
-   *
-   * Which means we can ask for the CORE_PROFILE_BIT without asking for
-   * a 3.2 version.
-   */
-  static const int attrib_list[] = {
-    GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
-    GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
-    GLX_CONTEXT_MINOR_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);
-}
-
 struct glvisualinfo {
   int supports_gl;
   int double_buffer;
@@ -951,12 +1077,13 @@ save_cached_gl_visuals (GdkDisplay *display, int system, int rgba)
   visualdata[1] = rgba;
 
   gdk_x11_display_error_trap_push (display);
-  XChangeProperty(dpy, DefaultRootWindow (dpy), gdk_x11_get_xatom_by_name_for_display (display, 
"GDK_VISUALS"),
-                  XA_INTEGER, 32, PropModeReplace, (unsigned char *)visualdata, 2);
+  XChangeProperty (dpy, DefaultRootWindow (dpy),
+                   gdk_x11_get_xatom_by_name_for_display (display, "GDK_VISUALS"),
+                   XA_INTEGER, 32, PropModeReplace,
+                   (unsigned char *)visualdata, 2);
   gdk_x11_display_error_trap_pop_ignored (display);
 }
 
-
 void
 _gdk_x11_screen_update_visuals_for_gl (GdkScreen *screen)
 {
@@ -1038,27 +1165,24 @@ _gdk_x11_screen_update_visuals_for_gl (GdkScreen *screen)
                           x11_screen->rgba_visual ? gdk_x11_visual_get_xvisual 
(x11_screen->rgba_visual)->visualid : 0);
 }
 
-
 GdkGLContext *
 gdk_x11_window_create_gl_context (GdkWindow    *window,
-                                 gboolean      attached,
-                                 GdkGLProfile  profile,
-                                 GdkGLContext *share,
-                                 GError      **error)
+                                  gboolean      attached,
+                                  GdkGLProfile  profile,
+                                  GdkGLContext *share,
+                                  GError      **error)
 {
   GdkDisplay *display;
   GdkX11GLContext *context;
   GdkVisual *visual;
   GLXFBConfig config;
-  GLXContext glx_context;
-  GLXWindow drawable;
-  gboolean is_direct;
-  XVisualInfo *xvisinfo;
-  Display *dpy;
-  DrawableInfo *info;
 
   display = gdk_window_get_display (window);
 
+  /* GDK_GL_PROFILE_DEFAULT is currently equivalent to the LEGACY profile */
+  if (profile == GDK_GL_PROFILE_DEFAULT)
+    profile = GDK_GL_PROFILE_LEGACY;
+
   if (!gdk_x11_screen_init_gl (gdk_window_get_screen (window)))
     {
       g_set_error_literal (error, GDK_GL_ERROR,
@@ -1079,101 +1203,9 @@ gdk_x11_window_create_gl_context (GdkWindow    *window,
     }
 
   visual = gdk_window_get_visual (window);
-
-  if (!find_fbconfig_for_visual (display, visual, &config, &xvisinfo, error))
+  if (!find_fbconfig_for_visual (display, visual, &config, error))
     return NULL;
 
-  dpy = gdk_x11_display_get_xdisplay (display);
-
-  /* we check for the presence of the GLX_ARB_create_context_profile
-   * extension before checking for a GLXFBConfig.
-   */
-  if (profile == GDK_GL_PROFILE_3_2_CORE)
-    {
-      GDK_NOTE (OPENGL, g_print ("Creating core GLX context\n"));
-      glx_context = create_gl3_context (display, config, share);
-    }
-  else
-    {
-      /* GDK_GL_PROFILE_DEFAULT is currently
-       * equivalent to the LEGACY profile
-       */
-      profile = GDK_GL_PROFILE_LEGACY;
-      GDK_NOTE (OPENGL, g_print ("Creating legacy GLX context\n"));
-      glx_context = create_gl_context (display, config, share);
-    }
-
-  if (glx_context == NULL)
-    {
-      g_set_error_literal (error, GDK_GL_ERROR,
-                           GDK_GL_ERROR_NOT_AVAILABLE,
-                           _("Unable to create a GL context"));
-      return NULL;
-    }
-
-  is_direct = glXIsDirect (dpy, glx_context);
-
-  info = get_glx_drawable_info (window->impl_window);
-  if (info == NULL)
-    {
-      XSetWindowAttributes attrs;
-      unsigned long mask;
-
-      gdk_x11_display_error_trap_push (display);
-
-      info = g_slice_new0 (DrawableInfo);
-      info->display = display;
-      info->last_frame_counter = 0;
-
-      attrs.override_redirect = True;
-      attrs.colormap = XCreateColormap (dpy, DefaultRootWindow (dpy), xvisinfo->visual, AllocNone);
-      attrs.border_pixel = 0;
-      mask = CWOverrideRedirect | CWColormap | CWBorderPixel;
-      info->dummy_xwin = XCreateWindow (dpy, DefaultRootWindow (dpy),
-                                       -100, -100, 1, 1,
-                                       0,
-                                       xvisinfo->depth,
-                                       CopyFromParent,
-                                       xvisinfo->visual,
-                                       mask,
-                                       &attrs);
-      XMapWindow(dpy, info->dummy_xwin);
-
-      if (GDK_X11_DISPLAY (display)->glx_version >= 13)
-       {
-         info->glx_drawable = glXCreateWindow (dpy, config,
-                                               gdk_x11_window_get_xid (window->impl_window),
-                                               NULL);
-         info->dummy_glx = glXCreateWindow (dpy, config, info->dummy_xwin, NULL);
-       }
-
-      if (gdk_x11_display_error_trap_pop (display))
-       {
-         g_set_error_literal (error, GDK_GL_ERROR,
-                              GDK_GL_ERROR_NOT_AVAILABLE,
-                              _("Unable to create a GL context"));
-
-         drawable_info_free (info);
-         glXDestroyContext (dpy, glx_context);
-
-         return NULL;
-       }
-
-      set_glx_drawable_info (window->impl_window, info);
-    }
-
-  XFree (xvisinfo);
-
-  if (attached)
-    drawable = info->glx_drawable ? info->glx_drawable : gdk_x11_window_get_xid (window->impl_window);
-  else
-    drawable = info->dummy_glx ? info->dummy_glx : info->dummy_xwin;
-
-  GDK_NOTE (OPENGL,
-            g_print ("Created GLX context[%p], %s\n",
-                     glx_context,
-                     is_direct ? "direct" : "indirect"));
-
   context = g_object_new (GDK_TYPE_X11_GL_CONTEXT,
                           "display", display,
                           "window", window,
@@ -1183,10 +1215,7 @@ gdk_x11_window_create_gl_context (GdkWindow    *window,
 
   context->profile = profile;
   context->glx_config = config;
-  context->glx_context = glx_context;
-  context->drawable = drawable;
   context->is_attached = attached;
-  context->is_direct = is_direct;
 
   return GDK_GL_CONTEXT (context);
 }
diff --git a/gtk/gtkglarea.c b/gtk/gtkglarea.c
index ee7a30f..b5f8a65 100644
--- a/gtk/gtkglarea.c
+++ b/gtk/gtkglarea.c
@@ -322,8 +322,21 @@ gtk_gl_area_real_create_context (GtkGLArea *area)
   GError *error = NULL;
   GdkGLContext *context;
 
-  context = gdk_window_create_gl_context (gtk_widget_get_window (widget), priv->profile, &priv->error);
-  gtk_gl_area_set_error (area, error);
+  context = gdk_window_create_gl_context (gtk_widget_get_window (widget), priv->profile, &error);
+  if (priv->error != NULL)
+    {
+      gtk_gl_area_set_error (area, error);
+      g_clear_object (&context);
+      return NULL;
+    }
+
+  gdk_gl_context_realize (context, &error);
+  if (priv->error != NULL)
+    {
+      gtk_gl_area_set_error (area, error);
+      g_clear_object (&context);
+      return NULL;
+    }
 
   return context;
 }


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