Hi,

>From the list archive, it seems many people are, quite naturally,
interested in OpenGL ES/EGL on non-X window system.  There is already
EGL_i915.so which supports OpenGL/EGL on KMS.  This patch series makes
the driver work with OpenGL ES.  It also has the benefit of hw
acceleration which is lacking in egl_softpipe.

The patch series starts with minor clean-ups.  The fourth patch
essentially removes libmesagallium.a from EGL_i915 and EGL_r300.  This
allows them to be used with other state trackers (OpenGL, OpenGL ES, and
OpenVG).  The drivers are also renamed to follow the naming rule of
other egl drivers.  This change is tested with EGL_i915 driver.  As I do
not have a radeon card, r300 is only compile-tested.

The rest patches add OpenGL ES ports of egltri and eglgears, and update
linux-opengl-es config.

-- 
Regards,
olv
>From f9302dec81de88ba3178210805d5473787ba8097 Mon Sep 17 00:00:00 2001
From: Chia-I Wu <[email protected]>
Date: Mon, 9 Nov 2009 10:23:23 +0800
Subject: [PATCH 1/7] mesa/es: Add .gitignore.


Signed-off-by: Chia-I Wu <[email protected]>
---
 src/mesa/es/.gitignore |    5 +++++
 1 files changed, 5 insertions(+), 0 deletions(-)
 create mode 100644 src/mesa/es/.gitignore

diff --git a/src/mesa/es/.gitignore b/src/mesa/es/.gitignore
new file mode 100644
index 0000000..7643e9f
--- /dev/null
+++ b/src/mesa/es/.gitignore
@@ -0,0 +1,5 @@
+glapi/glapi-es*
+glapi/glapi-stamp
+main/get_es*.c
+main/api_exec_es*.c
+objs-es*
-- 
1.6.5

>From 71b0cce5ab0ab1816bc75fb7a2a4703daff92f4c Mon Sep 17 00:00:00 2001
From: Chia-I Wu <[email protected]>
Date: Mon, 9 Nov 2009 10:33:04 +0800
Subject: [PATCH 2/7] progs/es: Add .gitignore.


Signed-off-by: Chia-I Wu <[email protected]>
---
 progs/es1/.gitignore |    8 ++++++++
 progs/es2/.gitignore |    3 +++
 2 files changed, 11 insertions(+), 0 deletions(-)
 create mode 100644 progs/es1/.gitignore
 create mode 100644 progs/es2/.gitignore

diff --git a/progs/es1/.gitignore b/progs/es1/.gitignore
new file mode 100644
index 0000000..2e7946f
--- /dev/null
+++ b/progs/es1/.gitignore
@@ -0,0 +1,8 @@
+xegl/drawtex
+xegl/es1_info
+xegl/msaa
+xegl/pbuffer
+xegl/render_tex
+xegl/torus
+xegl/tri
+xegl/two_win
diff --git a/progs/es2/.gitignore b/progs/es2/.gitignore
new file mode 100644
index 0000000..7d5c169
--- /dev/null
+++ b/progs/es2/.gitignore
@@ -0,0 +1,3 @@
+xegl/es2_info.c
+xegl/es2_info
+xegl/tri
-- 
1.6.5

>From c3800b26149397eb70a42ba6428ea481c934d9cf Mon Sep 17 00:00:00 2001
From: Chia-I Wu <[email protected]>
Date: Tue, 10 Nov 2009 13:10:55 +0800
Subject: [PATCH 3/7] egl_softpipe: Clean up Makefile.

Fix generation of depend.  Link to the dynamic libraries used.

Signed-off-by: Chia-I Wu <[email protected]>
---
 src/gallium/winsys/egl_xlib/Makefile |   15 +++++----------
 1 files changed, 5 insertions(+), 10 deletions(-)

diff --git a/src/gallium/winsys/egl_xlib/Makefile b/src/gallium/winsys/egl_xlib/Makefile
index 3efb7ed..06c1fb0 100644
--- a/src/gallium/winsys/egl_xlib/Makefile
+++ b/src/gallium/winsys/egl_xlib/Makefile
@@ -29,13 +29,7 @@ WINSYS_OBJECTS = $(WINSYS_SOURCES:.c=.o)
 LIBS = \
 	$(GALLIUM_DRIVERS) \
 	$(GALLIUM_AUXILIARIES)
-
-# XXX temporary (should create a separate lib with the GL API funcs and
-# mesa code, as done for ES 1.x, 2.x, OpenVG, etc)
-UNUSED_LIBS = \
-	$(TOP)/src/mesa/libglapi.a \
-	$(TOP)/src/mesa/libmesagallium.a \
-
+LIB_DEPS = $(EGL_LIB_DEPS) -lm -lX11
 
 LOCAL_CFLAGS =
 
@@ -60,14 +54,15 @@ $(TOP)/$(LIB_DIR)/$(DRIVER_NAME): $(WINSYS_OBJECTS) $(LIBS)
 		-noprefix \
 		-install $(TOP)/$(LIB_DIR) \
 		$(MKLIB_OPTIONS) $(WINSYS_OBJECTS) \
-		-Wl,--whole-archive $(LIBS) -Wl,--no-whole-archive
+		-Wl,--whole-archive $(LIBS) -Wl,--no-whole-archive \
+		$(LIB_DEPS)
 
 
-depend: $(ALL_SOURCES)
+depend: $(WINSYS_SOURCES)
 	@ echo "running $(MKDEP)"
 	@ rm -f depend  # workaround oops on gutsy?!?
 	@ touch depend
