summaryrefslogtreecommitdiff
path: root/va/egl/va_egl_impl.c
diff options
context:
space:
mode:
Diffstat (limited to 'va/egl/va_egl_impl.c')
-rw-r--r--va/egl/va_egl_impl.c499
1 files changed, 499 insertions, 0 deletions
diff --git a/va/egl/va_egl_impl.c b/va/egl/va_egl_impl.c
new file mode 100644
index 0000000..367f43f
--- /dev/null
+++ b/va/egl/va_egl_impl.c
@@ -0,0 +1,499 @@
+#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"
+
+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_pixmap_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;
+
+ 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
+vaQuerySurfaceTargetsEGL_impl_driver(VADisplay dpy,
+ EGLenum *target_list,
+ int *num_targets)
+{
+ VADriverContextP ctx = ((VADisplayContextP)(dpy))->pDriverContext;
+
+ INVOKE(ctx, QuerySurfaceTargets, (ctx, target_list, num_targets));
+
+ return VA_STATUS_SUCCESS;
+}
+
+static VAStatus
+vaCreateSurfaceEGL_impl_driver(VADisplay dpy,
+ EGLenum target,
+ unsigned int width,
+ unsigned int height,
+ VASurfaceEGL *gl_surface)
+{
+ VADriverContextP ctx = ((VADisplayContextP)(dpy))->pDriverContext;
+
+ INVOKE(ctx, CreateSurface, (ctx, target, width, height, gl_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
+vaSyncSurfaceEGL_impl_driver(VADisplay dpy,
+ VASurfaceEGL egl_surface)
+{
+ VADriverContextP ctx = ((VADisplayContextP)(dpy))->pDriverContext;
+
+ INVOKE(ctx, SyncSurface, (ctx, egl_surface));
+
+ return VA_STATUS_SUCCESS;
+}
+
+static VAStatus
+vaGetSurfaceInfoEGL_impl_driver(VADisplay dpy,
+ VASurfaceEGL egl_surface,
+ EGLenum *target,
+ EGLClientBuffer *buffer,
+ EGLint *attrib_list,
+ int *num_attribs)
+{
+ VADriverContextP ctx = ((VADisplayContextP)(dpy))->pDriverContext;
+
+ INVOKE(ctx, GetSurfaceInfo, (ctx, egl_surface, target, buffer, attrib_list, num_attribs));
+
+ 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','E','G','L')
+
+struct VASurfaceImplEGL {
+ uint32_t magic; ///< Magic number identifying a VASurfaceImplEGL
+ VASurfaceID surface; ///< Associated VA surface
+ EGLenum target; ///< EGL target
+ EGLClientBuffer buffer;
+ unsigned int width;
+ unsigned int height;
+ 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);
+}
+
+// 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
+sync_associated_surface(VADriverContextP ctx, VASurfaceImplEGLP pSurfaceImplEGL)
+{
+ VAStatus status;
+
+ status = sync_surface(ctx, pSurfaceImplEGL);
+
+ if (status != VA_STATUS_SUCCESS)
+ return status;
+
+ if (pSurfaceImplEGL->target != EGL_NATIVE_PIXMAP_KHR)
+ return VA_STATUS_ERROR_UNIMPLEMENTED;
+
+ status = ctx->vtable->vaPutSurface(
+ ctx,
+ pSurfaceImplEGL->surface,
+ (void *)pSurfaceImplEGL->buffer,
+ 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);
+ }
+
+ 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
+vaQuerySurfaceTargetsEGL_impl_libva(VADisplay dpy,
+ EGLenum *target_list,
+ int *num_targets)
+{
+ int i = 0;
+
+ /* FIXME: support other targets ??? */
+ target_list[i++] = EGL_NATIVE_PIXMAP_KHR;
+ *num_targets = i;
+ assert(i <= IMPL_MAX_EGL_SURFACE_TARGETS);
+
+ return VA_STATUS_SUCCESS;
+}
+
+static VAStatus
+vaCreateSurfaceEGL_impl_libva(VADisplay dpy,
+ EGLenum target,
+ unsigned int width,
+ unsigned int height,
+ VASurfaceEGL *egl_surface)
+{
+ VASurfaceImplEGLP pSurfaceImplEGL = NULL;
+
+ /* So far only support for EGL_NATIVE_PIXMAP_KHR */
+ if (target != 0 && target != EGL_NATIVE_PIXMAP_KHR)
+ return VA_STATUS_ERROR_INVALID_PARAMETER;
+
+ pSurfaceImplEGL = calloc(1, sizeof(*pSurfaceImplEGL));
+
+ if (!pSurfaceImplEGL) {
+ *egl_surface = 0;
+ return VA_STATUS_ERROR_ALLOCATION_FAILED;
+ }
+
+ pSurfaceImplEGL->magic = VA_SURFACE_IMPL_EGL_MAGIC;
+ pSurfaceImplEGL->surface = VA_INVALID_SURFACE;
+ pSurfaceImplEGL->target = target == 0 ? EGL_NATIVE_PIXMAP_KHR : target;
+ pSurfaceImplEGL->buffer = 0;
+ pSurfaceImplEGL->width = width;
+ pSurfaceImplEGL->height = height;
+ *egl_surface = (VASurfaceEGL)pSurfaceImplEGL;
+
+ return VA_STATUS_SUCCESS;
+}
+
+static VAStatus
+vaDestroySurfaceEGL_impl_libva(VADisplay dpy, VASurfaceEGL egl_surface)
+{
+ VASurfaceImplEGLP pSurfaceImplEGL;
+
+ INIT_SURFACE(pSurfaceImplEGL, egl_surface);
+
+ if (pSurfaceImplEGL->target == EGL_NATIVE_PIXMAP_KHR) {
+ if (pSurfaceImplEGL->buffer) {
+ destroy_native_pixmap(dpy, pSurfaceImplEGL->buffer);
+ pSurfaceImplEGL->buffer = 0;
+ }
+ }
+
+ free(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);
+
+ if (surface == VA_INVALID_SURFACE)
+ return VA_STATUS_ERROR_INVALID_SURFACE;
+
+ if (pSurfaceImplEGL->target == EGL_NATIVE_PIXMAP_KHR) {
+ if (pSurfaceImplEGL->buffer)
+ destroy_native_pixmap(dpy, pSurfaceImplEGL->buffer);
+
+ pSurfaceImplEGL->buffer = create_native_pixmap(dpy, pSurfaceImplEGL->width, pSurfaceImplEGL->height);
+ }
+
+ pSurfaceImplEGL->surface = surface;
+ pSurfaceImplEGL->flags = flags;
+
+ if (pSurfaceImplEGL->buffer)
+ return VA_STATUS_SUCCESS;
+
+ return VA_STATUS_ERROR_UNKNOWN;
+}
+
+static VAStatus
+vaSyncSurfaceEGL_impl_libva(VADisplay dpy,
+ VASurfaceEGL egl_surface)
+{
+ VADriverContextP ctx = ((VADisplayContextP)(dpy))->pDriverContext;
+ VASurfaceImplEGLP pSurfaceImplEGL;
+ VAStatus status;
+
+ INIT_SURFACE(pSurfaceImplEGL, egl_surface);
+
+ status = sync_associated_surface(ctx, pSurfaceImplEGL);
+
+ return status;
+}
+
+static VAStatus
+vaGetSurfaceInfoEGL_impl_libva(VADisplay dpy,
+ VASurfaceEGL egl_surface,
+ EGLenum *target,
+ EGLClientBuffer *buffer,
+ EGLint *attrib_list,
+ int *num_attribs)
+{
+ VADriverContextP ctx = ((VADisplayContextP)(dpy))->pDriverContext;
+ VASurfaceImplEGLP pSurfaceImplEGL;
+ VAStatus status;
+ int i = 0;
+
+ INIT_SURFACE(pSurfaceImplEGL, egl_surface);
+
+ if (pSurfaceImplEGL->surface == VA_INVALID_SURFACE)
+ return VA_STATUS_ERROR_INVALID_SURFACE;
+
+ if (*num_attribs < IMPL_MAX_EGL_SURFACE_ATTRIBUTES)
+ return VA_STATUS_ERROR_INVALID_PARAMETER;
+
+ *target = pSurfaceImplEGL->target;
+ *buffer = pSurfaceImplEGL->buffer;
+
+ if (pSurfaceImplEGL->target == EGL_NATIVE_PIXMAP_KHR) {
+ attrib_list[i++] = EGL_IMAGE_PRESERVED_KHR;
+ attrib_list[i + 1] = EGL_TRUE;
+ attrib_list[i++] = EGL_NONE;
+ } else {
+ /* FIXME later */
+ attrib_list[i++] = EGL_NONE;
+ }
+
+ *num_attribs = i;
+
+ return VA_STATUS_SUCCESS;
+}
+
+static VAStatus
+vaDeassociateSurfaceEGL_impl_libva(
+ VADisplay dpy,
+ VASurfaceEGL egl_surface
+ )
+{
+ VADriverContextP ctx = ((VADisplayContextP)(dpy))->pDriverContext;
+ VASurfaceImplEGLP pSurfaceImplEGL;
+ VAStatus status;
+
+ INIT_SURFACE(pSurfaceImplEGL, egl_surface);
+
+ if (pSurfaceImplEGL->target == EGL_NATIVE_PIXMAP_KHR) {
+ if (pSurfaceImplEGL->buffer)
+ destroy_native_pixmap(dpy, pSurfaceImplEGL->buffer);
+
+ pSurfaceImplEGL->buffer = 0;
+ }
+
+ pSurfaceImplEGL->surface = VA_INVALID_SURFACE;
+
+ return VA_STATUS_SUCCESS;
+}
+
+#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->vaQuerySurfaceTargetsEGL = vaQuerySurfaceTargetsEGL_impl_driver;
+ vtable->vaCreateSurfaceEGL = vaCreateSurfaceEGL_impl_driver;
+ vtable->vaDestroySurfaceEGL = vaDestroySurfaceEGL_impl_driver;
+ vtable->vaAssociateSurfaceEGL = vaAssociateSurfaceEGL_impl_driver;
+ vtable->vaSyncSurfaceEGL = vaSyncSurfaceEGL_impl_driver;
+ vtable->vaGetSurfaceInfoEGL = vaGetSurfaceInfoEGL_impl_driver;
+ vtable->vaDeassociateSurfaceEGL = vaDeassociateSurfaceEGL_impl_driver;
+ }
+ else {
+ if (pDisplayContext->vaCreateNativePixmap == NULL ||
+ pDisplayContext->vaFreeNativePixmap == NULL)
+ return VA_STATUS_ERROR_UNIMPLEMENTED;
+
+ if (!check_pixmap_extensions(ctx, egl_ctx->egl_display))
+ return VA_STATUS_ERROR_UNIMPLEMENTED;
+
+ vtable->vaQuerySurfaceTargetsEGL = vaQuerySurfaceTargetsEGL_impl_libva;
+ vtable->vaCreateSurfaceEGL = vaCreateSurfaceEGL_impl_libva;
+ vtable->vaDestroySurfaceEGL = vaDestroySurfaceEGL_impl_libva;
+ vtable->vaAssociateSurfaceEGL = vaAssociateSurfaceEGL_impl_libva;
+ vtable->vaSyncSurfaceEGL = vaSyncSurfaceEGL_impl_libva;
+ vtable->vaGetSurfaceInfoEGL = vaGetSurfaceInfoEGL_impl_libva;
+ vtable->vaDeassociateSurfaceEGL = vaDeassociateSurfaceEGL_impl_libva;
+ }
+
+ egl_ctx->is_initialized = 1;
+
+ return VA_STATUS_SUCCESS;
+}