gstreamer/gst-libs/gst/vaapi/gstvaapidisplay_egl.c
Hyunjun Ko a80e10ac5c libs: display{egl,glx}: cache GstVaapiTextures
instances when created and reuse

This patch improves performance when glimagesink uploads a GL texture.

It caches the GStVaapiTexture instances in GstVaapiDisplay{GLX,EGL}, using an
instance of GstVaapiTextureMap, so our internal texture structure can be found
by matching the GL texture id for each frame upload process, avoiding the
internal texture structure creation and its following destruction.

https://bugzilla.gnome.org/show_bug.cgi?id=769293

Signed-off-by: Víctor Manuel Jáquez Leal <victorx.jaquez@intel.com>
2016-09-22 17:01:59 +02:00

429 lines
13 KiB
C

/*
* gstvaapidisplay_egl.c - VA/EGL display abstraction
*
* Copyright (C) 2014 Intel Corporation
* Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1
* of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
#include "sysdeps.h"
#include <gmodule.h>
#include "gstvaapidisplay_egl.h"
#include "gstvaapidisplay_egl_priv.h"
#include "gstvaapiwindow.h"
#include "gstvaapiwindow_egl.h"
#include "gstvaapiwindow_priv.h"
#include "gstvaapitexture_egl.h"
#if USE_X11
#include "gstvaapidisplay_x11.h"
#endif
#if USE_WAYLAND
#include "gstvaapidisplay_wayland.h"
#endif
GST_DEBUG_CATEGORY (gst_debug_vaapidisplay_egl);
/* ------------------------------------------------------------------------- */
/* --- EGL backend implementation --- */
/* ------------------------------------------------------------------------- */
typedef struct
{
gpointer display;
guint display_type;
guint gles_version;
} InitParams;
static gboolean
reset_context (GstVaapiDisplayEGL * display, EGLContext gl_context)
{
EglConfig *config;
EglContext *ctx;
egl_object_replace (&display->egl_context, NULL);
if (gl_context != EGL_NO_CONTEXT)
ctx = egl_context_new_wrapped (display->egl_display, gl_context);
else {
config = egl_config_new (display->egl_display, display->gles_version,
GST_VIDEO_FORMAT_RGB);
if (!config)
return FALSE;
ctx = egl_context_new (display->egl_display, config, NULL);
egl_object_unref (config);
}
if (!ctx)
return FALSE;
egl_object_replace (&display->egl_context, ctx);
egl_object_unref (ctx);
return TRUE;
}
static inline gboolean
ensure_context (GstVaapiDisplayEGL * display)
{
return display->egl_context || reset_context (display, EGL_NO_CONTEXT);
}
static inline gboolean
ensure_context_is_wrapped (GstVaapiDisplayEGL * display, EGLContext gl_context)
{
return (display->egl_context &&
display->egl_context->base.handle.p == gl_context) ||
reset_context (display, gl_context);
}
static gboolean
gst_vaapi_display_egl_bind_display (GstVaapiDisplayEGL * display,
const InitParams * params)
{
GstVaapiDisplay *native_display = NULL;
EglDisplay *egl_display;
if (params->display) {
#if USE_X11
if (params->display_type == GST_VAAPI_DISPLAY_TYPE_X11)
native_display = gst_vaapi_display_x11_new_with_display (params->display);
#endif
#if USE_WAYLAND
if (params->display_type == GST_VAAPI_DISPLAY_TYPE_WAYLAND)
native_display =
gst_vaapi_display_wayland_new_with_display (params->display);
#endif
} else {
#if USE_X11
native_display = gst_vaapi_display_x11_new (NULL);
#endif
#if USE_WAYLAND
if (!native_display)
native_display = gst_vaapi_display_wayland_new (NULL);
#endif
}
if (!native_display)
return FALSE;
gst_vaapi_display_replace (&display->display, native_display);
gst_vaapi_display_unref (native_display);
egl_display = egl_display_new (GST_VAAPI_DISPLAY_NATIVE (display->display));
if (!egl_display)
return FALSE;
egl_object_replace (&display->egl_display, egl_display);
egl_object_unref (egl_display);
display->gles_version = params->gles_version;
return TRUE;
}
static void
gst_vaapi_display_egl_close_display (GstVaapiDisplayEGL * display)
{
gst_vaapi_display_replace (&display->display, NULL);
}
static void
gst_vaapi_display_egl_lock (GstVaapiDisplayEGL * display)
{
GstVaapiDisplayClass *const klass =
GST_VAAPI_DISPLAY_GET_CLASS (display->display);
if (klass->lock)
klass->lock (display->display);
}
static void
gst_vaapi_display_egl_unlock (GstVaapiDisplayEGL * display)
{
GstVaapiDisplayClass *const klass =
GST_VAAPI_DISPLAY_GET_CLASS (display->display);
if (klass->unlock)
klass->unlock (display->display);
}
static void
gst_vaapi_display_egl_sync (GstVaapiDisplayEGL * display)
{
GstVaapiDisplayClass *const klass =
GST_VAAPI_DISPLAY_GET_CLASS (display->display);
if (klass->sync)
klass->sync (display->display);
else if (klass->flush)
klass->flush (display->display);
}
static void
gst_vaapi_display_egl_flush (GstVaapiDisplayEGL * display)
{
GstVaapiDisplayClass *const klass =
GST_VAAPI_DISPLAY_GET_CLASS (display->display);
if (klass->flush)
klass->flush (display->display);
}
static gboolean
gst_vaapi_display_egl_get_display_info (GstVaapiDisplayEGL * display,
GstVaapiDisplayInfo * info)
{
GstVaapiDisplayClass *const klass =
GST_VAAPI_DISPLAY_GET_CLASS (display->display);
if (klass->get_display && !klass->get_display (display->display, info))
return FALSE;
return TRUE;
}
static void
gst_vaapi_display_egl_get_size (GstVaapiDisplayEGL * display,
guint * width_ptr, guint * height_ptr)
{
GstVaapiDisplayClass *const klass =
GST_VAAPI_DISPLAY_GET_CLASS (display->display);
if (klass->get_size)
klass->get_size (display->display, width_ptr, height_ptr);
}
static void
gst_vaapi_display_egl_get_size_mm (GstVaapiDisplayEGL * display,
guint * width_ptr, guint * height_ptr)
{
GstVaapiDisplayClass *const klass =
GST_VAAPI_DISPLAY_GET_CLASS (display->display);
if (klass->get_size_mm)
klass->get_size_mm (display->display, width_ptr, height_ptr);
}
static guintptr
gst_vaapi_display_egl_get_visual_id (GstVaapiDisplayEGL * display,
GstVaapiWindow * window)
{
if (!ensure_context (display))
return 0;
return display->egl_context->config->visual_id;
}
static GstVaapiWindow *
gst_vaapi_display_egl_create_window (GstVaapiDisplay * display, GstVaapiID id,
guint width, guint height)
{
if (id != GST_VAAPI_ID_INVALID)
return NULL;
return gst_vaapi_window_egl_new (display, width, height);
}
static void
ensure_texture_map (GstVaapiDisplayEGL * display)
{
if (!display->texture_map)
display->texture_map = gst_vaapi_texture_map_new ();
}
static GstVaapiTexture *
gst_vaapi_display_egl_create_texture (GstVaapiDisplay * display, GstVaapiID id,
guint target, guint format, guint width, guint height)
{
GstVaapiDisplayEGL *dpy = GST_VAAPI_DISPLAY_EGL (display);
GstVaapiTexture *texture;
if (id == GST_VAAPI_ID_INVALID)
return gst_vaapi_texture_egl_new (display, target, format, width, height);
ensure_texture_map (dpy);
if (!(texture = gst_vaapi_texture_map_lookup (dpy->texture_map, id))) {
if ((texture =
gst_vaapi_texture_egl_new_wrapped (display, id, target, format,
width, height))) {
gst_vaapi_texture_map_add (dpy->texture_map, texture, id);
}
}
return texture;
}
static GstVaapiTextureMap *
gst_vaapi_display_egl_get_texture_map (GstVaapiDisplay * display)
{
return GST_VAAPI_DISPLAY_EGL (display)->texture_map;
}
static void
gst_vaapi_display_egl_finalize (GstVaapiDisplay * display)
{
GstVaapiDisplayEGL *dpy = GST_VAAPI_DISPLAY_EGL (display);
if (dpy->texture_map)
gst_object_unref (dpy->texture_map);
GST_VAAPI_DISPLAY_EGL_GET_CLASS (display)->parent_finalize (display);
}
static void
gst_vaapi_display_egl_class_init (GstVaapiDisplayEGLClass * klass)
{
GstVaapiMiniObjectClass *const object_class =
GST_VAAPI_MINI_OBJECT_CLASS (klass);
GstVaapiDisplayClass *const dpy_class = GST_VAAPI_DISPLAY_CLASS (klass);
GST_DEBUG_CATEGORY_INIT (gst_debug_vaapidisplay_egl, "vaapidisplay_egl", 0,
"VA/EGL backend");
gst_vaapi_display_class_init (dpy_class);
/* chain up destructor */
klass->parent_finalize = object_class->finalize;
object_class->finalize = (GDestroyNotify) gst_vaapi_display_egl_finalize;
object_class->size = sizeof (GstVaapiDisplayEGL);
dpy_class->display_type = GST_VAAPI_DISPLAY_TYPE_EGL;
dpy_class->bind_display = (GstVaapiDisplayBindFunc)
gst_vaapi_display_egl_bind_display;
dpy_class->close_display = (GstVaapiDisplayCloseFunc)
gst_vaapi_display_egl_close_display;
dpy_class->lock = (GstVaapiDisplayLockFunc)
gst_vaapi_display_egl_lock;
dpy_class->unlock = (GstVaapiDisplayUnlockFunc)
gst_vaapi_display_egl_unlock;
dpy_class->sync = (GstVaapiDisplaySyncFunc)
gst_vaapi_display_egl_sync;
dpy_class->flush = (GstVaapiDisplayFlushFunc)
gst_vaapi_display_egl_flush;
dpy_class->get_display = (GstVaapiDisplayGetInfoFunc)
gst_vaapi_display_egl_get_display_info;
dpy_class->get_size = (GstVaapiDisplayGetSizeFunc)
gst_vaapi_display_egl_get_size;
dpy_class->get_size_mm = (GstVaapiDisplayGetSizeMFunc)
gst_vaapi_display_egl_get_size_mm;
dpy_class->get_visual_id = (GstVaapiDisplayGetVisualIdFunc)
gst_vaapi_display_egl_get_visual_id;
dpy_class->create_window = (GstVaapiDisplayCreateWindowFunc)
gst_vaapi_display_egl_create_window;
dpy_class->create_texture = (GstVaapiDisplayCreateTextureFunc)
gst_vaapi_display_egl_create_texture;
dpy_class->get_texture_map = gst_vaapi_display_egl_get_texture_map;
}
static inline const GstVaapiDisplayClass *
gst_vaapi_display_egl_class (void)
{
static GstVaapiDisplayEGLClass g_class;
static gsize g_class_init = FALSE;
if (g_once_init_enter (&g_class_init)) {
gst_vaapi_display_egl_class_init (&g_class);
g_once_init_leave (&g_class_init, TRUE);
}
return GST_VAAPI_DISPLAY_CLASS (&g_class);
}
/**
* gst_vaapi_display_egl_new:
* @display: a #GstVaapiDisplay, or %NULL to pick any one
* @gles_version: the OpenGL ES version API to use
*
* Creates a new #GstVaapiDisplay object suitable in EGL context. If
* the native @display is %NULL, then any type of display is picked,
* i.e. one that can be successfully opened. The @gles_version will
* further ensure the OpenGL ES API to use, or zero to indicate
* "desktop" OpenGL.
*
* Return value: a newly allocated #GstVaapiDisplay object
*/
GstVaapiDisplay *
gst_vaapi_display_egl_new (GstVaapiDisplay * display, guint gles_version)
{
InitParams params;
if (display) {
params.display = GST_VAAPI_DISPLAY_NATIVE (display);
params.display_type = GST_VAAPI_DISPLAY_VADISPLAY_TYPE (display);
} else {
params.display = NULL;
params.display_type = GST_VAAPI_DISPLAY_TYPE_ANY;
}
params.gles_version = gles_version;
return gst_vaapi_display_new (gst_vaapi_display_egl_class (),
GST_VAAPI_DISPLAY_INIT_FROM_NATIVE_DISPLAY, &params);
}
/**
* gst_vaapi_display_egl_new_with_native_display:
* @native_display: an EGLDisplay object
* @display_type: the display type of @native_display
* @gles_version: the OpenGL ES version API to use
*
* Creates a #GstVaapiDisplay based on the native display supplied in
* as @native_display. The caller still owns the display and must call
* native display close function when all #GstVaapiDisplay references
* are released. Doing so too early can yield undefined behaviour.
*
* The @gles_version will further ensure the OpenGL ES API to use, or
* zero to indicate "desktop" OpenGL.
*
* Return value: a newly allocated #GstVaapiDisplay object
*/
GstVaapiDisplay *
gst_vaapi_display_egl_new_with_native_display (gpointer native_display,
GstVaapiDisplayType display_type, guint gles_version)
{
InitParams params;
g_return_val_if_fail (native_display != NULL, NULL);
params.display = native_display;
params.display_type = display_type;
params.gles_version = gles_version;
return gst_vaapi_display_new (gst_vaapi_display_egl_class (),
GST_VAAPI_DISPLAY_INIT_FROM_NATIVE_DISPLAY, &params);
}
EglContext *
gst_vaapi_display_egl_get_context (GstVaapiDisplayEGL * display)
{
return ensure_context (display) ? display->egl_context : NULL;
}
EGLDisplay
gst_vaapi_display_egl_get_gl_display (GstVaapiDisplayEGL * display)
{
g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_EGL (display), EGL_NO_DISPLAY);
return display->egl_display->base.handle.p;
}
EGLContext
gst_vaapi_display_egl_get_gl_context (GstVaapiDisplayEGL * display)
{
g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_EGL (display), EGL_NO_CONTEXT);
return ensure_context (display) ? display->egl_context->base.handle.p :
EGL_NO_CONTEXT;
}
gboolean
gst_vaapi_display_egl_set_gl_context (GstVaapiDisplayEGL * display,
EGLContext gl_context)
{
g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_EGL (display), FALSE);
return ensure_context_is_wrapped (display, gl_context);
}