-	@ $(MKDEP) $(MKDEP_OPTIONS) $(DEFINES) $(INCLUDE_DIRS) $(ALL_SOURCES) \
+	@ $(MKDEP) $(MKDEP_OPTIONS) $(DEFINES) $(INCLUDE_DIRS) $(WINSYS_SOURCES) \
 		> /dev/null 2>/dev/null
 
 
-- 
1.6.5

>From 9c45c9a285bae24f27eac0b5eb8698047c8924b2 Mon Sep 17 00:00:00 2001
From: Chia-I Wu <[email protected]>
Date: Mon, 9 Nov 2009 10:54:19 +0800
Subject: [PATCH 4/7] st/egl: Allow APIs other than OpenGL.

This is done by stopping linking to libmesagallium.a and removing DRI
related stuff.  The state tracker an application links to decides the
API supported.

Signed-off-by: Chia-I Wu <[email protected]>
---
 src/gallium/state_trackers/egl/egl_tracker.c |    2 -
 src/gallium/winsys/drm/intel/egl/Makefile    |   29 +++++++++++++++++---------
 src/gallium/winsys/drm/intel/egl/dummy.c     |    1 +
 src/gallium/winsys/drm/radeon/egl/Makefile   |   28 +++++++++++++++++-------
 src/gallium/winsys/drm/radeon/egl/dummy.c    |    1 +
 5 files changed, 41 insertions(+), 20 deletions(-)
 create mode 100644 src/gallium/winsys/drm/intel/egl/dummy.c
 create mode 100644 src/gallium/winsys/drm/radeon/egl/dummy.c

diff --git a/src/gallium/state_trackers/egl/egl_tracker.c b/src/gallium/state_trackers/egl/egl_tracker.c
index 8d29bf4..1ad0097 100644
--- a/src/gallium/state_trackers/egl/egl_tracker.c
+++ b/src/gallium/state_trackers/egl/egl_tracker.c
@@ -167,8 +167,6 @@ drm_initialize(_EGLDriver *drv, _EGLDisplay *disp, EGLint *major, EGLint *minor)
 		goto err_screen;
 	dev->winsys = dev->screen->winsys;
 
-	driInitExtensions(NULL, NULL, GL_FALSE);
-
 	drm_update_res(dev);
 	res = dev->res;
 	if (res)
diff --git a/src/gallium/winsys/drm/intel/egl/Makefile b/src/gallium/winsys/drm/intel/egl/Makefile
index 1397e9f..c9c92b6 100644
--- a/src/gallium/winsys/drm/intel/egl/Makefile
+++ b/src/gallium/winsys/drm/intel/egl/Makefile
@@ -2,7 +2,7 @@ TOP = ../../../../../..
 GALLIUMDIR = ../../../..
 include $(TOP)/configs/current
 
-LIBNAME = EGL_i915.so
+LIBNAME = egl_i915.so
 
 PIPE_DRIVERS = \
 	$(TOP)/src/gallium/state_trackers/egl/libegldrm.a \
@@ -11,19 +11,28 @@ PIPE_DRIVERS = \
 	$(TOP)/src/gallium/drivers/trace/libtrace.a \
 	$(TOP)/src/gallium/drivers/i915/libi915.a
 
-DRIVER_SOURCES =
+DRIVER_EXTRAS = -lm -lpthread -ldrm_intel
 
-C_SOURCES = \
-	$(COMMON_GALLIUM_SOURCES) \
-	$(DRIVER_SOURCES)
+OBJECTS = dummy.o
 
-DRIVER_EXTRAS = -ldrm_intel
+default: $(TOP)/$(LIB_DIR)/$(LIBNAME)
 
-ASM_SOURCES = 
+$(TOP)/$(LIB_DIR)/$(LIBNAME): $(LIBNAME)
+	@mkdir -p $(TOP)/$(LIB_DIR)
+	$(INSTALL) $(LIBNAME) $(TOP)/$(LIB_DIR)
 
-DRIVER_DEFINES = -I../gem $(shell pkg-config libdrm --atleast-version=2.3.1 \
-				&& echo "-DDRM_VBLANK_FLIP=DRM_VBLANK_FLIP")
+$(LIBNAME): $(OBJECTS) $(GALLIUM_AUXILIARIES) $(PIPE_DRIVERS) Makefile
+	$(MKLIB) -noprefix -o $@ $(OBJECTS) \
+		-Wl,--whole-archive $(PIPE_DRIVERS) -Wl,--no-whole-archive \
+		-Wl,--start-group $(GALLIUM_AUXILIARIES) -Wl,--end-group \
+                 $(DRI_LIB_DEPS) $(DRIVER_EXTRAS)
 
-include ../../Makefile.template
+clean:
+	-rm -f *.o *.so *~
+
+depend:
 
 symlinks:
+
+install: $(LIBNAME)
+	$(MINSTALL) -m 755 $(LIBNAME) $(INSTALL_DIR)/$(LIB_DIR)
diff --git a/src/gallium/winsys/drm/intel/egl/dummy.c b/src/gallium/winsys/drm/intel/egl/dummy.c
new file mode 100644
index 0000000..58c7af8
--- /dev/null
+++ b/src/gallium/winsys/drm/intel/egl/dummy.c
@@ -0,0 +1 @@
+/* mklib expects at least one .o is given */
diff --git a/src/gallium/winsys/drm/radeon/egl/Makefile b/src/gallium/winsys/drm/radeon/egl/Makefile
index 6a1448d..2bd05a8 100644
--- a/src/gallium/winsys/drm/radeon/egl/Makefile
+++ b/src/gallium/winsys/drm/radeon/egl/Makefile
@@ -2,7 +2,7 @@ TOP = ../../../../../..
 GALLIUMDIR = ../../../..
 include $(TOP)/configs/current
 
