Add initial support for EGL.
authorGwenole Beauchesne <gwenole.beauchesne@intel.com>
Fri, 20 Feb 2015 14:27:53 +0000 (15:27 +0100)
committerGwenole Beauchesne <gwenole.beauchesne@intel.com>
Tue, 24 Feb 2015 14:20:03 +0000 (15:20 +0100)
Add initial support for EGL to libgstvaapi core library. The target
display server and the desired OpenGL API can be programmatically
selected at run-time.

A comprehensive set of EGL utilities are provided to support those
dynamic selection needs, but also most importantly to ensure that
the GL command stream is executed from within a single thread.

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

12 files changed:
configure.ac
gst-libs/gst/vaapi/Makefile.am
gst-libs/gst/vaapi/egl_compat.h [new file with mode: 0644]
gst-libs/gst/vaapi/egl_vtable.h [new file with mode: 0644]
gst-libs/gst/vaapi/gstvaapidisplay.c
gst-libs/gst/vaapi/gstvaapidisplay.h
gst-libs/gst/vaapi/gstvaapidisplay_egl.c [new file with mode: 0644]
gst-libs/gst/vaapi/gstvaapidisplay_egl.h [new file with mode: 0644]
gst-libs/gst/vaapi/gstvaapidisplay_egl_priv.h [new file with mode: 0644]
gst-libs/gst/vaapi/gstvaapiutils_egl.c [new file with mode: 0644]
gst-libs/gst/vaapi/gstvaapiutils_egl.h [new file with mode: 0644]
gst-libs/gst/vaapi/ogl_compat.h [new file with mode: 0644]

index f4efae0..e728459 100644 (file)
@@ -9,6 +9,9 @@ m4_if(gst_vaapi_pre_version, [0], [], [
 m4_append([gst_vaapi_version], gst_vaapi_pre_version, [.pre])
 ])
 
+# Configure defaults
+m4_define([default_glapi],              [any])
+
 # gstreamer-vaapi library (libtool) version number
 m4_define([gst_vaapi_lt_current],       [6])
 m4_define([gst0_vaapi_lt_current_bias], [0])
@@ -147,6 +150,16 @@ AC_ARG_ENABLE(wayland,
                    [enable Wayland output @<:@default=yes@:>@]),
     [], [enable_wayland="yes"])
 
+AC_ARG_ENABLE([egl],
+    AS_HELP_STRING([--enable-egl],
+        [enable EGL output @<:@default=yes@:>@]),
+    [], [enable_egl="yes"])
+
+AC_ARG_WITH([glapi],
+    AS_HELP_STRING([--with-glapi=APIs],
+        [build with the specified OpenGL APIs @<:@default=default_glapi@:>@]),
+    [GLAPI="$with_glapi"], [GLAPI=default_glapi])
+
 AC_ARG_WITH([gstreamer-api],
     AC_HELP_STRING([--with-gstreamer-api=VERSION],
                    [build against the specified GStreamer API version
@@ -205,6 +218,9 @@ if test -z "$GST_PKG_VERSION"; then
 fi
 AC_MSG_RESULT([$GST_API_VERSION])
 
+AC_DEFINE_UNQUOTED([GST_API_VERSION_S], ["$GST_API_VERSION"],
+    [Defined to the string representation of GStreamer version])
+
 dnl Versions for GStreamer and plugins-base
 case $GST_API_VERSION in
 0.10)
@@ -265,6 +281,9 @@ if test "$USE_GST_API_1_2p" = "yes" || test "$USE_GST_API_1_4p" = "yes" ; then
 fi
 AC_SUBST([GST_PKG_VERSION])
 
+AC_DEFINE_UNQUOTED([GST_PKG_VERSION_S], ["$GST_PKG_VERSION"],
+    [Defined to the string representation of GStreamer API version])
+
 dnl Validate certain features
 if test "$USE_GST_API_0_10" = "yes"; then
     AC_MSG_WARN([support for GStreamer 0.10 is obsolete, and will be removed])
@@ -494,6 +513,9 @@ esac
 GST_VAAPI_MAJOR_VERSION=`expr gst_vaapi_lt_current - "$lt_bias"`
 AC_SUBST(GST_VAAPI_MAJOR_VERSION)
 
+AC_DEFINE_UNQUOTED([GST_VAAPI_MAJOR_VERSION_S], ["$GST_VAAPI_MAJOR_VERSION"],
+    [Defined to the string representation of gstreamer-vaapi major version])
+
 dnl GST_VAAPI_LT_LDFLAGS:
 GST_VAAPI_LT_CURRENT="$GST_VAAPI_MAJOR_VERSION"
 GST_VAAPI_LT_REV=gst_vaapi_lt_revision
@@ -614,9 +636,15 @@ enable_opengl="no"
 if test "$enable_glx" = "yes"; then
     enable_opengl="yes"
 fi
+if test "$enable_egl" = "yes"; then
+    enable_opengl="yes"
+fi
+GLES_VERSION_MASK=0
 
 HAVE_GL=0
 if test "$enable_opengl" = "yes"; then
+case ",$GLAPI," in
+(*,any,*|*,gl,*)
     HAVE_GL=1
     PKG_CHECK_MODULES([GL], [gl], [:], [HAVE_GL=0])
     saved_CPPFLAGS="$CPPFLAGS"
@@ -627,7 +655,52 @@ if test "$enable_opengl" = "yes"; then
 #endif
     ])
     CPPFLAGS="$saved_CPPFLAGS"
+    ;;
+esac
+fi
+GLES_VERSION_MASK=`expr $GLES_VERSION_MASK "+" $HAVE_GL "*" 1`
+
+dnl OpenGL|ESv2
+HAVE_GLESv2=0
+if test "$enable_opengl" = "yes"; then
+case ",$GLAPI," in
+(*,any,*|*,gles2,*)
+    HAVE_GLESv2=1
+    PKG_CHECK_MODULES([GLES2], [glesv2], [:], [HAVE_GLESv2=0])
+    saved_CPPFLAGS="$CPPFLAGS"
+    CPPFLAGS="$CPPFLAGS $GLES2_CFLAGS"
+    AC_CHECK_HEADERS([GLES2/gl2.h GLES2/gl2ext.h], [:],
+        [HAVE_GLESv2=0], [
+#ifdef HAVE_GLES2_GL2_H
+# include <GLES2/gl2.h>
+#endif
+    ])
+    CPPFLAGS="$saved_CPPFLAGS"
+    ;;
+esac
+fi
+GLES_VERSION_MASK=`expr $GLES_VERSION_MASK "+" $HAVE_GLESv2 "*" 4`
+
+dnl OpenGL|ESv3
+HAVE_GLESv3=0
+if test "$enable_opengl" = "yes"; then
+case ",$GLAPI," in
+(*,any,*|*,gles3,*)
+    HAVE_GLESv3=1
+    PKG_CHECK_MODULES([GLES3], [glesv2], [:], [HAVE_GLESv3=0])
+    saved_CPPFLAGS="$CPPFLAGS"
+    CPPFLAGS="$CPPFLAGS $GLES3_CFLAGS"
+    AC_CHECK_HEADERS([GLES3/gl3.h GLES3/gl3ext.h GLES2/gl2ext.h], [:],
+        [HAVE_GLESv3=0], [
+#ifdef HAVE_GLES3_GL3_H
+# include <GLES3/gl3.h>
+#endif
+    ])
+    CPPFLAGS="$saved_CPPFLAGS"
+    ;;
+esac
 fi
+GLES_VERSION_MASK=`expr $GLES_VERSION_MASK "+" $HAVE_GLESv3 "*" 8`
 
 dnl ... GLX
 USE_GLX=0
@@ -647,6 +720,19 @@ if test "$enable_glx" = "yes" -a $HAVE_GL -eq 1 -a $USE_X11 -eq 1; then
     LIBS="$saved_LIBS"
 fi
 
+dnl ... EGL
+USE_EGL=0
+if test "$enable_egl" = "yes" -a $GLES_VERSION_MASK -ne 0; then
+    USE_EGL=1
+    PKG_CHECK_MODULES([EGL], [egl], [:], [USE_EGL=0])
+    saved_CPPFLAGS="$CPPFLAGS"
+    saved_LIBS="$LIBS"
+    AC_CHECK_HEADERS([EGL/egl.h], [:], [USE_EGL=0])
+    AC_CHECK_LIB([EGL], [eglGetDisplay], [:], [USE_EGL=0])
+    CPPFLAGS="$saved_CPPFLAGS"
+    LIBS="$saved_LIBS"
+fi
+
 dnl Check for Wayland
 USE_WAYLAND=0
 if test "$enable_wayland" = "yes"; then
@@ -920,6 +1006,13 @@ AC_DEFINE_UNQUOTED(USE_GLX, $USE_GLX,
     [Defined to 1 if GLX is enabled])
 AM_CONDITIONAL(USE_GLX, test $USE_GLX -eq 1)
 
+AC_DEFINE_UNQUOTED([USE_EGL], [$USE_EGL],
+    [Defined to 1 if EGL is enabled])
+AM_CONDITIONAL([USE_EGL], [test $USE_EGL -eq 1])
+
+AC_DEFINE_UNQUOTED([USE_GLES_VERSION_MASK], [$GLES_VERSION_MASK],
+    [Defined to the set of enabled OpenGL ES APIs])
+
 AC_DEFINE_UNQUOTED(USE_WAYLAND, $USE_WAYLAND,
     [Defined to 1 if WAYLAND is enabled])
 AM_CONDITIONAL(USE_WAYLAND, test $USE_WAYLAND -eq 1)
@@ -990,6 +1083,7 @@ VIDEO_OUTPUTS=""
 AS_IF([test $USE_DRM -eq 1], [VIDEO_OUTPUTS="$VIDEO_OUTPUTS drm"])
 AS_IF([test $USE_X11 -eq 1], [VIDEO_OUTPUTS="$VIDEO_OUTPUTS x11"])
 AS_IF([test $USE_GLX -eq 1], [VIDEO_OUTPUTS="$VIDEO_OUTPUTS glx"])
+AS_IF([test $USE_EGL -eq 1], [VIDEO_OUTPUTS="$VIDEO_OUTPUTS egl"])
 AS_IF([test $USE_WAYLAND -eq 1], [VIDEO_OUTPUTS="$VIDEO_OUTPUTS wayland"])
 
 echo
index 57b8313..a329e8f 100644 (file)
@@ -12,6 +12,10 @@ if USE_GLX
 lib_LTLIBRARIES += libgstvaapi-glx-@GST_API_VERSION@.la
 endif
 
+if USE_EGL
+lib_LTLIBRARIES += libgstvaapi-egl-@GST_API_VERSION@.la
+endif
+
 if USE_WAYLAND
 lib_LTLIBRARIES += libgstvaapi-wayland-@GST_API_VERSION@.la
 endif
@@ -271,6 +275,23 @@ libgstvaapi_glx_source_priv_h =                    \
        gstvaapiutils_x11.h                     \
        $(NULL)
 
+libgstvaapi_egl_source_c =                     \
+       gstvaapidisplay_egl.c                   \
+       gstvaapiutils_egl.c                     \
+       $(NULL)
+
+libgstvaapi_egl_source_h =                     \
+       gstvaapidisplay_egl.h                   \
+       $(NULL)
+
+libgstvaapi_egl_source_priv_h =                        \
+       egl_compat.h                            \
+       egl_vtable.h                            \
+       gstvaapidisplay_egl_priv.h              \
+       gstvaapiutils_egl.h                     \
+       ogl_compat.h                            \
+       $(NULL)
+
 libgstvaapi_wayland_source_c =                 \
        gstvaapidisplay_wayland.c               \
        gstvaapiutils.c                         \
@@ -433,6 +454,43 @@ libgstvaapi_glx_@GST_API_VERSION@_la_LDFLAGS =     \
        $(GST_VAAPI_LT_LDFLAGS)                 \
        $(NULL)
 
+libgstvaapi_egl_@GST_API_VERSION@_la_SOURCES = \
+       $(libgstvaapi_egl_source_c)             \
+       $(libgstvaapi_egl_source_priv_h)        \
+       $(NULL)
+
+libgstvaapi_egl_@GST_API_VERSION@include_HEADERS = \
+       $(libgstvaapi_egl_source_h)             \
+       $(NULL)
+
+libgstvaapi_egl_@GST_API_VERSION@includedir =  \
+       $(libgstvaapi_includedir)
+
+libgstvaapi_egl_@GST_API_VERSION@_la_CFLAGS =  \
+       -DIN_LIBGSTVAAPI                        \
+       -DGST_USE_UNSTABLE_API                  \
+       -I$(top_srcdir)/gst-libs                \
+       $(GLIB_CFLAGS)                          \
+       $(GST_BASE_CFLAGS)                      \
+       $(GST_VIDEO_CFLAGS)                     \
+       $(EGL_CFLAGS)                           \
+       $(NULL)
+
+libgstvaapi_egl_@GST_API_VERSION@_la_LIBADD =  \
+       $(GLIB_LIBS)                            \
+       $(GST_LIBS)                             \
+       $(GST_BASE_LIBS)                        \
+       $(GST_VIDEO_LIBS)                       \
+       libgstvaapi-$(GST_API_VERSION).la       \
+       $(EGL_LIBS)                             \
+       $(DLOPEN_LIBS)                          \
+       $(NULL)
+
+libgstvaapi_egl_@GST_API_VERSION@_la_LDFLAGS = \
+       $(GST_ALL_LDFLAGS)                      \
+       $(GST_VAAPI_LT_LDFLAGS)                 \
+       $(NULL)
+
 libgstvaapi_wayland_@GST_API_VERSION@_la_SOURCES = \
        $(libgstvaapi_wayland_source_c)         \
        $(libgstvaapi_wayland_source_priv_h)    \
@@ -513,6 +571,9 @@ EXTRA_DIST += \
        $(libgstvaapi_jpegenc_source_c)         \
        $(libgstvaapi_vp8enc_source_h)          \
        $(libgstvaapi_vp8enc_source_c)          \
+       $(libgstvaapi_egl_source_c)             \
+       $(libgstvaapi_egl_source_h)             \
+       $(libgstvaapi_egl_source_priv_h)        \
        $(NULL)
 
 CLEANFILES = \
