a test case to use VA/EGL interfaces
authorXiang, Haihao <haihao.xiang@intel.com>
Thu, 10 Nov 2011 02:34:45 +0000 (10:34 +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>
configure.ac
test/Makefile.am
test/egl/Makefile.am [new file with mode: 0644]
test/egl/va_egl_x11.c [new file with mode: 0644]

index 2b5661b..52f27fc 100644 (file)
@@ -235,6 +235,7 @@ AC_OUTPUT([
     test/Makefile
     test/basic/Makefile
     test/decode/Makefile
+    test/egl/Makefile
     test/encode/Makefile
     test/putsurface/Makefile
     test/vainfo/Makefile
index c55f6cb..79a0589 100644 (file)
@@ -25,4 +25,8 @@ AM_CFLAGS = -I$(top_srcdir)/va -I$(top_srcdir)/test/basic -I$(top_srcdir)/src/x1
 
 SUBDIRS = basic decode encode putsurface vainfo
 
+if USE_EGL
+SUBDIRS += egl
+endif
+
 EXTRA_DIST = loadsurface.h loadsurface_yuv.h
\ No newline at end of file
diff --git a/test/egl/Makefile.am b/test/egl/Makefile.am
new file mode 100644 (file)
index 0000000..caf7126
--- /dev/null
@@ -0,0 +1,15 @@
+bin_PROGRAMS = va_egl
+
+INCLUDES = -I$(top_srcdir)
+
+TEST_LIBS = $(top_builddir)/va/$(libvabackendlib) $(top_builddir)/va/$(libvacorelib) $(top_builddir)/va/libva-egl.la -lpthread -lX11 -lEGL -lGLESv1_CM
+
+va_egl_LDADD = $(TEST_LIBS)
+va_egl_SOURCES = va_egl_x11.c
+
+EXTRA_DIST =
+
+valgrind:      $(bin_PROGRAMS)
+       for a in $(bin_PROGRAMS); do \
+               valgrind --leak-check=full --show-reachable=yes .libs/$$a; \
+       done
diff --git a/test/egl/va_egl_x11.c b/test/egl/va_egl_x11.c
new file mode 100644 (file)
index 0000000..20d7415
--- /dev/null
@@ -0,0 +1,502 @@
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/keysym.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <va/va_x11.h>
+#include <va/va_egl.h>
+
+struct va_egl_context
+{
+    Display *x11_dpy;
+    Window win;
+
+    EGLDisplay egl_dpy;
+    EGLContext egl_ctx;
+    EGLSurface egl_surf;
+
+    VADisplay va_dpy;
+    VASurfaceID va_surface;
+    VASurfaceEGL va_egl_surface;
+
+    int x, y;
+    unsigned int width, height;
+    GLuint texture;
+    GLfloat ar;
+    unsigned int box_width;
+    unsigned char ydata;
+};
+
+static void
+va_egl_fini_egl(struct va_egl_context *ctx)
+{
+    eglMakeCurrent(ctx->egl_dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+    eglTerminate(ctx->egl_dpy);
+}
+
+static int
+va_egl_init_egl(struct va_egl_context *ctx)
+{
+    EGLint egl_major, egl_minor;
+    const char *s;
+
+    ctx->egl_dpy = eglGetDisplay(ctx->x11_dpy);
+
+    if (!ctx->egl_dpy) {
+        printf("Error: eglGetDisplay() failed\n");
+        return -1;
+    }
+
+    if (!eglInitialize(ctx->egl_dpy, &egl_major, &egl_minor)) {
+        printf("Error: eglInitialize() failed\n");
+        return -1;
+    }
+
+    s = eglQueryString(ctx->egl_dpy, EGL_VERSION);
+    printf("EGL_VERSION = %s\n", s);
+
+    return 0;
+}
+
+static int 
+yuvgen_planar(int width, int height,
+              unsigned char *Y_start, int Y_pitch,
+              unsigned char *U_start, int U_pitch,
+              unsigned char *V_start, int V_pitch,
+              int UV_interleave, int box_width, unsigned char ydata)
+{
+    int row;
+
+    /* copy Y plane */
+    for (row = 0; row < height; row++) {
+        unsigned char *Y_row = Y_start + row * Y_pitch;
+        int jj, xpos, ypos;
+
+        ypos = (row / box_width) & 0x1;
+
+        for (jj = 0; jj < width; jj++) {
+            xpos = ((jj) / box_width) & 0x1;
+                        
+            if ((xpos == 0) && (ypos == 0))
+                Y_row[jj] = ydata;
+            if ((xpos == 1) && (ypos == 1))
+                Y_row[jj] = ydata;
+                        
+            if ((xpos == 1) && (ypos == 0))
+                Y_row[jj] = 0xff - ydata;
+            if ((xpos == 0) && (ypos == 1))
+                Y_row[jj] = 0xff - ydata;
+        }
+    }
+  
+    /* copy UV data */
+    for( row = 0; row < height/2; row++) {
+        unsigned short value = 0x80;
+
+        if (UV_interleave) {
+            unsigned short *UV_row = (unsigned short *)(U_start + row * U_pitch);
+
+            memset(UV_row, value, width);
+        } else {
+            unsigned char *U_row = U_start + row * U_pitch;
+            unsigned char *V_row = V_start + row * V_pitch;
+            
+            memset(U_row, value, width / 2);
+            memset(V_row, value, width / 2);
+        }
+    }
+
+    return 0;
+}
+
+static int 
+va_egl_upload_surface(struct va_egl_context *ctx)
+{
+    VAImage surface_image;
+    void *surface_p = NULL, *U_start, *V_start;
+    
+    vaDeriveImage(ctx->va_dpy, ctx->va_surface, &surface_image);
+
+    vaMapBuffer(ctx->va_dpy, surface_image.buf, &surface_p);
+        
+    U_start = (char *)surface_p + surface_image.offsets[1];
+    V_start = (char *)surface_p + surface_image.offsets[2];
+
+    /* assume surface is planar format */
+    yuvgen_planar(surface_image.width, surface_image.height,
+                  (unsigned char *)surface_p, surface_image.pitches[0],
+                  (unsigned char *)U_start, surface_image.pitches[1],
+                  (unsigned char *)V_start, surface_image.pitches[2],
+                  (surface_image.format.fourcc==VA_FOURCC_NV12),
+                  ctx->box_width, ctx->ydata);
+        
+    vaUnmapBuffer(ctx->va_dpy,surface_image.buf);
+
+    vaDestroyImage(ctx->va_dpy,surface_image.image_id);
+
+    return 0;
+}
+
+static void
+va_egl_fini_va(struct va_egl_context *ctx)
+{
+    vaDestroySurfaces(ctx->va_dpy, &ctx->va_surface, 1);    
+    vaTerminate(ctx->va_dpy);
+}
+
+static int
+va_egl_init_va(struct va_egl_context *ctx)
+{
+    VAStatus va_status;
+    int major_ver, minor_ver;
+
+    ctx->va_dpy = vaGetDisplayEGL(ctx->x11_dpy, ctx->egl_dpy);
+
+    if (!ctx->va_dpy) {
+        printf("Error: vaGetDisplayEGL() failed\n");
+        return -1;
+    }
+
+    va_status = vaInitialize(ctx->va_dpy, &major_ver, &minor_ver);
+
+    if (va_status != VA_STATUS_SUCCESS) {
+        printf("Error: vaInitialize() failed\n");
+        return -1;
+    }
+
+    va_status = vaCreateSurfaces(ctx->va_dpy,
+                                 ctx->width, ctx->height,
+                                 VA_RT_FORMAT_YUV420, 
+                                 1, &ctx->va_surface);
+
+    if (va_status != VA_STATUS_SUCCESS) {
+        printf("Error: vaCreateSurfaces() failed\n");
+        return -1;
+    }
+
+    va_egl_upload_surface(ctx);
+
+    return 0;
+}
+
+static void
+va_egl_make_window(struct va_egl_context *ctx, const char *title)
+{
+    int scrnum;
+    XSetWindowAttributes attr;
+    unsigned long mask;
+    Window root;
+    XVisualInfo *visInfo, visTemplate;
+    int num_visuals;
+    EGLConfig config;
+    EGLint num_configs, vid;
+    const EGLint attribs[] = {
+        EGL_RED_SIZE, 8,
+        EGL_GREEN_SIZE, 8,
+        EGL_BLUE_SIZE, 8,
+        EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT,
+        EGL_NONE
+    };
+
+    scrnum = DefaultScreen(ctx->x11_dpy);
+    root = RootWindow(ctx->x11_dpy, scrnum);
+
+    if (!eglChooseConfig(ctx->egl_dpy, attribs, &config, 1, &num_configs) ||
+        !num_configs) {
+        printf("Error: couldn't get an EGL visual config\n");
+
+        return;
+    }
+
+    if (!eglGetConfigAttrib(ctx->egl_dpy, config, EGL_NATIVE_VISUAL_ID, &vid)) {
+        printf("Error: eglGetConfigAttrib() failed\n");
+
+        return;
+    }
+
+    /* The X window visual must match the EGL config */
+    visTemplate.visualid = vid;
+    visInfo = XGetVisualInfo(ctx->x11_dpy, VisualIDMask, &visTemplate, &num_visuals);
+
+    if (!visInfo) {
+        printf("Error: couldn't get X visual\n");
+
+        return;
+    }
+
+    /* window attributes */
+    attr.background_pixel = 0;
+    attr.border_pixel = 0;
+    attr.colormap = XCreateColormap(ctx->x11_dpy, root, visInfo->visual, AllocNone);
+    attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
+    attr.override_redirect = 0;
+    mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect;
+
+    ctx->win = XCreateWindow(ctx->x11_dpy,
+                             root,
+                             ctx->x, ctx->y,
+                             ctx->width, ctx->height,
+                             0, visInfo->depth, InputOutput,
+                             visInfo->visual, mask, &attr);
+
+    /* set hints and properties */
+    {
+        XSizeHints sizehints;
+        sizehints.x = ctx->x;
+        sizehints.y = ctx->y;
+        sizehints.width  = ctx->width;
+        sizehints.height = ctx->height;
+        sizehints.flags = USSize | USPosition;
+        XSetNormalHints(ctx->x11_dpy, ctx->win, &sizehints);
+        XSetStandardProperties(ctx->x11_dpy, ctx->win, title, title,
+                               None, (char **)NULL, 0, &sizehints);
+    }
+
+    eglBindAPI(EGL_OPENGL_ES_API);
+
+    ctx->egl_ctx = eglCreateContext(ctx->egl_dpy, config, EGL_NO_CONTEXT, NULL);
+
+    if (!ctx->egl_ctx) {
+        printf("Error: eglCreateContext() failed\n");
+        
+        return;
+    }
+
+    ctx->egl_surf = eglCreateWindowSurface(ctx->egl_dpy, config, ctx->win, NULL);
+    eglMakeCurrent(ctx->egl_dpy, ctx->egl_surf, ctx->egl_surf, ctx->egl_ctx);
+    XFree(visInfo);
+}
+
+static void
+va_egl_fini_gles(struct va_egl_context *ctx)
+{
+    glDeleteTextures(1, &ctx->texture);
+}
+
+static int
+va_egl_init_gles(struct va_egl_context *ctx)
+{
+    glClearColor(0.0, 0.0, 0.0, 0.0);
+    glColor4f(1.0, 1.0, 1.0, 1.0);
+
+    glDisable(GL_BLEND);
+    glDisable(GL_DEPTH_TEST);
+
+    glGenTextures(1, &ctx->texture);
+    glBindTexture(GL_TEXTURE_2D, ctx->texture);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glEnable(GL_TEXTURE_2D);
+
+    return 0;
+}
+
+static void
+va_egl_fini_va_egl(struct va_egl_context *ctx)
+{
+    vaDeassociateSurfaceEGL(ctx->va_dpy, ctx->va_egl_surface);
+    vaDestroySurfaceEGL(ctx->va_dpy, ctx->va_egl_surface);
+}
+
+static int
+va_egl_init_va_egl(struct va_egl_context *ctx)
+{
+    VAStatus va_status;
+
+    va_status = vaCreateSurfaceEGL(ctx->va_dpy,
+                                   GL_TEXTURE_2D, ctx->texture,
+                                   ctx->width, ctx->height,
+                                   &ctx->va_egl_surface);
+
+    if (va_status != VA_STATUS_SUCCESS) {
+        printf("Error: vaCreateSurfaceEGL() failed\n");
+        return -1;
+    }
+
+    va_status = vaAssociateSurfaceEGL(ctx->va_dpy,
+                                      ctx->va_egl_surface,
+                                      ctx->va_surface,
+                                      0);
+
+    if (va_status != VA_STATUS_SUCCESS) {
+        printf("Error: vaAssociateSurfaceEGL() failed\n");
+        return -1;
+    }
+
+    vaUpdateAssociatedSurfaceEGL(ctx->va_dpy, ctx->va_egl_surface);
+
+    return 0;
+}
+
+static void
+va_egl_fini(struct va_egl_context *ctx)
+{
+    va_egl_fini_gles(ctx);
+    va_egl_fini_va(ctx);
+    va_egl_fini_egl(ctx);
+    va_egl_fini_gles(ctx);
+    va_egl_fini_va_egl(ctx);
+
+    // XDestroyWindow(ctx->x11_dpy, ctx->win);
+    XCloseDisplay(ctx->x11_dpy);
+}
+
+static int
+va_egl_init(struct va_egl_context *ctx, int argc, char **argv)
+{
+    memset(ctx, 0, sizeof(*ctx));
+    ctx->x11_dpy = XOpenDisplay(NULL);
+    ctx->width = 320;
+    ctx->height = 320;
+    ctx->ar = 1.0;
+    ctx->box_width = 16;
+    ctx->ydata = 0xff;
+
+    if (!ctx->x11_dpy) {
+        printf("Error: couldn't open display %s\n", getenv("DISPLAY"));
+        return -1;
+    }
+
+    if (va_egl_init_egl(ctx) != 0)
+        return -1;
+
+    if (va_egl_init_va(ctx) != 0)
+        return -1;
+
+    va_egl_make_window(ctx, "VA/EGL");
+    va_egl_init_gles(ctx);
+    va_egl_init_va_egl(ctx);
+
+    return 0;
+}
+
+static void
+va_egl_reshape(struct va_egl_context *ctx, int width, int height)
+{
+    GLfloat ar = (GLfloat) width / (GLfloat) height;
+
+    ctx->width = width;
+    ctx->height = height;
+    ctx->ar = ar;
+
+    glViewport(0, 0, (GLint) width, (GLint) height);
+
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+    glOrthof(-ar, ar, -ar, ar, -1.0, 1.0);
+    glMatrixMode(GL_MODELVIEW);
+    glLoadIdentity();
+}
+
+static void
+va_egl_draw(struct va_egl_context *ctx)
+{
+    const GLfloat verts[][3] = {
+        { -ctx->ar, -ctx->ar, 0 },
+        {  ctx->ar, -ctx->ar, 0 },
+        {  ctx->ar,  ctx->ar, 0 },
+        { -ctx->ar,  ctx->ar, 0 }
+    };
+    const GLfloat texs[][2] = {
+        { 0, 0 },
+        { 1, 0 },
+        { 1, 1 },
+        { 0, 1 }
+    };
+
+    glClear(GL_COLOR_BUFFER_BIT);
+
+    glVertexPointer(3, GL_FLOAT, 0, verts);
+    glTexCoordPointer(2, GL_FLOAT, 0, texs);
+
+    glEnableClientState(GL_VERTEX_ARRAY);
+    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+
+    glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+    glDisableClientState(GL_VERTEX_ARRAY);
+    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+}
+
+static void
+va_egl_event_loop(struct va_egl_context *ctx)
+{
+    while (1) {
+        int redraw = 0;
+
+        if (XPending(ctx->x11_dpy) > 0) {
+            XEvent event;
+            XNextEvent(ctx->x11_dpy, &event);
+
+            switch (event.type) {
+            case Expose:
+                redraw = 1;
+                break;
+
+            case ConfigureNotify:
+                va_egl_reshape(ctx, event.xconfigure.width, event.xconfigure.height);
+                redraw = 1;
+                break;
+
+            case KeyPress:
+            {
+                char buffer[10];
+                int code;
+                code = XLookupKeysym(&event.xkey, 0);
+
+                if (code == XK_y) {
+                    ctx->ydata += 0x10;
+                    va_egl_upload_surface(ctx);
+                    vaUpdateAssociatedSurfaceEGL(ctx->va_dpy, ctx->va_egl_surface);
+                    redraw = 1;
+                } else {
+                    XLookupString(&event.xkey, buffer, sizeof(buffer),
+                                  NULL, NULL);
+                    
+                    if (buffer[0] == 27) {
+                        /* escape */
+                        return;
+                    }
+                }
+            }
+                
+            break;
+
+            default:
+                ; /*no-op*/
+            }
+        }
+
+        if (redraw) {
+            va_egl_draw(ctx);
+            eglSwapBuffers(ctx->egl_dpy, ctx->egl_surf);
+        }
+    }
+}
+
+static void
+va_egl_run(struct va_egl_context *ctx)
+{
+    XMapWindow(ctx->x11_dpy, ctx->win);
+    va_egl_reshape(ctx, ctx->width, ctx->height);
+    va_egl_event_loop(ctx);
+}
+
+int
+main(int argc, char *argv[])
+{
+    struct va_egl_context ctx;
+
+    if (va_egl_init(&ctx, argc, argv) == 0) {
+        va_egl_run(&ctx);
+        va_egl_fini(&ctx);
+    }
+
+    return 0;
+}