-LIBNAME = EGL_r300.so
+LIBNAME = egl_r300.so
 
 PIPE_DRIVERS = \
 	$(TOP)/src/gallium/state_trackers/egl/libegldrm.a \
@@ -11,16 +11,28 @@ PIPE_DRIVERS = \
 	$(TOP)/src/gallium/drivers/trace/libtrace.a \
 	$(TOP)/src/gallium/drivers/r300/libr300.a
 
-DRIVER_SOURCES =
+DRIVER_EXTRAS = -lm -lpthread -ldrm_radeon
 
-C_SOURCES = \
-	$(COMMON_GALLIUM_SOURCES) \
-	$(DRIVER_SOURCES)
+OBJECTS = dummy.o
 
-DRIVER_EXTRAS = -ldrm_radeon
+default: $(TOP)/$(LIB_DIR)/$(LIBNAME)
 
-ASM_SOURCES = 
+$(TOP)/$(LIB_DIR)/$(LIBNAME): $(LIBNAME)
+	@mkdir -p $(TOP)/$(LIB_DIR)
+	$(INSTALL) $(LIBNAME) $(TOP)/$(LIB_DIR)
 
-include ../../Makefile.template
+$(LIBNAME): $(OBJECTS) $(GALLIUM_AUXILIARIES) $(PIPE_DRIVERS) Makefile
+	$(MKLIB) -noprefix -o $@ $(OBJECTS) \
+		-Wl,--whole-archive $(PIPE_DRIVERS) -Wl,--no-whole-archive \
+		-Wl,--start-group $(GALLIUM_AUXILIARIES) -Wl,--end-group \
+                 $(DRI_LIB_DEPS) $(DRIVER_EXTRAS)
+
+clean:
+	-rm -f *.o *.so *~
+
+depend:
 
 symlinks:
+
+install: $(LIBNAME)
+	$(MINSTALL) -m 755 $(LIBNAME) $(INSTALL_DIR)/$(LIB_DIR)
diff --git a/src/gallium/winsys/drm/radeon/egl/dummy.c b/src/gallium/winsys/drm/radeon/egl/dummy.c
new file mode 100644
index 0000000..58c7af8
--- /dev/null
+++ b/src/gallium/winsys/drm/radeon/egl/dummy.c
@@ -0,0 +1 @@
+/* mklib expects at least one .o is given */
-- 
1.6.5

>From 05faded0cbe219672392e4b686afcf27db3e8e3f Mon Sep 17 00:00:00 2001
From: Chia-I Wu <[email protected]>
Date: Mon, 9 Nov 2009 11:13:38 +0800
Subject: [PATCH 5/7] progs/es1: Port egltri to OpenGL ES 1.1.

This demo requires EGL_MESA_screen_surface to run.

Signed-off-by: Chia-I Wu <[email protected]>
---
 progs/es1/.gitignore      |    1 +
 progs/es1/screen/Makefile |   28 +++++
 progs/es1/screen/tri.c    |  129 +++++++++++++++++++++
 progs/es1/screen/winsys.c |  272 +++++++++++++++++++++++++++++++++++++++++++++
 progs/es1/screen/winsys.h |   36 ++++++
 5 files changed, 466 insertions(+), 0 deletions(-)
 create mode 100644 progs/es1/screen/Makefile
 create mode 100644 progs/es1/screen/tri.c
 create mode 100644 progs/es1/screen/winsys.c
 create mode 100644 progs/es1/screen/winsys.h

diff --git a/progs/es1/.gitignore b/progs/es1/.gitignore
index 2e7946f..ac79ee4 100644
--- a/progs/es1/.gitignore
+++ b/progs/es1/.gitignore
@@ -1,3 +1,4 @@
+screen/tri
 xegl/drawtex
 xegl/es1_info
 xegl/msaa