diff --git a/gst-libs/gst/vaapi/egl_compat.h b/gst-libs/gst/vaapi/egl_compat.h
new file mode 100644 (file)
index 0000000..c417211
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * egl_compat.h - EGL compatiliby layer
+ *
+ * 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
+ */
+
+#ifndef EGL_COMPAT_H
+#define EGL_COMPAT_H
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include "ogl_compat.h"
+
+#ifndef GL_OES_EGL_image
+#define GL_OES_EGL_image 1
+typedef void *GLeglImageOES;
+typedef void (*PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)(GLenum target,
+    GLeglImageOES image);
+typedef void (*PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC)(GLenum target,
+    GLeglImageOES image);
+#endif /* GL_OES_EGL_image */
+
+#endif /* EGL_COMPAT_H */
diff --git a/gst-libs/gst/vaapi/egl_vtable.h b/gst-libs/gst/vaapi/egl_vtable.h
new file mode 100644 (file)
index 0000000..89c5d02
--- /dev/null
@@ -0,0 +1,785 @@
+/*
+ * egl_vtable.h - EGL function definitions
+ *
+ * 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
+ */
+
+/* ------------------------------------------------------------------------- */
+// Generate strings
+
+#define GL_PROTO_GEN_STRING(x) \
+  GL_PROTO_GEN_STRING_I(x)
+#define GL_PROTO_GEN_STRING_I(x) \
+  #x
+
+/* ------------------------------------------------------------------------- */
+// Concatenate arguments
+
+#define GL_PROTO_GEN_CONCAT(a1, a2) \
+  GL_PROTO_GEN_CONCAT2_I(a1, a2)
+#define GL_PROTO_GEN_CONCAT2(a1, a2) \
+  GL_PROTO_GEN_CONCAT2_I(a1, a2)
+#define GL_PROTO_GEN_CONCAT2_I(a1, a2) \
+  a1 ## a2
+
+#define GL_PROTO_GEN_CONCAT3(a1, a2, a3) \
+  GL_PROTO_GEN_CONCAT3_I(a1, a2, a3)
+#define GL_PROTO_GEN_CONCAT3_I(a1, a2, a3) \
+  a1 ## a2 ## a3
+
+#define GL_PROTO_GEN_CONCAT4(a1, a2, a3, a4) \
+  GL_PROTO_GEN_CONCAT4_I(a1, a2, a3, a4)
+#define GL_PROTO_GEN_CONCAT4_I(a1, a2, a3, a4) \
+  a1 ## a2 ## a3 ## a4
+
+#define GL_PROTO_GEN_CONCAT5(a1, a2, a3, a4, a5) \
+  GL_PROTO_GEN_CONCAT5_I(a1, a2, a3, a4, a5)
+#define GL_PROTO_GEN_CONCAT5_I(a1, a2, a3, a4, a5) \
+  a1 ## a2 ## a3 ## a4 ## a5
+
+/* ------------------------------------------------------------------------- */
+// Default macros
+
+#ifndef EGL_PROTO_BEGIN
+#define EGL_PROTO_BEGIN(NAME, TYPE, EXTENSION)
+#endif
+#ifndef EGL_PROTO_ARG_LIST
+#define EGL_PROTO_ARG_LIST(...) GL_PROTO_ARG_LIST(__VA_ARGS__)
+#endif
+#ifndef EGL_PROTO_ARG
+#define EGL_PROTO_ARG(NAME, TYPE) GL_PROTO_ARG(NAME, TYPE)
+#endif
+#ifndef EGL_PROTO_INVOKE
+#define EGL_PROTO_INVOKE(NAME, TYPE, ARGS)
+#endif
+#ifndef EGL_PROTO_END
+#define EGL_PROTO_END()
+#endif
+#ifndef EGL_DEFINE_EXTENSION
+#define EGL_DEFINE_EXTENSION(EXTENSION)
+#endif
+
+#ifndef GL_PROTO_BEGIN
+#define GL_PROTO_BEGIN(NAME, TYPE, EXTENSION)
+#endif
+#ifndef GL_PROTO_ARG_LIST
+#define GL_PROTO_ARG_LIST(...)
+#endif
+#ifndef GL_PROTO_ARG
+#define GL_PROTO_ARG(NAME, TYPE)
+#endif
+#ifndef GL_PROTO_INVOKE
+#define GL_PROTO_INVOKE(NAME, TYPE, ARGS)
+#endif
+#ifndef GL_PROTO_END
+#define GL_PROTO_END()
+#endif
+#ifndef GL_DEFINE_EXTENSION
+#define GL_DEFINE_EXTENSION(EXTENSION)
+#endif
+
+/* NOTE: this is auto-generated code -- do not edit! */
+
+EGL_PROTO_BEGIN(CreateImageKHR, EGLImageKHR, KHR_image_base)
+EGL_PROTO_ARG_LIST(
+EGL_PROTO_ARG(dpy, EGLDisplay),
+EGL_PROTO_ARG(ctx, EGLContext),
+EGL_PROTO_ARG(target, EGLenum),
+EGL_PROTO_ARG(buffer, EGLClientBuffer),
+EGL_PROTO_ARG(attrib_list, const EGLint *))
+EGL_PROTO_INVOKE(CreateImageKHR, EGLImageKHR, (dpy, ctx, target, buffer, attrib_list))
+EGL_PROTO_END()
+
+EGL_PROTO_BEGIN(DestroyImageKHR, EGLImageKHR, KHR_image_base)
+EGL_PROTO_ARG_LIST(
+EGL_PROTO_ARG(dpy, EGLDisplay),
+EGL_PROTO_ARG(image, EGLImageKHR))
+EGL_PROTO_INVOKE(DestroyImageKHR, EGLImageKHR, (dpy, image))
+EGL_PROTO_END()
+
+EGL_PROTO_BEGIN(CreateDRMImageMESA, EGLImageKHR, MESA_drm_image)
+EGL_PROTO_ARG_LIST(
+EGL_PROTO_ARG(dpy, EGLDisplay),
+EGL_PROTO_ARG(attrib_list, const EGLint *))
+EGL_PROTO_INVOKE(CreateDRMImageMESA, EGLImageKHR, (dpy, attrib_list))
+EGL_PROTO_END()
+
+EGL_PROTO_BEGIN(ExportDRMImageMESA, EGLImageKHR, MESA_drm_image)
+EGL_PROTO_ARG_LIST(
+EGL_PROTO_ARG(dpy, EGLDisplay),
+EGL_PROTO_ARG(image, EGLImageKHR),
+EGL_PROTO_ARG(name, EGLint *),
+EGL_PROTO_ARG(handle, EGLint *),
+EGL_PROTO_ARG(stride, EGLint *))
+EGL_PROTO_INVOKE(ExportDRMImageMESA, EGLImageKHR, (dpy, image, name, handle, stride))
+EGL_PROTO_END()
+
+EGL_DEFINE_EXTENSION(EXT_image_dma_buf_import)
+EGL_DEFINE_EXTENSION(KHR_create_context)
+EGL_DEFINE_EXTENSION(KHR_gl_texture_2D_image)
+EGL_DEFINE_EXTENSION(KHR_image_base)
+EGL_DEFINE_EXTENSION(KHR_surfaceless_context)
+EGL_DEFINE_EXTENSION(MESA_configless_context)
+EGL_DEFINE_EXTENSION(MESA_drm_image)
+
+GL_PROTO_BEGIN(GetError, GLenum, CORE_1_0)
+GL_PROTO_ARG_LIST()
+GL_PROTO_INVOKE(GetError, GLenum, ())
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(GetString, const GLubyte *, CORE_1_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(name, GLenum))
+GL_PROTO_INVOKE(GetString, const GLubyte *, (name))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(GetIntegerv, void, CORE_1_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(pname, GLenum),
+GL_PROTO_ARG(params, GLint *))
+GL_PROTO_INVOKE(GetIntegerv, void, (pname, params))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(Enable, void, CORE_1_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(cap, GLenum))
+GL_PROTO_INVOKE(Enable, void, (cap))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(Disable, void, CORE_1_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(cap, GLenum))
+GL_PROTO_INVOKE(Disable, void, (cap))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(IsEnabled, GLboolean, CORE_1_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(cap, GLenum))
+GL_PROTO_INVOKE(IsEnabled, GLboolean, (cap))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(Finish, void, CORE_1_0)
+GL_PROTO_ARG_LIST()
+GL_PROTO_INVOKE(Finish, void, ())
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(Flush, void, CORE_1_0)
+GL_PROTO_ARG_LIST()
+GL_PROTO_INVOKE(Flush, void, ())
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(Begin, void, CORE_1_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(mode, GLenum))
+GL_PROTO_INVOKE(Begin, void, (mode))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(End, void, CORE_1_0)
+GL_PROTO_ARG_LIST()
+GL_PROTO_INVOKE(End, void, ())
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(Color4f, void, CORE_1_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(red, GLfloat),
+GL_PROTO_ARG(green, GLfloat),
+GL_PROTO_ARG(blue, GLfloat),
+GL_PROTO_ARG(alpha, GLfloat))
+GL_PROTO_INVOKE(Color4f, void, (red, green, blue, alpha))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(Clear, void, CORE_1_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(mask, GLbitfield))
+GL_PROTO_INVOKE(Clear, void, (mask))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(ClearColor, void, CORE_1_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(red, GLclampf),
+GL_PROTO_ARG(green, GLclampf),
+GL_PROTO_ARG(blue, GLclampf),
+GL_PROTO_ARG(alpha, GLclampf))
+GL_PROTO_INVOKE(ClearColor, void, (red, green, blue, alpha))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(PushMatrix, void, CORE_1_0)
+GL_PROTO_ARG_LIST()
+GL_PROTO_INVOKE(PushMatrix, void, ())
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(PopMatrix, void, CORE_1_0)
+GL_PROTO_ARG_LIST()
+GL_PROTO_INVOKE(PopMatrix, void, ())
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(LoadIdentity, void, CORE_1_0)
+GL_PROTO_ARG_LIST()
+GL_PROTO_INVOKE(LoadIdentity, void, ())
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(MatrixMode, void, CORE_1_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(mode, GLenum))
+GL_PROTO_INVOKE(MatrixMode, void, (mode))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(PushAttrib, void, CORE_1_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(mask, GLbitfield))
+GL_PROTO_INVOKE(PushAttrib, void, (mask))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(PopAttrib, void, CORE_1_0)
+GL_PROTO_ARG_LIST()
+GL_PROTO_INVOKE(PopAttrib, void, ())
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(Viewport, void, CORE_1_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(x, GLint),
+GL_PROTO_ARG(y, GLint),
+GL_PROTO_ARG(width, GLsizei),
+GL_PROTO_ARG(height, GLsizei))
+GL_PROTO_INVOKE(Viewport, void, (x, y, width, height))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(Frustum, void, CORE_1_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(left, GLdouble),
+GL_PROTO_ARG(right, GLdouble),
+GL_PROTO_ARG(bottom, GLdouble),
+GL_PROTO_ARG(top, GLdouble),
+GL_PROTO_ARG(zNear, GLdouble),
+GL_PROTO_ARG(zFar, GLdouble))
+GL_PROTO_INVOKE(Frustum, void, (left, right, bottom, top, zNear, zFar))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(Scalef, void, CORE_1_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(x, GLfloat),
+GL_PROTO_ARG(y, GLfloat),
+GL_PROTO_ARG(z, GLfloat))
+GL_PROTO_INVOKE(Scalef, void, (x, y, z))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(Translatef, void, CORE_1_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(x, GLfloat),
+GL_PROTO_ARG(y, GLfloat),
+GL_PROTO_ARG(z, GLfloat))
+GL_PROTO_INVOKE(Translatef, void, (x, y, z))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(EnableClientState, void, CORE_1_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(array, GLenum))
+GL_PROTO_INVOKE(EnableClientState, void, (array))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(DisableClientState, void, CORE_1_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(array, GLenum))
+GL_PROTO_INVOKE(DisableClientState, void, (array))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(TexCoordPointer, void, CORE_1_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(size, GLint),
+GL_PROTO_ARG(type, GLenum),
+GL_PROTO_ARG(stride, GLsizei),
+GL_PROTO_ARG(pointer, const GLvoid *))
+GL_PROTO_INVOKE(TexCoordPointer, void, (size, type, stride, pointer))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(VertexPointer, void, CORE_1_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(size, GLint),
+GL_PROTO_ARG(type, GLenum),
+GL_PROTO_ARG(stride, GLsizei),
+GL_PROTO_ARG(pointer, const GLvoid *))
+GL_PROTO_INVOKE(VertexPointer, void, (size, type, stride, pointer))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(EnableVertexAttribArray, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(index, GLuint))
+GL_PROTO_INVOKE(EnableVertexAttribArray, void, (index))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(DisableVertexAttribArray, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(index, GLuint))
+GL_PROTO_INVOKE(DisableVertexAttribArray, void, (index))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(GetVertexAttribPointerv, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(index, GLuint),
+GL_PROTO_ARG(pname, GLenum),
+GL_PROTO_ARG(pointer, GLvoid **))
+GL_PROTO_INVOKE(GetVertexAttribPointerv, void, (index, pname, pointer))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(VertexAttribPointer, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(index, GLuint),
+GL_PROTO_ARG(size, GLint),
+GL_PROTO_ARG(type, GLenum),
+GL_PROTO_ARG(normalized, GLboolean),
+GL_PROTO_ARG(stride, GLsizei),
+GL_PROTO_ARG(pointer, const GLvoid *))
+GL_PROTO_INVOKE(VertexAttribPointer, void, (index, size, type, normalized, stride, pointer))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(DrawArrays, void, CORE_1_1)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(mode, GLenum),
+GL_PROTO_ARG(first, GLint),
+GL_PROTO_ARG(count, GLsizei))
+GL_PROTO_INVOKE(DrawArrays, void, (mode, first, count))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(GenTextures, void, CORE_1_1)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(n, GLsizei),
+GL_PROTO_ARG(textures, GLuint *))
+GL_PROTO_INVOKE(GenTextures, void, (n, textures))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(DeleteTextures, void, CORE_1_1)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(n, GLsizei),
+GL_PROTO_ARG(textures, const GLuint *))
+GL_PROTO_INVOKE(DeleteTextures, void, (n, textures))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(BindTexture, void, CORE_1_1)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(target, GLenum),
+GL_PROTO_ARG(texture, GLuint))
+GL_PROTO_INVOKE(BindTexture, void, (target, texture))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(ActiveTexture, void, CORE_1_3)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(texture, GLenum))
+GL_PROTO_INVOKE(ActiveTexture, void, (texture))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(GetTexLevelParameteriv, void, CORE_1_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(target, GLenum),
+GL_PROTO_ARG(level, GLint),
+GL_PROTO_ARG(pname, GLenum),
+GL_PROTO_ARG(params, GLint *))
+GL_PROTO_INVOKE(GetTexLevelParameteriv, void, (target, level, pname, params))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(TexParameterf, void, CORE_1_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(target, GLenum),
+GL_PROTO_ARG(pname, GLenum),
+GL_PROTO_ARG(param, GLfloat))
+GL_PROTO_INVOKE(TexParameterf, void, (target, pname, param))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(TexParameterfv, void, CORE_1_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(target, GLenum),
+GL_PROTO_ARG(pname, GLenum),
+GL_PROTO_ARG(params, const GLfloat *))
+GL_PROTO_INVOKE(TexParameterfv, void, (target, pname, params))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(TexParameteri, void, CORE_1_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(target, GLenum),
+GL_PROTO_ARG(pname, GLenum),
+GL_PROTO_ARG(param, GLint))
+GL_PROTO_INVOKE(TexParameteri, void, (target, pname, param))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(TexParameteriv, void, CORE_1_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(target, GLenum),
+GL_PROTO_ARG(pname, GLenum),
+GL_PROTO_ARG(params, const GLint *))
+GL_PROTO_INVOKE(TexParameteriv, void, (target, pname, params))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(TexImage2D, void, CORE_1_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(target, GLenum),
+GL_PROTO_ARG(level, GLint),
+GL_PROTO_ARG(internalformat, GLint),
+GL_PROTO_ARG(width, GLsizei),
+GL_PROTO_ARG(height, GLsizei),
+GL_PROTO_ARG(border, GLint),
+GL_PROTO_ARG(format, GLenum),
+GL_PROTO_ARG(type, GLenum),
+GL_PROTO_ARG(pixels, const GLvoid *))
+GL_PROTO_INVOKE(TexImage2D, void, (target, level, internalformat, width, height, border, format, type, pixels))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(TexSubImage2D, void, CORE_1_1)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(target, GLenum),
+GL_PROTO_ARG(level, GLint),
+GL_PROTO_ARG(xoffset, GLint),
+GL_PROTO_ARG(yoffset, GLint),
+GL_PROTO_ARG(width, GLsizei),
+GL_PROTO_ARG(height, GLsizei),
+GL_PROTO_ARG(format, GLenum),
+GL_PROTO_ARG(type, GLenum),
+GL_PROTO_ARG(UNUSED, GLuint),
+GL_PROTO_ARG(pixels, const GLvoid *))
+GL_PROTO_INVOKE(TexSubImage2D, void, (target, level, xoffset, yoffset, width, height, format, type, UNUSED, pixels))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(PixelStoref, void, CORE_1_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(pname, GLenum),
+GL_PROTO_ARG(param, GLfloat))
+GL_PROTO_INVOKE(PixelStoref, void, (pname, param))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(PixelStorei, void, CORE_1_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(pname, GLenum),
+GL_PROTO_ARG(param, GLint))
+GL_PROTO_INVOKE(PixelStorei, void, (pname, param))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(CreateShader, GLuint, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(type, GLenum))
+GL_PROTO_INVOKE(CreateShader, GLuint, (type))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(DeleteShader, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(program, GLuint))
+GL_PROTO_INVOKE(DeleteShader, void, (program))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(ShaderSource, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(shader, GLuint),
+GL_PROTO_ARG(count, GLsizei),
+GL_PROTO_ARG(string, const GLchar * const *),
+GL_PROTO_ARG(length, const GLint *))
+GL_PROTO_INVOKE(ShaderSource, void, (shader, count, string, length))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(CompileShader, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(shader, GLuint))
+GL_PROTO_INVOKE(CompileShader, void, (shader))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(GetShaderiv, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(shader, GLuint),
+GL_PROTO_ARG(pname, GLenum),
+GL_PROTO_ARG(params, GLint *))
+GL_PROTO_INVOKE(GetShaderiv, void, (shader, pname, params))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(GetShaderInfoLog, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(shader, GLuint),
+GL_PROTO_ARG(bufSize, GLsizei),
+GL_PROTO_ARG(length, GLsizei *),
+GL_PROTO_ARG(infoLog, GLchar *))
+GL_PROTO_INVOKE(GetShaderInfoLog, void, (shader, bufSize, length, infoLog))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(CreateProgram, GLuint, CORE_2_0)
+GL_PROTO_ARG_LIST()
+GL_PROTO_INVOKE(CreateProgram, GLuint, ())
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(DeleteProgram, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(program, GLuint))
+GL_PROTO_INVOKE(DeleteProgram, void, (program))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(AttachShader, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(program, GLuint),
+GL_PROTO_ARG(shader, GLuint))
+GL_PROTO_INVOKE(AttachShader, void, (program, shader))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(LinkProgram, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(program, GLuint))
+GL_PROTO_INVOKE(LinkProgram, void, (program))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(UseProgram, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(program, GLuint))
+GL_PROTO_INVOKE(UseProgram, void, (program))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(GetProgramiv, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(program, GLuint),
+GL_PROTO_ARG(pname, GLenum),
+GL_PROTO_ARG(params, GLint *))
+GL_PROTO_INVOKE(GetProgramiv, void, (program, pname, params))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(GetProgramInfoLog, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(program, GLuint),
+GL_PROTO_ARG(bufSize, GLsizei),
+GL_PROTO_ARG(length, GLsizei *),
+GL_PROTO_ARG(infoLog, GLchar *))
+GL_PROTO_INVOKE(GetProgramInfoLog, void, (program, bufSize, length, infoLog))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(BindAttribLocation, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(program, GLuint),
+GL_PROTO_ARG(index, GLuint),
+GL_PROTO_ARG(name, const GLchar *))
+GL_PROTO_INVOKE(BindAttribLocation, void, (program, index, name))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(GetUniformLocation, GLint, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(program, GLuint),
+GL_PROTO_ARG(name, const GLchar *))
+GL_PROTO_INVOKE(GetUniformLocation, GLint, (program, name))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(Uniform1f, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(location, GLint),
+GL_PROTO_ARG(v0, GLfloat))
+GL_PROTO_INVOKE(Uniform1f, void, (location, v0))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(Uniform1fv, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(location, GLint),
+GL_PROTO_ARG(count, GLsizei),
+GL_PROTO_ARG(value, const GLfloat *))
+GL_PROTO_INVOKE(Uniform1fv, void, (location, count, value))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(Uniform1i, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(location, GLint),
+GL_PROTO_ARG(v0, GLint))
+GL_PROTO_INVOKE(Uniform1i, void, (location, v0))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(Uniform1iv, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(location, GLint),
+GL_PROTO_ARG(count, GLsizei),
+GL_PROTO_ARG(value, const GLint *))
+GL_PROTO_INVOKE(Uniform1iv, void, (location, count, value))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(Uniform2f, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(location, GLint),
+GL_PROTO_ARG(v0, GLfloat),
+GL_PROTO_ARG(v1, GLfloat))
+GL_PROTO_INVOKE(Uniform2f, void, (location, v0, v1))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(Uniform2fv, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(location, GLint),
+GL_PROTO_ARG(count, GLsizei),
+GL_PROTO_ARG(value, const GLfloat *))
+GL_PROTO_INVOKE(Uniform2fv, void, (location, count, value))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(Uniform2i, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(location, GLint),
+GL_PROTO_ARG(v0, GLint),
+GL_PROTO_ARG(v1, GLint))
+GL_PROTO_INVOKE(Uniform2i, void, (location, v0, v1))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(Uniform2iv, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(location, GLint),
+GL_PROTO_ARG(count, GLsizei),
+GL_PROTO_ARG(value, const GLint *))
+GL_PROTO_INVOKE(Uniform2iv, void, (location, count, value))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(Uniform3f, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(location, GLint),
+GL_PROTO_ARG(v0, GLfloat),
+GL_PROTO_ARG(v1, GLfloat),
+GL_PROTO_ARG(v2, GLfloat))
+GL_PROTO_INVOKE(Uniform3f, void, (location, v0, v1, v2))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(Uniform3fv, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(location, GLint),
+GL_PROTO_ARG(count, GLsizei),
+GL_PROTO_ARG(value, const GLfloat *))
+GL_PROTO_INVOKE(Uniform3fv, void, (location, count, value))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(Uniform3i, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(location, GLint),
+GL_PROTO_ARG(v0, GLint),
+GL_PROTO_ARG(v1, GLint),
+GL_PROTO_ARG(v2, GLint))
+GL_PROTO_INVOKE(Uniform3i, void, (location, v0, v1, v2))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(Uniform3iv, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(location, GLint),
+GL_PROTO_ARG(count, GLsizei),
+GL_PROTO_ARG(value, const GLint *))
+GL_PROTO_INVOKE(Uniform3iv, void, (location, count, value))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(Uniform4f, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(location, GLint),
+GL_PROTO_ARG(v0, GLfloat),
+GL_PROTO_ARG(v1, GLfloat),
+GL_PROTO_ARG(v2, GLfloat),
+GL_PROTO_ARG(v3, GLfloat))
+GL_PROTO_INVOKE(Uniform4f, void, (location, v0, v1, v2, v3))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(Uniform4fv, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(location, GLint),
+GL_PROTO_ARG(count, GLsizei),
+GL_PROTO_ARG(value, const GLfloat *))
+GL_PROTO_INVOKE(Uniform4fv, void, (location, count, value))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(Uniform4i, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(location, GLint),
+GL_PROTO_ARG(v0, GLint),
+GL_PROTO_ARG(v1, GLint),
+GL_PROTO_ARG(v2, GLint),
+GL_PROTO_ARG(v3, GLint))
+GL_PROTO_INVOKE(Uniform4i, void, (location, v0, v1, v2, v3))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(Uniform4iv, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(location, GLint),
+GL_PROTO_ARG(count, GLsizei),
+GL_PROTO_ARG(value, const GLint *))
+GL_PROTO_INVOKE(Uniform4iv, void, (location, count, value))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(UniformMatrix2fv, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(location, GLint),
+GL_PROTO_ARG(count, GLsizei),
+GL_PROTO_ARG(transpose, GLboolean),
+GL_PROTO_ARG(value, const GLfloat *))
+GL_PROTO_INVOKE(UniformMatrix2fv, void, (location, count, transpose, value))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(UniformMatrix3fv, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(location, GLint),
+GL_PROTO_ARG(count, GLsizei),
+GL_PROTO_ARG(transpose, GLboolean),
+GL_PROTO_ARG(value, const GLfloat *))
+GL_PROTO_INVOKE(UniformMatrix3fv, void, (location, count, transpose, value))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(UniformMatrix4fv, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(location, GLint),
+GL_PROTO_ARG(count, GLsizei),
+GL_PROTO_ARG(transpose, GLboolean),
+GL_PROTO_ARG(value, const GLfloat *))
+GL_PROTO_INVOKE(UniformMatrix4fv, void, (location, count, transpose, value))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(EGLImageTargetTexture2DOES, void, OES_EGL_image)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(target, GLenum),
+GL_PROTO_ARG(image, void *))
+GL_PROTO_INVOKE(EGLImageTargetTexture2DOES, void, (target, image))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(EGLImageTargetRenderbufferStorageOES, void, OES_EGL_image)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(target, GLenum),
+GL_PROTO_ARG(image, void *))
+GL_PROTO_INVOKE(EGLImageTargetRenderbufferStorageOES, void, (target, image))
+GL_PROTO_END()
+
+GL_DEFINE_EXTENSION(CORE_1_0)
+GL_DEFINE_EXTENSION(CORE_1_1)
+GL_DEFINE_EXTENSION(CORE_1_3)
+GL_DEFINE_EXTENSION(CORE_2_0)
+GL_DEFINE_EXTENSION(OES_EGL_image)
+
+#undef EGL_PROTO_BEGIN
+#undef EGL_PROTO_BEGIN_I
+#undef EGL_PROTO_ARG_LIST
+#undef EGL_PROTO_ARG
+#undef EGL_PROTO_INVOKE
+#undef EGL_PROTO_INVOKE_I
+#undef EGL_PROTO_END
+#undef EGL_DEFINE_EXTENSION
+#undef EGL_DEFINE_EXTENSION_I
+
+#undef GL_PROTO_BEGIN
+#undef GL_PROTO_BEGIN_I
+#undef GL_PROTO_ARG_LIST
+#undef GL_PROTO_ARG
+#undef GL_PROTO_INVOKE
+#undef GL_PROTO_INVOKE_I
+#undef GL_PROTO_END
+#undef GL_DEFINE_EXTENSION
+#undef GL_DEFINE_EXTENSION_I
+
+#undef GL_PROTO_GEN_CONCAT5
+#undef GL_PROTO_GEN_CONCAT5_I
+#undef GL_PROTO_GEN_CONCAT4
+#undef GL_PROTO_GEN_CONCAT4_I
+#undef GL_PROTO_GEN_CONCAT3
+#undef GL_PROTO_GEN_CONCAT3_I
+#undef GL_PROTO_GEN_CONCAT2
+#undef GL_PROTO_GEN_CONCAT2_I
+#undef GL_PROTO_GEN_CONCAT
+#undef GL_PROTO_GEN_STRING
+#undef GL_PROTO_GEN_STRING_I
index fc37102..3fe523b 100644 (file)
@@ -163,6 +163,10 @@ gst_vaapi_display_type_get_type (void)
     {GST_VAAPI_DISPLAY_TYPE_GLX,
         "VA/GLX display", "glx"},
 #endif
