From 7740fd277516c7e56d30d1e52b385bc6c8542e22 Mon Sep 17 00:00:00 2001 From: "Xiang, Haihao" Date: Thu, 10 Nov 2011 10:47:03 +0800 Subject: VA/EGL interfaces Signed-off-by: Xiang, Haihao --- va/Makefile.am | 2 +- va/egl/Makefile.am | 14 +- va/egl/va_backend_egl.h | 32 +++ va/egl/va_egl.c | 178 ++++++++++++++++- va/egl/va_egl.h | 96 ++++++++- va/egl/va_egl_impl.c | 521 ++++++++++++++++++++++++++++++++++++++++++++++++ va/egl/va_egl_impl.h | 12 ++ va/egl/va_egl_private.h | 74 +++++++ va/va_backend.h | 4 +- 9 files changed, 921 insertions(+), 12 deletions(-) create mode 100644 va/egl/va_egl_impl.c create mode 100644 va/egl/va_egl_impl.h create mode 100644 va/egl/va_egl_private.h diff --git a/va/Makefile.am b/va/Makefile.am index 16a1e8f..bc70435 100644 --- a/va/Makefile.am +++ b/va/Makefile.am @@ -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 diff --git a/va/egl/Makefile.am b/va/egl/Makefile.am index c02daa7..74f3c70 100644 --- a/va/egl/Makefile.am +++ b/va/egl/Makefile.am @@ -20,16 +20,22 @@ # 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 diff --git a/va/egl/va_backend_egl.h b/va/egl/va_backend_egl.h index 925d933..9dae84f 100644 --- a/va/egl/va_backend_egl.h +++ b/va/egl/va_backend_egl.h @@ -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 */ diff --git a/va/egl/va_egl.c b/va/egl/va_egl.c index 36e5504..6caf4f8 100644 --- a/va/egl/va_egl.c +++ b/va/egl/va_egl.c @@ -53,14 +53,34 @@ * * 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; +} diff --git a/va/egl/va_egl.h b/va/egl/va_egl.h index 4243d0b..8f9c840 100644 --- a/va/egl/va_egl.h +++ b/va/egl/va_egl.h @@ -2,12 +2,16 @@ #define _VA_EGL_H_ #include +#include +#include +#include +#include #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 index 0000000..b47d266 --- /dev/null +++ b/va/egl/va_egl_impl.c @@ -0,0 +1,521 @@ +#define _GNU_SOURCE 1 +#include +#include +#include +#include +#include +#include + +#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 index 0000000..96bc9a8 --- /dev/null +++ b/va/egl/va_egl_impl.h @@ -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 index 0000000..d0d92fd --- /dev/null +++ b/va/egl/va_egl_private.h @@ -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_ */ diff --git a/va/va_backend.h b/va/va_backend.h index 22f1765..cddf759 100644 --- a/va/va_backend.h +++ b/va/va_backend.h @@ -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 */ -- cgit v1.2.1