diff --git a/progs/es1/screen/Makefile b/progs/es1/screen/Makefile
new file mode 100644
index 0000000..27be054
--- /dev/null
+++ b/progs/es1/screen/Makefile
@@ -0,0 +1,28 @@
+# progs/es1/screen/Makefile
+
+TOP = ../../..
+include $(TOP)/configs/current
+
+ES1_CFLAGS = -I$(TOP)/include
+ES1_LIBS = -L$(TOP)/$(LIB_DIR) -lEGL -lGLESv1_CM
+
+ES1_LIB_DEPS = \
+	$(TOP)/$(LIB_DIR)/libEGL.so \
+	$(TOP)/$(LIB_DIR)/libGLESv1_CM.so
+
+WINSYS_OBJS = winsys.o
+
+PROGRAMS = \
+	tri
+
+.c.o:
+	$(CC) -c $(ES1_CFLAGS) $(CFLAGS) $< -o $@
+
+default: $(PROGRAMS)
+
+tri: tri.o $(WINSYS_OBJS) $(ES1_LIB_DEPS)
+	$(CC) $(CFLAGS) -o $@ [email protected] $(WINSYS_OBJS) $(ES1_LIBS)
+
+clean:
+	-rm -f *.o *~
+	-rm -f $(PROGRAMS)
diff --git a/progs/es1/screen/tri.c b/progs/es1/screen/tri.c
new file mode 100644
index 0000000..bab9499
--- /dev/null
+++ b/progs/es1/screen/tri.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2009 Chia-I Wu <[email protected]>
+ *
+ * Based on egltri by
+ * Copyright (C) 1999-2001  Brian Paul   All Rights Reserved.
+ * Copyright (C) 2008  Brian Paul   All Rights Reserved.
+ * Copyright (C) 2008  Jakob Bornecrantz   All Rights Reserved.
+ *
+ * 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
+ * BRIAN PAUL 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <GLES/gl.h>
+#include "winsys.h"
+
+static GLfloat view_rotx = 0.0, view_roty = 0.0, view_rotz = 0.0;
+
+static void tri_init()
+{
+   glClearColor(0.4, 0.4, 0.4, 0.0);
+}
+
+static void tri_reshape(int width, int height)
+{
+   GLfloat ar = (GLfloat) width / (GLfloat) height;
+
+   glViewport(0, 0, (GLint) width, (GLint) height);
+
+   glMatrixMode(GL_PROJECTION);
+   glLoadIdentity();
+   glFrustumf(-ar, ar, -1, 1, 5.0, 60.0);
+
+   glMatrixMode(GL_MODELVIEW);
+   glLoadIdentity();
+   glTranslatef(0.0, 0.0, -10.0);
+}
+
+static void tri_draw(void *data)
+{
+   static const GLfloat verts[3][2] = {
+      { -1, -1 },
+      {  1, -1 },
+      {  0,  1 }
+   };
+   static const GLfloat colors[3][4] = {
+      { 1, 0, 0, 1 },
+      { 0, 1, 0, 1 },
+      { 0, 0, 1, 1 }
+   };
+
+   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+   glPushMatrix();
+   glRotatef(view_rotx, 1, 0, 0);
+   glRotatef(view_roty, 0, 1, 0);
+   glRotatef(view_rotz, 0, 0, 1);
+
+   {
+      glVertexPointer(2, GL_FLOAT, 0, verts);
+      glColorPointer(4, GL_FLOAT, 0, colors);
+      glEnableClientState(GL_VERTEX_ARRAY);
+      glEnableClientState(GL_COLOR_ARRAY);
+
+      glDrawArrays(GL_TRIANGLES, 0, 3);
+
+      glDisableClientState(GL_VERTEX_ARRAY);
+      glDisableClientState(GL_COLOR_ARRAY);
+   }
+
+   glPopMatrix();
+}
+
+static void tri_run(void)
+{
+   winsysRun(3.0, tri_draw, NULL);
+}
+
+int main(int argc, char *argv[])
+{
+   EGLint width, height;
+   GLboolean printInfo = GL_FALSE;
+   int i;
+
+   /* parse cmd line args */
+   for (i = 1; i < argc; i++) {
+      if (strcmp(argv[i], "-info") == 0) {
+         printInfo = GL_TRUE;
+      }
+      else {
+         printf("Warning: unknown parameter: %s\n", argv[i]);
+      }
+   }
+
+   if (!winsysInitScreen())
+      exit(1);
+   winsysQueryScreenSize(&width, &height);
+
+   if (printInfo) {
+      printf("GL_RENDERER   = %s\n", (char *) glGetString(GL_RENDERER));
+      printf("GL_VERSION    = %s\n", (char *) glGetString(GL_VERSION));
+      printf("GL_VENDOR     = %s\n", (char *) glGetString(GL_VENDOR));
+      printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS));
+   }
+
+   tri_init();
+   tri_reshape(width, height);
+   tri_run();
+
+   winsysFiniScreen();
+
+   return 0;
+}
diff --git a/progs/es1/screen/winsys.c b/progs/es1/screen/winsys.c
new file mode 100644
index 0000000..84d0047
--- /dev/null
+++ b/progs/es1/screen/winsys.c
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 2009 Chia-I Wu <[email protected]>
+ *
+ * Based on eglgears by
+ * Copyright (C) 1999-2001  Brian Paul   All Rights Reserved.
+ *
+ * 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
+ * BRIAN PAUL 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <sys/time.h>
+
+#define EGL_EGLEXT_PROTOTYPES
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include "winsys.h"
+
+#define MAX_MODES 100
+
+static struct {
+   EGLBoolean verbose;
+
+   EGLDisplay dpy;
+   EGLConfig conf;
+
+   EGLScreenMESA screen;
+   EGLModeMESA mode;
+   EGLint width, height;
+
+   EGLContext ctx;
+   EGLSurface surf;
+} screen;
+
+
+static EGLBoolean
+init_screen(void)
+{
+   EGLModeMESA modes[MAX_MODES];
+   EGLint num_screens, num_modes;
+   EGLint width, height, best_mode;
+   EGLint i;
+
+   if (!eglGetScreensMESA(screen.dpy, &screen.screen, 1, &num_screens) ||
+       !num_screens) {
+      printf("eglGetScreensMESA failed\n");
+      return EGL_FALSE;
+   }
+
+   if (!eglGetModesMESA(screen.dpy, screen.screen, modes, MAX_MODES,
+                        &num_modes) ||
+       !num_modes) {
+      printf("eglGetModesMESA failed!\n");
+      return EGL_FALSE;
+   }
+
+   printf("Found %d modes:\n", num_modes);
+
+   best_mode = 0;
+   width = 0;
+   height = 0;
+   for (i = 0; i < num_modes; i++) {
+      EGLint w, h;
+      eglGetModeAttribMESA(screen.dpy, modes[i], EGL_WIDTH, &w);
+      eglGetModeAttribMESA(screen.dpy, modes[i], EGL_HEIGHT, &h);
+      printf("%3d: %d x %d\n", i, w, h);
+      if (w > width && h > height) {
+         width = w;
+         height = h;
+         best_mode = i;
+      }
+   }
+
+   screen.mode = modes[best_mode];
+   screen.width = width;
+   screen.height = height;
+
+   return EGL_TRUE;
+}
+
+
+static EGLBoolean
+init_display(void)
+{
+   EGLint maj, min;
+   const char *exts;
+   const EGLint attribs[] = {
+      EGL_SURFACE_TYPE, 0x0,    /* should be EGL_SCREEN_BIT_MESA */
+      EGL_RENDERABLE_TYPE, 0x0, /* should be EGL_OPENGL_ES_BIT */
+      EGL_NONE
+   };
+   EGLint num_configs;
+
+   screen.dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+   if (!screen.dpy) {
+      printf("eglGetDisplay failed\n");
+      return EGL_FALSE;
+   }
+
+   if (!eglInitialize(screen.dpy, &maj, &min)) {
+      printf("eglInitialize failed\n");
+      return EGL_FALSE;
+   }
+
+   printf("EGL_VERSION = %s\n", eglQueryString(screen.dpy, EGL_VERSION));
+   printf("EGL_VENDOR = %s\n", eglQueryString(screen.dpy, EGL_VENDOR));
+
+   exts = eglQueryString(screen.dpy, EGL_EXTENSIONS);
+   assert(exts);
+
+   if (!strstr(exts, "EGL_MESA_screen_surface")) {
+      printf("EGL_MESA_screen_surface is not supported\n");
+      return EGL_FALSE;
+   }
+
+   if (!eglChooseConfig(screen.dpy, attribs, &screen.conf, 1,
+                        &num_configs) ||
+       !num_configs) {
+      printf("eglChooseConfig failed\n");
+      return EGL_FALSE;
+   }
+
+   return EGL_TRUE;
+}
+
+
+EGLBoolean
+winsysInitScreen(void)
+{
+        EGLint surf_attribs[20];
+        EGLint i;
+        EGLBoolean ok;
+
+        if (!init_display())
+           goto fail;
+        if (!init_screen())
+           goto fail;
+
+        /* create context */
+	screen.ctx = eglCreateContext(screen.dpy, screen.conf,
+                                      EGL_NO_CONTEXT, NULL);
+	if (screen.ctx == EGL_NO_CONTEXT) {
+		printf("eglCreateContext failed\n");
+                goto fail;
+	}
+
+	i = 0;
+	surf_attribs[i++] = EGL_WIDTH;
+	surf_attribs[i++] = screen.width;
+	surf_attribs[i++] = EGL_HEIGHT;
+	surf_attribs[i++] = screen.height;
+	surf_attribs[i++] = EGL_NONE;
+
+        /* create surface */
+        printf("Using screen size: %d x %d\n", screen.width, screen.height);
+        screen.surf = eglCreateScreenSurfaceMESA(screen.dpy, screen.conf,
+                                                 surf_attribs);
+	if (screen.surf == EGL_NO_SURFACE) {
+		printf("eglCreateScreenSurfaceMESA failed\n");
+                goto fail;
+	}
+
+	ok = eglMakeCurrent(screen.dpy, screen.surf, screen.surf, screen.ctx);
+	if (!ok) {
+		printf("eglMakeCurrent failed\n");
+		goto fail;
+	}
+
+	ok = eglShowScreenSurfaceMESA(screen.dpy, screen.screen,
+                                      screen.surf, screen.mode);
+	if (!ok) {
+		printf("eglShowScreenSurfaceMESA failed\n");
+                goto fail;
+	}
+
+        return EGL_TRUE;
+
+fail:
+        winsysFiniScreen();
+        return EGL_FALSE;
+}
+
+
+EGLBoolean
+winsysQueryScreenSize(EGLint *width, EGLint *height)
+{
+   if (!screen.dpy)
+      return EGL_FALSE;
+
+   if (width)
+      *width = screen.width;
+   if (height)
+      *height = screen.height;
+
+   return EGL_TRUE;
+}
+
+
+void
+winsysFiniScreen(void)
+{
+   if (screen.dpy) {
+      eglMakeCurrent(screen.dpy, EGL_NO_SURFACE, EGL_NO_SURFACE,
+                     EGL_NO_CONTEXT);
+      if (screen.surf != EGL_NO_SURFACE)
+         eglDestroySurface(screen.dpy, screen.surf);
+      if (screen.ctx != EGL_NO_CONTEXT)
+         eglDestroyContext(screen.dpy, screen.ctx);
+      eglTerminate(screen.dpy);
+
+      memset(&screen, 0, sizeof(screen));
+   }
+}
+
+
+void
+winsysSwapBuffers(void)
+{
+   eglSwapBuffers(screen.dpy, screen.surf);
+}
+
+
+/* return current time (in seconds) */
+double
+winsysNow(void)
+{
+   struct timeval tv;
+   gettimeofday(&tv, NULL);
+   return (double) tv.tv_sec + tv.tv_usec / 1000000.0;
+}
+
+
+void
+winsysRun(double seconds, void (*draw_frame)(void *data), void *data)
+{
+        double begin, end, last_frame, duration;
+	EGLint num_frames = 0;
+
+        begin = winsysNow();
+        end = begin + seconds;
+
+        last_frame = begin;
+        while (last_frame < end) {
+           draw_frame(data);
+           winsysSwapBuffers();
+           last_frame = winsysNow();
+           num_frames++;
+        }
+
+        duration = last_frame - begin;
+	printf("%d frames in %3.1f seconds = %6.3f FPS\n",
+               num_frames, duration, (double) num_frames / duration);
+}
diff --git a/progs/es1/screen/winsys.h b/progs/es1/screen/winsys.h
new file mode 100644
index 0000000..679c7e0
--- /dev/null
+++ b/progs/es1/screen/winsys.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2009 Chia-I Wu <[email protected]>
+ *
+ * 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
+ * BRIAN PAUL 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.
+ */
+
+#ifndef _WINSYS_H_
+#define _WINSYS_H_
+
+#include <EGL/egl.h>
+
+EGLBoolean winsysInitScreen(void);
+EGLBoolean winsysQueryScreenSize(EGLint *width, EGLint *height);
+void winsysFiniScreen(void);
+
+void winsysSwapBuffers(void);
+double winsysNow(void);
+
+void winsysRun(double seconds, void (*draw_frame)(void *data), void *data);
+
+#endif /* _WINSYS_H_ */
-- 
1.6.5