+#if USE_EGL
+    {GST_VAAPI_DISPLAY_TYPE_EGL,
+        "VA/EGL display", "egl"},
+#endif
 #if USE_WAYLAND
     {GST_VAAPI_DISPLAY_TYPE_WAYLAND,
         "VA/Wayland display", "wayland"},
@@ -2137,5 +2141,6 @@ gst_vaapi_display_has_opengl (GstVaapiDisplay * display)
   g_return_val_if_fail (display != NULL, FALSE);
 
   klass = GST_VAAPI_DISPLAY_GET_CLASS (display);
-  return (klass->display_type == GST_VAAPI_DISPLAY_TYPE_GLX);
+  return (klass->display_type == GST_VAAPI_DISPLAY_TYPE_GLX ||
+          klass->display_type == GST_VAAPI_DISPLAY_TYPE_EGL);
 }
index 998e96e..f4cc865 100644 (file)
@@ -91,6 +91,7 @@ typedef struct _GstVaapiDisplay                 GstVaapiDisplay;
  * @GST_VAAPI_DISPLAY_TYPE_GLX: VA/GLX display.
  * @GST_VAAPI_DISPLAY_TYPE_WAYLAND: VA/Wayland display.
  * @GST_VAAPI_DISPLAY_TYPE_DRM: VA/DRM display.
