[Mesa-dev] [PATCH] progs/egl: Add an OpenGL ES 2.0 demo for EGL_OES_image_pixmap.

Shuang He shuang.he at intel.com
Tue Jul 19 01:24:41 PDT 2011


This is based on opengles1/texture_from_pixmap.c
---
 src/egl/opengles2/Makefile.am           |    4 +-
 src/egl/opengles2/texture_from_pixmap.c |  653 +++++++++++++++++++++++++++++++
 2 files changed, 656 insertions(+), 1 deletions(-)
 create mode 100644 src/egl/opengles2/texture_from_pixmap.c

diff --git a/src/egl/opengles2/Makefile.am b/src/egl/opengles2/Makefile.am
index 8d85c06..1e791fb 100644
--- a/src/egl/opengles2/Makefile.am
+++ b/src/egl/opengles2/Makefile.am
@@ -38,7 +38,8 @@ if HAVE_GLESV2
 bin_PROGRAMS = \
 	es2_info \
 	es2gears \
-	es2tri
+	es2tri \
+	texture_from_pixmap
 endif
 endif
 
@@ -46,3 +47,4 @@ es2_info_LDADD = $(X11_LIBS)
 es2tri_LDADD = $(X11_LIBS)
 
 es2gears_LDADD = ../eglut/libeglut_x11.la