>From 66545096c832b3f3bb6360d6ed7ca47b6ca7533d Mon Sep 17 00:00:00 2001
From: Chia-I Wu <[email protected]>
Date: Mon, 9 Nov 2009 13:25:49 +0800
Subject: [PATCH 6/7] progs/es1: Port eglgears to OpenGL ES 1.1.

This demo requires EGL_MESA_screen_surface to run.

Signed-off-by: Chia-I Wu <[email protected]>
---
 progs/es1/.gitignore      |    1 +
 progs/es1/screen/Makefile |    4 +
 progs/es1/screen/gears.c  |  374 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 379 insertions(+), 0 deletions(-)
 create mode 100644 progs/es1/screen/gears.c

diff --git a/progs/es1/.gitignore b/progs/es1/.gitignore
index ac79ee4..4f14275 100644
--- a/progs/es1/.gitignore
+++ b/progs/es1/.gitignore
@@ -1,3 +1,4 @@
+screen/gears
 screen/tri
 xegl/drawtex
 xegl/es1_info
diff --git a/progs/es1/screen/Makefile b/progs/es1/screen/Makefile
index 27be054..4ba2f9a 100644
--- a/progs/es1/screen/Makefile
+++ b/progs/es1/screen/Makefile
@@ -13,6 +13,7 @@ ES1_LIB_DEPS = \
 WINSYS_OBJS = winsys.o
 
 PROGRAMS = \
