summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGwenole Beauchesne <gwenole.beauchesne@intel.com>2015-01-27 16:21:04 +0100
committerGwenole Beauchesne <gwenole.beauchesne@intel.com>2015-02-24 15:20:03 +0100
commitaabb8c99c23199ee17c4a91b64573c2cc5fe619c (patch)
tree8ec7adf2d5360dc1eef26827f481f08bd543d390
parent23c489d8eebbcfe544a224d57ff3dcf505bf4d85 (diff)
egl: add windowing support.
This provides for some basic EGL window abstraction.
-rw-r--r--gst-libs/gst/vaapi/Makefile.am2
-rw-r--r--gst-libs/gst/vaapi/gstvaapidisplay_egl.c24
-rw-r--r--gst-libs/gst/vaapi/gstvaapiutils_egl.c69
-rw-r--r--gst-libs/gst/vaapi/gstvaapiutils_egl.h13
-rw-r--r--gst-libs/gst/vaapi/gstvaapiwindow_egl.c565
-rw-r--r--gst-libs/gst/vaapi/gstvaapiwindow_egl.h39
6 files changed, 710 insertions, 2 deletions
diff --git a/gst-libs/gst/vaapi/Makefile.am b/gst-libs/gst/vaapi/Makefile.am
index 80735828..9e5fe88d 100644
--- a/gst-libs/gst/vaapi/Makefile.am
+++ b/gst-libs/gst/vaapi/Makefile.am
@@ -280,12 +280,14 @@ libgstvaapi_egl_source_c = \
gstvaapisurface_egl.c \
gstvaapitexture_egl.c \
gstvaapiutils_egl.c \
+ gstvaapiwindow_egl.c \
$(NULL)
libgstvaapi_egl_source_h = \
gstvaapidisplay_egl.h \
gstvaapisurface_egl.h \
gstvaapitexture_egl.h \
+ gstvaapiwindow_egl.h \
$(NULL)
libgstvaapi_egl_source_priv_h = \
diff --git a/gst-libs/gst/vaapi/gstvaapidisplay_egl.c b/gst-libs/gst/vaapi/gstvaapidisplay_egl.c
index 4de23456..30385d2b 100644
--- a/gst-libs/gst/vaapi/gstvaapidisplay_egl.c
+++ b/gst-libs/gst/vaapi/gstvaapidisplay_egl.c
@@ -25,6 +25,8 @@
#include "gstvaapidisplay_egl.h"
#include "gstvaapidisplay_egl_priv.h"
#include "gstvaapiwindow.h"
+#include "gstvaapiwindow_egl.h"
+#include "gstvaapiwindow_priv.h"
#include "gstvaapitexture_egl.h"
GST_DEBUG_CATEGORY (gst_debug_vaapidisplay_egl);
@@ -442,6 +444,24 @@ gst_vaapi_display_egl_get_size_mm (GstVaapiDisplayEGL * display,
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 GstVaapiTexture *
gst_vaapi_display_egl_create_texture (GstVaapiDisplay * display, GstVaapiID id,
guint target, guint format, guint width, guint height)
@@ -484,6 +504,10 @@ gst_vaapi_display_egl_class_init (GstVaapiDisplayEGLClass * klass)
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;
}
diff --git a/gst-libs/gst/vaapi/gstvaapiutils_egl.c b/gst-libs/gst/vaapi/gstvaapiutils_egl.c
index 62176251..12cbd826 100644
--- a/gst-libs/gst/vaapi/gstvaapiutils_egl.c
+++ b/gst-libs/gst/vaapi/gstvaapiutils_egl.c
@@ -168,6 +168,7 @@ typedef struct egl_object_class_s EglConfigClass;
typedef struct egl_object_class_s EglContextClass;
typedef struct egl_object_class_s EglSurfaceClass;
typedef struct egl_object_class_s EglProgramClass;
+typedef struct egl_object_class_s EglWindowClass;
EGL_OBJECT_DEFINE_CLASS (EglMessage, egl_message);
EGL_OBJECT_DEFINE_CLASS (EglVTable, egl_vtable);
@@ -176,6 +177,7 @@ EGL_OBJECT_DEFINE_CLASS (EglConfig, egl_config);
EGL_OBJECT_DEFINE_CLASS (EglContext, egl_context);
EGL_OBJECT_DEFINE_CLASS (EglSurface, egl_surface);
EGL_OBJECT_DEFINE_CLASS (EglProgram, egl_program);
+EGL_OBJECT_DEFINE_CLASS (EglWindow, egl_window);
/* ------------------------------------------------------------------------- */
// Desktop OpenGL and OpenGL|ES dispatcher (vtable)
@@ -818,7 +820,7 @@ egl_surface_finalize (EglSurface * surface)
egl_object_replace (&surface->display, NULL);
}
-EglSurface *
+static EglSurface *
egl_surface_new_wrapped (EglDisplay * display, EGLSurface gl_surface)
{
EglSurface *surface;
@@ -1088,7 +1090,7 @@ egl_context_get_vtable (EglContext * ctx, gboolean need_gl_symbols)
return ctx->vtable;
}
-void
+static void
egl_context_set_surface (EglContext * ctx, EglSurface * surface)
{
g_return_if_fail (ctx != NULL);
@@ -1258,6 +1260,69 @@ error:
}
/* ------------------------------------------------------------------------- */
+// EGL Window
+
+static gboolean
+egl_window_init (EglWindow * window, EglContext * ctx, gpointer native_window)
+{
+ EGLSurface gl_surface;
+
+ window->context = egl_context_new (ctx->display, ctx->config, ctx);
+ if (!window->context)
+ return FALSE;
+ ctx = window->context;
+
+ gl_surface = eglCreateWindowSurface (ctx->display->base.handle.p,
+ ctx->config->base.handle.p, (EGLNativeWindowType) native_window, NULL);
+ if (!gl_surface)
+ return FALSE;
+
+ window->surface = egl_surface_new_wrapped (ctx->display, gl_surface);
+ if (!window->surface)
+ goto error_create_surface;
+ window->base.handle.p = gl_surface;
+ window->base.is_wrapped = FALSE;
+
+ egl_context_set_surface (ctx, window->surface);
+ return TRUE;
+
+ /* ERRORS */
+error_create_surface:
+ GST_ERROR ("failed to create EGL wrapper surface");
+ eglDestroySurface (ctx->display->base.handle.p, gl_surface);
+ return FALSE;
+}
+
+static void
+egl_window_finalize (EglWindow * window)
+{
+ if (window->context && window->base.handle.p)
+ eglDestroySurface (window->context->display->base.handle.p,
+ window->base.handle.p);
+
+ egl_object_replace (&window->surface, NULL);
+ egl_object_replace (&window->context, NULL);
+}
+
+EglWindow *
+egl_window_new (EglContext * ctx, gpointer native_window)
+{
+ EglWindow *window;
+
+ g_return_val_if_fail (ctx != NULL, NULL);
+ g_return_val_if_fail (native_window != NULL, NULL);
+
+ window = egl_object_new0 (egl_window_class ());
+ if (!window || !egl_window_init (window, ctx, native_window))
+ goto error;
+ return window;
+
+error:
+ egl_object_replace (&window, NULL);
+ return NULL;
+}
+
+/* ------------------------------------------------------------------------- */
// Misc utility functions
void
diff --git a/gst-libs/gst/vaapi/gstvaapiutils_egl.h b/gst-libs/gst/vaapi/gstvaapiutils_egl.h
index d1fd28de..1c5cdc30 100644
--- a/gst-libs/gst/vaapi/gstvaapiutils_egl.h
+++ b/gst-libs/gst/vaapi/gstvaapiutils_egl.h
@@ -42,6 +42,7 @@ typedef struct egl_context_state_s EglContextState;
typedef struct egl_context_s EglContext;
typedef struct egl_surface_s EglSurface;
typedef struct egl_program_s EglProgram;
+typedef struct egl_window_s EglWindow;
#define EGL_PROTO_BEGIN(NAME, TYPE, EXTENSION) \
typedef TYPE (*GL_PROTO_GEN_CONCAT3(Egl,NAME,Proc))
@@ -171,6 +172,14 @@ struct egl_program_s
gint uniforms[EGL_MAX_UNIFORMS];
};
+struct egl_window_s
+{
+ EglObject base;
+
+ EglContext *context;
+ EglSurface *surface;
+};
+
#define egl_object_ref(obj) \
((gpointer)gst_vaapi_mini_object_ref ((GstVaapiMiniObject *)(obj)))
#define egl_object_unref(obj) \
@@ -223,6 +232,10 @@ egl_program_new (EglContext * ctx, const gchar * frag_shader_text,
const gchar * vert_shader_text);
G_GNUC_INTERNAL
+EglWindow *
+egl_window_new (EglContext * ctx, gpointer native_window);
+
+G_GNUC_INTERNAL
guint
egl_create_texture (EglContext * ctx, guint target, guint format,
guint width, guint height);
diff --git a/gst-libs/gst/vaapi/gstvaapiwindow_egl.c b/gst-libs/gst/vaapi/gstvaapiwindow_egl.c
new file mode 100644
index 00000000..006ca2eb
--- /dev/null
+++ b/gst-libs/gst/vaapi/gstvaapiwindow_egl.c
@@ -0,0 +1,565 @@
+/*
+ * gstvaapiwindow_egl.c - VA/EGL window 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
+ */
+
+/**
+ * SECTION:gstvaapiwindow_egl
+ * @short_description: VA/EGL window abstraction
+ */
+
+#include "sysdeps.h"
+#include "gstvaapiwindow_egl.h"
+#include "gstvaapiwindow_priv.h"
+#include "gstvaapitexture_egl.h"
+#include "gstvaapitexture_priv.h"
+#include "gstvaapidisplay_egl_priv.h"
+
+#define GST_VAAPI_WINDOW_EGL(obj) \
+ ((GstVaapiWindowEGL *)(obj))
+
+#define GST_VAAPI_WINDOW_EGL_CLASS(klass) \
+ ((GstVaapiWindowEGLClass *)(klass))
+
+#define GST_VAAPI_WINDOW_EGL_GET_CLASS(obj) \
+ GST_VAAPI_WINDOW_EGL_CLASS (GST_VAAPI_WINDOW_GET_CLASS (obj))
+
+typedef struct _GstVaapiWindowEGL GstVaapiWindowEGL;
+typedef struct _GstVaapiWindowEGLClass GstVaapiWindowEGLClass;
+
+enum
+{
+ RENDER_PROGRAM_VAR_PROJ = 0,
+ RENDER_PROGRAM_VAR_TEX0,
+ RENDER_PROGRAM_VAR_TEX1,
+ RENDER_PROGRAM_VAR_TEX2,
+};
+
+struct _GstVaapiWindowEGL
+{
+ GstVaapiWindow parent_instance;
+
+ GstVaapiWindow *window;
+ GstVaapiTexture *texture;
+ EglWindow *egl_window;
+ EglVTable *egl_vtable;
+ EglProgram *render_program;
+ gfloat render_projection[16];
+};
+
+struct _GstVaapiWindowEGLClass
+{
+ GstVaapiWindowClass parent_class;
+};
+
+typedef struct
+{
+ GstVaapiWindowEGL *window;
+ guint width;
+ guint height;
+ EglContext *egl_context;
+ gboolean success; /* result */
+} CreateObjectsArgs;
+
+typedef struct
+{
+ GstVaapiWindowEGL *window;
+ guint width;
+ guint height;
+ gboolean success; /* result */
+} ResizeWindowArgs;
+
+typedef struct
+{
+ GstVaapiWindowEGL *window;
+ GstVaapiSurface *surface;
+ const GstVaapiRectangle *src_rect;
+ const GstVaapiRectangle *dst_rect;
+ guint flags;
+ gboolean success; /* result */
+} UploadSurfaceArgs;
+
+static const gchar *vert_shader_text =
+ "#ifdef GL_ES\n"
+ "precision mediump float;\n"
+ "#endif\n"
+ "\n"
+ "uniform mat4 proj;\n"
+ "\n"
+ "attribute vec2 position;\n"
+ "attribute vec2 texcoord;\n"
+ "varying vec2 v_texcoord;\n"
+ "\n"
+ "void main () {\n"
+ " gl_Position = proj * vec4 (position, 0.0, 1.0);\n"
+ " v_texcoord = texcoord;\n"
+ "}\n";
+
+static const gchar *frag_shader_text_rgba =
+ "#ifdef GL_ES\n"
+ "precision mediump float;\n"
+ "#endif\n"
+ "\n"
+ "uniform sampler2D tex0;\n"
+ "\n"
+ "varying vec2 v_texcoord;\n"
+ "\n"
+ "void main () {\n"
+ " gl_FragColor = texture2D (tex0, v_texcoord);\n"
+ "}\n";
+
+static gboolean
+ensure_texture (GstVaapiWindowEGL * window, guint width, guint height)
+{
+ GstVaapiTexture *texture;
+
+ if (window->texture &&
+ GST_VAAPI_TEXTURE_WIDTH (window->texture) == width &&
+ GST_VAAPI_TEXTURE_HEIGHT (window->texture) == height)
+ return TRUE;
+
+ texture = gst_vaapi_texture_egl_new (GST_VAAPI_OBJECT_DISPLAY (window),
+ GL_TEXTURE_2D, GL_RGBA, width, height);
+ gst_vaapi_texture_replace (&window->texture, texture);
+ gst_vaapi_texture_replace (&texture, NULL);
+ return window->texture != NULL;
+}
+
+static gboolean
+ensure_shaders (GstVaapiWindowEGL * window)
+{
+ EglVTable *const vtable = window->egl_vtable;
+ EglProgram *program;
+ GLuint prog_id;
+
+ g_return_val_if_fail (window->texture != NULL, FALSE);
+ g_return_val_if_fail (GST_VAAPI_TEXTURE_FORMAT (window->texture) == GL_RGBA,
+ FALSE);
+
+ if (window->render_program)
+ return TRUE;
+
+ program = egl_program_new (window->egl_window->context,
+ frag_shader_text_rgba, vert_shader_text);
+ if (!program)
+ return FALSE;
+
+ prog_id = program->base.handle.u;
+
+ vtable->glUseProgram (prog_id);
+ program->uniforms[RENDER_PROGRAM_VAR_PROJ] =
+ vtable->glGetUniformLocation (prog_id, "proj");
+ program->uniforms[RENDER_PROGRAM_VAR_TEX0] =
+ vtable->glGetUniformLocation (prog_id, "tex0");
+ program->uniforms[RENDER_PROGRAM_VAR_TEX1] =
+ vtable->glGetUniformLocation (prog_id, "tex1");
+ program->uniforms[RENDER_PROGRAM_VAR_TEX2] =
+ vtable->glGetUniformLocation (prog_id, "tex2");
+ vtable->glUseProgram (0);
+
+ egl_matrix_set_identity (window->render_projection);
+
+ egl_object_replace (&window->render_program, program);
+ egl_object_replace (&program, NULL);
+ return TRUE;
+}
+
+static gboolean
+do_create_objects_unlocked (GstVaapiWindowEGL * window, guint width,
+ guint height, EglContext * egl_context)
+{
+ EglWindow *egl_window;
+ EglVTable *egl_vtable;
+
+ egl_window = egl_window_new (egl_context,
+ GSIZE_TO_POINTER (GST_VAAPI_OBJECT_ID (window->window)));
+ if (!egl_window)
+ return FALSE;
+ window->egl_window = egl_window;
+
+ egl_vtable = egl_context_get_vtable (egl_window->context, TRUE);
+ if (!egl_vtable)
+ return FALSE;
+ window->egl_vtable = egl_object_ref (egl_vtable);
+ return TRUE;
+}
+
+static void
+do_create_objects (CreateObjectsArgs * args)
+{
+ GstVaapiWindowEGL *const window = args->window;
+ EglContextState old_cs;
+
+ args->success = FALSE;
+
+ GST_VAAPI_OBJECT_LOCK_DISPLAY (window);
+ if (egl_context_set_current (args->egl_context, TRUE, &old_cs)) {
+ args->success = do_create_objects_unlocked (window, args->width,
+ args->height, args->egl_context);
+ egl_context_set_current (args->egl_context, FALSE, &old_cs);
+ }
+ GST_VAAPI_OBJECT_UNLOCK_DISPLAY (window);
+}
+
+static gboolean
+gst_vaapi_window_egl_create (GstVaapiWindowEGL * window,
+ guint * width, guint * height)
+{
+ GstVaapiDisplayEGL *const display =
+ GST_VAAPI_DISPLAY_EGL (GST_VAAPI_OBJECT_DISPLAY (window));
+ const GstVaapiDisplayClass *const native_dpy_class =
+ GST_VAAPI_DISPLAY_GET_CLASS (display->display);
+ CreateObjectsArgs args;
+
+ g_return_val_if_fail (native_dpy_class != NULL, FALSE);
+
+ window->window = native_dpy_class->create_window (GST_VAAPI_DISPLAY (display),
+ GST_VAAPI_ID_INVALID, *width, *height);
+ if (!window->window)
+ return FALSE;
+
+ gst_vaapi_window_get_size (window->window, width, height);
+
+ args.window = window;
+ args.width = *width;
+ args.height = *height;
+ args.egl_context = GST_VAAPI_DISPLAY_EGL_CONTEXT (display);
+ return egl_context_run (args.egl_context,
+ (EglContextRunFunc) do_create_objects, &args) && args.success;
+}
+
+static void
+do_destroy_objects_unlocked (GstVaapiWindowEGL * window)
+{
+ egl_object_replace (&window->render_program, NULL);
+ egl_object_replace (&window->egl_vtable, NULL);
+ egl_object_replace (&window->egl_window, NULL);
+}
+
+static void
+do_destroy_objects (GstVaapiWindowEGL * window)
+{
+ EglContext *const egl_context =
+ GST_VAAPI_DISPLAY_EGL_CONTEXT (GST_VAAPI_OBJECT_DISPLAY (window));
+ EglContextState old_cs;
+
+ if (!window->egl_window)
+ return;
+
+ GST_VAAPI_OBJECT_LOCK_DISPLAY (window);
+ if (egl_context_set_current (egl_context, TRUE, &old_cs)) {
+ do_destroy_objects_unlocked (window);
+ egl_context_set_current (egl_context, FALSE, &old_cs);
+ }
+ GST_VAAPI_OBJECT_UNLOCK_DISPLAY (window);
+}
+
+static void
+gst_vaapi_window_egl_destroy (GstVaapiWindowEGL * window)
+{
+ egl_context_run (window->egl_window->context,
+ (EglContextRunFunc) do_destroy_objects, window);
+ gst_vaapi_window_replace (&window->window, NULL);
+ gst_vaapi_texture_replace (&window->texture, NULL);
+}
+
+static gboolean
+gst_vaapi_window_egl_show (GstVaapiWindowEGL * window)
+{
+ const GstVaapiWindowClass *const klass =
+ GST_VAAPI_WINDOW_GET_CLASS (window->window);
+
+ g_return_val_if_fail (klass->show, FALSE);
+
+ return klass->show (window->window);
+}
+
+static gboolean
+gst_vaapi_window_egl_hide (GstVaapiWindowEGL * window)
+{
+ const GstVaapiWindowClass *const klass =
+ GST_VAAPI_WINDOW_GET_CLASS (window->window);
+
+ g_return_val_if_fail (klass->hide, FALSE);
+
+ return klass->hide (window->window);
+}
+
+static gboolean
+gst_vaapi_window_egl_get_geometry (GstVaapiWindowEGL * window,
+ gint * x_ptr, gint * y_ptr, guint * width_ptr, guint * height_ptr)
+{
+ const GstVaapiWindowClass *const klass =
+ GST_VAAPI_WINDOW_GET_CLASS (window->window);
+
+ return klass->get_geometry ? klass->get_geometry (window->window,
+ x_ptr, y_ptr, width_ptr, height_ptr) : FALSE;
+}
+
+static gboolean
+gst_vaapi_window_egl_set_fullscreen (GstVaapiWindowEGL * window,
+ gboolean fullscreen)
+{
+ const GstVaapiWindowClass *const klass =
+ GST_VAAPI_WINDOW_GET_CLASS (window->window);
+
+ return klass->set_fullscreen ? klass->set_fullscreen (window->window,
+ fullscreen) : FALSE;
+}
+
+static gboolean
+do_resize_window_unlocked (GstVaapiWindowEGL * window, guint width,
+ guint height)
+{
+ EglVTable *const vtable = window->egl_vtable;
+
+ vtable->glViewport (0, 0, width, height);
+ vtable->glClearColor (0.0f, 0.0f, 0.0f, 1.0f);
+ vtable->glClear (GL_COLOR_BUFFER_BIT);
+ return TRUE;
+}
+
+static void
+do_resize_window (ResizeWindowArgs * args)
+{
+ GstVaapiWindowEGL *const window = args->window;
+ EglContextState old_cs;
+
+ GST_VAAPI_OBJECT_LOCK_DISPLAY (window);
+ if (egl_context_set_current (window->egl_window->context, TRUE, &old_cs)) {
+ args->success = do_resize_window_unlocked (window, args->width,
+ args->height);
+ egl_context_set_current (window->egl_window->context, FALSE, &old_cs);
+ }
+ GST_VAAPI_OBJECT_UNLOCK_DISPLAY (window);
+}
+
+static gboolean
+gst_vaapi_window_egl_resize (GstVaapiWindowEGL * window, guint width,
+ guint height)
+{
+ const GstVaapiWindowClass *const klass =
+ GST_VAAPI_WINDOW_GET_CLASS (window->window);
+ ResizeWindowArgs args = { window, width, height };
+
+ g_return_val_if_fail (klass->resize, FALSE);
+
+ if (!klass->resize (window->window, width, height))
+ return FALSE;
+
+ return egl_context_run (window->egl_window->context,
+ (EglContextRunFunc) do_resize_window, &args) && args.success;
+}
+
+static gboolean
+do_render_texture (GstVaapiWindowEGL * window, const GstVaapiRectangle * rect)
+{
+ const GLuint tex_id = GST_VAAPI_OBJECT_ID (window->texture);
+ EglVTable *const vtable = window->egl_vtable;
+ GLfloat x0, y0, x1, y1;
+ GLfloat texcoords[4][2];
+ GLfloat positions[4][2];
+ guint tex_width, tex_height;
+
+ if (!ensure_shaders (window))
+ return FALSE;
+
+ tex_width = GST_VAAPI_TEXTURE_WIDTH (window->texture);
+ tex_height = GST_VAAPI_TEXTURE_HEIGHT (window->texture);
+
+ // Source coords in VA surface
+ x0 = 0.0f;
+ y0 = 0.0f;
+ x1 = 1.0f;
+ y1 = 1.0f;
+ texcoords[0][0] = x0;
+ texcoords[0][1] = y1;
+ texcoords[1][0] = x1;
+ texcoords[1][1] = y1;
+ texcoords[2][0] = x1;
+ texcoords[2][1] = y0;
+ texcoords[3][0] = x0;
+ texcoords[3][1] = y0;
+
+ // Target coords in EGL surface
+ x0 = 2.0f * ((GLfloat) rect->x / tex_width) - 1.0f;
+ y1 = -2.0f * ((GLfloat) rect->y / tex_height) + 1.0f;
+ x1 = 2.0f * ((GLfloat) (rect->x + rect->width) / tex_width) - 1.0f;
+ y0 = -2.0f * ((GLfloat) (rect->y + rect->height) / tex_height) + 1.0f;
+ positions[0][0] = x0;
+ positions[0][1] = y0;
+ positions[1][0] = x1;
+ positions[1][1] = y0;
+ positions[2][0] = x1;
+ positions[2][1] = y1;
+ positions[3][0] = x0;
+ positions[3][1] = y1;
+
+ vtable->glClear (GL_COLOR_BUFFER_BIT);
+
+ if (G_UNLIKELY (window->egl_window->context->config->gles_version == 1)) {
+ vtable->glBindTexture (GST_VAAPI_TEXTURE_TARGET (window->texture), tex_id);
+ vtable->glEnableClientState (GL_VERTEX_ARRAY);
+ vtable->glVertexPointer (2, GL_FLOAT, 0, positions);
+ vtable->glEnableClientState (GL_TEXTURE_COORD_ARRAY);
+ vtable->glTexCoordPointer (2, GL_FLOAT, 0, texcoords);
+
+ vtable->glDrawArrays (GL_TRIANGLE_FAN, 0, 4);
+
+ vtable->glDisableClientState (GL_VERTEX_ARRAY);
+ vtable->glDisableClientState (GL_TEXTURE_COORD_ARRAY);
+ } else {
+ EglProgram *const program = window->render_program;
+
+ vtable->glUseProgram (program->base.handle.u);
+ vtable->glUniformMatrix4fv (program->uniforms[RENDER_PROGRAM_VAR_PROJ],
+ 1, GL_FALSE, window->render_projection);
+ vtable->glEnableVertexAttribArray (0);
+ vtable->glVertexAttribPointer (0, 2, GL_FLOAT, GL_FALSE, 0, positions);
+ vtable->glEnableVertexAttribArray (1);
+ vtable->glVertexAttribPointer (1, 2, GL_FLOAT, GL_FALSE, 0, texcoords);
+
+ vtable->glBindTexture (GST_VAAPI_TEXTURE_TARGET (window->texture), tex_id);
+ vtable->glUniform1i (program->uniforms[RENDER_PROGRAM_VAR_TEX0], 0);
+ vtable->glDrawArrays (GL_TRIANGLE_FAN, 0, 4);
+
+ vtable->glDisableVertexAttribArray (1);
+ vtable->glDisableVertexAttribArray (0);
+ vtable->glUseProgram (0);
+ }
+
+ eglSwapBuffers (window->egl_window->context->display->base.handle.p,
+ window->egl_window->base.handle.p);
+ return TRUE;
+}
+
+static gboolean
+do_upload_surface_unlocked (GstVaapiWindowEGL * window,
+ GstVaapiSurface * surface, const GstVaapiRectangle * src_rect,
+ const GstVaapiRectangle * dst_rect, guint flags)
+{
+ if (!ensure_texture (window, dst_rect->width, dst_rect->height))
+ return FALSE;
+ if (!gst_vaapi_texture_put_surface (window->texture, surface, src_rect,
+ flags))
+ return FALSE;
+ if (!do_render_texture (window, dst_rect))
+ return FALSE;
+ return TRUE;
+}
+
+static void
+do_upload_surface (UploadSurfaceArgs * args)
+{
+ GstVaapiWindowEGL *const window = args->window;
+ EglContextState old_cs;
+
+ args->success = FALSE;
+
+ GST_VAAPI_OBJECT_LOCK_DISPLAY (window);
+ if (egl_context_set_current (window->egl_window->context, TRUE, &old_cs)) {
+ args->success = do_upload_surface_unlocked (window, args->surface,
+ args->src_rect, args->dst_rect, args->flags);
+ egl_context_set_current (window->egl_window->context, FALSE, &old_cs);
+ }
+ GST_VAAPI_OBJECT_UNLOCK_DISPLAY (window);
+}
+
+static gboolean
+gst_vaapi_window_egl_render (GstVaapiWindowEGL * window,
+ GstVaapiSurface * surface, const GstVaapiRectangle * src_rect,
+ const GstVaapiRectangle * dst_rect, guint flags)
+{
+ UploadSurfaceArgs args = { window, surface, src_rect, dst_rect, flags };
+
+ return egl_context_run (window->egl_window->context,
+ (EglContextRunFunc) do_upload_surface, &args) && args.success;
+}
+
+static gboolean
+gst_vaapi_window_egl_render_pixmap (GstVaapiWindowEGL * window,
+ GstVaapiPixmap * pixmap,
+ const GstVaapiRectangle * src_rect, const GstVaapiRectangle * dst_rect)
+{
+ const GstVaapiWindowClass *const klass =
+ GST_VAAPI_WINDOW_GET_CLASS (window->window);
+
+ if (!klass->render_pixmap)
+ return FALSE;
+ return klass->render_pixmap (window->window, pixmap, src_rect, dst_rect);
+}
+
+void
+gst_vaapi_window_egl_class_init (GstVaapiWindowEGLClass * klass)
+{
+ GstVaapiObjectClass *const object_class = GST_VAAPI_OBJECT_CLASS (klass);
+ GstVaapiWindowClass *const window_class = GST_VAAPI_WINDOW_CLASS (klass);
+
+ object_class->finalize = (GstVaapiObjectFinalizeFunc)
+ gst_vaapi_window_egl_destroy;
+
+ window_class->create = (GstVaapiWindowCreateFunc)
+ gst_vaapi_window_egl_create;
+ window_class->show = (GstVaapiWindowShowFunc)
+ gst_vaapi_window_egl_show;
+ window_class->hide = (GstVaapiWindowHideFunc)
+ gst_vaapi_window_egl_hide;
+ window_class->get_geometry = (GstVaapiWindowGetGeometryFunc)
+ gst_vaapi_window_egl_get_geometry;
+ window_class->set_fullscreen = (GstVaapiWindowSetFullscreenFunc)
+ gst_vaapi_window_egl_set_fullscreen;
+ window_class->resize = (GstVaapiWindowResizeFunc)
+ gst_vaapi_window_egl_resize;
+ window_class->render = (GstVaapiWindowRenderFunc)
+ gst_vaapi_window_egl_render;
+ window_class->render_pixmap = (GstVaapiWindowRenderPixmapFunc)
+ gst_vaapi_window_egl_render_pixmap;
+}
+
+#define gst_vaapi_window_egl_finalize \
+ gst_vaapi_window_egl_destroy
+
+GST_VAAPI_OBJECT_DEFINE_CLASS_WITH_CODE (GstVaapiWindowEGL,
+ gst_vaapi_window_egl, gst_vaapi_window_egl_class_init (&g_class));
+
+/**
+ * gst_vaapi_window_egl_new:
+ * @display: a #GstVaapiDisplay
+ * @width: the requested window width, in pixels
+ * @height: the requested windo height, in pixels
+ *
+ * Creates a window with the specified @width and @height. The window
+ * will be attached to the @display and remains invisible to the user
+ * until gst_vaapi_window_show() is called.
+ *
+ * Return value: the newly allocated #GstVaapiWindow object
+ */
+GstVaapiWindow *
+gst_vaapi_window_egl_new (GstVaapiDisplay * display, guint width, guint height)
+{
+ GST_DEBUG ("new window, size %ux%u", width, height);
+
+ g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_EGL (display), NULL);
+
+ return
+ gst_vaapi_window_new_internal (GST_VAAPI_WINDOW_CLASS
+ (gst_vaapi_window_egl_class ()), display, GST_VAAPI_ID_INVALID, width,
+ height);
+}
diff --git a/gst-libs/gst/vaapi/gstvaapiwindow_egl.h b/gst-libs/gst/vaapi/gstvaapiwindow_egl.h
new file mode 100644
index 00000000..b2ffa2de
--- /dev/null
+++ b/gst-libs/gst/vaapi/gstvaapiwindow_egl.h
@@ -0,0 +1,39 @@
+/*
+ * gstvaapiwindow_egl.h - VA/EGL window 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
+ */
+
+#ifndef GST_VAAPI_WINDOW_EGL_H
+#define GST_VAAPI_WINDOW_EGL_H
+
+#include <gst/vaapi/gstvaapidisplay.h>
+#include <gst/vaapi/gstvaapiwindow.h>
+
+G_BEGIN_DECLS
+
+#define GST_VAAPI_WINDOW_EGL(obj) \
+ ((GstVaapiWindowEGL *)(obj))
+
+GstVaapiWindow *
+gst_vaapi_window_egl_new (GstVaapiDisplay * display, guint width, guint height);
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_WINDOW_EGL_H */