+ * @GST_VAAPI_DISPLAY_TYPE_EGL: VA/EGL display.
  */
 typedef enum
 {
@@ -99,6 +100,7 @@ typedef enum
   GST_VAAPI_DISPLAY_TYPE_GLX,
   GST_VAAPI_DISPLAY_TYPE_WAYLAND,
   GST_VAAPI_DISPLAY_TYPE_DRM,
+  GST_VAAPI_DISPLAY_TYPE_EGL,
 } GstVaapiDisplayType;
 
 #define GST_VAAPI_TYPE_DISPLAY_TYPE \
diff --git a/gst-libs/gst/vaapi/gstvaapidisplay_egl.c b/gst-libs/gst/vaapi/gstvaapidisplay_egl.c
new file mode 100644 (file)
index 0000000..b02f253
--- /dev/null
@@ -0,0 +1,582 @@
+/*
+ *  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"
+
+GST_DEBUG_CATEGORY (gst_debug_vaapidisplay_egl);
+
+/* ------------------------------------------------------------------------- */
+/* --- Display backend loader                                            --- */
+/* ------------------------------------------------------------------------- */
+
+typedef struct _GstVaapiDisplayLoader GstVaapiDisplayLoader;
+typedef struct _GstVaapiDisplayLoaderInfo GstVaapiDisplayLoaderInfo;
+
+typedef GstVaapiDisplay *(*GstVaapiDisplayCreateFunc) (const gchar * name);
+typedef GstVaapiDisplay *(*GstVaapiDisplayCreateFromNativeFunc) (gpointer dpy);
+
+struct _GstVaapiDisplayLoader
+{
+  GstVaapiMiniObject parent_instance;
+
+  GModule *module;
+  GPtrArray *module_names;
+  GstVaapiDisplayCreateFunc create_display;
+  GstVaapiDisplayCreateFromNativeFunc create_display_from_native;
+};
+
+struct _GstVaapiDisplayLoaderInfo
+{
+  const gchar *name;
+  GstVaapiDisplayType type;
+  const gchar *create_display;
+  const gchar *create_display_from_native;
+};
+
+static GMutex g_loader_lock;
+static GstVaapiDisplayLoader *g_loader;
+
+/* *INDENT-OFF* */
+static const GstVaapiDisplayLoaderInfo g_loader_info[] = {
+#if USE_WAYLAND
+  { "wayland",
+    GST_VAAPI_DISPLAY_TYPE_WAYLAND,
+    "gst_vaapi_display_wayland_new",
+    "gst_vaapi_display_wayland_new_with_display",
+  },
+#endif
+#if USE_X11
+  { "x11",
+    GST_VAAPI_DISPLAY_TYPE_X11,
+    "gst_vaapi_display_x11_new",
+    "gst_vaapi_display_x11_new_with_display",
+  },
+#endif
+  {NULL,}
+};
+/* *INDENT-ON* */
+
+static void
+gst_vaapi_display_loader_finalize (GstVaapiDisplayLoader * loader)
+{
+  if (!loader)
+    return;
+
+  if (loader->module) {
+    g_module_close (loader->module);
+    loader->module = NULL;
+  }
+
+  if (loader->module_names) {
+    g_ptr_array_unref (loader->module_names);
+    loader->module_names = NULL;
+  }
+}
+
+static inline const GstVaapiMiniObjectClass *
+gst_vaapi_display_loader_class (void)
+{
+  static const GstVaapiMiniObjectClass g_class = {
+    .size = sizeof (GstVaapiDisplayLoader),
+    .finalize = (GDestroyNotify) gst_vaapi_display_loader_finalize,
+  };
+  return &g_class;
+}
+
+static inline GstVaapiDisplayLoader *
+gst_vaapi_display_loader_new (void)
+{
+  return (GstVaapiDisplayLoader *)
+      gst_vaapi_mini_object_new0 (gst_vaapi_display_loader_class ());
+}
+
+static gboolean
+gst_vaapi_display_loader_reset_module_names (GstVaapiDisplayLoader * loader,
+    const GstVaapiDisplayLoaderInfo * loader_info)
+{
+  gchar *module_name;
+
+  if (loader->module_names)
+    g_ptr_array_unref (loader->module_names);
+  loader->module_names = g_ptr_array_new_full (3, (GDestroyNotify) g_free);
+  if (!loader->module_names)
+    return FALSE;
+
+  module_name =
+      g_strdup_printf ("libgstvaapi-%s-%s.la", loader_info->name,
+      GST_API_VERSION_S);
+  if (module_name)
+    g_ptr_array_add (loader->module_names, module_name);
+
+  module_name =
+      g_strdup_printf ("libgstvaapi-%s-%s.so", loader_info->name,
+      GST_API_VERSION_S);
+  if (module_name)
+    g_ptr_array_add (loader->module_names, module_name);
+
+  module_name =
+      g_strdup_printf ("libgstvaapi-%s-%s.so.%s", loader_info->name,
+      GST_API_VERSION_S, GST_VAAPI_MAJOR_VERSION_S);
+  if (module_name)
+    g_ptr_array_add (loader->module_names, module_name);
+
+  return loader->module_names->len > 0;
+}
+
+static gboolean
+gst_vaapi_display_loader_try_load_module (GstVaapiDisplayLoader * loader,
+    const GstVaapiDisplayLoaderInfo * loader_info)
+{
+  guint i;
+
+  if (!gst_vaapi_display_loader_reset_module_names (loader, loader_info))
+    return FALSE;
+
+  if (loader->module) {
+    g_module_close (loader->module);
+    loader->module = NULL;
+  }
+
+  for (i = 0; i < loader->module_names->len; i++) {
+    const gchar *const module_name =
+        g_ptr_array_index (loader->module_names, i);
+
+    loader->module = g_module_open (module_name,
+        G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
+    if (loader->module)
+      return TRUE;
+  }
+  return FALSE;
+}
+
+static gboolean
+gst_vaapi_display_loader_try_load (GstVaapiDisplayLoader * loader,
+    const GstVaapiDisplayLoaderInfo * loader_info)
+{
+  guint has_errors = 0;
+
+  if (!gst_vaapi_display_loader_try_load_module (loader, loader_info))
+    return FALSE;
+  GST_DEBUG ("loaded backend: %s", g_module_name (loader->module));
+
+  has_errors |= !g_module_symbol (loader->module,
+      loader_info->create_display, (gpointer *) & loader->create_display);
+  has_errors |= !g_module_symbol (loader->module,
+      loader_info->create_display_from_native,
+      (gpointer *) & loader->create_display_from_native);
+
+  return has_errors == 0;
+}
+
+static GstVaapiDisplay *
+gst_vaapi_display_loader_try_load_any (GstVaapiDisplayLoader * loader)
+{
+  GstVaapiDisplay *display;
+  const GstVaapiDisplayLoaderInfo *loader_info;
+
+  for (loader_info = g_loader_info; loader_info->name != NULL; loader_info++) {
+    if (!gst_vaapi_display_loader_try_load (loader, loader_info))
+      continue;
+
+    display = loader->create_display (NULL);
+    if (display) {
+      GST_INFO ("selected backend: %s", loader_info->name);
+      return display;
+    }
+  }
+  return NULL;
+}
+
+#define gst_vaapi_display_loader_ref(loader) \
+  ((GstVaapiDisplayLoader *) gst_vaapi_mini_object_ref (GST_VAAPI_MINI_OBJECT (loader)))
+#define gst_vaapi_display_loader_unref(loader) \
+  gst_vaapi_mini_object_unref (GST_VAAPI_MINI_OBJECT (loader))
+#define gst_vaapi_display_loader_replace(old_loader_ptr, new_loader) \
+  gst_vaapi_mini_object_replace ((GstVaapiMiniObject **)(old_loader_ptr), \
+      GST_VAAPI_MINI_OBJECT (new_loader))
+
+static GstVaapiDisplayLoader *
+gst_vaapi_display_loader_acquire_global (void)
+{
+  GstVaapiDisplayLoader *loader;
+
+  g_mutex_lock (&g_loader_lock);
+  loader = g_loader ? gst_vaapi_display_loader_ref (g_loader) :
+      gst_vaapi_display_loader_new ();
+  g_loader = loader;
+  g_mutex_unlock (&g_loader_lock);
+  return loader;
+}
+
+static void
+gst_vaapi_display_loader_release_global (void)
+{
+  g_mutex_lock (&g_loader_lock);
+  gst_vaapi_display_loader_replace (&g_loader, NULL);
+  g_mutex_unlock (&g_loader_lock);
+}
+
+static const GstVaapiDisplayLoaderInfo *
+gst_vaapi_display_loader_map_lookup_type (GstVaapiDisplayType type)
+{
+  const GstVaapiDisplayLoaderInfo *loader_info;
+
+  for (loader_info = g_loader_info; loader_info->name != NULL; loader_info++) {
+    if (loader_info->type == type)
+      return loader_info;
+  }
+  return NULL;
+}
+
+/* ------------------------------------------------------------------------- */
+/* --- EGL backend implementation                                        --- */
+/* ------------------------------------------------------------------------- */
+
+static const guint g_display_types = 1U << GST_VAAPI_DISPLAY_TYPE_EGL;
+
+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;
+  GstVaapiDisplayLoader *loader;
+  const GstVaapiDisplayLoaderInfo *loader_info;
+  EglDisplay *egl_display;
+
+  loader = gst_vaapi_display_loader_acquire_global ();
+  if (params->display) {
+    loader_info =
+        gst_vaapi_display_loader_map_lookup_type (params->display_type);
+    if (!loader_info)
+      goto error_unsupported_display_type;
+
+    loader = gst_vaapi_display_loader_new ();
+    if (!loader || !gst_vaapi_display_loader_try_load (loader, loader_info))
+      goto error_init_loader;
+
+    native_display = loader->create_display_from_native (params->display);
+  } else {
+    gst_vaapi_display_loader_ref (loader);
+    native_display = gst_vaapi_display_loader_try_load_any (loader);
+  }
+  gst_vaapi_display_loader_replace (&display->loader, loader);
+  gst_vaapi_display_loader_unref (loader);
+  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;
+
+  /* ERRORS */
+error_unsupported_display_type:
+  GST_ERROR ("unsupported display type (%d)", params->display_type);
+  return FALSE;
+error_init_loader:
+  GST_ERROR ("failed to initialize display backend loader");
+  gst_vaapi_display_loader_replace (&loader, NULL);
+  return FALSE;
+}
+
+static void
+gst_vaapi_display_egl_close_display (GstVaapiDisplayEGL * display)
+{
+  gst_vaapi_display_replace (&display->display, NULL);
+  gst_vaapi_display_loader_replace (&display->loader, NULL);
+  gst_vaapi_display_loader_release_global ();
+}
+
+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 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);
+
+  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;
+}
+
+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);
+}
diff --git a/gst-libs/gst/vaapi/gstvaapidisplay_egl.h b/gst-libs/gst/vaapi/gstvaapidisplay_egl.h
new file mode 100644 (file)
index 0000000..2f79e88
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ *  gstvaapidisplay_egl.h - 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) egl later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT EGL 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_DISPLAY_EGL_H
+#define GST_VAAPI_DISPLAY_EGL_H
+
+#include <EGL/egl.h>
+#include <gst/vaapi/gstvaapidisplay.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstVaapiDisplayEGL GstVaapiDisplayEGL;
+
+#define GST_VAAPI_DISPLAY_EGL(obj) \
+  ((GstVaapiDisplayEGL *)(obj))
+
+GstVaapiDisplay *
+gst_vaapi_display_egl_new (GstVaapiDisplay * display, guint gles_version);
+
+GstVaapiDisplay *
+gst_vaapi_display_egl_new_with_native_display (gpointer native_display,
+    GstVaapiDisplayType display_type, guint gles_version);
+
+EGLDisplay
+gst_vaapi_display_egl_get_gl_display (GstVaapiDisplayEGL * display);
+
+EGLContext
+gst_vaapi_display_egl_get_gl_context (GstVaapiDisplayEGL * display);
+
+gboolean
+gst_vaapi_display_egl_set_gl_context (GstVaapiDisplayEGL * display,
+    EGLContext gl_context);
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_DISPLAY_EGL_H */
diff --git a/gst-libs/gst/vaapi/gstvaapidisplay_egl_priv.h b/gst-libs/gst/vaapi/gstvaapidisplay_egl_priv.h
new file mode 100644 (file)
index 0000000..3db5ad8
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ *  gstvaapidisplay_egl_priv.h - Internal VA/EGL interface
+ *
+ *  Copyright (C) 2014 Splitted-Desktop Systems
+ *    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_DISPLAY_EGL_PRIV_H
+#define GST_VAAPI_DISPLAY_EGL_PRIV_H
+
+#include <gst/vaapi/gstvaapiwindow.h>
+#include "gstvaapidisplay_egl.h"
+#include "gstvaapidisplay_priv.h"
+#include "gstvaapiutils_egl.h"
+
+G_BEGIN_DECLS
+
+#define GST_VAAPI_IS_DISPLAY_EGL(display) \
+  ((display) != NULL && \
+   GST_VAAPI_DISPLAY_GET_CLASS_TYPE (display) == GST_VAAPI_DISPLAY_TYPE_EGL)
+
+#define GST_VAAPI_DISPLAY_EGL_CLASS(klass) \
+  ((GstVaapiDisplayEGLClass *)(klass))
+
+#define GST_VAAPI_DISPLAY_EGL_GET_CLASS(obj) \
+  GST_VAAPI_DISPLAY_EGL_CLASS (GST_VAAPI_DISPLAY_GET_CLASS (obj))
+
+/**
+ * GST_VAAPI_DISPLAY_EGL_DISPLAY:
+ * @display: a #GstVaapiDisplay
+ *
+ * Macro that evaluates to #EglDisplay wrapper for @display.
+ * This is an internal macro that does not do any run-time type check.
+ */
+#undef  GST_VAAPI_DISPLAY_EGL_DISPLAY
+#define GST_VAAPI_DISPLAY_EGL_DISPLAY(display) \
+  (GST_VAAPI_DISPLAY_EGL (display)->egl_display)
+
+/**
+ * GST_VAAPI_DISPLAY_EGL_CONTEXT:
+ * @display: a #GstVaapiDisplay
+ *
+ * Macro that evaluates to #EglContext wrapper for @display.
+ * This is an internal macro that does not do any run-time type check.
+ */
+#undef  GST_VAAPI_DISPLAY_EGL_CONTEXT
+#define GST_VAAPI_DISPLAY_EGL_CONTEXT(display) \
+  gst_vaapi_display_egl_get_context (GST_VAAPI_DISPLAY_EGL (display))
+
+typedef struct _GstVaapiDisplayEGLClass GstVaapiDisplayEGLClass;
+
+/**
+ * GstVaapiDisplayEGL:
+ *
+ * VA/EGL display wrapper.
+ */
+struct _GstVaapiDisplayEGL
+{
+  /*< private >*/
+  GstVaapiDisplay parent_instance;
+
+  gpointer loader;
+  GstVaapiDisplay *display;
+  EglDisplay *egl_display;
+  EglContext *egl_context;
+  guint gles_version;
+};
+
+/**
+ * GstVaapiDisplayEGLClass:
+ *
+ * VA/EGL display wrapper clas.
+ */
+struct _GstVaapiDisplayEGLClass
+{
+  /*< private >*/
+  GstVaapiDisplayClass parent_class;
+};
+
+G_GNUC_INTERNAL
+EglContext *
+gst_vaapi_display_egl_get_context (GstVaapiDisplayEGL * display);
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_DISPLAY_EGL_PRIV_H */
diff --git a/gst-libs/gst/vaapi/gstvaapiutils_egl.c b/gst-libs/gst/vaapi/gstvaapiutils_egl.c
new file mode 100644 (file)
index 0000000..6217625
--- /dev/null
@@ -0,0 +1,1342 @@
+/*
+ * gstvaapiutils_egl.c - EGL utilities
+ *
+ * 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
+ */
+
+#include "sysdeps.h"
+#include "gstvaapiutils_egl.h"
+
+typedef struct egl_message_s EglMessage;
+struct egl_message_s
+{
+  EglObject base;
+  EglContextRunFunc func;
+  gpointer args;
+};
+
+static void
+egl_message_finalize (EglMessage * msg)
+{
+}
+
+/* ------------------------------------------------------------------------- */
+// Utility functions
+
+typedef struct gl_version_info_s GlVersionInfo;
+struct gl_version_info_s
+{
+  guint gles_version;
+  guint gl_api_bit;
+  guint gl_api;
+  const gchar *gl_api_name;
+};
+
+static const GlVersionInfo gl_version_info[] = {
+  {0, EGL_OPENGL_BIT, EGL_OPENGL_API, "OpenGL"},
+  {1, EGL_OPENGL_ES_BIT, EGL_OPENGL_ES_API, "OpenGL_ES"},
+  {2, EGL_OPENGL_ES2_BIT, EGL_OPENGL_ES_API, "OpenGL_ES2"},
+  {3, EGL_OPENGL_ES3_BIT_KHR, EGL_OPENGL_ES_API, "OpenGL_ES3"},
+  {0,}
+};
+
+static const GlVersionInfo *
+gl_version_info_lookup (guint gles_version)
+{
+  const GlVersionInfo *vinfo;
+
+  for (vinfo = gl_version_info; vinfo->gl_api_bit != 0; vinfo++) {
+    if (vinfo->gles_version == gles_version)
+      return vinfo;
+  }
+  return NULL;
+}
+
+static const GlVersionInfo *
+gl_version_info_lookup_by_api (guint api)
+{
+  const GlVersionInfo *vinfo;
+
+  for (vinfo = gl_version_info; vinfo->gl_api_bit != 0; vinfo++) {
+    if (api & vinfo->gl_api_bit)
+      return vinfo;
+  }
+  return NULL;
+}
+
+static const GlVersionInfo *
+gl_version_info_lookup_by_api_name (const gchar * name)
+{
+  const GlVersionInfo *vinfo;
+
+  for (vinfo = gl_version_info; vinfo->gl_api_bit != 0; vinfo++) {
+    if (g_strcmp0 (vinfo->gl_api_name, name) == 0)
+      return vinfo;
+  }
+  return NULL;
+}
+
+static gboolean
+g_strv_match_string (gchar ** extensions_list, const gchar * name)
+{
+  if (extensions_list) {
+    for (; *extensions_list != NULL; extensions_list++) {
+      if (g_strcmp0 (*extensions_list, name) == 0)
+        return TRUE;
+    }
+  }
+  return FALSE;
+}
+
+static gboolean
+egl_find_attrib_value (const EGLint * attribs, EGLint type, EGLint * value_ptr)
+{
+  while (attribs[0] != EGL_NONE) {
+    if (attribs[0] == type) {
+      if (value_ptr)
+        *value_ptr = attribs[1];
+      return TRUE;
+    }
+    attribs += 2;
+  }
+  return FALSE;
+}
+
+/* ------------------------------------------------------------------------- */
+// Basic objects
+
+#define EGL_OBJECT(object) ((EglObject *)(object))
+#define EGL_OBJECT_CLASS(klass) ((EglObjectClass *)(klass))
+
+#define EGL_OBJECT_DEFINE_CLASS_WITH_CODE(TN, t_n, code)        \
+static void                                                     \
+G_PASTE(t_n,_finalize) (TN * object);                           \
+                                                                \
+static inline const EglObjectClass *                            \
+G_PASTE(t_n,_class) (void)                                      \
+{                                                               \
+  static G_PASTE(TN,Class) g_class;                             \
+  static gsize g_class_init = FALSE;                            \
+                                                                \
+  if (g_once_init_enter (&g_class_init)) {                      \
+    GstVaapiMiniObjectClass *const object_class =               \
+        GST_VAAPI_MINI_OBJECT_CLASS (&g_class);                 \
+    code;                                                       \
+    object_class->size = sizeof (TN);                           \
+    object_class->finalize = (GDestroyNotify)                   \
+      G_PASTE(t_n,_finalize);                                   \
+    g_once_init_leave (&g_class_init, TRUE);                    \
+  }                                                             \
+  return EGL_OBJECT_CLASS (&g_class);                           \
+}
+
+#define EGL_OBJECT_DEFINE_CLASS(TN, t_n) \
+  EGL_OBJECT_DEFINE_CLASS_WITH_CODE (TN, t_n, /**/)
+
+static inline gpointer
+egl_object_new (const EglObjectClass * klass)
+{
+  return gst_vaapi_mini_object_new (GST_VAAPI_MINI_OBJECT_CLASS (klass));
+}
+
+static inline gpointer
+egl_object_new0 (const EglObjectClass * klass)
+{
+  return gst_vaapi_mini_object_new0 (GST_VAAPI_MINI_OBJECT_CLASS (klass));
+}
+
+typedef struct egl_object_class_s EglMessageClass;
+typedef struct egl_object_class_s EglVTableClass;
+typedef struct egl_object_class_s EglDisplayClass;
+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;
+
+EGL_OBJECT_DEFINE_CLASS (EglMessage, egl_message);
+EGL_OBJECT_DEFINE_CLASS (EglVTable, egl_vtable);
+EGL_OBJECT_DEFINE_CLASS (EglDisplay, egl_display);
+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);
+
+/* ------------------------------------------------------------------------- */
+// Desktop OpenGL and OpenGL|ES dispatcher (vtable)
+
+static GMutex gl_vtables_lock;
+static EglVTable *gl_vtables[4];
+
+#if (USE_GLES_VERSION_MASK & (1U << 0))
+static const gchar *gl_library_names[] = {
+  "libGL.la",
+  "libGL.so.1",
+  NULL
+};
+#endif
+
+#if (USE_GLES_VERSION_MASK & (1U << 1))
+static const gchar *gles1_library_names[] = {
+  "libGLESv1_CM.la",
+  "libGLESv1_CM.so.1",
+  NULL
+};
+#endif
+
+#if (USE_GLES_VERSION_MASK & (1U << 2))
+static const gchar *gles2_library_names[] = {
+  "libGLESv2.la",
+  "libGLESv2.so.2",
+  NULL
+};
+#endif
+
+static const gchar **gl_library_names_group[] = {
+#if (USE_GLES_VERSION_MASK & (1U << 0))
+  gl_library_names,
+#endif
+  NULL
+};
+
+static const gchar **gles1_library_names_group[] = {
+#if (USE_GLES_VERSION_MASK & (1U << 1))
+  gles1_library_names,
+#endif
+  NULL
+};
+
+static const gchar **gles2_library_names_group[] = {
+#if (USE_GLES_VERSION_MASK & (1U << 2))
+  gles2_library_names,
+#endif
+  NULL
+};
+
+static const gchar **gles3_library_names_group[] = {
+#if (USE_GLES_VERSION_MASK & (1U << 3))
+  gles2_library_names,
+#endif
+  NULL
+};
+
+static const gchar ***
+egl_vtable_get_library_names_group (guint gles_version)
+{
+  const gchar ***library_names_group;
+
+  switch (gles_version) {
+    case 0:
+      library_names_group = gl_library_names_group;
+      break;
+    case 1:
+      library_names_group = gles1_library_names_group;
+      break;
+    case 2:
+      library_names_group = gles2_library_names_group;
+      break;
+    case 3:
+      library_names_group = gles3_library_names_group;
+      break;
+    default:
+      library_names_group = NULL;
+      break;
+  }
+  return library_names_group;
+}
+
+static gboolean
+egl_vtable_check_extension (EglVTable * vtable, EGLDisplay display,
+    gboolean is_egl, const gchar * group_name, guint * group_ptr)
+{
+  gchar ***extensions_list;
+  const gchar *extensions;
+
+  g_return_val_if_fail (group_name != NULL, FALSE);
+  g_return_val_if_fail (group_ptr != NULL, FALSE);
+
+  if (*group_ptr > 0)
+    return TRUE;
+
+  GST_DEBUG ("check for %s extension %s", is_egl ? "EGL" : "GL", group_name);
+
+  if (is_egl) {
+    if (!vtable->egl_extensions) {
+      extensions = eglQueryString (display, EGL_EXTENSIONS);
+      if (!extensions)
+        return FALSE;
+      GST_DEBUG ("EGL extensions: %s", extensions);
+      vtable->egl_extensions = g_strsplit (extensions, " ", 0);
+    }
+    extensions_list = &vtable->egl_extensions;
+  } else {
+    if (!vtable->gl_extensions) {
+      extensions = (const gchar *) vtable->glGetString (GL_EXTENSIONS);
+      if (!extensions)
+        return FALSE;
+      GST_DEBUG ("GL extensions: %s", extensions);
+      vtable->gl_extensions = g_strsplit (extensions, " ", 0);
+    }
+    extensions_list = &vtable->gl_extensions;
+  }
+  if (!g_strv_match_string (*extensions_list, group_name))
+    return FALSE;
+
+  GST_LOG ("  found %s extension %s", is_egl ? "EGL" : "GL", group_name);
+  (*group_ptr)++;
+  return TRUE;
+}
+
+static gboolean
+egl_vtable_load_symbol (EglVTable * vtable, EGLDisplay display, gboolean is_egl,
+    const gchar * symbol_name, gpointer * symbol_ptr,
+    const gchar * group_name, guint * group_ptr)
+{
+  void (*symbol) (void);
+
+  if (group_ptr && !*group_ptr) {
+    if (!egl_vtable_check_extension (vtable, display, is_egl, group_name,
+            group_ptr))
+      return FALSE;
+  }
+
+  if (is_egl) {
+    symbol = eglGetProcAddress (symbol_name);
+  } else {
+    if (!g_module_symbol (vtable->base.handle.p, symbol_name,
+            (gpointer *) & symbol))
+      return FALSE;
+  }
+  if (!symbol)
+    return FALSE;
+
+  GST_LOG ("  found symbol %s", symbol_name);
+  if (symbol_ptr)
+    *symbol_ptr = symbol;
+  if (group_ptr)
+    (*group_ptr)++;
+  return TRUE;
+}
+
+static gboolean
+egl_vtable_load_egl_symbols (EglVTable * vtable, EGLDisplay display)
+{
+  guint n = 0;
+
+#define EGL_DEFINE_EXTENSION(NAME) do {                         \
+      egl_vtable_check_extension (vtable, display, TRUE,        \
+          "EGL_" G_STRINGIFY (NAME),                            \
+          &vtable->GL_PROTO_GEN_CONCAT(has_EGL_,NAME));         \
+    } while (0);
+
+#define EGL_PROTO_BEGIN(NAME, TYPE, EXTENSION) do {             \
+      n += egl_vtable_load_symbol (vtable, display, TRUE,       \
+          G_STRINGIFY(GL_PROTO_GEN_CONCAT(egl,NAME)),           \
+          (gpointer *) &vtable->GL_PROTO_GEN_CONCAT(egl,NAME),  \
+          "EGL_" G_STRINGIFY(EXTENSION),                        \
+          &vtable->GL_PROTO_GEN_CONCAT(has_EGL_,EXTENSION));    \
+    } while (0);
+
+#include "egl_vtable.h"
+
+  vtable->num_egl_symbols = n;
+  return TRUE;
+}
+
+static gboolean
+egl_vtable_load_gl_symbols (EglVTable * vtable, EGLDisplay display)
+{
+  guint n = 0;
+
+  vtable->has_GL_CORE_1_0 = 1;
+  vtable->has_GL_CORE_1_1 = 1;
+  vtable->has_GL_CORE_1_3 = 1;
+  vtable->has_GL_CORE_2_0 = 1;
+
+#define GL_DEFINE_EXTENSION(NAME) do {                          \
+      egl_vtable_check_extension (vtable, display, FALSE,       \
+          "GL_" G_STRINGIFY (NAME),                             \
+          &vtable->GL_PROTO_GEN_CONCAT(has_GL_,NAME));          \
+    } while (0);
+
+#define GL_PROTO_BEGIN(NAME, TYPE, EXTENSION) do {              \
+      n += egl_vtable_load_symbol (vtable, display, FALSE,      \
+          G_STRINGIFY(GL_PROTO_GEN_CONCAT(gl,NAME)),            \
+          (gpointer *) &vtable->GL_PROTO_GEN_CONCAT(gl,NAME),   \
+          "GL_" G_STRINGIFY(EXTENSION),                         \
+          &vtable->GL_PROTO_GEN_CONCAT(has_GL_,EXTENSION));     \
+    } while (0);
+
+#include "egl_vtable.h"
+
+  --vtable->has_GL_CORE_1_0;
+  --vtable->has_GL_CORE_1_1;
+  --vtable->has_GL_CORE_1_3;
+  --vtable->has_GL_CORE_2_0;
+
+  vtable->num_gl_symbols = n;
+  return TRUE;
+}
+
+static gboolean
+egl_vtable_try_load_library (EglVTable * vtable, const gchar * name)
+{
+  if (vtable->base.handle.p)
+    g_module_close (vtable->base.handle.p);
+  vtable->base.handle.p = g_module_open (name,
+      G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
+  if (!vtable->base.handle.p)
+    return FALSE;
+
+  GST_DEBUG ("loaded backend: %s", g_module_name (vtable->base.handle.p));
+  return TRUE;
+}
+
+static gboolean
+egl_vtable_find_library (EglVTable * vtable)
+{
+  const gchar ***library_names_ptr =
+      egl_vtable_get_library_names_group (vtable->gles_version);
+
+  if (!library_names_ptr)
+    return FALSE;
+
+  for (; *library_names_ptr != NULL; library_names_ptr++) {
+    const gchar **library_name_ptr = *library_names_ptr;
+    for (; *library_name_ptr != NULL; library_name_ptr++) {
+      if (egl_vtable_try_load_library (vtable, *library_name_ptr))
+        return TRUE;
+    }
+  }
+  return FALSE;
+}
+
+static gboolean
+egl_vtable_init (EglVTable * vtable, EGLDisplay display, guint gles_version)
+{
+  GST_DEBUG ("initialize for OpenGL|ES API version %d", gles_version);
+
+  vtable->gles_version = gles_version;
+  if (!egl_vtable_find_library (vtable))
+    return FALSE;
+  if (!egl_vtable_load_egl_symbols (vtable, display))
+    return FALSE;
+  return TRUE;
+}
+
+static void
+egl_vtable_finalize (EglVTable * vtable)
+{
+  g_strfreev (vtable->egl_extensions);
+  g_strfreev (vtable->gl_extensions);
+  if (vtable->base.handle.p)
+    g_module_close (vtable->base.handle.p);
+
+  if (vtable->base.is_wrapped) {
+    g_mutex_lock (&gl_vtables_lock);
+    gl_vtables[vtable->gles_version] = NULL;
+    g_mutex_unlock (&gl_vtables_lock);
+  }
+}
+
+static EglVTable *
+egl_vtable_new (EglDisplay * display, guint gles_version)
+{
+  EglVTable *vtable;
+
+  g_return_val_if_fail (display != NULL, NULL);
+
+  vtable = egl_object_new0 (egl_vtable_class ());
+  if (!vtable
+      || !egl_vtable_init (vtable, display->base.handle.p, gles_version))
+    goto error;
+  return vtable;
+
+error:
+  egl_object_replace (&vtable, NULL);
+  return NULL;
+}
+
+static EglVTable *
+egl_vtable_new_cached (EglDisplay * display, guint gles_version)
+{
+  EglVTable *vtable, **vtable_ptr;
+
+  g_return_val_if_fail (gles_version < G_N_ELEMENTS (gl_vtables), NULL);
+
+  vtable_ptr = &gl_vtables[gles_version];
+
+  g_mutex_lock (&gl_vtables_lock);
+  vtable = *vtable_ptr;
+  if (vtable)
+    egl_object_ref (vtable);
+  else {
+    vtable = egl_vtable_new (display, gles_version);
+    if (vtable) {
+      vtable->base.is_wrapped = TRUE;
+      *vtable_ptr = vtable;
+    }
+  }
+  g_mutex_unlock (&gl_vtables_lock);
+  return vtable;
+}
+
+/* ------------------------------------------------------------------------- */
+// EGL Display
+
+static gboolean
+egl_display_run (EglDisplay * display, EglContextRunFunc func, gpointer args)
+{
+  EglMessage *msg;
+
+  if (display->gl_thread == g_thread_self ()) {
+    func (args);
+    return TRUE;
+  }
+
+  msg = egl_object_new0 (egl_message_class ());
+  if (!msg)
+    return FALSE;
+
+  msg->base.is_valid = TRUE;
+  msg->func = func;
+  msg->args = args;
+  g_async_queue_push (display->gl_queue, egl_object_ref (msg));
+
+  g_mutex_lock (&display->mutex);
+  while (msg->base.is_valid)
+    g_cond_wait (&display->gl_thread_ready, &display->mutex);
+  g_mutex_unlock (&display->mutex);
+  egl_object_unref (msg);
+  return TRUE;
+}
+
+static gpointer
+egl_display_thread (gpointer data)
+{
+  EglDisplay *const display = data;
+  EGLDisplay gl_display = display->base.handle.p;
+  EGLint major_version, minor_version;
+  gchar **gl_apis, **gl_api;
+
+  if (!display->base.is_wrapped) {
+    gl_display = display->base.handle.p = eglGetDisplay (gl_display);
+    if (!gl_display)
+      goto error;
+    if (!eglInitialize (gl_display, &major_version, &minor_version))
+      goto error;
+  }
+
+  display->gl_vendor_string =
+      g_strdup (eglQueryString (gl_display, EGL_VENDOR));
+  display->gl_version_string =
+      g_strdup (eglQueryString (gl_display, EGL_VERSION));
+  display->gl_apis_string =
+      g_strdup (eglQueryString (gl_display, EGL_CLIENT_APIS));
+
+  GST_INFO ("EGL vendor: %s", display->gl_vendor_string);
+  GST_INFO ("EGL version: %s", display->gl_version_string);
+  GST_INFO ("EGL client APIs: %s", display->gl_apis_string);
+
+  gl_apis = g_strsplit (display->gl_apis_string, " ", 0);
+  if (!gl_apis)
+    goto error;
+  for (gl_api = gl_apis; *gl_api != NULL; gl_api++) {
+    const GlVersionInfo *const vinfo =
+        gl_version_info_lookup_by_api_name (*gl_api);
+
+    if (vinfo)
+      display->gl_apis |= vinfo->gl_api_bit;
+  }
+  g_strfreev (gl_apis);
+  if (!display->gl_apis)
+    goto error;
+
+  display->base.is_valid = TRUE;
+  g_cond_broadcast (&display->gl_thread_ready);
+
+  while (!display->gl_thread_cancel) {
+    EglMessage *const msg =
+        g_async_queue_timeout_pop (display->gl_queue, 100000);
+
+    if (msg) {
+      if (msg->base.is_valid) {
+        msg->func (msg->args);
+        msg->base.is_valid = FALSE;
+        g_cond_broadcast (&display->gl_thread_ready);
+      }
+      egl_object_unref (msg);
+    }
+  }
+
+done:
+  if (gl_display != EGL_NO_DISPLAY && !display->base.is_wrapped)
+    eglTerminate (gl_display);
+  display->base.handle.p = NULL;
+  g_cond_broadcast (&display->gl_thread_ready);
+  return NULL;
+
+error:
+  display->base.is_valid = FALSE;
+  goto done;
+}
+
+static gboolean
+egl_display_init (EglDisplay * display)
+{
+  display->gl_queue =
+      g_async_queue_new_full ((GDestroyNotify) gst_vaapi_mini_object_unref);
+  if (!display->gl_queue)
+    return FALSE;
+
+  g_mutex_init (&display->mutex);
+  g_cond_init (&display->gl_thread_ready);
+  display->gl_thread = g_thread_try_new ("OpenGL Thread", egl_display_thread,
+      display, NULL);
+  if (!display->gl_thread)
+    return FALSE;
+
+  g_mutex_lock (&display->mutex);
+  g_cond_wait (&display->gl_thread_ready, &display->mutex);
+  g_mutex_unlock (&display->mutex);
+  return display->base.is_valid;
+}
+
+static void
+egl_display_finalize (EglDisplay * display)
+{
+  display->gl_thread_cancel = TRUE;
+  g_thread_join (display->gl_thread);
+  g_cond_clear (&display->gl_thread_ready);
+  g_mutex_clear (&display->mutex);
+  g_async_queue_unref (display->gl_queue);
+
+  g_free (display->gl_vendor_string);
+  g_free (display->gl_version_string);
+  g_free (display->gl_apis_string);
+}
+
+static EglDisplay *
+egl_display_new_full (gpointer handle, gboolean is_wrapped)
+{
+  EglDisplay *display;
+
+  display = egl_object_new0 (egl_display_class ());
+  if (!display)
+    return NULL;
+
+  display->base.handle.p = handle;
+  display->base.is_wrapped = is_wrapped;
+  if (!egl_display_init (display))
+    goto error;
+  return display;
+
+error:
+  egl_object_unref (display);
+  return NULL;
+}
+
+EglDisplay *
+egl_display_new (gpointer native_display)
+{
+  g_return_val_if_fail (native_display != NULL, NULL);
+
+  return egl_display_new_full (native_display, FALSE);
+}
+
+EglDisplay *
+egl_display_new_wrapped (EGLDisplay gl_display)
+{
+  g_return_val_if_fail (gl_display != EGL_NO_DISPLAY, NULL);
+
+  return egl_display_new_full (gl_display, TRUE);
+}
+
+/* ------------------------------------------------------------------------- */
+// EGL Config
+
+static gboolean
+egl_config_init (EglConfig * config, EglDisplay * display,
+    const EGLint * attribs)
+{
+  EGLDisplay const gl_display = display->base.handle.p;
+  const GlVersionInfo *vinfo;
+  EGLConfig gl_config;
+  EGLint v, gl_apis, num_configs;
+
+  egl_object_replace (&config->display, display);
+
+  if (!eglChooseConfig (gl_display, attribs, &gl_config, 1, &num_configs))
+    return FALSE;
+  if (num_configs != 1)
+    return FALSE;
+  config->base.handle.p = gl_config;
+
+  if (!eglGetConfigAttrib (gl_display, gl_config, EGL_CONFIG_ID, &v))
+    return FALSE;
+  config->config_id = v;
+
+  if (!eglGetConfigAttrib (gl_display, gl_config, EGL_NATIVE_VISUAL_ID, &v))
+    return FALSE;
+  config->visual_id = v;
+
+  if (!eglGetConfigAttrib (gl_display, gl_config, EGL_RENDERABLE_TYPE, &v))
+    return FALSE;
+  if (!egl_find_attrib_value (attribs, EGL_RENDERABLE_TYPE, &gl_apis))
+    return FALSE;
+  vinfo = gl_version_info_lookup_by_api (v & gl_apis);
+  if (!vinfo)
+    return FALSE;
+  config->gles_version = vinfo->gles_version;
+  config->gl_api = vinfo->gles_version > 0 ? EGL_OPENGL_ES_API : EGL_OPENGL_API;
+  return TRUE;
+}
+
+static void
+egl_config_finalize (EglConfig * config)
+{
+  egl_object_replace (&config->display, NULL);
+}
+
+EglConfig *
+egl_config_new (EglDisplay * display, guint gles_version, GstVideoFormat format)
+{
+  EGLint attribs[2 * 6 + 1], *attrib = attribs;
+  const GstVideoFormatInfo *finfo;
+  const GlVersionInfo *vinfo;
+
+  g_return_val_if_fail (display != NULL, NULL);
+
+  finfo = gst_video_format_get_info (format);
+  if (!finfo || !GST_VIDEO_FORMAT_INFO_IS_RGB (finfo))
+    return NULL;
+
+  vinfo = gl_version_info_lookup (gles_version);
+  if (!vinfo)
+    return NULL;
+
+  *attrib++ = EGL_COLOR_BUFFER_TYPE;
+  *attrib++ = EGL_RGB_BUFFER;
+  *attrib++ = EGL_RED_SIZE;
+  *attrib++ = GST_VIDEO_FORMAT_INFO_DEPTH (finfo, GST_VIDEO_COMP_R);
+  *attrib++ = EGL_GREEN_SIZE;
+  *attrib++ = GST_VIDEO_FORMAT_INFO_DEPTH (finfo, GST_VIDEO_COMP_G);
+  *attrib++ = EGL_BLUE_SIZE;
+  *attrib++ = GST_VIDEO_FORMAT_INFO_DEPTH (finfo, GST_VIDEO_COMP_B);
+  *attrib++ = EGL_ALPHA_SIZE;
+  *attrib++ = GST_VIDEO_FORMAT_INFO_DEPTH (finfo, GST_VIDEO_COMP_A);
+  *attrib++ = EGL_RENDERABLE_TYPE;
+  *attrib++ = vinfo->gl_api_bit;
+  *attrib++ = EGL_NONE;
+  g_assert (attrib - attribs <= G_N_ELEMENTS (attribs));
+
+  return egl_config_new_with_attribs (display, attribs);
+}
+
+EglConfig *
+egl_config_new_with_attribs (EglDisplay * display, const EGLint * attribs)
+{
+  EglConfig *config;
+
+  g_return_val_if_fail (display != NULL, NULL);
+  g_return_val_if_fail (attribs != NULL, NULL);
+
+  config = egl_object_new0 (egl_config_class ());
+  if (!config || !egl_config_init (config, display, attribs))
+    goto error;
+  return config;
+
+error:
+  egl_object_replace (&config, NULL);
+  return NULL;
+}
+
+static EglConfig *
+egl_config_new_from_gl_context (EglDisplay * display, EGLContext gl_context)
+{
+  EGLDisplay const gl_display = display->base.handle.p;
+  EGLint attribs[3 * 2 + 1], *attrib = attribs;
+  EGLint config_id, api, v;
+  guint gles_version;
+  const GlVersionInfo *vinfo;
+
+  if (!eglQueryContext (gl_display, gl_context, EGL_CONFIG_ID, &config_id))
+    return NULL;
+  if (!eglQueryContext (gl_display, gl_context, EGL_CONTEXT_CLIENT_TYPE, &api))
+    return NULL;
+  if (!eglQueryContext (gl_display, gl_context, EGL_CONTEXT_CLIENT_VERSION, &v))
+    return NULL;
+
+  if (api == EGL_OPENGL_API)
+    gles_version = 0;
+  else if (api == EGL_OPENGL_ES_API)
+    gles_version = v;
+  else {
+    GST_ERROR ("unsupported EGL client API (%d)", api);
+    return NULL;
+  }
+
+  vinfo = gl_version_info_lookup (gles_version);
+  if (!vinfo)
+    return NULL;
+
+  *attrib++ = EGL_COLOR_BUFFER_TYPE;
+  *attrib++ = EGL_RGB_BUFFER;
+  *attrib++ = EGL_CONFIG_ID;
+  *attrib++ = config_id;
+  *attrib++ = EGL_RENDERABLE_TYPE;
+  *attrib++ = vinfo->gl_api_bit;
+  *attrib++ = EGL_NONE;
+  g_assert (attrib - attribs <= G_N_ELEMENTS (attribs));
+
+  return egl_config_new_with_attribs (display, attribs);
+}
+
+/* ------------------------------------------------------------------------- */
+// EGL Surface
+
+static void
+egl_surface_finalize (EglSurface * surface)
+{
+  if (surface->base.handle.p != EGL_NO_SURFACE && !surface->base.is_wrapped)
+    eglDestroySurface (surface->display->base.handle.p, surface->base.handle.p);
+  egl_object_replace (&surface->display, NULL);
+}
+
+EglSurface *
+egl_surface_new_wrapped (EglDisplay * display, EGLSurface gl_surface)
+{
+  EglSurface *surface;
+
+  g_return_val_if_fail (display != NULL, NULL);
+
+  surface = egl_object_new (egl_surface_class ());
+  if (!surface)
+    return NULL;
+
+  surface->base.is_wrapped = TRUE;
+  surface->base.handle.p = gl_surface;
+  surface->display = egl_object_ref (display);
+  return surface;
+}
+
+/* ------------------------------------------------------------------------- */
+// EGL Context
+
+static void
+egl_context_state_get_current (EglContextState * cs);
+
+static gboolean
+egl_context_state_set_current (EglContextState * new_cs,
+    EglContextState * old_cs);
+
+static gboolean
+ensure_vtable (EglContext * ctx)
+{
+  if (!ctx->vtable) {
+    ctx->vtable = egl_vtable_new_cached (ctx->display,
+        ctx->config ? ctx->config->gles_version : 0);
+    if (!ctx->vtable)
+      return FALSE;
+  }
+  return TRUE;
+}
+
+static gboolean
+ensure_context (EglContext * ctx, EGLContext gl_parent_context)
+{
+  EGLDisplay *const gl_display = ctx->display->base.handle.p;
+  EGLContext gl_context = ctx->base.handle.p;
+  EGLint gles_attribs[3], *attribs = NULL;
+
+  if (!gl_context) {
+    if (ctx->config->gles_version >= 2) {
+      attribs = gles_attribs;
+      attribs[0] = EGL_CONTEXT_CLIENT_VERSION;
+      attribs[1] = ctx->config->gles_version;
+      attribs[2] = EGL_NONE;
+    }
+
+    gl_context = eglCreateContext (gl_display, ctx->config->base.handle.p,
+        gl_parent_context, attribs);
+    if (!gl_context)
+      goto error_create_context;
+    ctx->base.handle.p = gl_context;
+  }
+  return TRUE;
+
+  /* ERRORS */
+error_create_context:
+  GST_ERROR ("failed to create EGL context");
+  return FALSE;
+}
+
+static inline gboolean
+ensure_gl_is_surfaceless (EglContext * ctx)
+{
+  return ctx->vtable->has_EGL_KHR_surfaceless_context ||
+      (ctx->read_surface && ctx->draw_surface);
+}
+
+static gboolean
+ensure_gl_scene (EglContext * ctx)
+{
+  EglVTable *vtable;
+
+  if (!ensure_gl_is_surfaceless (ctx))
+    return FALSE;
+
+  if (ctx->base.is_valid)
+    return TRUE;
+
+  vtable = egl_context_get_vtable (ctx, TRUE);
+  if (!vtable)
+    return FALSE;
+
+  vtable->glClearColor (0.0, 0.0, 0.0, 1.0);
+  if (ctx->config && ctx->config->gles_version == 0)
+    vtable->glEnable (GL_TEXTURE_2D);
+  vtable->glDisable (GL_BLEND);
+  vtable->glDisable (GL_DEPTH_TEST);
+
+  ctx->base.is_valid = TRUE;
+  return TRUE;
+}
+
+/**
+ * egl_context_state_get_current:
+ * @cs: return location to the current #EglContextState
+ *
+ * Retrieves the current EGL context, display and surface to pack into
+ * the #EglContextState struct.
+ */
+static void
+egl_context_state_get_current (EglContextState * cs)
+{
+  cs->display = eglGetCurrentDisplay ();
+  cs->context = eglGetCurrentContext ();
+  if (cs->context) {
+    cs->read_surface = eglGetCurrentSurface (EGL_READ);
+    cs->draw_surface = eglGetCurrentSurface (EGL_DRAW);
+  } else {
+    cs->read_surface = EGL_NO_SURFACE;
+    cs->draw_surface = EGL_NO_SURFACE;
+  }
+}
+
+/**
+ * egl_context_state_set_current:
+ * @new_cs: the requested new #EglContextState
+ * @old_cs: return location to the context that was previously current
+ *
+ * Makes the @new_cs EGL context the current EGL rendering context of
+ * the calling thread, replacing the previously current context if
+ * there was one.
+ *
+ * If @old_cs is non %NULL, the previously current EGL context and
+ * surface are recorded.
+ *
+ * Return value: %TRUE on success
+ */
+static gboolean
+egl_context_state_set_current (EglContextState * new_cs,
+    EglContextState * old_cs)
+{
+  /* If display is NULL, this could be that new_cs was retrieved from
+     egl_context_state_get_current() 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->context && !new_cs->read_surface && !new_cs->draw_surface;
+
+  if (old_cs) {
+    if (old_cs == new_cs)
+      return TRUE;
+    egl_context_state_get_current (old_cs);
+    if (old_cs->display == new_cs->display &&
+        old_cs->context == new_cs->context &&
+        old_cs->read_surface == new_cs->read_surface &&
+        old_cs->draw_surface == new_cs->draw_surface)
+      return TRUE;
+  }
+  return eglMakeCurrent (new_cs->display, new_cs->draw_surface,
+      new_cs->read_surface, new_cs->context);
+}
+
+static gboolean
+egl_context_init (EglContext * ctx, EglDisplay * display, EglConfig * config,
+    EGLContext gl_parent_context)
+{
+  egl_object_replace (&ctx->display, display);
+  egl_object_replace (&ctx->config, config);
+
+  if (config)
+    eglBindAPI (config->gl_api);
+
+  if (!ensure_vtable (ctx))
+    return FALSE;
+  if (!ensure_context (ctx, gl_parent_context))
+    return FALSE;
+  return TRUE;
+}
+
+static void
+egl_context_finalize (EglContext * ctx)
+{
+  if (ctx->base.handle.p && !ctx->base.is_wrapped)
+    eglDestroyContext (ctx->display->base.handle.p, ctx->base.handle.p);
+  egl_object_replace (&ctx->read_surface, NULL);
+  egl_object_replace (&ctx->draw_surface, NULL);
+  egl_object_replace (&ctx->config, NULL);
+  egl_object_replace (&ctx->display, NULL);
+  egl_object_replace (&ctx->vtable, NULL);
+}
+
+typedef struct
+{
+  EglDisplay *display;
+  EglConfig *config;
+  EGLContext gl_parent_context;
+  EglContext *context;          /* result */
+} CreateContextArgs;
+
+static void
+do_egl_context_new (CreateContextArgs * args)
+{
+  EglContext *ctx;
+
+  ctx = egl_object_new0 (egl_context_class ());
+  if (!ctx || !egl_context_init (ctx, args->display, args->config,
+          args->gl_parent_context))
+    goto error;
+  args->context = ctx;
+  return;
+
+error:
+  egl_object_replace (&ctx, NULL);
+  args->context = NULL;
+}
+
+EglContext *
+egl_context_new (EglDisplay * display, EglConfig * config, EglContext * parent)
+{
+  CreateContextArgs args;
+
+  g_return_val_if_fail (display != NULL, NULL);
+  g_return_val_if_fail (config != NULL, NULL);
+
+  args.display = display;
+  args.config = config;
+  args.gl_parent_context = parent ? parent->base.handle.p : EGL_NO_CONTEXT;
+  if (!egl_display_run (display, (EglContextRunFunc) do_egl_context_new, &args))
+    return NULL;
+  return args.context;
+}
+
+EglContext *
+egl_context_new_wrapped (EglDisplay * display, EGLContext gl_context)
+{
+  CreateContextArgs args;
+  EglConfig *config;
+  gboolean success;
+
+  g_return_val_if_fail (display != NULL, NULL);
+  g_return_val_if_fail (gl_context != EGL_NO_CONTEXT, NULL);
+
+  config = egl_config_new_from_gl_context (display, gl_context);
+  if (!config)
+    return NULL;
+
+  args.display = display;
+  args.config = config;
+  args.gl_parent_context = gl_context;
+  success = egl_display_run (display, (EglContextRunFunc) do_egl_context_new,
+      &args);
+  egl_object_unref (config);
+  if (!success)
+    return NULL;
+  return args.context;
+}
+
+EglVTable *
+egl_context_get_vtable (EglContext * ctx, gboolean need_gl_symbols)
+{
+  g_return_val_if_fail (ctx != NULL, NULL);
+  g_return_val_if_fail (ctx->display->gl_thread == g_thread_self (), NULL);
+
+  if (!ensure_vtable (ctx))
+    return NULL;
+
+  if (need_gl_symbols && !(ctx->vtable->num_gl_symbols > 0 ||
+          egl_vtable_load_gl_symbols (ctx->vtable,
+              ctx->display->base.handle.p)))
+    return NULL;
+  return ctx->vtable;
+}
+
+void
+egl_context_set_surface (EglContext * ctx, EglSurface * surface)
+{
+  g_return_if_fail (ctx != NULL);
+  g_return_if_fail (surface != NULL);
+
+  egl_object_replace (&ctx->read_surface, surface);
+  egl_object_replace (&ctx->draw_surface, surface);
+}
+
+gboolean
+egl_context_set_current (EglContext * ctx, gboolean activate,
+    EglContextState * old_cs)
+{
+  EglContextState cs, *new_cs;
+
+  g_return_val_if_fail (ctx != NULL, FALSE);
+  g_return_val_if_fail (ctx->display->gl_thread == g_thread_self (), FALSE);
+
+  if (activate) {
+    new_cs = &cs;
+    new_cs->display = ctx->display->base.handle.p;
+    new_cs->context = ctx->base.handle.p;
+    new_cs->draw_surface = ctx->draw_surface ?
+        ctx->draw_surface->base.handle.p : EGL_NO_SURFACE;
+    new_cs->read_surface = ctx->read_surface ?
+        ctx->read_surface->base.handle.p : EGL_NO_SURFACE;
+  } else if (old_cs) {
+    new_cs = old_cs;
+    old_cs = NULL;
+  } else {
+    new_cs = &cs;
+    new_cs->display = ctx->display->base.handle.p;
+    new_cs->context = EGL_NO_CONTEXT;
+    new_cs->draw_surface = EGL_NO_SURFACE;
+    new_cs->read_surface = EGL_NO_SURFACE;
+    old_cs = NULL;
+  }
+
+  if (!egl_context_state_set_current (new_cs, old_cs))
+    return FALSE;
+  if (activate && !ensure_gl_scene (ctx))
+    return FALSE;
+  return TRUE;
+}
+
+gboolean
+egl_context_run (EglContext * ctx, EglContextRunFunc func, gpointer args)
+{
+  g_return_val_if_fail (ctx != NULL, FALSE);
+  g_return_val_if_fail (func != NULL, FALSE);
+
+  return egl_display_run (ctx->display, func, args);
+}
+
+/* ------------------------------------------------------------------------- */
+// EGL Program
+
+static GLuint
+egl_compile_shader (EglContext * ctx, GLenum type, const char *source)
+{
+  EglVTable *const vtable = egl_context_get_vtable (ctx, TRUE);
+  GLuint shader;
+  GLint status;
+  char log[BUFSIZ];
+  GLsizei log_length;
+
+  shader = vtable->glCreateShader (type);
+  vtable->glShaderSource (shader, 1, &source, NULL);
+  vtable->glCompileShader (shader);
+  vtable->glGetShaderiv (shader, GL_COMPILE_STATUS, &status);
+  if (!status) {
+    GST_ERROR ("failed to compile %s shader",
+        type == GL_FRAGMENT_SHADER ? "fragment" :
+        type == GL_VERTEX_SHADER ? "vertex" : "<unknown>");
+
+    vtable->glGetShaderInfoLog (shader, sizeof (log), &log_length, log);
+    GST_ERROR ("info log: %s", log);
+    return 0;
+  }
+  return shader;
+}
+
+static void
+egl_program_finalize (EglProgram * program)
+{
+  EglVTable *const vtable = program->vtable;
+
+  if (program->base.handle.u)
+    vtable->glDeleteProgram (program->base.handle.u);
+  if (program->frag_shader)
+    vtable->glDeleteShader (program->frag_shader);
+  if (program->vert_shader)
+    vtable->glDeleteShader (program->vert_shader);
+  egl_object_replace (&program->vtable, NULL);
+}
+
+static gboolean
+egl_program_init (EglProgram * program, EglContext * ctx,
+    const gchar * frag_shader_text, const gchar * vert_shader_text)
+{
+  EglVTable *const vtable = egl_context_get_vtable (ctx, TRUE);
+  GLuint prog_id;
+  char msg[BUFSIZ];
+  GLsizei msglen;
+  GLint status;
+
+  if (ctx->config->gles_version == 1)
+    goto error_unsupported_gles_version;
+
+  program->vtable = egl_object_ref (vtable);
+
+  program->frag_shader =
+      egl_compile_shader (ctx, GL_FRAGMENT_SHADER, frag_shader_text);
+  if (!program->frag_shader)
+    return FALSE;
+
+  program->vert_shader =
+      egl_compile_shader (ctx, GL_VERTEX_SHADER, vert_shader_text);
+  if (!program->vert_shader)
+    return FALSE;
+
+  prog_id = vtable->glCreateProgram ();
+  if (!prog_id)
+    return FALSE;
+  program->base.handle.u = prog_id;
+
+  vtable->glAttachShader (prog_id, program->frag_shader);
+  vtable->glAttachShader (prog_id, program->vert_shader);
+  vtable->glBindAttribLocation (prog_id, 0, "position");
+  vtable->glBindAttribLocation (prog_id, 1, "texcoord");
+  vtable->glLinkProgram (prog_id);
+
+  vtable->glGetProgramiv (prog_id, GL_LINK_STATUS, &status);
+  if (!status)
+    goto error_link_program;
+  return TRUE;
+
+  /* ERRORS */
+error_unsupported_gles_version:
+  GST_ERROR ("unsupported shader with OpenGL|ES version 1");
+  return FALSE;
+error_link_program:
+  vtable->glGetProgramInfoLog (prog_id, sizeof (msg), &msglen, msg);
+  GST_ERROR ("failed to link program: %s", msg);
+  return FALSE;
+}
+
+EglProgram *
+egl_program_new (EglContext * ctx, const gchar * frag_shader_text,
+    const gchar * vert_shader_text)
+{
+  EglProgram *program;
+
+  g_return_val_if_fail (ctx != NULL, NULL);
+  g_return_val_if_fail (frag_shader_text != NULL, NULL);
+  g_return_val_if_fail (vert_shader_text != NULL, NULL);
+
+  program = egl_object_new0 (egl_program_class ());
+  if (!program
+      || !egl_program_init (program, ctx, frag_shader_text, vert_shader_text))
+    goto error;
+  return program;
+
+error:
+  egl_object_replace (&program, NULL);
+  return NULL;
+}
+
+/* ------------------------------------------------------------------------- */
+// Misc utility functions
+
+void
+egl_matrix_set_identity (gfloat m[16])
+{
+#define MAT(m,r,c) (m)[(c) * 4 + (r)]
+  MAT(m,0,0) = 1.0; MAT(m,0,1) = 0.0; MAT(m,0,2) = 0.0; MAT(m,0,3) = 0.0;
+  MAT(m,1,0) = 0.0; MAT(m,1,1) = 1.0; MAT(m,1,2) = 0.0; MAT(m,1,3) = 0.0;
+  MAT(m,2,0) = 0.0; MAT(m,2,1) = 0.0; MAT(m,2,2) = 1.0; MAT(m,2,3) = 0.0;
+  MAT(m,3,0) = 0.0; MAT(m,3,1) = 0.0; MAT(m,3,2) = 0.0; MAT(m,3,3) = 1.0;
+#undef MAT
+}
+
+/**
+ * egl_create_texture:
+ * @ctx: the parent #EglContext object
+ * @target: the target to which the texture is bound
+ * @format: the format of the pixel data
+ * @width: the requested width, in pixels
+ * @height: the requested height, in pixels
+ *
+ * Creates a texture with the specified dimensions and @format. The
+ * internal format will be automatically derived from @format.
+ *
+ * Return value: the newly created texture name
+ */
+guint
+egl_create_texture (EglContext * ctx, guint target, guint format,
+    guint width, guint height)
+{
+  EglVTable *const vtable = egl_context_get_vtable (ctx, TRUE);
+  guint internal_format, texture, bytes_per_component;
+
+  internal_format = format;
+  switch (format) {
+    case GL_LUMINANCE:
+      bytes_per_component = 1;
+      break;
+    case GL_LUMINANCE_ALPHA:
+      bytes_per_component = 2;
+      break;
+    case GL_RGBA:
+    case GL_BGRA_EXT:
+      internal_format = GL_RGBA;
+      bytes_per_component = 4;
+      break;
+    default:
+      bytes_per_component = 0;
+      break;
+  }
+  g_assert (bytes_per_component > 0);
+
+  vtable->glGenTextures (1, &texture);
+  vtable->glBindTexture (target, texture);
+
+  if (width > 0 && height > 0)
+    vtable->glTexImage2D (target, 0, internal_format, width, height, 0,
+        format, GL_UNSIGNED_BYTE, NULL);
+
+  vtable->glTexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+  vtable->glTexParameteri (target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+  vtable->glTexParameteri (target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+  vtable->glTexParameteri (target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+  vtable->glPixelStorei (GL_UNPACK_ALIGNMENT, bytes_per_component);
+
+  return texture;
+}
+
+/**
+ * egl_destroy_texture:
+ * @ctx: the parent #EglContext object
+ * @texture: the texture name to delete
+ *
+ * Destroys the supplied @texture name.
+ */
+void
+egl_destroy_texture (EglContext * ctx, guint texture)
+{
+  EglVTable *const vtable = egl_context_get_vtable (ctx, TRUE);
+
+  vtable->glDeleteTextures (1, &texture);
+}
diff --git a/gst-libs/gst/vaapi/gstvaapiutils_egl.h b/gst-libs/gst/vaapi/gstvaapiutils_egl.h
new file mode 100644 (file)
index 0000000..d1fd28d
--- /dev/null
@@ -0,0 +1,238 @@
+/*
+ * gstvaapiutils_egl.h - EGL utilities
+ *
+ * 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
+ */
+
+#ifndef GST_VAAPI_UTILS_EGL_H
+#define GST_VAAPI_UTILS_EGL_H
+
+#include <gmodule.h>
+#include <gst/gstinfo.h>
+#include <gst/video/video-format.h>
+#include "egl_compat.h"
+#include "gstvaapiminiobject.h"
+
+GST_DEBUG_CATEGORY_EXTERN (gst_debug_vaapidisplay_egl);
+#define GST_CAT_DEFAULT gst_debug_vaapidisplay_egl
+
+typedef union egl_handle_s                      EglHandle;
+typedef struct egl_object_s                     EglObject;
+typedef struct egl_object_class_s               EglObjectClass;
+typedef struct egl_vtable_s                     EglVTable;
+typedef struct egl_display_s                    EglDisplay;
+typedef struct egl_config_s                     EglConfig;
+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;
+
+#define EGL_PROTO_BEGIN(NAME, TYPE, EXTENSION) \
+  typedef TYPE (*GL_PROTO_GEN_CONCAT3(Egl,NAME,Proc))
+#define EGL_PROTO_END()                         ;
+#define GL_PROTO_BEGIN(NAME, TYPE, EXTENSION) \
+  typedef TYPE (*GL_PROTO_GEN_CONCAT3(Gl,NAME,Proc))
+#define GL_PROTO_ARG_LIST(...)                  (__VA_ARGS__)
+#define GL_PROTO_ARG(NAME, TYPE)                TYPE NAME
+#define GL_PROTO_END()                          ;
+#include "egl_vtable.h"
+
+union egl_handle_s
+{
+  gpointer p;
+  guintptr u;
+  gintptr i;
+};
+
+struct egl_object_s
+{
+  /*< private >*/
+  GstVaapiMiniObject parent_instance;
+
+  EglHandle handle;
+  guint is_wrapped:1;
+  guint is_valid:1;
+};
+
+struct egl_object_class_s
+{
+  /*< private >*/
+  GstVaapiMiniObjectClass parent_class;
+};
+
+struct egl_vtable_s
+{
+  EglObject base;
+
+  gchar **egl_extensions;
+  guint num_egl_symbols;
+  gchar **gl_extensions;
+  guint num_gl_symbols;
+  guint gles_version;
+
+#define EGL_PROTO_BEGIN(NAME, TYPE, EXTENSION) \
+  GL_PROTO_BEGIN_I(NAME, TYPE, EXTENSION, Egl, egl)
+#define GL_PROTO_BEGIN(NAME, TYPE, EXTENSION) \
+  GL_PROTO_BEGIN_I(NAME, TYPE, EXTENSION,  Gl,  gl)
+#define GL_PROTO_BEGIN_I(NAME, TYPE, EXTENSION, Prefix, prefix) \
+  GL_PROTO_GEN_CONCAT3(Prefix,NAME,Proc) GL_PROTO_GEN_CONCAT(prefix,NAME);
+#include "egl_vtable.h"
+
+#define EGL_DEFINE_EXTENSION(EXTENSION) \
+  GL_DEFINE_EXTENSION_I(EXTENSION, EGL)
+#define GL_DEFINE_EXTENSION(EXTENSION) \
+  GL_DEFINE_EXTENSION_I(EXTENSION,  GL)
+#define GL_DEFINE_EXTENSION_I(EXTENSION, PREFIX) \
+  guint GL_PROTO_GEN_CONCAT4(has_,PREFIX,_,EXTENSION);
+#include "egl_vtable.h"
+};
+
+struct egl_display_s
+{
+  EglObject base;
+
+  gchar *gl_vendor_string;
+  gchar *gl_version_string;
+  gchar *gl_apis_string;
+  guint gl_apis;                /* EGL_*_BIT mask */
+
+  GMutex mutex;
+  GThread *gl_thread;
+  GCond gl_thread_ready;
+  volatile gboolean gl_thread_cancel;
+  GAsyncQueue *gl_queue;
+};
+
+struct egl_config_s
+{
+  EglObject base;
+
+  EglDisplay *display;
+  guint gl_api;                 /* EGL_*_API value */
+  guint gles_version;
+  gint config_id;
+  gint visual_id;
+};
+
+typedef void (*EglContextRunFunc) (gpointer args);
+
+struct egl_context_state_s
+{
+  EGLDisplay display;
+  EGLContext context;
+  EGLSurface read_surface;
+  EGLSurface draw_surface;
+};
+
+struct egl_context_s
+{
+  EglObject base;
+
+  EglVTable *vtable;
+  EglDisplay *display;
+  EglConfig *config;
+  EglSurface *read_surface;
+  EglSurface *draw_surface;
+};
+
+struct egl_surface_s
+{
+  EglObject base;
+
+  EglDisplay *display;
+};
+
+/* Defined to the maximum number of uniforms for a shader program */
+#define EGL_MAX_UNIFORMS 16
+
+struct egl_program_s
+{
+  EglObject base;
+
+  EglVTable *vtable;
+  guint frag_shader;
+  guint vert_shader;
+  gint uniforms[EGL_MAX_UNIFORMS];
+};
+
+#define egl_object_ref(obj) \
+  ((gpointer)gst_vaapi_mini_object_ref ((GstVaapiMiniObject *)(obj)))
+#define egl_object_unref(obj) \
+  gst_vaapi_mini_object_unref ((GstVaapiMiniObject *)(obj))
+#define egl_object_replace(old_obj_ptr, new_obj) \
+  gst_vaapi_mini_object_replace ((GstVaapiMiniObject **)(old_obj_ptr), \
+      (GstVaapiMiniObject *)(new_obj))
+
+G_GNUC_INTERNAL
+EglDisplay *
+egl_display_new (gpointer native_display);
+
+G_GNUC_INTERNAL
+EglDisplay *
+egl_display_new_wrapped (EGLDisplay gl_display);
+
+G_GNUC_INTERNAL
+EglConfig *
+egl_config_new (EglDisplay * display, guint gles_version,
+    GstVideoFormat format);
+
+G_GNUC_INTERNAL
+EglConfig *
+egl_config_new_with_attribs (EglDisplay * display, const EGLint * attribs);
+
+G_GNUC_INTERNAL
+EglContext *
+egl_context_new (EglDisplay * display, EglConfig * config, EglContext * parent);
+
+G_GNUC_INTERNAL
+EglContext *
+egl_context_new_wrapped (EglDisplay * display, EGLContext gl_context);
+
+G_GNUC_INTERNAL
+EglVTable *
+egl_context_get_vtable (EglContext * ctx, gboolean need_gl_symbols);
+
+G_GNUC_INTERNAL
+gboolean
+egl_context_set_current (EglContext * ctx, gboolean activate,
+    EglContextState * old_cs);
+
+G_GNUC_INTERNAL
+gboolean
+egl_context_run (EglContext * ctx, EglContextRunFunc func, gpointer args);
+
+G_GNUC_INTERNAL
+EglProgram *
+egl_program_new (EglContext * ctx, const gchar * frag_shader_text,
+    const gchar * vert_shader_text);
+
+G_GNUC_INTERNAL
+guint
+egl_create_texture (EglContext * ctx, guint target, guint format,
+    guint width, guint height);
+
+G_GNUC_INTERNAL
+void
+egl_destroy_texture (EglContext * ctx, guint texture);
+
+G_GNUC_INTERNAL
+void
+egl_matrix_set_identity (gfloat m[16]);
+
+#endif /* GST_VAAPI_UTILS_EGL_H */
diff --git a/gst-libs/gst/vaapi/ogl_compat.h b/gst-libs/gst/vaapi/ogl_compat.h
new file mode 100644 (file)
index 0000000..2fa40e7
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * ogl_compat.h - OpenGL compatiliby layer
+ *
+ * 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
+ */
+
+#ifndef OGL_COMPAT_H
+#define OGL_COMPAT_H
+
+typedef void                    GLvoid;
+typedef char                    GLchar;
+typedef unsigned char           GLubyte;
+typedef unsigned char           GLboolean;
+typedef int                     GLint;
+typedef unsigned int            GLuint;
+typedef int                     GLsizei;
+typedef float                   GLfloat;
+typedef double                  GLdouble;
+typedef GLuint                  GLenum;
+typedef GLuint                  GLbitfield;
+typedef GLfloat                 GLclampf;
+
+#define GL_VENDOR               0x1F00
+#define GL_RENDERER             0x1F01
+#define GL_VERSION              0x1F02
+#define GL_EXTENSIONS           0x1F03
+#define GL_NEAREST              0x2600
+#define GL_LINEAR               0x2601
+
+#define GL_DEPTH_BUFFER_BIT     0x00000100
+#define GL_COLOR_BUFFER_BIT     0x00004000
+#define GL_FALSE                0
+#define GL_TRUE                 1
+#define GL_NONE                 0
+
+#define GL_BLEND                0x0BE2
+#define GL_DEPTH_TEST           0x0B71
+
+#define GL_TEXTURE0             0x84C0
+#define GL_TEXTURE1             0x84C1
+#define GL_TEXTURE2             0x84C2
+#define GL_TEXTURE3             0x84C3
+#define GL_TEXTURE_2D           0x0DE1
+#define GL_TEXTURE_EXTERNAL_OES 0x8D65
+#define GL_TEXTURE_MAG_FILTER   0x2800
+#define GL_TEXTURE_MIN_FILTER   0x2801
+#define GL_TEXTURE_WRAP_S       0x2802
+#define GL_TEXTURE_WRAP_T       0x2803
+
+#define GL_UNPACK_ALIGNMENT     0x0cf5
+
+#define GL_TRIANGLE_FAN         0x0006
+
+#define GL_BYTE                 0x1400
+#define GL_UNSIGNED_BYTE        0x1401
+#define GL_SHORT                0x1402
+#define GL_UNSIGNED_SHORT       0x1403
+#define GL_INT                  0x1404
+#define GL_UNSIGNED_INT         0x1405
+#define GL_FLOAT                0x1406
+
+#define GL_ALPHA                0x1906
+#define GL_RGB                  0x1907
+#define GL_RGBA                 0x1908
+#define GL_LUMINANCE            0x1909
+#define GL_LUMINANCE_ALPHA      0x190A
+
+#define GL_REPEAT               0x2901
+#define GL_CLAMP_TO_EDGE        0x812F
+
+#define GL_VERTEX_ARRAY         0x8074
+#define GL_TEXTURE_COORD_ARRAY  0x8078
+
+#define GL_FRAGMENT_SHADER      0x8B30
+#define GL_VERTEX_SHADER        0x8B31
+#define GL_COMPILE_STATUS       0x8B81
+#define GL_LINK_STATUS          0x8B82
+#define GL_INFO_LOG_LENGTH      0x8B84
+
+#define GL_BGRA_EXT             0x80e1
+#ifndef GL_R8
+#define GL_R8                   GL_R8_EXT
+#endif
+#ifndef GL_RG8
+#define GL_RG8                  GL_RG8_EXT
+#endif
+
+#endif /* OGL_COMPAT_H */