+	gears \
 	tri
 
 .c.o:
@@ -20,6 +21,9 @@ PROGRAMS = \
 
 default: $(PROGRAMS)
 
+gears: gears.o $(WINSYS_OBJS) $(ES1_LIB_DEPS)
+	$(CC) $(CFLAGS) -o $@ [email protected] $(WINSYS_OBJS) $(ES1_LIBS)
+
 tri: tri.o $(WINSYS_OBJS) $(ES1_LIB_DEPS)
 	$(CC) $(CFLAGS) -o $@ [email protected] $(WINSYS_OBJS) $(ES1_LIBS)
 
diff --git a/progs/es1/screen/gears.c b/progs/es1/screen/gears.c
new file mode 100644
index 0000000..c762582
--- /dev/null
+++ b/progs/es1/screen/gears.c
@@ -0,0 +1,374 @@
+/*
+ * Copyright (C) 2009 Chia-I Wu <[email protected]>
+ *
+ * Based on eglgears by
+ * Copyright (C) 1999-2001  Brian Paul   All Rights Reserved.
+ *
+ * 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
+ * BRIAN PAUL 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.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <assert.h>
+
+#include <GLES/gl.h>
+#include "winsys.h"
+
+#ifndef M_PI
+#define M_PI 3.14159265
+#endif
+
+
+struct gear {
+   GLuint vbo;
+   GLfloat *vertices;
+   GLsizei stride;
+
+   GLint num_teeth;
+};
+
+static GLfloat view_rotx = 20.0, view_roty = 30.0, view_rotz = 0.0;
+static struct gear gears[3];
+static GLfloat angle = 0.0;
+
+/*
+ *  Initialize a gear wheel.
+ *
+ *  Input:  gear - gear to initialize
+ *          inner_radius - radius of hole at center
+ *          outer_radius - radius at center of teeth
+ *          width - width of gear
+ *          teeth - number of teeth
+ *          tooth_depth - depth of tooth
+ */
+static void
+init_gear(struct gear *gear, GLfloat inner_radius, GLfloat outer_radius,
+          GLfloat width, GLint teeth, GLfloat tooth_depth)
+{
+   GLfloat r0, r1, r2;
+   GLfloat a0, da;
+   GLint verts_per_tooth, total_verts, total_size;
+   GLint count, i;
+   GLfloat *verts;
+
+   r0 = inner_radius;
+   r1 = outer_radius - tooth_depth / 2.0;
+   r2 = outer_radius + tooth_depth / 2.0;
+
+   a0 = 2.0 * M_PI / teeth;
+   da = a0 / 4.0;
+
+   gear->vbo = 0;
+   gear->vertices = NULL;
+   gear->stride = sizeof(GLfloat) * 6; /* XYZ + normal */
+   gear->num_teeth = teeth;
+
+   verts_per_tooth = 10 + 4;
+   total_verts = teeth * verts_per_tooth;
+   total_size = total_verts * gear->stride;
+
+   verts = malloc(total_size);
+   if (!verts) {
+      printf("failed to allocate vertices\n");
+      return;
+   }
+
+#define GEAR_VERT(r, n, sign)                      \
+   do {                                            \
+      verts[count * 6 + 0] = (r) * vx[n];          \
+      verts[count * 6 + 1] = (r) * vy[n];          \
+      verts[count * 6 + 2] = (sign) * width * 0.5; \
+      verts[count * 6 + 3] = normal[0];            \
+      verts[count * 6 + 4] = normal[1];            \
+      verts[count * 6 + 5] = normal[2];            \
+      count++;                                     \
+   } while (0)
+
+   count = 0;
+   for (i = 0; i < teeth; i++) {
+      GLfloat normal[3];
+      GLfloat vx[5], vy[5];
+      GLfloat u, v;
+
+      normal[0] = 0.0;
+      normal[1] = 0.0;
+      normal[2] = 0.0;
+
+      vx[0] = cos(i * a0 + 0 * da);
+      vy[0] = sin(i * a0 + 0 * da);
+      vx[1] = cos(i * a0 + 1 * da);
+      vy[1] = sin(i * a0 + 1 * da);
+      vx[2] = cos(i * a0 + 2 * da);
+      vy[2] = sin(i * a0 + 2 * da);
+      vx[3] = cos(i * a0 + 3 * da);
+      vy[3] = sin(i * a0 + 3 * da);
+      vx[4] = cos(i * a0 + 4 * da);
+      vy[4] = sin(i * a0 + 4 * da);
+
+      /* outward faces of a tooth, 10 verts */
+      normal[0] = vx[0];
+      normal[1] = vy[0];
+      GEAR_VERT(r1, 0,  1);
+      GEAR_VERT(r1, 0, -1);
+
+      u = r2 * vx[1] - r1 * vx[0];
+      v = r2 * vy[1] - r1 * vy[0];
+      normal[0] = v;
+      normal[1] = -u;
+      GEAR_VERT(r2, 1,  1);
+      GEAR_VERT(r2, 1, -1);
+
+      normal[0] = vx[0];
+      normal[1] = vy[0];
+      GEAR_VERT(r2, 2,  1);
+      GEAR_VERT(r2, 2, -1);
+
+      u = r1 * vx[3] - r2 * vx[2];
+      v = r1 * vy[3] - r2 * vy[2];
+      normal[0] = v;
+      normal[1] = -u;
+      GEAR_VERT(r1, 3,  1);
+      GEAR_VERT(r1, 3, -1);
+
+      normal[0] = vx[0];
+      normal[1] = vy[0];
+      GEAR_VERT(r1, 4,  1);
+      GEAR_VERT(r1, 4, -1);
+
+      /* inside radius cylinder, 4 verts */
+      normal[0] = -vx[4];
+      normal[1] = -vy[4];
+      GEAR_VERT(r0, 4,  1);
+      GEAR_VERT(r0, 4, -1);
+
+      normal[0] = -vx[0];
+      normal[1] = -vy[0];
+      GEAR_VERT(r0, 0,  1);
+      GEAR_VERT(r0, 0, -1);
+
+      assert(count % verts_per_tooth == 0);
+   }
+   assert(count == total_verts);
+#undef GEAR_VERT
+
+   gear->vertices = verts;
+
+   /* setup VBO */
+   glGenBuffers(1, &gear->vbo);
+   if (gear->vbo) {
+      glBindBuffer(GL_ARRAY_BUFFER, gear->vbo);
+      glBufferData(GL_ARRAY_BUFFER, total_size, verts, GL_STATIC_DRAW);
+   }
+}
+
+
+static void
+draw_gear(const struct gear *gear)
+{
+   GLint i;
+
+   if (!gear->vbo && !gear->vertices) {
+      printf("nothing to be drawn\n");
+      return;
+   }
+
+   if (gear->vbo) {
+      glBindBuffer(GL_ARRAY_BUFFER, gear->vbo);
+      glVertexPointer(3, GL_FLOAT, gear->stride, (const GLvoid *) 0);
+      glNormalPointer(GL_FLOAT, gear->stride, (const GLvoid *) (sizeof(GLfloat) * 3));
+   } else {
+      glBindBuffer(GL_ARRAY_BUFFER, 0);
+      glVertexPointer(3, GL_FLOAT, gear->stride, gear->vertices);
+      glNormalPointer(GL_FLOAT, gear->stride, gear->vertices + 3);
+   }
+
+   glEnableClientState(GL_VERTEX_ARRAY);
+
+   for (i = 0; i < gear->num_teeth; i++) {
+      const GLint base = (10 + 4) * i;
+      GLushort indices[7];
+
+      glShadeModel(GL_FLAT);
+
+      /* front face */
+      indices[0] = base + 12;
+      indices[1] = base +  0;
+      indices[2] = base +  2;
+      indices[3] = base +  4;
+      indices[4] = base +  6;
+      indices[5] = base +  8;
+      indices[6] = base + 10;
+
+      glNormal3f(0.0, 0.0, 1.0);
+      glDrawElements(GL_TRIANGLE_FAN, 7, GL_UNSIGNED_SHORT, indices);
+
+      /* back face */
+      indices[0] = base + 13;
+      indices[1] = base + 11;
+      indices[2] = base +  9;
+      indices[3] = base +  7;
+      indices[4] = base +  5;
+      indices[5] = base +  3;
+      indices[6] = base +  1;
+
+      glNormal3f(0.0, 0.0, -1.0);
+      glDrawElements(GL_TRIANGLE_FAN, 7, GL_UNSIGNED_SHORT, indices);
+
+      glEnableClientState(GL_NORMAL_ARRAY);
+
+      /* outward face of a tooth */
+      glDrawArrays(GL_TRIANGLE_STRIP, base, 10);
+
+      /* inside radius cylinder */
+      glShadeModel(GL_SMOOTH);
+      glDrawArrays(GL_TRIANGLE_STRIP, base + 10, 4);
+
+      glDisableClientState(GL_NORMAL_ARRAY);
+   }
+
+   glDisableClientState(GL_VERTEX_ARRAY);
+}
+
+
+static void
+gears_draw(void *data)
+{
+   static const GLfloat red[4] = { 0.8, 0.1, 0.0, 1.0 };
+   static const GLfloat green[4] = { 0.0, 0.8, 0.2, 1.0 };
+   static const GLfloat blue[4] = { 0.2, 0.2, 1.0, 1.0 };
+
+   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+   glPushMatrix();
+   glRotatef(view_rotx, 1.0, 0.0, 0.0);
+   glRotatef(view_roty, 0.0, 1.0, 0.0);
+   glRotatef(view_rotz, 0.0, 0.0, 1.0);
+
+   glPushMatrix();
+   glTranslatef(-3.0, -2.0, 0.0);
+   glRotatef(angle, 0.0, 0.0, 1.0);
+
+   glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, red);
+   draw_gear(&gears[0]);
+
+   glPopMatrix();
+
+   glPushMatrix();
+   glTranslatef(3.1, -2.0, 0.0);
+   glRotatef(-2.0 * angle - 9.0, 0.0, 0.0, 1.0);
+
+   glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, green);
+   draw_gear(&gears[1]);
+
+   glPopMatrix();
+
+   glPushMatrix();
+   glTranslatef(-3.1, 4.2, 0.0);
+   glRotatef(-2.0 * angle - 25.0, 0.0, 0.0, 1.0);
+
+   glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, blue);
+   draw_gear(&gears[2]);
+
+   glPopMatrix();
+
+   glPopMatrix();
+
+   /* advance rotation for next frame */
+   angle += 0.5; /* 0.5 degree per frame */
+   if (angle > 3600.0)
+      angle -= 3600.0;
+}
+
+
+static void gears_fini(void)
+{
+   GLint i;
+   for (i = 0; i < 3; i++) {
+      struct gear *gear = &gears[i];
+      if (gear->vbo) {
+         glDeleteBuffers(1, &gear->vbo);
+         gear->vbo = 0;
+      }
+      if (gear->vertices) {
+         free(gear->vertices);
+         gear->vertices = NULL;
+      }
+   }
+}
+
+
+static void gears_init(void)
+{
+   static const GLfloat pos[4] = { 5.0, 5.0, 10.0, 0.0 };
+
+   glLightfv(GL_LIGHT0, GL_POSITION, pos);
+   glEnable(GL_CULL_FACE);
+   glEnable(GL_LIGHTING);
+   glEnable(GL_LIGHT0);
+   glEnable(GL_DEPTH_TEST);
+   glEnable(GL_NORMALIZE);
+
+   init_gear(&gears[0], 1.0, 4.0, 1.0, 20, 0.7);
+   init_gear(&gears[1], 0.5, 2.0, 2.0, 10, 0.7);
+   init_gear(&gears[2], 1.3, 2.0, 0.5, 10, 0.7);
+}
+
+
+/* new window size or exposure */
+static void
+gears_reshape(int width, int height)
+{
+   GLfloat h = (GLfloat) height / (GLfloat) width;
+
+   glViewport(0, 0, (GLint) width, (GLint) height);
+
+   glMatrixMode(GL_PROJECTION);
+   glLoadIdentity();
+   glFrustumf(-1.0, 1.0, -h, h, 5.0, 60.0);
+
+   glMatrixMode(GL_MODELVIEW);
+   glLoadIdentity();
+   glTranslatef(0.0, 0.0, -40.0);
+}
+
+
+static void gears_run(void)
+{
+   winsysRun(5.0, gears_draw, NULL);
+}
+
+
+int
+main(int argc, char *argv[])
+{
+   EGLint width, height;
+
+   if (!winsysInitScreen())
+      exit(1);
+   winsysQueryScreenSize(&width, &height);
+
+   gears_init();
+   gears_reshape(width, height);
+   gears_run();
+   gears_fini();
+
+   winsysFiniScreen();
+
+   return 0;
+}
-- 
1.6.5

