}
/**
- * gl_make_current:
+ * gl_create_context:
* @dpy: an X11 #Display
- * @win: an X11 #Window
- * @ctx: the requested GLX context
- * @state: an optional #GLContextState
+ * @screen: the associated screen of @dpy
+ * @parent: the parent #GLContextState, or %NULL if none is to be used
*
- * Makes the @window GLX context the current GLX rendering context of
+ * Creates a GLX context sharing textures and displays lists with
+ * @parent, if not %NULL.
+ *
+ * Return value: the newly created GLX context
+ */
+GLContextState *
+gl_create_context(Display *dpy, int screen, GLContextState *parent)
+{
+ GLContextState *cs;
+ GLXFBConfig *fb_configs = NULL;
+ int n_fb_configs;
+
+ static GLint fb_config_attrs[] = {
+ GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
+ GLX_RENDER_TYPE, GLX_RGBA_BIT,
+ GLX_DOUBLEBUFFER, True,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ None
+ };
+
+ cs = malloc(sizeof(*cs));
+ if (!cs)
+ goto error;
+
+ cs->display = dpy;
+ cs->window = parent ? parent->window : None;
+ cs->visual = NULL;
+ cs->context = NULL;
+ cs->swapped_buffers = FALSE;
+
+ fb_configs = glXChooseFBConfig(dpy, screen, fb_config_attrs, &n_fb_configs);
+ if (!fb_configs)
+ goto error;
+
+ cs->visual = glXGetVisualFromFBConfig(dpy, fb_configs[0]);
+ if (!cs->visual)
+ goto error;
+
+ cs->context = glXCreateNewContext(
+ dpy,
+ fb_configs[0],
+ GLX_RGBA_TYPE,
+ parent ? parent->context : NULL,
+ True
+ );
+ if (cs->context)
+ goto end;
+
+error:
+ gl_destroy_context(cs);
+ cs = NULL;
+end:
+ if (fb_configs)
+ XFree(fb_configs);
+ return cs;
+}
+
+/**
+ * gl_destroy_context:
+ * @cs: a #GLContextState
+ *
+ * Destroys the GLX context @cs
+ */
+void
+gl_destroy_context(GLContextState *cs)
+{
+ if (!cs)
+ return;
+
+ if (cs->visual) {
+ XFree(cs->visual);
+ cs->visual = NULL;
+ }
+
+ if (cs->display && cs->context) {
+ if (glXGetCurrentContext() == cs->context) {
+ /* XXX: if buffers were never swapped, the application
+ will crash later with the NVIDIA driver */
+ if (!cs->swapped_buffers)
+ gl_swap_buffers(cs);
+ glXMakeCurrent(cs->display, None, NULL);
+ }
+ glXDestroyContext(cs->display, cs->context);
+ cs->display = NULL;
+ cs->context = NULL;
+ }
+ free(cs);
+}
+
+/**
+ * gl_get_current_context:
+ * @cs: return location to the current #GLContextState
+ *
+ * Retrieves the current GLX context, display and drawable packed into
+ * the #GLContextState struct.
+ */
+void
+gl_get_current_context(GLContextState *cs)
+{
+ cs->display = glXGetCurrentDisplay();
+ cs->window = glXGetCurrentDrawable();
+ cs->context = glXGetCurrentContext();
+}
+
+/**
+ * gl_set_current_context:
+ * @new_cs: the requested new #GLContextState
+ * @old_cs: return location to the context that was previously current
+ *
+ * Makes the @new_cs GLX context the current GLX rendering context of
* the calling thread, replacing the previously current context if
* there was one.
*
- * If @state is non %NULL, the previously current GLX context and
+ * If @old_cs is non %NULL, the previously current GLX context and
* window are recorded.
*
* Return value: %TRUE on success
*/
gboolean
-gl_make_current(Display *dpy, Window win, GLXContext ctx, GLContextState *state)
+gl_set_current_context(GLContextState *new_cs, GLContextState *old_cs)
{
- if (state) {
- state->context = glXGetCurrentContext();
- state->window = glXGetCurrentDrawable();
- if (state->context == ctx && state->window == win)
+ /* If display is NULL, this could be that new_cs was retrieved from
+ gl_get_current_context() with none set previously. If that case,
+ the other fields are also NULL and we don't return an error */
+ if (!new_cs->display)
+ return !new_cs->window && !new_cs->context;
+
+ if (old_cs) {
+ if (old_cs == new_cs)
+ return TRUE;
+ gl_get_current_context(old_cs);
+ if (old_cs->display == new_cs->display &&
+ old_cs->window == new_cs->window &&
+ old_cs->context == new_cs->context)
return TRUE;
}
- return glXMakeCurrent(dpy, win, ctx);
+ return glXMakeCurrent(new_cs->display, new_cs->window, new_cs->context);
}
/**
* gl_swap_buffers:
- * @dpy: an X11 #Display
- * @win: an X11 #Window
+ * @cs: a #GLContextState
*
* Promotes the contents of the back buffer of the @win window to
* become the contents of the front buffer. This simply is wrapper
* around glXSwapBuffers().
*/
void
-gl_swap_buffers(Display *dpy, Window win)
+gl_swap_buffers(GLContextState *cs)
{
- glXSwapBuffers(dpy, win);
+ glXSwapBuffers(cs->display, cs->window);
+ cs->swapped_buffers = TRUE;
}
/**
GstVaapiWindowGLXPrivate))
struct _GstVaapiWindowGLXPrivate {
- XVisualInfo *vi;
- XVisualInfo vi_static;
Colormap cmap;
- GLXContext context;
+ GLContextState *gl_context;
guint is_constructed : 1;
- guint foreign_context : 1;
guint foreign_window : 1;
- guint swapped_buffers : 1;
};
enum {
PROP_GLX_CONTEXT
};
-static XVisualInfo *
-gst_vaapi_window_glx_create_visual(GstVaapiWindowGLX *window);
-
/* Fill rectangle coords with capped bounds */
static inline void
fill_rect(
}
}
-static inline void
-_gst_vaapi_window_glx_set_context(
- GstVaapiWindowGLX *window,
- GLXContext context,
- gboolean is_foreign
-)
-{
- GstVaapiWindowGLXPrivate * const priv = window->priv;
-
- priv->context = context;
- priv->foreign_context = is_foreign;
-}
-
static void
-gst_vaapi_window_glx_destroy_context(GstVaapiWindowGLX *window)
+_gst_vaapi_window_glx_destroy_context(GstVaapiWindowGLX *window)
{
GstVaapiWindowGLXPrivate * const priv = window->priv;
- Display * const dpy = GST_VAAPI_OBJECT_XDISPLAY(window);
- if (priv->context) {
- if (!priv->foreign_context) {
- GST_VAAPI_OBJECT_LOCK_DISPLAY(window);
- if (glXGetCurrentContext() == priv->context) {
- /* XXX: if buffers were never swapped, the application
- will crash later with the NVIDIA driver */
- if (!priv->swapped_buffers)
- gl_swap_buffers(dpy, GST_VAAPI_OBJECT_ID(window));
- gl_make_current(dpy, None, NULL, NULL);
- }
- glXDestroyContext(dpy, priv->context);
- GST_VAAPI_OBJECT_UNLOCK_DISPLAY(window);
- }
- priv->context = NULL;
- priv->foreign_context = FALSE;
+ GST_VAAPI_OBJECT_LOCK_DISPLAY(window);
+ if (priv->gl_context) {
+ gl_destroy_context(priv->gl_context);
+ priv->gl_context = NULL;
}
+ GST_VAAPI_OBJECT_UNLOCK_DISPLAY(window);
}
static gboolean
-gst_vaapi_window_glx_create_context(GstVaapiWindowGLX *window)
+_gst_vaapi_window_glx_create_context(
+ GstVaapiWindowGLX *window,
+ GLXContext foreign_context
+)
{
GstVaapiWindowGLXPrivate * const priv = window->priv;
Display * const dpy = GST_VAAPI_OBJECT_XDISPLAY(window);
- GLXContext ctx = NULL;
- GLContextState cs;
- guint width, height;
- gboolean has_errors = TRUE;
+ GLContextState parent_cs;
- if (!gst_vaapi_window_glx_create_visual(window))
- return FALSE;
+ parent_cs.display = dpy;
+ parent_cs.window = None;
+ parent_cs.context = foreign_context;
GST_VAAPI_OBJECT_LOCK_DISPLAY(window);
- ctx = glXCreateContext(dpy, priv->vi, NULL, True);
- if (ctx && glXIsDirect(dpy, ctx)) {
- _gst_vaapi_window_glx_set_context(window, ctx, FALSE);
- if (gl_make_current(dpy, GST_VAAPI_OBJECT_ID(window), ctx, &cs)) {
- glDisable(GL_DEPTH_TEST);
- glDepthMask(GL_FALSE);
- glDisable(GL_CULL_FACE);
- glDrawBuffer(GL_BACK);
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
- gst_vaapi_window_get_size(GST_VAAPI_WINDOW(window), &width, &height);
- gl_resize(width, height);
-
- gl_set_bgcolor(0);
- glClear(GL_COLOR_BUFFER_BIT);
- if (cs.context)
- gl_make_current(dpy, cs.window, cs.context, NULL);
- has_errors = FALSE;
- }
+ priv->gl_context = gl_create_context(dpy, DefaultScreen(dpy), &parent_cs);
+ if (!priv->gl_context) {
+ GST_DEBUG("could not create GLX context");
+ goto end;
}
- else if (ctx)
- glXDestroyContext(dpy, ctx);
- GST_VAAPI_OBJECT_UNLOCK_DISPLAY(window);
- return !has_errors;
+ if (!glXIsDirect(dpy, priv->gl_context->context)) {
+ GST_DEBUG("could not create a direct-rendering GLX context");
+ goto out_destroy_context;
+ }
+ goto end;
+
+out_destroy_context:
+ gl_destroy_context(priv->gl_context);
+ priv->gl_context = NULL;
+end:
+ GST_VAAPI_OBJECT_UNLOCK_DISPLAY(window);
+ return priv->gl_context != NULL;
}
-static inline void
-gst_vaapi_window_glx_destroy_visual(GstVaapiWindowGLX *window)
+static gboolean
+_gst_vaapi_window_glx_ensure_context(
+ GstVaapiWindowGLX *window,
+ GLXContext foreign_context
+)
{
GstVaapiWindowGLXPrivate * const priv = window->priv;
- if (priv->vi) {
- if (priv->vi != &priv->vi_static)
- XFree(priv->vi);
- priv->vi = NULL;
+ if (priv->gl_context) {
+ if (!foreign_context || foreign_context == priv->gl_context->context)
+ return TRUE;
+ _gst_vaapi_window_glx_destroy_context(window);
}
+ return _gst_vaapi_window_glx_create_context(window, foreign_context);
}
-static XVisualInfo *
-gst_vaapi_window_glx_create_visual(GstVaapiWindowGLX *window)
+static gboolean
+gst_vaapi_window_glx_ensure_context(
+ GstVaapiWindowGLX *window,
+ GLXContext foreign_context
+)
{
GstVaapiWindowGLXPrivate * const priv = window->priv;
- Display * const dpy = GST_VAAPI_OBJECT_XDISPLAY(window);
- XWindowAttributes wattr;
- int screen;
- gboolean has_errors;
-
- /* XXX: add and use a GstVaapiWindow:double-buffer property? */
- static GLint gl_visual_attr[] = {
- GLX_RGBA,
- GLX_RED_SIZE, 1,
- GLX_GREEN_SIZE, 1,
- GLX_BLUE_SIZE, 1,
- GLX_DOUBLEBUFFER,
- GL_NONE
- };
-
- if (!priv->vi) {
- /* XXX: add and use a GstVaapiDisplayX11:x11-screen property? */
- screen = DefaultScreen(dpy);
-
- GST_VAAPI_OBJECT_LOCK_DISPLAY(window);
- x11_trap_errors();
- if (!priv->foreign_window)
- priv->vi = glXChooseVisual(dpy, screen, gl_visual_attr);
- else {
- XGetWindowAttributes(dpy, GST_VAAPI_OBJECT_ID(window), &wattr);
- if (XMatchVisualInfo(dpy, screen, wattr.depth, wattr.visual->class,
- &priv->vi_static))
- priv->vi = &priv->vi_static;
- }
- has_errors = x11_untrap_errors() != 0;
- GST_VAAPI_OBJECT_UNLOCK_DISPLAY(window);
+ GLContextState old_cs;
+ guint width, height;
- if (has_errors)
- return NULL;
+ if (!_gst_vaapi_window_glx_ensure_context(window, foreign_context))
+ return FALSE;
+
+ priv->gl_context->window = GST_VAAPI_OBJECT_ID(window);
+ if (!gl_set_current_context(priv->gl_context, &old_cs)) {
+ GST_DEBUG("could not make newly created GLX context current");
+ return FALSE;
}
- return priv->vi;
+
+ glDisable(GL_DEPTH_TEST);
+ glDepthMask(GL_FALSE);
+ glDisable(GL_CULL_FACE);
+ glDrawBuffer(GL_BACK);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ gst_vaapi_window_get_size(GST_VAAPI_WINDOW(window), &width, &height);
+ gl_resize(width, height);
+
+ gl_set_bgcolor(0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ gl_set_current_context(&old_cs, NULL);
+ return TRUE;
}
static Visual *
gst_vaapi_window_glx_get_visual(GstVaapiWindow *window)
{
- XVisualInfo *vi;
+ GstVaapiWindowGLX * const glx_window = GST_VAAPI_WINDOW_GLX(window);
- vi = gst_vaapi_window_glx_create_visual(GST_VAAPI_WINDOW_GLX(window));
- if (!vi)
+ if (!_gst_vaapi_window_glx_ensure_context(glx_window, NULL))
return NULL;
- return vi->visual;
+ return glx_window->priv->gl_context->visual->visual;
}
static void
Display * const dpy = GST_VAAPI_OBJECT_XDISPLAY(window);
int screen;
XWindowAttributes wattr;
- XVisualInfo *vi;
- gboolean has_errors;
+ gboolean success = FALSE;
if (!priv->cmap) {
- GST_VAAPI_OBJECT_LOCK_DISPLAY(window);
- x11_trap_errors();
if (!priv->foreign_window) {
- vi = gst_vaapi_window_glx_create_visual(window);
- if (vi) {
- /* XXX: add a GstVaapiDisplayX11:x11-screen property? */
- screen = DefaultScreen(dpy);
- priv->cmap = XCreateColormap(
- dpy,
- RootWindow(dpy, screen),
- vi->visual,
- AllocNone
- );
- }
+ if (!_gst_vaapi_window_glx_ensure_context(window, NULL))
+ return None;
+ GST_VAAPI_OBJECT_LOCK_DISPLAY(window);
+ x11_trap_errors();
+ /* XXX: add a GstVaapiDisplayX11:x11-screen property? */
+ screen = DefaultScreen(dpy);
+ priv->cmap = XCreateColormap(
+ dpy,
+ RootWindow(dpy, screen),
+ priv->gl_context->visual->visual,
+ AllocNone
+ );
+ success = x11_untrap_errors() == 0;
+ GST_VAAPI_OBJECT_UNLOCK_DISPLAY(window);
}
else {
+ GST_VAAPI_OBJECT_LOCK_DISPLAY(window);
+ x11_trap_errors();
XGetWindowAttributes(dpy, GST_VAAPI_OBJECT_ID(window), &wattr);
priv->cmap = wattr.colormap;
+ success = x11_untrap_errors() == 0;
+ GST_VAAPI_OBJECT_UNLOCK_DISPLAY(window);
}
- has_errors = x11_untrap_errors() != 0;
- GST_VAAPI_OBJECT_UNLOCK_DISPLAY(window);
-
- if (has_errors)
+ if (!success)
return None;
}
return priv->cmap;
{
GstVaapiWindowGLXPrivate * const priv = GST_VAAPI_WINDOW_GLX(window)->priv;
Display * const dpy = GST_VAAPI_OBJECT_XDISPLAY(window);
- GLContextState cs;
+ GLContextState old_cs;
if (!GST_VAAPI_WINDOW_CLASS(gst_vaapi_window_glx_parent_class)->
resize(window, width, height))
GST_VAAPI_OBJECT_LOCK_DISPLAY(window);
XSync(dpy, False); /* make sure resize completed */
- if (gl_make_current(dpy, GST_VAAPI_OBJECT_ID(window), priv->context, &cs)) {
+ if (gl_set_current_context(priv->gl_context, &old_cs)) {
gl_resize(width, height);
- if (cs.context)
- gl_make_current(dpy, cs.window, cs.context, NULL);
+ gl_set_current_context(&old_cs, NULL);
}
GST_VAAPI_OBJECT_UNLOCK_DISPLAY(window);
return TRUE;
{
GstVaapiWindowGLX * const window = GST_VAAPI_WINDOW_GLX(object);
- gst_vaapi_window_glx_destroy_context(window);
- gst_vaapi_window_glx_destroy_visual(window);
+ _gst_vaapi_window_glx_destroy_context(window);
gst_vaapi_window_glx_destroy_colormap(window);
G_OBJECT_CLASS(gst_vaapi_window_glx_parent_class)->finalize(object);
GstVaapiWindowGLXPrivate * const priv = GST_VAAPI_WINDOW_GLX(object)->priv;
GObjectClass *parent_class;
- priv->foreign_context = priv->context != NULL;
-
parent_class = G_OBJECT_CLASS(gst_vaapi_window_glx_parent_class);
if (parent_class->constructed)
parent_class->constructed(object);
priv->foreign_window =
gst_vaapi_window_x11_is_foreign_xid(GST_VAAPI_WINDOW_X11(object));
- priv->is_constructed = priv->foreign_context ||
- gst_vaapi_window_glx_create_context(GST_VAAPI_WINDOW_GLX(object));
+ priv->is_constructed =
+ gst_vaapi_window_glx_ensure_context(GST_VAAPI_WINDOW_GLX(object), NULL);
}
static void
GstVaapiWindowGLXPrivate *priv = GST_VAAPI_WINDOW_GLX_GET_PRIVATE(window);
window->priv = priv;
- priv->vi = NULL;
priv->cmap = None;
- priv->context = NULL;
+ priv->gl_context = NULL;
priv->is_constructed = FALSE;
- priv->foreign_context = FALSE;
priv->foreign_window = FALSE;
- priv->swapped_buffers = FALSE;
}
/**
g_return_val_if_fail(GST_VAAPI_IS_WINDOW_GLX(window), NULL);
g_return_val_if_fail(window->priv->is_constructed, FALSE);
- return window->priv->context;
+ return window->priv->gl_context->context;
}
/**
g_return_val_if_fail(GST_VAAPI_IS_WINDOW_GLX(window), FALSE);
g_return_val_if_fail(window->priv->is_constructed, FALSE);
- gst_vaapi_window_glx_destroy_context(window);
-
- if (ctx) {
- _gst_vaapi_window_glx_set_context(window, ctx, TRUE);
- return TRUE;
- }
- return gst_vaapi_window_glx_create_context(window);
+ return gst_vaapi_window_glx_ensure_context(window, ctx);
}
/**
g_return_val_if_fail(window->priv->is_constructed, FALSE);
GST_VAAPI_OBJECT_LOCK_DISPLAY(window);
- success = gl_make_current(
- GST_VAAPI_OBJECT_XDISPLAY(window),
- GST_VAAPI_OBJECT_ID(window),
- window->priv->context,
- NULL
- );
+ success = gl_set_current_context(window->priv->gl_context, NULL);
GST_VAAPI_OBJECT_UNLOCK_DISPLAY(window);
return success;
}
g_return_if_fail(window->priv->is_constructed);
GST_VAAPI_OBJECT_LOCK_DISPLAY(window);
- gl_swap_buffers(
- GST_VAAPI_OBJECT_XDISPLAY(window),
- GST_VAAPI_OBJECT_ID(window)
- );
- glClear(GL_COLOR_BUFFER_BIT);
+ gl_swap_buffers(window->priv->gl_context);
GST_VAAPI_OBJECT_UNLOCK_DISPLAY(window);
-
- window->priv->swapped_buffers = TRUE;
}
/**