From 2ac9bac5f4920584e612033078dfafcfe97694c5 Mon Sep 17 00:00:00 2001 From: "Xiang, Haihao" Date: Thu, 10 Nov 2011 10:34:45 +0800 Subject: a test case to use VA/EGL interfaces Signed-off-by: Xiang, Haihao --- configure.ac | 1 + test/Makefile.am | 4 + test/egl/Makefile.am | 15 ++ test/egl/va_egl_x11.c | 502 ++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 522 insertions(+) create mode 100644 test/egl/Makefile.am create mode 100644 test/egl/va_egl_x11.c diff --git a/configure.ac b/configure.ac index 2b5661b..52f27fc 100644 --- a/configure.ac +++ b/configure.ac @@ -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 diff --git a/test/Makefile.am b/test/Makefile.am index c55f6cb..79a0589 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -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 index 0000000..caf7126 --- /dev/null +++ b/test/egl/Makefile.am @@ -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 index 0000000..20d7415 --- /dev/null +++ b/test/egl/va_egl_x11.c @@ -0,0 +1,502 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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; +} -- cgit v1.2.1