VA/EGL interfaces
authorXiang, Haihao <haihao.xiang@intel.com>
Thu, 10 Nov 2011 02:47:03 +0000 (10:47 +0800)
committerXiang, Haihao <haihao.xiang@intel.com>
Wed, 14 Dec 2011 00:27:03 +0000 (08:27 +0800)
Signed-off-by: Xiang, Haihao <haihao.xiang@intel.com>
va/Makefile.am
va/egl/Makefile.am
va/egl/va_backend_egl.h
va/egl/va_egl.c
va/egl/va_egl.h
va/egl/va_egl_impl.c [new file with mode: 0644]
va/egl/va_egl_impl.h [new file with mode: 0644]
va/egl/va_egl_private.h [new file with mode: 0644]
va/va_backend.h

index 16a1e8f..bc70435 100644 (file)
@@ -92,7 +92,7 @@ libva_egl_la_SOURCES          =
 libva_egl_la_LDFLAGS           = $(LDADD)
 libva_egl_la_DEPENDENCIES      = $(libvacorelib) egl/libva_egl.la libva-x11.la
 libva_egl_la_LIBADD            = $(libvacorelib) egl/libva_egl.la libva-x11.la \
-       $(GL_DEPS_LIBS) -ldl
+       $(EGL_DEPS_LIBS) -ldl
 endif
 
 if BUILD_DUMMY_BACKEND
index c02daa7..74f3c70 100644 (file)
 # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
-INCLUDES = -DLINUX -I$(top_srcdir) -I$(top_srcdir)/va -I$(top_srcdir)/va/x11
+INCLUDES = -DLINUX -I$(top_srcdir) -I$(top_srcdir)/va
 
 source_c = \
-       va_egl.c                
+       va_egl.c                \
+       va_egl_impl.c           \
+       $(NULL)
 
 source_h = \
        va_egl.h                \
-       va_backend_egl.h
+       va_backend_egl.h        \
+       $(NULL)
 
-source_h_priv = 
+source_h_priv = \
+       va_egl_impl.h           \
+       va_egl_private.h        \
+       $(NULL) 
 
 noinst_LTLIBRARIES      = libva_egl.la
 libva_eglincludedir     = ${includedir}/va
index 925d933..9dae84f 100644 (file)
@@ -36,6 +36,38 @@ struct VADriverVTableEGL {
         void **buffer
     );
     /* TBD: more APIs for EGL */
+    /* Optional: create a surface used for display to OpenGL */
+    VAStatus (*vaCreateSurfaceEGL)(
+        VADriverContextP ctx,
+        GLenum target,
+        GLuint texture,
+        unsigned int width,
+        unsigned int height,
+        VASurfaceEGL *egl_surface
+    );
+
+    /* Optional: destroy a VA/EGL surface */
+    VAStatus (*vaDestroySurfaceEGL)(
+        VADriverContextP ctx,
+        VASurfaceEGL egl_surface
+    );
+
+    VAStatus (*vaAssociateSurfaceEGL)(
+        VADriverContextP ctx,
+        VASurfaceEGL egl_surface,
+        VASurfaceID surface,
+        unsigned int flags
+    );
+
+    VAStatus (*vaUpdateAssociatedSurfaceEGL)(
+        VADriverContextP ctx,
+        VASurfaceEGL egl_surface
+    );
+
+    VAStatus (*vaDeassociateSurfaceEGL)(
+        VADriverContextP ctx,
+        VASurfaceEGL egl_surface
+    );
 };
 
 #endif /* VA_BACKEND_EGL_H */
index 36e5504..6caf4f8 100644 (file)
  *
  * Bellow API vaGetEGLClientBufferFromSurface is for this purpose
  */
-
-#include "va.h"
-#include "va_backend_egl.h"
-#include "va_egl.h"
+#include "va_egl_private.h"
+#include "va_egl_impl.h"
 
 #define CTX(dpy) (((VADisplayContextP)dpy)->pDriverContext)
 #define CHECK_DISPLAY(dpy) if( !vaDisplayIsValid(dpy) ) { return VA_STATUS_ERROR_INVALID_DISPLAY; }
 