>From dc2c91e9fdd0f4afd7691bb0dbeaf4fdcc95d77b Mon Sep 17 00:00:00 2001
From: Chia-I Wu <[email protected]>
Date: Tue, 10 Nov 2009 12:48:14 +0800
Subject: [PATCH 7/7] Update config linux-opengl-es.

Build demos that require EGL_MESA_screen_surface, and build egl_i915.so
that supports EGL_MESA_screen_surface.

Signed-off-by: Chia-I Wu <[email protected]>
---
 configs/linux-opengl-es |    8 +++++++-
 1 files changed, 7 insertions(+), 1 deletions(-)

diff --git a/configs/linux-opengl-es b/configs/linux-opengl-es
index 2ba94b6..1254f06 100644
--- a/configs/linux-opengl-es
+++ b/configs/linux-opengl-es
@@ -7,7 +7,7 @@ CONFIG_NAME = linux-opengl-es
 # Directories to build
 LIB_DIR = lib
 SRC_DIRS = egl mesa/es gallium gallium/winsys
-PROGRAM_DIRS = es1/xegl es2/xegl
+PROGRAM_DIRS = es1/screen es1/xegl es2/xegl
 
 # no mesa or egl drivers
 DRIVER_DIRS =
@@ -19,3 +19,9 @@ GALLIUM_DRIVERS_DIRS = softpipe
 GALLIUM_WINSYS_DIRS = egl_xlib
 # and libGLES*.so
 GALLIUM_STATE_TRACKERS_DIRS = es
+
+# build egl_i915.so
+GALLIUM_DRIVERS_DIRS += trace i915
+GALLIUM_STATE_TRACKERS_DIRS += egl
+GALLIUM_WINSYS_DIRS += drm
+GALLIUM_WINSYS_DRM_DIRS = intel
-- 
1.6.5

------------------------------------------------------------------------------
Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day 
trial. Simplify your report design, integration and deployment - and focus on 
what you do best, core application coding. Discover what's new with
Crystal Reports now.  http://p.sf.net/sfu/bobj-july
_______________________________________________
Mesa3d-dev mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mesa3d-dev

Reply via email to