+texture_from_pixmap_LDADD = $(X11_LIBS)
diff --git a/src/egl/opengles2/texture_from_pixmap.c b/src/egl/opengles2/texture_from_pixmap.c
new file mode 100644
index 0000000..5e47468
--- /dev/null
+++ b/src/egl/opengles2/texture_from_pixmap.c
@@ -0,0 +1,653 @@
+/*
+ * Mesa 3-D graphics library
+ * Version:  7.9
+ *
+ * Copyright (C) 2010 LunarG Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Chia-I Wu <olv at lunarg.com>
+ *    Shuang He <shuang.he at intel.com>
+ */
+
+/*
+ * This demo uses EGL_KHR_image_pixmap and GL_OES_EGL_image to demonstrate
+ * texture-from-pixmap.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h> /* for usleep */
+#include <sys/time.h> /* for gettimeofday */
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/keysym.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+struct app_data {
+   /* native */
+   Display *xdpy;
+   Window canvas, cube;
+   Pixmap pix;
+   unsigned int width, height, depth;
+   GC fg, bg;
+
+   /* EGL */
+   EGLDisplay dpy;
+   EGLContext ctx;
+   EGLSurface surf;
+   EGLImageKHR img;
+
+   /* OpenGL ES */
+   GLuint texture;
+
+   PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR;
+   PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR;
+   PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES;
+
+   /* app state */
+   Bool loop;
+   Bool redraw, reshape;
+
+   struct {
+      Bool active;
+      unsigned long next_frame; /* in ms */
+   } animate;
+
+   struct {
+      Bool active;
+      int x1, y1;
+      int x2, y2;
+   } paint;
+   int prog;
+   int vs;
+   int fs;
+};
+
+enum pigilt_attrib_location {
+       PIGLIT_ATTRIB_POS,
+       PIGLIT_ATTRIB_TEX
+};
+
+static const char vertex_shader[] =
+"attribute vec3 pos;\n"
+"attribute vec3 tex;\n"
+"\n"
+"\n"
+"varying mediump vec2 texCoord;\n"
+"\n"
+"void main(void)\n"
+"{\n"
+"    gl_Position = vec4(pos, 1.0);\n"
+"    texCoord = tex.xy;\n"
+"}";
+
+static const char fragment_shader[] =
+"uniform sampler2D texid;\n"
+"varying mediump vec2 texCoord;\n"
+"\n"
+"void main(void)\n"
+"{\n"
+"    gl_FragColor = texture2D(texid, texCoord);\n"
+"}";
+
+
+static void
+gl_redraw(void)
+{
+   float verts[4][4];
+   float tex[4][2];
+   float x = -0.5;
+   float y = -0.5;
+   float w = 1.0;
+   float h = 1.0;
+   float tx = 0.0;
+   float ty = 1.0;
+   float tw = 1.0;
+   float th = -1.0;
+
+   verts[0][0] = x;
+   verts[0][1] = y;
+   verts[0][2] = 0.0;
+   verts[0][3] = 1.0;
+   tex[0][0] = tx;
+   tex[0][1] = ty;
+   verts[1][0] = x + w;
+   verts[1][1] = y;
+   verts[1][2] = 0.0;
+   verts[1][3] = 1.0;
+   tex[1][0] = tx + tw;
+   tex[1][1] = ty;
+   verts[2][0] = x;
+   verts[2][1] = y + h;
+   verts[2][2] = 0.0;
+   verts[2][3] = 1.0;
+   tex[2][0] = tx;
+   tex[2][1] = ty + th;
+   verts[3][0] = x + w;
+   verts[3][1] = y + h;
+   verts[3][2] = 0.0;
+   verts[3][3] = 1.0;
+   tex[3][0] = tx + tw;
+   tex[3][1] = ty + th;
+
+   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+   glVertexAttribPointer(PIGLIT_ATTRIB_POS, 4, GL_FLOAT, GL_FALSE, 0, verts);
+   glVertexAttribPointer(PIGLIT_ATTRIB_TEX, 2, GL_FLOAT, GL_FALSE, 0, tex);
+   glEnableVertexAttribArray(PIGLIT_ATTRIB_POS);
+   glEnableVertexAttribArray(PIGLIT_ATTRIB_TEX);
+   glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+   glDisableVertexAttribArray(PIGLIT_ATTRIB_POS);
+   glDisableVertexAttribArray(PIGLIT_ATTRIB_TEX);
+}
+
+static void
+gl_reshape(int width, int height)
+{
+   GLfloat ar = (GLfloat) width / (GLfloat) height;
+
+   glViewport(0, 0, width, height);
+}
+
+static void
+app_redraw(struct app_data *data)
+{
+   /* pixmap has changed */
+   if (data->reshape || data->paint.active) {
+      /*
+       * The extension only states that
+       *
+       *   If an application specifies an EGLImage sibling as the destination
+       *   for rendering and/or pixel download operations (e.g., as an
+       *   OpenGL-ES framebuffer object, glTexSubImage2D, etc.), the modified
+       *   image results will be observed by all EGLImage siblings in all
+       *   client API contexts.
+       *
+       * Though not required by the drivers I tested, I think the rules of
+       * "Propagating Changes to Objects" should apply here.  That is, the
+       * changes made by the native engine must be completed and the resource
+       * must be re-attached.
+       */
+      eglWaitNative(EGL_CORE_NATIVE_ENGINE);
+      data->glEGLImageTargetTexture2DOES(GL_TEXTURE_2D,
+            (GLeglImageOES) data->img);
+   }
+
+   XCopyArea(data->xdpy, data->pix, data->canvas, data->fg,
+         0, 0, data->width, data->height, 0, 0);
+
+   gl_redraw();
+   eglSwapBuffers(data->dpy, data->surf);
+}
+
+static void
+app_reshape(struct app_data *data)
+{
+   const EGLint img_attribs[] = {
+      EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
+      EGL_NONE
+   };
+
+   XResizeWindow(data->xdpy, data->cube, data->width, data->height);
+   XMoveWindow(data->xdpy, data->cube, data->width, 0);
+
+   if (data->img)
+      data->eglDestroyImageKHR(data->dpy, data->img);
+   if (data->pix)
+      XFreePixmap(data->xdpy, data->pix);
+
+   data->pix = XCreatePixmap(data->xdpy, data->canvas, data->width, data->height, data->depth);
+   XFillRectangle(data->xdpy, data->pix, data->bg, 0, 0, data->width, data->height);
+
+   data->img = data->eglCreateImageKHR(data->dpy, EGL_NO_CONTEXT,
+         EGL_NATIVE_PIXMAP_KHR, (EGLClientBuffer) data->pix, img_attribs);
+
+   gl_reshape(data->width, data->height);
+}
+
+static void
+app_toggle_animate(struct app_data *data)
+{
+   data->animate.active = !data->animate.active;
+
+   if (data->animate.active) {
+      struct timeval tv;
+
+      gettimeofday(&tv, NULL);
+      data->animate.next_frame = tv.tv_sec * 1000 + tv.tv_usec / 1000;
+   }
+}
+
+static void
+app_next_event(struct app_data *data)
+{
+   XEvent event;
+
+   data->reshape = False;
+   data->redraw = False;
+   data->paint.active = False;
+
+   if (data->animate.active) {
+      struct timeval tv;
+      unsigned long now;
+
+      gettimeofday(&tv, NULL);
+      now = tv.tv_sec * 1000 + tv.tv_usec / 1000;
+
+      /* wait for next frame */
+      if (!XPending(data->xdpy) && now < data->animate.next_frame) {
+         usleep((data->animate.next_frame - now) * 1000);
+         gettimeofday(&tv, NULL);
+         now = tv.tv_sec * 1000 + tv.tv_usec / 1000;
+      }
+
+      while (now >= data->animate.next_frame) {
+         /* 30fps */
+         data->animate.next_frame += 1000 / 30;
+      }
+
+      /* check again in case there were events when sleeping */
+      if (!XPending(data->xdpy)) {
+         data->redraw = True;
+         return;
+      }
+   }
+
+   XNextEvent(data->xdpy, &event);
+
+   switch (event.type) {
+   case ConfigureNotify:
+      data->width = event.xconfigure.width / 2;
+      data->height = event.xconfigure.height;
+      data->reshape = True;
+      break;
+   case Expose:
+      data->redraw = True;
+      break;
+   case KeyPress:
+      {
+         int code;
+
+         code = XLookupKeysym(&event.xkey, 0);
+         switch (code) {
+         case XK_a:
+            app_toggle_animate(data);
+            break;
+         case XK_Escape:
+            data->loop = False;
+            break;
+         default:
+            break;
+         }
+      }
+      break;
+   case ButtonPress:
+      data->paint.x1 = data->paint.x2 = event.xbutton.x;
+      data->paint.y1 = data->paint.y2 = event.xbutton.y;
+      break;
+   case ButtonRelease:
+      data->paint.active = False;
+      break;
+   case MotionNotify:
+      data->paint.x1 = data->paint.x2;
+      data->paint.y1 = data->paint.y2;
+      data->paint.x2 = event.xmotion.x;
+      data->paint.y2 = event.xmotion.y;
+      data->paint.active = True;
+      break;
+   default:
+      break;
+   }
+
+   if (data->paint.active || data->reshape)
+      data->redraw = True;
+}
+
+
+static void
+app_init_gl(struct app_data *data)
+{
+   int ok, err;
+   char msg[512];
+   const char *p;
+  
+   glClearColor(1.0, 0.1, 0.3, 0.0);
+
+   glGenTextures(1, &data->texture);
+
+   glBindTexture(GL_TEXTURE_2D, data->texture);
+   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+   data->prog = glCreateProgram();
+   glBindAttribLocation(data->prog, PIGLIT_ATTRIB_POS, "pos");
+   glBindAttribLocation(data->prog, PIGLIT_ATTRIB_TEX, "tex");
+
+   p = vertex_shader;
+   data->vs = glCreateShader(GL_VERTEX_SHADER);   
+   glShaderSource(data->vs, 1, &p, NULL);
+   glCompileShader(data->vs);
+   glGetShaderiv(data->vs, GL_COMPILE_STATUS, &ok);
+   int length;
+   glGetShaderInfoLog(data->vs, sizeof msg, &length, msg);
+   printf("vertex shader info: %s\n", msg);
+
+   /* Compile the fragment shader */
+   p = fragment_shader;
+   data->fs = glCreateShader(GL_FRAGMENT_SHADER);
+   glShaderSource(data->fs, 1, &p, NULL);
+   glCompileShader(data->fs);
+   glGetShaderiv(data->fs, GL_COMPILE_STATUS, &ok);
+
+   glGetShaderInfoLog(data->fs, sizeof msg, NULL, msg);
+   printf("fragment shader info: %s\n", msg);
+
+   glAttachShader(data->prog, data->vs);
+   glAttachShader(data->prog, data->fs);
+   glLinkProgram(data->prog);
+   glDeleteShader(data->vs);
+   glDeleteShader(data->fs);
+
+   glGetProgramiv(data->prog, GL_LINK_STATUS, &ok);
+   if (!ok) {
+      GLchar *info;
+      GLint size;
+      
+      glGetProgramiv(data->prog, GL_INFO_LOG_LENGTH, &size);
+      info = malloc(size);
+     
+      glGetProgramInfoLog(data->prog, size, NULL, info);
+      fprintf(stderr, "Failed to link:\n%s\n", info);
+
+      free(info);
+   }
+   
+   glUseProgram(data->prog);
+
+}
+
+static Bool
+app_init_exts(struct app_data *data)
+{
+   const char *exts;
+
+   exts = eglQueryString(data->dpy, EGL_EXTENSIONS);
+   data->eglCreateImageKHR =
+      (PFNEGLCREATEIMAGEKHRPROC) eglGetProcAddress("eglCreateImageKHR");
+   data->eglDestroyImageKHR =
+      (PFNEGLDESTROYIMAGEKHRPROC) eglGetProcAddress("eglDestroyImageKHR");
+   if (!exts || !strstr(exts, "EGL_KHR_image_pixmap") ||
+       !data->eglCreateImageKHR || !data->eglDestroyImageKHR) {
+      printf("EGL does not support EGL_KHR_image_pixmap\n");
+      return False;
+   }
+
+   exts = (const char *) glGetString(GL_EXTENSIONS);
+   data->glEGLImageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)
+      eglGetProcAddress("glEGLImageTargetTexture2DOES");
+   if (!exts || !strstr(exts, "GL_OES_EGL_image") ||
+       !data->glEGLImageTargetTexture2DOES) {
+      printf("OpenGL ES does not support GL_OES_EGL_image\n");
+      return False;
+   }
+
+   return True;
+}
+
+static void
+app_run(struct app_data *data)
+{
+   Window root;
+   int x, y;
+   unsigned int border;
+
+   if (!eglMakeCurrent(data->dpy, data->surf, data->surf, data->ctx))
+      return;
+
+   if (!app_init_exts(data))
+      return;
+
+   printf("Draw something on the left with the mouse!\n");
+
+   app_init_gl(data);
+
+   if (!XGetGeometry(data->xdpy, data->canvas, &root, &x, &y,
+            &data->width, &data->height, &border, &data->depth))
+      return;
+   data->width /= 2;
+
+   app_reshape(data);
+
+   XMapWindow(data->xdpy, data->canvas);
+   XMapWindow(data->xdpy, data->cube);
+
+   app_toggle_animate(data);
+   data->loop = True;
+
+   while (data->loop) {
+      app_next_event(data);
+
+      if (data->reshape)
+         app_reshape(data);
+      if (data->paint.active) {
+         XDrawLine(data->xdpy, data->pix, data->fg,
+               data->paint.x1, data->paint.y1,
+               data->paint.x2, data->paint.y2);
+      }
+
+      if (data->redraw)
+         app_redraw(data);
+   }
+
+   eglMakeCurrent(data->dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+}
+
+static Bool
+make_x_window(struct app_data *data, const char *name,
+              int x, int y, int width, int height)
+{
+   static const EGLint attribs[] = {
+      EGL_RED_SIZE, 1,
+      EGL_GREEN_SIZE, 1,
+      EGL_BLUE_SIZE, 1,
+      EGL_DEPTH_SIZE, 1,
+      EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+      EGL_NONE
+   };
+   static const EGLint ctx_attribs[] = {
+      EGL_CONTEXT_CLIENT_VERSION, 2,
+      EGL_NONE
+   };
+   int scrnum;
+   XSetWindowAttributes attr;
+   unsigned long mask;
+   Window root;
+   Window win;
+   XVisualInfo *visInfo, visTemplate;
+   int num_visuals;
+   EGLConfig config;
+   EGLint num_configs;
+   EGLint vid;
+
+   scrnum = DefaultScreen( data->xdpy );
+   root = RootWindow( data->xdpy, scrnum );
+
+   if (!eglChooseConfig( data->dpy, attribs, &config, 1, &num_configs)) {
+      printf("Error: couldn't get an EGL visual config\n");
+      exit(1);
+   }
+
+   assert(config);
+   assert(num_configs > 0);
+
+   if (!eglGetConfigAttrib(data->dpy, config, EGL_NATIVE_VISUAL_ID, &vid)) {
+      printf("Error: eglGetConfigAttrib() failed\n");
+      exit(1);
+   }
+
+   /* The X window visual must match the EGL config */
+   visTemplate.visualid = vid;
+   visInfo = XGetVisualInfo(data->xdpy, VisualIDMask, &visTemplate, &num_visuals);
+   if (!visInfo) {
+      printf("Error: couldn't get X visual\n");
+      exit(1);
+   }
+
+   /* window attributes */
+   attr.background_pixel = 0;
+   attr.border_pixel = 0;
+   attr.colormap = XCreateColormap( data->xdpy, root, visInfo->visual, AllocNone);
+   attr.event_mask = StructureNotifyMask | ExposureMask |
+                     KeyPressMask | ButtonPressMask | ButtonMotionMask;
+   mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
+
+   win = XCreateWindow( data->xdpy, root, 0, 0, width * 2, height,
+		        0, visInfo->depth, InputOutput,
+		        visInfo->visual, mask, &attr );
+
+   /* set hints and properties */
+   {
+      XSizeHints sizehints;
+      sizehints.x = x;
+      sizehints.y = y;
+      sizehints.width  = width;
+      sizehints.height = height;
+      sizehints.flags = USSize | USPosition;
+      XSetNormalHints(data->xdpy, win, &sizehints);
+      XSetStandardProperties(data->xdpy, win, name, name,
+                              None, (char **)NULL, 0, &sizehints);
+   }
+
+   data->canvas = win;
+
+   attr.event_mask = 0x0;
+   win = XCreateWindow( data->xdpy, win, width, 0, width, height,
+		        0, visInfo->depth, InputOutput,
+		        visInfo->visual, mask, &attr );
+   data->cube = win;
+
+   eglBindAPI(EGL_OPENGL_ES_API);
+
+   data->ctx = eglCreateContext(data->dpy, config, EGL_NO_CONTEXT, ctx_attribs );
+   if (!data->ctx) {
+      printf("Error: eglCreateContext failed\n");
+      exit(1);
+   }
+
+   data->surf = eglCreateWindowSurface(data->dpy, config, data->cube, NULL);
+   if (!data->surf) {
+      printf("Error: eglCreateWindowSurface failed\n");
+      exit(1);
+   }
+
+   XFree(visInfo);
+
+   return (data->canvas && data->cube && data->ctx && data->surf);
+}
+
+static void
+app_fini(struct app_data *data)
+{
+   if (data->img)
+      data->eglDestroyImageKHR(data->dpy, data->img);
+   if (data->pix)
+      XFreePixmap(data->xdpy, data->pix);
+
+   if (data->fg)
+      XFreeGC(data->xdpy, data->fg);
+   if (data->bg)
+      XFreeGC(data->xdpy, data->bg);
+
+   if (data->surf)
+      eglDestroySurface(data->dpy, data->surf);
+   if (data->ctx)
+      eglDestroyContext(data->dpy, data->ctx);
+
+   if (data->cube)
+      XDestroyWindow(data->xdpy, data->cube);
+   if (data->canvas)
+      XDestroyWindow(data->xdpy, data->canvas);
+
+   if (data->dpy)
+      eglTerminate(data->dpy);
+   if (data->xdpy)
+      XCloseDisplay(data->xdpy);
+}
+
+
+static Bool
+app_init(struct app_data *data, int argc, char **argv)
+{
+   XGCValues gc_vals;
+
+   memset(data, 0, sizeof(*data));
+
+   data->xdpy = XOpenDisplay(NULL);
+   if (!data->xdpy)
+      goto fail;
+
+   data->dpy = eglGetDisplay(data->xdpy);
+   if (!data->dpy || !eglInitialize(data->dpy, NULL, NULL))
+      goto fail;
+
+   if (!make_x_window(data, "EGLImage TFP", 0, 0, 300, 300))
+      goto fail;
+
+   gc_vals.function = GXcopy;
+   gc_vals.foreground = WhitePixel(data->xdpy, DefaultScreen(data->xdpy));
+   gc_vals.line_width = 3;
+   gc_vals.line_style = LineSolid;
+   gc_vals.fill_style = FillSolid;
+
+   data->fg = XCreateGC(data->xdpy, data->canvas,
+         GCFunction | GCForeground | GCLineWidth | GCLineStyle | GCFillStyle,
+         &gc_vals);
+   gc_vals.foreground = BlackPixel(data->xdpy, DefaultScreen(data->xdpy));
+   data->bg = XCreateGC(data->xdpy, data->canvas,
+         GCFunction | GCForeground | GCLineWidth | GCLineStyle | GCFillStyle,
+         &gc_vals);
+   if (!data->fg || !data->bg)
+      goto fail;
+
+
+   return True;
+
+fail:
+   app_fini(data);
+   return False;
+}
+
+int
+main(int argc, char **argv)
+{
+   struct app_data data;
+
+   if (app_init(&data, argc, argv)) {
+      app_run(&data);
+      app_fini(&data);
+   }
+
+   return 0;
+}
-- 
1.7.4.rc2.21.g8671.dirty



More information about the mesa-dev mailing list