+#define INIT_CONTEXT(ctx, dpy) do {                             \
+        if (!vaDisplayIsValid(dpy))                             \
+            return VA_STATUS_ERROR_INVALID_DISPLAY;             \
+                                                                \
+        ctx = ((VADisplayContextP)(dpy))->pDriverContext;       \
+        if (!(ctx))                                             \
+            return VA_STATUS_ERROR_INVALID_DISPLAY;             \
+                                                                \
+        status = va_egl_init_context(dpy);                      \
+        if (status != VA_STATUS_SUCCESS)                        \
+            return status;                                      \
+    } while (0)
+
+#define INVOKE(ctx, func, args) do {                            \
+        VADriverVTablePrivEGLP vtable;                          \
+        vtable = &VA_DRIVER_CONTEXT_EGL(ctx)->vtable;           \
+        if (!vtable->va##func##EGL)                             \
+            return VA_STATUS_ERROR_UNIMPLEMENTED;               \
+        status = vtable->va##func##EGL args;                    \
+    } while (0)
+
+
 VAStatus vaGetEGLClientBufferFromSurface (
     VADisplay dpy,
     VASurfaceID surface,
@@ -79,4 +99,154 @@ VAStatus vaGetEGLClientBufferFromSurface (
       return VA_STATUS_ERROR_UNIMPLEMENTED;
 }
   
+// Destroy VA/EGL display context
+static void va_DisplayContextDestroy(VADisplayContextP pDisplayContext)
+{
+    VADisplayContextEGLP pDisplayContextEGL;
+    VADriverContextP     pDriverContext;
+    VADriverContextEGLP  pDriverContextEGL;
+
+    if (!pDisplayContext)
+        return;
+
+    pDriverContext     = pDisplayContext->pDriverContext;
+    pDriverContextEGL  = pDriverContext->egl;
+    if (pDriverContextEGL) {
+        free(pDriverContextEGL);
+        pDriverContext->egl = NULL;
+    }
+
+    pDisplayContextEGL = pDisplayContext->opaque;
+    if (pDisplayContextEGL) {
+        vaDestroyFunc vaDestroy = pDisplayContextEGL->vaDestroy;
+        free(pDisplayContextEGL);
+        pDisplayContext->opaque = NULL;
+        if (vaDestroy)
+            vaDestroy(pDisplayContext);
+    }
+}
+
+// Return a suitable VADisplay for VA API
+VADisplay vaGetDisplayEGL(VANativeDisplay native_dpy,
+                          EGLDisplay egl_dpy)
+{
+    VADisplay            dpy                = NULL;
+    VADisplayContextP    pDisplayContext    = NULL;
+    VADisplayContextEGLP pDisplayContextEGL = NULL;
+    VADriverContextP     pDriverContext;
+    VADriverContextEGLP  pDriverContextEGL  = NULL;
+
+    dpy = vaGetDisplay(native_dpy);
+
+    if (!dpy)
+        return NULL;
+
+    if (egl_dpy == EGL_NO_DISPLAY)
+        goto error;
+
+    pDisplayContext = (VADisplayContextP)dpy;
+    pDriverContext  = pDisplayContext->pDriverContext;
+
+    pDisplayContextEGL = calloc(1, sizeof(*pDisplayContextEGL));
+    if (!pDisplayContextEGL)
+        goto error;
+
+    pDriverContextEGL = calloc(1, sizeof(*pDriverContextEGL));
+    if (!pDriverContextEGL)
+        goto error;
+
+    pDisplayContextEGL->vaDestroy = pDisplayContext->vaDestroy;
+    pDisplayContext->vaDestroy = va_DisplayContextDestroy;
+    pDisplayContext->opaque = pDisplayContextEGL;
+    pDriverContextEGL->egl_display = egl_dpy;
+    pDriverContext->egl = pDriverContextEGL;
+    return dpy;
+
+error:
+    free(pDriverContextEGL);
+    free(pDisplayContextEGL);
+    pDisplayContext->vaDestroy(pDisplayContext);
+    return NULL;
+}
+
+// Create a surface used for display to OpenGL
+VAStatus vaCreateSurfaceEGL(
+    VADisplay dpy,
+    GLenum target,
+    GLuint texture,
+    unsigned int width,
+    unsigned int height,
+    VASurfaceEGL *gl_surface
+)
+{
+    VADriverContextP ctx;
+    VAStatus status;
+
+    if (target != GL_TEXTURE_2D)
+        return VA_STATUS_ERROR_INVALID_PARAMETER;
+
+    INIT_CONTEXT(ctx, dpy);
+
+    INVOKE(ctx, CreateSurface, (dpy, target, texture, width, height, gl_surface));
+    return status;
+}
+
+// Destroy a VA/EGL surface
+VAStatus vaDestroySurfaceEGL(
+    VADisplay dpy,
+    VASurfaceEGL egl_surface
+)
+{
+    VADriverContextP ctx;
+    VAStatus status;
+
+    INIT_CONTEXT(ctx, dpy);
+
+    INVOKE(ctx, DestroySurface, (dpy, egl_surface));
+    return status;
+}
+
+VAStatus vaAssociateSurfaceEGL(
+    VADisplay dpy,
+    VASurfaceEGL egl_surface,
+    VASurfaceID surface,
+    unsigned int flags
+)
+{
+    VADriverContextP ctx;
+    VAStatus status;
+
+    INIT_CONTEXT(ctx, dpy);
+
+    INVOKE(ctx, AssociateSurface, (dpy, egl_surface, surface, flags));
+    return status;
+}
+
+VAStatus vaUpdateAssociatedSurfaceEGL(
+    VADisplay dpy,
+    VASurfaceEGL egl_surface
+)
+{
+    VADriverContextP ctx;
+    VAStatus status;
+
+    INIT_CONTEXT(ctx, dpy);
+
+    INVOKE(ctx, UpdateAssociatedSurface, (dpy, egl_surface));
+    return status;
+}
+
+VAStatus vaDeassociateSurfaceEGL(
+    VADisplay dpy,
+    VASurfaceEGL egl_surface
+)
+{
+    VADriverContextP ctx;
+    VAStatus status;
+
+    INIT_CONTEXT(ctx, dpy);
+
+    INVOKE(ctx, DeassociateSurface, (dpy, egl_surface));
+    return status;
+}
   
index 4243d0b..8f9c840 100644 (file)
@@ -2,12 +2,16 @@
 #define _VA_EGL_H_
 
 #include <va/va.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-typedef void*   EGLClientBuffer;
+typedef void *VASurfaceEGL;
 
 /*This function is used to get EGLClientBuffer
  * (lower 16bits is buffer index, upper 16bits 
@@ -20,6 +24,96 @@ VAStatus vaGetEGLClientBufferFromSurface (
     EGLClientBuffer *buffer     /* out*/
 );
 
