mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-11-10 10:50:10 +00:00
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:
parent
8f50148a34
commit
22e6f37c9c
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -1116,7 +1116,6 @@ GdkGLContext * gdk_window_create_gl_context (GdkWindow *window,
|
||||
GdkGLProfile profile,
|
||||
GError **error);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GDK_WINDOW_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__ */
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user