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
This commit is contained in:
Emmanuele Bassi 2015-01-27 21:23:23 +00:00
parent 8f50148a34
commit 22e6f37c9c
9 changed files with 363 additions and 225 deletions

View File

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

View File

@ -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
void gdk_gl_context_make_current (GdkGLContext *context);
gboolean gdk_gl_context_realize (GdkGLContext *context,
GError **error);
GDK_AVAILABLE_IN_3_16
GdkGLContext * gdk_gl_context_get_current (void);
void gdk_gl_context_make_current (GdkGLContext *context);
GDK_AVAILABLE_IN_3_16
void gdk_gl_context_clear_current (void);
GdkGLContext * gdk_gl_context_get_current (void);
GDK_AVAILABLE_IN_3_16
void gdk_gl_context_clear_current (void);
G_END_DECLS

View File

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

View File

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

View File

@ -1116,7 +1116,6 @@ GdkGLContext * gdk_window_create_gl_context (GdkWindow *window,
GdkGLProfile profile,
GError **error);
G_END_DECLS
#endif /* __GDK_WINDOW_H__ */

View File

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

View File

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

View File

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

View File

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