+/**
+ * Return a suitable VADisplay for VA API
+ *
+ * @param[in] native_dpy the native display
+ * @param[in] egl_dpy the EGL display
+ * @return a VADisplay
+ */
+VADisplay vaGetDisplayEGL(
+    VANativeDisplay native_dpy,
+    EGLDisplay egl_dpy
+);
+
+/**
+ * Create a surface used for display to OpenGL ES
+ *
+ * The application shall maintain the live EGL context itself.
+ *
+ * @param[in]  dpy        the VA display
+ * @param[in]  target     the GL target to which the texture needs to be bound, must be GL_TEXTURE_2D
+ * @param[in]  texture    the GL texture
+ * @param[in]  width      the surface width
+ * @param[in]  height     the surface height
+ * @param[out] gl_surface the VA/EGL surface
+ * @return VA_STATUS_SUCCESS if successful
+ */
+VAStatus vaCreateSurfaceEGL(
+    VADisplay dpy,
+    GLenum target,
+    GLuint texture,
+    unsigned int width,
+    unsigned int height,
+    VASurfaceEGL *gl_surface
+);
+
+/**
+ * Destroy a VA/EGL surface
+ *
+ * The application shall maintain the live EGL context itself.
+ *
+ * @param[in]  dpy        the VA display
+ * @param[in]  gl_surface the VA surface
+ * @return VA_STATUS_SUCCESS if successful
+ */
+VAStatus vaDestroySurfaceEGL(
+    VADisplay dpy,
+    VASurfaceEGL gl_surface
+);
+
+/**
+ * Associate a EGLClientBuffer with a VA surface
+ *
+ * @param[in]  dpy         the VA display
+ * @param[in]  egl_surface the VA/EGL destination surface
+ * @param[in]  surface     the VA surface
+ * @param[in]  flags       the flags to PutSurface
+ * @return VA_STATUS_SUCCESS if successful
+ */
+VAStatus vaAssociateSurfaceEGL(
+    VADisplay dpy,
+    VASurfaceEGL egl_surface,
+    VASurfaceID surface,
+    unsigned int flags
+);
+
+/**
+ * Update the content of a VA/EGL surface
+ *
+ * Changes to VA surface are committed to VA/EGL surface at this point.
+ *
+ * @param[in]  dpy         the VA display
+ * @param[in]  egl_surface the VA/EGL destination surface
+ * @return VA_STATUS_SUCCESS if successful
+ */
+VAStatus vaUpdateAssociatedSurfaceEGL(
+    VADisplay dpy,
+    VASurfaceEGL egl_surface
+);
+
+/**
+ * Deassociate a EGLClientBuffer
+ *
+ * @param[in]  dpy         the VA display
+ * @param[in]  egl_surface the VA/EGL destination surface
+ * @return VA_STATUS_SUCCESS if successful
+ */
+VAStatus vaDeassociateSurfaceEGL(
+    VADisplay dpy,
+    VASurfaceEGL egl_surface
+);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/va/egl/va_egl_impl.c b/va/egl/va_egl_impl.c
new file mode 100644 (file)
index 0000000..b47d266
--- /dev/null
@@ -0,0 +1,521 @@
+#define _GNU_SOURCE 1
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <assert.h>
+#include <dlfcn.h>
+
+#include "va_egl_private.h"
+#include "va_egl_impl.h"
+
+// Returns the OpenGL ES VTable
+static inline VAOpenGLESVTableP 
+gles_get_vtable(VADriverContextP ctx)
+{
+    return &VA_DRIVER_CONTEXT_EGL(ctx)->gles_vtable;
+}
+
+// Lookup for a EGL function
+typedef void (*EGLFuncPtr)(void);
+typedef EGLFuncPtr (*EGLGetProcAddressProc)(const char *);
+
+static EGLFuncPtr 
+get_proc_address_default(const char *name)
+{
+    return NULL;
+}
+
+static EGLGetProcAddressProc 
+get_proc_address_func(void)
+{
+    EGLGetProcAddressProc get_proc_func;
+
+    dlerror();
+    get_proc_func = (EGLGetProcAddressProc)
+        dlsym(RTLD_DEFAULT, "eglGetProcAddress");
+
+    if (!dlerror())
+        return get_proc_func;
+
+    return get_proc_address_default;
+}
+
+static inline EGLFuncPtr 
+get_proc_address(const char *name)
+{
+    static EGLGetProcAddressProc get_proc_func = NULL;
+
+    get_proc_func = get_proc_address_func();
+
+    return get_proc_func(name);
+}
+
+// Check for GLES extensions (TFP, FBO)
+static int 
+check_extension(const char *name, const char *exts)
+{
+    const char *end;
+    int name_len, n;
+
+    if (!name || !exts)
+        return 0;
+
+    end = exts + strlen(exts);
+    name_len = strlen(name);
+
+    while (exts < end) {
+        n = strcspn(exts, " ");
+
+        if (n == name_len && strncmp(name, exts, n) == 0)
+            return 1;
+
+        exts += (n + 1);
+    }
+
+    return 0;
+}
+
+static int 
+check_extensions(VADriverContextP ctx, EGLDisplay egl_display)
+{
+    const char *exts;
+
+    exts = (const char *)eglQueryString(egl_display, EGL_EXTENSIONS);
+
+    if (!check_extension("EGL_KHR_image_pixmap", exts))
+        return 0;
+
+    exts = (const char *)glGetString(GL_EXTENSIONS);
+
+    if (!check_extension("GL_OES_EGL_image", exts))
+        return 0;
+
+#if 0
+    if (!check_extension("GL_OES_texture_npot", exts))
+        return 0;
+#endif
+
+    return 1;
+}
+
+static int 
+init_extensions(VADriverContextP ctx)
+{
+    VAOpenGLESVTableP pOpenGLESVTable = gles_get_vtable(ctx);
+
+    /* EGL_KHR_image_pixmap */
+    pOpenGLESVTable->egl_create_image_khr = 
+        (PFNEGLCREATEIMAGEKHRPROC)get_proc_address("eglCreateImageKHR");
+    pOpenGLESVTable->egl_destroy_image_khr =
+        (PFNEGLDESTROYIMAGEKHRPROC)get_proc_address("eglDestroyImageKHR");
+
+    /* GL_OES_EGL_image */
+    pOpenGLESVTable->gles_egl_image_target_texture_2d =
+        (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)get_proc_address("glEGLImageTargetTexture2DOES");
+
+    return 1;
+}
+
+/* ========================================================================= */
+/* === VA/EGL implementation from the driver (fordward calls)            === */
+/* ========================================================================= */
+#ifdef INVOKE
+#undef INVOKE
+#endif
+
+#define INVOKE(ctx, func, args) do {                    \
+        VADriverVTableEGLP vtable = (ctx)->vtable_egl;  \
+        if (!vtable->va##func##EGL)                     \
+            return VA_STATUS_ERROR_UNIMPLEMENTED;       \
+                                                        \
+        VAStatus status = vtable->va##func##EGL args;   \
+        if (status != VA_STATUS_SUCCESS)                \
+            return status;                              \
+    } while (0)
+
+static VAStatus
+vaCreateSurfaceEGL_impl_driver(VADisplay dpy,
+                               GLenum target,
+                               GLuint texture,
+                               unsigned int width,
+                               unsigned int height,
+                               VASurfaceEGL *egl_surface)
+{
+    VADriverContextP ctx = ((VADisplayContextP)(dpy))->pDriverContext;
+    INVOKE(ctx, CreateSurface, (ctx, target, texture, width, height, egl_surface));
+    return VA_STATUS_SUCCESS;
+}
+
+static VAStatus
+vaDestroySurfaceEGL_impl_driver(VADisplay dpy, VASurfaceEGL egl_surface)
+{
+    VADriverContextP ctx = ((VADisplayContextP)(dpy))->pDriverContext;
+    INVOKE(ctx, DestroySurface, (ctx, egl_surface));
+    return VA_STATUS_SUCCESS;
+}
+
+static VAStatus
+vaAssociateSurfaceEGL_impl_driver(VADisplay dpy,
+                                  VASurfaceEGL egl_surface,
+                                  VASurfaceID surface,
+                                  unsigned int flags)
+{
+    VADriverContextP ctx = ((VADisplayContextP)(dpy))->pDriverContext;
+    INVOKE(ctx, AssociateSurface, (ctx, egl_surface, surface, flags));
+
+    return VA_STATUS_SUCCESS;
+}
+
+static VAStatus
+vaUpdateAssociatedSurfaceEGL_impl_driver(VADisplay dpy,
+                                         VASurfaceEGL egl_surface)
+{
+    VADriverContextP ctx = ((VADisplayContextP)(dpy))->pDriverContext;
+    INVOKE(ctx, UpdateAssociatedSurface, (ctx, egl_surface));
+
+    return VA_STATUS_SUCCESS;
+}
+
+static VAStatus
+vaDeassociateSurfaceEGL_impl_driver(VADisplay dpy,
+                                    VASurfaceEGL egl_surface)
+{
+    VADriverContextP ctx = ((VADisplayContextP)(dpy))->pDriverContext;
+    INVOKE(ctx, DeassociateSurface, (ctx, egl_surface));
+
+    return VA_STATUS_SUCCESS;
+}
+
+#undef INVOKE
+
+/* ========================================================================= */
+/* === VA/EGL helpers                                                    === */
+/* ========================================================================= */
+/** Unique VASurfaceImplEGL identifier */
+#define VA_SURFACE_IMPL_EGL_MAGIC VA_FOURCC('V','I','E','L')
+
+struct VASurfaceImplEGL {
+    uint32_t            magic;      ///< Magic number identifying a VASurfaceImplEGL
+    VASurfaceID         surface;    ///< Associated VA surface
+    GLenum              target;     ///< GL target to which the texture is bound
+    GLuint              texture;    ///< GL texture
+    unsigned int        width;
+    unsigned int        height;
+    void                *pixmap;
+    EGLImageKHR         img_khr;
+    unsigned int        flags;
+};
+
+static void *
+create_native_pixmap(VADisplay dpy, unsigned int width, unsigned int height)
+{
+    VADisplayContextP pDisplayContext = (VADisplayContextP)dpy;
+    VAStatus status;
+    void *native_pixmap = NULL;
+
+    status = pDisplayContext->vaCreateNativePixmap(pDisplayContext, width, height, &native_pixmap);
+
+    if (status != VA_STATUS_SUCCESS)
+        native_pixmap = NULL;
+
+    return native_pixmap;
+}
+
+static void
+destroy_native_pixmap(VADisplay dpy, void *native_pixmap)
+{
+    VADisplayContextP pDisplayContext = (VADisplayContextP)dpy;
+    
+    pDisplayContext->vaFreeNativePixmap(pDisplayContext, native_pixmap);
+}
+
+// Destroy VA/EGL surface
+static void
+destroy_surface(VADisplay dpy, VASurfaceImplEGLP pSurfaceImplEGL)
+{
+    VADriverContextP ctx = ((VADisplayContextP)(dpy))->pDriverContext;
+    VADriverContextEGLP egl_ctx = VA_DRIVER_CONTEXT_EGL(ctx);
+    VAOpenGLESVTableP const pOpenGLESVTable = gles_get_vtable(ctx);
+
+    if (pSurfaceImplEGL->img_khr) {
+        pOpenGLESVTable->egl_destroy_image_khr(egl_ctx->egl_display,
+                                               pSurfaceImplEGL->img_khr);
+        pSurfaceImplEGL->img_khr = EGL_NO_IMAGE_KHR;
+    }
+
+    if (pSurfaceImplEGL->pixmap) {
+        destroy_native_pixmap(dpy, pSurfaceImplEGL->pixmap);
+        pSurfaceImplEGL->pixmap = 0;
+    }
+
+    free(pSurfaceImplEGL);
+}
+
+// Create VA/EGL surface
+static VASurfaceImplEGLP
+create_surface(VADisplay dpy,
+               GLenum target,
+               GLuint texture,
+               unsigned int width,
+               unsigned int height)
+{
+    VADriverContextP ctx = ((VADisplayContextP)(dpy))->pDriverContext;
+    VADriverContextEGLP egl_ctx = VA_DRIVER_CONTEXT_EGL(ctx);
+    VAOpenGLESVTableP const pOpenGLESVTable = gles_get_vtable(ctx);
+    VASurfaceImplEGLP pSurfaceImplEGL = NULL;
+    int is_error = 1;
+    const EGLint img_attribs[] = {
+        EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
+        EGL_NONE
+    };
+
+    pSurfaceImplEGL = calloc(1, sizeof(*pSurfaceImplEGL));
+
+    if (!pSurfaceImplEGL)
+        goto end;
+
+    pSurfaceImplEGL->magic = VA_SURFACE_IMPL_EGL_MAGIC;
+    pSurfaceImplEGL->surface = VA_INVALID_SURFACE;
+    pSurfaceImplEGL->target = target;
+    pSurfaceImplEGL->texture = texture;
+    pSurfaceImplEGL->width = width;
+    pSurfaceImplEGL->height = height;
+    pSurfaceImplEGL->pixmap = create_native_pixmap(dpy, width, height);
+
+    if (!pSurfaceImplEGL->pixmap)
+        goto end;
+
+    pSurfaceImplEGL->img_khr = pOpenGLESVTable->egl_create_image_khr(egl_ctx->egl_display,
+                                                                 EGL_NO_CONTEXT,
+                                                                 EGL_NATIVE_PIXMAP_KHR,
+                                                                 (EGLClientBuffer)pSurfaceImplEGL->pixmap,
+                                                                 img_attribs);
+    
+    if (!pSurfaceImplEGL->img_khr)
+        goto end;
+
+    is_error = 0;
+
+end:
+    if (is_error && pSurfaceImplEGL) {
+        destroy_surface(dpy, pSurfaceImplEGL);
+        pSurfaceImplEGL = NULL;
+    }
+
+    return pSurfaceImplEGL;
+}
+
+// Check VASurfaceImplEGL is valid
+static inline int check_surface(VASurfaceImplEGLP pSurfaceImplEGL)
+{
+    return pSurfaceImplEGL && pSurfaceImplEGL->magic == VA_SURFACE_IMPL_EGL_MAGIC;
+}
+
+static inline VAStatus
+deassociate_surface(VADriverContextP ctx, VASurfaceImplEGLP pSurfaceImplEGL)
+{
+    pSurfaceImplEGL->surface = VA_INVALID_SURFACE;
+
+    return VA_STATUS_SUCCESS;
+}
+
+static VAStatus
+associate_surface(VADriverContextP ctx,
+                  VASurfaceImplEGLP pSurfaceImplEGL,
+                  VASurfaceID surface,
+                  unsigned int flags)
+{
+    VAStatus status;
+
+    status = deassociate_surface(ctx, pSurfaceImplEGL);
+
+    if (status != VA_STATUS_SUCCESS)
+        return status;
+
+    pSurfaceImplEGL->surface = surface;
+    pSurfaceImplEGL->flags = flags;
+
+    return VA_STATUS_SUCCESS;
+}
+
+static inline VAStatus
+sync_surface(VADriverContextP ctx, VASurfaceImplEGLP pSurfaceImplEGL)
+{
+    if (pSurfaceImplEGL->surface == VA_INVALID_SURFACE)
+        return VA_STATUS_ERROR_INVALID_SURFACE;
+
+    return ctx->vtable->vaSyncSurface(ctx, pSurfaceImplEGL->surface);
+}
+
+static VAStatus
+update_accociated_surface(VADriverContextP ctx, VASurfaceImplEGLP pSurfaceImplEGL)
+{
+    VAOpenGLESVTableP pOpenGLESVTable = gles_get_vtable(ctx);
+    VAStatus status;
+
+    status = sync_surface(ctx, pSurfaceImplEGL);
+
+    if (status != VA_STATUS_SUCCESS)
+        return status;
+
+    status = ctx->vtable->vaPutSurface(
+        ctx,
+        pSurfaceImplEGL->surface,
+        (void *)pSurfaceImplEGL->pixmap,
+        0, 0, pSurfaceImplEGL->width, pSurfaceImplEGL->height,
+        0, 0, pSurfaceImplEGL->width, pSurfaceImplEGL->height,
+        NULL, 0,
+        pSurfaceImplEGL->flags
+    );
+
+    if (status == VA_STATUS_SUCCESS) {
+        eglWaitNative(EGL_CORE_NATIVE_ENGINE);
+        pOpenGLESVTable->gles_egl_image_target_texture_2d(pSurfaceImplEGL->target,
+                                                          (GLeglImageOES)pSurfaceImplEGL->img_khr);
+    }
+
+    return status;
+}
+
+/* ========================================================================= */
+/* === VA/EGL implementation from libVA (generic and suboptimal path)    === */
+/* ========================================================================= */
+#ifdef INIT_SURFACE
+#undef INIT_SURFACE
+#endif
+
+#define INIT_SURFACE(surface, egl_surface) do {         \
+        surface = (VASurfaceImplEGLP)(egl_surface);     \
+        if (!check_surface(surface))                    \
+            return VA_STATUS_ERROR_INVALID_SURFACE;     \
+    } while (0)
+
+static VAStatus
+vaCreateSurfaceEGL_impl_libva(VADisplay dpy,
+                              GLenum target,
+                              GLuint texture,
+                              unsigned int width,
+                              unsigned int height,
+                              VASurfaceEGL *egl_surface)
+{
+    VASurfaceEGL pSurfaceEGL;
+
+    pSurfaceEGL = create_surface(dpy, target, texture, width, height);
+
+    if (!pSurfaceEGL)
+        return VA_STATUS_ERROR_ALLOCATION_FAILED;
+
+    *egl_surface = pSurfaceEGL;
+
+    return VA_STATUS_SUCCESS;
+}
+
+static VAStatus
+vaDestroySurfaceEGL_impl_libva(VADisplay dpy, VASurfaceEGL egl_surface)
+{
+    VASurfaceImplEGLP pSurfaceImplEGL;
+
+    INIT_SURFACE(pSurfaceImplEGL, egl_surface);
+
+    destroy_surface(dpy, pSurfaceImplEGL);
+
+    return VA_STATUS_SUCCESS;
+}
+
+static VAStatus
+vaAssociateSurfaceEGL_impl_libva(
+    VADisplay dpy,
+    VASurfaceEGL egl_surface,
+    VASurfaceID surface,
+    unsigned int flags
+)
+{
+    VADriverContextP ctx = ((VADisplayContextP)(dpy))->pDriverContext;
+    VASurfaceImplEGLP pSurfaceImplEGL;
+    VAStatus status;
+
+    INIT_SURFACE(pSurfaceImplEGL, egl_surface);
+
+    status = associate_surface(ctx, egl_surface, surface, flags);
+
+    return status;
+}
+
+static VAStatus
+vaUpdateAssociatedSurfaceEGL_impl_libva(
+    VADisplay dpy,
+    VASurfaceEGL egl_surface
+)
+{
+    VADriverContextP ctx = ((VADisplayContextP)(dpy))->pDriverContext;
+    VASurfaceImplEGLP pSurfaceImplEGL;
+    VAStatus status;
+
+    INIT_SURFACE(pSurfaceImplEGL, egl_surface);
+
+    status = update_accociated_surface(ctx, egl_surface);
+
+    return status;
+}
+
+static VAStatus
+vaDeassociateSurfaceEGL_impl_libva(
+    VADisplay dpy,
+    VASurfaceEGL egl_surface
+)
+{
+    VADriverContextP ctx = ((VADisplayContextP)(dpy))->pDriverContext;
+    VASurfaceImplEGLP pSurfaceImplEGL;
+    VAStatus status;
+
+    INIT_SURFACE(pSurfaceImplEGL, egl_surface);
+
+    status = deassociate_surface(ctx, egl_surface);
+
+    return status;
+}
+
+#undef INIT_SURFACE
+
+/* ========================================================================= */
+/* === Private VA/EGL vtable initialization                              === */
+/* ========================================================================= */
+
+// Initialize EGL driver context
+VAStatus va_egl_init_context(VADisplay dpy)
+{
+    VADisplayContextP pDisplayContext = (VADisplayContextP)dpy;
+    VADriverContextP ctx = pDisplayContext->pDriverContext;
+    VADriverContextEGLP egl_ctx = VA_DRIVER_CONTEXT_EGL(ctx);
+    VADriverVTablePrivEGLP  vtable  = &egl_ctx->vtable;
+
+    if (egl_ctx->is_initialized)
+        return VA_STATUS_SUCCESS;
+
+    if (ctx->vtable_egl && ctx->vtable_egl->vaCreateSurfaceEGL) {
+        vtable->vaCreateSurfaceEGL = vaCreateSurfaceEGL_impl_driver;
+        vtable->vaDestroySurfaceEGL = vaDestroySurfaceEGL_impl_driver;
+        vtable->vaAssociateSurfaceEGL = vaAssociateSurfaceEGL_impl_driver;
+        vtable->vaUpdateAssociatedSurfaceEGL = vaUpdateAssociatedSurfaceEGL_impl_driver;
+        vtable->vaDeassociateSurfaceEGL = vaDeassociateSurfaceEGL_impl_driver;
+    }
+    else {
+        if (pDisplayContext->vaCreateNativePixmap == NULL ||
+            pDisplayContext->vaFreeNativePixmap == NULL)
+            return VA_STATUS_ERROR_UNIMPLEMENTED;
+
+        vtable->vaCreateSurfaceEGL = vaCreateSurfaceEGL_impl_libva;
+        vtable->vaDestroySurfaceEGL = vaDestroySurfaceEGL_impl_libva;
+        vtable->vaAssociateSurfaceEGL = vaAssociateSurfaceEGL_impl_libva;
+        vtable->vaUpdateAssociatedSurfaceEGL = vaUpdateAssociatedSurfaceEGL_impl_libva;
+        vtable->vaDeassociateSurfaceEGL = vaDeassociateSurfaceEGL_impl_libva;
+
+        if (!check_extensions(ctx, egl_ctx->egl_display) || !init_extensions(ctx))
+            return VA_STATUS_ERROR_UNIMPLEMENTED;
+    }
+
+    egl_ctx->is_initialized = 1;
+
+    return VA_STATUS_SUCCESS;
+}
diff --git a/va/egl/va_egl_impl.h b/va/egl/va_egl_impl.h
new file mode 100644 (file)
index 0000000..96bc9a8
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef _VA_EGL_IMPL_H_
+#define _VA_EGL_IMPL_H_
+
+/**
+ * Initialize EGL driver context
+ *
+ * @param[in]  dpy        the VA Display
+ * @return VA_STATUS_SUCCESS if successful
+ */
+VAStatus va_egl_init_context(VADisplay dpy);
+
+#endif /* _VA_GLX_IMPL_H_ */
diff --git a/va/egl/va_egl_private.h b/va/egl/va_egl_private.h
new file mode 100644 (file)
index 0000000..d0d92fd
--- /dev/null
@@ -0,0 +1,74 @@
+#ifndef _VA_EGL_PRIVATE_H_
+#define _VA_EGL_PRIVATE_H_
+
+#include "sysdeps.h"
+#include "va.h"
+#include "va_backend.h"
+#include "va_egl.h"
+#include "va_backend_egl.h"
+
+typedef struct VAOpenGLESVTable *VAOpenGLESVTableP;
+
+struct VAOpenGLESVTable {
+    /* EGL_KHR_image_pixmap */
+    PFNEGLCREATEIMAGEKHRPROC            egl_create_image_khr;
+    PFNEGLDESTROYIMAGEKHRPROC           egl_destroy_image_khr;
+
+    /* GL_OES_EGL_image */
+    PFNGLEGLIMAGETARGETTEXTURE2DOESPROC gles_egl_image_target_texture_2d;
+};
+
+typedef struct VADisplayContextEGL *VADisplayContextEGLP;
+typedef struct VADriverContextEGL  *VADriverContextEGLP;
+typedef struct VASurfaceImplEGL    *VASurfaceImplEGLP;
+typedef struct VADriverVTableEGL   *VADriverVTableEGLP;
+typedef struct VADriverVTablePrivEGL *VADriverVTablePrivEGLP;
+typedef void (*vaDestroyFunc)(VADisplayContextP);
+
+struct VADisplayContextEGL {
+    vaDestroyFunc vaDestroy;
+};
+
+#define VA_DRIVER_CONTEXT_EGL(ctx) ((VADriverContextEGLP)((ctx)->egl))
+
+struct VADriverVTablePrivEGL {
+    VAStatus (*vaCreateSurfaceEGL)(
+        VADisplay dpy,
+        GLenum target,
+        GLuint texture,
+        unsigned int width,
+        unsigned int height,
+        VASurfaceEGL *egl_surface
+    );
+
+    VAStatus (*vaDestroySurfaceEGL)(
+        VADisplay dpy,
+        VASurfaceEGL egl_surface
+    );
+
+    VAStatus (*vaAssociateSurfaceEGL)(
+        VADisplay dpy,
+        VASurfaceEGL egl_surface,
+        VASurfaceID surface,
+        unsigned int flags
+    );
+
+    VAStatus (*vaUpdateAssociatedSurfaceEGL)(
+        VADisplay dpy,
+        VASurfaceEGL egl_surface
+    );
+
+    VAStatus (*vaDeassociateSurfaceEGL)(
+        VADisplay dpy,
+        VASurfaceEGL egl_surface
+    );
+};
+
+struct VADriverContextEGL {
+    struct VADriverVTablePrivEGL vtable;
+    struct VAOpenGLESVTable gles_vtable;
+    unsigned int is_initialized : 1;
+    EGLDisplay  egl_display;
+};
+
+#endif /* _VA_EGL_PRIVATE_H_ */
index 22f1765..cddf759 100644 (file)
@@ -433,8 +433,8 @@ struct VADriverContext
     
     void *dri_state;
     void *glx;                         /* opaque for GLX code */
-
-    unsigned long reserved[45];         /* reserve for future add-ins, decrease the subscript accordingly */
+    void *egl;
+    unsigned long reserved[44];         /* reserve for future add-ins, decrease the subscript accordingly */
 };
 
 #define VA_DISPLAY_MAGIC 0x56414430 /* VAD0 */