summaryrefslogtreecommitdiff
path: root/package
diff options
context:
space:
mode:
authorPhil Sutter <phil@nwl.cc>2010-06-15 22:28:54 +0200
committerPhil Sutter <phil@nwl.cc>2010-06-20 16:23:52 +0200
commit48ad3e135426d7f0116e4ad8efc85d20aad64910 (patch)
tree08b2fb27aa77da0ead2f90eaa94b80f52ccaa54b /package
parent0549414af010737828696592acec9b263cd0513a (diff)
MesaLib: add glxinfo and glxgears subpackages
As these xdemos reside in their own package but without the necessary infrastructure (this config thingy), I've created a patch from the addon-package.
Diffstat (limited to 'package')
-rw-r--r--package/MesaLib/Makefile17
-rw-r--r--package/MesaLib/patches/000-mesalib-xdemos.patch14774
2 files changed, 14789 insertions, 2 deletions
diff --git a/package/MesaLib/Makefile b/package/MesaLib/Makefile
index a5f624374..5836f994f 100644
--- a/package/MesaLib/Makefile
+++ b/package/MesaLib/Makefile
@@ -15,6 +15,11 @@ PKG_BUILDDEP+= dri2proto glproto expat
PKG_URL:= http://www.mesa3d.org/
PKG_SITES:= ftp://ftp.freedesktop.org/pub/mesa/7.8.1/
+PKG_DESCR_GLXINFO:= Display various GLX information
+PKG_SECT_GLXINFO:= x11
+PKG_DESCR_GLXGEARS:= Nice little OpenGL demo application
+PKG_SECT_GLXGEARS:= x11
+
WRKDIST= ${WRKDIR}/Mesa-${PKG_VERSION}
PKG_TARGET_DEPENDS:= ibmx40 lemote
@@ -22,6 +27,8 @@ PKG_TARGET_DEPENDS:= ibmx40 lemote
include $(TOPDIR)/mk/package.mk
$(eval $(call PKG_template,MESALIB,mesalib,$(PKG_VERSION)-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION}))
+$(eval $(call PKG_template,GLXINFO,glxinfo,$(PKG_VERSION)-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR_GLXINFO},${PKG_SECT_GLXINFO}))
+$(eval $(call PKG_template,GLXGEARS,glxgears,$(PKG_VERSION)-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR_GLXGEARS},${PKG_SECT_GLXGEARS}))
ifeq (${ADK_LINUX_X86_IBMX40},y)
DRI_DRIVERS:=i810
@@ -39,7 +46,7 @@ CONFIGURE_ARGS+= --disable-static \
--disable-glw \
--with-driver=dri \
--with-dri-drivers=${DRI_DRIVERS} \
- --without-demos
+ --with-demos=xdemos
XAKE_FLAGS+= APP_CC=${HOSTCC} HOST_CC=${HOSTCC}
@@ -50,7 +57,7 @@ pre-configure:
--disable-glw \
--disable-gallium \
--with-driver=xlib \
- --without-demos \
+ --with-demos=xdemos \
);
${MAKE} -C ${WRKBUILD}/src/glsl
${MAKE} -C ${WRKBUILD}/src/glsl/apps
@@ -66,5 +73,11 @@ ifeq (${ADK_LINUX_MIPS64_LEMOTE},y)
$(INSTALL_BIN) $(WRKINST)/usr/lib/dri/swrast_dri.so \
${IDIR_MESALIB}/usr/lib/dri/
endif
+ ${INSTALL_DIR} ${IDIR_GLXINFO}/usr/bin
+ ${INSTALL_BIN} ${WRKBUILD}/progs/xdemos/glxinfo \
+ ${IDIR_GLXINFO}/usr/bin/
+ ${INSTALL_DIR} ${IDIR_GLXGEARS}/usr/bin
+ ${INSTALL_BIN} ${WRKBUILD}/progs/xdemos/glxgears \
+ ${IDIR_GLXGEARS}/usr/bin/
include ${TOPDIR}/mk/pkg-bottom.mk
diff --git a/package/MesaLib/patches/000-mesalib-xdemos.patch b/package/MesaLib/patches/000-mesalib-xdemos.patch
new file mode 100644
index 000000000..866e68c2e
--- /dev/null
+++ b/package/MesaLib/patches/000-mesalib-xdemos.patch
@@ -0,0 +1,14774 @@
+diff -Naurp Mesa-7.8.1/progs/xdemos/corender.c Mesa-7.8.1.patched/progs/xdemos/corender.c
+--- Mesa-7.8.1/progs/xdemos/corender.c 1970-01-01 01:00:00.000000000 +0100
++++ Mesa-7.8.1.patched/progs/xdemos/corender.c 2010-06-13 13:45:06.789793146 +0200
+@@ -0,0 +1,400 @@
++/**
++ * Example of cooperative rendering into one window by two processes.
++ * The first instance of the program creates the GLX window.
++ * The second instance of the program gets the window ID from the first
++ * and draws into it.
++ * Socket IPC is used for synchronization.
++ *
++ * Usage:
++ * 1. run 'corender &'
++ * 2. run 'corender 2' (any arg will do)
++ *
++ * Brian Paul
++ * 11 Oct 2007
++ */
++
++
++#include <GL/gl.h>
++#include <GL/glx.h>
++#include <assert.h>
++#include <math.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <X11/keysym.h>
++#include <unistd.h>
++#include "ipc.h"
++
++
++#ifndef M_PI
++#define M_PI 3.14159265358979323846
++#endif
++
++static int MyID = 0; /* 0 or 1 */
++static int WindowID = 0;
++static GLXContext Context = 0;
++static int Width = 700, Height = 350;
++static int Rot = 0;
++static int Sock = 0;
++
++static GLfloat Red[4] = {1.0, 0.2, 0.2, 1.0};
++static GLfloat Blue[4] = {0.2, 0.2, 1.0, 1.0};
++
++static int Sync = 1; /** synchronized rendering? */
++
++
++static void
++setup_ipc(void)
++{
++ int k, port = 10001;
++
++ if (MyID == 0) {
++ /* I'm the first one, wait for connection from second */
++ k = CreatePort(&port);
++ assert(k != -1);
++
++ printf("Waiting for connection from another 'corender'\n");
++ Sock = AcceptConnection(k);
++ assert(Sock != -1);
++
++ printf("Got connection, sending windowID\n");
++
++ /* send windowID */
++ SendData(Sock, &WindowID, sizeof(WindowID));
++ }
++ else {
++ /* I'm the second one, connect to first */
++ char hostname[1000];
++
++ MyHostName(hostname, 1000);
++ Sock = Connect(hostname, port);
++ assert(Sock != -1);
++
++ /* get windowID */
++ ReceiveData(Sock, &WindowID, sizeof(WindowID));
++ printf("Contacted first 'corender', getting WindowID\n");
++ }
++}
++
++
++
++/** from GLUT */
++static void
++doughnut(GLfloat r, GLfloat R, GLint nsides, GLint rings)
++{
++ int i, j;
++ GLfloat theta, phi, theta1;
++ GLfloat cosTheta, sinTheta;
++ GLfloat cosTheta1, sinTheta1;
++ GLfloat ringDelta, sideDelta;
++
++ ringDelta = 2.0 * M_PI / rings;
++ sideDelta = 2.0 * M_PI / nsides;
++
++ theta = 0.0;
++ cosTheta = 1.0;
++ sinTheta = 0.0;
++ for (i = rings - 1; i >= 0; i--) {
++ theta1 = theta + ringDelta;
++ cosTheta1 = cos(theta1);
++ sinTheta1 = sin(theta1);
++ glBegin(GL_QUAD_STRIP);
++ phi = 0.0;
++ for (j = nsides; j >= 0; j--) {
++ GLfloat cosPhi, sinPhi, dist;
++
++ phi += sideDelta;
++ cosPhi = cos(phi);
++ sinPhi = sin(phi);
++ dist = R + r * cosPhi;
++
++ glNormal3f(cosTheta1 * cosPhi, -sinTheta1 * cosPhi, sinPhi);
++ glVertex3f(cosTheta1 * dist, -sinTheta1 * dist, r * sinPhi);
++ glNormal3f(cosTheta * cosPhi, -sinTheta * cosPhi, sinPhi);
++ glVertex3f(cosTheta * dist, -sinTheta * dist, r * sinPhi);
++ }
++ glEnd();
++ theta = theta1;
++ cosTheta = cosTheta1;
++ sinTheta = sinTheta1;
++ }
++}
++
++
++static void
++redraw(Display *dpy)
++{
++ int dbg = 0;
++
++ glXMakeCurrent(dpy, WindowID, Context);
++ glEnable(GL_LIGHTING);
++ glEnable(GL_LIGHT0);
++ glEnable(GL_DEPTH_TEST);
++ glClearColor(0.5, 0.5, 0.5, 0.0);
++
++ if (MyID == 0) {
++ /* First process */
++
++ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
++
++ glPushMatrix();
++ glTranslatef(-1, 0, 0);
++ glRotatef(Rot, 1, 0, 0);
++ glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, Red);
++ doughnut(0.5, 2.0, 20, 30);
++ glPopMatrix();
++
++ glFinish();
++ if (!Sync) {
++ usleep(1000*10);
++ }
++
++ /* signal second process to render */
++ if (Sync) {
++ int code = 1;
++ if (dbg) printf("0: send signal\n");
++ SendData(Sock, &code, sizeof(code));
++ SendData(Sock, &Rot, sizeof(Rot));
++ }
++
++ /* wait for second process to finish rendering */
++ if (Sync) {
++ int code = 0;
++ if (dbg) printf("0: wait signal\n");
++ ReceiveData(Sock, &code, sizeof(code));
++ if (dbg) printf("0: got signal\n");
++ assert(code == 2);
++ }
++
++ }
++ else {
++ /* Second process */
++
++ /* wait for first process's signal for me to render */
++ if (Sync) {
++ int code = 0;
++ if (dbg) printf("1: wait signal\n");
++ ReceiveData(Sock, &code, sizeof(code));
++ ReceiveData(Sock, &Rot, sizeof(Rot));
++
++ if (dbg) printf("1: got signal\n");
++ assert(code == 1);
++ }
++
++ /* XXX this clear should not be here, but for some reason, it
++ * makes things _mostly_ work correctly w/ NVIDIA's driver.
++ * There's only occasional glitches.
++ * Without this glClear(), depth buffer for the second process
++ * is pretty much broken.
++ */
++ /* glClear(GL_DEPTH_BUFFER_BIT); */
++
++ glPushMatrix();
++ glTranslatef(1, 0, 0);
++ glRotatef(Rot + 90 , 1, 0, 0);
++ glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, Blue);
++ doughnut(0.5, 2.0, 20, 30);
++ glPopMatrix();
++ glFinish();
++
++ glXSwapBuffers(dpy, WindowID);
++ usleep(1000*10);
++
++ /* signal first process that I'm done rendering */
++ if (Sync) {
++ int code = 2;
++ if (dbg) printf("1: send signal\n");
++ SendData(Sock, &code, sizeof(code));
++ }
++ }
++}
++
++
++static void
++resize(Display *dpy, int width, int height)
++{
++ float ar = (float) width / height;
++
++ glXMakeCurrent(dpy, WindowID, Context);
++
++ glViewport(0, 0, width, height);
++ glMatrixMode(GL_PROJECTION);
++ glLoadIdentity();
++ glFrustum(-ar, ar, 1.0, -1.0, 5.0, 200.0);
++ glMatrixMode(GL_MODELVIEW);
++ glLoadIdentity();
++ glTranslatef(0, 0, -15);
++
++ Width = width;
++ Height = height;
++}
++
++
++
++static void
++set_window_title(Display *dpy, Window win, const char *title)
++{
++ XSizeHints sizehints;
++ sizehints.flags = 0;
++ XSetStandardProperties(dpy, win, title, title,
++ None, (char **)NULL, 0, &sizehints);
++}
++
++
++static Window
++make_gl_window(Display *dpy, XVisualInfo *visinfo, int width, int height)
++{
++ int scrnum;
++ XSetWindowAttributes attr;
++ unsigned long mask;
++ Window root;
++ Window win;
++ int x = 0, y = 0;
++ char *name = NULL;
++
++ scrnum = DefaultScreen( dpy );
++ root = RootWindow( dpy, scrnum );
++
++ /* window attributes */
++ attr.background_pixel = 0;
++ attr.border_pixel = 0;
++ attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone);
++ attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
++ mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
++
++ win = XCreateWindow( dpy, root, x, y, width, 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(dpy, win, &sizehints);
++ XSetStandardProperties(dpy, win, name, name,
++ None, (char **)NULL, 0, &sizehints);
++ }
++
++ return win;
++}
++
++
++static void
++set_event_mask(Display *dpy, Window win)
++{
++ XSetWindowAttributes attr;
++ attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
++ XChangeWindowAttributes(dpy, win, CWEventMask, &attr);
++}
++
++
++static void
++event_loop(Display *dpy)
++{
++ while (1) {
++ while (XPending(dpy) > 0) {
++ XEvent event;
++ XNextEvent(dpy, &event);
++
++ switch (event.type) {
++ case Expose:
++ redraw(dpy);
++ break;
++ case ConfigureNotify:
++ resize(dpy, event.xconfigure.width, event.xconfigure.height);
++ break;
++ case KeyPress:
++ {
++ char buffer[10];
++ int r, code;
++ code = XLookupKeysym(&event.xkey, 0);
++ if (code == XK_Left) {
++ }
++ else {
++ r = XLookupString(&event.xkey, buffer, sizeof(buffer),
++ NULL, NULL);
++ if (buffer[0] == 27) {
++ exit(0);
++ }
++ }
++ }
++ default:
++ /* nothing */
++ ;
++ }
++ }
++
++ if (MyID == 0 || !Sync)
++ Rot += 1;
++ redraw(dpy);
++ }
++}
++
++
++static XVisualInfo *
++choose_visual(Display *dpy)
++{
++ int attribs[] = { GLX_RGBA,
++ GLX_RED_SIZE, 1,
++ GLX_GREEN_SIZE, 1,
++ GLX_BLUE_SIZE, 1,
++ GLX_DOUBLEBUFFER,
++ GLX_DEPTH_SIZE, 1,
++ None };
++ int scrnum = DefaultScreen( dpy );
++ return glXChooseVisual(dpy, scrnum, attribs);
++}
++
++
++static void
++parse_opts(int argc, char *argv[])
++{
++ if (argc > 1) {
++ MyID = 1;
++ }
++}
++
++
++int
++main( int argc, char *argv[] )
++{
++ Display *dpy;
++ XVisualInfo *visinfo;
++
++ parse_opts(argc, argv);
++
++ dpy = XOpenDisplay(NULL);
++
++ visinfo = choose_visual(dpy);
++
++ Context = glXCreateContext( dpy, visinfo, NULL, True );
++ if (!Context) {
++ printf("Error: glXCreateContext failed\n");
++ exit(1);
++ }
++
++ if (MyID == 0) {
++ WindowID = make_gl_window(dpy, visinfo, Width, Height);
++ set_window_title(dpy, WindowID, "corender");
++ XMapWindow(dpy, WindowID);
++ /*printf("WindowID 0x%x\n", (int) WindowID);*/
++ }
++
++ /* do ipc hand-shake here */
++ setup_ipc();
++ assert(Sock);
++ assert(WindowID);
++
++ if (MyID == 1) {
++ set_event_mask(dpy, WindowID);
++ }
++
++ resize(dpy, Width, Height);
++
++ event_loop(dpy);
++
++ return 0;
++}
+diff -Naurp Mesa-7.8.1/progs/xdemos/glsync.c Mesa-7.8.1.patched/progs/xdemos/glsync.c
+--- Mesa-7.8.1/progs/xdemos/glsync.c 1970-01-01 01:00:00.000000000 +0100
++++ Mesa-7.8.1.patched/progs/xdemos/glsync.c 2010-06-13 13:45:06.789793146 +0200
+@@ -0,0 +1,295 @@
++/*
++ * Copyright © 2007 Intel Corporation
++ *
++ * 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 (including the next
++ * paragraph) 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:
++ * Jesse Barnes <jesse.barnes@intel.com>
++ *
++ */
++
++/** @file glsync.c
++ * The program is simple: it paints a window alternating colors (red &
++ * white) either as fast as possible or synchronized to vblank events
++ *
++ * If run normally, the program should display a window that exhibits
++ * significant tearing between red and white colors (e.g. you might get
++ * a "waterfall" effect of red and white horizontal bars).
++ *
++ * If run with the '-s b' option, the program should synchronize the
++ * window color changes with the vertical blank period, resulting in a
++ * window that looks orangish with a high frequency flicker (which may
++ * be invisible). If the window is moved to another screen, this
++ * property should be preserved. If the window spans two screens, it
++ * shouldn't tear on whichever screen most of the window is on; the
++ * portion on the other screen may show some tearing (like the
++ * waterfall effect above).
++ *
++ * Other options include '-w <width>' and '-h <height' to set the
++ * window size.
++ */
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <unistd.h>
++#include <GL/gl.h>
++#include <GL/glu.h>
++#include <GL/glx.h>
++#include <GL/glxext.h>
++#include <X11/X.h>
++#include <X11/Xlib.h>
++#include <X11/Xutil.h>
++
++void (*video_sync_get)();
++void (*video_sync)();
++void (*swap_interval)();
++
++static int GLXExtensionSupported(Display *dpy, const char *extension)
++{
++ const char *extensionsString, *pos;
++
++ extensionsString = glXQueryExtensionsString(dpy, DefaultScreen(dpy));
++
++ pos = strstr(extensionsString, extension);
++
++ if (pos != NULL && (pos == extensionsString || pos[-1] == ' ') &&
++ (pos[strlen(extension)] == ' ' || pos[strlen(extension)] == '\0'))
++ return 1;
++
++ return 0;
++}
++
++extern char *optarg;
++extern int optind, opterr, optopt;
++static char optstr[] = "w:h:s:vi:";
++
++enum sync_type {
++ none = 0,
++ sgi_video_sync,
++ buffer_swap
++};
++
++static void usage(char *name)
++{
++ printf("usage: %s [-w <width>] [-h <height>] [-s<sync method>] "
++ "[-v]\n", name);
++ printf("\t-s<sync method>:\n");
++ printf("\t\tn: none\n");
++ printf("\t\ts: SGI video sync extension\n");
++ printf("\t\tb: buffer swap\n");
++ printf("\t-i<swap interval>\n");
++ printf("\t-v: verbose (print count)\n");
++ exit(-1);
++}
++
++int main(int argc, char *argv[])
++{
++ Display *disp;
++ XVisualInfo *pvi;
++ XSetWindowAttributes swa;
++ GLint last_val = -1, count = 0;
++ Window winGL;
++ GLXContext context;
++ int dummy;
++ Atom wmDelete;
++ enum sync_type waitforsync = none;
++ int width = 500, height = 500, verbose = 0, interval = 1;
++ int c, i = 1;
++ int ret;
++ int attribs[] = { GLX_RGBA,
++ GLX_RED_SIZE, 1,
++ GLX_GREEN_SIZE, 1,
++ GLX_BLUE_SIZE, 1,
++ None };
++ int db_attribs[] = { GLX_RGBA,
++ GLX_RED_SIZE, 1,
++ GLX_GREEN_SIZE, 1,
++ GLX_BLUE_SIZE, 1,
++ GLX_DOUBLEBUFFER,
++ GLX_DEPTH_SIZE, 1,
++ None };
++ XSizeHints sizehints;
++
++ opterr = 0;
++ while ((c = getopt(argc, argv, optstr)) != -1) {
++ switch (c) {
++ case 'w':
++ width = atoi(optarg);
++ break;
++ case 'h':
++ height = atoi(optarg);
++ break;
++ case 's':
++ switch (optarg[0]) {
++ case 'n':
++ waitforsync = none;
++ break;
++ case 's':
++ waitforsync = sgi_video_sync;
++ break;
++ case 'b':
++ waitforsync = buffer_swap;
++ break;
++ default:
++ usage(argv[0]);
++ break;
++ }
++ break;
++ case 'v':
++ verbose = 1;
++ break;
++ case 'i':
++ interval = atoi(optarg);
++ break;
++ default:
++ usage(argv[0]);
++ break;
++ }
++ }
++
++ disp = XOpenDisplay(NULL);
++ if (!disp) {
++ fprintf(stderr, "failed to open display\n");
++ return -1;
++ }
++
++ if (!glXQueryExtension(disp, &dummy, &dummy)) {
++ fprintf(stderr, "glXQueryExtension failed\n");
++ return -1;
++ }
++
++ if (!GLXExtensionSupported(disp, "GLX_SGI_video_sync")) {
++ fprintf(stderr, "GLX_SGI_video_sync not supported, exiting\n");
++ return -1;
++ }
++
++ if (waitforsync != buffer_swap) {
++ pvi = glXChooseVisual(disp, DefaultScreen(disp), attribs);
++ } else {
++ pvi = glXChooseVisual(disp, DefaultScreen(disp), db_attribs);
++ }
++
++ if (!pvi) {
++ fprintf(stderr, "failed to choose visual, exiting\n");
++ return -1;
++ }
++
++ pvi->screen = DefaultScreen(disp);
++
++ swa.colormap = XCreateColormap(disp, RootWindow(disp, pvi->screen),
++ pvi->visual, AllocNone);
++ swa.border_pixel = 0;
++ swa.event_mask = ExposureMask | KeyPressMask | ButtonPressMask |
++ StructureNotifyMask;
++ winGL = XCreateWindow(disp, RootWindow(disp, pvi->screen),
++ 0, 0,
++ width, height,
++ 0, pvi->depth, InputOutput, pvi->visual,
++ CWBorderPixel | CWColormap | CWEventMask, &swa);
++ if (!winGL) {
++ fprintf(stderr, "window creation failed\n");
++ return -1;
++ }
++ wmDelete = XInternAtom(disp, "WM_DELETE_WINDOW", True);
++ XSetWMProtocols(disp, winGL, &wmDelete, 1);
++
++ sizehints.x = 0;
++ sizehints.y = 0;
++ sizehints.width = width;
++ sizehints.height = height;
++ sizehints.flags = USSize | USPosition;
++
++ XSetNormalHints(disp, winGL, &sizehints);
++ XSetStandardProperties(disp, winGL, "glsync test", "glsync text",
++ None, NULL, 0, &sizehints);
++
++ context = glXCreateContext(disp, pvi, NULL, GL_TRUE);
++ if (!context) {
++ fprintf(stderr, "failed to create glx context\n");
++ return -1;
++ }
++
++ XMapWindow(disp, winGL);
++ ret = glXMakeCurrent(disp, winGL, context);
++ if (!ret) {
++ fprintf(stderr, "failed to make context current: %d\n", ret);
++ }
++
++ video_sync_get = glXGetProcAddress((unsigned char *)"glXGetVideoSyncSGI");
++ video_sync = glXGetProcAddress((unsigned char *)"glXWaitVideoSyncSGI");
++
++ swap_interval = glXGetProcAddress((unsigned char *)"glXSwapIntervalSGI");
++
++ if (!video_sync_get || !video_sync || !swap_interval) {
++ fprintf(stderr, "failed to get sync functions\n");
++ return -1;
++ }
++
++ if (waitforsync == buffer_swap) {
++ swap_interval(interval);
++ fprintf(stderr, "set swap interval to %d\n", interval);
++ }
++ video_sync_get(&count);
++ count++;
++ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
++ while (i++) {
++ /* Alternate colors to make tearing obvious */
++ if (i & 1) {
++ glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
++ glColor3f(1.0f, 1.0f, 1.0f);
++ } else {
++ glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
++ glColor3f(1.0f, 0.0f, 0.0f);
++ }
++
++ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
++ glRectf(0, 0, width, height);
++
++ /* Wait for vsync */
++ if (waitforsync == sgi_video_sync) {
++ if (verbose)
++ fprintf(stderr, "waiting on count %d\n", count);
++ video_sync(2, (count + 1) % 2, &count);
++ if (count < last_val)
++ fprintf(stderr, "error: vblank count went backwards: %d -> %d\n", last_val, count);
++ if (count == last_val)
++ fprintf(stderr, "error: count didn't change: %d\n", count);
++ last_val = count;
++ glFlush();
++ } else if (waitforsync == buffer_swap) {
++ glXSwapBuffers(disp, winGL);
++ } else {
++ video_sync_get(&count);
++ sleep(1);
++ glFinish();
++ }
++
++ if (verbose) {
++ video_sync_get(&count);
++ fprintf(stderr, "current count: %d\n", count);
++ }
++ }
++
++ XDestroyWindow(disp, winGL);
++ glXDestroyContext(disp, context);
++ XCloseDisplay(disp);
++
++ return 0;
++}
+diff -Naurp Mesa-7.8.1/progs/xdemos/glthreads.c Mesa-7.8.1.patched/progs/xdemos/glthreads.c
+--- Mesa-7.8.1/progs/xdemos/glthreads.c 1970-01-01 01:00:00.000000000 +0100
++++ Mesa-7.8.1.patched/progs/xdemos/glthreads.c 2010-06-13 13:45:06.789793146 +0200
+@@ -0,0 +1,716 @@
++/*
++ * Copyright (C) 2000 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.
++ */
++
++
++/*
++ * This program tests GLX thread safety.
++ * Command line options:
++ * -p Open a display connection for each thread
++ * -l Enable application-side locking
++ * -n <num threads> Number of threads to create (default is 2)
++ * -display <display name> Specify X display (default is $DISPLAY)
++ * -t Use texture mapping
++ *
++ * Brian Paul 20 July 2000
++ */
++
++
++/*
++ * Notes:
++ * - Each thread gets its own GLX context.
++ *
++ * - The GLX contexts share texture objects.
++ *
++ * - When 't' is pressed to update the texture image, the window/thread which
++ * has input focus is signalled to change the texture. The other threads
++ * should see the updated texture the next time they call glBindTexture.
++ */
++
++
++#if defined(PTHREADS) /* defined by Mesa on Linux and other platforms */
++
++#include <assert.h>
++#include <GL/gl.h>
++#include <GL/glx.h>
++#include <math.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <unistd.h>
++#include <pthread.h>
++
++
++/*
++ * Each window/thread/context:
++ */
++struct winthread {
++ Display *Dpy;
++ int Index;
++ pthread_t Thread;
++ Window Win;
++ GLXContext Context;
++ float Angle;
++ int WinWidth, WinHeight;
++ GLboolean NewSize;
++ GLboolean Initialized;
++ GLboolean MakeNewTexture;
++};
++
++
++#define MAX_WINTHREADS 100
++static struct winthread WinThreads[MAX_WINTHREADS];
++static int NumWinThreads = 0;
++static volatile GLboolean ExitFlag = GL_FALSE;
++
++static GLboolean MultiDisplays = 0;
++static GLboolean Locking = 0;
++static GLboolean Texture = GL_FALSE;
++static GLuint TexObj = 12;
++static GLboolean Animate = GL_TRUE;
++
++static pthread_mutex_t Mutex;
++static pthread_cond_t CondVar;
++static pthread_mutex_t CondMutex;
++
++
++static void
++Error(const char *msg)
++{
++ fprintf(stderr, "Error: %s\n", msg);
++ exit(1);
++}
++
++
++static void
++signal_redraw(void)
++{
++ pthread_mutex_lock(&CondMutex);
++ pthread_cond_broadcast(&CondVar);
++ pthread_mutex_unlock(&CondMutex);
++}
++
++
++static void
++MakeNewTexture(struct winthread *wt)
++{
++#define TEX_SIZE 128
++ static float step = 0.0;
++ GLfloat image[TEX_SIZE][TEX_SIZE][4];
++ GLint width;
++ int i, j;
++
++ for (j = 0; j < TEX_SIZE; j++) {
++ for (i = 0; i < TEX_SIZE; i++) {
++ float dt = 5.0 * (j - 0.5 * TEX_SIZE) / TEX_SIZE;
++ float ds = 5.0 * (i - 0.5 * TEX_SIZE) / TEX_SIZE;
++ float r = dt * dt + ds * ds + step;
++ image[j][i][0] =
++ image[j][i][1] =
++ image[j][i][2] = 0.75 + 0.25 * cos(r);
++ image[j][i][3] = 1.0;
++ }
++ }
++
++ step += 0.5;
++
++ glBindTexture(GL_TEXTURE_2D, TexObj);
++
++ glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
++ if (width) {
++ assert(width == TEX_SIZE);
++ /* sub-tex replace */
++ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, TEX_SIZE, TEX_SIZE,
++ GL_RGBA, GL_FLOAT, image);
++ }
++ else {
++ /* create new */
++ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
++ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
++
++ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TEX_SIZE, TEX_SIZE, 0,
++ GL_RGBA, GL_FLOAT, image);
++ }
++}
++
++
++
++/* draw a colored cube */
++static void
++draw_object(void)
++{
++ glPushMatrix();
++ glScalef(0.75, 0.75, 0.75);
++
++ glColor3f(1, 0, 0);
++
++ if (Texture) {
++ glBindTexture(GL_TEXTURE_2D, TexObj);
++ glEnable(GL_TEXTURE_2D);
++ }
++ else {
++ glDisable(GL_TEXTURE_2D);
++ }
++
++ glBegin(GL_QUADS);
++
++ /* -X */
++ glColor3f(0, 1, 1);
++ glTexCoord2f(0, 0); glVertex3f(-1, -1, -1);
++ glTexCoord2f(1, 0); glVertex3f(-1, 1, -1);
++ glTexCoord2f(1, 1); glVertex3f(-1, 1, 1);
++ glTexCoord2f(0, 1); glVertex3f(-1, -1, 1);
++
++ /* +X */
++ glColor3f(1, 0, 0);
++ glTexCoord2f(0, 0); glVertex3f(1, -1, -1);
++ glTexCoord2f(1, 0); glVertex3f(1, 1, -1);
++ glTexCoord2f(1, 1); glVertex3f(1, 1, 1);
++ glTexCoord2f(0, 1); glVertex3f(1, -1, 1);
++
++ /* -Y */
++ glColor3f(1, 0, 1);
++ glTexCoord2f(0, 0); glVertex3f(-1, -1, -1);
++ glTexCoord2f(1, 0); glVertex3f( 1, -1, -1);
++ glTexCoord2f(1, 1); glVertex3f( 1, -1, 1);
++ glTexCoord2f(0, 1); glVertex3f(-1, -1, 1);
++
++ /* +Y */
++ glColor3f(0, 1, 0);
++ glTexCoord2f(0, 0); glVertex3f(-1, 1, -1);
++ glTexCoord2f(1, 0); glVertex3f( 1, 1, -1);
++ glTexCoord2f(1, 1); glVertex3f( 1, 1, 1);
++ glTexCoord2f(0, 1); glVertex3f(-1, 1, 1);
++
++ /* -Z */
++ glColor3f(1, 1, 0);
++ glTexCoord2f(0, 0); glVertex3f(-1, -1, -1);
++ glTexCoord2f(1, 0); glVertex3f( 1, -1, -1);
++ glTexCoord2f(1, 1); glVertex3f( 1, 1, -1);
++ glTexCoord2f(0, 1); glVertex3f(-1, 1, -1);
++
++ /* +Y */
++ glColor3f(0, 0, 1);
++ glTexCoord2f(0, 0); glVertex3f(-1, -1, 1);
++ glTexCoord2f(1, 0); glVertex3f( 1, -1, 1);
++ glTexCoord2f(1, 1); glVertex3f( 1, 1, 1);
++ glTexCoord2f(0, 1); glVertex3f(-1, 1, 1);
++
++ glEnd();
++
++ glPopMatrix();
++}
++
++
++/* signal resize of given window */
++static void
++resize(struct winthread *wt, int w, int h)
++{
++ wt->NewSize = GL_TRUE;
++ wt->WinWidth = w;
++ wt->WinHeight = h;
++ if (!Animate)
++ signal_redraw();
++}
++
++
++/*
++ * We have an instance of this for each thread.
++ */
++static void
++draw_loop(struct winthread *wt)
++{
++ while (!ExitFlag) {
++
++ if (Locking)
++ pthread_mutex_lock(&Mutex);
++
++ glXMakeCurrent(wt->Dpy, wt->Win, wt->Context);
++ if (!wt->Initialized) {
++ printf("glthreads: %d: GL_RENDERER = %s\n", wt->Index,
++ (char *) glGetString(GL_RENDERER));
++ if (Texture /*&& wt->Index == 0*/) {
++ MakeNewTexture(wt);
++ }
++ wt->Initialized = GL_TRUE;
++ }
++
++ if (Locking)
++ pthread_mutex_unlock(&Mutex);
++
++ glEnable(GL_DEPTH_TEST);
++
++ if (wt->NewSize) {
++ GLfloat w = (float) wt->WinWidth / (float) wt->WinHeight;
++ glViewport(0, 0, wt->WinWidth, wt->WinHeight);
++ glMatrixMode(GL_PROJECTION);
++ glLoadIdentity();
++ glFrustum(-w, w, -1.0, 1.0, 1.5, 10);
++ glMatrixMode(GL_MODELVIEW);
++ glLoadIdentity();
++ glTranslatef(0, 0, -2.5);
++ wt->NewSize = GL_FALSE;
++ }
++
++ if (wt->MakeNewTexture) {
++ MakeNewTexture(wt);
++ wt->MakeNewTexture = GL_FALSE;
++ }
++
++ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
++
++ glPushMatrix();
++ glRotatef(wt->Angle, 0, 1, 0);
++ glRotatef(wt->Angle, 1, 0, 0);
++ glScalef(0.7, 0.7, 0.7);
++ draw_object();
++ glPopMatrix();
++
++ if (Locking)
++ pthread_mutex_lock(&Mutex);
++
++ glXSwapBuffers(wt->Dpy, wt->Win);
++
++ if (Locking)
++ pthread_mutex_unlock(&Mutex);
++
++ if (Animate) {
++ usleep(5000);
++ }
++ else {
++ /* wait for signal to draw */
++ pthread_mutex_lock(&CondMutex);
++ pthread_cond_wait(&CondVar, &CondMutex);
++ pthread_mutex_unlock(&CondMutex);
++ }
++ wt->Angle += 1.0;
++ }
++}
++
++
++static void
++keypress(XEvent *event, struct winthread *wt)
++{
++ char buf[100];
++ KeySym keySym;
++ XComposeStatus stat;
++
++ XLookupString(&event->xkey, buf, sizeof(buf), &keySym, &stat);
++
++ switch (keySym) {
++ case XK_Escape:
++ /* tell all threads to exit */
++ if (!Animate) {
++ signal_redraw();
++ }
++ ExitFlag = GL_TRUE;
++ /*printf("exit draw_loop %d\n", wt->Index);*/
++ return;
++ case XK_t:
++ case XK_T:
++ if (Texture) {
++ wt->MakeNewTexture = GL_TRUE;
++ if (!Animate)
++ signal_redraw();
++ }
++ break;
++ case XK_a:
++ case XK_A:
++ Animate = !Animate;
++ if (Animate) /* yes, prev Animate state! */
++ signal_redraw();
++ break;
++ case XK_s:
++ case XK_S:
++ if (!Animate)
++ signal_redraw();
++ break;
++ default:
++ ; /* nop */
++ }
++}
++
++
++/*
++ * The main process thread runs this loop.
++ * Single display connection for all threads.
++ */
++static void
++event_loop(Display *dpy)
++{
++ XEvent event;
++ int i;
++
++ assert(!MultiDisplays);
++
++ while (!ExitFlag) {
++
++ if (Locking) {
++ while (1) {
++ int k;
++ pthread_mutex_lock(&Mutex);
++ k = XPending(dpy);
++ if (k) {
++ XNextEvent(dpy, &event);
++ pthread_mutex_unlock(&Mutex);
++ break;
++ }
++ pthread_mutex_unlock(&Mutex);
++ usleep(5000);
++ }
++ }
++ else {
++ XNextEvent(dpy, &event);
++ }
++
++ switch (event.type) {
++ case ConfigureNotify:
++ /* Find winthread for this event's window */
++ for (i = 0; i < NumWinThreads; i++) {
++ struct winthread *wt = &WinThreads[i];
++ if (event.xconfigure.window == wt->Win) {
++ resize(wt, event.xconfigure.width,
++ event.xconfigure.height);
++ break;
++ }
++ }
++ break;
++ case KeyPress:
++ for (i = 0; i < NumWinThreads; i++) {
++ struct winthread *wt = &WinThreads[i];
++ if (event.xkey.window == wt->Win) {
++ keypress(&event, wt);
++ break;
++ }
++ }
++ break;
++ default:
++ /*no-op*/ ;
++ }
++ }
++}
++
++
++/*
++ * Separate display connection for each thread.
++ */
++static void
++event_loop_multi(void)
++{
++ XEvent event;
++ int w = 0;
++
++ assert(MultiDisplays);
++
++ while (!ExitFlag) {
++ struct winthread *wt = &WinThreads[w];
++ if (XPending(wt->Dpy)) {
++ XNextEvent(wt->Dpy, &event);
++ switch (event.type) {
++ case ConfigureNotify:
++ resize(wt, event.xconfigure.width, event.xconfigure.height);
++ break;
++ case KeyPress:
++ keypress(&event, wt);
++ break;
++ default:
++ ; /* nop */
++ }
++ }
++ w = (w + 1) % NumWinThreads;
++ usleep(5000);
++ }
++}
++
++
++
++/*
++ * we'll call this once for each thread, before the threads are created.
++ */
++static void
++create_window(struct winthread *wt, GLXContext shareCtx)
++{
++ Window win;
++ GLXContext ctx;
++ int attrib[] = { GLX_RGBA,
++ GLX_RED_SIZE, 1,
++ GLX_GREEN_SIZE, 1,
++ GLX_BLUE_SIZE, 1,
++ GLX_DEPTH_SIZE, 1,
++ GLX_DOUBLEBUFFER,
++ None };
++ int scrnum;
++ XSetWindowAttributes attr;
++ unsigned long mask;
++ Window root;
++ XVisualInfo *visinfo;
++ int width = 160, height = 160;
++ int xpos = (wt->Index % 8) * (width + 10);
++ int ypos = (wt->Index / 8) * (width + 20);
++
++ scrnum = DefaultScreen(wt->Dpy);
++ root = RootWindow(wt->Dpy, scrnum);
++
++ visinfo = glXChooseVisual(wt->Dpy, scrnum, attrib);
++ if (!visinfo) {
++ Error("Unable to find RGB, Z, double-buffered visual");
++ }
++
++ /* window attributes */
++ attr.background_pixel = 0;
++ attr.border_pixel = 0;
++ attr.colormap = XCreateColormap(wt->Dpy, root, visinfo->visual, AllocNone);
++ attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
++ mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
++
++ win = XCreateWindow(wt->Dpy, root, xpos, ypos, width, height,
++ 0, visinfo->depth, InputOutput,
++ visinfo->visual, mask, &attr);
++ if (!win) {
++ Error("Couldn't create window");
++ }
++
++ {
++ XSizeHints sizehints;
++ sizehints.x = xpos;
++ sizehints.y = ypos;
++ sizehints.width = width;
++ sizehints.height = height;
++ sizehints.flags = USSize | USPosition;
++ XSetNormalHints(wt->Dpy, win, &sizehints);
++ XSetStandardProperties(wt->Dpy, win, "glthreads", "glthreads",
++ None, (char **)NULL, 0, &sizehints);
++ }
++
++
++ ctx = glXCreateContext(wt->Dpy, visinfo, shareCtx, True);
++ if (!ctx) {
++ Error("Couldn't create GLX context");
++ }
++
++ XMapWindow(wt->Dpy, win);
++ XSync(wt->Dpy, 0);
++
++ /* save the info for this window/context */
++ wt->Win = win;
++ wt->Context = ctx;
++ wt->Angle = 0.0;
++ wt->WinWidth = width;
++ wt->WinHeight = height;
++ wt->NewSize = GL_TRUE;
++}
++
++
++/*
++ * Called by pthread_create()
++ */
++static void *
++thread_function(void *p)
++{
++ struct winthread *wt = (struct winthread *) p;
++ draw_loop(wt);
++ return NULL;
++}
++
++
++/*
++ * called before exit to wait for all threads to finish
++ */
++static void
++clean_up(void)
++{
++ int i;
++
++ /* wait for threads to finish */
++ for (i = 0; i < NumWinThreads; i++) {
++ pthread_join(WinThreads[i].Thread, NULL);
++ }
++
++ for (i = 0; i < NumWinThreads; i++) {
++ glXDestroyContext(WinThreads[i].Dpy, WinThreads[i].Context);
++ XDestroyWindow(WinThreads[i].Dpy, WinThreads[i].Win);
++ }
++}
++
++
++static void
++usage(void)
++{
++ printf("glthreads: test of GL thread safety (any key = exit)\n");
++ printf("Usage:\n");
++ printf(" glthreads [options]\n");
++ printf("Options:\n");
++ printf(" -display DISPLAYNAME Specify display string\n");
++ printf(" -n NUMTHREADS Number of threads to create\n");
++ printf(" -p Use a separate display connection for each thread\n");
++ printf(" -l Use application-side locking\n");
++ printf(" -t Enable texturing\n");
++ printf("Keyboard:\n");
++ printf(" Esc Exit\n");
++ printf(" t Change texture image (requires -t option)\n");
++ printf(" a Toggle animation\n");
++ printf(" s Step rotation (when not animating)\n");
++}
++
++
++int
++main(int argc, char *argv[])
++{
++ char *displayName = NULL;
++ int numThreads = 2;
++ Display *dpy = NULL;
++ int i;
++ Status threadStat;
++
++ if (argc == 1) {
++ usage();
++ }
++ else {
++ int i;
++ for (i = 1; i < argc; i++) {
++ if (strcmp(argv[i], "-display") == 0 && i + 1 < argc) {
++ displayName = argv[i + 1];
++ i++;
++ }
++ else if (strcmp(argv[i], "-p") == 0) {
++ MultiDisplays = 1;
++ }
++ else if (strcmp(argv[i], "-l") == 0) {
++ Locking = 1;
++ }
++ else if (strcmp(argv[i], "-t") == 0) {
++ Texture = 1;
++ }
++ else if (strcmp(argv[i], "-n") == 0 && i + 1 < argc) {
++ numThreads = atoi(argv[i + 1]);
++ if (numThreads < 1)
++ numThreads = 1;
++ else if (numThreads > MAX_WINTHREADS)
++ numThreads = MAX_WINTHREADS;
++ i++;
++ }
++ else {
++ usage();
++ exit(1);
++ }
++ }
++ }
++
++ if (Locking)
++ printf("glthreads: Using explicit locks around Xlib calls.\n");
++ else
++ printf("glthreads: No explict locking.\n");
++
++ if (MultiDisplays)
++ printf("glthreads: Per-thread display connections.\n");
++ else
++ printf("glthreads: Single display connection.\n");
++
++ /*
++ * VERY IMPORTANT: call XInitThreads() before any other Xlib functions.
++ */
++ if (!MultiDisplays) {
++ if (!Locking) {
++ threadStat = XInitThreads();
++ if (threadStat) {
++ printf("XInitThreads() returned %d (success)\n", (int) threadStat);
++ }
++ else {
++ printf("XInitThreads() returned 0 (failure- this program may fail)\n");
++ }
++ }
++
++ dpy = XOpenDisplay(displayName);
++ if (!dpy) {
++ fprintf(stderr, "Unable to open display %s\n", XDisplayName(displayName));
++ return -1;
++ }
++ }
++
++ pthread_mutex_init(&Mutex, NULL);
++ pthread_mutex_init(&CondMutex, NULL);
++ pthread_cond_init(&CondVar, NULL);
++
++ printf("glthreads: creating windows\n");
++
++ NumWinThreads = numThreads;
++
++ /* Create the GLX windows and contexts */
++ for (i = 0; i < numThreads; i++) {
++ GLXContext share;
++
++ if (MultiDisplays) {
++ WinThreads[i].Dpy = XOpenDisplay(displayName);
++ assert(WinThreads[i].Dpy);
++ }
++ else {
++ WinThreads[i].Dpy = dpy;
++ }
++ WinThreads[i].Index = i;
++ WinThreads[i].Initialized = GL_FALSE;
++
++ share = (Texture && i > 0) ? WinThreads[0].Context : 0;
++
++ create_window(&WinThreads[i], share);
++ }
++
++ printf("glthreads: creating threads\n");
++
++ /* Create the threads */
++ for (i = 0; i < numThreads; i++) {
++ pthread_create(&WinThreads[i].Thread, NULL, thread_function,
++ (void*) &WinThreads[i]);
++ printf("glthreads: Created thread %p\n", (void *) WinThreads[i].Thread);
++ }
++
++ if (MultiDisplays)
++ event_loop_multi();
++ else
++ event_loop(dpy);
++
++ clean_up();
++
++ if (MultiDisplays) {
++ for (i = 0; i < numThreads; i++) {
++ XCloseDisplay(WinThreads[i].Dpy);
++ }
++ }
++ else {
++ XCloseDisplay(dpy);
++ }
++
++ return 0;
++}
++
++
++#else /* PTHREADS */
++
++
++#include <stdio.h>
++
++int
++main(int argc, char *argv[])
++{
++ printf("Sorry, this program wasn't compiled with PTHREADS defined.\n");
++ return 0;
++}
++
++
++#endif /* PTHREADS */
+diff -Naurp Mesa-7.8.1/progs/xdemos/glxcontexts.c Mesa-7.8.1.patched/progs/xdemos/glxcontexts.c
+--- Mesa-7.8.1/progs/xdemos/glxcontexts.c 1970-01-01 01:00:00.000000000 +0100
++++ Mesa-7.8.1.patched/progs/xdemos/glxcontexts.c 2010-06-13 13:45:06.789793146 +0200
+@@ -0,0 +1,548 @@
++/*
++ * 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.
++ */
++
++/*
++ * Version of glxgears that creates/destroys the rendering context for each
++ * frame. Also periodically destroy/recreate the window.
++ * Good for finding memory leaks, etc.
++ *
++ * Command line options:
++ * -info print GL implementation information
++ *
++ */
++
++
++#include <assert.h>
++#include <math.h>
++#include <stdlib.h>
++#include <stdio.h>
++#include <string.h>
++#include <X11/Xlib.h>
++#include <X11/keysym.h>
++#include <GL/gl.h>
++#include <GL/glx.h>
++
++
++#define BENCHMARK
++
++#ifdef BENCHMARK
++
++/* XXX this probably isn't very portable */
++
++#include <sys/time.h>
++#include <unistd.h>
++
++/* return current time (in seconds) */
++static double
++current_time(void)
++{
++ struct timeval tv;
++#ifdef __VMS
++ (void) gettimeofday(&tv, NULL );
++#else
++ struct timezone tz;
++ (void) gettimeofday(&tv, &tz);
++#endif
++ return (double) tv.tv_sec + tv.tv_usec / 1000000.0;
++}
++
++#else /*BENCHMARK*/
++
++/* dummy */
++static double
++current_time(void)
++{
++ /* update this function for other platforms! */
++ static double t = 0.0;
++ static int warn = 1;
++ if (warn) {
++ fprintf(stderr, "Warning: current_time() not implemented!!\n");
++ warn = 0;
++ }
++ return t += 1.0;
++}
++
++#endif /*BENCHMARK*/
++
++
++
++#ifndef M_PI
++#define M_PI 3.14159265
++#endif
++
++
++static GLfloat view_rotx = 20.0, view_roty = 30.0, view_rotz = 0.0;
++static GLint gear1, gear2, gear3;
++static GLfloat angle = 0.0;
++
++static XVisualInfo *visinfo = NULL;
++static int WinWidth = 300, WinHeight = 300;
++
++
++/*
++ *
++ * Draw a gear wheel. You'll probably want to call this function when
++ * building a display list since we do a lot of trig here.
++ *
++ * Input: 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
++gear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width,
++ GLint teeth, GLfloat tooth_depth)
++{
++ GLint i;
++ GLfloat r0, r1, r2;
++ GLfloat angle, da;
++ GLfloat u, v, len;
++
++ r0 = inner_radius;
++ r1 = outer_radius - tooth_depth / 2.0;
++ r2 = outer_radius + tooth_depth / 2.0;
++
++ da = 2.0 * M_PI / teeth / 4.0;
++
++ glShadeModel(GL_FLAT);
++
++ glNormal3f(0.0, 0.0, 1.0);
++
++ /* draw front face */
++ glBegin(GL_QUAD_STRIP);
++ for (i = 0; i <= teeth; i++) {
++ angle = i * 2.0 * M_PI / teeth;
++ glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
++ glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
++ if (i < teeth) {
++ glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
++ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
++ width * 0.5);
++ }
++ }
++ glEnd();
++
++ /* draw front sides of teeth */
++ glBegin(GL_QUADS);
++ da = 2.0 * M_PI / teeth / 4.0;
++ for (i = 0; i < teeth; i++) {
++ angle = i * 2.0 * M_PI / teeth;
++
++ glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
++ glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
++ glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
++ width * 0.5);
++ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
++ width * 0.5);
++ }
++ glEnd();
++
++ glNormal3f(0.0, 0.0, -1.0);
++
++ /* draw back face */
++ glBegin(GL_QUAD_STRIP);
++ for (i = 0; i <= teeth; i++) {
++ angle = i * 2.0 * M_PI / teeth;
++ glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
++ glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
++ if (i < teeth) {
++ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
++ -width * 0.5);
++ glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
++ }
++ }
++ glEnd();
++
++ /* draw back sides of teeth */
++ glBegin(GL_QUADS);
++ da = 2.0 * M_PI / teeth / 4.0;
++ for (i = 0; i < teeth; i++) {
++ angle = i * 2.0 * M_PI / teeth;
++
++ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
++ -width * 0.5);
++ glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
++ -width * 0.5);
++ glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
++ glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
++ }
++ glEnd();
++
++ /* draw outward faces of teeth */
++ glBegin(GL_QUAD_STRIP);
++ for (i = 0; i < teeth; i++) {
++ angle = i * 2.0 * M_PI / teeth;
++
++ glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
++ glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
++ u = r2 * cos(angle + da) - r1 * cos(angle);
++ v = r2 * sin(angle + da) - r1 * sin(angle);
++ len = sqrt(u * u + v * v);
++ u /= len;
++ v /= len;
++ glNormal3f(v, -u, 0.0);
++ glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
++ glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
++ glNormal3f(cos(angle), sin(angle), 0.0);
++ glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
++ width * 0.5);
++ glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
++ -width * 0.5);
++ u = r1 * cos(angle + 3 * da) - r2 * cos(angle + 2 * da);
++ v = r1 * sin(angle + 3 * da) - r2 * sin(angle + 2 * da);
++ glNormal3f(v, -u, 0.0);
++ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
++ width * 0.5);
++ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
++ -width * 0.5);
++ glNormal3f(cos(angle), sin(angle), 0.0);
++ }
++
++ glVertex3f(r1 * cos(0), r1 * sin(0), width * 0.5);
++ glVertex3f(r1 * cos(0), r1 * sin(0), -width * 0.5);
++
++ glEnd();
++
++ glShadeModel(GL_SMOOTH);
++
++ /* draw inside radius cylinder */
++ glBegin(GL_QUAD_STRIP);
++ for (i = 0; i <= teeth; i++) {
++ angle = i * 2.0 * M_PI / teeth;
++ glNormal3f(-cos(angle), -sin(angle), 0.0);
++ glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
++ glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
++ }
++ glEnd();
++}
++
++
++static void
++do_draw(void)
++{
++ 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);
++ glCallList(gear1);
++ glPopMatrix();
++
++ glPushMatrix();
++ glTranslatef(3.1, -2.0, 0.0);
++ glRotatef(-2.0 * angle - 9.0, 0.0, 0.0, 1.0);
++ glCallList(gear2);
++ glPopMatrix();
++
++ glPushMatrix();
++ glTranslatef(-3.1, 4.2, 0.0);
++ glRotatef(-2.0 * angle - 25.0, 0.0, 0.0, 1.0);
++ glCallList(gear3);
++ glPopMatrix();
++
++ glPopMatrix();
++}
++
++
++/* new window size or exposure */
++static void
++reshape(int width, int height)
++{
++ glViewport(0, 0, (GLint) width, (GLint) height);
++
++ {
++ GLfloat h = (GLfloat) height / (GLfloat) width;
++
++ glMatrixMode(GL_PROJECTION);
++ glLoadIdentity();
++ glFrustum(-1.0, 1.0, -h, h, 5.0, 60.0);
++ }
++
++ glMatrixMode(GL_MODELVIEW);
++ glLoadIdentity();
++ glTranslatef(0.0, 0.0, -40.0);
++}
++
++
++static void
++init(void)
++{
++ static GLfloat pos[4] = { 5.0, 5.0, 10.0, 0.0 };
++ static GLfloat red[4] = { 0.8, 0.1, 0.0, 1.0 };
++ static GLfloat green[4] = { 0.0, 0.8, 0.2, 1.0 };
++ static GLfloat blue[4] = { 0.2, 0.2, 1.0, 1.0 };
++
++ glLightfv(GL_LIGHT0, GL_POSITION, pos);
++ glEnable(GL_CULL_FACE);
++ glEnable(GL_LIGHTING);
++ glEnable(GL_LIGHT0);
++ glEnable(GL_DEPTH_TEST);
++
++ /* make the gears */
++ gear1 = glGenLists(1);
++ glNewList(gear1, GL_COMPILE);
++ glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red);
++ gear(1.0, 4.0, 1.0, 20, 0.7);
++ glEndList();
++
++ gear2 = glGenLists(1);
++ glNewList(gear2, GL_COMPILE);
++ glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green);
++ gear(0.5, 2.0, 2.0, 10, 0.7);
++ glEndList();
++
++ gear3 = glGenLists(1);
++ glNewList(gear3, GL_COMPILE);
++ glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue);
++ gear(1.3, 2.0, 0.5, 10, 0.7);
++ glEndList();
++
++ glEnable(GL_NORMALIZE);
++}
++
++
++static void
++draw( Display *dpy, Window win )
++{
++ GLXContext ctx;
++
++ ctx = glXCreateContext( dpy, visinfo, NULL, True );
++ if (!ctx) {
++ printf("Error: glXCreateContext failed\n");
++ exit(1);
++ }
++
++ glXMakeCurrent(dpy, win, ctx);
++
++ init();
++
++ reshape(WinWidth, WinHeight);
++
++ do_draw();
++
++ glDeleteLists(gear1, 1);
++ glDeleteLists(gear2, 1);
++ glDeleteLists(gear3, 1);
++
++ glXSwapBuffers(dpy, win);
++ glXDestroyContext(dpy, ctx);
++}
++
++
++/*
++ * Create an RGB, double-buffered window.
++ * Return the window and context handles.
++ */
++static void
++make_window( Display *dpy, const char *name,
++ int x, int y, int width, int height,
++ Window *winRet)
++{
++ int attribs[] = { GLX_RGBA,
++ GLX_RED_SIZE, 1,
++ GLX_GREEN_SIZE, 1,
++ GLX_BLUE_SIZE, 1,
++ GLX_DOUBLEBUFFER,
++ GLX_DEPTH_SIZE, 1,
++ None };
++ int scrnum;
++ XSetWindowAttributes attr;
++ unsigned long mask;
++ Window root;
++ Window win;
++
++ scrnum = DefaultScreen( dpy );
++ root = RootWindow( dpy, scrnum );
++
++ if (visinfo)
++ XFree(visinfo);
++
++ visinfo = glXChooseVisual( dpy, scrnum, attribs );
++ if (!visinfo) {
++ printf("Error: couldn't get an RGB, Double-buffered visual\n");
++ exit(1);
++ }
++
++ /* window attributes */
++ attr.background_pixel = 0;
++ attr.border_pixel = 0;
++ attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone);
++ attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
++ attr.override_redirect = 0;
++ mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect;
++
++ win = XCreateWindow( dpy, root, x, y, width, 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(dpy, win, &sizehints);
++ XSetStandardProperties(dpy, win, name, name,
++ None, (char **)NULL, 0, &sizehints);
++ }
++
++ *winRet = win;
++}
++
++
++static void
++event_loop(Display *dpy)
++{
++ Window win;
++ make_window(dpy, "glxgears", 0, 0, WinWidth, WinHeight, &win);
++ XMapWindow(dpy, win);
++
++ while (1) {
++ while (XPending(dpy) > 0) {
++ XEvent event;
++ XNextEvent(dpy, &event);
++ switch (event.type) {
++ case Expose:
++ /* we'll redraw below */
++ break;
++ case ConfigureNotify:
++ WinWidth = event.xconfigure.width;
++ WinHeight = event.xconfigure.height;
++ break;
++ case KeyPress:
++ {
++ char buffer[10];
++ int r, code;
++ code = XLookupKeysym(&event.xkey, 0);
++ if (code == XK_Left) {
++ view_roty += 5.0;
++ }
++ else if (code == XK_Right) {
++ view_roty -= 5.0;
++ }
++ else if (code == XK_Up) {
++ view_rotx += 5.0;
++ }
++ else if (code == XK_Down) {
++ view_rotx -= 5.0;
++ }
++ else {
++ r = XLookupString(&event.xkey, buffer, sizeof(buffer),
++ NULL, NULL);
++ if (buffer[0] == 27) {
++ /* escape */
++ return;
++ }
++ }
++ }
++ }
++ }
++
++ {
++ static int frames = 0;
++ static double tRot0 = -1.0, tRate0 = -1.0;
++ double dt, t = current_time();
++ if (tRot0 < 0.0)
++ tRot0 = t;
++ dt = t - tRot0;
++ tRot0 = t;
++
++ /* advance rotation for next frame */
++ angle += 70.0 * dt; /* 70 degrees per second */
++ if (angle > 3600.0)
++ angle -= 3600.0;
++
++ draw( dpy, win );
++
++ frames++;
++
++ if (tRate0 < 0.0)
++ tRate0 = t;
++
++ if (t - tRate0 >= 1.0) {
++ GLfloat seconds = t - tRate0;
++ GLfloat fps = frames / seconds;
++ printf("%d frames in %3.1f seconds = %6.3f FPS\n", frames, seconds,
++ fps);
++ tRate0 = t;
++
++ /* Destroy window and create new one */
++ XDestroyWindow(dpy, win);
++ make_window(dpy, "glxgears",
++ (int)(fps * 100) % 100, (int)(fps * 100) % 100, /* x,y */
++ WinWidth, WinHeight, &win);
++ XMapWindow(dpy, win);
++
++ frames = 0;
++ }
++ }
++ }
++}
++
++
++int
++main(int argc, char *argv[])
++{
++ Display *dpy;
++ char *dpyName = NULL;
++ GLboolean printInfo = GL_FALSE;
++ int i;
++
++ for (i = 1; i < argc; i++) {
++ if (strcmp(argv[i], "-display") == 0) {
++ dpyName = argv[i+1];
++ i++;
++ }
++ else if (strcmp(argv[i], "-info") == 0) {
++ printInfo = GL_TRUE;
++ }
++ else
++ printf("Warrning: unknown parameter: %s\n", argv[i]);
++ }
++
++ dpy = XOpenDisplay(dpyName);
++ if (!dpy) {
++ fprintf(stderr, "Error: couldn't open display %s\n",
++ XDisplayName(dpyName));
++ return -1;
++ }
++
++ 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));
++ }
++
++ event_loop(dpy);
++
++ XCloseDisplay(dpy);
++
++ return 0;
++}
+diff -Naurp Mesa-7.8.1/progs/xdemos/glxdemo.c Mesa-7.8.1.patched/progs/xdemos/glxdemo.c
+--- Mesa-7.8.1/progs/xdemos/glxdemo.c 1970-01-01 01:00:00.000000000 +0100
++++ Mesa-7.8.1.patched/progs/xdemos/glxdemo.c 2010-06-13 13:45:06.789793146 +0200
+@@ -0,0 +1,127 @@
++
++
++/*
++ * A demonstration of using the GLX functions. This program is in the
++ * public domain.
++ *
++ * Brian Paul
++ */
++
++#include <GL/gl.h>
++#include <GL/glx.h>
++#include <stdio.h>
++#include <stdlib.h>
++
++
++
++static void redraw( Display *dpy, Window w )
++{
++ printf("Redraw event\n");
++
++ glClear( GL_COLOR_BUFFER_BIT );
++
++ glColor3f( 1.0, 1.0, 0.0 );
++ glRectf( -0.8, -0.8, 0.8, 0.8 );
++
++ glXSwapBuffers( dpy, w );
++}
++
++
++
++static void resize( unsigned int width, unsigned int height )
++{
++ printf("Resize event\n");
++ glViewport( 0, 0, width, height );
++ glMatrixMode( GL_PROJECTION );
++ glLoadIdentity();
++ glOrtho( -1.0, 1.0, -1.0, 1.0, -1.0, 1.0 );
++}
++
++
++
++static Window make_rgb_db_window( Display *dpy,
++ unsigned int width, unsigned int height )
++{
++ int attrib[] = { GLX_RGBA,
++ GLX_RED_SIZE, 1,
++ GLX_GREEN_SIZE, 1,
++ GLX_BLUE_SIZE, 1,
++ GLX_DOUBLEBUFFER,
++ None };
++ int scrnum;
++ XSetWindowAttributes attr;
++ unsigned long mask;
++ Window root;
++ Window win;
++ GLXContext ctx;
++ XVisualInfo *visinfo;
++
++ scrnum = DefaultScreen( dpy );
++ root = RootWindow( dpy, scrnum );
++
++ visinfo = glXChooseVisual( dpy, scrnum, attrib );
++ if (!visinfo) {
++ printf("Error: couldn't get an RGB, Double-buffered visual\n");
++ exit(1);
++ }
++
++ /* window attributes */
++ attr.background_pixel = 0;
++ attr.border_pixel = 0;
++ attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone);
++ attr.event_mask = StructureNotifyMask | ExposureMask;
++ mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
++
++ win = XCreateWindow( dpy, root, 0, 0, width, height,
++ 0, visinfo->depth, InputOutput,
++ visinfo->visual, mask, &attr );
++
++ ctx = glXCreateContext( dpy, visinfo, NULL, True );
++ if (!ctx) {
++ printf("Error: glXCreateContext failed\n");
++ exit(1);
++ }
++
++ glXMakeCurrent( dpy, win, ctx );
++
++ return win;
++}
++
++
++static void event_loop( Display *dpy )
++{
++ XEvent event;
++
++ while (1) {
++ XNextEvent( dpy, &event );
++
++ switch (event.type) {
++ case Expose:
++ redraw( dpy, event.xany.window );
++ break;
++ case ConfigureNotify:
++ resize( event.xconfigure.width, event.xconfigure.height );
++ break;
++ }
++ }
++}
++
++
++
++int main( int argc, char *argv[] )
++{
++ Display *dpy;
++ Window win;
++
++ dpy = XOpenDisplay(NULL);
++
++ win = make_rgb_db_window( dpy, 300, 300 );
++
++ glShadeModel( GL_FLAT );
++ glClearColor( 0.5, 0.5, 0.5, 1.0 );
++
++ XMapWindow( dpy, win );
++
++ event_loop( dpy );
++ return 0;
++}
+diff -Naurp Mesa-7.8.1/progs/xdemos/glxgears.c Mesa-7.8.1.patched/progs/xdemos/glxgears.c
+--- Mesa-7.8.1/progs/xdemos/glxgears.c 1970-01-01 01:00:00.000000000 +0100
++++ Mesa-7.8.1.patched/progs/xdemos/glxgears.c 2010-06-13 13:45:06.789793146 +0200
+@@ -0,0 +1,787 @@
++/*
++ * 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.
++ */
++
++/*
++ * This is a port of the infamous "gears" demo to straight GLX (i.e. no GLUT)
++ * Port by Brian Paul 23 March 2001
++ *
++ * See usage() below for command line options.
++ */
++
++
++#include <math.h>
++#include <stdlib.h>
++#include <stdio.h>
++#include <string.h>
++#include <X11/Xlib.h>
++#include <X11/keysym.h>
++#include <GL/gl.h>
++#include <GL/glx.h>
++#include <GL/glxext.h>
++
++#ifndef GLX_MESA_swap_control
++#define GLX_MESA_swap_control 1
++typedef int (*PFNGLXGETSWAPINTERVALMESAPROC)(void);
++#endif
++
++
++#define BENCHMARK
++
++#ifdef BENCHMARK
++
++/* XXX this probably isn't very portable */
++
++#include <sys/time.h>
++#include <unistd.h>
++
++/* return current time (in seconds) */
++static double
++current_time(void)
++{
++ struct timeval tv;
++#ifdef __VMS
++ (void) gettimeofday(&tv, NULL );
++#else
++ struct timezone tz;
++ (void) gettimeofday(&tv, &tz);
++#endif
++ return (double) tv.tv_sec + tv.tv_usec / 1000000.0;
++}
++
++#else /*BENCHMARK*/
++
++/* dummy */
++static double
++current_time(void)
++{
++ /* update this function for other platforms! */
++ static double t = 0.0;
++ static int warn = 1;
++ if (warn) {
++ fprintf(stderr, "Warning: current_time() not implemented!!\n");
++ warn = 0;
++ }
++ return t += 1.0;
++}
++
++#endif /*BENCHMARK*/
++
++
++
++#ifndef M_PI
++#define M_PI 3.14159265
++#endif
++
++
++/** Event handler results: */
++#define NOP 0
++#define EXIT 1
++#define DRAW 2
++
++static GLfloat view_rotx = 20.0, view_roty = 30.0, view_rotz = 0.0;
++static GLint gear1, gear2, gear3;
++static GLfloat angle = 0.0;
++
++static GLboolean fullscreen = GL_FALSE; /* Create a single fullscreen window */
++static GLboolean stereo = GL_FALSE; /* Enable stereo. */
++static GLboolean animate = GL_TRUE; /* Animation */
++static GLfloat eyesep = 5.0; /* Eye separation. */
++static GLfloat fix_point = 40.0; /* Fixation point distance. */
++static GLfloat left, right, asp; /* Stereo frustum params. */
++
++
++/*
++ *
++ * Draw a gear wheel. You'll probably want to call this function when
++ * building a display list since we do a lot of trig here.
++ *
++ * Input: 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
++gear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width,
++ GLint teeth, GLfloat tooth_depth)
++{
++ GLint i;
++ GLfloat r0, r1, r2;
++ GLfloat angle, da;
++ GLfloat u, v, len;
++
++ r0 = inner_radius;
++ r1 = outer_radius - tooth_depth / 2.0;
++ r2 = outer_radius + tooth_depth / 2.0;
++
++ da = 2.0 * M_PI / teeth / 4.0;
++
++ glShadeModel(GL_FLAT);
++
++ glNormal3f(0.0, 0.0, 1.0);
++
++ /* draw front face */
++ glBegin(GL_QUAD_STRIP);
++ for (i = 0; i <= teeth; i++) {
++ angle = i * 2.0 * M_PI / teeth;
++ glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
++ glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
++ if (i < teeth) {
++ glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
++ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
++ width * 0.5);
++ }
++ }
++ glEnd();
++
++ /* draw front sides of teeth */
++ glBegin(GL_QUADS);
++ da = 2.0 * M_PI / teeth / 4.0;
++ for (i = 0; i < teeth; i++) {
++ angle = i * 2.0 * M_PI / teeth;
++
++ glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
++ glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
++ glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
++ width * 0.5);
++ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
++ width * 0.5);
++ }
++ glEnd();
++
++ glNormal3f(0.0, 0.0, -1.0);
++
++ /* draw back face */
++ glBegin(GL_QUAD_STRIP);
++ for (i = 0; i <= teeth; i++) {
++ angle = i * 2.0 * M_PI / teeth;
++ glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
++ glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
++ if (i < teeth) {
++ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
++ -width * 0.5);
++ glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
++ }
++ }
++ glEnd();
++
++ /* draw back sides of teeth */
++ glBegin(GL_QUADS);
++ da = 2.0 * M_PI / teeth / 4.0;
++ for (i = 0; i < teeth; i++) {
++ angle = i * 2.0 * M_PI / teeth;
++
++ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
++ -width * 0.5);
++ glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
++ -width * 0.5);
++ glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
++ glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
++ }
++ glEnd();
++
++ /* draw outward faces of teeth */
++ glBegin(GL_QUAD_STRIP);
++ for (i = 0; i < teeth; i++) {
++ angle = i * 2.0 * M_PI / teeth;
++
++ glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
++ glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
++ u = r2 * cos(angle + da) - r1 * cos(angle);
++ v = r2 * sin(angle + da) - r1 * sin(angle);
++ len = sqrt(u * u + v * v);
++ u /= len;
++ v /= len;
++ glNormal3f(v, -u, 0.0);
++ glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
++ glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
++ glNormal3f(cos(angle), sin(angle), 0.0);
++ glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
++ width * 0.5);
++ glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
++ -width * 0.5);
++ u = r1 * cos(angle + 3 * da) - r2 * cos(angle + 2 * da);
++ v = r1 * sin(angle + 3 * da) - r2 * sin(angle + 2 * da);
++ glNormal3f(v, -u, 0.0);
++ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
++ width * 0.5);
++ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
++ -width * 0.5);
++ glNormal3f(cos(angle), sin(angle), 0.0);
++ }
++
++ glVertex3f(r1 * cos(0), r1 * sin(0), width * 0.5);
++ glVertex3f(r1 * cos(0), r1 * sin(0), -width * 0.5);
++
++ glEnd();
++
++ glShadeModel(GL_SMOOTH);
++
++ /* draw inside radius cylinder */
++ glBegin(GL_QUAD_STRIP);
++ for (i = 0; i <= teeth; i++) {
++ angle = i * 2.0 * M_PI / teeth;
++ glNormal3f(-cos(angle), -sin(angle), 0.0);
++ glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
++ glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
++ }
++ glEnd();
++}
++
++
++static void
++draw(void)
++{
++ 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);
++ glCallList(gear1);
++ glPopMatrix();
++
++ glPushMatrix();
++ glTranslatef(3.1, -2.0, 0.0);
++ glRotatef(-2.0 * angle - 9.0, 0.0, 0.0, 1.0);
++ glCallList(gear2);
++ glPopMatrix();
++
++ glPushMatrix();
++ glTranslatef(-3.1, 4.2, 0.0);
++ glRotatef(-2.0 * angle - 25.0, 0.0, 0.0, 1.0);
++ glCallList(gear3);
++ glPopMatrix();
++
++ glPopMatrix();
++}
++
++
++static void
++draw_gears(void)
++{
++ if (stereo) {
++ /* First left eye. */
++ glDrawBuffer(GL_BACK_LEFT);
++
++ glMatrixMode(GL_PROJECTION);
++ glLoadIdentity();
++ glFrustum(left, right, -asp, asp, 5.0, 60.0);
++
++ glMatrixMode(GL_MODELVIEW);
++
++ glPushMatrix();
++ glTranslated(+0.5 * eyesep, 0.0, 0.0);
++ draw();
++ glPopMatrix();
++
++ /* Then right eye. */
++ glDrawBuffer(GL_BACK_RIGHT);
++
++ glMatrixMode(GL_PROJECTION);
++ glLoadIdentity();
++ glFrustum(-right, -left, -asp, asp, 5.0, 60.0);
++
++ glMatrixMode(GL_MODELVIEW);
++
++ glPushMatrix();
++ glTranslated(-0.5 * eyesep, 0.0, 0.0);
++ draw();
++ glPopMatrix();
++ }
++ else {
++ draw();
++ }
++}
++
++
++/** Draw single frame, do SwapBuffers, compute FPS */
++static void
++draw_frame(Display *dpy, Window win)
++{
++ static int frames = 0;
++ static double tRot0 = -1.0, tRate0 = -1.0;
++ double dt, t = current_time();
++
++ if (tRot0 < 0.0)
++ tRot0 = t;
++ dt = t - tRot0;
++ tRot0 = t;
++
++ if (animate) {
++ /* advance rotation for next frame */
++ angle += 70.0 * dt; /* 70 degrees per second */
++ if (angle > 3600.0)
++ angle -= 3600.0;
++ }
++
++ draw_gears();
++ glXSwapBuffers(dpy, win);
++
++ frames++;
++
++ if (tRate0 < 0.0)
++ tRate0 = t;
++ if (t - tRate0 >= 5.0) {
++ GLfloat seconds = t - tRate0;
++ GLfloat fps = frames / seconds;
++ printf("%d frames in %3.1f seconds = %6.3f FPS\n", frames, seconds,
++ fps);
++ tRate0 = t;
++ frames = 0;
++ }
++}
++
++
++/* new window size or exposure */
++static void
++reshape(int width, int height)
++{
++ glViewport(0, 0, (GLint) width, (GLint) height);
++
++ if (stereo) {
++ GLfloat w;
++
++ asp = (GLfloat) height / (GLfloat) width;
++ w = fix_point * (1.0 / 5.0);
++
++ left = -5.0 * ((w - 0.5 * eyesep) / fix_point);
++ right = 5.0 * ((w + 0.5 * eyesep) / fix_point);
++ }
++ else {
++ GLfloat h = (GLfloat) height / (GLfloat) width;
++
++ glMatrixMode(GL_PROJECTION);
++ glLoadIdentity();
++ glFrustum(-1.0, 1.0, -h, h, 5.0, 60.0);
++ }
++
++ glMatrixMode(GL_MODELVIEW);
++ glLoadIdentity();
++ glTranslatef(0.0, 0.0, -40.0);
++}
++
++
++
++static void
++init(void)
++{
++ static GLfloat pos[4] = { 5.0, 5.0, 10.0, 0.0 };
++ static GLfloat red[4] = { 0.8, 0.1, 0.0, 1.0 };
++ static GLfloat green[4] = { 0.0, 0.8, 0.2, 1.0 };
++ static GLfloat blue[4] = { 0.2, 0.2, 1.0, 1.0 };
++
++ glLightfv(GL_LIGHT0, GL_POSITION, pos);
++ glEnable(GL_CULL_FACE);
++ glEnable(GL_LIGHTING);
++ glEnable(GL_LIGHT0);
++ glEnable(GL_DEPTH_TEST);
++
++ /* make the gears */
++ gear1 = glGenLists(1);
++ glNewList(gear1, GL_COMPILE);
++ glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red);
++ gear(1.0, 4.0, 1.0, 20, 0.7);
++ glEndList();
++
++ gear2 = glGenLists(1);
++ glNewList(gear2, GL_COMPILE);
++ glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green);
++ gear(0.5, 2.0, 2.0, 10, 0.7);
++ glEndList();
++
++ gear3 = glGenLists(1);
++ glNewList(gear3, GL_COMPILE);
++ glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue);
++ gear(1.3, 2.0, 0.5, 10, 0.7);
++ glEndList();
++
++ glEnable(GL_NORMALIZE);
++}
++
++
++/**
++ * Remove window border/decorations.
++ */
++static void
++no_border( Display *dpy, Window w)
++{
++ static const unsigned MWM_HINTS_DECORATIONS = (1 << 1);
++ static const int PROP_MOTIF_WM_HINTS_ELEMENTS = 5;
++
++ typedef struct
++ {
++ unsigned long flags;
++ unsigned long functions;
++ unsigned long decorations;
++ long inputMode;
++ unsigned long status;
++ } PropMotifWmHints;
++
++ PropMotifWmHints motif_hints;
++ Atom prop, proptype;
++ unsigned long flags = 0;
++
++ /* setup the property */
++ motif_hints.flags = MWM_HINTS_DECORATIONS;
++ motif_hints.decorations = flags;
++
++ /* get the atom for the property */
++ prop = XInternAtom( dpy, "_MOTIF_WM_HINTS", True );
++ if (!prop) {
++ /* something went wrong! */
++ return;
++ }
++
++ /* not sure this is correct, seems to work, XA_WM_HINTS didn't work */
++ proptype = prop;
++
++ XChangeProperty( dpy, w, /* display, window */
++ prop, proptype, /* property, type */
++ 32, /* format: 32-bit datums */
++ PropModeReplace, /* mode */
++ (unsigned char *) &motif_hints, /* data */
++ PROP_MOTIF_WM_HINTS_ELEMENTS /* nelements */
++ );
++}
++
++
++/*
++ * Create an RGB, double-buffered window.
++ * Return the window and context handles.
++ */
++static void
++make_window( Display *dpy, const char *name,
++ int x, int y, int width, int height,
++ Window *winRet, GLXContext *ctxRet)
++{
++ int attribs[] = { GLX_RGBA,
++ GLX_RED_SIZE, 1,
++ GLX_GREEN_SIZE, 1,
++ GLX_BLUE_SIZE, 1,
++ GLX_DOUBLEBUFFER,
++ GLX_DEPTH_SIZE, 1,
++ None };
++ int stereoAttribs[] = { GLX_RGBA,
++ GLX_RED_SIZE, 1,
++ GLX_GREEN_SIZE, 1,
++ GLX_BLUE_SIZE, 1,
++ GLX_DOUBLEBUFFER,
++ GLX_DEPTH_SIZE, 1,
++ GLX_STEREO,
++ None };
++ int scrnum;
++ XSetWindowAttributes attr;
++ unsigned long mask;
++ Window root;
++ Window win;
++ GLXContext ctx;
++ XVisualInfo *visinfo;
++
++ scrnum = DefaultScreen( dpy );
++ root = RootWindow( dpy, scrnum );
++
++ if (fullscreen) {
++ x = 0; y = 0;
++ width = DisplayWidth( dpy, scrnum );
++ height = DisplayHeight( dpy, scrnum );
++ }
++
++ if (stereo)
++ visinfo = glXChooseVisual( dpy, scrnum, stereoAttribs );
++ else
++ visinfo = glXChooseVisual( dpy, scrnum, attribs );
++ if (!visinfo) {
++ if (stereo) {
++ printf("Error: couldn't get an RGB, "
++ "Double-buffered, Stereo visual\n");
++ } else
++ printf("Error: couldn't get an RGB, Double-buffered visual\n");
++ exit(1);
++ }
++
++ /* window attributes */
++ attr.background_pixel = 0;
++ attr.border_pixel = 0;
++ attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone);
++ attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
++ /* XXX this is a bad way to get a borderless window! */
++ mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
++
++ win = XCreateWindow( dpy, root, x, y, width, height,
++ 0, visinfo->depth, InputOutput,
++ visinfo->visual, mask, &attr );
++
++ if (fullscreen)
++ no_border(dpy, win);
++
++ /* set hints and properties */
++ {
++ XSizeHints sizehints;
++ sizehints.x = x;
++ sizehints.y = y;
++ sizehints.width = width;
++ sizehints.height = height;
++ sizehints.flags = USSize | USPosition;
++ XSetNormalHints(dpy, win, &sizehints);
++ XSetStandardProperties(dpy, win, name, name,
++ None, (char **)NULL, 0, &sizehints);
++ }
++
++ ctx = glXCreateContext( dpy, visinfo, NULL, True );
++ if (!ctx) {
++ printf("Error: glXCreateContext failed\n");
++ exit(1);
++ }
++
++ XFree(visinfo);
++
++ *winRet = win;
++ *ctxRet = ctx;
++}
++
++
++/**
++ * Determine whether or not a GLX extension is supported.
++ */
++static int
++is_glx_extension_supported(Display *dpy, const char *query)
++{
++ const int scrnum = DefaultScreen(dpy);
++ const char *glx_extensions = NULL;
++ const size_t len = strlen(query);
++ const char *ptr;
++
++ if (glx_extensions == NULL) {
++ glx_extensions = glXQueryExtensionsString(dpy, scrnum);
++ }
++
++ ptr = strstr(glx_extensions, query);
++ return ((ptr != NULL) && ((ptr[len] == ' ') || (ptr[len] == '\0')));
++}
++
++
++/**
++ * Attempt to determine whether or not the display is synched to vblank.
++ */
++static void
++query_vsync(Display *dpy, GLXDrawable drawable)
++{
++ int interval = 0;
++
++#if defined(GLX_EXT_swap_control)
++ if (is_glx_extension_supported(dpy, "GLX_EXT_swap_control")) {
++ unsigned int tmp = -1;
++ glXQueryDrawable(dpy, drawable, GLX_SWAP_INTERVAL_EXT, &tmp);
++ interval = tmp;
++ } else
++#endif
++ if (is_glx_extension_supported(dpy, "GLX_MESA_swap_control")) {
++ PFNGLXGETSWAPINTERVALMESAPROC pglXGetSwapIntervalMESA =
++ (PFNGLXGETSWAPINTERVALMESAPROC)
++ glXGetProcAddressARB((const GLubyte *) "glXGetSwapIntervalMESA");
++
++ interval = (*pglXGetSwapIntervalMESA)();
++ } else if (is_glx_extension_supported(dpy, "GLX_SGI_swap_control")) {
++ /* The default swap interval with this extension is 1. Assume that it
++ * is set to the default.
++ *
++ * Many Mesa-based drivers default to 0, but all of these drivers also
++ * export GLX_MESA_swap_control. In that case, this branch will never
++ * be taken, and the correct result should be reported.
++ */
++ interval = 1;
++ }
++
++
++ if (interval > 0) {
++ printf("Running synchronized to the vertical refresh. The framerate should be\n");
++ if (interval == 1) {
++ printf("approximately the same as the monitor refresh rate.\n");
++ } else if (interval > 1) {
++ printf("approximately 1/%d the monitor refresh rate.\n",
++ interval);
++ }
++ }
++}
++
++/**
++ * Handle one X event.
++ * \return NOP, EXIT or DRAW
++ */
++static int
++handle_event(Display *dpy, Window win, XEvent *event)
++{
++ (void) dpy;
++ (void) win;
++
++ switch (event->type) {
++ case Expose:
++ return DRAW;
++ case ConfigureNotify:
++ reshape(event->xconfigure.width, event->xconfigure.height);
++ break;
++ case KeyPress:
++ {
++ char buffer[10];
++ int r, code;
++ code = XLookupKeysym(&event->xkey, 0);
++ if (code == XK_Left) {
++ view_roty += 5.0;
++ }
++ else if (code == XK_Right) {
++ view_roty -= 5.0;
++ }
++ else if (code == XK_Up) {
++ view_rotx += 5.0;
++ }
++ else if (code == XK_Down) {
++ view_rotx -= 5.0;
++ }
++ else {
++ r = XLookupString(&event->xkey, buffer, sizeof(buffer),
++ NULL, NULL);
++ if (buffer[0] == 27) {
++ /* escape */
++ return EXIT;
++ }
++ else if (buffer[0] == 'a' || buffer[0] == 'A') {
++ animate = !animate;
++ }
++ }
++ return DRAW;
++ }
++ }
++ return NOP;
++}
++
++
++static void
++event_loop(Display *dpy, Window win)
++{
++ while (1) {
++ int op;
++ while (!animate || XPending(dpy) > 0) {
++ XEvent event;
++ XNextEvent(dpy, &event);
++ op = handle_event(dpy, win, &event);
++ if (op == EXIT)
++ return;
++ else if (op == DRAW)
++ break;
++ }
++
++ draw_frame(dpy, win);
++ }
++}
++
++
++static void
++usage(void)
++{
++ printf("Usage:\n");
++ printf(" -display <displayname> set the display to run on\n");
++ printf(" -stereo run in stereo mode\n");
++ printf(" -fullscreen run in fullscreen mode\n");
++ printf(" -info display OpenGL renderer info\n");
++ printf(" -geometry WxH+X+Y window geometry\n");
++}
++
++
++int
++main(int argc, char *argv[])
++{
++ unsigned int winWidth = 300, winHeight = 300;
++ int x = 0, y = 0;
++ Display *dpy;
++ Window win;
++ GLXContext ctx;
++ char *dpyName = NULL;
++ GLboolean printInfo = GL_FALSE;
++ int i;
++
++ for (i = 1; i < argc; i++) {
++ if (strcmp(argv[i], "-display") == 0) {
++ dpyName = argv[i+1];
++ i++;
++ }
++ else if (strcmp(argv[i], "-info") == 0) {
++ printInfo = GL_TRUE;
++ }
++ else if (strcmp(argv[i], "-stereo") == 0) {
++ stereo = GL_TRUE;
++ }
++ else if (strcmp(argv[i], "-fullscreen") == 0) {
++ fullscreen = GL_TRUE;
++ }
++ else if (i < argc-1 && strcmp(argv[i], "-geometry") == 0) {
++ XParseGeometry(argv[i+1], &x, &y, &winWidth, &winHeight);
++ i++;
++ }
++ else {
++ usage();
++ return -1;
++ }
++ }
++
++ dpy = XOpenDisplay(dpyName);
++ if (!dpy) {
++ printf("Error: couldn't open display %s\n",
++ dpyName ? dpyName : getenv("DISPLAY"));
++ return -1;
++ }
++
++ make_window(dpy, "glxgears", x, y, winWidth, winHeight, &win, &ctx);
++ XMapWindow(dpy, win);
++ glXMakeCurrent(dpy, win, ctx);
++ query_vsync(dpy, win);
++
++ 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));
++ }
++
++ init();
++
++ /* Set initial projection/viewing transformation.
++ * We can't be sure we'll get a ConfigureNotify event when the window
++ * first appears.
++ */
++ reshape(winWidth, winHeight);
++
++ event_loop(dpy, win);
++
++ glDeleteLists(gear1, 1);
++ glDeleteLists(gear2, 1);
++ glDeleteLists(gear3, 1);
++ glXMakeCurrent(dpy, None, NULL);
++ glXDestroyContext(dpy, ctx);
++ XDestroyWindow(dpy, win);
++ XCloseDisplay(dpy);
++
++ return 0;
++}
+diff -Naurp Mesa-7.8.1/progs/xdemos/glxgears_fbconfig.c Mesa-7.8.1.patched/progs/xdemos/glxgears_fbconfig.c
+--- Mesa-7.8.1/progs/xdemos/glxgears_fbconfig.c 1970-01-01 01:00:00.000000000 +0100
++++ Mesa-7.8.1.patched/progs/xdemos/glxgears_fbconfig.c 2010-06-13 13:45:06.788792936 +0200
+@@ -0,0 +1,632 @@
++/*
++ * 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.
++ */
++
++/**
++ * \file glxgears_fbconfig.c
++ * Yet-another-version of gears. Originally ported to GLX by Brian Paul on
++ * 23 March 2001. Modified to use fbconfigs by Ian Romanick on 10 Feb 2004.
++ *
++ * Command line options:
++ * -info print GL implementation information
++ *
++ * \author Brian Paul
++ * \author Ian Romanick <idr@us.ibm.com>
++ */
++
++
++#define GLX_GLXEXT_PROTOTYPES
++
++#include <math.h>
++#include <stdlib.h>
++#include <stdio.h>
++#include <string.h>
++#include <X11/Xlib.h>
++#include <X11/keysym.h>
++#include <GL/gl.h>
++#include <GL/glx.h>
++#include <GL/glxext.h>
++#include <assert.h>
++#include "pbutil.h"
++
++static PFNGLXCHOOSEFBCONFIGPROC choose_fbconfig = NULL;
++static PFNGLXGETVISUALFROMFBCONFIGPROC get_visual_from_fbconfig = NULL;
++static PFNGLXCREATENEWCONTEXTPROC create_new_context = NULL;
++static PFNGLXCREATEWINDOWPROC create_window = NULL;
++static PFNGLXDESTROYWINDOWPROC destroy_window = NULL;
++
++#define BENCHMARK
++
++#ifdef BENCHMARK
++
++/* XXX this probably isn't very portable */
++
++#include <sys/time.h>
++#include <unistd.h>
++
++/* return current time (in seconds) */
++static int
++current_time(void)
++{
++ struct timeval tv;
++#ifdef __VMS
++ (void) gettimeofday(&tv, NULL );
++#else
++ struct timezone tz;
++ (void) gettimeofday(&tv, &tz);
++#endif
++ return (int) tv.tv_sec;
++}
++
++#else /*BENCHMARK*/
++
++/* dummy */
++static int
++current_time(void)
++{
++ return 0;
++}
++
++#endif /*BENCHMARK*/
++
++
++
++#ifndef M_PI
++#define M_PI 3.14159265
++#endif
++
++
++static GLfloat view_rotx = 20.0, view_roty = 30.0, view_rotz = 0.0;
++static GLint gear1, gear2, gear3;
++static GLfloat angle = 0.0;
++
++
++/*
++ *
++ * Draw a gear wheel. You'll probably want to call this function when
++ * building a display list since we do a lot of trig here.
++ *
++ * Input: 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
++gear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width,
++ GLint teeth, GLfloat tooth_depth)
++{
++ GLint i;
++ GLfloat r0, r1, r2;
++ GLfloat angle, da;
++ GLfloat u, v, len;
++
++ r0 = inner_radius;
++ r1 = outer_radius - tooth_depth / 2.0;
++ r2 = outer_radius + tooth_depth / 2.0;
++
++ da = 2.0 * M_PI / teeth / 4.0;
++
++ glShadeModel(GL_FLAT);
++
++ glNormal3f(0.0, 0.0, 1.0);
++
++ /* draw front face */
++ glBegin(GL_QUAD_STRIP);
++ for (i = 0; i <= teeth; i++) {
++ angle = i * 2.0 * M_PI / teeth;
++ glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
++ glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
++ if (i < teeth) {
++ glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
++ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
++ width * 0.5);
++ }
++ }
++ glEnd();
++
++ /* draw front sides of teeth */
++ glBegin(GL_QUADS);
++ da = 2.0 * M_PI / teeth / 4.0;
++ for (i = 0; i < teeth; i++) {
++ angle = i * 2.0 * M_PI / teeth;
++
++ glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
++ glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
++ glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
++ width * 0.5);
++ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
++ width * 0.5);
++ }
++ glEnd();
++
++ glNormal3f(0.0, 0.0, -1.0);
++
++ /* draw back face */
++ glBegin(GL_QUAD_STRIP);
++ for (i = 0; i <= teeth; i++) {
++ angle = i * 2.0 * M_PI / teeth;
++ glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
++ glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
++ if (i < teeth) {
++ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
++ -width * 0.5);
++ glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
++ }
++ }
++ glEnd();
++
++ /* draw back sides of teeth */
++ glBegin(GL_QUADS);
++ da = 2.0 * M_PI / teeth / 4.0;
++ for (i = 0; i < teeth; i++) {
++ angle = i * 2.0 * M_PI / teeth;
++
++ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
++ -width * 0.5);
++ glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
++ -width * 0.5);
++ glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
++ glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
++ }
++ glEnd();
++
++ /* draw outward faces of teeth */
++ glBegin(GL_QUAD_STRIP);
++ for (i = 0; i < teeth; i++) {
++ angle = i * 2.0 * M_PI / teeth;
++
++ glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
++ glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
++ u = r2 * cos(angle + da) - r1 * cos(angle);
++ v = r2 * sin(angle + da) - r1 * sin(angle);
++ len = sqrt(u * u + v * v);
++ u /= len;
++ v /= len;
++ glNormal3f(v, -u, 0.0);
++ glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
++ glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
++ glNormal3f(cos(angle), sin(angle), 0.0);
++ glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
++ width * 0.5);
++ glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
++ -width * 0.5);
++ u = r1 * cos(angle + 3 * da) - r2 * cos(angle + 2 * da);
++ v = r1 * sin(angle + 3 * da) - r2 * sin(angle + 2 * da);
++ glNormal3f(v, -u, 0.0);
++ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
++ width * 0.5);
++ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
++ -width * 0.5);
++ glNormal3f(cos(angle), sin(angle), 0.0);
++ }
++
++ glVertex3f(r1 * cos(0), r1 * sin(0), width * 0.5);
++ glVertex3f(r1 * cos(0), r1 * sin(0), -width * 0.5);
++
++ glEnd();
++
++ glShadeModel(GL_SMOOTH);
++
++ /* draw inside radius cylinder */
++ glBegin(GL_QUAD_STRIP);
++ for (i = 0; i <= teeth; i++) {
++ angle = i * 2.0 * M_PI / teeth;
++ glNormal3f(-cos(angle), -sin(angle), 0.0);
++ glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
++ glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
++ }
++ glEnd();
++}
++
++
++static void
++draw(void)
++{
++ 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);
++ glCallList(gear1);
++ glPopMatrix();
++
++ glPushMatrix();
++ glTranslatef(3.1, -2.0, 0.0);
++ glRotatef(-2.0 * angle - 9.0, 0.0, 0.0, 1.0);
++ glCallList(gear2);
++ glPopMatrix();
++
++ glPushMatrix();
++ glTranslatef(-3.1, 4.2, 0.0);
++ glRotatef(-2.0 * angle - 25.0, 0.0, 0.0, 1.0);
++ glCallList(gear3);
++ glPopMatrix();
++
++ glPopMatrix();
++}
++
++
++/* new window size or exposure */
++static void
++reshape(int width, int height)
++{
++ GLfloat h = (GLfloat) height / (GLfloat) width;
++
++ glViewport(0, 0, (GLint) width, (GLint) height);
++ glMatrixMode(GL_PROJECTION);
++ glLoadIdentity();
++ glFrustum(-1.0, 1.0, -h, h, 5.0, 60.0);
++ glMatrixMode(GL_MODELVIEW);
++ glLoadIdentity();
++ glTranslatef(0.0, 0.0, -40.0);
++}
++
++
++static void
++init(void)
++{
++ static GLfloat pos[4] = { 5.0, 5.0, 10.0, 0.0 };
++ static GLfloat red[4] = { 0.8, 0.1, 0.0, 1.0 };
++ static GLfloat green[4] = { 0.0, 0.8, 0.2, 1.0 };
++ static GLfloat blue[4] = { 0.2, 0.2, 1.0, 1.0 };
++
++ glLightfv(GL_LIGHT0, GL_POSITION, pos);
++ glEnable(GL_CULL_FACE);
++ glEnable(GL_LIGHTING);
++ glEnable(GL_LIGHT0);
++ glEnable(GL_DEPTH_TEST);
++
++ /* make the gears */
++ gear1 = glGenLists(1);
++ glNewList(gear1, GL_COMPILE);
++ glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red);
++ gear(1.0, 4.0, 1.0, 20, 0.7);
++ glEndList();
++
++ gear2 = glGenLists(1);
++ glNewList(gear2, GL_COMPILE);
++ glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green);
++ gear(0.5, 2.0, 2.0, 10, 0.7);
++ glEndList();
++
++ gear3 = glGenLists(1);
++ glNewList(gear3, GL_COMPILE);
++ glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue);
++ gear(1.3, 2.0, 0.5, 10, 0.7);
++ glEndList();
++
++ glEnable(GL_NORMALIZE);
++}
++
++
++static GLXWindow
++dummy_create_window(Display *dpy, GLXFBConfig config, Window win,
++ const int *attrib_list)
++{
++ (void) dpy;
++ (void) config;
++ (void) attrib_list;
++
++ return (GLXWindow) win;
++}
++
++
++static void
++dummy_destroy_window(Display *dpy, GLXWindow win)
++{
++ (void) dpy;
++ (void) win;
++}
++
++
++/**
++ * Initialize fbconfig related function pointers.
++ */
++static void
++init_fbconfig_functions(Display *dpy, int scrnum)
++{
++ const char * glx_extensions;
++ const char * match;
++ static const char ext_name[] = "GLX_SGIX_fbconfig";
++ const size_t len = strlen( ext_name );
++ int major;
++ int minor;
++ GLboolean ext_version_supported;
++ GLboolean glx_1_3_supported;
++
++
++ /* Determine if GLX 1.3 or greater is supported.
++ */
++ glXQueryVersion(dpy, & major, & minor);
++ glx_1_3_supported = (major == 1) && (minor >= 3);
++
++ /* Determine if GLX_SGIX_fbconfig is supported.
++ */
++ glx_extensions = glXQueryExtensionsString(dpy, scrnum);
++ match = strstr( glx_extensions, ext_name );
++
++ ext_version_supported = (match != NULL)
++ && ((match[len] == '\0') || (match[len] == ' '));
++
++ printf( "GLX 1.3 is %ssupported.\n",
++ (glx_1_3_supported) ? "" : "not " );
++ printf( "%s is %ssupported.\n",
++ ext_name, (ext_version_supported) ? "" : "not " );
++
++ if ( glx_1_3_supported ) {
++ choose_fbconfig = (PFNGLXCHOOSEFBCONFIGPROC)
++ glXGetProcAddressARB((GLubyte *) "glXChooseFBConfig");
++ get_visual_from_fbconfig = (PFNGLXGETVISUALFROMFBCONFIGPROC)
++ glXGetProcAddressARB((GLubyte *) "glXGetVisualFromFBConfig");
++ create_new_context = (PFNGLXCREATENEWCONTEXTPROC)
++ glXGetProcAddressARB((GLubyte *) "glXCreateNewContext");
++ create_window = (PFNGLXCREATEWINDOWPROC)
++ glXGetProcAddressARB((GLubyte *) "glXCreateWindow");
++ destroy_window = (PFNGLXDESTROYWINDOWPROC)
++ glXGetProcAddressARB((GLubyte *) "glXDestroyWindow");
++ }
++ else if ( ext_version_supported ) {
++ choose_fbconfig = (PFNGLXCHOOSEFBCONFIGPROC)
++ glXGetProcAddressARB((GLubyte *) "glXChooseFBConfigSGIX");
++ get_visual_from_fbconfig = (PFNGLXGETVISUALFROMFBCONFIGPROC)
++ glXGetProcAddressARB((GLubyte *) "glXGetVisualFromFBConfigSGIX");
++ create_new_context = (PFNGLXCREATENEWCONTEXTPROC)
++ glXGetProcAddressARB((GLubyte *) "glXCreateContextWithConfigSGIX");
++ create_window = dummy_create_window;
++ destroy_window = dummy_destroy_window;
++ }
++ else {
++ printf( "This demo requires either GLX 1.3 or %s be supported.\n",
++ ext_name );
++ exit(1);
++ }
++
++ if ( choose_fbconfig == NULL ) {
++ printf( "glXChooseFBConfig not found!\n" );
++ exit(1);
++ }
++
++ if ( get_visual_from_fbconfig == NULL ) {
++ printf( "glXGetVisualFromFBConfig not found!\n" );
++ exit(1);
++ }
++
++ if ( create_new_context == NULL ) {
++ printf( "glXCreateNewContext not found!\n" );
++ exit(1);
++ }
++}
++
++
++/*
++ * Create an RGB, double-buffered window.
++ * Return the window and context handles.
++ */
++static void
++make_window( Display *dpy, const char *name,
++ int x, int y, int width, int height,
++ Window *winRet, GLXWindow *glxWinRet, GLXContext *ctxRet)
++{
++ int attrib[] = { GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
++ GLX_RENDER_TYPE, GLX_RGBA_BIT,
++ GLX_RED_SIZE, 1,
++ GLX_GREEN_SIZE, 1,
++ GLX_BLUE_SIZE, 1,
++ GLX_DOUBLEBUFFER, GL_TRUE,
++ GLX_DEPTH_SIZE, 1,
++ None };
++ GLXFBConfig * fbconfig;
++ int num_configs;
++ int scrnum;
++ int i;
++ XSetWindowAttributes attr;
++ unsigned long mask;
++ Window root;
++ Window win;
++ GLXWindow glxWin;
++ GLXContext ctx;
++ XVisualInfo *visinfo;
++
++ scrnum = DefaultScreen( dpy );
++ root = RootWindow( dpy, scrnum );
++
++ init_fbconfig_functions(dpy, scrnum);
++ fbconfig = (*choose_fbconfig)(dpy, scrnum, attrib, & num_configs);
++ if (fbconfig == NULL) {
++ printf("Error: couldn't get an RGB, Double-buffered visual\n");
++ exit(1);
++ }
++
++ printf("\nThe following fbconfigs meet the requirements. The first one "
++ "will be used.\n\n");
++ for ( i = 0 ; i < num_configs ; i++ ) {
++ PrintFBConfigInfo(dpy, scrnum, fbconfig[i], GL_TRUE);
++ }
++
++ /* window attributes */
++ visinfo = (*get_visual_from_fbconfig)(dpy, fbconfig[0]);
++ assert(visinfo != NULL);
++ attr.background_pixel = 0;
++ attr.border_pixel = 0;
++ attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone);
++ attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
++ mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
++
++ win = XCreateWindow( dpy, root, 0, 0, width, 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(dpy, win, &sizehints);
++ XSetStandardProperties(dpy, win, name, name,
++ None, (char **)NULL, 0, &sizehints);
++ }
++
++ glxWin = (*create_window)(dpy, fbconfig[0], win, NULL);
++
++ ctx = (*create_new_context)(dpy, fbconfig[0], GLX_RGBA_TYPE, NULL, GL_TRUE);
++ if (!ctx) {
++ printf("Error: glXCreateNewContext failed\n");
++ exit(1);
++ }
++
++ XFree(fbconfig);
++
++ *glxWinRet = glxWin;
++ *winRet = win;
++ *ctxRet = ctx;
++}
++
++
++static void
++event_loop(Display *dpy, GLXWindow win)
++{
++ while (1) {
++ while (XPending(dpy) > 0) {
++ XEvent event;
++ XNextEvent(dpy, &event);
++ switch (event.type) {
++ case Expose:
++ /* we'll redraw below */
++ break;
++ case ConfigureNotify:
++ reshape(event.xconfigure.width, event.xconfigure.height);
++ break;
++ case KeyPress:
++ {
++ char buffer[10];
++ int r, code;
++ code = XLookupKeysym(&event.xkey, 0);
++ if (code == XK_Left) {
++ view_roty += 5.0;
++ }
++ else if (code == XK_Right) {
++ view_roty -= 5.0;
++ }
++ else if (code == XK_Up) {
++ view_rotx += 5.0;
++ }
++ else if (code == XK_Down) {
++ view_rotx -= 5.0;
++ }
++ else {
++ r = XLookupString(&event.xkey, buffer, sizeof(buffer),
++ NULL, NULL);
++ if (buffer[0] == 27) {
++ /* escape */
++ return;
++ }
++ }
++ }
++ }
++ }
++
++ /* next frame */
++ angle += 2.0;
++
++ draw();
++ glXSwapBuffers(dpy, win);
++
++ /* calc framerate */
++ {
++ static int t0 = -1;
++ static int frames = 0;
++ int t = current_time();
++
++ if (t0 < 0)
++ t0 = t;
++
++ frames++;
++
++ if (t - t0 >= 5.0) {
++ GLfloat seconds = t - t0;
++ GLfloat fps = frames / seconds;
++ printf("%d frames in %3.1f seconds = %6.3f FPS\n", frames, seconds,
++ fps);
++ t0 = t;
++ frames = 0;
++ }
++ }
++ }
++}
++
++
++int
++main(int argc, char *argv[])
++{
++ Display *dpy;
++ Window win;
++ GLXWindow glxWin;
++ GLXContext ctx;
++ const char *dpyName = NULL;
++ GLboolean printInfo = GL_FALSE;
++ int i;
++
++ for (i = 1; i < argc; i++) {
++ if (strcmp(argv[i], "-display") == 0) {
++ dpyName = argv[i+1];
++ i++;
++ }
++ else if (strcmp(argv[i], "-info") == 0) {
++ printInfo = GL_TRUE;
++ }
++ }
++
++ dpy = XOpenDisplay(dpyName);
++ if (!dpy) {
++ printf("Error: couldn't open display %s\n", XDisplayName(dpyName));
++ return -1;
++ }
++
++ make_window(dpy, "glxgears", 0, 0, 300, 300, &win, &glxWin, &ctx);
++ XMapWindow(dpy, win);
++ glXMakeCurrent(dpy, glxWin, ctx);
++
++ 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));
++ }
++
++ init();
++
++ event_loop(dpy, glxWin);
++
++ glXDestroyContext(dpy, ctx);
++ destroy_window(dpy, glxWin);
++ XDestroyWindow(dpy, win);
++ XCloseDisplay(dpy);
++
++ return 0;
++}
+diff -Naurp Mesa-7.8.1/progs/xdemos/glxgears_pixmap.c Mesa-7.8.1.patched/progs/xdemos/glxgears_pixmap.c
+--- Mesa-7.8.1/progs/xdemos/glxgears_pixmap.c 1970-01-01 01:00:00.000000000 +0100
++++ Mesa-7.8.1.patched/progs/xdemos/glxgears_pixmap.c 2010-06-13 13:45:06.789793146 +0200
+@@ -0,0 +1,547 @@
++/*
++ * Copyright (C) 1999-2001 Brian Paul All Rights Reserved.
++ * Copyright (C) 2008 Red Hat, Inc 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.
++ */
++
++/**
++ * \file glxgears_pixmap.c
++ * Yet-another-version of gears. Originally ported to GLX by Brian Paul on
++ * 23 March 2001. Modified to use fbconfigs by Ian Romanick on 10 Feb 2004.
++ *
++ * Command line options:
++ * -info print GL implementation information
++ *
++ * \author Brian Paul
++ * \author Ian Romanick <idr@us.ibm.com>
++ * \author Kristian Hoegsberg <krh@redhat.com>
++ */
++
++
++#define GLX_GLXEXT_PROTOTYPES
++
++#include <math.h>
++#include <stdlib.h>
++#include <stdio.h>
++#include <string.h>
++#include <X11/Xlib.h>
++#include <X11/keysym.h>
++#include <GL/gl.h>
++#include <GL/glx.h>
++#include <GL/glxext.h>
++#include <assert.h>
++#include "pbutil.h"
++
++#define BENCHMARK
++
++#ifdef BENCHMARK
++
++/* XXX this probably isn't very portable */
++
++#include <sys/time.h>
++#include <unistd.h>
++
++/* return current time (in seconds) */
++static int
++current_time(void)
++{
++ struct timeval tv;
++#ifdef __VMS
++ (void) gettimeofday(&tv, NULL );
++#else
++ struct timezone tz;
++ (void) gettimeofday(&tv, &tz);
++#endif
++ return (int) tv.tv_sec;
++}
++
++#else /*BENCHMARK*/
++
++/* dummy */
++static int
++current_time(void)
++{
++ return 0;
++}
++
++#endif /*BENCHMARK*/
++
++
++
++#ifndef M_PI
++#define M_PI 3.14159265
++#endif
++
++
++static GLfloat view_rotx = 20.0, view_roty = 30.0, view_rotz = 0.0;
++static GLint gear1, gear2, gear3;
++static GLfloat angle = 0.0;
++
++
++/*
++ *
++ * Draw a gear wheel. You'll probably want to call this function when
++ * building a display list since we do a lot of trig here.
++ *
++ * Input: 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
++gear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width,
++ GLint teeth, GLfloat tooth_depth)
++{
++ GLint i;
++ GLfloat r0, r1, r2;
++ GLfloat angle, da;
++ GLfloat u, v, len;
++
++ r0 = inner_radius;
++ r1 = outer_radius - tooth_depth / 2.0;
++ r2 = outer_radius + tooth_depth / 2.0;
++
++ da = 2.0 * M_PI / teeth / 4.0;
++
++ glShadeModel(GL_FLAT);
++
++ glNormal3f(0.0, 0.0, 1.0);
++
++ /* draw front face */
++ glBegin(GL_QUAD_STRIP);
++ for (i = 0; i <= teeth; i++) {
++ angle = i * 2.0 * M_PI / teeth;
++ glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
++ glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
++ if (i < teeth) {
++ glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
++ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
++ width * 0.5);
++ }
++ }
++ glEnd();
++
++ /* draw front sides of teeth */
++ glBegin(GL_QUADS);
++ da = 2.0 * M_PI / teeth / 4.0;
++ for (i = 0; i < teeth; i++) {
++ angle = i * 2.0 * M_PI / teeth;
++
++ glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
++ glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
++ glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
++ width * 0.5);
++ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
++ width * 0.5);
++ }
++ glEnd();
++
++ glNormal3f(0.0, 0.0, -1.0);
++
++ /* draw back face */
++ glBegin(GL_QUAD_STRIP);
++ for (i = 0; i <= teeth; i++) {
++ angle = i * 2.0 * M_PI / teeth;
++ glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
++ glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
++ if (i < teeth) {
++ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
++ -width * 0.5);
++ glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
++ }
++ }
++ glEnd();
++
++ /* draw back sides of teeth */
++ glBegin(GL_QUADS);
++ da = 2.0 * M_PI / teeth / 4.0;
++ for (i = 0; i < teeth; i++) {
++ angle = i * 2.0 * M_PI / teeth;
++
++ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
++ -width * 0.5);
++ glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
++ -width * 0.5);
++ glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
++ glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
++ }
++ glEnd();
++
++ /* draw outward faces of teeth */
++ glBegin(GL_QUAD_STRIP);
++ for (i = 0; i < teeth; i++) {
++ angle = i * 2.0 * M_PI / teeth;
++
++ glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
++ glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
++ u = r2 * cos(angle + da) - r1 * cos(angle);
++ v = r2 * sin(angle + da) - r1 * sin(angle);
++ len = sqrt(u * u + v * v);
++ u /= len;
++ v /= len;
++ glNormal3f(v, -u, 0.0);
++ glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
++ glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
++ glNormal3f(cos(angle), sin(angle), 0.0);
++ glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
++ width * 0.5);
++ glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
++ -width * 0.5);
++ u = r1 * cos(angle + 3 * da) - r2 * cos(angle + 2 * da);
++ v = r1 * sin(angle + 3 * da) - r2 * sin(angle + 2 * da);
++ glNormal3f(v, -u, 0.0);
++ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
++ width * 0.5);
++ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
++ -width * 0.5);
++ glNormal3f(cos(angle), sin(angle), 0.0);
++ }
++
++ glVertex3f(r1 * cos(0), r1 * sin(0), width * 0.5);
++ glVertex3f(r1 * cos(0), r1 * sin(0), -width * 0.5);
++
++ glEnd();
++
++ glShadeModel(GL_SMOOTH);
++
++ /* draw inside radius cylinder */
++ glBegin(GL_QUAD_STRIP);
++ for (i = 0; i <= teeth; i++) {
++ angle = i * 2.0 * M_PI / teeth;
++ glNormal3f(-cos(angle), -sin(angle), 0.0);
++ glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
++ glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
++ }
++ glEnd();
++}
++
++
++static void
++draw(void)
++{
++ 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);
++ glCallList(gear1);
++ glPopMatrix();
++
++ glPushMatrix();
++ glTranslatef(3.1, -2.0, 0.0);
++ glRotatef(-2.0 * angle - 9.0, 0.0, 0.0, 1.0);
++ glCallList(gear2);
++ glPopMatrix();
++
++ glPushMatrix();
++ glTranslatef(-3.1, 4.2, 0.0);
++ glRotatef(-2.0 * angle - 25.0, 0.0, 0.0, 1.0);
++ glCallList(gear3);
++ glPopMatrix();
++
++ glPopMatrix();
++}
++
++
++struct gears {
++ Window win;
++ GLXContext ctx;
++ Pixmap pixmap;
++ GLXPixmap glxpixmap;
++ GC gc;
++ int width, height;
++};
++
++
++/* new window size or exposure */
++static void
++reshape(struct gears *gears, int width, int height)
++{
++ gears->width = width;
++ gears->height = height;
++}
++
++
++static void
++init(int width, int height)
++{
++ static GLfloat pos[4] = { 5.0, 5.0, 10.0, 0.0 };
++ static GLfloat red[4] = { 0.8, 0.1, 0.0, 1.0 };
++ static GLfloat green[4] = { 0.0, 0.8, 0.2, 1.0 };
++ static GLfloat blue[4] = { 0.2, 0.2, 1.0, 1.0 };
++ GLfloat h = (GLfloat) height / (GLfloat) width;
++
++ glLightfv(GL_LIGHT0, GL_POSITION, pos);
++ glEnable(GL_CULL_FACE);
++ glEnable(GL_LIGHTING);
++ glEnable(GL_LIGHT0);
++ glEnable(GL_DEPTH_TEST);
++
++ /* make the gears */
++ gear1 = glGenLists(1);
++ glNewList(gear1, GL_COMPILE);
++ glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red);
++ gear(1.0, 4.0, 1.0, 20, 0.7);
++ glEndList();
++
++ gear2 = glGenLists(1);
++ glNewList(gear2, GL_COMPILE);
++ glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green);
++ gear(0.5, 2.0, 2.0, 10, 0.7);
++ glEndList();
++
++ gear3 = glGenLists(1);
++ glNewList(gear3, GL_COMPILE);
++ glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue);
++ gear(1.3, 2.0, 0.5, 10, 0.7);
++ glEndList();
++
++ glEnable(GL_NORMALIZE);
++
++ glViewport(0, 0, (GLint) width, (GLint) height);
++ glMatrixMode(GL_PROJECTION);
++ glLoadIdentity();
++ glFrustum(-1.0, 1.0, -h, h, 5.0, 60.0);
++ glMatrixMode(GL_MODELVIEW);
++ glLoadIdentity();
++ glTranslatef(0.0, 0.0, -40.0);
++}
++
++/*
++ * Create an RGB, double-buffered window.
++ * Return the window and context handles.
++ */
++static void
++make_window( Display *dpy, const char *name,
++ int x, int y, int width, int height, struct gears *gears)
++{
++ int attrib[] = { GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
++ GLX_RENDER_TYPE, GLX_RGBA_BIT,
++ GLX_RED_SIZE, 1,
++ GLX_GREEN_SIZE, 1,
++ GLX_BLUE_SIZE, 1,
++ GLX_DOUBLEBUFFER, GL_FALSE,
++ GLX_DEPTH_SIZE, 1,
++ None };
++ GLXFBConfig * fbconfig;
++ int num_configs;
++ int scrnum;
++ XSetWindowAttributes attr;
++ unsigned long mask;
++ Window root;
++ XVisualInfo *visinfo;
++
++ gears->width = width;
++ gears->height = height;
++
++ scrnum = DefaultScreen( dpy );
++ root = RootWindow( dpy, scrnum );
++
++ fbconfig = glXChooseFBConfig(dpy, scrnum, attrib, & num_configs);
++ if (fbconfig == NULL) {
++ printf("Error: couldn't get an RGB, Double-buffered visual\n");
++ exit(1);
++ }
++
++ /* window attributes */
++ visinfo = glXGetVisualFromFBConfig(dpy, fbconfig[0]);
++ assert(visinfo != NULL);
++ attr.background_pixel = 0;
++ attr.border_pixel = 0;
++ attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone);
++ attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
++ mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
++
++ gears->win = XCreateWindow( dpy, root, 0, 0, width, 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(dpy, gears->win, &sizehints);
++ XSetStandardProperties(dpy, gears->win, name, name,
++ None, (char **)NULL, 0, &sizehints);
++ }
++
++ gears->gc = XCreateGC(dpy, gears->win, 0, NULL);
++
++ gears->pixmap = XCreatePixmap(dpy, gears->win,
++ width, height, visinfo->depth);
++ if (!gears->pixmap) {
++ printf("Error: XCreatePixmap failed\n");
++ exit(-1);
++ }
++
++ gears->glxpixmap = glXCreatePixmap(dpy, fbconfig[0], gears->pixmap, NULL);
++ if (!gears->glxpixmap) {
++ printf("Error: glXCreatePixmap failed\n");
++ exit(-1);
++ }
++
++ gears->ctx = glXCreateNewContext(dpy, fbconfig[0],
++ GLX_RGBA_TYPE, NULL, GL_TRUE);
++ if (!gears->ctx) {
++ printf("Error: glXCreateNewContext failed\n");
++ exit(1);
++ }
++
++ XFree(fbconfig);
++}
++
++
++static void
++event_loop(Display *dpy, struct gears *gears)
++{
++ int x, y;
++
++ while (1) {
++ while (XPending(dpy) > 0) {
++ XEvent event;
++ XNextEvent(dpy, &event);
++ switch (event.type) {
++ case Expose:
++ /* we'll redraw below */
++ break;
++ case ConfigureNotify:
++ reshape(gears, event.xconfigure.width, event.xconfigure.height);
++ break;
++ case KeyPress:
++ {
++ char buffer[10];
++ int r, code;
++ code = XLookupKeysym(&event.xkey, 0);
++ if (code == XK_Left) {
++ view_roty += 5.0;
++ }
++ else if (code == XK_Right) {
++ view_roty -= 5.0;
++ }
++ else if (code == XK_Up) {
++ view_rotx += 5.0;
++ }
++ else if (code == XK_Down) {
++ view_rotx -= 5.0;
++ }
++ else {
++ r = XLookupString(&event.xkey, buffer, sizeof(buffer),
++ NULL, NULL);
++ if (buffer[0] == 27) {
++ /* escape */
++ return;
++ }
++ }
++ }
++ }
++ }
++
++ /* next frame */
++ angle += 2.0;
++
++ draw();
++ glFinish();
++
++ for (x = 0; x < gears->width; x += 100)
++ for (y = 0; y < gears->width; y += 100)
++ XCopyArea(dpy, gears->pixmap, gears->win, gears->gc,
++ 50, 50, 100, 100, x, y);
++
++ /* calc framerate */
++ {
++ static int t0 = -1;
++ static int frames = 0;
++ int t = current_time();
++
++ if (t0 < 0)
++ t0 = t;
++
++ frames++;
++
++ if (t - t0 >= 5.0) {
++ GLfloat seconds = t - t0;
++ GLfloat fps = frames / seconds;
++ printf("%d frames in %3.1f seconds = %6.3f FPS\n", frames, seconds,
++ fps);
++ t0 = t;
++ frames = 0;
++ }
++ }
++ }
++}
++
++
++int
++main(int argc, char *argv[])
++{
++ Display *dpy;
++ const char *dpyName = NULL;
++ GLboolean printInfo = GL_FALSE;
++ struct gears gears;
++ int i, width = 200, height = 200;
++
++ for (i = 1; i < argc; i++) {
++ if (strcmp(argv[i], "-display") == 0) {
++ dpyName = argv[i+1];
++ i++;
++ }
++ else if (strcmp(argv[i], "-info") == 0) {
++ printInfo = GL_TRUE;
++ }
++ }
++
++ dpy = XOpenDisplay(dpyName);
++ if (!dpy) {
++ printf("Error: couldn't open display %s\n", XDisplayName(dpyName));
++ return -1;
++ }
++
++ make_window(dpy, "glxgears", 0, 0, width, height, &gears);
++ XMapWindow(dpy, gears.win);
++ glXMakeCurrent(dpy, gears.glxpixmap, gears.ctx);
++
++ 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));
++ }
++
++ init(width, height);
++
++ event_loop(dpy, &gears);
++
++ glXDestroyContext(dpy, gears.ctx);
++ XDestroyWindow(dpy, gears.win);
++ glXDestroyPixmap(dpy, gears.pixmap);
++ XFreePixmap(dpy, gears.pixmap);
++ XCloseDisplay(dpy);
++
++ return 0;
++}
+diff -Naurp Mesa-7.8.1/progs/xdemos/glxheads.c Mesa-7.8.1.patched/progs/xdemos/glxheads.c
+--- Mesa-7.8.1/progs/xdemos/glxheads.c 1970-01-01 01:00:00.000000000 +0100
++++ Mesa-7.8.1.patched/progs/xdemos/glxheads.c 2010-06-13 13:45:06.789793146 +0200
+@@ -0,0 +1,313 @@
++
++/*
++ * Exercise multiple GLX connections on multiple X displays.
++ * Direct GLX contexts are attempted first, then indirect.
++ * Each window will display a spinning green triangle.
++ *
++ * Copyright (C) 2000 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 <GL/gl.h>
++#include <GL/glx.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <unistd.h>
++
++
++
++/*
++ * Each display/window/context:
++ */
++struct head {
++ char DisplayName[1000];
++ Display *Dpy;
++ Window Win;
++ GLXContext Context;
++ float Angle;
++ char Renderer[1000];
++ char Vendor[1000];
++ char Version[1000];
++};
++
++
++#define MAX_HEADS 20
++static struct head Heads[MAX_HEADS];
++static int NumHeads = 0;
++
++
++static void
++Error(const char *display, const char *msg)
++{
++ fprintf(stderr, "Error on display %s - %s\n", XDisplayName(display), msg);
++ exit(1);
++}
++
++
++static struct head *
++AddHead(const char *displayName)
++{
++ Display *dpy;
++ Window win;
++ GLXContext ctx;
++ int attrib[] = { GLX_RGBA,
++ GLX_RED_SIZE, 1,
++ GLX_GREEN_SIZE, 1,
++ GLX_BLUE_SIZE, 1,
++ GLX_DOUBLEBUFFER,
++ None };
++ int scrnum;
++ XSetWindowAttributes attr;
++ unsigned long mask;
++ Window root;
++ XVisualInfo *visinfo;
++ int width = 300, height = 300;
++ int xpos = 10, ypos = 10;
++
++ if (NumHeads >= MAX_HEADS)
++ return NULL;
++
++ dpy = XOpenDisplay(displayName);
++ if (!dpy) {
++ Error(displayName, "Unable to open display");
++ return NULL;
++ }
++
++ scrnum = DefaultScreen(dpy);
++ root = RootWindow(dpy, scrnum);
++
++ visinfo = glXChooseVisual(dpy, scrnum, attrib);
++ if (!visinfo) {
++ Error(displayName, "Unable to find RGB, double-buffered visual");
++ return NULL;
++ }
++
++ /* window attributes */
++ attr.background_pixel = 0;
++ attr.border_pixel = 0;
++ attr.colormap = XCreateColormap(dpy, root, visinfo->visual, AllocNone);
++ attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
++ mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
++
++ win = XCreateWindow(dpy, root, 0, 0, width, height,
++ 0, visinfo->depth, InputOutput,
++ visinfo->visual, mask, &attr);
++ if (!win) {
++ Error(displayName, "Couldn't create window");
++ return NULL;
++ }
++
++ {
++ XSizeHints sizehints;
++ sizehints.x = xpos;
++ sizehints.y = ypos;
++ sizehints.width = width;
++ sizehints.height = height;
++ sizehints.flags = USSize | USPosition;
++ XSetNormalHints(dpy, win, &sizehints);
++ XSetStandardProperties(dpy, win, displayName, displayName,
++ None, (char **)NULL, 0, &sizehints);
++ }
++
++
++ ctx = glXCreateContext(dpy, visinfo, NULL, True);
++ if (!ctx) {
++ Error(displayName, "Couldn't create GLX context");
++ return NULL;
++ }
++
++ XMapWindow(dpy, win);
++
++ if (!glXMakeCurrent(dpy, win, ctx)) {
++ Error(displayName, "glXMakeCurrent failed");
++ printf("glXMakeCurrent failed in Redraw()\n");
++ return NULL;
++ }
++
++ /* save the info for this head */
++ {
++ struct head *h = &Heads[NumHeads];
++ const char * tmp;
++
++ if (strlen(displayName) + 1 > sizeof(h->DisplayName)) {
++ Error(displayName, "displayName string length overflow");
++ return NULL;
++ }
++ strcpy(h->DisplayName, displayName);
++
++ h->Dpy = dpy;
++ h->Win = win;
++ h->Context = ctx;
++ h->Angle = 0.0;
++
++ tmp = (char *) glGetString(GL_VERSION);
++ if (strlen(tmp) + 1 > sizeof(h->Version)) {
++ Error(displayName, "GL_VERSION string length overflow");
++ return NULL;
++ }
++ strcpy(h->Version, tmp);
++
++ tmp = (char *) glGetString(GL_VENDOR);
++ if (strlen(tmp) + 1 > sizeof(h->Vendor)) {
++ Error(displayName, "GL_VENDOR string length overflow");
++ return NULL;
++ }
++ strcpy(h->Vendor, tmp);
++
++ tmp = (char *) glGetString(GL_RENDERER);
++ if (strlen(tmp) + 1 > sizeof(h->Renderer)) {
++ Error(displayName, "GL_RENDERER string length overflow");
++ return NULL;
++ }
++ strcpy(h->Renderer, tmp);
++
++ NumHeads++;
++ return &Heads[NumHeads-1];
++ }
++
++}
++
++
++static void
++Redraw(struct head *h)
++{
++ if (!glXMakeCurrent(h->Dpy, h->Win, h->Context)) {
++ Error(h->DisplayName, "glXMakeCurrent failed");
++ printf("glXMakeCurrent failed in Redraw()\n");
++ return;
++ }
++
++ h->Angle += 1.0;
++
++ glShadeModel(GL_FLAT);
++ glClearColor(0.5, 0.5, 0.5, 1.0);
++ glClear(GL_COLOR_BUFFER_BIT);
++
++ /* draw green triangle */
++ glColor3f(0.0, 1.0, 0.0);
++ glPushMatrix();
++ glRotatef(h->Angle, 0, 0, 1);
++ glBegin(GL_TRIANGLES);
++ glVertex2f(0, 0.8);
++ glVertex2f(-0.8, -0.7);
++ glVertex2f(0.8, -0.7);
++ glEnd();
++ glPopMatrix();
++
++ glXSwapBuffers(h->Dpy, h->Win);
++}
++
++
++
++static void
++Resize(const struct head *h, unsigned int width, unsigned int height)
++{
++ if (!glXMakeCurrent(h->Dpy, h->Win, h->Context)) {
++ Error(h->DisplayName, "glXMakeCurrent failed in Resize()");
++ return;
++ }
++ glFlush();
++ glViewport(0, 0, width, height);
++ glMatrixMode(GL_PROJECTION);
++ glLoadIdentity();
++ glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
++}
++
++
++
++static void
++EventLoop(void)
++{
++ while (1) {
++ int i;
++ for (i = 0; i < NumHeads; i++) {
++ struct head *h = &Heads[i];
++ while (XPending(h->Dpy) > 0) {
++ XEvent event;
++ XNextEvent(h->Dpy, &event);
++ if (event.xany.window == h->Win) {
++ switch (event.type) {
++ case Expose:
++ Redraw(h);
++ break;
++ case ConfigureNotify:
++ Resize(h, event.xconfigure.width, event.xconfigure.height);
++ break;
++ case KeyPress:
++ return;
++ default:
++ /*no-op*/ ;
++ }
++ }
++ else {
++ printf("window mismatch\n");
++ }
++ }
++ Redraw(h);
++ }
++ usleep(1);
++ }
++}
++
++
++
++static void
++PrintInfo(const struct head *h)
++{
++ printf("Name: %s\n", h->DisplayName);
++ printf(" Display: %p\n", (void *) h->Dpy);
++ printf(" Window: 0x%x\n", (int) h->Win);
++ printf(" Context: 0x%lx\n", (long) h->Context);
++ printf(" GL_VERSION: %s\n", h->Version);
++ printf(" GL_VENDOR: %s\n", h->Vendor);
++ printf(" GL_RENDERER: %s\n", h->Renderer);
++}
++
++
++int
++main(int argc, char *argv[])
++{
++ int i;
++ if (argc == 1) {
++ struct head *h;
++ printf("glxheads: exercise multiple GLX connections (any key = exit)\n");
++ printf("Usage:\n");
++ printf(" glxheads xdisplayname ...\n");
++ printf("Example:\n");
++ printf(" glxheads :0 mars:0 venus:1\n");
++
++ h = AddHead(XDisplayName(NULL));
++ if (h)
++ PrintInfo(h);
++ }
++ else {
++ for (i = 1; i < argc; i++) {
++ const char *name = argv[i];
++ struct head *h = AddHead(name);
++ if (h) {
++ PrintInfo(h);
++ }
++ }
++ }
++
++ EventLoop();
++ return 0;
++}
+diff -Naurp Mesa-7.8.1/progs/xdemos/glxinfo.c Mesa-7.8.1.patched/progs/xdemos/glxinfo.c
+--- Mesa-7.8.1/progs/xdemos/glxinfo.c 1970-01-01 01:00:00.000000000 +0100
++++ Mesa-7.8.1.patched/progs/xdemos/glxinfo.c 2010-06-13 13:45:06.788792936 +0200
+@@ -0,0 +1,1195 @@
++/*
++ * Copyright (C) 1999-2006 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.
++ */
++
++
++/*
++ * This program is a work-alike of the IRIX glxinfo program.
++ * Command line options:
++ * -t print wide table
++ * -v print verbose information
++ * -display DisplayName specify the X display to interogate
++ * -b only print ID of "best" visual on screen 0
++ * -i use indirect rendering connection only
++ * -l print interesting OpenGL limits (added 5 Sep 2002)
++ *
++ * Brian Paul 26 January 2000
++ */
++
++#define GLX_GLXEXT_PROTOTYPES
++
++#include <X11/Xlib.h>
++#include <X11/Xutil.h>
++#include <GL/gl.h>
++#include <GL/glx.h>
++#include <stdio.h>
++#include <string.h>
++#include <stdlib.h>
++
++
++#ifndef GLX_NONE_EXT
++#define GLX_NONE_EXT 0x8000
++#endif
++
++#ifndef GLX_TRANSPARENT_RGB
++#define GLX_TRANSPARENT_RGB 0x8008
++#endif
++
++#ifndef GLX_RGBA_BIT
++#define GLX_RGBA_BIT 0x00000001
++#endif
++
++#ifndef GLX_COLOR_INDEX_BIT
++#define GLX_COLOR_INDEX_BIT 0x00000002
++#endif
++
++typedef enum
++{
++ Normal,
++ Wide,
++ Verbose
++} InfoMode;
++
++
++struct visual_attribs
++{
++ /* X visual attribs */
++ int id;
++ int klass;
++ int depth;
++ int redMask, greenMask, blueMask;
++ int colormapSize;
++ int bitsPerRGB;
++
++ /* GL visual attribs */
++ int supportsGL;
++ int transparentType;
++ int transparentRedValue;
++ int transparentGreenValue;
++ int transparentBlueValue;
++ int transparentAlphaValue;
++ int transparentIndexValue;
++ int bufferSize;
++ int level;
++ int render_type;
++ int doubleBuffer;
++ int stereo;
++ int auxBuffers;
++ int redSize, greenSize, blueSize, alphaSize;
++ int depthSize;
++ int stencilSize;
++ int accumRedSize, accumGreenSize, accumBlueSize, accumAlphaSize;
++ int numSamples, numMultisample;
++ int visualCaveat;
++};
++
++
++/*
++ * Print a list of extensions, with word-wrapping.
++ */
++static void
++print_extension_list(const char *ext)
++{
++ const char *indentString = " ";
++ const int indent = 4;
++ const int max = 79;
++ int width, i, j;
++
++ if (!ext || !ext[0])
++ return;
++
++ width = indent;
++ printf("%s", indentString);
++ i = j = 0;
++ while (1) {
++ if (ext[j] == ' ' || ext[j] == 0) {
++ /* found end of an extension name */
++ const int len = j - i;
++ if (width + len > max) {
++ /* start a new line */
++ printf("\n");
++ width = indent;
++ printf("%s", indentString);
++ }
++ /* print the extension name between ext[i] and ext[j] */
++ while (i < j) {
++ printf("%c", ext[i]);
++ i++;
++ }
++ /* either we're all done, or we'll continue with next extension */
++ width += len + 1;
++ if (ext[j] == 0) {
++ break;
++ }
++ else {
++ i++;
++ j++;
++ if (ext[j] == 0)
++ break;
++ printf(", ");
++ width += 2;
++ }
++ }
++ j++;
++ }
++ printf("\n");
++}
++
++
++static void
++print_display_info(Display *dpy)
++{
++ printf("name of display: %s\n", DisplayString(dpy));
++}
++
++
++/**
++ * Print interesting limits for vertex/fragment programs.
++ */
++static void
++print_program_limits(GLenum target)
++{
++#if defined(GL_ARB_vertex_program) || defined(GL_ARB_fragment_program)
++ struct token_name {
++ GLenum token;
++ const char *name;
++ };
++ static const struct token_name common_limits[] = {
++ { GL_MAX_PROGRAM_INSTRUCTIONS_ARB, "GL_MAX_PROGRAM_INSTRUCTIONS_ARB" },
++ { GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB, "GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB" },
++ { GL_MAX_PROGRAM_TEMPORARIES_ARB, "GL_MAX_PROGRAM_TEMPORARIES_ARB" },
++ { GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB, "GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB" },
++ { GL_MAX_PROGRAM_PARAMETERS_ARB, "GL_MAX_PROGRAM_PARAMETERS_ARB" },
++ { GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB, "GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB" },
++ { GL_MAX_PROGRAM_ATTRIBS_ARB, "GL_MAX_PROGRAM_ATTRIBS_ARB" },
++ { GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB, "GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB" },
++ { GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB, "GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB" },
++ { GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB, "GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB" },
++ { GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB, "GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB" },
++ { GL_MAX_PROGRAM_ENV_PARAMETERS_ARB, "GL_MAX_PROGRAM_ENV_PARAMETERS_ARB" },
++ { (GLenum) 0, NULL }
++ };
++ static const struct token_name fragment_limits[] = {
++ { GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB, "GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB" },
++ { GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB, "GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB" },
++ { GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB, "GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB" },
++ { GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB, "GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB" },
++ { GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB, "GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB" },
++ { GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB, "GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB" },
++ { (GLenum) 0, NULL }
++ };
++
++ PFNGLGETPROGRAMIVARBPROC GetProgramivARB_func = (PFNGLGETPROGRAMIVARBPROC)
++ glXGetProcAddressARB((GLubyte *) "glGetProgramivARB");
++
++ GLint max[1];
++ int i;
++
++ if (target == GL_VERTEX_PROGRAM_ARB) {
++ printf(" GL_VERTEX_PROGRAM_ARB:\n");
++ }
++ else if (target == GL_FRAGMENT_PROGRAM_ARB) {
++ printf(" GL_FRAGMENT_PROGRAM_ARB:\n");
++ }
++ else {
++ return; /* something's wrong */
++ }
++
++ for (i = 0; common_limits[i].token; i++) {
++ GetProgramivARB_func(target, common_limits[i].token, max);
++ if (glGetError() == GL_NO_ERROR) {
++ printf(" %s = %d\n", common_limits[i].name, max[0]);
++ }
++ }
++ if (target == GL_FRAGMENT_PROGRAM_ARB) {
++ for (i = 0; fragment_limits[i].token; i++) {
++ GetProgramivARB_func(target, fragment_limits[i].token, max);
++ if (glGetError() == GL_NO_ERROR) {
++ printf(" %s = %d\n", fragment_limits[i].name, max[0]);
++ }
++ }
++ }
++#endif /* GL_ARB_vertex_program / GL_ARB_fragment_program */
++}
++
++
++/**
++ * Print interesting limits for vertex/fragment shaders.
++ */
++static void
++print_shader_limits(GLenum target)
++{
++ struct token_name {
++ GLenum token;
++ const char *name;
++ };
++#if defined(GL_ARB_vertex_shader)
++ static const struct token_name vertex_limits[] = {
++ { GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB, "GL_MAX_VERTEX_UNIFORM_COMPONENTS_ARB" },
++ { GL_MAX_VARYING_FLOATS_ARB, "GL_MAX_VARYING_FLOATS_ARB" },
++ { GL_MAX_VERTEX_ATTRIBS_ARB, "GL_MAX_VERTEX_ATTRIBS_ARB" },
++ { GL_MAX_TEXTURE_IMAGE_UNITS_ARB, "GL_MAX_TEXTURE_IMAGE_UNITS_ARB" },
++ { GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB, "GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS_ARB" },
++ { GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB, "GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB" },
++ { GL_MAX_TEXTURE_COORDS_ARB, "GL_MAX_TEXTURE_COORDS_ARB" },
++ { (GLenum) 0, NULL }
++ };
++#endif
++#if defined(GL_ARB_fragment_shader)
++ static const struct token_name fragment_limits[] = {
++ { GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB, "GL_MAX_FRAGMENT_UNIFORM_COMPONENTS_ARB" },
++ { GL_MAX_TEXTURE_COORDS_ARB, "GL_MAX_TEXTURE_COORDS_ARB" },
++ { GL_MAX_TEXTURE_IMAGE_UNITS_ARB, "GL_MAX_TEXTURE_IMAGE_UNITS_ARB" },
++ { (GLenum) 0, NULL }
++ };
++#endif
++ GLint max[1];
++ int i;
++
++#if defined(GL_ARB_vertex_shader)
++ if (target == GL_VERTEX_SHADER_ARB) {
++ printf(" GL_VERTEX_SHADER_ARB:\n");
++ for (i = 0; vertex_limits[i].token; i++) {
++ glGetIntegerv(vertex_limits[i].token, max);
++ if (glGetError() == GL_NO_ERROR) {
++ printf(" %s = %d\n", vertex_limits[i].name, max[0]);
++ }
++ }
++ }
++#endif
++#if defined(GL_ARB_fragment_shader)
++ if (target == GL_FRAGMENT_SHADER_ARB) {
++ printf(" GL_FRAGMENT_SHADER_ARB:\n");
++ for (i = 0; fragment_limits[i].token; i++) {
++ glGetIntegerv(fragment_limits[i].token, max);
++ if (glGetError() == GL_NO_ERROR) {
++ printf(" %s = %d\n", fragment_limits[i].name, max[0]);
++ }
++ }
++ }
++#endif
++}
++
++
++/**
++ * Print interesting OpenGL implementation limits.
++ */
++static void
++print_limits(const char *extensions)
++{
++ struct token_name {
++ GLuint count;
++ GLenum token;
++ const char *name;
++ };
++ static const struct token_name limits[] = {
++ { 1, GL_MAX_ATTRIB_STACK_DEPTH, "GL_MAX_ATTRIB_STACK_DEPTH" },
++ { 1, GL_MAX_CLIENT_ATTRIB_STACK_DEPTH, "GL_MAX_CLIENT_ATTRIB_STACK_DEPTH" },
++ { 1, GL_MAX_CLIP_PLANES, "GL_MAX_CLIP_PLANES" },
++ { 1, GL_MAX_COLOR_MATRIX_STACK_DEPTH, "GL_MAX_COLOR_MATRIX_STACK_DEPTH" },
++ { 1, GL_MAX_ELEMENTS_VERTICES, "GL_MAX_ELEMENTS_VERTICES" },
++ { 1, GL_MAX_ELEMENTS_INDICES, "GL_MAX_ELEMENTS_INDICES" },
++ { 1, GL_MAX_EVAL_ORDER, "GL_MAX_EVAL_ORDER" },
++ { 1, GL_MAX_LIGHTS, "GL_MAX_LIGHTS" },
++ { 1, GL_MAX_LIST_NESTING, "GL_MAX_LIST_NESTING" },
++ { 1, GL_MAX_MODELVIEW_STACK_DEPTH, "GL_MAX_MODELVIEW_STACK_DEPTH" },
++ { 1, GL_MAX_NAME_STACK_DEPTH, "GL_MAX_NAME_STACK_DEPTH" },
++ { 1, GL_MAX_PIXEL_MAP_TABLE, "GL_MAX_PIXEL_MAP_TABLE" },
++ { 1, GL_MAX_PROJECTION_STACK_DEPTH, "GL_MAX_PROJECTION_STACK_DEPTH" },
++ { 1, GL_MAX_TEXTURE_STACK_DEPTH, "GL_MAX_TEXTURE_STACK_DEPTH" },
++ { 1, GL_MAX_TEXTURE_SIZE, "GL_MAX_TEXTURE_SIZE" },
++ { 1, GL_MAX_3D_TEXTURE_SIZE, "GL_MAX_3D_TEXTURE_SIZE" },
++ { 2, GL_MAX_VIEWPORT_DIMS, "GL_MAX_VIEWPORT_DIMS" },
++ { 2, GL_ALIASED_LINE_WIDTH_RANGE, "GL_ALIASED_LINE_WIDTH_RANGE" },
++ { 2, GL_SMOOTH_LINE_WIDTH_RANGE, "GL_SMOOTH_LINE_WIDTH_RANGE" },
++ { 2, GL_ALIASED_POINT_SIZE_RANGE, "GL_ALIASED_POINT_SIZE_RANGE" },
++ { 2, GL_SMOOTH_POINT_SIZE_RANGE, "GL_SMOOTH_POINT_SIZE_RANGE" },
++#if defined(GL_ARB_texture_cube_map)
++ { 1, GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB, "GL_MAX_CUBE_MAP_TEXTURE_SIZE_ARB" },
++#endif
++#if defined(GLX_NV_texture_rectangle)
++ { 1, GL_MAX_RECTANGLE_TEXTURE_SIZE_NV, "GL_MAX_RECTANGLE_TEXTURE_SIZE_NV" },
++#endif
++#if defined(GL_ARB_texture_compression)
++ { 1, GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB, "GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB" },
++#endif
++#if defined(GL_ARB_multitexture)
++ { 1, GL_MAX_TEXTURE_UNITS_ARB, "GL_MAX_TEXTURE_UNITS_ARB" },
++#endif
++#if defined(GL_EXT_texture_lod_bias)
++ { 1, GL_MAX_TEXTURE_LOD_BIAS_EXT, "GL_MAX_TEXTURE_LOD_BIAS_EXT" },
++#endif
++#if defined(GL_EXT_texture_filter_anisotropic)
++ { 1, GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, "GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT" },
++#endif
++#if defined(GL_ARB_draw_buffers)
++ { 1, GL_MAX_DRAW_BUFFERS_ARB, "GL_MAX_DRAW_BUFFERS_ARB" },
++#endif
++ { 0, (GLenum) 0, NULL }
++ };
++ GLint i, max[2];
++
++ printf("OpenGL limits:\n");
++ for (i = 0; limits[i].count; i++) {
++ glGetIntegerv(limits[i].token, max);
++ if (glGetError() == GL_NO_ERROR) {
++ if (limits[i].count == 1)
++ printf(" %s = %d\n", limits[i].name, max[0]);
++ else /* XXX fix if we ever query something with more than 2 values */
++ printf(" %s = %d, %d\n", limits[i].name, max[0], max[1]);
++ }
++ }
++
++ /* these don't fit into the above mechanism, unfortunately */
++ glGetConvolutionParameteriv(GL_CONVOLUTION_2D, GL_MAX_CONVOLUTION_WIDTH, max);
++ glGetConvolutionParameteriv(GL_CONVOLUTION_2D, GL_MAX_CONVOLUTION_HEIGHT, max+1);
++ if (glGetError() == GL_NONE) {
++ printf(" GL_MAX_CONVOLUTION_WIDTH/HEIGHT = %d, %d\n", max[0], max[1]);
++ }
++
++#if defined(GL_ARB_vertex_program)
++ if (strstr(extensions, "GL_ARB_vertex_program")) {
++ print_program_limits(GL_VERTEX_PROGRAM_ARB);
++ }
++#endif
++#if defined(GL_ARB_fragment_program)
++ if (strstr(extensions, "GL_ARB_fragment_program")) {
++ print_program_limits(GL_FRAGMENT_PROGRAM_ARB);
++ }
++#endif
++#if defined(GL_ARB_vertex_shader)
++ if (strstr(extensions, "GL_ARB_vertex_shader")) {
++ print_shader_limits(GL_VERTEX_SHADER_ARB);
++ }
++#endif
++#if defined(GL_ARB_fragment_shader)
++ if (strstr(extensions, "GL_ARB_fragment_shader")) {
++ print_shader_limits(GL_FRAGMENT_SHADER_ARB);
++ }
++#endif
++}
++
++
++static void
++print_screen_info(Display *dpy, int scrnum, Bool allowDirect, GLboolean limits)
++{
++ Window win;
++ int attribSingle[] = {
++ GLX_RGBA,
++ GLX_RED_SIZE, 1,
++ GLX_GREEN_SIZE, 1,
++ GLX_BLUE_SIZE, 1,
++ None };
++ int attribDouble[] = {
++ GLX_RGBA,
++ GLX_RED_SIZE, 1,
++ GLX_GREEN_SIZE, 1,
++ GLX_BLUE_SIZE, 1,
++ GLX_DOUBLEBUFFER,
++ None };
++
++ XSetWindowAttributes attr;
++ unsigned long mask;
++ Window root;
++ GLXContext ctx = NULL;
++ XVisualInfo *visinfo;
++ int width = 100, height = 100;
++
++ root = RootWindow(dpy, scrnum);
++
++ /*
++ * Find a basic GLX visual. We'll then create a rendering context and
++ * query various info strings.
++ */
++ visinfo = glXChooseVisual(dpy, scrnum, attribSingle);
++ if (!visinfo)
++ visinfo = glXChooseVisual(dpy, scrnum, attribDouble);
++
++ if (visinfo)
++ ctx = glXCreateContext( dpy, visinfo, NULL, allowDirect );
++
++#ifdef GLX_VERSION_1_3
++ /* Try glXChooseFBConfig() if glXChooseVisual didn't work.
++ * XXX when would that happen?
++ */
++ if (!visinfo) {
++ int fbAttribSingle[] = {
++ GLX_RENDER_TYPE, GLX_RGBA_BIT,
++ GLX_RED_SIZE, 1,
++ GLX_GREEN_SIZE, 1,
++ GLX_BLUE_SIZE, 1,
++ GLX_DOUBLEBUFFER, GL_FALSE,
++ None };
++ int fbAttribDouble[] = {
++ GLX_RENDER_TYPE, GLX_RGBA_BIT,
++ GLX_RED_SIZE, 1,
++ GLX_GREEN_SIZE, 1,
++ GLX_BLUE_SIZE, 1,
++ GLX_DOUBLEBUFFER, GL_TRUE,
++ None };
++ GLXFBConfig *configs = NULL;
++ int nConfigs;
++
++ configs = glXChooseFBConfig(dpy, scrnum, fbAttribSingle, &nConfigs);
++ if (!configs)
++ configs = glXChooseFBConfig(dpy, scrnum, fbAttribDouble, &nConfigs);
++
++ if (configs) {
++ visinfo = glXGetVisualFromFBConfig(dpy, configs[0]);
++ ctx = glXCreateNewContext(dpy, configs[0], GLX_RGBA_TYPE, NULL, allowDirect);
++ XFree(configs);
++ }
++ }
++#endif
++
++ if (!visinfo) {
++ fprintf(stderr, "Error: couldn't find RGB GLX visual or fbconfig\n");
++ return;
++ }
++
++ if (!ctx) {
++ fprintf(stderr, "Error: glXCreateContext failed\n");
++ XFree(visinfo);
++ return;
++ }
++
++ attr.background_pixel = 0;
++ attr.border_pixel = 0;
++ attr.colormap = XCreateColormap(dpy, root, visinfo->visual, AllocNone);
++ attr.event_mask = StructureNotifyMask | ExposureMask;
++ mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
++ win = XCreateWindow(dpy, root, 0, 0, width, height,
++ 0, visinfo->depth, InputOutput,
++ visinfo->visual, mask, &attr);
++
++ if (glXMakeCurrent(dpy, win, ctx)) {
++ const char *serverVendor = glXQueryServerString(dpy, scrnum, GLX_VENDOR);
++ const char *serverVersion = glXQueryServerString(dpy, scrnum, GLX_VERSION);
++ const char *serverExtensions = glXQueryServerString(dpy, scrnum, GLX_EXTENSIONS);
++ const char *clientVendor = glXGetClientString(dpy, GLX_VENDOR);
++ const char *clientVersion = glXGetClientString(dpy, GLX_VERSION);
++ const char *clientExtensions = glXGetClientString(dpy, GLX_EXTENSIONS);
++ const char *glxExtensions = glXQueryExtensionsString(dpy, scrnum);
++ const char *glVendor = (const char *) glGetString(GL_VENDOR);
++ const char *glRenderer = (const char *) glGetString(GL_RENDERER);
++ const char *glVersion = (const char *) glGetString(GL_VERSION);
++ const char *glExtensions = (const char *) glGetString(GL_EXTENSIONS);
++ int glxVersionMajor;
++ int glxVersionMinor;
++ char *displayName = NULL;
++ char *colon = NULL, *period = NULL;
++
++ if (! glXQueryVersion( dpy, & glxVersionMajor, & glxVersionMinor )) {
++ fprintf(stderr, "Error: glXQueryVersion failed\n");
++ exit(1);
++ }
++
++ /* Strip the screen number from the display name, if present. */
++ if (!(displayName = (char *) malloc(strlen(DisplayString(dpy)) + 1))) {
++ fprintf(stderr, "Error: malloc() failed\n");
++ exit(1);
++ }
++ strcpy(displayName, DisplayString(dpy));
++ colon = strrchr(displayName, ':');
++ if (colon) {
++ period = strchr(colon, '.');
++ if (period)
++ *period = '\0';
++ }
++ printf("display: %s screen: %d\n", displayName, scrnum);
++ free(displayName);
++ printf("direct rendering: ");
++ if (glXIsDirect(dpy, ctx)) {
++ printf("Yes\n");
++ } else {
++ if (!allowDirect) {
++ printf("No (-i specified)\n");
++ } else if (getenv("LIBGL_ALWAYS_INDIRECT")) {
++ printf("No (LIBGL_ALWAYS_INDIRECT set)\n");
++ } else {
++ printf("No (If you want to find out why, try setting "
++ "LIBGL_DEBUG=verbose)\n");
++ }
++ }
++ printf("server glx vendor string: %s\n", serverVendor);
++ printf("server glx version string: %s\n", serverVersion);
++ printf("server glx extensions:\n");
++ print_extension_list(serverExtensions);
++ printf("client glx vendor string: %s\n", clientVendor);
++ printf("client glx version string: %s\n", clientVersion);
++ printf("client glx extensions:\n");
++ print_extension_list(clientExtensions);
++ printf("GLX version: %u.%u\n", glxVersionMajor, glxVersionMinor);
++ printf("GLX extensions:\n");
++ print_extension_list(glxExtensions);
++ printf("OpenGL vendor string: %s\n", glVendor);
++ printf("OpenGL renderer string: %s\n", glRenderer);
++ printf("OpenGL version string: %s\n", glVersion);
++#ifdef GL_VERSION_2_0
++ if (glVersion[0] >= '2' && glVersion[1] == '.') {
++ char *v = (char *) glGetString(GL_SHADING_LANGUAGE_VERSION);
++ printf("OpenGL shading language version string: %s\n", v);
++ }
++#endif
++
++ printf("OpenGL extensions:\n");
++ print_extension_list(glExtensions);
++ if (limits)
++ print_limits(glExtensions);
++ }
++ else {
++ fprintf(stderr, "Error: glXMakeCurrent failed\n");
++ }
++
++ glXDestroyContext(dpy, ctx);
++ XFree(visinfo);
++ XDestroyWindow(dpy, win);
++}
++
++
++static const char *
++visual_class_name(int cls)
++{
++ switch (cls) {
++ case StaticColor:
++ return "StaticColor";
++ case PseudoColor:
++ return "PseudoColor";
++ case StaticGray:
++ return "StaticGray";
++ case GrayScale:
++ return "GrayScale";
++ case TrueColor:
++ return "TrueColor";
++ case DirectColor:
++ return "DirectColor";
++ default:
++ return "";
++ }
++}
++
++
++static const char *
++visual_class_abbrev(int cls)
++{
++ switch (cls) {
++ case StaticColor:
++ return "sc";
++ case PseudoColor:
++ return "pc";
++ case StaticGray:
++ return "sg";
++ case GrayScale:
++ return "gs";
++ case TrueColor:
++ return "tc";
++ case DirectColor:
++ return "dc";
++ default:
++ return "";
++ }
++}
++
++static const char *
++visual_render_type_name(int type)
++{
++ switch (type) {
++ case GLX_RGBA_BIT:
++ return "rgba";
++ case GLX_COLOR_INDEX_BIT:
++ return "ci";
++ case GLX_RGBA_BIT | GLX_COLOR_INDEX_BIT:
++ return "rgba|ci";
++ default:
++ return "";
++ }
++}
++
++static GLboolean
++get_visual_attribs(Display *dpy, XVisualInfo *vInfo,
++ struct visual_attribs *attribs)
++{
++ const char *ext = glXQueryExtensionsString(dpy, vInfo->screen);
++ int rgba;
++
++ memset(attribs, 0, sizeof(struct visual_attribs));
++
++ attribs->id = vInfo->visualid;
++#if defined(__cplusplus) || defined(c_plusplus)
++ attribs->klass = vInfo->c_class;
++#else
++ attribs->klass = vInfo->class;
++#endif
++ attribs->depth = vInfo->depth;
++ attribs->redMask = vInfo->red_mask;
++ attribs->greenMask = vInfo->green_mask;
++ attribs->blueMask = vInfo->blue_mask;
++ attribs->colormapSize = vInfo->colormap_size;
++ attribs->bitsPerRGB = vInfo->bits_per_rgb;
++
++ if (glXGetConfig(dpy, vInfo, GLX_USE_GL, &attribs->supportsGL) != 0 ||
++ !attribs->supportsGL)
++ return GL_FALSE;
++ glXGetConfig(dpy, vInfo, GLX_BUFFER_SIZE, &attribs->bufferSize);
++ glXGetConfig(dpy, vInfo, GLX_LEVEL, &attribs->level);
++ glXGetConfig(dpy, vInfo, GLX_RGBA, &rgba);
++ if (rgba)
++ attribs->render_type = GLX_RGBA_BIT;
++ else
++ attribs->render_type = GLX_COLOR_INDEX_BIT;
++
++ glXGetConfig(dpy, vInfo, GLX_DOUBLEBUFFER, &attribs->doubleBuffer);
++ glXGetConfig(dpy, vInfo, GLX_STEREO, &attribs->stereo);
++ glXGetConfig(dpy, vInfo, GLX_AUX_BUFFERS, &attribs->auxBuffers);
++ glXGetConfig(dpy, vInfo, GLX_RED_SIZE, &attribs->redSize);
++ glXGetConfig(dpy, vInfo, GLX_GREEN_SIZE, &attribs->greenSize);
++ glXGetConfig(dpy, vInfo, GLX_BLUE_SIZE, &attribs->blueSize);
++ glXGetConfig(dpy, vInfo, GLX_ALPHA_SIZE, &attribs->alphaSize);
++ glXGetConfig(dpy, vInfo, GLX_DEPTH_SIZE, &attribs->depthSize);
++ glXGetConfig(dpy, vInfo, GLX_STENCIL_SIZE, &attribs->stencilSize);
++ glXGetConfig(dpy, vInfo, GLX_ACCUM_RED_SIZE, &attribs->accumRedSize);
++ glXGetConfig(dpy, vInfo, GLX_ACCUM_GREEN_SIZE, &attribs->accumGreenSize);
++ glXGetConfig(dpy, vInfo, GLX_ACCUM_BLUE_SIZE, &attribs->accumBlueSize);
++ glXGetConfig(dpy, vInfo, GLX_ACCUM_ALPHA_SIZE, &attribs->accumAlphaSize);
++
++ /* get transparent pixel stuff */
++ glXGetConfig(dpy, vInfo,GLX_TRANSPARENT_TYPE, &attribs->transparentType);
++ if (attribs->transparentType == GLX_TRANSPARENT_RGB) {
++ glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_RED_VALUE, &attribs->transparentRedValue);
++ glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_GREEN_VALUE, &attribs->transparentGreenValue);
++ glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_BLUE_VALUE, &attribs->transparentBlueValue);
++ glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_ALPHA_VALUE, &attribs->transparentAlphaValue);
++ }
++ else if (attribs->transparentType == GLX_TRANSPARENT_INDEX) {
++ glXGetConfig(dpy, vInfo, GLX_TRANSPARENT_INDEX_VALUE, &attribs->transparentIndexValue);
++ }
++
++ /* multisample attribs */
++#ifdef GLX_ARB_multisample
++ if (ext && strstr(ext, "GLX_ARB_multisample")) {
++ glXGetConfig(dpy, vInfo, GLX_SAMPLE_BUFFERS_ARB, &attribs->numMultisample);
++ glXGetConfig(dpy, vInfo, GLX_SAMPLES_ARB, &attribs->numSamples);
++ }
++#endif
++ else {
++ attribs->numSamples = 0;
++ attribs->numMultisample = 0;
++ }
++
++#if defined(GLX_EXT_visual_rating)
++ if (ext && strstr(ext, "GLX_EXT_visual_rating")) {
++ glXGetConfig(dpy, vInfo, GLX_VISUAL_CAVEAT_EXT, &attribs->visualCaveat);
++ }
++ else {
++ attribs->visualCaveat = GLX_NONE_EXT;
++ }
++#else
++ attribs->visualCaveat = 0;
++#endif
++
++ return GL_TRUE;
++}
++
++#ifdef GLX_VERSION_1_3
++
++static int
++glx_token_to_visual_class(int visual_type)
++{
++ switch (visual_type) {
++ case GLX_TRUE_COLOR:
++ return TrueColor;
++ case GLX_DIRECT_COLOR:
++ return DirectColor;
++ case GLX_PSEUDO_COLOR:
++ return PseudoColor;
++ case GLX_STATIC_COLOR:
++ return StaticColor;
++ case GLX_GRAY_SCALE:
++ return GrayScale;
++ case GLX_STATIC_GRAY:
++ return StaticGray;
++ case GLX_NONE:
++ default:
++ return None;
++ }
++}
++
++static GLboolean
++get_fbconfig_attribs(Display *dpy, GLXFBConfig fbconfig,
++ struct visual_attribs *attribs)
++{
++ int visual_type;
++
++ memset(attribs, 0, sizeof(struct visual_attribs));
++
++ glXGetFBConfigAttrib(dpy, fbconfig, GLX_FBCONFIG_ID, &attribs->id);
++
++#if 0
++ attribs->depth = vInfo->depth;
++ attribs->redMask = vInfo->red_mask;
++ attribs->greenMask = vInfo->green_mask;
++ attribs->blueMask = vInfo->blue_mask;
++ attribs->colormapSize = vInfo->colormap_size;
++ attribs->bitsPerRGB = vInfo->bits_per_rgb;
++#endif
++
++ glXGetFBConfigAttrib(dpy, fbconfig, GLX_X_VISUAL_TYPE, &visual_type);
++ attribs->klass = glx_token_to_visual_class(visual_type);
++
++ glXGetFBConfigAttrib(dpy, fbconfig, GLX_BUFFER_SIZE, &attribs->bufferSize);
++ glXGetFBConfigAttrib(dpy, fbconfig, GLX_LEVEL, &attribs->level);
++ glXGetFBConfigAttrib(dpy, fbconfig, GLX_RENDER_TYPE, &attribs->render_type);
++ glXGetFBConfigAttrib(dpy, fbconfig, GLX_DOUBLEBUFFER, &attribs->doubleBuffer);
++ glXGetFBConfigAttrib(dpy, fbconfig, GLX_STEREO, &attribs->stereo);
++ glXGetFBConfigAttrib(dpy, fbconfig, GLX_AUX_BUFFERS, &attribs->auxBuffers);
++
++ glXGetFBConfigAttrib(dpy, fbconfig, GLX_RED_SIZE, &attribs->redSize);
++ glXGetFBConfigAttrib(dpy, fbconfig, GLX_GREEN_SIZE, &attribs->greenSize);
++ glXGetFBConfigAttrib(dpy, fbconfig, GLX_BLUE_SIZE, &attribs->blueSize);
++ glXGetFBConfigAttrib(dpy, fbconfig, GLX_ALPHA_SIZE, &attribs->alphaSize);
++ glXGetFBConfigAttrib(dpy, fbconfig, GLX_DEPTH_SIZE, &attribs->depthSize);
++ glXGetFBConfigAttrib(dpy, fbconfig, GLX_STENCIL_SIZE, &attribs->stencilSize);
++
++ glXGetFBConfigAttrib(dpy, fbconfig, GLX_ACCUM_RED_SIZE, &attribs->accumRedSize);
++ glXGetFBConfigAttrib(dpy, fbconfig, GLX_ACCUM_GREEN_SIZE, &attribs->accumGreenSize);
++ glXGetFBConfigAttrib(dpy, fbconfig, GLX_ACCUM_BLUE_SIZE, &attribs->accumBlueSize);
++ glXGetFBConfigAttrib(dpy, fbconfig, GLX_ACCUM_ALPHA_SIZE, &attribs->accumAlphaSize);
++
++ /* get transparent pixel stuff */
++ glXGetFBConfigAttrib(dpy, fbconfig,GLX_TRANSPARENT_TYPE, &attribs->transparentType);
++ if (attribs->transparentType == GLX_TRANSPARENT_RGB) {
++ glXGetFBConfigAttrib(dpy, fbconfig, GLX_TRANSPARENT_RED_VALUE, &attribs->transparentRedValue);
++ glXGetFBConfigAttrib(dpy, fbconfig, GLX_TRANSPARENT_GREEN_VALUE, &attribs->transparentGreenValue);
++ glXGetFBConfigAttrib(dpy, fbconfig, GLX_TRANSPARENT_BLUE_VALUE, &attribs->transparentBlueValue);
++ glXGetFBConfigAttrib(dpy, fbconfig, GLX_TRANSPARENT_ALPHA_VALUE, &attribs->transparentAlphaValue);
++ }
++ else if (attribs->transparentType == GLX_TRANSPARENT_INDEX) {
++ glXGetFBConfigAttrib(dpy, fbconfig, GLX_TRANSPARENT_INDEX_VALUE, &attribs->transparentIndexValue);
++ }
++
++ glXGetFBConfigAttrib(dpy, fbconfig, GLX_SAMPLE_BUFFERS, &attribs->numMultisample);
++ glXGetFBConfigAttrib(dpy, fbconfig, GLX_SAMPLES, &attribs->numSamples);
++ glXGetFBConfigAttrib(dpy, fbconfig, GLX_CONFIG_CAVEAT, &attribs->visualCaveat);
++
++ return GL_TRUE;
++}
++
++#endif
++
++
++
++static void
++print_visual_attribs_verbose(const struct visual_attribs *attribs)
++{
++ printf("Visual ID: %x depth=%d class=%s\n",
++ attribs->id, attribs->depth, visual_class_name(attribs->klass));
++ printf(" bufferSize=%d level=%d renderType=%s doubleBuffer=%d stereo=%d\n",
++ attribs->bufferSize, attribs->level,
++ visual_render_type_name(attribs->render_type),
++ attribs->doubleBuffer, attribs->stereo);
++ printf(" rgba: redSize=%d greenSize=%d blueSize=%d alphaSize=%d\n",
++ attribs->redSize, attribs->greenSize,
++ attribs->blueSize, attribs->alphaSize);
++ printf(" auxBuffers=%d depthSize=%d stencilSize=%d\n",
++ attribs->auxBuffers, attribs->depthSize, attribs->stencilSize);
++ printf(" accum: redSize=%d greenSize=%d blueSize=%d alphaSize=%d\n",
++ attribs->accumRedSize, attribs->accumGreenSize,
++ attribs->accumBlueSize, attribs->accumAlphaSize);
++ printf(" multiSample=%d multiSampleBuffers=%d\n",
++ attribs->numSamples, attribs->numMultisample);
++#ifdef GLX_EXT_visual_rating
++ if (attribs->visualCaveat == GLX_NONE_EXT || attribs->visualCaveat == 0)
++ printf(" visualCaveat=None\n");
++ else if (attribs->visualCaveat == GLX_SLOW_VISUAL_EXT)
++ printf(" visualCaveat=Slow\n");
++ else if (attribs->visualCaveat == GLX_NON_CONFORMANT_VISUAL_EXT)
++ printf(" visualCaveat=Nonconformant\n");
++#endif
++ if (attribs->transparentType == GLX_NONE) {
++ printf(" Opaque.\n");
++ }
++ else if (attribs->transparentType == GLX_TRANSPARENT_RGB) {
++ printf(" Transparent RGB: Red=%d Green=%d Blue=%d Alpha=%d\n",attribs->transparentRedValue,attribs->transparentGreenValue,attribs->transparentBlueValue,attribs->transparentAlphaValue);
++ }
++ else if (attribs->transparentType == GLX_TRANSPARENT_INDEX) {
++ printf(" Transparent index=%d\n",attribs->transparentIndexValue);
++ }
++}
++
++
++static void
++print_visual_attribs_short_header(void)
++{
++ printf(" visual x bf lv rg d st colorbuffer ax dp st accumbuffer ms cav\n");
++ printf(" id dep cl sp sz l ci b ro r g b a bf th cl r g b a ns b eat\n");
++ printf("----------------------------------------------------------------------\n");
++}
++
++
++static void
++print_visual_attribs_short(const struct visual_attribs *attribs)
++{
++ char *caveat = NULL;
++#ifdef GLX_EXT_visual_rating
++ if (attribs->visualCaveat == GLX_NONE_EXT || attribs->visualCaveat == 0)
++ caveat = "None";
++ else if (attribs->visualCaveat == GLX_SLOW_VISUAL_EXT)
++ caveat = "Slow";
++ else if (attribs->visualCaveat == GLX_NON_CONFORMANT_VISUAL_EXT)
++ caveat = "Ncon";
++ else
++ caveat = "None";
++#else
++ caveat = "None";
++#endif
++
++ printf("0x%02x %2d %2s %2d %2d %2d %c%c %c %c %2d %2d %2d %2d %2d %2d %2d",
++ attribs->id,
++ attribs->depth,
++ visual_class_abbrev(attribs->klass),
++ attribs->transparentType != GLX_NONE,
++ attribs->bufferSize,
++ attribs->level,
++ (attribs->render_type & GLX_RGBA_BIT) ? 'r' : ' ',
++ (attribs->render_type & GLX_COLOR_INDEX_BIT) ? 'c' : ' ',
++ attribs->doubleBuffer ? 'y' : '.',
++ attribs->stereo ? 'y' : '.',
++ attribs->redSize, attribs->greenSize,
++ attribs->blueSize, attribs->alphaSize,
++ attribs->auxBuffers,
++ attribs->depthSize,
++ attribs->stencilSize
++ );
++
++ printf(" %2d %2d %2d %2d %2d %1d %s\n",
++ attribs->accumRedSize, attribs->accumGreenSize,
++ attribs->accumBlueSize, attribs->accumAlphaSize,
++ attribs->numSamples, attribs->numMultisample,
++ caveat
++ );
++}
++
++
++static void
++print_visual_attribs_long_header(void)
++{
++ printf("Vis Vis Visual Trans buff lev render DB ste r g b a aux dep ste accum buffers MS MS\n");
++ printf(" ID Depth Type parent size el type reo sz sz sz sz buf th ncl r g b a num bufs\n");
++ printf("----------------------------------------------------------------------------------------------------\n");
++}
++
++
++static void
++print_visual_attribs_long(const struct visual_attribs *attribs)
++{
++ printf("0x%2x %2d %-11s %2d %2d %2d %4s %3d %3d %3d %3d %3d %3d",
++ attribs->id,
++ attribs->depth,
++ visual_class_name(attribs->klass),
++ attribs->transparentType != GLX_NONE,
++ attribs->bufferSize,
++ attribs->level,
++ visual_render_type_name(attribs->render_type),
++ attribs->doubleBuffer,
++ attribs->stereo,
++ attribs->redSize, attribs->greenSize,
++ attribs->blueSize, attribs->alphaSize
++ );
++
++ printf(" %3d %4d %2d %3d %3d %3d %3d %2d %2d\n",
++ attribs->auxBuffers,
++ attribs->depthSize,
++ attribs->stencilSize,
++ attribs->accumRedSize, attribs->accumGreenSize,
++ attribs->accumBlueSize, attribs->accumAlphaSize,
++ attribs->numSamples, attribs->numMultisample
++ );
++}
++
++
++static void
++print_visual_info(Display *dpy, int scrnum, InfoMode mode)
++{
++ XVisualInfo theTemplate;
++ XVisualInfo *visuals;
++ int numVisuals, numGlxVisuals;
++ long mask;
++ int i;
++ struct visual_attribs attribs;
++
++ /* get list of all visuals on this screen */
++ theTemplate.screen = scrnum;
++ mask = VisualScreenMask;
++ visuals = XGetVisualInfo(dpy, mask, &theTemplate, &numVisuals);
++
++ numGlxVisuals = 0;
++ for (i = 0; i < numVisuals; i++) {
++ if (get_visual_attribs(dpy, &visuals[i], &attribs))
++ numGlxVisuals++;
++ }
++
++ if (numGlxVisuals == 0)
++ return;
++
++ printf("%d GLX Visuals\n", numGlxVisuals);
++
++ if (mode == Normal)
++ print_visual_attribs_short_header();
++ else if (mode == Wide)
++ print_visual_attribs_long_header();
++
++ for (i = 0; i < numVisuals; i++) {
++ if (!get_visual_attribs(dpy, &visuals[i], &attribs))
++ continue;
++
++ if (mode == Verbose)
++ print_visual_attribs_verbose(&attribs);
++ else if (mode == Normal)
++ print_visual_attribs_short(&attribs);
++ else if (mode == Wide)
++ print_visual_attribs_long(&attribs);
++ }
++ printf("\n");
++
++ XFree(visuals);
++}
++
++#ifdef GLX_VERSION_1_3
++
++static void
++print_fbconfig_info(Display *dpy, int scrnum, InfoMode mode)
++{
++ int numFBConfigs = 0;
++ struct visual_attribs attribs;
++ GLXFBConfig *fbconfigs;
++ int i;
++
++ /* get list of all fbconfigs on this screen */
++ fbconfigs = glXGetFBConfigs(dpy, scrnum, &numFBConfigs);
++
++ if (numFBConfigs == 0) {
++ XFree(fbconfigs);
++ return;
++ }
++
++ printf("%d GLXFBConfigs:\n", numFBConfigs);
++ if (mode == Normal)
++ print_visual_attribs_short_header();
++ else if (mode == Wide)
++ print_visual_attribs_long_header();
++
++ for (i = 0; i < numFBConfigs; i++) {
++ get_fbconfig_attribs(dpy, fbconfigs[i], &attribs);
++
++ if (mode == Verbose)
++ print_visual_attribs_verbose(&attribs);
++ else if (mode == Normal)
++ print_visual_attribs_short(&attribs);
++ else if (mode == Wide)
++ print_visual_attribs_long(&attribs);
++ }
++ printf("\n");
++
++ XFree(fbconfigs);
++}
++
++#endif
++
++/*
++ * Stand-alone Mesa doesn't really implement the GLX protocol so it
++ * doesn't really know the GLX attributes associated with an X visual.
++ * The first time a visual is presented to Mesa's pseudo-GLX it
++ * attaches ancilliary buffers to it (like depth and stencil).
++ * But that usually only works if glXChooseVisual is used.
++ * This function calls glXChooseVisual() to sort of "prime the pump"
++ * for Mesa's GLX so that the visuals that get reported actually
++ * reflect what applications will see.
++ * This has no effect when using true GLX.
++ */
++static void
++mesa_hack(Display *dpy, int scrnum)
++{
++ static int attribs[] = {
++ GLX_RGBA,
++ GLX_RED_SIZE, 1,
++ GLX_GREEN_SIZE, 1,
++ GLX_BLUE_SIZE, 1,
++ GLX_DEPTH_SIZE, 1,
++ GLX_STENCIL_SIZE, 1,
++ GLX_ACCUM_RED_SIZE, 1,
++ GLX_ACCUM_GREEN_SIZE, 1,
++ GLX_ACCUM_BLUE_SIZE, 1,
++ GLX_ACCUM_ALPHA_SIZE, 1,
++ GLX_DOUBLEBUFFER,
++ None
++ };
++ XVisualInfo *visinfo;
++
++ visinfo = glXChooseVisual(dpy, scrnum, attribs);
++ if (visinfo)
++ XFree(visinfo);
++}
++
++
++/*
++ * Examine all visuals to find the so-called best one.
++ * We prefer deepest RGBA buffer with depth, stencil and accum
++ * that has no caveats.
++ */
++static int
++find_best_visual(Display *dpy, int scrnum)
++{
++ XVisualInfo theTemplate;
++ XVisualInfo *visuals;
++ int numVisuals;
++ long mask;
++ int i;
++ struct visual_attribs bestVis;
++
++ /* get list of all visuals on this screen */
++ theTemplate.screen = scrnum;
++ mask = VisualScreenMask;
++ visuals = XGetVisualInfo(dpy, mask, &theTemplate, &numVisuals);
++
++ /* init bestVis with first visual info */
++ get_visual_attribs(dpy, &visuals[0], &bestVis);
++
++ /* try to find a "better" visual */
++ for (i = 1; i < numVisuals; i++) {
++ struct visual_attribs vis;
++
++ get_visual_attribs(dpy, &visuals[i], &vis);
++
++ /* always skip visuals with caveats */
++ if (vis.visualCaveat != GLX_NONE_EXT)
++ continue;
++
++ /* see if this vis is better than bestVis */
++ if ((!bestVis.supportsGL && vis.supportsGL) ||
++ (bestVis.visualCaveat != GLX_NONE_EXT) ||
++ (!(bestVis.render_type & GLX_RGBA_BIT) && (vis.render_type & GLX_RGBA_BIT)) ||
++ (!bestVis.doubleBuffer && vis.doubleBuffer) ||
++ (bestVis.redSize < vis.redSize) ||
++ (bestVis.greenSize < vis.greenSize) ||
++ (bestVis.blueSize < vis.blueSize) ||
++ (bestVis.alphaSize < vis.alphaSize) ||
++ (bestVis.depthSize < vis.depthSize) ||
++ (bestVis.stencilSize < vis.stencilSize) ||
++ (bestVis.accumRedSize < vis.accumRedSize)) {
++ /* found a better visual */
++ bestVis = vis;
++ }
++ }
++
++ XFree(visuals);
++
++ return bestVis.id;
++}
++
++
++static void
++usage(void)
++{
++ printf("Usage: glxinfo [-v] [-t] [-h] [-i] [-b] [-display <dname>]\n");
++ printf("\t-v: Print visuals info in verbose form.\n");
++ printf("\t-t: Print verbose table.\n");
++ printf("\t-display <dname>: Print GLX visuals on specified server.\n");
++ printf("\t-h: This information.\n");
++ printf("\t-i: Force an indirect rendering context.\n");
++ printf("\t-b: Find the 'best' visual and print its number.\n");
++ printf("\t-l: Print interesting OpenGL limits.\n");
++}
++
++
++int
++main(int argc, char *argv[])
++{
++ char *displayName = NULL;
++ Display *dpy;
++ int numScreens, scrnum;
++ InfoMode mode = Normal;
++ GLboolean findBest = GL_FALSE;
++ GLboolean limits = GL_FALSE;
++ Bool allowDirect = True;
++ int i;
++
++ for (i = 1; i < argc; i++) {
++ if (strcmp(argv[i], "-display") == 0 && i + 1 < argc) {
++ displayName = argv[i + 1];
++ i++;
++ }
++ else if (strcmp(argv[i], "-t") == 0) {
++ mode = Wide;
++ }
++ else if (strcmp(argv[i], "-v") == 0) {
++ mode = Verbose;
++ }
++ else if (strcmp(argv[i], "-b") == 0) {
++ findBest = GL_TRUE;
++ }
++ else if (strcmp(argv[i], "-i") == 0) {
++ allowDirect = False;
++ }
++ else if (strcmp(argv[i], "-l") == 0) {
++ limits = GL_TRUE;
++ }
++ else if (strcmp(argv[i], "-h") == 0) {
++ usage();
++ return 0;
++ }
++ else {
++ printf("Unknown option `%s'\n", argv[i]);
++ usage();
++ return 0;
++ }
++ }
++
++ dpy = XOpenDisplay(displayName);
++ if (!dpy) {
++ fprintf(stderr, "Error: unable to open display %s\n", XDisplayName(displayName));
++ return -1;
++ }
++
++ if (findBest) {
++ int b;
++ mesa_hack(dpy, 0);
++ b = find_best_visual(dpy, 0);
++ printf("%d\n", b);
++ }
++ else {
++ numScreens = ScreenCount(dpy);
++ print_display_info(dpy);
++ for (scrnum = 0; scrnum < numScreens; scrnum++) {
++ mesa_hack(dpy, scrnum);
++ print_screen_info(dpy, scrnum, allowDirect, limits);
++ printf("\n");
++ print_visual_info(dpy, scrnum, mode);
++#ifdef GLX_VERSION_1_3
++ print_fbconfig_info(dpy, scrnum, mode);
++#endif
++ if (scrnum + 1 < numScreens)
++ printf("\n\n");
++ }
++ }
++
++ XCloseDisplay(dpy);
++
++ return 0;
++}
+diff -Naurp Mesa-7.8.1/progs/xdemos/glxpbdemo.c Mesa-7.8.1.patched/progs/xdemos/glxpbdemo.c
+--- Mesa-7.8.1/progs/xdemos/glxpbdemo.c 1970-01-01 01:00:00.000000000 +0100
++++ Mesa-7.8.1.patched/progs/xdemos/glxpbdemo.c 2010-06-13 13:45:06.789793146 +0200
+@@ -0,0 +1,431 @@
++
++/*
++ * This program demonstrates how to do "off-screen" rendering using
++ * the GLX pixel buffer extension.
++ *
++ * Written by Brian Paul for the "OpenGL and Window System Integration"
++ * course presented at SIGGRAPH '97. Updated on 5 October 2002.
++ *
++ * Updated on 31 January 2004 to use native GLX by
++ * Andrew P. Lentvorski, Jr. <bsder@allcaps.org>
++ *
++ * Usage:
++ * glxpbdemo width height imgfile
++ * Where:
++ * width is the width, in pixels, of the image to generate.
++ * height is the height, in pixels, of the image to generate.
++ * imgfile is the name of the PPM image file to write.
++ *
++ *
++ * This demo draws 3-D boxes with random orientation.
++ *
++ * On machines such as the SGI Indigo you may have to reconfigure your
++ * display/X server to enable pbuffers. Look in the /usr/gfx/ucode/MGRAS/vof/
++ * directory for display configurations with the _pbuf suffix. Use
++ * setmon -x <vof> to configure your X server and display for pbuffers.
++ *
++ * O2 systems seem to support pbuffers well.
++ *
++ */
++
++#include <string.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <X11/Xlib.h>
++#include <GL/glx.h>
++
++/* Some ugly global vars */
++static GLXFBConfig gFBconfig = 0;
++static Display *gDpy = NULL;
++static int gScreen = 0;
++static GLXPbuffer gPBuffer = 0;
++static int gWidth, gHeight;
++
++
++/*
++ * Test for appropriate version of GLX to run this program
++ * Input: dpy - the X display
++ * screen - screen number
++ * Return: 0 = GLX not available.
++ * 1 = GLX available.
++ */
++static int
++RuntimeQueryGLXVersion(Display *dpy, int screen)
++{
++#if defined(GLX_VERSION_1_3) || defined(GLX_VERSION_1_4)
++ char *glxversion;
++
++ glxversion = (char *) glXGetClientString(dpy, GLX_VERSION);
++ if (!(strstr(glxversion, "1.3") || strstr(glxversion, "1.4")))
++ return 0;
++
++ glxversion = (char *) glXQueryServerString(dpy, screen, GLX_VERSION);
++ if (!(strstr(glxversion, "1.3") || strstr(glxversion, "1.4")))
++ return 0;
++
++ return 1;
++#else
++ return 0;
++#endif
++}
++
++
++
++/*
++ * Create the pbuffer and return a GLXPbuffer handle.
++ */
++static GLXPbuffer
++MakePbuffer( Display *dpy, int screen, int width, int height )
++{
++ GLXFBConfig *fbConfigs;
++ GLXFBConfig chosenFBConfig;
++ GLXPbuffer pBuffer = None;
++
++ int nConfigs;
++ int fbconfigid;
++
++ int fbAttribs[] = {
++ GLX_RENDER_TYPE, GLX_RGBA_BIT,
++ GLX_DEPTH_SIZE, 1,
++ GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT | GLX_PBUFFER_BIT,
++ None
++ };
++
++ int pbAttribs[] = {
++ GLX_PBUFFER_WIDTH, 0,
++ GLX_PBUFFER_HEIGHT, 0,
++ GLX_LARGEST_PBUFFER, False,
++ GLX_PRESERVED_CONTENTS, False,
++ None
++ };
++
++ pbAttribs[1] = width;
++ pbAttribs[3] = height;
++
++ fbConfigs = glXChooseFBConfig(dpy, screen, fbAttribs, &nConfigs);
++
++ if (0 == nConfigs || !fbConfigs) {
++ printf("Error: glxChooseFBConfig failed\n");
++ XFree(fbConfigs);
++ XCloseDisplay(dpy);
++ return 0;
++ }
++
++ chosenFBConfig = fbConfigs[0];
++
++ glXGetFBConfigAttrib(dpy, chosenFBConfig, GLX_FBCONFIG_ID, &fbconfigid);
++ printf("Chose 0x%x as fbconfigid\n", fbconfigid);
++
++ /* Create the pbuffer using first fbConfig in the list that works. */
++ pBuffer = glXCreatePbuffer(dpy, chosenFBConfig, pbAttribs);
++
++ if (pBuffer) {
++ gFBconfig = chosenFBConfig;
++ gWidth = width;
++ gHeight = height;
++ }
++
++ XFree(fbConfigs);
++
++ return pBuffer;
++}
++
++
++
++/*
++ * Do all the X / GLX setup stuff.
++ */
++static int
++Setup(int width, int height)
++{
++#if defined(GLX_VERSION_1_3) || defined(GLX_VERSION_1_4)
++ GLXContext glCtx;
++
++ /* Open the X display */
++ gDpy = XOpenDisplay(NULL);
++ if (!gDpy) {
++ printf("Error: couldn't open default X display.\n");
++ return 0;
++ }
++
++ /* Get default screen */
++ gScreen = DefaultScreen(gDpy);
++
++ /* Test that GLX is available */
++ if (!RuntimeQueryGLXVersion(gDpy, gScreen)) {
++ printf("Error: GLX 1.3 or 1.4 not available\n");
++ XCloseDisplay(gDpy);
++ return 0;
++ }
++
++ /* Create Pbuffer */
++ gPBuffer = MakePbuffer( gDpy, gScreen, width, height );
++ if (gPBuffer==None) {
++ printf("Error: couldn't create pbuffer\n");
++ XCloseDisplay(gDpy);
++ return 0;
++ }
++
++ /* Create GLX context */
++ glCtx = glXCreateNewContext(gDpy, gFBconfig, GLX_RGBA_TYPE, NULL, True);
++ if (glCtx) {
++ if (!glXIsDirect(gDpy, glCtx)) {
++ printf("Warning: using indirect GLXContext\n");
++ }
++ }
++ else {
++ printf("Error: Couldn't create GLXContext\n");
++ XCloseDisplay(gDpy);
++ return 0;
++ }
++
++ /* Bind context to pbuffer */
++ if (!glXMakeCurrent(gDpy, gPBuffer, glCtx)) {
++ printf("Error: glXMakeCurrent failed\n");
++ XCloseDisplay(gDpy);
++ return 0;
++ }
++
++ return 1; /* Success!! */
++#else
++ printf("Error: GLX version 1.3 or 1.4 not available at compile time\n");
++ return 0;
++#endif
++}
++
++
++
++/* One-time GL setup */
++static void
++InitGL(void)
++{
++ static GLfloat pos[4] = {0.0, 0.0, 10.0, 0.0};
++ glEnable(GL_LIGHTING);
++ glEnable(GL_LIGHT0);
++ glLightfv(GL_LIGHT0, GL_POSITION, pos);
++ glEnable(GL_NORMALIZE);
++ glEnable(GL_DEPTH_TEST);
++ glEnable(GL_CULL_FACE);
++
++ glViewport(0, 0, gWidth, gHeight);
++ glMatrixMode( GL_PROJECTION );
++ glLoadIdentity();
++ glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 25.0 );
++ glMatrixMode( GL_MODELVIEW );
++ glLoadIdentity();
++ glTranslatef( 0.0, 0.0, -15.0 );
++
++}
++
++
++/* Return random float in [0,1] */
++static float
++Random(void)
++{
++ int i = rand();
++ return (float) (i % 1000) / 1000.0;
++}
++
++
++static void
++RandomColor(void)
++{
++ GLfloat c[4];
++ c[0] = Random();
++ c[1] = Random();
++ c[2] = Random();
++ c[3] = 1.0;
++ glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, c);
++}
++
++
++/* This function borrowed from Mark Kilgard's GLUT */
++static void
++drawBox(GLfloat x0, GLfloat x1, GLfloat y0, GLfloat y1,
++ GLfloat z0, GLfloat z1, GLenum type)
++{
++ static GLfloat n[6][3] =
++ {
++ {-1.0, 0.0, 0.0},
++ {0.0, 1.0, 0.0},
++ {1.0, 0.0, 0.0},
++ {0.0, -1.0, 0.0},
++ {0.0, 0.0, 1.0},
++ {0.0, 0.0, -1.0}
++ };
++ static GLint faces[6][4] =
++ {
++ {0, 1, 2, 3},
++ {3, 2, 6, 7},
++ {7, 6, 5, 4},
++ {4, 5, 1, 0},
++ {5, 6, 2, 1},
++ {7, 4, 0, 3}
++ };
++ GLfloat v[8][3], tmp;
++ GLint i;
++
++ if (x0 > x1) {
++ tmp = x0;
++ x0 = x1;
++ x1 = tmp;
++ }
++ if (y0 > y1) {
++ tmp = y0;
++ y0 = y1;
++ y1 = tmp;
++ }
++ if (z0 > z1) {
++ tmp = z0;
++ z0 = z1;
++ z1 = tmp;
++ }
++ v[0][0] = v[1][0] = v[2][0] = v[3][0] = x0;
++ v[4][0] = v[5][0] = v[6][0] = v[7][0] = x1;
++ v[0][1] = v[1][1] = v[4][1] = v[5][1] = y0;
++ v[2][1] = v[3][1] = v[6][1] = v[7][1] = y1;
++ v[0][2] = v[3][2] = v[4][2] = v[7][2] = z0;
++ v[1][2] = v[2][2] = v[5][2] = v[6][2] = z1;
++
++ for (i = 0; i < 6; i++) {
++ glBegin(type);
++ glNormal3fv(&n[i][0]);
++ glVertex3fv(&v[faces[i][0]][0]);
++ glVertex3fv(&v[faces[i][1]][0]);
++ glVertex3fv(&v[faces[i][2]][0]);
++ glVertex3fv(&v[faces[i][3]][0]);
++ glEnd();
++ }
++}
++
++
++
++/* Render a scene */
++static void
++Render(void)
++{
++ int NumBoxes = 100;
++ int i;
++
++ InitGL();
++ glClearColor(0.2, 0.2, 0.9, 0.0);
++ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
++
++ for (i=0;i<NumBoxes;i++) {
++ float tx = -2.0 + 4.0 * Random();
++ float ty = -2.0 + 4.0 * Random();
++ float tz = 4.0 - 16.0 * Random();
++ float sx = 0.1 + Random() * 0.4;
++ float sy = 0.1 + Random() * 0.4;
++ float sz = 0.1 + Random() * 0.4;
++ float rx = Random();
++ float ry = Random();
++ float rz = Random();
++ float ra = Random() * 360.0;
++ glPushMatrix();
++ glTranslatef(tx, ty, tz);
++ glRotatef(ra, rx, ry, rz);
++ glScalef(sx, sy, sz);
++ RandomColor();
++ drawBox(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0, GL_POLYGON);
++ glPopMatrix();
++ }
++
++ glFinish();
++}
++
++
++
++static void
++WriteFile(const char *filename)
++{
++ FILE *f;
++ GLubyte *image;
++ int i;
++
++ image = malloc(gWidth * gHeight * 3 * sizeof(GLubyte));
++ if (!image) {
++ printf("Error: couldn't allocate image buffer\n");
++ return;
++ }
++
++ glPixelStorei(GL_PACK_ALIGNMENT, 1);
++ glReadPixels(0, 0, gWidth, gHeight, GL_RGB, GL_UNSIGNED_BYTE, image);
++
++ f = fopen(filename, "w");
++ if (!f) {
++ printf("Couldn't open image file: %s\n", filename);
++ return;
++ }
++ fprintf(f,"P6\n");
++ fprintf(f,"# ppm-file created by %s\n", "trdemo2");
++ fprintf(f,"%i %i\n", gWidth, gHeight);
++ fprintf(f,"255\n");
++ fclose(f);
++ f = fopen(filename, "ab"); /* now append binary data */
++ if (!f) {
++ printf("Couldn't append to image file: %s\n", filename);
++ return;
++ }
++
++ for (i=0;i<gHeight;i++) {
++ GLubyte *rowPtr;
++ /* Remember, OpenGL images are bottom to top. Have to reverse. */
++ rowPtr = image + (gHeight-1-i) * gWidth*3;
++ fwrite(rowPtr, 1, gWidth*3, f);
++ }
++
++ fclose(f);
++ free(image);
++
++ printf("Wrote %d by %d image file: %s\n", gWidth, gHeight, filename);
++}
++
++
++
++/*
++ * Print message describing command line parameters.
++ */
++static void
++Usage(const char *appName)
++{
++ printf("Usage:\n");
++ printf(" %s width height imgfile\n", appName);
++ printf("Where imgfile is a ppm file\n");
++}
++
++
++
++int
++main(int argc, char *argv[])
++{
++ if (argc!=4) {
++ Usage(argv[0]);
++ }
++ else {
++ int width = atoi(argv[1]);
++ int height = atoi(argv[2]);
++ char *fileName = argv[3];
++ if (width<=0) {
++ printf("Error: width parameter must be at least 1.\n");
++ return 1;
++ }
++ if (height<=0) {
++ printf("Error: height parameter must be at least 1.\n");
++ return 1;
++ }
++ if (!Setup(width, height)) {
++ return 1;
++ }
++
++ printf("Setup completed\n");
++ Render();
++ printf("Render completed.\n");
++ WriteFile(fileName);
++ printf("File write completed.\n");
++
++ glXDestroyPbuffer( gDpy, gPBuffer );
++ }
++ return 0;
++}
++
+diff -Naurp Mesa-7.8.1/progs/xdemos/glxpixmap.c Mesa-7.8.1.patched/progs/xdemos/glxpixmap.c
+--- Mesa-7.8.1/progs/xdemos/glxpixmap.c 1970-01-01 01:00:00.000000000 +0100
++++ Mesa-7.8.1.patched/progs/xdemos/glxpixmap.c 2010-06-13 13:45:06.788792936 +0200
+@@ -0,0 +1,187 @@
++
++
++/*
++ * A demonstration of using the GLXPixmap functions. This program is in
++ * the public domain.
++ *
++ * Brian Paul
++ */
++
++
++#include <GL/gl.h>
++#define GLX_GLXEXT_PROTOTYPES
++#include <GL/glx.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++
++
++static GLXContext ctx;
++static XVisualInfo *visinfo;
++static GC gc;
++
++
++
++static Window make_rgb_window( Display *dpy,
++ unsigned int width, unsigned int height )
++{
++ const int sbAttrib[] = { GLX_RGBA,
++ GLX_RED_SIZE, 1,
++ GLX_GREEN_SIZE, 1,
++ GLX_BLUE_SIZE, 1,
++ None };
++ const int dbAttrib[] = { GLX_RGBA,
++ GLX_RED_SIZE, 1,
++ GLX_GREEN_SIZE, 1,
++ GLX_BLUE_SIZE, 1,
++ GLX_DOUBLEBUFFER,
++ None };
++ int scrnum;
++ XSetWindowAttributes attr;
++ unsigned long mask;
++ Window root;
++ Window win;
++
++ scrnum = DefaultScreen( dpy );
++ root = RootWindow( dpy, scrnum );
++
++ visinfo = glXChooseVisual( dpy, scrnum, (int *) sbAttrib );
++ if (!visinfo) {
++ visinfo = glXChooseVisual( dpy, scrnum, (int *) dbAttrib );
++ if (!visinfo) {
++ printf("Error: couldn't get an RGB visual\n");
++ exit(1);
++ }
++ }
++
++ /* window attributes */
++ attr.background_pixel = 0;
++ attr.border_pixel = 0;
++ /* TODO: share root colormap if possible */
++ attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone);
++ attr.event_mask = StructureNotifyMask | ExposureMask;
++ mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
++
++ win = XCreateWindow( dpy, root, 0, 0, width, height,
++ 0, visinfo->depth, InputOutput,
++ visinfo->visual, mask, &attr );
++
++ /* make an X GC so we can do XCopyArea later */
++ gc = XCreateGC( dpy, win, 0, NULL );
++
++ /* need indirect context */
++ ctx = glXCreateContext( dpy, visinfo, NULL, False );
++ if (!ctx) {
++ printf("Error: glXCreateContext failed\n");
++ exit(-1);
++ }
++
++ printf("Direct rendering: %s\n", glXIsDirect(dpy, ctx) ? "Yes" : "No");
++
++ return win;
++}
++
++
++static GLXPixmap make_pixmap( Display *dpy, Window win,
++ unsigned int width, unsigned int height,
++ Pixmap *pixmap)
++{
++ Pixmap pm;
++ GLXPixmap glxpm;
++ XWindowAttributes attr;
++
++ pm = XCreatePixmap( dpy, win, width, height, visinfo->depth );
++ if (!pm) {
++ printf("Error: XCreatePixmap failed\n");
++ exit(-1);
++ }
++
++ XGetWindowAttributes( dpy, win, &attr );
++
++ /*
++ * IMPORTANT:
++ * Use the glXCreateGLXPixmapMESA funtion when using Mesa because
++ * Mesa needs to know the colormap associated with a pixmap in order
++ * to render correctly. This is because Mesa allows RGB rendering
++ * into any kind of visual, not just TrueColor or DirectColor.
++ */
++#ifdef GLX_MESA_pixmap_colormap
++ if (strstr(glXQueryExtensionsString(dpy, 0), "GLX_MESA_pixmap_colormap")) {
++ /* stand-alone Mesa, specify the colormap */
++ glxpm = glXCreateGLXPixmapMESA( dpy, visinfo, pm, attr.colormap );
++ }
++ else {
++ glxpm = glXCreateGLXPixmap( dpy, visinfo, pm );
++ }
++#else
++ /* This will work with Mesa too if the visual is TrueColor or DirectColor */
++ glxpm = glXCreateGLXPixmap( dpy, visinfo, pm );
++#endif
++
++ if (!glxpm) {
++ printf("Error: GLXCreateGLXPixmap failed\n");
++ exit(-1);
++ }
++
++ *pixmap = pm;
++
++ return glxpm;
++}
++
++
++
++static void event_loop( Display *dpy, GLXPixmap pm )
++{
++ XEvent event;
++
++ while (1) {
++ XNextEvent( dpy, &event );
++
++ switch (event.type) {
++ case Expose:
++ printf("Redraw\n");
++ /* copy the image from GLXPixmap to window */
++ XCopyArea( dpy, pm, event.xany.window, /* src, dest */
++ gc, 0, 0, 300, 300, /* gc, src pos, size */
++ 0, 0 ); /* dest pos */
++ break;
++ case ConfigureNotify:
++ /* nothing */
++ break;
++ }
++ }
++}
++
++
++
++int main( int argc, char *argv[] )
++{
++ Display *dpy;
++ Window win;
++ Pixmap pm;
++ GLXPixmap glxpm;
++
++ dpy = XOpenDisplay(NULL);
++
++ win = make_rgb_window( dpy, 300, 300 );
++ glxpm = make_pixmap( dpy, win, 300, 300, &pm );
++
++ glXMakeCurrent( dpy, glxpm, ctx );
++ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
++
++ /* Render an image into the pixmap */
++ glShadeModel( GL_FLAT );
++ glClearColor( 0.5, 0.5, 0.5, 1.0 );
++ glClear( GL_COLOR_BUFFER_BIT );
++ glViewport( 0, 0, 300, 300 );
++ glOrtho( -1.0, 1.0, -1.0, 1.0, -1.0, 1.0 );
++ glColor3f( 0.0, 1.0, 1.0 );
++ glRectf( -0.75, -0.75, 0.75, 0.75 );
++ glFlush();
++ glXWaitGL();
++
++ XMapWindow( dpy, win );
++
++ event_loop( dpy, pm );
++ return 0;
++}
+diff -Naurp Mesa-7.8.1/progs/xdemos/glxsnoop.c Mesa-7.8.1.patched/progs/xdemos/glxsnoop.c
+--- Mesa-7.8.1/progs/xdemos/glxsnoop.c 1970-01-01 01:00:00.000000000 +0100
++++ Mesa-7.8.1.patched/progs/xdemos/glxsnoop.c 2010-06-13 13:45:06.788792936 +0200
+@@ -0,0 +1,377 @@
++/**
++ * Display/snoop the z/stencil/back/front buffers of another app's window.
++ * Also, an example of the need for shared ancillary renderbuffers.
++ *
++ * Hint: use 'xwininfo' to get a window's ID.
++ *
++ * Brian Paul
++ * 11 Oct 2007
++ */
++
++#define GL_GLEXT_PROTOTYPES
++
++#include <GL/gl.h>
++#include <GL/glx.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <X11/keysym.h>
++
++
++#define Z_BUFFER 1
++#define STENCIL_BUFFER 2
++#define BACK_BUFFER 3
++#define FRONT_BUFFER 4
++
++
++static int Buffer = BACK_BUFFER;
++static int WindowID = 0;
++static const char *DisplayName = NULL;
++static GLXContext Context = 0;
++static int Width, Height;
++
++
++/**
++ * Grab the z/stencil/back/front image from the srcWin and display it
++ * (possibly converted to grayscale) in the dstWin.
++ */
++static void
++redraw(Display *dpy, Window srcWin, Window dstWin )
++{
++ GLubyte *image = malloc(Width * Height * 4);
++
++ glXMakeCurrent(dpy, srcWin, Context);
++ glPixelStorei(GL_PACK_ALIGNMENT, 1);
++ if (Buffer == BACK_BUFFER) {
++ glReadBuffer(GL_BACK);
++ glReadPixels(0, 0, Width, Height, GL_RGBA, GL_UNSIGNED_BYTE, image);
++ }
++ else if (Buffer == FRONT_BUFFER) {
++ glReadBuffer(GL_FRONT);
++ glReadPixels(0, 0, Width, Height, GL_RGBA, GL_UNSIGNED_BYTE, image);
++ }
++ else if (Buffer == Z_BUFFER) {
++ GLfloat *z = malloc(Width * Height * sizeof(GLfloat));
++ int i;
++ glReadPixels(0, 0, Width, Height, GL_DEPTH_COMPONENT, GL_FLOAT, z);
++ for (i = 0; i < Width * Height; i++) {
++ image[i*4+0] =
++ image[i*4+1] =
++ image[i*4+2] = (GLint) (255.0 * z[i]);
++ image[i*4+3] = 255;
++ }
++ free(z);
++ }
++ else if (Buffer == STENCIL_BUFFER) {
++ GLubyte *sten = malloc(Width * Height * sizeof(GLubyte));
++ int i, min = 100, max = -1;
++ float step;
++ int sz;
++ glGetIntegerv(GL_STENCIL_BITS, &sz);
++ glReadPixels(0, 0, Width, Height,
++ GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, sten);
++ /* find min/max for converting stencil to grayscale */
++ for (i = 0; i < Width * Height; i++) {
++ if (sten[i] < min)
++ min = sten[i];
++ if (sten[i] > max)
++ max = sten[i];
++ }
++ if (min == max)
++ step = 0;
++ else
++ step = 255.0 / (float) (max - min);
++ for (i = 0; i < Width * Height; i++) {
++ image[i*4+0] =
++ image[i*4+1] =
++ image[i*4+2] = (GLint) ((sten[i] - min) * step);
++ image[i*4+3] = 255;
++ }
++ free(sten);
++ }
++
++ glXMakeCurrent(dpy, dstWin, Context);
++ glWindowPos2iARB(0, 0);
++ glDrawBuffer(GL_FRONT);
++ glDrawPixels(Width, Height, GL_RGBA, GL_UNSIGNED_BYTE, image);
++ glFlush();
++
++ free(image);
++}
++
++
++static void
++set_window_title(Display *dpy, Window win, const char *title)
++{
++ XSizeHints sizehints;
++ sizehints.flags = 0;
++ XSetStandardProperties(dpy, win, title, title,
++ None, (char **)NULL, 0, &sizehints);
++}
++
++
++static Window
++make_gl_window(Display *dpy, XVisualInfo *visinfo, int width, int height)
++{
++ int scrnum;
++ XSetWindowAttributes attr;
++ unsigned long mask;
++ Window root;
++ Window win;
++ int x = 0, y = 0;
++ char *name = NULL;
++
++ scrnum = DefaultScreen( dpy );
++ root = RootWindow( dpy, scrnum );
++
++ /* window attributes */
++ attr.background_pixel = 0;
++ attr.border_pixel = 0;
++ attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone);
++ attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
++ mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
++
++ win = XCreateWindow( dpy, root, x, y, width, 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(dpy, win, &sizehints);
++ XSetStandardProperties(dpy, win, name, name,
++ None, (char **)NULL, 0, &sizehints);
++ }
++
++ return win;
++}
++
++
++static void
++update_window_title(Display *dpy, Window win)
++{
++ char title[1000], *buf;
++
++ switch (Buffer) {
++ case Z_BUFFER:
++ buf = "Z";
++ break;
++ case STENCIL_BUFFER:
++ buf = "Stencil";
++ break;
++ case BACK_BUFFER:
++ buf = "Back";
++ break;
++ case FRONT_BUFFER:
++ buf = "Front";
++ break;
++ default:
++ buf = "";
++ }
++
++ sprintf(title, "glxsnoop window 0x%x (%s buffer)", (int) WindowID, buf);
++
++ set_window_title(dpy, win, title);
++}
++
++
++static void
++keypress(Display *dpy, Window win, char key)
++{
++ switch (key) {
++ case 27:
++ /* escape */
++ exit(0);
++ break;
++ case 's':
++ Buffer = STENCIL_BUFFER;
++ break;
++ case 'z':
++ Buffer = Z_BUFFER;
++ break;
++ case 'f':
++ Buffer = FRONT_BUFFER;
++ break;
++ case 'b':
++ Buffer = BACK_BUFFER;
++ break;
++ default:
++ return;
++ }
++
++ update_window_title(dpy, win);
++ redraw(dpy, WindowID, win);
++}
++
++
++static void
++event_loop(Display *dpy, Window win)
++{
++ XEvent event;
++
++ while (1) {
++ XNextEvent( dpy, &event );
++
++ switch (event.type) {
++ case Expose:
++ redraw(dpy, WindowID, win);
++ break;
++ case ConfigureNotify:
++ /*resize( event.xconfigure.width, event.xconfigure.height );*/
++ break;
++ case KeyPress:
++ {
++ char buffer[10];
++ int r, code;
++ code = XLookupKeysym(&event.xkey, 0);
++ if (code == XK_Left) {
++ }
++ else {
++ r = XLookupString(&event.xkey, buffer, sizeof(buffer),
++ NULL, NULL);
++ keypress(dpy, win, buffer[0]);
++ }
++ }
++ default:
++ /* nothing */
++ ;
++ }
++ }
++}
++
++
++static VisualID
++get_window_visualid(Display *dpy, Window win)
++{
++ XWindowAttributes attr;
++
++ if (XGetWindowAttributes(dpy, win, &attr)) {
++ return attr.visual->visualid;
++ }
++ else {
++ return 0;
++ }
++}
++
++
++static void
++get_window_size(Display *dpy, Window win, int *w, int *h)
++{
++ XWindowAttributes attr;
++
++ if (XGetWindowAttributes(dpy, win, &attr)) {
++ *w = attr.width;
++ *h = attr.height;
++ }
++ else {
++ *w = *h = 0;
++ }
++}
++
++
++static XVisualInfo *
++visualid_to_visualinfo(Display *dpy, VisualID vid)
++{
++ XVisualInfo *vinfo, templ;
++ long mask;
++ int n;
++
++ templ.visualid = vid;
++ mask = VisualIDMask;
++
++ vinfo = XGetVisualInfo(dpy, mask, &templ, &n);
++ return vinfo;
++}
++
++
++static void
++key_usage(void)
++{
++ printf("Keyboard:\n");
++ printf(" z - display Z buffer\n");
++ printf(" s - display stencil buffer\n");
++ printf(" f - display front color buffer\n");
++ printf(" b - display back buffer\n");
++}
++
++
++static void
++usage(void)
++{
++ printf("Usage: glxsnoop [-display dpy] windowID\n");
++ key_usage();
++}
++
++
++static void
++parse_opts(int argc, char *argv[])
++{
++ int i;
++
++ for (i = 1; i < argc; i++) {
++ if (strcmp(argv[i], "-h") == 0) {
++ usage();
++ exit(0);
++ }
++ else if (strcmp(argv[i], "-display") == 0) {
++ DisplayName = argv[i + 1];
++ i++;
++ }
++ else {
++ if (argv[i][0] == '0' && argv[i][1] == 'x') {
++ /* hex */
++ WindowID = strtol(argv[i], NULL, 16);
++ }
++ else {
++ WindowID = atoi(argv[i]);
++ }
++ break;
++ }
++ }
++
++ if (!WindowID) {
++ usage();
++ exit(0);
++ }
++}
++
++
++int
++main( int argc, char *argv[] )
++{
++ Display *dpy;
++ VisualID vid;
++ XVisualInfo *visinfo;
++ Window win;
++
++ parse_opts(argc, argv);
++
++ key_usage();
++
++ dpy = XOpenDisplay(DisplayName);
++
++ /* find the VisualID for the named window */
++ vid = get_window_visualid(dpy, WindowID);
++ get_window_size(dpy, WindowID, &Width, &Height);
++
++ visinfo = visualid_to_visualinfo(dpy, vid);
++
++ Context = glXCreateContext( dpy, visinfo, NULL, True );
++ if (!Context) {
++ printf("Error: glXCreateContext failed\n");
++ exit(1);
++ }
++
++ win = make_gl_window(dpy, visinfo, Width, Height);
++ XMapWindow(dpy, win);
++ update_window_title(dpy, win);
++
++ event_loop( dpy, win );
++
++ return 0;
++}
+diff -Naurp Mesa-7.8.1/progs/xdemos/glxswapcontrol.c Mesa-7.8.1.patched/progs/xdemos/glxswapcontrol.c
+--- Mesa-7.8.1/progs/xdemos/glxswapcontrol.c 1970-01-01 01:00:00.000000000 +0100
++++ Mesa-7.8.1.patched/progs/xdemos/glxswapcontrol.c 2010-06-13 13:45:06.788792936 +0200
+@@ -0,0 +1,893 @@
++/*
++ * 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.
++ */
++
++/*
++ * This is a port of the infamous "gears" demo to straight GLX (i.e. no GLUT)
++ * Port by Brian Paul 23 March 2001
++ *
++ * Modified by Ian Romanick <idr@us.ibm.com> 09 April 2003 to support
++ * GLX_{MESA,SGI}_swap_control and GLX_OML_sync_control.
++ *
++ * Command line options:
++ * -display Name of the display to use.
++ * -info print GL implementation information
++ * -swap N Attempt to set the swap interval to 1/N second
++ * -forcegetrate Get the display refresh rate even if the required GLX
++ * extension is not supported.
++ */
++
++
++#include <math.h>
++#include <stdlib.h>
++#include <stdio.h>
++#include <string.h>
++#include <X11/Xlib.h>
++#include <X11/keysym.h>
++#ifndef __VMS
++/*# include <stdint.h>*/
++#endif
++# define GLX_GLXEXT_PROTOTYPES
++#include <GL/gl.h>
++#include <GL/glx.h>
++
++#ifndef GLX_MESA_swap_control
++typedef GLint ( * PFNGLXSWAPINTERVALMESAPROC) (unsigned interval);
++typedef GLint ( * PFNGLXGETSWAPINTERVALMESAPROC) ( void );
++#endif
++
++#if !defined( GLX_OML_sync_control ) && defined( _STDINT_H )
++#define GLX_OML_sync_control 1
++typedef Bool ( * PFNGLXGETMSCRATEOMLPROC) (Display *dpy, GLXDrawable drawable, int32_t *numerator, int32_t *denominator);
++#endif
++
++#ifndef GLX_MESA_swap_frame_usage
++#define GLX_MESA_swap_frame_usage 1
++typedef int ( * PFNGLXGETFRAMEUSAGEMESAPROC) (Display *dpy, GLXDrawable drawable, float * usage );
++#endif
++
++#define BENCHMARK
++
++PFNGLXGETFRAMEUSAGEMESAPROC get_frame_usage = NULL;
++
++#ifdef BENCHMARK
++
++/* XXX this probably isn't very portable */
++
++#include <sys/time.h>
++#include <unistd.h>
++
++#define NUL '\0'
++
++/* return current time (in seconds) */
++static int
++current_time(void)
++{
++ struct timeval tv;
++#ifdef __VMS
++ (void) gettimeofday(&tv, NULL );
++#else
++ struct timezone tz;
++ (void) gettimeofday(&tv, &tz);
++#endif
++ return (int) tv.tv_sec;
++}
++
++#else /*BENCHMARK*/
++
++/* dummy */
++static int
++current_time(void)
++{
++ return 0;
++}
++
++#endif /*BENCHMARK*/
++
++
++
++#ifndef M_PI
++#define M_PI 3.14159265
++#endif
++
++
++static GLfloat view_rotx = 20.0, view_roty = 30.0, view_rotz = 0.0;
++static GLint gear1, gear2, gear3;
++static GLfloat angle = 0.0;
++
++static GLboolean has_OML_sync_control = GL_FALSE;
++static GLboolean has_SGI_swap_control = GL_FALSE;
++static GLboolean has_MESA_swap_control = GL_FALSE;
++static GLboolean has_MESA_swap_frame_usage = GL_FALSE;
++
++static char ** extension_table = NULL;
++static unsigned num_extensions;
++
++static GLboolean use_ztrick = GL_FALSE;
++static GLfloat aspectX = 1.0f, aspectY = 1.0f;
++
++/*
++ *
++ * Draw a gear wheel. You'll probably want to call this function when
++ * building a display list since we do a lot of trig here.
++ *
++ * Input: 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
++gear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width,
++ GLint teeth, GLfloat tooth_depth)
++{
++ GLint i;
++ GLfloat r0, r1, r2;
++ GLfloat angle, da;
++ GLfloat u, v, len;
++
++ r0 = inner_radius;
++ r1 = outer_radius - tooth_depth / 2.0;
++ r2 = outer_radius + tooth_depth / 2.0;
++
++ da = 2.0 * M_PI / teeth / 4.0;
++
++ glShadeModel(GL_FLAT);
++
++ glNormal3f(0.0, 0.0, 1.0);
++
++ /* draw front face */
++ glBegin(GL_QUAD_STRIP);
++ for (i = 0; i <= teeth; i++) {
++ angle = i * 2.0 * M_PI / teeth;
++ glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
++ glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
++ if (i < teeth) {
++ glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
++ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
++ width * 0.5);
++ }
++ }
++ glEnd();
++
++ /* draw front sides of teeth */
++ glBegin(GL_QUADS);
++ da = 2.0 * M_PI / teeth / 4.0;
++ for (i = 0; i < teeth; i++) {
++ angle = i * 2.0 * M_PI / teeth;
++
++ glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
++ glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
++ glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
++ width * 0.5);
++ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
++ width * 0.5);
++ }
++ glEnd();
++
++ glNormal3f(0.0, 0.0, -1.0);
++
++ /* draw back face */
++ glBegin(GL_QUAD_STRIP);
++ for (i = 0; i <= teeth; i++) {
++ angle = i * 2.0 * M_PI / teeth;
++ glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
++ glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
++ if (i < teeth) {
++ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
++ -width * 0.5);
++ glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
++ }
++ }
++ glEnd();
++
++ /* draw back sides of teeth */
++ glBegin(GL_QUADS);
++ da = 2.0 * M_PI / teeth / 4.0;
++ for (i = 0; i < teeth; i++) {
++ angle = i * 2.0 * M_PI / teeth;
++
++ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
++ -width * 0.5);
++ glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
++ -width * 0.5);
++ glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
++ glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
++ }
++ glEnd();
++
++ /* draw outward faces of teeth */
++ glBegin(GL_QUAD_STRIP);
++ for (i = 0; i < teeth; i++) {
++ angle = i * 2.0 * M_PI / teeth;
++
++ glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
++ glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
++ u = r2 * cos(angle + da) - r1 * cos(angle);
++ v = r2 * sin(angle + da) - r1 * sin(angle);
++ len = sqrt(u * u + v * v);
++ u /= len;
++ v /= len;
++ glNormal3f(v, -u, 0.0);
++ glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
++ glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
++ glNormal3f(cos(angle), sin(angle), 0.0);
++ glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
++ width * 0.5);
++ glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
++ -width * 0.5);
++ u = r1 * cos(angle + 3 * da) - r2 * cos(angle + 2 * da);
++ v = r1 * sin(angle + 3 * da) - r2 * sin(angle + 2 * da);
++ glNormal3f(v, -u, 0.0);
++ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
++ width * 0.5);
++ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
++ -width * 0.5);
++ glNormal3f(cos(angle), sin(angle), 0.0);
++ }
++
++ glVertex3f(r1 * cos(0), r1 * sin(0), width * 0.5);
++ glVertex3f(r1 * cos(0), r1 * sin(0), -width * 0.5);
++
++ glEnd();
++
++ glShadeModel(GL_SMOOTH);
++
++ /* draw inside radius cylinder */
++ glBegin(GL_QUAD_STRIP);
++ for (i = 0; i <= teeth; i++) {
++ angle = i * 2.0 * M_PI / teeth;
++ glNormal3f(-cos(angle), -sin(angle), 0.0);
++ glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
++ glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
++ }
++ glEnd();
++}
++
++
++static void
++draw(void)
++{
++ if ( use_ztrick ) {
++ static GLboolean flip = GL_FALSE;
++ static const GLfloat vert[4][3] = {
++ { -1, -1, -0.999 },
++ { 1, -1, -0.999 },
++ { 1, 1, -0.999 },
++ { -1, 1, -0.999 }
++ };
++ static const GLfloat col[4][3] = {
++ { 1.0, 0.6, 0.0 },
++ { 1.0, 0.6, 0.0 },
++ { 0.0, 0.0, 0.0 },
++ { 0.0, 0.0, 0.0 },
++ };
++
++ if ( flip ) {
++ glDepthRange(0, 0.5);
++ glDepthFunc(GL_LEQUAL);
++ }
++ else {
++ glDepthRange(1.0, 0.4999);
++ glDepthFunc(GL_GEQUAL);
++ }
++
++ flip = !flip;
++
++ /* The famous Quake "Z trick" only works when the whole screen is
++ * re-drawn each frame.
++ */
++
++ glMatrixMode(GL_MODELVIEW);
++ glLoadIdentity();
++ glMatrixMode(GL_PROJECTION);
++ glLoadIdentity();
++ glOrtho(-1, 1, -1, 1, -1, 1);
++ glDisable(GL_LIGHTING);
++ glShadeModel(GL_SMOOTH);
++
++ glEnableClientState( GL_VERTEX_ARRAY );
++ glEnableClientState( GL_COLOR_ARRAY );
++ glVertexPointer( 3, GL_FLOAT, 0, vert );
++ glColorPointer( 3, GL_FLOAT, 0, col );
++ glDrawArrays( GL_POLYGON, 0, 4 );
++ glDisableClientState( GL_COLOR_ARRAY );
++ glDisableClientState( GL_VERTEX_ARRAY );
++
++ glMatrixMode(GL_PROJECTION);
++ glLoadIdentity();
++ glFrustum(-aspectX, aspectX, -aspectY, aspectY, 5.0, 60.0);
++
++ glEnable(GL_LIGHTING);
++
++ glMatrixMode(GL_MODELVIEW);
++ glLoadIdentity();
++ glTranslatef(0.0, 0.0, -45.0);
++ }
++ else {
++ 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);
++ glCallList(gear1);
++ glPopMatrix();
++
++ glPushMatrix();
++ glTranslatef(3.1, -2.0, 0.0);
++ glRotatef(-2.0 * angle - 9.0, 0.0, 0.0, 1.0);
++ glCallList(gear2);
++ glPopMatrix();
++
++ glPushMatrix();
++ glTranslatef(-3.1, 4.2, 0.0);
++ glRotatef(-2.0 * angle - 25.0, 0.0, 0.0, 1.0);
++ glCallList(gear3);
++ glPopMatrix();
++
++ glPopMatrix();
++}
++
++
++/* new window size or exposure */
++static void
++reshape(int width, int height)
++{
++ if (width > height) {
++ aspectX = (GLfloat) width / (GLfloat) height;
++ aspectY = 1.0;
++ }
++ else {
++ aspectX = 1.0;
++ aspectY = (GLfloat) height / (GLfloat) width;
++ }
++
++ glViewport(0, 0, (GLint) width, (GLint) height);
++ glMatrixMode(GL_PROJECTION);
++ glLoadIdentity();
++
++ glFrustum(-aspectX, aspectX, -aspectY, aspectY, 5.0, 60.0);
++ glMatrixMode(GL_MODELVIEW);
++ glLoadIdentity();
++ glTranslatef(0.0, 0.0, -45.0);
++}
++
++
++static void
++init(void)
++{
++ static GLfloat pos[4] = { 5.0, 5.0, 10.0, 0.0 };
++ static GLfloat red[4] = { 0.8, 0.1, 0.0, 1.0 };
++ static GLfloat green[4] = { 0.0, 0.8, 0.2, 1.0 };
++ static GLfloat blue[4] = { 0.2, 0.2, 1.0, 1.0 };
++
++ glLightfv(GL_LIGHT0, GL_POSITION, pos);
++ glEnable(GL_CULL_FACE);
++ glEnable(GL_LIGHTING);
++ glEnable(GL_LIGHT0);
++ glEnable(GL_DEPTH_TEST);
++
++ /* make the gears */
++ gear1 = glGenLists(1);
++ glNewList(gear1, GL_COMPILE);
++ glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red);
++ gear(1.0, 4.0, 1.0, 20, 0.7);
++ glEndList();
++
++ gear2 = glGenLists(1);
++ glNewList(gear2, GL_COMPILE);
++ glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green);
++ gear(0.5, 2.0, 2.0, 10, 0.7);
++ glEndList();
++
++ gear3 = glGenLists(1);
++ glNewList(gear3, GL_COMPILE);
++ glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue);
++ gear(1.3, 2.0, 0.5, 10, 0.7);
++ glEndList();
++
++ glEnable(GL_NORMALIZE);
++}
++
++
++/**
++ * Remove window border/decorations.
++ */
++static void
++no_border( Display *dpy, Window w)
++{
++ static const unsigned MWM_HINTS_DECORATIONS = (1 << 1);
++ static const int PROP_MOTIF_WM_HINTS_ELEMENTS = 5;
++
++ typedef struct
++ {
++ unsigned long flags;
++ unsigned long functions;
++ unsigned long decorations;
++ long inputMode;
++ unsigned long status;
++ } PropMotifWmHints;
++
++ PropMotifWmHints motif_hints;
++ Atom prop, proptype;
++ unsigned long flags = 0;
++
++ /* setup the property */
++ motif_hints.flags = MWM_HINTS_DECORATIONS;
++ motif_hints.decorations = flags;
++
++ /* get the atom for the property */
++ prop = XInternAtom( dpy, "_MOTIF_WM_HINTS", True );
++ if (!prop) {
++ /* something went wrong! */
++ return;
++ }
++
++ /* not sure this is correct, seems to work, XA_WM_HINTS didn't work */
++ proptype = prop;
++
++ XChangeProperty( dpy, w, /* display, window */
++ prop, proptype, /* property, type */
++ 32, /* format: 32-bit datums */
++ PropModeReplace, /* mode */
++ (unsigned char *) &motif_hints, /* data */
++ PROP_MOTIF_WM_HINTS_ELEMENTS /* nelements */
++ );
++}
++
++
++/*
++ * Create an RGB, double-buffered window.
++ * Return the window and context handles.
++ */
++static void
++make_window( Display *dpy, const char *name,
++ int x, int y, int width, int height, GLboolean fullscreen,
++ Window *winRet, GLXContext *ctxRet)
++{
++ int attrib[] = { GLX_RGBA,
++ GLX_RED_SIZE, 1,
++ GLX_GREEN_SIZE, 1,
++ GLX_BLUE_SIZE, 1,
++ GLX_DOUBLEBUFFER,
++ GLX_DEPTH_SIZE, 1,
++ None };
++ int scrnum;
++ XSetWindowAttributes attr;
++ unsigned long mask;
++ Window root;
++ Window win;
++ GLXContext ctx;
++ XVisualInfo *visinfo;
++
++ scrnum = DefaultScreen( dpy );
++ root = RootWindow( dpy, scrnum );
++
++ if (fullscreen) {
++ x = y = 0;
++ width = DisplayWidth( dpy, scrnum );
++ height = DisplayHeight( dpy, scrnum );
++ }
++
++ visinfo = glXChooseVisual( dpy, scrnum, attrib );
++ if (!visinfo) {
++ printf("Error: couldn't get an RGB, Double-buffered visual\n");
++ exit(1);
++ }
++
++ /* window attributes */
++ attr.background_pixel = 0;
++ attr.border_pixel = 0;
++ attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone);
++ attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
++ mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
++
++ win = XCreateWindow( dpy, root, 0, 0, width, 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(dpy, win, &sizehints);
++ XSetStandardProperties(dpy, win, name, name,
++ None, (char **)NULL, 0, &sizehints);
++ }
++
++ if (fullscreen)
++ no_border(dpy, win);
++
++ ctx = glXCreateContext( dpy, visinfo, NULL, True );
++ if (!ctx) {
++ printf("Error: glXCreateContext failed\n");
++ exit(1);
++ }
++
++ XFree(visinfo);
++
++ *winRet = win;
++ *ctxRet = ctx;
++}
++
++
++static void
++event_loop(Display *dpy, Window win)
++{
++ float frame_usage = 0.0;
++
++ while (1) {
++ while (XPending(dpy) > 0) {
++ XEvent event;
++ XNextEvent(dpy, &event);
++ switch (event.type) {
++ case Expose:
++ /* we'll redraw below */
++ break;
++ case ConfigureNotify:
++ reshape(event.xconfigure.width, event.xconfigure.height);
++ break;
++ case KeyPress:
++ {
++ char buffer[10];
++ int r, code;
++ code = XLookupKeysym(&event.xkey, 0);
++ if (code == XK_Left) {
++ view_roty += 5.0;
++ }
++ else if (code == XK_Right) {
++ view_roty -= 5.0;
++ }
++ else if (code == XK_Up) {
++ view_rotx += 5.0;
++ }
++ else if (code == XK_Down) {
++ view_rotx -= 5.0;
++ }
++ else {
++ r = XLookupString(&event.xkey, buffer, sizeof(buffer),
++ NULL, NULL);
++ if (buffer[0] == 27) {
++ /* escape */
++ return;
++ }
++ }
++ }
++ }
++ }
++
++ /* next frame */
++ angle += 2.0;
++
++ draw();
++
++ glXSwapBuffers(dpy, win);
++
++ if ( get_frame_usage != NULL ) {
++ GLfloat temp;
++
++ (*get_frame_usage)( dpy, win, & temp );
++ frame_usage += temp;
++ }
++
++ /* calc framerate */
++ {
++ static int t0 = -1;
++ static int frames = 0;
++ int t = current_time();
++
++ if (t0 < 0)
++ t0 = t;
++
++ frames++;
++
++ if (t - t0 >= 5.0) {
++ GLfloat seconds = t - t0;
++ GLfloat fps = frames / seconds;
++ if ( get_frame_usage != NULL ) {
++ printf("%d frames in %3.1f seconds = %6.3f FPS (%3.1f%% usage)\n",
++ frames, seconds, fps,
++ (frame_usage * 100.0) / (float) frames );
++ }
++ else {
++ printf("%d frames in %3.1f seconds = %6.3f FPS\n",
++ frames, seconds, fps);
++ }
++
++ t0 = t;
++ frames = 0;
++ frame_usage = 0.0;
++ }
++ }
++ }
++}
++
++
++/**
++ * Display the refresh rate of the display using the GLX_OML_sync_control
++ * extension.
++ */
++static void
++show_refresh_rate( Display * dpy )
++{
++#if defined(GLX_OML_sync_control) && defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
++ PFNGLXGETMSCRATEOMLPROC get_msc_rate;
++ int32_t n;
++ int32_t d;
++
++ get_msc_rate = (PFNGLXGETMSCRATEOMLPROC) glXGetProcAddressARB( (const GLubyte *) "glXGetMscRateOML" );
++ if ( get_msc_rate != NULL ) {
++ (*get_msc_rate)( dpy, glXGetCurrentDrawable(), &n, &d );
++ printf( "refresh rate: %.1fHz\n", (float) n / d );
++ return;
++ }
++#endif
++ printf( "glXGetMscRateOML not supported.\n" );
++}
++
++
++/**
++ * Fill in the table of extension strings from a supplied extensions string
++ * (as returned by glXQueryExtensionsString).
++ *
++ * \param string String of GLX extensions.
++ * \sa is_extension_supported
++ */
++static void
++make_extension_table( const char * string )
++{
++ char ** string_tab;
++ unsigned num_strings;
++ unsigned base;
++ unsigned idx;
++ unsigned i;
++
++ /* Count the number of spaces in the string. That gives a base-line
++ * figure for the number of extension in the string.
++ */
++
++ num_strings = 1;
++ for ( i = 0 ; string[i] != NUL ; i++ ) {
++ if ( string[i] == ' ' ) {
++ num_strings++;
++ }
++ }
++
++ string_tab = (char **) malloc( sizeof( char * ) * num_strings );
++ if ( string_tab == NULL ) {
++ return;
++ }
++
++ base = 0;
++ idx = 0;
++
++ while ( string[ base ] != NUL ) {
++ /* Determine the length of the next extension string.
++ */
++
++ for ( i = 0
++ ; (string[ base + i ] != NUL) && (string[ base + i ] != ' ')
++ ; i++ ) {
++ /* empty */ ;
++ }
++
++ if ( i > 0 ) {
++ /* If the string was non-zero length, add it to the table. We
++ * can get zero length strings if there is a space at the end of
++ * the string or if there are two (or more) spaces next to each
++ * other in the string.
++ */
++
++ string_tab[ idx ] = malloc( sizeof( char ) * (i + 1) );
++ if ( string_tab[ idx ] == NULL ) {
++ return;
++ }
++
++ (void) memcpy( string_tab[ idx ], & string[ base ], i );
++ string_tab[ idx ][i] = NUL;
++ idx++;
++ }
++
++
++ /* Skip to the start of the next extension string.
++ */
++
++ for ( base += i
++ ; (string[ base ] == ' ') && (string[ base ] != NUL)
++ ; base++ ) {
++ /* empty */ ;
++ }
++ }
++
++ extension_table = string_tab;
++ num_extensions = idx;
++}
++
++
++/**
++ * Determine of an extension is supported. The extension string table
++ * must have already be initialized by calling \c make_extension_table.
++ *
++ * \praram ext Extension to be tested.
++ * \return GL_TRUE of the extension is supported, GL_FALSE otherwise.
++ * \sa make_extension_table
++ */
++static GLboolean
++is_extension_supported( const char * ext )
++{
++ unsigned i;
++
++ for ( i = 0 ; i < num_extensions ; i++ ) {
++ if ( strcmp( ext, extension_table[i] ) == 0 ) {
++ return GL_TRUE;
++ }
++ }
++
++ return GL_FALSE;
++}
++
++
++int
++main(int argc, char *argv[])
++{
++ Display *dpy;
++ Window win;
++ GLXContext ctx;
++ char *dpyName = NULL;
++ int swap_interval = 1;
++ GLboolean do_swap_interval = GL_FALSE;
++ GLboolean force_get_rate = GL_FALSE;
++ GLboolean fullscreen = GL_FALSE;
++ GLboolean printInfo = GL_FALSE;
++ int i;
++ PFNGLXSWAPINTERVALMESAPROC set_swap_interval = NULL;
++ PFNGLXGETSWAPINTERVALMESAPROC get_swap_interval = NULL;
++ int width = 300, height = 300;
++
++ for (i = 1; i < argc; i++) {
++ if (strcmp(argv[i], "-display") == 0 && i + 1 < argc) {
++ dpyName = argv[i+1];
++ i++;
++ }
++ else if (strcmp(argv[i], "-info") == 0) {
++ printInfo = GL_TRUE;
++ }
++ else if (strcmp(argv[i], "-swap") == 0 && i + 1 < argc) {
++ swap_interval = atoi( argv[i+1] );
++ do_swap_interval = GL_TRUE;
++ i++;
++ }
++ else if (strcmp(argv[i], "-forcegetrate") == 0) {
++ /* This option was put in because some DRI drivers don't support the
++ * full GLX_OML_sync_control extension, but they do support
++ * glXGetMscRateOML.
++ */
++ force_get_rate = GL_TRUE;
++ }
++ else if (strcmp(argv[i], "-fullscreen") == 0) {
++ fullscreen = GL_TRUE;
++ }
++ else if (strcmp(argv[i], "-ztrick") == 0) {
++ use_ztrick = GL_TRUE;
++ }
++ else if (strcmp(argv[i], "-help") == 0) {
++ printf("Usage:\n");
++ printf(" gears [options]\n");
++ printf("Options:\n");
++ printf(" -help Print this information\n");
++ printf(" -display displayName Specify X display\n");
++ printf(" -info Display GL information\n");
++ printf(" -swap N Swap no more than once per N vertical refreshes\n");
++ printf(" -forcegetrate Try to use glXGetMscRateOML function\n");
++ printf(" -fullscreen Full-screen window\n");
++ return 0;
++ }
++ }
++
++ dpy = XOpenDisplay(dpyName);
++ if (!dpy) {
++ printf("Error: couldn't open display %s\n", XDisplayName(dpyName));
++ return -1;
++ }
++
++ make_window(dpy, "glxgears", 0, 0, width, height, fullscreen, &win, &ctx);
++ XMapWindow(dpy, win);
++ glXMakeCurrent(dpy, win, ctx);
++
++ make_extension_table( (char *) glXQueryExtensionsString(dpy,DefaultScreen(dpy)) );
++ has_OML_sync_control = is_extension_supported( "GLX_OML_sync_control" );
++ has_SGI_swap_control = is_extension_supported( "GLX_SGI_swap_control" );
++ has_MESA_swap_control = is_extension_supported( "GLX_MESA_swap_control" );
++ has_MESA_swap_frame_usage = is_extension_supported( "GLX_MESA_swap_frame_usage" );
++
++ if ( has_MESA_swap_control ) {
++ set_swap_interval = (PFNGLXSWAPINTERVALMESAPROC) glXGetProcAddressARB( (const GLubyte *) "glXSwapIntervalMESA" );
++ get_swap_interval = (PFNGLXGETSWAPINTERVALMESAPROC) glXGetProcAddressARB( (const GLubyte *) "glXGetSwapIntervalMESA" );
++ }
++ else if ( has_SGI_swap_control ) {
++ set_swap_interval = (PFNGLXSWAPINTERVALMESAPROC) glXGetProcAddressARB( (const GLubyte *) "glXSwapIntervalSGI" );
++ }
++
++
++ if ( has_MESA_swap_frame_usage ) {
++ get_frame_usage = (PFNGLXGETFRAMEUSAGEMESAPROC) glXGetProcAddressARB( (const GLubyte *) "glXGetFrameUsageMESA" );
++ }
++
++
++ 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));
++ if ( has_OML_sync_control || force_get_rate ) {
++ show_refresh_rate( dpy );
++ }
++
++ if ( get_swap_interval != NULL ) {
++ printf("Default swap interval = %d\n", (*get_swap_interval)() );
++ }
++ }
++
++ if ( do_swap_interval ) {
++ if ( set_swap_interval != NULL ) {
++ if ( ((swap_interval == 0) && !has_MESA_swap_control)
++ || (swap_interval < 0) ) {
++ printf( "Swap interval must be non-negative or greater than zero "
++ "if GLX_MESA_swap_control is not supported.\n" );
++ }
++ else {
++ (*set_swap_interval)( swap_interval );
++ }
++
++ if ( printInfo && (get_swap_interval != NULL) ) {
++ printf("Current swap interval = %d\n", (*get_swap_interval)() );
++ }
++ }
++ else {
++ printf("Unable to set swap-interval. Neither GLX_SGI_swap_control "
++ "nor GLX_MESA_swap_control are supported.\n" );
++ }
++ }
++
++ init();
++
++ /* Set initial projection/viewing transformation.
++ * same as glxgears.c
++ */
++ reshape(width, height);
++
++ event_loop(dpy, win);
++
++ glXDestroyContext(dpy, ctx);
++ XDestroyWindow(dpy, win);
++ XCloseDisplay(dpy);
++
++ return 0;
++}
+diff -Naurp Mesa-7.8.1/progs/xdemos/ipc.c Mesa-7.8.1.patched/progs/xdemos/ipc.c
+--- Mesa-7.8.1/progs/xdemos/ipc.c 1970-01-01 01:00:00.000000000 +0100
++++ Mesa-7.8.1.patched/progs/xdemos/ipc.c 2010-06-13 13:45:06.789793146 +0200
+@@ -0,0 +1,264 @@
++/* Copyright (c) 2003 Tungsten Graphics, 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, the Tungsten
++ * Graphics splash screen, 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.
++ */
++
++/*
++ * Simple IPC API
++ * Brian Paul
++ */
++
++
++#include <assert.h>
++#include <stdio.h>
++#include <string.h>
++#include <sys/types.h>
++#include <netinet/in.h>
++#include <netinet/tcp.h>
++#include <arpa/inet.h>
++#include <netdb.h>
++#include <unistd.h>
++#include <sys/socket.h>
++#include "ipc.h"
++
++#if defined(IRIX) || defined(irix)
++typedef int socklen_t;
++#endif
++
++#define NO_DELAY 1
++
++#define DEFAULT_MASTER_PORT 7011
++
++
++/*
++ * Return my hostname in <nameOut>.
++ * Return 1 for success, 0 for error.
++ */
++int
++MyHostName(char *nameOut, int maxNameLength)
++{
++ int k = gethostname(nameOut, maxNameLength);
++ return k==0;
++}
++
++
++/*
++ * Create a socket attached to a port. Later, we can call AcceptConnection
++ * on the socket returned from this function.
++ * Return the new socket number or -1 if error.
++ */
++int
++CreatePort(int *port)
++{
++ char hostname[1000];
++ struct sockaddr_in servaddr;
++ struct hostent *hp;
++ int so_reuseaddr = 1;
++ int tcp_nodelay = 1;
++ int sock, k;
++
++ /* create socket */
++ sock = socket(AF_INET, SOCK_STREAM, 0);
++ assert(sock > 2);
++
++ /* get my host name */
++ k = gethostname(hostname, 1000);
++ assert(k == 0);
++
++ /* get hostent info */
++ hp = gethostbyname(hostname);
++ assert(hp);
++
++ /* initialize the servaddr struct */
++ memset(&servaddr, 0, sizeof(servaddr) );
++ servaddr.sin_family = AF_INET;
++ servaddr.sin_port = htons((unsigned short) (*port));
++ memcpy((char *) &servaddr.sin_addr, hp->h_addr,
++ sizeof(servaddr.sin_addr));
++
++ /* deallocate when we exit */
++ k = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
++ (char *) &so_reuseaddr, sizeof(so_reuseaddr));
++ assert(k==0);
++
++ /* send packets immediately */
++#if NO_DELAY
++ k = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
++ (char *) &tcp_nodelay, sizeof(tcp_nodelay));
++ assert(k==0);
++#endif
++
++ if (*port == 0)
++ *port = DEFAULT_MASTER_PORT;
++
++ k = 1;
++ while (k && (*port < 65534)) {
++ /* bind our address to the socket */
++ servaddr.sin_port = htons((unsigned short) (*port));
++ k = bind(sock, (struct sockaddr *) &servaddr, sizeof(servaddr));
++ if (k)
++ *port = *port + 1;
++ }
++
++#if 0
++ printf("###### Real Port: %d\n", *port);
++#endif
++
++ /* listen for connections */
++ k = listen(sock, 100);
++ assert(k == 0);
++
++ return sock;
++}
++
++
++/*
++ * Accept a connection on the named socket.
++ * Return a new socket for the new connection, or -1 if error.
++ */
++int
++AcceptConnection(int socket)
++{
++ struct sockaddr addr;
++ socklen_t addrLen;
++ int newSock;
++
++ addrLen = sizeof(addr);
++ newSock = accept(socket, &addr, &addrLen);
++ if (newSock == 1)
++ return -1;
++ else
++ return newSock;
++}
++
++
++/*
++ * Contact the server running on the given host on the named port.
++ * Return socket number or -1 if error.
++ */
++int
++Connect(const char *hostname, int port)
++{
++ struct sockaddr_in servaddr;
++ struct hostent *hp;
++ int sock, k;
++ int tcp_nodelay = 1;
++
++ assert(port);
++
++ sock = socket(AF_INET, SOCK_STREAM, 0);
++ assert(sock >= 0);
++
++ hp = gethostbyname(hostname);
++ assert(hp);
++
++ memset(&servaddr, 0, sizeof(servaddr));
++ servaddr.sin_family = AF_INET;
++ servaddr.sin_port = htons((unsigned short) port);
++ memcpy((char *) &servaddr.sin_addr, hp->h_addr, sizeof(servaddr.sin_addr));
++
++ k = connect(sock, (struct sockaddr *) &servaddr, sizeof(servaddr));
++ if (k != 0) {
++ perror("Connect:");
++ return -1;
++ }
++
++#if NO_DELAY
++ /* send packets immediately */
++ k = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
++ (char *) &tcp_nodelay, sizeof(tcp_nodelay));
++ assert(k==0);
++#endif
++
++ return sock;
++}
++
++
++void
++CloseSocket(int socket)
++{
++ close(socket);
++}
++
++
++int
++SendData(int socket, const void *data, int bytes)
++{
++ int sent = 0;
++ int b;
++
++ while (sent < bytes) {
++ b = write(socket, (char *) data + sent, bytes - sent);
++ if (b <= 0)
++ return -1; /* something broke */
++ sent += b;
++ }
++ return sent;
++}
++
++
++int
++ReceiveData(int socket, void *data, int bytes)
++{
++ int received = 0, b;
++
++ while (received < bytes) {
++ b = read(socket, (char *) data + received, bytes - received);
++ if (b <= 0)
++ return -1;
++ received += b;
++ }
++ return received;
++}
++
++
++int
++SendString(int socket, const char *str)
++{
++ const int len = strlen(str);
++ int sent, b;
++
++ /* first, send a 4-byte length indicator */
++ b = write(socket, &len, sizeof(len));
++ if (b <= 0)
++ return -1;
++
++ sent = SendData(socket, str, len);
++ assert(sent == len);
++ return sent;
++}
++
++
++int
++ReceiveString(int socket, char *str, int maxLen)
++{
++ int len, received, b;
++
++ /* first, read 4 bytes to see how long of string to receive */
++ b = read(socket, &len, sizeof(len));
++ if (b <= 0)
++ return -1;
++
++ assert(len <= maxLen); /* XXX fix someday */
++ assert(len >= 0);
++ received = ReceiveData(socket, str, len);
++ assert(received != -1);
++ assert(received == len);
++ str[len] = 0;
++ return received;
++}
+diff -Naurp Mesa-7.8.1/progs/xdemos/ipc.h Mesa-7.8.1.patched/progs/xdemos/ipc.h
+--- Mesa-7.8.1/progs/xdemos/ipc.h 1970-01-01 01:00:00.000000000 +0100
++++ Mesa-7.8.1.patched/progs/xdemos/ipc.h 2010-06-13 13:45:06.789793146 +0200
+@@ -0,0 +1,16 @@
++#ifndef IPC_H
++#define IPC_H
++
++
++extern int MyHostName(char *nameOut, int maxNameLength);
++extern int CreatePort(int *port);
++extern int AcceptConnection(int socket);
++extern int Connect(const char *hostname, int port);
++extern void CloseSocket(int socket);
++extern int SendData(int socket, const void *data, int bytes);
++extern int ReceiveData(int socket, void *data, int bytes);
++extern int SendString(int socket, const char *str);
++extern int ReceiveString(int socket, char *str, int maxLen);
++
++
++#endif /* IPC_H */
+diff -Naurp Mesa-7.8.1/progs/xdemos/Makefile Mesa-7.8.1.patched/progs/xdemos/Makefile
+--- Mesa-7.8.1/progs/xdemos/Makefile 1970-01-01 01:00:00.000000000 +0100
++++ Mesa-7.8.1.patched/progs/xdemos/Makefile 2010-06-13 13:45:06.788792936 +0200
+@@ -0,0 +1,103 @@
++# progs/xdemos/Makefile
++
++TOP = ../..
++include $(TOP)/configs/current
++
++
++INCDIR = $(TOP)/include
++
++LIB_DEP = $(TOP)/$(LIB_DIR)/$(GL_LIB_NAME)
++
++# Add X11 and pthread libs to satisfy GNU gold.
++APP_LIB_DEPS += -lX11 -lpthread
++
++LIBS = -L$(TOP)/$(LIB_DIR) -l$(GL_LIB) -L$(libdir) $(APP_LIB_DEPS)
++
++PROGS = \
++ corender \
++ glsync \
++ glthreads \
++ glxdemo \
++ glxgears \
++ glxgears_fbconfig \
++ glxgears_pixmap \
++ glxcontexts \
++ glxheads \
++ glxinfo \
++ glxpixmap \
++ glxpbdemo \
++ glxsnoop \
++ glxswapcontrol \
++ manywin \
++ msctest \
++ multictx \
++ offset \
++ omlsync \
++ overlay \
++ pbinfo \
++ pbdemo \
++ sharedtex \
++ sharedtex_mt \
++ texture_from_pixmap \
++ wincopy \
++ xfont \
++ xrotfontdemo
++
++# Don't build these by default because of extra library dependencies
++EXTRA_PROGS = \
++ shape \
++ yuvrect_client \
++ xdemo
++
++
++
++##### RULES #####
++
++.o: $(LIB_DEP)
++ $(APP_CC) $(CFLAGS) $(LDFLAGS) $< $(LIBS) -o $@
++
++.c.o:
++ $(APP_CC) -I$(INCDIR) $(X11_INCLUDES) $(CFLAGS) $< -c -o $@
++
++
++##### TARGETS #####
++
++default: $(PROGS)
++
++$(PROGS): $(PROGS:%=%.o)
++
++extra: $(EXTRA_PROGS)
++
++
++clean:
++ -rm -f $(PROGS) $(EXTRA_PROGS)
++ -rm -f *.o *~
++
++
++# special cases
++pbutil.o: pbutil.h
++pbinfo.o: pbutil.h
++pbinfo: pbinfo.o pbutil.o
++ $(APP_CC) $(CFLAGS) $(LDFLAGS) pbinfo.o pbutil.o $(LIBS) -o $@
++
++pbdemo.o: pbutil.h
++pbdemo: pbdemo.o pbutil.o
++ $(APP_CC) $(CFLAGS) $(LDFLAGS) pbdemo.o pbutil.o $(LIBS) -o $@
++
++glxgears_fbconfig.o: pbutil.h
++glxgears_fbconfig: glxgears_fbconfig.o pbutil.o
++ $(APP_CC) $(CFLAGS) $(LDFLAGS) glxgears_fbconfig.o pbutil.o $(LIBS) -o $@
++
++xuserotfont.o: xuserotfont.h
++xrotfontdemo.o: xuserotfont.h
++xrotfontdemo: xrotfontdemo.o xuserotfont.o
++ $(APP_CC) $(CFLAGS) $(LDFLAGS) xrotfontdemo.o xuserotfont.o $(LIBS) -o $@
++
++ipc.o: ipc.h
++corender.o: ipc.h
++corender: corender.o ipc.o
++ $(APP_CC) $(CFLAGS) $(LDFLAGS) corender.o ipc.o $(LIBS) -o $@
++
++yuvrect_client: yuvrect_client.o
++ $(APP_CC) $(CFLAGS) $< $(LDFLAGS) $(LIBS) -l$(GLU_LIB) -o $@
++
+diff -Naurp Mesa-7.8.1/progs/xdemos/manywin.c Mesa-7.8.1.patched/progs/xdemos/manywin.c
+--- Mesa-7.8.1/progs/xdemos/manywin.c 1970-01-01 01:00:00.000000000 +0100
++++ Mesa-7.8.1.patched/progs/xdemos/manywin.c 2010-06-13 13:45:06.789793146 +0200
+@@ -0,0 +1,421 @@
++/*
++ * Create N GLX windows/contexts and render to them in round-robin order.
++ * Also, have the contexts share all texture objects.
++ * Press 'd' to delete a texture, 'u' to unbind it.
++ *
++ * Copyright (C) 2000 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 <GL/gl.h>
++#include <GL/glx.h>
++#include <assert.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <unistd.h>
++#include <X11/keysym.h>
++
++
++/*
++ * Each display/window/context:
++ */
++struct head {
++ char DisplayName[1000];
++ Display *Dpy;
++ Window Win;
++ GLXContext Context;
++ float Angle;
++ char Renderer[1000];
++ char Vendor[1000];
++ char Version[1000];
++};
++
++
++#define MAX_HEADS 200
++static struct head Heads[MAX_HEADS];
++static int NumHeads = 0;
++static GLboolean SwapSeparate = GL_TRUE;
++static GLuint TexObj = 0;
++
++
++static void
++Error(const char *display, const char *msg)
++{
++ fprintf(stderr, "Error on display %s - %s\n", XDisplayName(display), msg);
++ exit(1);
++}
++
++
++static struct head *
++AddHead(const char *displayName, const char *name)
++{
++ Display *dpy;
++ Window win;
++ GLXContext ctx;
++ int attrib[] = { GLX_RGBA,
++ GLX_RED_SIZE, 1,
++ GLX_GREEN_SIZE, 1,
++ GLX_BLUE_SIZE, 1,
++ GLX_DOUBLEBUFFER,
++ None };
++ int scrnum;
++ XSetWindowAttributes attr;
++ unsigned long mask;
++ Window root;
++ XVisualInfo *visinfo;
++ int width = 90, height = 90;
++ int xpos = 0, ypos = 0;
++
++ if (NumHeads >= MAX_HEADS)
++ return NULL;
++
++ dpy = XOpenDisplay(displayName);
++ if (!dpy) {
++ Error(displayName, "Unable to open display");
++ return NULL;
++ }
++
++ scrnum = DefaultScreen(dpy);
++ root = RootWindow(dpy, scrnum);
++
++ visinfo = glXChooseVisual(dpy, scrnum, attrib);
++ if (!visinfo) {
++ Error(displayName, "Unable to find RGB, double-buffered visual");
++ return NULL;
++ }
++
++ /* window attributes */
++ xpos = (NumHeads % 10) * 100;
++ ypos = (NumHeads / 10) * 100;
++ printf("%d, %d\n", xpos, ypos);
++ attr.background_pixel = 0;
++ attr.border_pixel = 0;
++ attr.colormap = XCreateColormap(dpy, root, visinfo->visual, AllocNone);
++ attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
++ mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
++
++ win = XCreateWindow(dpy, root, xpos, ypos, width, height,
++ 0, visinfo->depth, InputOutput,
++ visinfo->visual, mask, &attr);
++ if (!win) {
++ Error(displayName, "Couldn't create window");
++ return NULL;
++ }
++
++ {
++ XSizeHints sizehints;
++ sizehints.x = xpos;
++ sizehints.y = ypos;
++ sizehints.width = width;
++ sizehints.height = height;
++ sizehints.flags = USSize | USPosition;
++ XSetNormalHints(dpy, win, &sizehints);
++ XSetStandardProperties(dpy, win, name, name,
++ None, (char **)NULL, 0, &sizehints);
++ }
++
++ if (NumHeads == 0) {
++ ctx = glXCreateContext(dpy, visinfo, NULL, True);
++ }
++ else {
++ /* share textures & dlists with 0th context */
++ printf("sharing\n");
++ ctx = glXCreateContext(dpy, visinfo, Heads[0].Context, True);
++ }
++ if (!ctx) {
++ Error(displayName, "Couldn't create GLX context");
++ return NULL;
++ }
++
++ XMapWindow(dpy, win);
++
++ if (!glXMakeCurrent(dpy, win, ctx)) {
++ Error(displayName, "glXMakeCurrent failed");
++ printf("glXMakeCurrent failed in Redraw()\n");
++ return NULL;
++ }
++
++ if (NumHeads == 0) {
++ /* create texture object now */
++ static const GLubyte checker[2][2][4] = {
++ { {255, 255, 255, 255}, { 0, 0, 0, 255} },
++ { { 0, 0, 0, 0}, {255, 255, 255, 255} }
++ };
++ glGenTextures(1, &TexObj);
++ assert(TexObj);
++ glBindTexture(GL_TEXTURE_2D, TexObj);
++ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGB,
++ GL_UNSIGNED_BYTE, checker);
++ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
++ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
++ }
++ else {
++ /* bind 0th context's texture in this context too */
++ assert(TexObj);
++ glBindTexture(GL_TEXTURE_2D, TexObj);
++ }
++ glEnable(GL_TEXTURE_2D);
++
++ /* save the info for this head */
++ {
++ struct head *h = &Heads[NumHeads];
++ const char * tmp;
++
++ if (strlen(name) + 1 > sizeof(h->DisplayName)) {
++ Error(displayName, "name string overflow");
++ return NULL;
++ }
++ strcpy(h->DisplayName, name);
++
++ h->Dpy = dpy;
++ h->Win = win;
++ h->Context = ctx;
++ h->Angle = 0.0;
++
++ tmp = (char *) glGetString(GL_VERSION);
++ if (strlen(tmp) + 1 > sizeof(h->Version)) {
++ Error(displayName, "GL_VERSION string overflow");
++ return NULL;
++ }
++ strcpy(h->Version, tmp);
++
++ tmp = (char *) glGetString(GL_VENDOR);
++ if (strlen(tmp) + 1 > sizeof(h->Vendor)) {
++ Error(displayName, "GL_VENDOR string overflow");
++ return NULL;
++ }
++ strcpy(h->Vendor, tmp);
++
++ tmp = (char *) glGetString(GL_RENDERER);
++ if (strlen(tmp) + 1 > sizeof(h->Renderer)) {
++ Error(displayName, "GL_RENDERER string overflow");
++ return NULL;
++ }
++ strcpy(h->Renderer, tmp);
++
++ NumHeads++;
++ return &Heads[NumHeads-1];
++ }
++
++}
++
++
++static void
++DestroyHeads(void)
++{
++ int i;
++ for (i = 0; i < NumHeads; i++) {
++ XDestroyWindow(Heads[i].Dpy, Heads[i].Win);
++ glXDestroyContext(Heads[i].Dpy, Heads[i].Context);
++ XCloseDisplay(Heads[i].Dpy);
++ }
++}
++
++
++static void
++Redraw(struct head *h)
++{
++ if (!glXMakeCurrent(h->Dpy, h->Win, h->Context)) {
++ Error(h->DisplayName, "glXMakeCurrent failed");
++ printf("glXMakeCurrent failed in Redraw()\n");
++ return;
++ }
++
++ h->Angle += 1.0;
++
++ glShadeModel(GL_FLAT);
++ glClearColor(0.5, 0.5, 0.5, 1.0);
++ glClear(GL_COLOR_BUFFER_BIT);
++
++ /* draw green triangle */
++ glColor3f(0.0, 1.0, 0.0);
++ glPushMatrix();
++ glRotatef(h->Angle, 0, 0, 1);
++ glBegin(GL_TRIANGLES);
++ glTexCoord2f(0.5, 1.0); glVertex2f(0, 0.8);
++ glTexCoord2f(0.0, 0.0); glVertex2f(-0.8, -0.7);
++ glTexCoord2f(1.0, 0.0); glVertex2f(0.8, -0.7);
++ glEnd();
++ glPopMatrix();
++
++ if (!SwapSeparate)
++ glXSwapBuffers(h->Dpy, h->Win);
++}
++
++
++static void
++Swap(struct head *h)
++{
++ glXSwapBuffers(h->Dpy, h->Win);
++}
++
++
++static void
++Resize(const struct head *h, unsigned int width, unsigned int height)
++{
++ if (!glXMakeCurrent(h->Dpy, h->Win, h->Context)) {
++ Error(h->DisplayName, "glXMakeCurrent failed in Resize()");
++ return;
++ }
++ glFlush();
++ glViewport(0, 0, width, height);
++ glMatrixMode(GL_PROJECTION);
++ glLoadIdentity();
++ glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
++}
++
++
++
++static void
++EventLoop(void)
++{
++ while (1) {
++ int i;
++ for (i = 0; i < NumHeads; i++) {
++ struct head *h = &Heads[i];
++ while (XPending(h->Dpy) > 0) {
++ XEvent event;
++ XNextEvent(h->Dpy, &event);
++ if (event.xany.window == h->Win) {
++ switch (event.type) {
++ case Expose:
++ Redraw(h);
++ if (SwapSeparate)
++ Swap(h);
++ break;
++ case ConfigureNotify:
++ Resize(h, event.xconfigure.width, event.xconfigure.height);
++ break;
++ case KeyPress:
++ {
++ char buf[100];
++ KeySym keySym;
++ XComposeStatus stat;
++ XLookupString(&event.xkey, buf, sizeof(buf), &keySym, &stat);
++ switch (keySym) {
++ case XK_Escape:
++ return;
++ break;
++ case XK_d:
++ case XK_D:
++ printf("Delete Texture in window %d\n", i);
++ glXMakeCurrent(h->Dpy, h->Win, h->Context);
++ glDeleteTextures(1, &TexObj);
++ break;
++ case XK_u:
++ case XK_U:
++ printf("Unbind Texture in window %d\n", i);
++ glXMakeCurrent(h->Dpy, h->Win, h->Context);
++ glBindTexture(GL_TEXTURE_2D, 0);
++ break;
++ }
++ }
++ break;
++ default:
++ /*no-op*/ ;
++ }
++ }
++ else {
++ printf("window mismatch\n");
++ }
++ }
++ }
++
++ /* redraw all windows */
++ for (i = 0; i < NumHeads; i++) {
++ Redraw(&Heads[i]);
++ }
++ /* swapbuffers on all windows, if not already done */
++ if (SwapSeparate) {
++ for (i = 0; i < NumHeads; i++) {
++ Swap(&Heads[i]);
++ }
++ }
++ usleep(1);
++ }
++}
++
++
++
++static void
++PrintInfo(const struct head *h)
++{
++ printf("Name: %s\n", h->DisplayName);
++ printf(" Display: %p\n", (void *) h->Dpy);
++ printf(" Window: 0x%x\n", (int) h->Win);
++ printf(" Context: 0x%lx\n", (long) h->Context);
++ printf(" GL_VERSION: %s\n", h->Version);
++ printf(" GL_VENDOR: %s\n", h->Vendor);
++ printf(" GL_RENDERER: %s\n", h->Renderer);
++}
++
++
++int
++main(int argc, char *argv[])
++{
++ char *dpyName = NULL;
++ int i;
++
++ if (argc == 1) {
++ printf("manywin: open N simultaneous glx windows\n");
++ printf("Usage:\n");
++ printf(" manywin [-s] numWindows\n");
++ printf("Options:\n");
++ printf(" -s = swap immediately after drawing (see src code)\n");
++ printf("Example:\n");
++ printf(" manywin 10\n");
++ return 0;
++ }
++ else {
++ int n = 3;
++ for (i = 1; i < argc; i++) {
++ if (strcmp(argv[i], "-s") == 0) {
++ SwapSeparate = GL_FALSE;
++ }
++ else if (strcmp(argv[i], "-display") == 0 && i < argc) {
++ dpyName = argv[i+1];
++ i++;
++ }
++ else {
++ n = atoi(argv[i]);
++ }
++ }
++ if (n < 1)
++ n = 1;
++ if (n > MAX_HEADS)
++ n = MAX_HEADS;
++
++ printf("%d windows\n", n);
++ for (i = 0; i < n; i++) {
++ char name[100];
++ struct head *h;
++ sprintf(name, "%d", i);
++ h = AddHead(dpyName, name);
++ if (h) {
++ PrintInfo(h);
++ }
++ }
++ }
++
++ EventLoop();
++ DestroyHeads();
++ return 0;
++}
+diff -Naurp Mesa-7.8.1/progs/xdemos/msctest.c Mesa-7.8.1.patched/progs/xdemos/msctest.c
+--- Mesa-7.8.1/progs/xdemos/msctest.c 1970-01-01 01:00:00.000000000 +0100
++++ Mesa-7.8.1.patched/progs/xdemos/msctest.c 2010-06-13 13:45:06.789793146 +0200
+@@ -0,0 +1,195 @@
++/*
++ * Copyright © 2009 Intel Corporation
++ *
++ * 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 (including the next
++ * paragraph) 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:
++ * Jesse Barnes <jesse.barnes@intel.com>
++ *
++ */
++
++/** @file msctest.c
++ * Simple test for MSC functionality.
++ */
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <unistd.h>
++#include <GL/gl.h>
++#include <GL/glu.h>
++#include <GL/glx.h>
++#include <GL/glxext.h>
++#include <X11/X.h>
++#include <X11/Xlib.h>
++#include <X11/Xutil.h>
++
++void (*get_sync_values)(Display *dpy, Window winGL, int64_t *ust, int64_t *msc, int64_t *sbc);
++void (*wait_sync)(Display *dpy, Window winGL, int64_t target_msc, int64_t divisor, int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc);
++
++static int GLXExtensionSupported(Display *dpy, const char *extension)
++{
++ const char *extensionsString, *pos;
++
++ extensionsString = glXQueryExtensionsString(dpy, DefaultScreen(dpy));
++
++ pos = strstr(extensionsString, extension);
++
++ if (pos != NULL && (pos == extensionsString || pos[-1] == ' ') &&
++ (pos[strlen(extension)] == ' ' || pos[strlen(extension)] == '\0'))
++ return 1;
++
++ return 0;
++}
++
++extern char *optarg;
++extern int optind, opterr, optopt;
++static char optstr[] = "v";
++
++static void usage(char *name)
++{
++ printf("usage: %s\n", name);
++ exit(-1);
++}
++
++int main(int argc, char *argv[])
++{
++ Display *disp;
++ XVisualInfo *pvi;
++ XSetWindowAttributes swa;
++ int attrib[14];
++ Window winGL;
++ GLXContext context;
++ int dummy;
++ Atom wmDelete;
++ int verbose = 0, width = 200, height = 200;
++ int c, i = 1;
++ int64_t ust, msc, sbc;
++
++ opterr = 0;
++ while ((c = getopt(argc, argv, optstr)) != -1) {
++ switch (c) {
++ case 'v':
++ verbose = 1;
++ break;
++ default:
++ usage(argv[0]);
++ break;
++ }
++ }
++
++ disp = XOpenDisplay(NULL);
++ if (!disp) {
++ fprintf(stderr, "failed to open display\n");
++ return -1;
++ }
++
++ if (!glXQueryExtension(disp, &dummy, &dummy)) {
++ fprintf(stderr, "glXQueryExtension failed\n");
++ return -1;
++ }
++
++ if (!GLXExtensionSupported(disp, "GLX_OML_sync_control")) {
++ fprintf(stderr, "GLX_OML_sync_control not supported, exiting\n");
++ return -1;
++ }
++
++ attrib[0] = GLX_RGBA;
++ attrib[1] = 1;
++ attrib[2] = GLX_RED_SIZE;
++ attrib[3] = 1;
++ attrib[4] = GLX_GREEN_SIZE;
++ attrib[5] = 1;
++ attrib[6] = GLX_BLUE_SIZE;
++ attrib[7] = 1;
++ attrib[8] = GLX_DOUBLEBUFFER;
++ attrib[9] = 1;
++ attrib[10] = None;
++
++ pvi = glXChooseVisual(disp, DefaultScreen(disp), attrib);
++ if (!pvi) {
++ fprintf(stderr, "failed to choose visual, exiting\n");
++ return -1;
++ }
++
++ context = glXCreateContext(disp, pvi, None, GL_TRUE);
++ if (!context) {
++ fprintf(stderr, "failed to create glx context\n");
++ return -1;
++ }
++
++ pvi->screen = DefaultScreen(disp);
++
++ swa.colormap = XCreateColormap(disp, RootWindow(disp, pvi->screen),
++ pvi->visual, AllocNone);
++ swa.border_pixel = 0;
++ swa.event_mask = ExposureMask | KeyPressMask | ButtonPressMask |
++ StructureNotifyMask;
++ winGL = XCreateWindow(disp, RootWindow(disp, pvi->screen),
++ 0, 0,
++ width, height,
++ 0, pvi->depth, InputOutput, pvi->visual,
++ CWBorderPixel | CWColormap | CWEventMask, &swa);
++ if (!winGL) {
++ fprintf(stderr, "window creation failed\n");
++ return -1;
++ }
++ wmDelete = XInternAtom(disp, "WM_DELETE_WINDOW", True);
++ XSetWMProtocols(disp, winGL, &wmDelete, 1);
++
++ XSetStandardProperties(disp, winGL, "msc test", "msc text",
++ None, NULL, 0, NULL);
++
++ XMapRaised(disp, winGL);
++
++ glXMakeCurrent(disp, winGL, context);
++
++ get_sync_values = (void *)glXGetProcAddress((unsigned char *)"glXGetSyncValuesOML");
++ wait_sync = (void *)glXGetProcAddress((unsigned char *)"glXWaitForMscOML");
++
++ if (!get_sync_values || !wait_sync) {
++ fprintf(stderr, "failed to get sync values function\n");
++ return -1;
++ }
++
++ while (i++) {
++ get_sync_values(disp, winGL, &ust, &msc, &sbc);
++ fprintf(stderr, "ust: %llu, msc: %llu, sbc: %llu\n", ust, msc,
++ sbc);
++
++ /* Alternate colors to make tearing obvious */
++ if (i & 1)
++ glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
++ else
++ glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
++ glClear(GL_COLOR_BUFFER_BIT);
++ glXSwapBuffers(disp, winGL);
++ wait_sync(disp, winGL, 0, 60, 0, &ust, &msc, &sbc);
++ fprintf(stderr,
++ "wait returned ust: %llu, msc: %llu, sbc: %llu\n",
++ ust, msc, sbc);
++ sleep(1);
++ }
++
++ XDestroyWindow(disp, winGL);
++ glXDestroyContext(disp, context);
++ XCloseDisplay(disp);
++
++ return 0;
++}
+diff -Naurp Mesa-7.8.1/progs/xdemos/multictx.c Mesa-7.8.1.patched/progs/xdemos/multictx.c
+--- Mesa-7.8.1/progs/xdemos/multictx.c 1970-01-01 01:00:00.000000000 +0100
++++ Mesa-7.8.1.patched/progs/xdemos/multictx.c 2010-06-13 13:45:06.789793146 +0200
+@@ -0,0 +1,585 @@
++/*
++ * Copyright (C) 2009 VMware, Inc. 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.
++ */
++
++/*
++ * Test rendering with two contexts into one window.
++ * Setup different rendering state for each context to check that
++ * context switching is handled properly.
++ *
++ * Brian Paul
++ * 6 Aug 2009
++ */
++
++
++#include <math.h>
++#include <stdlib.h>
++#include <stdio.h>
++#include <string.h>
++#include <sys/time.h>
++#include <unistd.h>
++#include <X11/Xlib.h>
++#include <X11/keysym.h>
++#include <GL/gl.h>
++#include <GL/glx.h>
++
++
++
++#ifndef M_PI
++#define M_PI 3.14159265
++#endif
++
++
++/** Event handler results: */
++#define NOP 0
++#define EXIT 1
++#define DRAW 2
++
++static GLfloat view_rotx = 0.0, view_roty = 210.0, view_rotz = 0.0;
++static GLint gear1, gear2;
++static GLfloat angle = 0.0;
++
++static GLboolean animate = GL_TRUE; /* Animation */
++
++
++static double
++current_time(void)
++{
++ struct timeval tv;
++#ifdef __VMS
++ (void) gettimeofday(&tv, NULL );
++#else
++ struct timezone tz;
++ (void) gettimeofday(&tv, &tz);
++#endif
++ return (double) tv.tv_sec + tv.tv_usec / 1000000.0;
++}
++
++
++/*
++ *
++ * Draw a gear wheel. You'll probably want to call this function when
++ * building a display list since we do a lot of trig here.
++ *
++ * Input: 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
++gear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width,
++ GLint teeth, GLfloat tooth_depth)
++{
++ GLint i;
++ GLfloat r0, r1, r2;
++ GLfloat angle, da;
++ GLfloat u, v, len;
++
++ r0 = inner_radius;
++ r1 = outer_radius - tooth_depth / 2.0;
++ r2 = outer_radius + tooth_depth / 2.0;
++
++ da = 2.0 * M_PI / teeth / 4.0;
++
++ glShadeModel(GL_FLAT);
++
++ glNormal3f(0.0, 0.0, 1.0);
++
++ /* draw front face */
++ glBegin(GL_QUAD_STRIP);
++ for (i = 0; i <= teeth; i++) {
++ angle = i * 2.0 * M_PI / teeth;
++ glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
++ glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
++ if (i < teeth) {
++ glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
++ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
++ width * 0.5);
++ }
++ }
++ glEnd();
++
++ /* draw front sides of teeth */
++ glBegin(GL_QUADS);
++ da = 2.0 * M_PI / teeth / 4.0;
++ for (i = 0; i < teeth; i++) {
++ angle = i * 2.0 * M_PI / teeth;
++
++ glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
++ glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
++ glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
++ width * 0.5);
++ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
++ width * 0.5);
++ }
++ glEnd();
++
++ glNormal3f(0.0, 0.0, -1.0);
++
++ /* draw back face */
++ glBegin(GL_QUAD_STRIP);
++ for (i = 0; i <= teeth; i++) {
++ angle = i * 2.0 * M_PI / teeth;
++ glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
++ glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
++ if (i < teeth) {
++ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
++ -width * 0.5);
++ glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
++ }
++ }
++ glEnd();
++
++ /* draw back sides of teeth */
++ glBegin(GL_QUADS);
++ da = 2.0 * M_PI / teeth / 4.0;
++ for (i = 0; i < teeth; i++) {
++ angle = i * 2.0 * M_PI / teeth;
++
++ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
++ -width * 0.5);
++ glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
++ -width * 0.5);
++ glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
++ glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
++ }
++ glEnd();
++
++ /* draw outward faces of teeth */
++ glBegin(GL_QUAD_STRIP);
++ for (i = 0; i < teeth; i++) {
++ angle = i * 2.0 * M_PI / teeth;
++
++ glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
++ glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
++ u = r2 * cos(angle + da) - r1 * cos(angle);
++ v = r2 * sin(angle + da) - r1 * sin(angle);
++ len = sqrt(u * u + v * v);
++ u /= len;
++ v /= len;
++ glNormal3f(v, -u, 0.0);
++ glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
++ glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
++ glNormal3f(cos(angle), sin(angle), 0.0);
++ glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
++ width * 0.5);
++ glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
++ -width * 0.5);
++ u = r1 * cos(angle + 3 * da) - r2 * cos(angle + 2 * da);
++ v = r1 * sin(angle + 3 * da) - r2 * sin(angle + 2 * da);
++ glNormal3f(v, -u, 0.0);
++ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
++ width * 0.5);
++ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
++ -width * 0.5);
++ glNormal3f(cos(angle), sin(angle), 0.0);
++ }
++
++ glVertex3f(r1 * cos(0), r1 * sin(0), width * 0.5);
++ glVertex3f(r1 * cos(0), r1 * sin(0), -width * 0.5);
++
++ glEnd();
++
++ glShadeModel(GL_SMOOTH);
++
++ /* draw inside radius cylinder */
++ glBegin(GL_QUAD_STRIP);
++ for (i = 0; i <= teeth; i++) {
++ angle = i * 2.0 * M_PI / teeth;
++ glNormal3f(-cos(angle), -sin(angle), 0.0);
++ glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
++ glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
++ }
++ glEnd();
++}
++
++
++static void
++draw(int ctx)
++{
++ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
++
++ glPushMatrix();
++ glRotatef(view_rotx, 1.0, 0.0, 0.0);
++ glRotatef(view_roty + angle, 0.0, 1.0, 0.0);
++ glRotatef(view_rotz, 0.0, 0.0, 1.0);
++
++ if (ctx == 0) {
++ glDisable(GL_CULL_FACE);
++ glPushMatrix();
++ glRotatef(angle, 0.0, 0.0, 1.0);
++ glCallList(gear1);
++ glPopMatrix();
++ /* This should not effect the other context's rendering */
++ glEnable(GL_CULL_FACE);
++ glCullFace(GL_FRONT_AND_BACK);
++ }
++ else {
++ glPushMatrix();
++ glRotatef(-2.0 * angle - 9.0, 0.0, 0.0, 1.0);
++ glCallList(gear2);
++ glPopMatrix();
++ }
++
++ glPopMatrix();
++
++ /* this flush is important since we'll be switching contexts next */
++ glFlush();
++}
++
++
++
++static void
++draw_frame(Display *dpy, Window win, GLXContext ctx1, GLXContext ctx2)
++{
++ static double tRot0 = -1.0;
++ double dt, t = current_time();
++
++ if (tRot0 < 0.0)
++ tRot0 = t;
++ dt = t - tRot0;
++ tRot0 = t;
++
++ if (animate) {
++ /* advance rotation for next frame */
++ angle += 70.0 * dt; /* 70 degrees per second */
++ if (angle > 3600.0)
++ angle -= 3600.0;
++ }
++
++ glXMakeCurrent(dpy, (GLXDrawable) win, ctx1);
++ draw(0);
++
++ glXMakeCurrent(dpy, (GLXDrawable) win, ctx2);
++ draw(1);
++
++ glXSwapBuffers(dpy, win);
++}
++
++
++/* new window size or exposure */
++static void
++reshape(Display *dpy, Window win,
++ GLXContext ctx1, GLXContext ctx2, int width, int height)
++{
++ int i;
++
++ width /= 2;
++
++ /* loop: left half of window, right half of window */
++ for (i = 0; i < 2; i++) {
++ if (i == 0)
++ glXMakeCurrent(dpy, win, ctx1);
++ else
++ glXMakeCurrent(dpy, win, ctx2);
++
++ glViewport(width * i, 0, width, height);
++ glScissor(width * i, 0, width, height);
++
++ {
++ GLfloat h = (GLfloat) height / (GLfloat) width;
++
++ glMatrixMode(GL_PROJECTION);
++ glLoadIdentity();
++ glFrustum(-1.0, 1.0, -h, h, 5.0, 60.0);
++ }
++
++ glMatrixMode(GL_MODELVIEW);
++ glLoadIdentity();
++ glTranslatef(0.0, 0.0, -30.0);
++ }
++}
++
++
++
++static void
++init(Display *dpy, Window win, GLXContext ctx1, GLXContext ctx2)
++{
++ static GLfloat pos[4] = { 5.0, 5.0, 10.0, 0.0 };
++ static GLfloat red[4] = { 0.8, 0.1, 0.0, 1.0 };
++ static GLfloat green[4] = { 0.0, 0.8, 0.2, 0.5 };
++ /*static GLfloat blue[4] = { 0.2, 0.2, 1.0, 1.0 };*/
++
++ /* first ctx */
++ {
++ static GLuint stipple[32] = {
++ 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff,
++ 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff,
++
++ 0xff00ff00, 0xff00ff00, 0xff00ff00, 0xff00ff00,
++ 0xff00ff00, 0xff00ff00, 0xff00ff00, 0xff00ff00,
++
++ 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff,
++ 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff,
++
++ 0xff00ff00, 0xff00ff00, 0xff00ff00, 0xff00ff00,
++ 0xff00ff00, 0xff00ff00, 0xff00ff00, 0xff00ff00
++ };
++
++ glXMakeCurrent(dpy, win, ctx1);
++
++ glLightfv(GL_LIGHT0, GL_POSITION, pos);
++ glEnable(GL_LIGHTING);
++ glEnable(GL_LIGHT0);
++ glEnable(GL_DEPTH_TEST);
++
++ gear1 = glGenLists(1);
++ glNewList(gear1, GL_COMPILE);
++ glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red);
++ gear(1.0, 4.0, 1.0, 20, 0.7);
++ glEndList();
++
++ glEnable(GL_NORMALIZE);
++ glEnable(GL_SCISSOR_TEST);
++ glClearColor(0.4, 0.4, 0.4, 1.0);
++
++ glPolygonStipple((GLubyte *) stipple);
++ glEnable(GL_POLYGON_STIPPLE);
++ }
++
++ /* second ctx */
++ {
++ glXMakeCurrent(dpy, win, ctx2);
++
++ glLightfv(GL_LIGHT0, GL_POSITION, pos);
++ glEnable(GL_LIGHTING);
++ glEnable(GL_LIGHT0);
++ glEnable(GL_DEPTH_TEST);
++
++ gear2 = glGenLists(1);
++ glNewList(gear2, GL_COMPILE);
++ glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green);
++ gear(1.5, 3.0, 1.5, 16, 0.7);
++ glEndList();
++
++ glEnable(GL_NORMALIZE);
++ glEnable(GL_SCISSOR_TEST);
++ glClearColor(0.6, 0.6, 0.6, 1.0);
++
++ glEnable(GL_BLEND);
++ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
++ }
++}
++
++
++/**
++ * Create an RGB, double-buffered window.
++ * Return the window and two context handles.
++ */
++static void
++make_window_and_contexts( Display *dpy, const char *name,
++ int x, int y, int width, int height,
++ Window *winRet,
++ GLXContext *ctxRet1,
++ GLXContext *ctxRet2)
++{
++ int attribs[] = { GLX_RGBA,
++ GLX_RED_SIZE, 1,
++ GLX_GREEN_SIZE, 1,
++ GLX_BLUE_SIZE, 1,
++ GLX_DOUBLEBUFFER,
++ GLX_DEPTH_SIZE, 1,
++ None };
++ int scrnum;
++ XSetWindowAttributes attr;
++ unsigned long mask;
++ Window root;
++ Window win;
++ XVisualInfo *visinfo;
++
++ scrnum = DefaultScreen( dpy );
++ root = RootWindow( dpy, scrnum );
++
++ visinfo = glXChooseVisual( dpy, scrnum, attribs );
++ if (!visinfo) {
++ printf("Error: couldn't get an RGB, Double-buffered visual\n");
++ exit(1);
++ }
++
++ /* window attributes */
++ attr.background_pixel = 0;
++ attr.border_pixel = 0;
++ attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone);
++ attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
++ mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
++
++ win = XCreateWindow( dpy, root, x, y, width, 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(dpy, win, &sizehints);
++ XSetStandardProperties(dpy, win, name, name,
++ None, (char **)NULL, 0, &sizehints);
++ }
++
++ *winRet = win;
++ *ctxRet1 = glXCreateContext( dpy, visinfo, NULL, True );
++ *ctxRet2 = glXCreateContext( dpy, visinfo, NULL, True );
++
++ if (!*ctxRet1 || !*ctxRet2) {
++ printf("Error: glXCreateContext failed\n");
++ exit(1);
++ }
++
++ XFree(visinfo);
++}
++
++
++/**
++ * Handle one X event.
++ * \return NOP, EXIT or DRAW
++ */
++static int
++handle_event(Display *dpy, Window win, GLXContext ctx1, GLXContext ctx2,
++ XEvent *event)
++{
++ (void) dpy;
++ (void) win;
++
++ switch (event->type) {
++ case Expose:
++ return DRAW;
++ case ConfigureNotify:
++ reshape(dpy, win, ctx1, ctx2,
++ event->xconfigure.width, event->xconfigure.height);
++ break;
++ case KeyPress:
++ {
++ char buffer[10];
++ int r, code;
++ code = XLookupKeysym(&event->xkey, 0);
++ if (code == XK_Left) {
++ view_roty += 5.0;
++ }
++ else if (code == XK_Right) {
++ view_roty -= 5.0;
++ }
++ else if (code == XK_Up) {
++ view_rotx += 5.0;
++ }
++ else if (code == XK_Down) {
++ view_rotx -= 5.0;
++ }
++ else {
++ r = XLookupString(&event->xkey, buffer, sizeof(buffer),
++ NULL, NULL);
++ if (buffer[0] == 27) {
++ /* escape */
++ return EXIT;
++ }
++ else if (buffer[0] == 'a' || buffer[0] == 'A') {
++ animate = !animate;
++ }
++ }
++ return DRAW;
++ }
++ }
++ return NOP;
++}
++
++
++static void
++event_loop(Display *dpy, Window win, GLXContext ctx1, GLXContext ctx2)
++{
++ while (1) {
++ int op;
++ while (!animate || XPending(dpy) > 0) {
++ XEvent event;
++ XNextEvent(dpy, &event);
++ op = handle_event(dpy, win, ctx1, ctx2, &event);
++ if (op == EXIT)
++ return;
++ else if (op == DRAW)
++ break;
++ }
++
++ draw_frame(dpy, win, ctx1, ctx2);
++ }
++}
++
++
++int
++main(int argc, char *argv[])
++{
++ unsigned int winWidth = 800, winHeight = 400;
++ int x = 0, y = 0;
++ Display *dpy;
++ Window win;
++ GLXContext ctx1, ctx2;
++ char *dpyName = NULL;
++ GLboolean printInfo = GL_FALSE;
++ int i;
++
++ for (i = 1; i < argc; i++) {
++ if (strcmp(argv[i], "-display") == 0) {
++ dpyName = argv[i+1];
++ i++;
++ }
++ else {
++ return 1;
++ }
++ }
++
++ dpy = XOpenDisplay(dpyName);
++ if (!dpy) {
++ printf("Error: couldn't open display %s\n",
++ dpyName ? dpyName : getenv("DISPLAY"));
++ return -1;
++ }
++
++ make_window_and_contexts(dpy, "multictx", x, y, winWidth, winHeight,
++ &win, &ctx1, &ctx2);
++ XMapWindow(dpy, win);
++
++ 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));
++ }
++
++ init(dpy, win, ctx1, ctx2);
++
++ /* Set initial projection/viewing transformation.
++ * We can't be sure we'll get a ConfigureNotify event when the window
++ * first appears.
++ */
++ reshape(dpy, win, ctx1, ctx2, winWidth, winHeight);
++
++ event_loop(dpy, win, ctx1, ctx2);
++
++ glDeleteLists(gear1, 1);
++ glDeleteLists(gear2, 1);
++ glXDestroyContext(dpy, ctx1);
++ glXDestroyContext(dpy, ctx2);
++ XDestroyWindow(dpy, win);
++ XCloseDisplay(dpy);
++
++ return 0;
++}
+diff -Naurp Mesa-7.8.1/progs/xdemos/offset.c Mesa-7.8.1.patched/progs/xdemos/offset.c
+--- Mesa-7.8.1/progs/xdemos/offset.c 1970-01-01 01:00:00.000000000 +0100
++++ Mesa-7.8.1.patched/progs/xdemos/offset.c 2010-06-13 13:45:06.789793146 +0200
+@@ -0,0 +1,343 @@
++/****************************************************************************
++Copyright 1995 by Silicon Graphics Incorporated, Mountain View, California.
++
++ All Rights Reserved
++
++Permission to use, copy, modify, and distribute this software and its
++documentation for any purpose and without fee is hereby granted,
++provided that the above copyright notice appear in all copies and that
++both that copyright notice and this permission notice appear in
++supporting documentation, and that the name of Silicon Graphics not be
++used in advertising or publicity pertaining to distribution of the
++software without specific, written prior permission.
++
++SILICON GRAPHICS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
++INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
++EVENT SHALL SILICON GRAPHICS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
++CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
++USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
++OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
++PERFORMANCE OF THIS SOFTWARE.
++
++****************************************************************************/
++
++/*
++ * Derived from code written by Kurt Akeley, November 1992
++ *
++ * Uses PolygonOffset to draw hidden-line images. PolygonOffset
++ * shifts the z values of polygons an amount that is
++ * proportional to their slope in screen z. This keeps
++ * the lines, which are drawn without displacement, from
++ * interacting with their respective polygons, and
++ * thus eliminates line dropouts.
++ *
++ * The left image shows an ordinary antialiased wireframe image.
++ * The center image shows an antialiased hidden-line image without
++ * PolygonOffset.
++ * The right image shows an antialiased hidden-line image using
++ * PolygonOffset to reduce artifacts.
++ *
++ * Drag with a mouse button pressed to rotate the models.
++ * Press the escape key to exit.
++ */
++
++/*
++ * Modified for OpenGL 1.1 glPolygonOffset() conventions
++ */
++
++
++#include <GL/glx.h>
++#include <X11/keysym.h>
++#include <stdlib.h>
++#include <stdio.h>
++#include <string.h>
++
++#undef GL_EXT_polygon_offset /* use GL 1.1 version instead of extension */
++
++
++#ifndef EXIT_FAILURE
++# define EXIT_FAILURE 1
++#endif
++#ifndef EXIT_SUCCESS
++# define EXIT_SUCCESS 0
++#endif
++
++#define MAXQUAD 6
++
++typedef float Vertex[3];
++
++typedef Vertex Quad[4];
++
++/* data to define the six faces of a unit cube */
++Quad quads[MAXQUAD] = {
++ { {0,0,0}, {0,0,1}, {0,1,1}, {0,1,0} }, /* x = 0 */
++ { {0,0,0}, {1,0,0}, {1,0,1}, {0,0,1} }, /* y = 0 */
++ { {0,0,0}, {1,0,0}, {1,1,0}, {0,1,0} }, /* z = 0 */
++ { {1,0,0}, {1,0,1}, {1,1,1}, {1,1,0} }, /* x = 1 */
++ { {0,1,0}, {1,1,0}, {1,1,1}, {0,1,1} }, /* y = 1 */
++ { {0,0,1}, {1,0,1}, {1,1,1}, {0,1,1} } /* z = 1 */
++};
++
++#define WIREFRAME 0
++#define HIDDEN_LINE 1
++
++static void error(const char* prog, const char* msg);
++static void cubes(int mx, int my, int mode);
++static void fill(Quad quad);
++static void outline(Quad quad);
++static void draw_hidden(Quad quad, int mode, int face);
++static void process_input(Display *dpy, Window win);
++static int query_extension(char* extName);
++
++static int attributeList[] = { GLX_RGBA, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1,
++ GLX_BLUE_SIZE, 1, GLX_DOUBLEBUFFER, GLX_DEPTH_SIZE, 1, None };
++
++static int dimension = 3;
++
++static float Scale = 1.0;
++
++
++int main(int argc, char** argv) {
++ Display *dpy;
++ XVisualInfo *vi;
++ XSetWindowAttributes swa;
++ Window win;
++ GLXContext cx;
++ GLint z;
++
++ dpy = XOpenDisplay(0);
++ if (!dpy) error(argv[0], "can't open display");
++
++ vi = glXChooseVisual(dpy, DefaultScreen(dpy), attributeList);
++ if (!vi) error(argv[0], "no suitable visual");
++
++ cx = glXCreateContext(dpy, vi, 0, GL_TRUE);
++
++ swa.colormap = XCreateColormap(dpy, RootWindow(dpy, vi->screen),
++ vi->visual, AllocNone);
++
++ swa.border_pixel = 0;
++ swa.event_mask = ExposureMask | StructureNotifyMask | KeyPressMask |
++ ButtonPressMask | ButtonMotionMask;
++ win = XCreateWindow(dpy, RootWindow(dpy, vi->screen), 0, 0, 900, 300,
++ 0, vi->depth, InputOutput, vi->visual,
++ CWBorderPixel|CWColormap|CWEventMask, &swa);
++ XStoreName(dpy, win, "hiddenline");
++ XMapWindow(dpy, win);
++
++ glXMakeCurrent(dpy, win, cx);
++
++ /* check for the polygon offset extension */
++#ifndef GL_VERSION_1_1
++ if (!query_extension("GL_EXT_polygon_offset"))
++ error(argv[0], "polygon_offset extension is not available");
++#else
++ (void) query_extension;
++#endif
++
++ /* set up viewing parameters */
++ glMatrixMode(GL_PROJECTION);
++ glFrustum(-1, 1, -1, 1, 6, 20);
++ glMatrixMode(GL_MODELVIEW);
++ glTranslatef(0, 0, -15);
++
++ /* set other relevant state information */
++ glEnable(GL_DEPTH_TEST);
++
++ glGetIntegerv(GL_DEPTH_BITS, &z);
++ printf("GL_DEPTH_BITS = %d\n", z);
++
++#ifdef GL_EXT_polygon_offset
++ printf("using 1.0 offset extension\n");
++ glPolygonOffsetEXT( 1.0, 0.00001 );
++#else
++ printf("using 1.1 offset\n");
++ glPolygonOffset( 1.0, 0.5 );
++#endif
++
++ glShadeModel( GL_FLAT );
++ glDisable( GL_DITHER );
++
++ /* process events until the user presses ESC */
++ while (1) process_input(dpy, win);
++
++ return 0;
++}
++
++static void
++draw_scene(int mx, int my) {
++ glClearColor(0.25, 0.25, 0.25, 0);
++ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
++
++ glPushMatrix();
++ glTranslatef(-1.7, 0.0, 0.0);
++ cubes(mx, my, WIREFRAME);
++ glPopMatrix();
++
++ glPushMatrix();
++ cubes(mx, my, HIDDEN_LINE);
++ glPopMatrix();
++
++ glPushMatrix();
++ glTranslatef(1.7, 0.0, 0.0);
++#ifdef GL_EXT_polygon_offset
++ glEnable(GL_POLYGON_OFFSET_EXT);
++#else
++ glEnable(GL_POLYGON_OFFSET_FILL);
++#endif
++ glScalef(Scale, Scale, Scale);
++ cubes(mx, my, HIDDEN_LINE);
++#ifdef GL_EXT_polygon_offset
++ glDisable(GL_POLYGON_OFFSET_EXT);
++#else
++ glDisable(GL_POLYGON_OFFSET_FILL);
++#endif
++ glPopMatrix();
++}
++
++
++static void
++cubes(int mx, int my, int mode) {
++ int x, y, z, i;
++
++ /* track the mouse */
++ glRotatef(mx / 2.0, 0, 1, 0);
++ glRotatef(my / 2.0, 1, 0, 0);
++
++ /* draw the lines as hidden polygons */
++ glTranslatef(-0.5, -0.5, -0.5);
++ glScalef(1.0/dimension, 1.0/dimension, 1.0/dimension);
++ for (z = 0; z < dimension; z++) {
++ for (y = 0; y < dimension; y++) {
++ for (x = 0; x < dimension; x++) {
++ glPushMatrix();
++ glTranslatef(x, y, z);
++ glScalef(0.8, 0.8, 0.8);
++ for (i = 0; i < MAXQUAD; i++)
++ draw_hidden(quads[i], mode, i);
++ glPopMatrix();
++ }
++ }
++ }
++}
++
++static void
++fill(Quad quad) {
++ /* draw a filled polygon */
++ glBegin(GL_QUADS);
++ glVertex3fv(quad[0]);
++ glVertex3fv(quad[1]);
++ glVertex3fv(quad[2]);
++ glVertex3fv(quad[3]);
++ glEnd();
++}
++
++static void
++outline(Quad quad) {
++ /* draw an outlined polygon */
++ glBegin(GL_LINE_LOOP);
++ glVertex3fv(quad[0]);
++ glVertex3fv(quad[1]);
++ glVertex3fv(quad[2]);
++ glVertex3fv(quad[3]);
++ glEnd();
++}
++
++static void
++draw_hidden(Quad quad, int mode, int face) {
++ static const GLfloat colors[3][3] = {
++ {0.5, 0.5, 0.0},
++ {0.8, 0.5, 0.0},
++ {0.0, 0.5, 0.8}
++ };
++ if (mode == HIDDEN_LINE) {
++ glColor3fv(colors[face % 3]);
++ fill(quad);
++ }
++
++ /* draw the outline using white */
++ glColor3f(1, 1, 1);
++ outline(quad);
++}
++
++static void
++process_input(Display *dpy, Window win) {
++ XEvent event;
++ static int prevx, prevy;
++ static int deltax = 90, deltay = 40;
++
++ do {
++ char buf[31];
++ KeySym keysym;
++
++ XNextEvent(dpy, &event);
++ switch(event.type) {
++ case Expose:
++ break;
++ case ConfigureNotify: {
++ /* this approach preserves a 1:1 viewport aspect ratio */
++ int vX, vY, vW, vH;
++ int eW = event.xconfigure.width, eH = event.xconfigure.height;
++ if (eW >= eH) {
++ vX = 0;
++ vY = (eH - eW) >> 1;
++ vW = vH = eW;
++ } else {
++ vX = (eW - eH) >> 1;
++ vY = 0;
++ vW = vH = eH;
++ }
++ glViewport(vX, vY, vW, vH);
++ }
++ break;
++ case KeyPress:
++ (void) XLookupString(&event.xkey, buf, sizeof(buf), &keysym, NULL);
++ switch (keysym) {
++ case 'Z':
++ Scale *= 1.1;
++ break;
++ case 'z':
++ Scale *= 0.9;
++ break;
++ case XK_Escape:
++ exit(EXIT_SUCCESS);
++ default:
++ break;
++ }
++ break;
++ case ButtonPress:
++ prevx = event.xbutton.x;
++ prevy = event.xbutton.y;
++ break;
++ case MotionNotify:
++ deltax += (event.xbutton.x - prevx); prevx = event.xbutton.x;
++ deltay += (event.xbutton.y - prevy); prevy = event.xbutton.y;
++ break;
++ default:
++ break;
++ }
++ } while (XPending(dpy));
++
++ draw_scene(deltax, deltay);
++ glXSwapBuffers(dpy, win);
++}
++
++static void
++error(const char *prog, const char *msg) {
++ fprintf(stderr, "%s: %s\n", prog, msg);
++ exit(EXIT_FAILURE);
++}
++
++static int
++query_extension(char* extName) {
++ char *p = (char *) glGetString(GL_EXTENSIONS);
++ char *end = p + strlen(p);
++ while (p < end) {
++ int n = strcspn(p, " ");
++ if ((strlen(extName) == n) && (strncmp(extName, p, n) == 0))
++ return GL_TRUE;
++ p += (n + 1);
++ }
++ return GL_FALSE;
++}
++
+diff -Naurp Mesa-7.8.1/progs/xdemos/omlsync.c Mesa-7.8.1.patched/progs/xdemos/omlsync.c
+--- Mesa-7.8.1/progs/xdemos/omlsync.c 1970-01-01 01:00:00.000000000 +0100
++++ Mesa-7.8.1.patched/progs/xdemos/omlsync.c 2010-06-13 13:45:06.788792936 +0200
+@@ -0,0 +1,265 @@
++/*
++ * Copyright © 2007-2010 Intel Corporation
++ *
++ * 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 (including the next
++ * paragraph) 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:
++ * Jesse Barnes <jesse.barnes@intel.com>
++ *
++ */
++
++/** @file omlsync.c
++ * The program is simple: it paints a window alternating colors (red &
++ * white) either as fast as possible or synchronized to vblank events
++ *
++ * If run normally, the program should display a window that exhibits
++ * significant tearing between red and white colors (e.g. you might get
++ * a "waterfall" effect of red and white horizontal bars).
++ *
++ * If run with the '-s b' option, the program should synchronize the
++ * window color changes with the vertical blank period, resulting in a
++ * window that looks orangish with a high frequency flicker (which may
++ * be invisible). If the window is moved to another screen, this
++ * property should be preserved. If the window spans two screens, it
++ * shouldn't tear on whichever screen most of the window is on; the
++ * portion on the other screen may show some tearing (like the
++ * waterfall effect above).
++ *
++ * Other options include '-w <width>' and '-h <height>' to set the
++ * window size.
++ */
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <unistd.h>
++#include <GL/gl.h>
++#include <GL/glu.h>
++#include <GL/glx.h>
++#include <GL/glxext.h>
++#include <X11/X.h>
++#include <X11/Xlib.h>
++#include <X11/Xutil.h>
++
++Bool (*glXGetSyncValuesOML)(Display *dpy, GLXDrawable drawable,
++ int64_t *ust, int64_t *msc, int64_t *sbc);
++Bool (*glXGetMscRateOML)(Display *dpy, GLXDrawable drawable, int32_t *numerator,
++ int32_t *denominator);
++int64_t (*glXSwapBuffersMscOML)(Display *dpy, GLXDrawable drawable,
++ int64_t target_msc, int64_t divisor,
++ int64_t remainder);
++Bool (*glXWaitForMscOML)(Display *dpy, GLXDrawable drawable, int64_t target_msc,
++ int64_t divisor, int64_t remainder, int64_t *ust,
++ int64_t *msc, int64_t *sbc);
++Bool (*glXWaitForSbcOML)(Display *dpy, GLXDrawable drawable, int64_t target_sbc,
++ int64_t *ust, int64_t *msc, int64_t *sbc);
++int (*glXSwapInterval)(int interval);
++
++static int GLXExtensionSupported(Display *dpy, const char *extension)
++{
++ const char *extensionsString, *pos;
++
++ extensionsString = glXQueryExtensionsString(dpy, DefaultScreen(dpy));
++
++ pos = strstr(extensionsString, extension);
++
++ if (pos != NULL && (pos == extensionsString || pos[-1] == ' ') &&
++ (pos[strlen(extension)] == ' ' || pos[strlen(extension)] == '\0'))
++ return 1;
++
++ return 0;
++}
++
++extern char *optarg;
++extern int optind, opterr, optopt;
++static char optstr[] = "w:h:vd:r:n:i:";
++
++static void usage(char *name)
++{
++ printf("usage: %s [-w <width>] [-h <height>] ...\n", name);
++ printf("\t-d<divisor> - divisor for OML swap\n");
++ printf("\t-r<remainder> - remainder for OML swap\n");
++ printf("\t-n<interval> - wait interval for OML WaitMSC\n");
++ printf("\t-i<swap interval> - swap at most once every n frames\n");
++ printf("\t-v: verbose (print count)\n");
++ exit(-1);
++}
++
++int main(int argc, char *argv[])
++{
++ Display *disp;
++ XVisualInfo *pvi;
++ XSetWindowAttributes swa;
++ Window winGL;
++ GLXContext context;
++ int dummy;
++ Atom wmDelete;
++ int64_t ust, msc, sbc;
++ int width = 500, height = 500, verbose = 0, divisor = 0, remainder = 0,
++ wait_interval = 0, swap_interval = 1;
++ int c, i = 1;
++ int ret;
++ int db_attribs[] = { GLX_RGBA,
++ GLX_RED_SIZE, 1,
++ GLX_GREEN_SIZE, 1,
++ GLX_BLUE_SIZE, 1,
++ GLX_DOUBLEBUFFER,
++ GLX_DEPTH_SIZE, 1,
++ None };
++ XSizeHints sizehints;
++
++ opterr = 0;
++ while ((c = getopt(argc, argv, optstr)) != -1) {
++ switch (c) {
++ case 'w':
++ width = atoi(optarg);
++ break;
++ case 'h':
++ height = atoi(optarg);
++ break;
++ case 'v':
++ verbose = 1;
++ break;
++ case 'd':
++ divisor = atoi(optarg);
++ break;
++ case 'r':
++ remainder = atoi(optarg);
++ break;
++ case 'n':
++ wait_interval = atoi(optarg);
++ break;
++ case 'i':
++ swap_interval = atoi(optarg);
++ break;
++ default:
++ usage(argv[0]);
++ break;
++ }
++ }
++
++ disp = XOpenDisplay(NULL);
++ if (!disp) {
++ fprintf(stderr, "failed to open display\n");
++ return -1;
++ }
++
++ if (!glXQueryExtension(disp, &dummy, &dummy)) {
++ fprintf(stderr, "glXQueryExtension failed\n");
++ return -1;
++ }
++
++ if (!GLXExtensionSupported(disp, "GLX_OML_sync_control")) {
++ fprintf(stderr, "GLX_OML_sync_control not supported\n");
++ return -1;
++ }
++
++ if (!GLXExtensionSupported(disp, "GLX_MESA_swap_control")) {
++ fprintf(stderr, "GLX_MESA_swap_control not supported\n");
++ return -1;
++ }
++
++ pvi = glXChooseVisual(disp, DefaultScreen(disp), db_attribs);
++
++ if (!pvi) {
++ fprintf(stderr, "failed to choose visual, exiting\n");
++ return -1;
++ }
++
++ pvi->screen = DefaultScreen(disp);
++
++ swa.colormap = XCreateColormap(disp, RootWindow(disp, pvi->screen),
++ pvi->visual, AllocNone);
++ swa.border_pixel = 0;
++ swa.event_mask = ExposureMask | KeyPressMask | ButtonPressMask |
++ StructureNotifyMask;
++ winGL = XCreateWindow(disp, RootWindow(disp, pvi->screen),
++ 0, 0,
++ width, height,
++ 0, pvi->depth, InputOutput, pvi->visual,
++ CWBorderPixel | CWColormap | CWEventMask, &swa);
++ if (!winGL) {
++ fprintf(stderr, "window creation failed\n");
++ return -1;
++ }
++ wmDelete = XInternAtom(disp, "WM_DELETE_WINDOW", True);
++ XSetWMProtocols(disp, winGL, &wmDelete, 1);
++
++ sizehints.x = 0;
++ sizehints.y = 0;
++ sizehints.width = width;
++ sizehints.height = height;
++ sizehints.flags = USSize | USPosition;
++
++ XSetNormalHints(disp, winGL, &sizehints);
++ XSetStandardProperties(disp, winGL, "glsync test", "glsync text",
++ None, NULL, 0, &sizehints);
++
++ context = glXCreateContext(disp, pvi, NULL, GL_TRUE);
++ if (!context) {
++ fprintf(stderr, "failed to create glx context\n");
++ return -1;
++ }
++
++ XMapWindow(disp, winGL);
++ ret = glXMakeCurrent(disp, winGL, context);
++ if (!ret) {
++ fprintf(stderr, "failed to make context current: %d\n", ret);
++ }
++
++ glXGetSyncValuesOML = (void *)glXGetProcAddress((unsigned char *)"glXGetSyncValuesOML");
++ glXGetMscRateOML = (void *)glXGetProcAddress((unsigned char *)"glXGetMscRateOML");
++ glXSwapBuffersMscOML = (void *)glXGetProcAddress((unsigned char *)"glXSwapBuffersMscOML");
++ glXWaitForMscOML = (void *)glXGetProcAddress((unsigned char *)"glXWaitForMscOML");
++ glXWaitForSbcOML = (void *)glXGetProcAddress((unsigned char *)"glXWaitForSbcOML");
++ glXSwapInterval = (void *)glXGetProcAddress((unsigned char *)"glXSwapIntervalMESA");
++
++ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
++
++ glXSwapInterval(swap_interval);
++ fprintf(stderr, "set swap interval to %d\n", swap_interval);
++
++ glXGetSyncValuesOML(disp, winGL, &ust, &msc, &sbc);
++ while (i++) {
++ /* Alternate colors to make tearing obvious */
++ if (i & 1) {
++ glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
++ glColor3f(1.0f, 1.0f, 1.0f);
++ } else {
++ glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
++ glColor3f(1.0f, 0.0f, 0.0f);
++ }
++
++ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
++ glRectf(0, 0, width, height);
++
++ glXSwapBuffersMscOML(disp, winGL, 0, divisor, remainder);
++
++ if (wait_interval) {
++ glXWaitForMscOML(disp, winGL, msc + wait_interval,
++ 0, 0, &ust, &msc, &sbc);
++ }
++ }
++
++ XDestroyWindow(disp, winGL);
++ glXDestroyContext(disp, context);
++ XCloseDisplay(disp);
++
++ return 0;
++}
+diff -Naurp Mesa-7.8.1/progs/xdemos/opencloseopen.c Mesa-7.8.1.patched/progs/xdemos/opencloseopen.c
+--- Mesa-7.8.1/progs/xdemos/opencloseopen.c 1970-01-01 01:00:00.000000000 +0100
++++ Mesa-7.8.1.patched/progs/xdemos/opencloseopen.c 2010-06-13 13:45:06.788792936 +0200
+@@ -0,0 +1,189 @@
++/*
++ * Copyright (C) 1999-2001 Brian Paul All Rights Reserved.
++ * (C) Copyright IBM Corporation 2003
++ *
++ * 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 <unistd.h>
++#include <string.h>
++#include <X11/Xlib.h>
++#include <GL/gl.h>
++#include <GL/glx.h>
++
++/** \file opencloseopen.c
++ * Simple test for Mesa bug #508473. Create a window and rendering context.
++ * Draw a single frame. Close the window, destroy the context, and close
++ * the display. Re-open the display, create a new window and context. This
++ * should work, but, at least as of Mesa 5.1, it segfaults. See the bug
++ * report for more details.
++ *
++ * Most of the code here was lifed from various other Mesa xdemos.
++ */
++
++static void
++draw(void)
++{
++ glViewport(0, 0, 300, 300);
++ glMatrixMode(GL_PROJECTION);
++ glLoadIdentity();
++ glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
++ glMatrixMode(GL_MODELVIEW);
++
++ glShadeModel(GL_FLAT);
++ glClearColor(0.5, 0.5, 0.5, 1.0);
++ glClear(GL_COLOR_BUFFER_BIT);
++
++ /* draw blue quad */
++ glLoadIdentity();
++ glColor3f(0.3, 0.3, 1.0);
++ glPushMatrix();
++ glRotatef(0, 0, 0, 1);
++ glBegin(GL_POLYGON);
++ glVertex2f(-0.5, -0.25);
++ glVertex2f( 0.5, -0.25);
++ glVertex2f( 0.5, 0.25);
++ glVertex2f(-0.5, 0.25);
++ glEnd();
++ glPopMatrix();}
++
++
++/*
++ * Create an RGB, double-buffered window.
++ * Return the window and context handles.
++ */
++static void
++make_window( const char * dpyName, const char *name,
++ int x, int y, int width, int height,
++ Display **dpyRet, Window *winRet, GLXContext *ctxRet)
++{
++ int attrib[] = { GLX_RGBA,
++ GLX_RED_SIZE, 1,
++ GLX_GREEN_SIZE, 1,
++ GLX_BLUE_SIZE, 1,
++ GLX_DOUBLEBUFFER,
++ None };
++ int scrnum;
++ XSetWindowAttributes attr;
++ unsigned long mask;
++ Window root;
++ Window win;
++ GLXContext ctx;
++ XVisualInfo *visinfo;
++ Display *dpy;
++
++ dpy = XOpenDisplay(dpyName);
++ if (!dpy) {
++ printf("Error: couldn't open display %s\n", XDisplayName(dpyName));
++ exit(1);
++ }
++
++ *dpyRet = dpy;
++ scrnum = DefaultScreen( dpy );
++ root = RootWindow( dpy, scrnum );
++
++ visinfo = glXChooseVisual( dpy, scrnum, attrib );
++ if (!visinfo) {
++ printf("Error: couldn't get an RGB, Double-buffered visual\n");
++ exit(1);
++ }
++
++ /* window attributes */
++ attr.background_pixel = 0;
++ attr.border_pixel = 0;
++ attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone);
++ attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
++ mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
++
++ win = XCreateWindow( dpy, root, 0, 0, width, 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(dpy, win, &sizehints);
++ XSetStandardProperties(dpy, win, name, name,
++ None, (char **)NULL, 0, &sizehints);
++ }
++
++ ctx = glXCreateContext( dpy, visinfo, NULL, True );
++ if (!ctx) {
++ printf("Error: glXCreateContext failed\n");
++ exit(1);
++ }
++
++ XFree(visinfo);
++
++ *winRet = win;
++ *ctxRet = ctx;
++}
++
++
++static void
++destroy_window( Display *dpy, Window win, GLXContext ctx )
++{
++ glXMakeCurrent(dpy, None, NULL);
++ glXDestroyContext(dpy, ctx);
++ XDestroyWindow(dpy, win);
++ XCloseDisplay(dpy);
++}
++
++
++int
++main(int argc, char *argv[])
++{
++ Display *dpy;
++ Window win;
++ GLXContext ctx;
++ char *dpyName = NULL;
++ int i;
++
++ for (i = 1; i < argc; i++) {
++ if (strcmp(argv[i], "-display") == 0) {
++ dpyName = argv[i+1];
++ i++;
++ }
++ }
++
++ printf("If this program segfaults, then Mesa bug #508473 is probably "
++ "back.\n");
++ make_window(dpyName, "Open-close-open", 0, 0, 300, 300, &dpy, &win, &ctx);
++ XMapWindow(dpy, win);
++ glXMakeCurrent(dpy, win, ctx);
++
++ draw();
++ glXSwapBuffers(dpy, win);
++ sleep(2);
++
++ destroy_window(dpy, win, ctx);
++
++ make_window(dpyName, "Open-close-open", 0, 0, 300, 300, &dpy, &win, &ctx);
++ XMapWindow(dpy, win);
++ glXMakeCurrent(dpy, win, ctx);
++ destroy_window(dpy, win, ctx);
++
++ return 0;
++}
+diff -Naurp Mesa-7.8.1/progs/xdemos/overlay.c Mesa-7.8.1.patched/progs/xdemos/overlay.c
+--- Mesa-7.8.1/progs/xdemos/overlay.c 1970-01-01 01:00:00.000000000 +0100
++++ Mesa-7.8.1.patched/progs/xdemos/overlay.c 2010-06-13 13:45:06.789793146 +0200
+@@ -0,0 +1,246 @@
++/*
++ * GLX overlay test/demo.
++ *
++ * Brian Paul
++ * 18 July 2005
++ */
++
++#include <GL/gl.h>
++#include <GL/glx.h>
++#include <X11/keysym.h>
++#include <assert.h>
++#include <stdio.h>
++#include <stdlib.h>
++
++static int WinWidth = 300, WinHeight = 300;
++static Window NormalWindow = 0;
++static Window OverlayWindow = 0;
++static GLXContext NormalContext = 0;
++static GLXContext OverlayContext = 0;
++static GLboolean RGBOverlay = GL_FALSE;
++static GLfloat Angle = 0.0;
++
++
++static void
++RedrawNormal(Display *dpy)
++{
++ glXMakeCurrent(dpy, NormalWindow, NormalContext);
++ glViewport(0, 0, WinWidth, WinHeight);
++ glMatrixMode(GL_PROJECTION);
++ glLoadIdentity();
++ glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
++ glMatrixMode(GL_MODELVIEW);
++ glClearColor(0.5, 0.5, 0.5, 1.0);
++ glClear(GL_COLOR_BUFFER_BIT);
++ glColor3f(1.0, 1.0, 0.0);
++ glPushMatrix();
++ glRotatef(Angle, 0, 0, 1);
++ glRectf(-0.8, -0.8, 0.8, 0.8);
++ glPopMatrix();
++ glXSwapBuffers(dpy, NormalWindow);
++}
++
++
++static void
++RedrawOverlay(Display *dpy)
++{
++ glXMakeCurrent(dpy, OverlayWindow, OverlayContext);
++ glViewport(0, 0, WinWidth, WinHeight);
++ glMatrixMode(GL_PROJECTION);
++ glLoadIdentity();
++ glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
++ glMatrixMode(GL_MODELVIEW);
++ glClear(GL_COLOR_BUFFER_BIT);
++ if (RGBOverlay) {
++ glColor3f(0.0, 1.0, 1.0);
++ }
++ else {
++ glIndexi(2);
++ }
++ glBegin(GL_LINES);
++ glVertex2f(-1, -1);
++ glVertex2f(1, 1);
++ glVertex2f(1, -1);
++ glVertex2f(-1, 1);
++ glEnd();
++ glXSwapBuffers(dpy, OverlayWindow);
++}
++
++
++static Window
++MakeWindow(Display *dpy, XVisualInfo *visinfo, Window parent,
++ unsigned int width, unsigned int height)
++{
++ int scrnum;
++ XSetWindowAttributes attr;
++ unsigned long mask;
++ Window root;
++ Window win;
++
++ scrnum = DefaultScreen(dpy);
++ root = RootWindow(dpy, scrnum);
++
++ /* window attributes */
++ attr.background_pixel = 0;
++ attr.border_pixel = 0;
++ attr.colormap = XCreateColormap(dpy, root, visinfo->visual, AllocNone);
++ attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
++ mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
++
++ win = XCreateWindow(dpy, parent, 0, 0, width, height,
++ 0, visinfo->depth, InputOutput,
++ visinfo->visual, mask, &attr);
++ return win;
++}
++
++
++static void
++MakeNormalWindow(Display *dpy)
++{
++ int attrib[] = { GLX_RGBA,
++ GLX_RED_SIZE, 1,
++ GLX_GREEN_SIZE, 1,
++ GLX_BLUE_SIZE, 1,
++ GLX_DOUBLEBUFFER,
++ None };
++ int scrnum;
++ Window root;
++ XVisualInfo *visinfo;
++
++ scrnum = DefaultScreen(dpy);
++ root = RootWindow(dpy, scrnum);
++
++ visinfo = glXChooseVisual(dpy, scrnum, attrib);
++ if (!visinfo) {
++ printf("Error: couldn't get an RGB, Double-buffered visual\n");
++ exit(1);
++ }
++
++ NormalWindow = MakeWindow(dpy, visinfo, root, WinWidth, WinHeight);
++ assert(NormalWindow);
++
++ NormalContext = glXCreateContext(dpy, visinfo, NULL, True);
++ assert(NormalContext);
++}
++
++
++static void
++MakeOverlayWindow(Display *dpy)
++{
++ int rgbAttribs[] = {
++ GLX_RGBA,
++ GLX_RED_SIZE, 1,
++ GLX_GREEN_SIZE, 1,
++ GLX_BLUE_SIZE, 1,
++ GLX_DOUBLEBUFFER,
++ GLX_LEVEL, 1,
++ None
++ };
++ int indexAttribs[] = {
++ /*GLX_RGBA, leave this out */
++ GLX_RED_SIZE, 1,
++ GLX_GREEN_SIZE, 1,
++ GLX_BLUE_SIZE, 1,
++ GLX_DOUBLEBUFFER,
++ GLX_LEVEL, 1,
++ None
++ };
++ int scrnum;
++ Window root;
++ XVisualInfo *visinfo;
++
++ scrnum = DefaultScreen(dpy);
++ root = RootWindow(dpy, scrnum);
++
++ visinfo = glXChooseVisual(dpy, scrnum, rgbAttribs);
++ if (visinfo) {
++ printf("Found RGB overlay visual 0x%x\n", (int) visinfo->visualid);
++ RGBOverlay = GL_TRUE;
++ }
++ else {
++ visinfo = glXChooseVisual(dpy, scrnum, indexAttribs);
++ if (visinfo) {
++ printf("Found Color Index overlay visual 0x%x\n",
++ (int) visinfo->visualid);
++ /* XXX setup the colormap entries! */
++ }
++ else {
++ printf("Couldn't get an overlay visual.\n");
++ printf("Your hardware probably doesn't support framebuffer overlay planes.\n");
++ exit(1);
++ }
++ }
++
++ OverlayWindow = MakeWindow(dpy, visinfo, NormalWindow, WinWidth, WinHeight);
++ assert(OverlayWindow);
++
++ OverlayContext = glXCreateContext(dpy, visinfo, NULL, True);
++ assert(OverlayContext);
++}
++
++
++static void
++EventLoop(Display *dpy)
++{
++ XEvent event;
++
++ while (1) {
++ XNextEvent(dpy, &event);
++
++ switch (event.type) {
++ case Expose:
++ RedrawNormal(dpy);
++ RedrawOverlay(dpy);
++ break;
++ case ConfigureNotify:
++ WinWidth = event.xconfigure.width;
++ WinHeight = event.xconfigure.height;
++ if (event.xconfigure.window == NormalWindow)
++ XResizeWindow(dpy, OverlayWindow, WinWidth, WinHeight);
++ break;
++ case KeyPress:
++ {
++ char buffer[10];
++ int r, code;
++ code = XLookupKeysym(&event.xkey, 0);
++ r = XLookupString(&event.xkey, buffer, sizeof(buffer),
++ NULL, NULL);
++ if (buffer[0] == 27) {
++ /* escape */
++ return;
++ }
++ else if (buffer[0] == ' ') {
++ Angle += 5.0;
++ RedrawNormal(dpy);
++ }
++ }
++ break;
++ default:
++ ; /* nothing */
++ }
++ }
++}
++
++
++int
++main(int argc, char *argv[])
++{
++ Display *dpy = XOpenDisplay(NULL);
++
++ assert(dpy);
++
++ MakeNormalWindow(dpy);
++ MakeOverlayWindow(dpy);
++
++ XMapWindow(dpy, NormalWindow);
++ XMapWindow(dpy, OverlayWindow);
++
++ EventLoop(dpy);
++
++ glXDestroyContext(dpy, OverlayContext);
++ glXDestroyContext(dpy, NormalContext);
++ XDestroyWindow(dpy, OverlayWindow);
++ XDestroyWindow(dpy, NormalWindow);
++
++ return 0;
++}
+diff -Naurp Mesa-7.8.1/progs/xdemos/pbdemo.c Mesa-7.8.1.patched/progs/xdemos/pbdemo.c
+--- Mesa-7.8.1/progs/xdemos/pbdemo.c 1970-01-01 01:00:00.000000000 +0100
++++ Mesa-7.8.1.patched/progs/xdemos/pbdemo.c 2010-06-13 13:45:06.789793146 +0200
+@@ -0,0 +1,493 @@
++
++/*
++ * This program demonstrates how to do "off-screen" rendering using
++ * the GLX pixel buffer extension.
++ *
++ * Written by Brian Paul for the "OpenGL and Window System Integration"
++ * course presented at SIGGRAPH '97. Updated on 5 October 2002.
++ *
++ * Usage:
++ * pbuffers width height imgfile
++ * Where:
++ * width is the width, in pixels, of the image to generate.
++ * height is the height, in pixels, of the image to generate.
++ * imgfile is the name of the PPM image file to write.
++ *
++ *
++ * This demo draws 3-D boxes with random orientation. A pbuffer with
++ * a depth (Z) buffer is prefered but if such a pbuffer can't be created
++ * we use a non-depth-buffered config.
++ *
++ * On machines such as the SGI Indigo you may have to reconfigure your
++ * display/X server to enable pbuffers. Look in the /usr/gfx/ucode/MGRAS/vof/
++ * directory for display configurationswith the _pbuf suffix. Use
++ * setmon -x <vof> to configure your X server and display for pbuffers.
++ *
++ * O2 systems seem to support pbuffers well.
++ *
++ * IR systems (at least 1RM systems) don't have single-buffered, RGBA,
++ * Z-buffered pbuffer configs. BUT, they DO have DOUBLE-buffered, RGBA,
++ * Z-buffered pbuffers. Note how we try four different fbconfig attribute
++ * lists below!
++ */
++
++
++#include <assert.h>
++#include <string.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <X11/Xlib.h>
++#include "pbutil.h"
++
++
++/* Some ugly global vars */
++static Display *gDpy = NULL;
++static int gScreen = 0;
++static FBCONFIG gFBconfig = 0;
++static PBUFFER gPBuffer = 0;
++static int gWidth, gHeight;
++static GLXContext glCtx;
++
++
++
++/*
++ * Create the pbuffer and return a GLXPbuffer handle.
++ *
++ * We loop over a list of fbconfigs trying to create
++ * a pixel buffer. We return the first pixel buffer which we successfully
++ * create.
++ */
++static PBUFFER
++MakePbuffer( Display *dpy, int screen, int width, int height )
++{
++#define NUM_FB_CONFIGS 4
++ const char fbString[NUM_FB_CONFIGS][100] = {
++ "Single Buffered, depth buffer",
++ "Double Buffered, depth buffer",
++ "Single Buffered, no depth buffer",
++ "Double Buffered, no depth buffer"
++ };
++ int fbAttribs[NUM_FB_CONFIGS][100] = {
++ {
++ /* Single buffered, with depth buffer */
++ GLX_RENDER_TYPE, GLX_RGBA_BIT,
++ GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT,
++ GLX_RED_SIZE, 1,
++ GLX_GREEN_SIZE, 1,
++ GLX_BLUE_SIZE, 1,
++ GLX_DEPTH_SIZE, 1,
++ GLX_DOUBLEBUFFER, 0,
++ GLX_STENCIL_SIZE, 0,
++ None
++ },
++ {
++ /* Double buffered, with depth buffer */
++ GLX_RENDER_TYPE, GLX_RGBA_BIT,
++ GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT,
++ GLX_RED_SIZE, 1,
++ GLX_GREEN_SIZE, 1,
++ GLX_BLUE_SIZE, 1,
++ GLX_DEPTH_SIZE, 1,
++ GLX_DOUBLEBUFFER, 1,
++ GLX_STENCIL_SIZE, 0,
++ None
++ },
++ {
++ /* Single buffered, without depth buffer */
++ GLX_RENDER_TYPE, GLX_RGBA_BIT,
++ GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT,
++ GLX_RED_SIZE, 1,
++ GLX_GREEN_SIZE, 1,
++ GLX_BLUE_SIZE, 1,
++ GLX_DEPTH_SIZE, 0,
++ GLX_DOUBLEBUFFER, 0,
++ GLX_STENCIL_SIZE, 0,
++ None
++ },
++ {
++ /* Double buffered, without depth buffer */
++ GLX_RENDER_TYPE, GLX_RGBA_BIT,
++ GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT,
++ GLX_RED_SIZE, 1,
++ GLX_GREEN_SIZE, 1,
++ GLX_BLUE_SIZE, 1,
++ GLX_DEPTH_SIZE, 0,
++ GLX_DOUBLEBUFFER, 1,
++ GLX_STENCIL_SIZE, 0,
++ None
++ }
++ };
++ Bool largest = True;
++ Bool preserve = False;
++ FBCONFIG *fbConfigs;
++ PBUFFER pBuffer = None;
++ int nConfigs;
++ int i;
++ int attempt;
++
++ for (attempt=0; attempt<NUM_FB_CONFIGS; attempt++) {
++
++ /* Get list of possible frame buffer configurations */
++ fbConfigs = ChooseFBConfig(dpy, screen, fbAttribs[attempt], &nConfigs);
++ if (nConfigs==0 || !fbConfigs) {
++ printf("Note: glXChooseFBConfig(%s) failed\n", fbString[attempt]);
++ XFree(fbConfigs);
++ continue;
++ }
++
++#if 0 /*DEBUG*/
++ for (i=0;i<nConfigs;i++) {
++ printf("Config %d\n", i);
++ PrintFBConfigInfo(dpy, screen, fbConfigs[i], 0);
++ }
++#endif
++
++ /* Create the pbuffer using first fbConfig in the list that works. */
++ for (i=0;i<nConfigs;i++) {
++ pBuffer = CreatePbuffer(dpy, screen, fbConfigs[i], width, height, largest, preserve);
++ if (pBuffer) {
++ gFBconfig = fbConfigs[i];
++ gWidth = width;
++ gHeight = height;
++ break;
++ }
++ }
++
++ if (pBuffer!=None) {
++ break;
++ }
++ }
++
++ if (pBuffer) {
++ printf("Using: %s\n", fbString[attempt]);
++ }
++
++ XFree(fbConfigs);
++
++ return pBuffer;
++#undef NUM_FB_CONFIGS
++}
++
++
++
++/*
++ * Do all the X / GLX setup stuff.
++ */
++static int
++Setup(int width, int height)
++{
++ int pbSupport;
++ XVisualInfo *visInfo;
++
++ /* Open the X display */
++ gDpy = XOpenDisplay(NULL);
++ if (!gDpy) {
++ printf("Error: couldn't open default X display.\n");
++ return 0;
++ }
++
++ /* Get default screen */
++ gScreen = DefaultScreen(gDpy);
++
++ /* Test that pbuffers are available */
++ pbSupport = QueryPbuffers(gDpy, gScreen);
++ if (pbSupport == 1) {
++ printf("Using GLX 1.3 Pbuffers\n");
++ }
++ else if (pbSupport == 2) {
++ printf("Using SGIX Pbuffers\n");
++ }
++ else {
++ printf("Error: pbuffers not available on this screen\n");
++ XCloseDisplay(gDpy);
++ return 0;
++ }
++
++ /* Create Pbuffer */
++ gPBuffer = MakePbuffer( gDpy, gScreen, width, height );
++ if (gPBuffer==None) {
++ printf("Error: couldn't create pbuffer\n");
++ XCloseDisplay(gDpy);
++ return 0;
++ }
++
++ /* Test drawable queries */
++ {
++ unsigned int v;
++ glXQueryDrawable( gDpy, gPBuffer, GLX_WIDTH, &v);
++ printf("GLX_WIDTH = %u\n", v);
++ glXQueryDrawable( gDpy, gPBuffer, GLX_HEIGHT, &v);
++ printf("GLX_HEIGHT = %u\n", v);
++ glXQueryDrawable( gDpy, gPBuffer, GLX_PRESERVED_CONTENTS, &v);
++ printf("GLX_PRESERVED_CONTENTS = %u\n", v);
++ glXQueryDrawable( gDpy, gPBuffer, GLX_LARGEST_PBUFFER, &v);
++ printf("GLX_LARGEST_PBUFFER = %u\n", v);
++ glXQueryDrawable( gDpy, gPBuffer, GLX_FBCONFIG_ID, &v);
++ printf("GLX_FBCONFIG_ID = %u\n", v);
++ }
++
++ /* Get corresponding XVisualInfo */
++ visInfo = GetVisualFromFBConfig(gDpy, gScreen, gFBconfig);
++ if (!visInfo) {
++ printf("Error: can't get XVisualInfo from FBconfig\n");
++ XCloseDisplay(gDpy);
++ return 0;
++ }
++
++ /* Create GLX context */
++ glCtx = glXCreateContext(gDpy, visInfo, NULL, True);
++ if (!glCtx) {
++ /* try indirect */
++ glCtx = glXCreateContext(gDpy, visInfo, NULL, False);
++ if (!glCtx) {
++ printf("Error: Couldn't create GLXContext\n");
++ XFree(visInfo);
++ XCloseDisplay(gDpy);
++ return 0;
++ }
++ else {
++ printf("Warning: using indirect GLXContext\n");
++ }
++ }
++
++ /* Bind context to pbuffer */
++ if (!glXMakeCurrent(gDpy, gPBuffer, glCtx)) {
++ printf("Error: glXMakeCurrent failed\n");
++ XFree(visInfo);
++ XCloseDisplay(gDpy);
++ return 0;
++ }
++
++ return 1; /* Success!! */
++}
++
++
++
++/* One-time GL setup */
++static void
++InitGL(void)
++{
++ static GLfloat pos[4] = {0.0, 0.0, 10.0, 0.0};
++ glEnable(GL_LIGHTING);
++ glEnable(GL_LIGHT0);
++ glLightfv(GL_LIGHT0, GL_POSITION, pos);
++ glEnable(GL_NORMALIZE);
++ glEnable(GL_DEPTH_TEST);
++ glEnable(GL_CULL_FACE);
++
++ glViewport(0, 0, gWidth, gHeight);
++ glMatrixMode( GL_PROJECTION );
++ glLoadIdentity();
++ glFrustum( -1.0, 1.0, -1.0, 1.0, 5.0, 25.0 );
++ glMatrixMode( GL_MODELVIEW );
++ glLoadIdentity();
++ glTranslatef( 0.0, 0.0, -15.0 );
++}
++
++
++/* Return random float in [0,1] */
++static float
++Random(void)
++{
++ int i = rand();
++ return (float) (i % 1000) / 1000.0;
++}
++
++
++static void
++RandomColor(void)
++{
++ GLfloat c[4];
++ c[0] = Random();
++ c[1] = Random();
++ c[2] = Random();
++ c[3] = 1.0;
++ glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, c);
++}
++
++
++/* This function borrowed from Mark Kilgard's GLUT */
++static void
++drawBox(GLfloat x0, GLfloat x1, GLfloat y0, GLfloat y1,
++ GLfloat z0, GLfloat z1, GLenum type)
++{
++ static GLfloat n[6][3] =
++ {
++ {-1.0, 0.0, 0.0},
++ {0.0, 1.0, 0.0},
++ {1.0, 0.0, 0.0},
++ {0.0, -1.0, 0.0},
++ {0.0, 0.0, 1.0},
++ {0.0, 0.0, -1.0}
++ };
++ static GLint faces[6][4] =
++ {
++ {0, 1, 2, 3},
++ {3, 2, 6, 7},
++ {7, 6, 5, 4},
++ {4, 5, 1, 0},
++ {5, 6, 2, 1},
++ {7, 4, 0, 3}
++ };
++ GLfloat v[8][3], tmp;
++ GLint i;
++
++ if (x0 > x1) {
++ tmp = x0;
++ x0 = x1;
++ x1 = tmp;
++ }
++ if (y0 > y1) {
++ tmp = y0;
++ y0 = y1;
++ y1 = tmp;
++ }
++ if (z0 > z1) {
++ tmp = z0;
++ z0 = z1;
++ z1 = tmp;
++ }
++ v[0][0] = v[1][0] = v[2][0] = v[3][0] = x0;
++ v[4][0] = v[5][0] = v[6][0] = v[7][0] = x1;
++ v[0][1] = v[1][1] = v[4][1] = v[5][1] = y0;
++ v[2][1] = v[3][1] = v[6][1] = v[7][1] = y1;
++ v[0][2] = v[3][2] = v[4][2] = v[7][2] = z0;
++ v[1][2] = v[2][2] = v[5][2] = v[6][2] = z1;
++
++ for (i = 0; i < 6; i++) {
++ glBegin(type);
++ glNormal3fv(&n[i][0]);
++ glVertex3fv(&v[faces[i][0]][0]);
++ glVertex3fv(&v[faces[i][1]][0]);
++ glVertex3fv(&v[faces[i][2]][0]);
++ glVertex3fv(&v[faces[i][3]][0]);
++ glEnd();
++ }
++}
++
++
++
++/* Render a scene */
++static void
++Render(void)
++{
++ int NumBoxes = 100;
++ int i;
++
++ glClearColor(0.2, 0.2, 0.9, 0.0);
++ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
++
++ for (i=0;i<NumBoxes;i++) {
++ float tx = -2.0 + 4.0 * Random();
++ float ty = -2.0 + 4.0 * Random();
++ float tz = 4.0 - 16.0 * Random();
++ float sx = 0.1 + Random() * 0.4;
++ float sy = 0.1 + Random() * 0.4;
++ float sz = 0.1 + Random() * 0.4;
++ float rx = Random();
++ float ry = Random();
++ float rz = Random();
++ float ra = Random() * 360.0;
++ glPushMatrix();
++ glTranslatef(tx, ty, tz);
++ glRotatef(ra, rx, ry, rz);
++ glScalef(sx, sy, sz);
++ RandomColor();
++ drawBox(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0, GL_POLYGON);
++ glPopMatrix();
++ }
++
++ glFinish();
++}
++
++
++
++static void
++WriteFile(const char *filename)
++{
++ FILE *f;
++ GLubyte *image;
++ int i;
++
++ image = malloc(gWidth * gHeight * 3 * sizeof(GLubyte));
++ if (!image) {
++ printf("Error: couldn't allocate image buffer\n");
++ return;
++ }
++
++ glPixelStorei(GL_PACK_ALIGNMENT, 1);
++ glReadPixels(0, 0, gWidth, gHeight, GL_RGB, GL_UNSIGNED_BYTE, image);
++
++ f = fopen(filename, "w");
++ if (!f) {
++ printf("Couldn't open image file: %s\n", filename);
++ return;
++ }
++ fprintf(f,"P6\n");
++ fprintf(f,"# ppm-file created by %s\n", "trdemo2");
++ fprintf(f,"%i %i\n", gWidth, gHeight);
++ fprintf(f,"255\n");
++ fclose(f);
++ f = fopen(filename, "ab"); /* now append binary data */
++ if (!f) {
++ printf("Couldn't append to image file: %s\n", filename);
++ return;
++ }
++
++ for (i=0;i<gHeight;i++) {
++ GLubyte *rowPtr;
++ /* Remember, OpenGL images are bottom to top. Have to reverse. */
++ rowPtr = image + (gHeight-1-i) * gWidth*3;
++ fwrite(rowPtr, 1, gWidth*3, f);
++ }
++
++ fclose(f);
++ free(image);
++
++ printf("Wrote %d by %d image file: %s\n", gWidth, gHeight, filename);
++}
++
++
++
++/*
++ * Print message describing command line parameters.
++ */
++static void
++Usage(const char *appName)
++{
++ printf("Usage:\n");
++ printf(" %s width height imgfile\n", appName);
++ printf("Where imgfile is a ppm file\n");
++}
++
++
++
++int
++main(int argc, char *argv[])
++{
++ if (argc!=4) {
++ Usage(argv[0]);
++ }
++ else {
++ int width = atoi(argv[1]);
++ int height = atoi(argv[2]);
++ char *fileName = argv[3];
++ if (width<=0) {
++ printf("Error: width parameter must be at least 1.\n");
++ return 1;
++ }
++ if (height<=0) {
++ printf("Error: height parameter must be at least 1.\n");
++ return 1;
++ }
++ if (!Setup(width, height)) {
++ return 1;
++ }
++ InitGL();
++ Render();
++ WriteFile(fileName);
++ DestroyPbuffer(gDpy, gScreen, gPBuffer);
++ }
++ return 0;
++}
++
+diff -Naurp Mesa-7.8.1/progs/xdemos/pbinfo.c Mesa-7.8.1.patched/progs/xdemos/pbinfo.c
+--- Mesa-7.8.1/progs/xdemos/pbinfo.c 1970-01-01 01:00:00.000000000 +0100
++++ Mesa-7.8.1.patched/progs/xdemos/pbinfo.c 2010-06-13 13:45:06.789793146 +0200
+@@ -0,0 +1,107 @@
++
++/*
++ * Print list of fbconfigs and test each to see if a pbuffer can be created
++ * for that config.
++ *
++ * Brian Paul
++ * April 1997
++ * Updated on 5 October 2002.
++ */
++
++
++#include <X11/Xlib.h>
++#include <stdio.h>
++#include <string.h>
++#include "pbutil.h"
++
++
++
++
++static void
++PrintConfigs(Display *dpy, int screen, Bool horizFormat)
++{
++ FBCONFIG *fbConfigs;
++ int nConfigs;
++ int i;
++
++ fbConfigs = GetAllFBConfigs(dpy, screen, &nConfigs);
++ if (!nConfigs || !fbConfigs) {
++ printf("Error: glxGetFBConfigs failed\n");
++ XFree(fbConfigs);
++ return;
++ }
++
++ printf("Number of fbconfigs: %d\n", nConfigs);
++
++ if (horizFormat) {
++ printf(" ID VisualType Depth Lvl RGB CI DB Stereo R G B A");
++ printf(" Z S AR AG AB AA MSbufs MSnum Pbuffer Float\n");
++ }
++
++ /* Print config info */
++ for (i = 0; i < nConfigs; i++) {
++ PrintFBConfigInfo(dpy, screen, fbConfigs[i], horizFormat);
++ }
++
++ /* free the list */
++ XFree(fbConfigs);
++}
++
++
++
++static void
++PrintUsage(void)
++{
++ printf("Options:\n");
++ printf(" -display <display-name> specify X display name\n");
++ printf(" -t print in tabular format\n");
++ printf(" -v print in verbose format\n");
++ printf(" -help print this information\n");
++}
++
++
++int
++main(int argc, char *argv[])
++{
++ Display *dpy;
++ int scrn;
++ char *dpyName = NULL;
++ Bool horizFormat = True;
++ int i;
++
++ for (i=1; i<argc; i++) {
++ if (strcmp(argv[i],"-display")==0) {
++ if (i+1<argc) {
++ dpyName = argv[i+1];
++ i++;
++ }
++ }
++ else if (strcmp(argv[i],"-t")==0) {
++ /* tabular format */
++ horizFormat = True;
++ }
++ else if (strcmp(argv[i],"-v")==0) {
++ /* verbose format */
++ horizFormat = False;
++ }
++ else if (strcmp(argv[i],"-help")==0) {
++ PrintUsage();
++ return 0;
++ }
++ else {
++ printf("Unknown option: %s\n", argv[i]);
++ }
++ }
++
++ dpy = XOpenDisplay(dpyName);
++
++ if (!dpy) {
++ printf("Error: couldn't open display %s\n", XDisplayName(dpyName));
++ return 1;
++ }
++
++ scrn = DefaultScreen(dpy);
++ PrintConfigs(dpy, scrn, horizFormat);
++ XCloseDisplay(dpy);
++ return 0;
++}
+diff -Naurp Mesa-7.8.1/progs/xdemos/pbutil.c Mesa-7.8.1.patched/progs/xdemos/pbutil.c
+--- Mesa-7.8.1/progs/xdemos/pbutil.c 1970-01-01 01:00:00.000000000 +0100
++++ Mesa-7.8.1.patched/progs/xdemos/pbutil.c 2010-06-13 13:45:06.789793146 +0200
+@@ -0,0 +1,446 @@
++
++/*
++ * OpenGL pbuffers utility functions.
++ *
++ * Brian Paul
++ * Original code: April 1997
++ * Updated on 5 October 2002
++ * Updated again on 3 January 2005 to use GLX 1.3 functions in preference
++ * to the GLX_SGIX_fbconfig/pbuffer extensions.
++ */
++
++#include <stdio.h>
++#include <string.h>
++#include "pbutil.h"
++
++
++/**
++ * Test if we pixel buffers are available for a particular X screen.
++ * Input: dpy - the X display
++ * screen - screen number
++ * Return: 0 = fbconfigs not available.
++ * 1 = fbconfigs are available via GLX 1.3.
++ * 2 = fbconfigs and pbuffers are available via GLX_SGIX_fbconfig
++ */
++int
++QueryFBConfig(Display *dpy, int screen)
++{
++#if defined(GLX_VERSION_1_3)
++ {
++ /* GLX 1.3 supports pbuffers */
++ int glxVersionMajor, glxVersionMinor;
++ if (!glXQueryVersion(dpy, &glxVersionMajor, &glxVersionMinor)) {
++ /* GLX not available! */
++ return 0;
++ }
++ if (glxVersionMajor * 100 + glxVersionMinor >= 103) {
++ return 1;
++ }
++ /* fall-through */
++ }
++#endif
++
++ /* Try the SGIX extensions */
++ {
++ char *extensions;
++ extensions = (char *) glXQueryServerString(dpy, screen, GLX_EXTENSIONS);
++ if (extensions && strstr(extensions,"GLX_SGIX_fbconfig")) {
++ return 2;
++ }
++ }
++
++ return 0;
++}
++
++/**
++ * Test if we pixel buffers are available for a particular X screen.
++ * Input: dpy - the X display
++ * screen - screen number
++ * Return: 0 = pixel buffers not available.
++ * 1 = pixel buffers are available via GLX 1.3.
++ * 2 = pixel buffers are available via GLX_SGIX_fbconfig/pbuffer.
++ */
++int
++QueryPbuffers(Display *dpy, int screen)
++{
++ int ret;
++
++ ret = QueryFBConfig(dpy, screen);
++ if (ret == 2) {
++ char *extensions;
++ extensions = (char *) glXQueryServerString(dpy, screen, GLX_EXTENSIONS);
++ if (extensions && strstr(extensions, "GLX_SGIX_pbuffer"))
++ return 2;
++ else
++ return 0;
++ }
++ else
++ return ret;
++}
++
++FBCONFIG *
++ChooseFBConfig(Display *dpy, int screen, const int attribs[], int *nConfigs)
++{
++ int fbcSupport = QueryPbuffers(dpy, screen);
++#if defined(GLX_VERSION_1_3)
++ if (fbcSupport == 1) {
++ return glXChooseFBConfig(dpy, screen, attribs, nConfigs);
++ }
++#endif
++#if defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer)
++ if (fbcSupport == 2) {
++ return glXChooseFBConfigSGIX(dpy, screen, (int *) attribs, nConfigs);
++ }
++#endif
++ return NULL;
++}
++
++
++FBCONFIG *
++GetAllFBConfigs(Display *dpy, int screen, int *nConfigs)
++{
++ int fbcSupport = QueryFBConfig(dpy, screen);
++#if defined(GLX_VERSION_1_3)
++ if (fbcSupport == 1) {
++ return glXGetFBConfigs(dpy, screen, nConfigs);
++ }
++#endif
++#if defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer)
++ if (fbcSupport == 2) {
++ /* The GLX_SGIX_fbconfig extensions says to pass NULL to get list
++ * of all available configurations.
++ */
++ return glXChooseFBConfigSGIX(dpy, screen, NULL, nConfigs);
++ }
++#endif
++ return NULL;
++}
++
++
++XVisualInfo *
++GetVisualFromFBConfig(Display *dpy, int screen, FBCONFIG config)
++{
++ int fbcSupport = QueryFBConfig(dpy, screen);
++#if defined(GLX_VERSION_1_3)
++ if (fbcSupport == 1) {
++ return glXGetVisualFromFBConfig(dpy, config);
++ }
++#endif
++#if defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer)
++ if (fbcSupport == 2) {
++ return glXGetVisualFromFBConfigSGIX(dpy, config);
++ }
++#endif
++ return NULL;
++}
++
++
++/**
++ * Either use glXGetFBConfigAttrib() or glXGetFBConfigAttribSGIX()
++ * to query an fbconfig attribute.
++ */
++static int
++GetFBConfigAttrib(Display *dpy, int screen,
++#if defined(GLX_VERSION_1_3)
++ const GLXFBConfig config,
++#elif defined(GLX_SGIX_fbconfig)
++ const GLXFBConfigSGIX config,
++#endif
++ int attrib
++ )
++{
++ int fbcSupport = QueryFBConfig(dpy, screen);
++ int value = 0;
++
++#if defined(GLX_VERSION_1_3)
++ if (fbcSupport == 1) {
++ /* ok */
++ if (glXGetFBConfigAttrib(dpy, config, attrib, &value) != 0) {
++ value = 0;
++ }
++ return value;
++ }
++ /* fall-through */
++#endif
++
++#if defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer)
++ if (fbcSupport == 2) {
++ if (glXGetFBConfigAttribSGIX(dpy, config, attrib, &value) != 0) {
++ value = 0;
++ }
++ return value;
++ }
++#endif
++
++ return value;
++}
++
++
++
++/**
++ * Print parameters for a GLXFBConfig to stdout.
++ * Input: dpy - the X display
++ * screen - the X screen number
++ * fbConfig - the fbconfig handle
++ * horizFormat - if true, print in horizontal format
++ */
++void
++PrintFBConfigInfo(Display *dpy, int screen, FBCONFIG config, Bool horizFormat)
++{
++ PBUFFER pBuffer;
++ int width=2, height=2;
++ int bufferSize, level, doubleBuffer, stereo, auxBuffers;
++ int redSize, greenSize, blueSize, alphaSize;
++ int depthSize, stencilSize;
++ int accumRedSize, accumBlueSize, accumGreenSize, accumAlphaSize;
++ int sampleBuffers, samples;
++ int drawableType, renderType, xRenderable, xVisual, id;
++ int maxWidth, maxHeight, maxPixels;
++ int optWidth, optHeight;
++ int floatComponents = 0;
++
++ /* do queries using the GLX 1.3 tokens (same as the SGIX tokens) */
++ bufferSize = GetFBConfigAttrib(dpy, screen, config, GLX_BUFFER_SIZE);
++ level = GetFBConfigAttrib(dpy, screen, config, GLX_LEVEL);
++ doubleBuffer = GetFBConfigAttrib(dpy, screen, config, GLX_DOUBLEBUFFER);
++ stereo = GetFBConfigAttrib(dpy, screen, config, GLX_STEREO);
++ auxBuffers = GetFBConfigAttrib(dpy, screen, config, GLX_AUX_BUFFERS);
++ redSize = GetFBConfigAttrib(dpy, screen, config, GLX_RED_SIZE);
++ greenSize = GetFBConfigAttrib(dpy, screen, config, GLX_GREEN_SIZE);
++ blueSize = GetFBConfigAttrib(dpy, screen, config, GLX_BLUE_SIZE);
++ alphaSize = GetFBConfigAttrib(dpy, screen, config, GLX_ALPHA_SIZE);
++ depthSize = GetFBConfigAttrib(dpy, screen, config, GLX_DEPTH_SIZE);
++ stencilSize = GetFBConfigAttrib(dpy, screen, config, GLX_STENCIL_SIZE);
++ accumRedSize = GetFBConfigAttrib(dpy, screen, config, GLX_ACCUM_RED_SIZE);
++ accumGreenSize = GetFBConfigAttrib(dpy, screen, config, GLX_ACCUM_GREEN_SIZE);
++ accumBlueSize = GetFBConfigAttrib(dpy, screen, config, GLX_ACCUM_BLUE_SIZE);
++ accumAlphaSize = GetFBConfigAttrib(dpy, screen, config, GLX_ACCUM_ALPHA_SIZE);
++ sampleBuffers = GetFBConfigAttrib(dpy, screen, config, GLX_SAMPLE_BUFFERS);
++ samples = GetFBConfigAttrib(dpy, screen, config, GLX_SAMPLES);
++ drawableType = GetFBConfigAttrib(dpy, screen, config, GLX_DRAWABLE_TYPE);
++ renderType = GetFBConfigAttrib(dpy, screen, config, GLX_RENDER_TYPE);
++ xRenderable = GetFBConfigAttrib(dpy, screen, config, GLX_X_RENDERABLE);
++ xVisual = GetFBConfigAttrib(dpy, screen, config, GLX_X_VISUAL_TYPE);
++ if (!xRenderable || !(drawableType & GLX_WINDOW_BIT_SGIX))
++ xVisual = -1;
++
++ id = GetFBConfigAttrib(dpy, screen, config, GLX_FBCONFIG_ID);
++ maxWidth = GetFBConfigAttrib(dpy, screen, config, GLX_MAX_PBUFFER_WIDTH);
++ maxHeight = GetFBConfigAttrib(dpy, screen, config, GLX_MAX_PBUFFER_HEIGHT);
++ maxPixels = GetFBConfigAttrib(dpy, screen, config, GLX_MAX_PBUFFER_PIXELS);
++#if defined(GLX_SGIX_pbuffer)
++ optWidth = GetFBConfigAttrib(dpy, screen, config, GLX_OPTIMAL_PBUFFER_WIDTH_SGIX);
++ optHeight = GetFBConfigAttrib(dpy, screen, config, GLX_OPTIMAL_PBUFFER_HEIGHT_SGIX);
++#else
++ optWidth = optHeight = 0;
++#endif
++#if defined(GLX_NV_float_buffer)
++ floatComponents = GetFBConfigAttrib(dpy, screen, config, GLX_FLOAT_COMPONENTS_NV);
++#endif
++
++ /* See if we can create a pbuffer with this config */
++ pBuffer = CreatePbuffer(dpy, screen, config, width, height, False, False);
++
++ if (horizFormat) {
++ printf("0x%-9x ", id);
++ if (xVisual==GLX_STATIC_GRAY) printf("StaticGray ");
++ else if (xVisual==GLX_GRAY_SCALE) printf("GrayScale ");
++ else if (xVisual==GLX_STATIC_COLOR) printf("StaticColor ");
++ else if (xVisual==GLX_PSEUDO_COLOR) printf("PseudoColor ");
++ else if (xVisual==GLX_TRUE_COLOR) printf("TrueColor ");
++ else if (xVisual==GLX_DIRECT_COLOR) printf("DirectColor ");
++ else printf(" -none- ");
++ printf(" %3d %3d %s %s %s %2s ", bufferSize, level,
++ (renderType & GLX_RGBA_BIT_SGIX) ? "y" : ".",
++ (renderType & GLX_COLOR_INDEX_BIT_SGIX) ? "y" : ".",
++ doubleBuffer ? "y" : ".",
++ stereo ? "y" : ".");
++ printf("%2d %2d %2d %2d ", redSize, greenSize, blueSize, alphaSize);
++ printf("%2d %2d ", depthSize, stencilSize);
++ printf("%2d %2d %2d %2d", accumRedSize, accumGreenSize, accumBlueSize,
++ accumAlphaSize);
++ printf(" %2d %2d", sampleBuffers, samples);
++ printf(" %s %c", pBuffer ? "y" : ".",
++ ".y"[floatComponents]);
++ printf("\n");
++ }
++ else {
++ printf("Id 0x%x\n", id);
++ printf(" Buffer Size: %d\n", bufferSize);
++ printf(" Level: %d\n", level);
++ printf(" Double Buffer: %s\n", doubleBuffer ? "yes" : "no");
++ printf(" Stereo: %s\n", stereo ? "yes" : "no");
++ printf(" Aux Buffers: %d\n", auxBuffers);
++ printf(" Red Size: %d\n", redSize);
++ printf(" Green Size: %d\n", greenSize);
++ printf(" Blue Size: %d\n", blueSize);
++ printf(" Alpha Size: %d\n", alphaSize);
++ printf(" Depth Size: %d\n", depthSize);
++ printf(" Stencil Size: %d\n", stencilSize);
++ printf(" Accum Red Size: %d\n", accumRedSize);
++ printf(" Accum Green Size: %d\n", accumGreenSize);
++ printf(" Accum Blue Size: %d\n", accumBlueSize);
++ printf(" Accum Alpha Size: %d\n", accumAlphaSize);
++ printf(" Sample Buffers: %d\n", sampleBuffers);
++ printf(" Samples/Pixel: %d\n", samples);
++ printf(" Drawable Types: ");
++ if (drawableType & GLX_WINDOW_BIT) printf("Window ");
++ if (drawableType & GLX_PIXMAP_BIT) printf("Pixmap ");
++ if (drawableType & GLX_PBUFFER_BIT) printf("PBuffer");
++ printf("\n");
++ printf(" Render Types: ");
++ if (renderType & GLX_RGBA_BIT_SGIX) printf("RGBA ");
++ if (renderType & GLX_COLOR_INDEX_BIT_SGIX) printf("CI ");
++ printf("\n");
++ printf(" X Renderable: %s\n", xRenderable ? "yes" : "no");
++
++ printf(" Pbuffer: %s\n", pBuffer ? "yes" : "no");
++ printf(" Max Pbuffer width: %d\n", maxWidth);
++ printf(" Max Pbuffer height: %d\n", maxHeight);
++ printf(" Max Pbuffer pixels: %d\n", maxPixels);
++ printf(" Optimum Pbuffer width: %d\n", optWidth);
++ printf(" Optimum Pbuffer height: %d\n", optHeight);
++
++ printf(" Float Components: %s\n", floatComponents ? "yes" : "no");
++ }
++
++ if (pBuffer) {
++ DestroyPbuffer(dpy, screen, pBuffer);
++ }
++}
++
++
++
++GLXContext
++CreateContext(Display *dpy, int screen, FBCONFIG config)
++{
++ int fbcSupport = QueryFBConfig(dpy, screen);
++#if defined(GLX_VERSION_1_3)
++ if (fbcSupport == 1) {
++ /* GLX 1.3 */
++ GLXContext c;
++ c = glXCreateNewContext(dpy, config, GLX_RGBA_TYPE, NULL, True);
++ if (!c) {
++ /* try indirect */
++ c = glXCreateNewContext(dpy, config, GLX_RGBA_TYPE, NULL, False);
++ }
++ return c;
++ }
++#endif
++#if defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer)
++ if (fbcSupport == 2) {
++ GLXContext c;
++ c = glXCreateContextWithConfigSGIX(dpy, config, GLX_RGBA_TYPE_SGIX, NULL, True);
++ if (!c) {
++ c = glXCreateContextWithConfigSGIX(dpy, config, GLX_RGBA_TYPE_SGIX, NULL, False);
++ }
++ return c;
++ }
++#endif
++ return 0;
++}
++
++
++void
++DestroyContext(Display *dpy, GLXContext ctx)
++{
++ glXDestroyContext(dpy, ctx);
++}
++
++
++/* This is only used by CreatePbuffer() */
++static int XErrorFlag = 0;
++static int HandleXError(Display *dpy, XErrorEvent *event)
++{
++ XErrorFlag = 1;
++ return 0;
++}
++
++
++/**
++ * Create a Pbuffer. Use an X error handler to deal with potential
++ * BadAlloc errors.
++ *
++ * Input: dpy - the X display
++ * fbConfig - an FBConfig as returned by glXChooseFBConfigSGIX().
++ * width, height - size of pixel buffer to request, in pixels.
++ * pbAttribs - list of optional pixel buffer attributes
++ * Return: a Pbuffer or None.
++ */
++PBUFFER
++CreatePbuffer(Display *dpy, int screen, FBCONFIG config,
++ int width, int height, Bool largest, Bool preserve)
++{
++ int (*oldHandler)(Display *, XErrorEvent *);
++ PBUFFER pBuffer = None;
++ int pbSupport = QueryPbuffers(dpy, screen);
++
++ /* Catch X protocol errors with our own error handler */
++ oldHandler = XSetErrorHandler(HandleXError);
++ XErrorFlag = 0;
++
++#if defined(GLX_VERSION_1_3)
++ if (pbSupport == 1) {
++ /* GLX 1.3 */
++ int attribs[100], i = 0;
++ attribs[i++] = GLX_PBUFFER_WIDTH;
++ attribs[i++] = width;
++ attribs[i++] = GLX_PBUFFER_HEIGHT;
++ attribs[i++] = height;
++ attribs[i++] = GLX_PRESERVED_CONTENTS;
++ attribs[i++] = preserve;
++ attribs[i++] = GLX_LARGEST_PBUFFER;
++ attribs[i++] = largest;
++ attribs[i++] = 0;
++ pBuffer = glXCreatePbuffer(dpy, config, attribs);
++ }
++ else
++#endif
++#if defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer)
++ if (pbSupport == 2) {
++ int attribs[100], i = 0;
++ attribs[i++] = GLX_PRESERVED_CONTENTS;
++ attribs[i++] = preserve;
++ attribs[i++] = GLX_LARGEST_PBUFFER;
++ attribs[i++] = largest;
++ attribs[i++] = 0;
++ pBuffer = glXCreateGLXPbufferSGIX(dpy, config, width, height, attribs);
++ }
++ else
++#endif
++ {
++ pBuffer = None;
++ }
++
++ XSync(dpy, False);
++ /* Restore original X error handler */
++ (void) XSetErrorHandler(oldHandler);
++
++ /* Return pbuffer (may be None) */
++ if (!XErrorFlag && pBuffer != None) {
++ /*printf("config %d worked!\n", i);*/
++ return pBuffer;
++ }
++ else {
++ return None;
++ }
++}
++
++
++void
++DestroyPbuffer(Display *dpy, int screen, PBUFFER pbuffer)
++{
++ int pbSupport = QueryPbuffers(dpy, screen);
++#if defined(GLX_VERSION_1_3)
++ if (pbSupport == 1) {
++ glXDestroyPbuffer(dpy, pbuffer);
++ return;
++ }
++#endif
++#if defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer)
++ if (pbSupport == 2) {
++ glXDestroyGLXPbufferSGIX(dpy, pbuffer);
++ return;
++ }
++#endif
++}
+diff -Naurp Mesa-7.8.1/progs/xdemos/pbutil.h Mesa-7.8.1.patched/progs/xdemos/pbutil.h
+--- Mesa-7.8.1/progs/xdemos/pbutil.h 1970-01-01 01:00:00.000000000 +0100
++++ Mesa-7.8.1.patched/progs/xdemos/pbutil.h 2010-06-13 13:45:06.789793146 +0200
+@@ -0,0 +1,69 @@
++/*
++ * OpenGL pbuffers utility functions.
++ *
++ * Brian Paul
++ * April 1997
++ */
++
++
++#ifndef PBUTIL_H
++#define PBUTIL_H
++
++
++#define GLX_GLXEXT_PROTOTYPES
++#include <GL/glx.h>
++
++
++#if defined(GLX_VERSION_1_3)
++#define PBUFFER GLXPbuffer
++#define FBCONFIG GLXFBConfig
++#elif defined(GLX_SGIX_fbconfig) && defined(GLX_SGIX_pbuffer)
++#define PBUFFER GLXPbufferSGIX
++#define FBCONFIG GLXFBConfigSGIX
++#else
++#define PBUFFER int
++#define FBCONFIG int
++#endif
++
++
++extern int
++QueryFBConfig(Display *dpy, int screen);
++
++extern int
++QueryPbuffers(Display *dpy, int screen);
++
++
++extern void
++PrintFBConfigInfo(Display *dpy, int screen, FBCONFIG config, Bool horizFormat);
++
++
++extern FBCONFIG *
++ChooseFBConfig(Display *dpy, int screen, const int attribs[], int *nConfigs);
++
++
++extern FBCONFIG *
++GetAllFBConfigs(Display *dpy, int screen, int *nConfigs);
++
++
++extern XVisualInfo *
++GetVisualFromFBConfig(Display *dpy, int screen, FBCONFIG config);
++
++
++extern GLXContext
++CreateContext(Display *dpy, int screen, FBCONFIG config);
++
++
++extern void
++DestroyContext(Display *dpy, GLXContext ctx);
++
++
++extern PBUFFER
++CreatePbuffer(Display *dpy, int screen, FBCONFIG config,
++ int width, int height, Bool preserve, Bool largest);
++
++
++extern void
++DestroyPbuffer(Display *dpy, int screen, PBUFFER pbuffer);
++
++
++#endif /*PBUTIL_H*/
+diff -Naurp Mesa-7.8.1/progs/xdemos/shape.c Mesa-7.8.1.patched/progs/xdemos/shape.c
+--- Mesa-7.8.1/progs/xdemos/shape.c 1970-01-01 01:00:00.000000000 +0100
++++ Mesa-7.8.1.patched/progs/xdemos/shape.c 2010-06-13 13:45:06.789793146 +0200
+@@ -0,0 +1,393 @@
++
++/*
++ * Example of using the X "shape" extension with OpenGL: render a spinning
++ * cube inside of a non-rectangular window.
++ *
++ * Press ESC to exit. Press up/down to change window shape.
++ *
++ * To compile add "shape" to the PROGS list in Makefile.
++ *
++ * Brian Paul
++ * June 16, 1997
++ *
++ * This program is in the public domain.
++ */
++
++
++#include <math.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <sys/time.h>
++#include <time.h>
++#include <unistd.h>
++#include <X11/Xlib.h>
++#include <X11/Xutil.h>
++#include <X11/keysym.h>
++#include <X11/extensions/shape.h>
++#include <GL/glx.h>
++
++#ifndef PI
++#define PI 3.1415926
++#endif
++
++
++static int Width=500, Height=500;
++
++static float Xangle = 0.0, Yangle = 0.0;
++static int Sides = 5;
++static int MinSides = 3;
++static int MaxSides = 20;
++
++
++/* return current time (in seconds) */
++static double
++current_time(void)
++{
++ struct timeval tv;
++#ifdef __VMS
++ (void) gettimeofday(&tv, NULL );
++#else
++ struct timezone tz;
++ (void) gettimeofday(&tv, &tz);
++#endif
++ return (double) tv.tv_sec + tv.tv_usec / 1000000.0;
++}
++
++
++/*
++ * Draw the OpenGL stuff and do a SwapBuffers.
++ */
++static void display(Display *dpy, Window win)
++{
++ float scale = 1.7;
++
++ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
++
++ glPushMatrix();
++
++ glScalef(scale, scale, scale);
++ glRotatef(Xangle, 1.0, 0.0, 0.0);
++ glRotatef(Yangle, 0.0, 1.0, 0.0);
++
++ /*
++ * wireframe box
++ */
++ glColor3f(1.0, 1.0, 1.0);
++ glBegin(GL_LINE_LOOP);
++ glVertex3f(-1.0, -1.0, -1.0);
++ glVertex3f( 1.0, -1.0, -1.0);
++ glVertex3f( 1.0, 1.0, -1.0);
++ glVertex3f(-1.0, 1.0, -1.0);
++ glEnd();
++
++ glBegin(GL_LINE_LOOP);
++ glVertex3f(-1.0, -1.0, 1.0);
++ glVertex3f( 1.0, -1.0, 1.0);
++ glVertex3f( 1.0, 1.0, 1.0);
++ glVertex3f(-1.0, 1.0, 1.0);
++ glEnd();
++
++ glBegin(GL_LINES);
++ glVertex3f(-1.0, -1.0, -1.0); glVertex3f(-1.0, -1.0, 1.0);
++ glVertex3f( 1.0, -1.0, -1.0); glVertex3f( 1.0, -1.0, 1.0);
++ glVertex3f( 1.0, 1.0, -1.0); glVertex3f( 1.0, 1.0, 1.0);
++ glVertex3f(-1.0, 1.0, -1.0); glVertex3f(-1.0, 1.0, 1.0);
++ glEnd();
++
++ /*
++ * Solid box
++ */
++ glPushMatrix();
++ glScalef(0.75, 0.75, 0.75);
++
++ glColor3f(1, 0, 0);
++ glBegin(GL_POLYGON);
++ glVertex3f(1, -1, -1);
++ glVertex3f(1, 1, -1);
++ glVertex3f(1, 1, 1);
++ glVertex3f(1, -1, 1);
++ glEnd();
++
++ glColor3f(0, 1, 1);
++ glBegin(GL_POLYGON);
++ glVertex3f(-1, -1, -1);
++ glVertex3f(-1, 1, -1);
++ glVertex3f(-1, 1, 1);
++ glVertex3f(-1, -1, 1);
++ glEnd();
++
++ glColor3f(0, 1, 0);
++ glBegin(GL_POLYGON);
++ glVertex3f(-1, 1, -1);
++ glVertex3f( 1, 1, -1);
++ glVertex3f( 1, 1, 1);
++ glVertex3f(-1, 1, 1);
++ glEnd();
++
++ glColor3f(1, 0, 1);
++ glBegin(GL_POLYGON);
++ glVertex3f(-1, -1, -1);
++ glVertex3f( 1, -1, -1);
++ glVertex3f( 1, -1, 1);
++ glVertex3f(-1, -1, 1);
++ glEnd();
++
++ glColor3f(0, 0, 1);
++ glBegin(GL_POLYGON);
++ glVertex3f(-1, -1, 1);
++ glVertex3f( 1, -1, 1);
++ glVertex3f( 1, 1, 1);
++ glVertex3f(-1, 1, 1);
++ glEnd();
++
++ glColor3f(1, 1, 0);
++ glBegin(GL_POLYGON);
++ glVertex3f(-1, -1, -1);
++ glVertex3f( 1, -1, -1);
++ glVertex3f( 1, 1, -1);
++ glVertex3f(-1, 1, -1);
++ glEnd();
++ glPopMatrix();
++
++
++ glPopMatrix();
++
++ glXSwapBuffers(dpy, win);
++}
++
++
++/*
++ * This is called when we have to recompute the window shape bitmask.
++ * We just generate an n-sided regular polygon here but any other shape
++ * would be possible.
++ */
++static void make_shape_mask(Display *dpy, Window win, int width, int height,
++ int sides)
++{
++ Pixmap shapeMask;
++ XGCValues xgcv;
++ GC gc;
++
++ /* allocate 1-bit deep pixmap and a GC */
++ shapeMask = XCreatePixmap(dpy, win, width, height, 1);
++ gc = XCreateGC(dpy, shapeMask, 0, &xgcv);
++
++ /* clear shapeMask to zeros */
++ XSetForeground(dpy, gc, 0);
++ XFillRectangle(dpy, shapeMask, gc, 0, 0, width, height);
++
++ /* draw mask */
++ XSetForeground(dpy, gc, 1);
++ {
++ int cx = width / 2;
++ int cy = height / 2;
++ float angle = 0.0;
++ float step = 2.0 * PI / sides;
++ float radius = width / 2;
++ int i;
++ XPoint points[100];
++ for (i=0;i<sides;i++) {
++ int x = cx + radius * sin(angle);
++ int y = cy - radius * cos(angle);
++ points[i].x = x;
++ points[i].y = y;
++ angle += step;
++ }
++ XFillPolygon(dpy, shapeMask, gc, points, sides, Convex, CoordModeOrigin);
++ }
++
++ /* This is the only SHAPE extension call- simple! */
++ XShapeCombineMask(dpy, win, ShapeBounding, 0, 0, shapeMask, ShapeSet);
++
++ XFreeGC(dpy, gc);
++ XFreePixmap(dpy, shapeMask);
++}
++
++
++/*
++ * Called when window is resized. Do OpenGL viewport and projection stuff.
++ */
++static void reshape(int width, int height)
++{
++ glViewport(0, 0, width, height);
++ glMatrixMode(GL_PROJECTION);
++ glLoadIdentity();
++ glFrustum(-1.0, 1.0, -1.0, 1.0, 3.0, 20.0);
++ glMatrixMode(GL_MODELVIEW);
++ glLoadIdentity();
++ glTranslatef(0.0, 0.0, -10.0);
++
++ glEnable(GL_DEPTH_TEST);
++}
++
++
++/*
++ * Process X events.
++ */
++static void event_loop(Display *dpy, Window win)
++{
++ while (1) {
++ XEvent event;
++ if (XPending(dpy)) {
++ XNextEvent(dpy, &event);
++ switch (event.type) {
++ case Expose:
++ display(dpy, event.xexpose.window);
++ break;
++ case ConfigureNotify:
++ Width = event.xconfigure.width;
++ Height = event.xconfigure.height,
++ make_shape_mask(dpy, win, Width, Height, Sides);
++ reshape(Width, Height);
++ break;
++ case KeyPress:
++ {
++ char buf[100];
++ KeySym keySym;
++ XComposeStatus stat;
++ XLookupString(&event.xkey, buf, sizeof(buf), &keySym, &stat);
++ switch (keySym) {
++ case XK_Escape:
++ exit(0);
++ break;
++ case XK_Up:
++ Sides++;
++ if (Sides>MaxSides) Sides = MaxSides;
++ make_shape_mask(dpy, win, Width, Height, Sides);
++ break;
++ case XK_Down:
++ Sides--;
++ if (Sides<MinSides) Sides = MinSides;
++ make_shape_mask(dpy, win, Width, Height, Sides);
++ break;
++ }
++ }
++ break;
++ default:
++ ;;
++ }
++ }
++ else {
++ static double t0 = -1.0;
++ double dt, t = current_time();
++ if (t0 < 0.0)
++ t0 = t;
++ dt = t - t0;
++ Xangle += 90.0 * dt; /* 90 degrees per second */
++ Yangle += 70.0 * dt;
++ t0 = t;
++ display(dpy, win);
++ }
++ }
++}
++
++
++/*
++ * Allocate a "nice" colormap. This could be better (HP-CR support, etc).
++ */
++static Colormap alloc_colormap(Display *dpy, Window parent, Visual *vis)
++{
++ Screen *scr = DefaultScreenOfDisplay(dpy);
++ int scrnum = DefaultScreen(dpy);
++
++ if (MaxCmapsOfScreen(scr)==1 && vis==DefaultVisual(dpy, scrnum)) {
++ /* The window and root are of the same visual type so */
++ /* share the root colormap. */
++ return DefaultColormap(dpy, scrnum);
++ }
++ else {
++ return XCreateColormap(dpy, parent, vis, AllocNone);
++ }
++}
++
++
++int main(int argc, char *argv[])
++{
++ static int glAttribs[] = {
++ GLX_DOUBLEBUFFER,
++ GLX_RGBA,
++ GLX_DEPTH_SIZE, 1,
++ None
++ };
++ Display *dpy;
++ XVisualInfo *visInfo;
++ int scrn;
++ Window root;
++ Colormap cmap;
++ Window win;
++ XSetWindowAttributes winAttribs;
++ unsigned long winAttribsMask;
++ GLXContext glCtx;
++ int ignore;
++ const char *name = "OpenGL in a Shaped Window";
++
++ dpy = XOpenDisplay(NULL);
++ if (!dpy) {
++ fprintf(stderr, "Couldn't open default display\n");
++ return 1;
++ }
++
++ /* check that we can use the shape extension */
++ if (!XQueryExtension(dpy, "SHAPE", &ignore, &ignore, &ignore )) {
++ fprintf(stderr, "Display doesn't support shape extension\n");
++ return 1;
++ }
++
++ scrn = DefaultScreen(dpy);
++
++ root = RootWindow(dpy, scrn);
++
++ visInfo = glXChooseVisual(dpy, scrn, glAttribs);
++ if (!visInfo) {
++ fprintf(stderr, "Couldn't get RGB, DB, Z visual\n");
++ return 1;
++ }
++
++ glCtx = glXCreateContext(dpy, visInfo, 0, True);
++ if (!glCtx) {
++ fprintf(stderr, "Couldn't create GL context\n");
++ return 1;
++ }
++
++ cmap = alloc_colormap(dpy, root, visInfo->visual);
++ if (!cmap) {
++ fprintf(stderr, "Couln't create colormap\n");
++ return 1;
++ }
++
++ winAttribs.border_pixel = 0;
++ winAttribs.colormap = cmap;
++ winAttribs.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
++ winAttribsMask = CWBorderPixel | CWColormap | CWEventMask;
++ win = XCreateWindow(dpy, root, 0, 0, Width, Height, 0,
++ visInfo->depth, InputOutput,
++ visInfo->visual,
++ winAttribsMask, &winAttribs);
++
++ {
++ XSizeHints sizehints;
++ /*
++ sizehints.x = xpos;
++ sizehints.y = ypos;
++ sizehints.width = width;
++ sizehints.height = height;
++ */
++ sizehints.flags = 0;
++ XSetNormalHints(dpy, win, &sizehints);
++ XSetStandardProperties(dpy, win, name, name,
++ None, (char **)NULL, 0, &sizehints);
++ }
++
++
++ XMapWindow(dpy, win);
++
++ glXMakeCurrent(dpy, win, glCtx);
++
++ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
++ printf("Press ESC to exit.\n");
++ printf("Press up/down to change window shape.\n");
++
++ event_loop(dpy, win);
++
++ return 0;
++}
+diff -Naurp Mesa-7.8.1/progs/xdemos/sharedtex.c Mesa-7.8.1.patched/progs/xdemos/sharedtex.c
+--- Mesa-7.8.1/progs/xdemos/sharedtex.c 1970-01-01 01:00:00.000000000 +0100
++++ Mesa-7.8.1.patched/progs/xdemos/sharedtex.c 2010-06-13 13:45:06.789793146 +0200
+@@ -0,0 +1,324 @@
++/*
++ * Test sharing of texture objects by two rendering contexts.
++ * In particular, test that changing a texture object in one context
++ * effects the texture in the second context.
++ *
++ * Brian Paul
++ * 30 Apr 2008
++ *
++ * Copyright (C) 2008 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 <GL/gl.h>
++#include <GL/glx.h>
++#include <assert.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <unistd.h>
++#include <X11/keysym.h>
++
++
++#define MAX_CONTEXTS 2
++
++#define TEX_SIZE 32
++
++static const char *DisplayName = NULL;
++static Display *Dpy;
++static XVisualInfo *VisInfo;
++static Window Win;
++static GLXContext Contexts[MAX_CONTEXTS];
++static int WinWidth = 300, WinHeight = 300;
++
++static int DrawContext = 0, TexContext = 1;
++
++static GLuint TexObj = 0;
++static GLboolean NewTexture = GL_FALSE;
++
++
++static void
++Error(const char *msg)
++{
++ fprintf(stderr, "sharedtex error: %s\n", msg);
++ exit(1);
++}
++
++
++static void
++CreateWindow(const char *name)
++{
++ int attrib[] = { GLX_RGBA,
++ GLX_RED_SIZE, 1,
++ GLX_GREEN_SIZE, 1,
++ GLX_BLUE_SIZE, 1,
++ GLX_DOUBLEBUFFER,
++ None };
++ int scrnum;
++ XSetWindowAttributes attr;
++ unsigned long mask;
++ Window root;
++ int xpos = 0, ypos = 0;
++ static int n = 0;
++
++ scrnum = DefaultScreen(Dpy);
++ root = RootWindow(Dpy, scrnum);
++
++ VisInfo = glXChooseVisual(Dpy, scrnum, attrib);
++ if (!VisInfo) {
++ Error("Unable to find RGB, double-buffered visual");
++ }
++
++ /* window attributes */
++ xpos = (n % 10) * 100;
++ ypos = (n / 10) * 100;
++ n++;
++
++ attr.background_pixel = 0;
++ attr.border_pixel = 0;
++ attr.colormap = XCreateColormap(Dpy, root, VisInfo->visual, AllocNone);
++ attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
++ mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
++
++ Win = XCreateWindow(Dpy, root, xpos, ypos, WinWidth, WinHeight,
++ 0, VisInfo->depth, InputOutput,
++ VisInfo->visual, mask, &attr);
++ if (!Win) {
++ Error("Couldn't create window");
++ }
++
++ {
++ XSizeHints sizehints;
++ sizehints.x = xpos;
++ sizehints.y = ypos;
++ sizehints.width = WinWidth;
++ sizehints.height = WinHeight;
++ sizehints.flags = USSize | USPosition;
++ XSetNormalHints(Dpy, Win, &sizehints);
++ XSetStandardProperties(Dpy, Win, name, name,
++ None, (char **)NULL, 0, &sizehints);
++ }
++
++ XMapWindow(Dpy, Win);
++}
++
++
++/**
++ * Change texture image, using TexContext
++ */
++static void
++ModifyTexture(void)
++{
++ GLuint tex[TEX_SIZE][TEX_SIZE];
++ GLuint c0, c1;
++ int i, j;
++
++ if (Win && !glXMakeCurrent(Dpy, Win, Contexts[TexContext])) {
++ Error("glXMakeCurrent failed");
++ }
++
++ /* choose two random colors */
++ c0 = rand() & 0xffffffff;
++ c1 = rand() & 0xffffffff;
++
++ for (i = 0; i < TEX_SIZE; i++) {
++ for (j = 0; j < TEX_SIZE; j++) {
++ if (((i / 4) ^ (j / 4)) & 1) {
++ tex[i][j] = c0;
++ }
++ else {
++ tex[i][j] = c1;
++ }
++ }
++ }
++
++ glBindTexture(GL_TEXTURE_2D, TexObj);
++ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TEX_SIZE, TEX_SIZE, 0,
++ GL_RGBA, GL_UNSIGNED_BYTE, tex);
++
++ NewTexture = GL_TRUE;
++}
++
++
++static void
++InitContext(void)
++{
++ glGenTextures(1, &TexObj);
++ assert(TexObj);
++ glBindTexture(GL_TEXTURE_2D, TexObj);
++ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
++ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
++ glEnable(GL_TEXTURE_2D);
++
++ printf("GL_RENDERER = %s\n", (char*) glGetString(GL_RENDERER));
++}
++
++
++static void
++Setup(void)
++{
++ int i;
++
++ Dpy = XOpenDisplay(DisplayName);
++ if (!Dpy) {
++ Error("Unable to open display");
++ }
++
++ CreateWindow("sharedtex");
++
++ for (i = 0; i < MAX_CONTEXTS; i++) {
++ GLXContext share = i > 0 ? Contexts[0] : 0;
++
++ Contexts[i] = glXCreateContext(Dpy, VisInfo, share, True);
++ if (!Contexts[i]) {
++ Error("Unable to create GLX context");
++ }
++
++ if (!glXMakeCurrent(Dpy, Win, Contexts[i])) {
++ Error("glXMakeCurrent failed");
++ }
++
++ InitContext();
++ }
++
++ ModifyTexture();
++}
++
++
++/**
++ * Redraw window, using DrawContext
++ */
++static void
++Redraw(void)
++{
++ static float rot = 0.0;
++ float ar;
++
++ rot += 1.0;
++
++ if (Win && !glXMakeCurrent(Dpy, Win, Contexts[DrawContext])) {
++ Error("glXMakeCurrent failed");
++ }
++
++ glViewport(0, 0, WinWidth, WinHeight);
++ ar = (float) WinWidth / (float) WinHeight;
++ glMatrixMode(GL_PROJECTION);
++ glLoadIdentity();
++ glOrtho(-ar, ar, -1.0, 1.0, -1.0, 1.0);
++ glMatrixMode(GL_MODELVIEW);
++
++ glShadeModel(GL_FLAT);
++ glClearColor(0.5, 0.5, 0.5, 1.0);
++ glClear(GL_COLOR_BUFFER_BIT);
++
++ glPushMatrix();
++ glRotatef(rot, 0, 0, 1);
++ glScalef(0.7, 0.7, 0.7);
++
++ if (NewTexture) {
++ /* rebind to get new contents */
++ glBindTexture(GL_TEXTURE_2D, TexObj);
++ NewTexture = GL_FALSE;
++ }
++
++ /* draw textured quad */
++ glBegin(GL_POLYGON);
++ glTexCoord2f( 0.0, 0.0 ); glVertex2f( -1.0, -1.0 );
++ glTexCoord2f( 1.0, 0.0 ); glVertex2f( 1.0, -1.0 );
++ glTexCoord2f( 1.0, 1.0 ); glVertex2f( 1.0, 1.0 );
++ glTexCoord2f( 0.0, 1.0 ); glVertex2f( -1.0, 1.0 );
++ glEnd();
++
++ glPopMatrix();
++
++ if (Win)
++ glXSwapBuffers(Dpy, Win);
++}
++
++
++static void
++EventLoop(void)
++{
++ while (1) {
++ while (XPending(Dpy) > 0) {
++ XEvent event;
++ XNextEvent(Dpy, &event);
++
++ switch (event.type) {
++ case Expose:
++ Redraw();
++ break;
++ case ConfigureNotify:
++ WinWidth = event.xconfigure.width;
++ WinHeight = event.xconfigure.height;
++ break;
++ case KeyPress:
++ {
++ char buf[100];
++ KeySym keySym;
++ XComposeStatus stat;
++ XLookupString(&event.xkey, buf, sizeof(buf), &keySym, &stat);
++ switch (keySym) {
++ case XK_Escape:
++ exit(0);
++ break;
++ case XK_t:
++ case XK_T:
++ ModifyTexture();
++ break;
++ default:
++ ;
++ }
++ }
++ Redraw();
++ break;
++ default:
++ /*no-op*/ ;
++ }
++ }
++
++ Redraw();
++ usleep(10000);
++ }
++}
++
++
++
++
++int
++main(int argc, char *argv[])
++{
++ int i;
++
++ for (i = 1; i < argc; i++) {
++ if (strcmp(argv[i], "-display") == 0 && i < argc) {
++ DisplayName = argv[i+1];
++ i++;
++ }
++ }
++
++ Setup();
++
++ printf("Press 't' to change texture image/colors\n");
++
++ EventLoop();
++
++ return 0;
++}
+diff -Naurp Mesa-7.8.1/progs/xdemos/sharedtex_mt.c Mesa-7.8.1.patched/progs/xdemos/sharedtex_mt.c
+--- Mesa-7.8.1/progs/xdemos/sharedtex_mt.c 1970-01-01 01:00:00.000000000 +0100
++++ Mesa-7.8.1.patched/progs/xdemos/sharedtex_mt.c 2010-06-13 13:45:06.788792936 +0200
+@@ -0,0 +1,490 @@
++/* $Id: sharedtex.c,v 1.2 2002/01/16 14:32:46 joukj Exp $ */
++
++/*
++ * Test sharing of display lists and texture objects between GLX contests.
++ * Brian Paul
++ * Summer 2000
++ *
++ *
++ * Copyright (C) 2000 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.
++ *
++ *
++ * Modified 2009 for multithreading by Thomas Hellstrom.
++ */
++
++
++#include <GL/gl.h>
++#include <GL/glx.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <unistd.h>
++#include <string.h>
++#include <pthread.h>
++#include <X11/X.h>
++
++struct thread_init_arg {
++ int id;
++};
++
++struct window {
++ pthread_mutex_t drawMutex;
++ char DisplayName[1000];
++ Display *Dpy;
++ Window Win;
++ GLXContext Context;
++ float Angle;
++ int Id;
++ XVisualInfo *visInfo;
++};
++
++
++#define MAX_WINDOWS 20
++static struct window Windows[MAX_WINDOWS];
++static int NumWindows = 0;
++static int terminate = 0;
++static GLXContext gCtx;
++static Display *gDpy;
++static GLuint Textures[3];
++
++
++
++static void
++Error(const char *display, const char *msg)
++{
++ fprintf(stderr, "Error on display %s - %s\n", display, msg);
++ exit(1);
++}
++
++
++static int
++initMainthread(Display *dpy, const char *displayName)
++{
++ int scrnum;
++ XVisualInfo *visinfo;
++ int attrib[] = { GLX_RGBA,
++ GLX_RED_SIZE, 1,
++ GLX_GREEN_SIZE, 1,
++ GLX_BLUE_SIZE, 1,
++ GLX_DOUBLEBUFFER,
++ GLX_DEPTH_SIZE, 1,
++ None };
++
++ scrnum = DefaultScreen(dpy);
++ visinfo = glXChooseVisual(dpy, scrnum, attrib);
++ if (!visinfo) {
++ Error(displayName, "Unable to find RGB, double-buffered visual");
++ return -1;
++ }
++ gCtx = glXCreateContext(dpy, visinfo, NULL, True);
++ if (!gCtx) {
++ Error(displayName, "Couldn't create GLX context");
++ return -1;
++ }
++ return 0;
++}
++
++static struct window *
++AddWindow(Display *dpy, const char *displayName, int xpos, int ypos,
++ GLXContext sCtx)
++{
++ Window win;
++ GLXContext ctx;
++ int attrib[] = { GLX_RGBA,
++ GLX_RED_SIZE, 1,
++ GLX_GREEN_SIZE, 1,
++ GLX_BLUE_SIZE, 1,
++ GLX_DOUBLEBUFFER,
++ GLX_DEPTH_SIZE, 1,
++ None };
++ int scrnum;
++ XSetWindowAttributes attr;
++ unsigned long mask;
++ Window root;
++ XVisualInfo *visinfo;
++ int width = 300, height = 300;
++
++ if (NumWindows >= MAX_WINDOWS)
++ return NULL;
++
++ scrnum = DefaultScreen(dpy);
++ root = RootWindow(dpy, scrnum);
++
++ visinfo = glXChooseVisual(dpy, scrnum, attrib);
++ if (!visinfo) {
++ Error(displayName, "Unable to find RGB, double-buffered visual");
++ return NULL;
++ }
++
++ /* window attributes */
++ attr.background_pixel = 0;
++ attr.border_pixel = 0;
++ attr.colormap = XCreateColormap(dpy, root, visinfo->visual, AllocNone);
++ attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
++ mask = CWBorderPixel | CWColormap | CWEventMask;
++
++ win = XCreateWindow(dpy, root, xpos, ypos, width, height,
++ 0, visinfo->depth, InputOutput,
++ visinfo->visual, mask, &attr);
++ if (!win) {
++ Error(displayName, "Couldn't create window");
++ return NULL;
++ }
++
++ {
++ XSizeHints sizehints;
++ sizehints.x = xpos;
++ sizehints.y = ypos;
++ sizehints.width = width;
++ sizehints.height = height;
++ sizehints.flags = USSize | USPosition;
++ XSetNormalHints(dpy, win, &sizehints);
++ XSetStandardProperties(dpy, win, displayName, displayName,
++ None, (char **)NULL, 0, &sizehints);
++ }
++
++
++ ctx = glXCreateContext(dpy, visinfo,
++ sCtx ? sCtx : NULL, True);
++
++ if (!ctx) {
++ Error(displayName, "Couldn't create GLX context");
++ return NULL;
++ }
++
++ XMapWindow(dpy, win);
++
++ /* save the info for this window */
++ {
++ static int id = 0;
++ struct window *h = &Windows[NumWindows];
++ if (strlen(displayName) + 1 > sizeof(h->DisplayName)) {
++ Error(displayName, "string overflow");
++ return NULL;
++ }
++ strcpy(h->DisplayName, displayName);
++ h->Dpy = dpy;
++ h->Win = win;
++ h->Context = ctx;
++ h->Angle = 0.0;
++ h->Id = id++;
++ h->visInfo = visinfo;
++ pthread_mutex_init(&h->drawMutex, NULL);
++ NumWindows++;
++ return &Windows[NumWindows-1];
++ }
++}
++
++
++static void
++InitGLstuff(void)
++
++{
++ glGenTextures(3, Textures);
++
++ /* setup first texture object */
++ {
++ GLubyte image[16][16][4];
++ GLint i, j;
++ glBindTexture(GL_TEXTURE_2D, Textures[0]);
++
++ /* red/white checkerboard */
++ for (i = 0; i < 16; i++) {
++ for (j = 0; j < 16; j++) {
++ if ((i ^ j) & 1) {
++ image[i][j][0] = 255;
++ image[i][j][1] = 255;
++ image[i][j][2] = 255;
++ image[i][j][3] = 255;
++ }
++ else {
++ image[i][j][0] = 255;
++ image[i][j][1] = 0;
++ image[i][j][2] = 0;
++ image[i][j][3] = 255;
++ }
++ }
++ }
++
++ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
++ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA,
++ GL_UNSIGNED_BYTE, image);
++ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
++ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
++ }
++
++ /* setup second texture object */
++ {
++ GLubyte image[8][8][3];
++ GLint i, j;
++ glBindTexture(GL_TEXTURE_2D, Textures[1]);
++
++ /* green/yellow checkerboard */
++ for (i = 0; i < 8; i++) {
++ for (j = 0; j < 8; j++) {
++ if ((i ^ j) & 1) {
++ image[i][j][0] = 0;
++ image[i][j][1] = 255;
++ image[i][j][2] = 0;
++ }
++ else {
++ image[i][j][0] = 255;
++ image[i][j][1] = 255;
++ image[i][j][2] = 0;
++ }
++ }
++ }
++
++ glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
++ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 8, 8, 0, GL_RGB,
++ GL_UNSIGNED_BYTE, image);
++ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
++ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
++ }
++
++ /* setup second texture object */
++ {
++ GLubyte image[4][4][3];
++ GLint i, j;
++ glBindTexture(GL_TEXTURE_2D, Textures[2]);
++
++ /* blue/gray checkerboard */
++ for (i = 0; i < 4; i++) {
++ for (j = 0; j < 4; j++) {
++ if ((i ^ j) & 1) {
++ image[i][j][0] = 0;
++ image[i][j][1] = 0;
++ image[i][j][2] = 255;
++ }
++ else {
++ image[i][j][0] = 200;
++ image[i][j][1] = 200;
++ image[i][j][2] = 200;
++ }
++ }
++ }
++
++ glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
++ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 4, 4, 0, GL_RGB,
++ GL_UNSIGNED_BYTE, image);
++ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
++ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
++ }
++
++ /* Now make the cube object display list */
++
++ 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));
++}
++
++static void
++Redraw(struct window *h)
++{
++ pthread_mutex_lock(&h->drawMutex);
++ if (!glXMakeCurrent(h->Dpy, h->Win, h->Context)) {
++ Error(h->DisplayName, "glXMakeCurrent failed in Redraw");
++ pthread_mutex_unlock(&h->drawMutex);
++ return;
++ }
++
++ h->Angle += 1.0;
++
++ glShadeModel(GL_FLAT);
++ glClearColor(0.25, 0.25, 0.25, 1.0);
++ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
++
++ glEnable(GL_TEXTURE_2D);
++ glEnable(GL_DEPTH_TEST);
++ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
++
++ glColor3f(1, 1, 1);
++
++ glPushMatrix();
++ if (h->Id == 0)
++ glRotatef(h->Angle, 0, 1, -1);
++ else if (h->Id == 1)
++ glRotatef(-(h->Angle), 0, 1, -1);
++ else if (h->Id == 2)
++ glRotatef(h->Angle, 0, 1, 1);
++ else if (h->Id == 3)
++ glRotatef(-(h->Angle), 0, 1, 1);
++ glBindTexture(GL_TEXTURE_2D, Textures[0]);
++ glBegin(GL_POLYGON);
++ glTexCoord2f(0, 0); glVertex3f(-1, -1, -1);
++ glTexCoord2f(1, 0); glVertex3f(-1, 1, -1);
++ glTexCoord2f(1, 1); glVertex3f(-1, 1, 1);
++ glTexCoord2f(0, 1); glVertex3f(-1, -1, 1);
++ glEnd();
++ glBegin(GL_POLYGON);
++ glTexCoord2f(0, 0); glVertex3f(1, -1, -1);
++ glTexCoord2f(1, 0); glVertex3f(1, 1, -1);
++ glTexCoord2f(1, 1); glVertex3f(1, 1, 1);
++ glTexCoord2f(0, 1); glVertex3f(1, -1, 1);
++ glEnd();
++
++ glBindTexture(GL_TEXTURE_2D, Textures[1]);
++ glBegin(GL_POLYGON);
++ glTexCoord2f(0, 0); glVertex3f(-1, -1, -1);
++ glTexCoord2f(1, 0); glVertex3f( 1, -1, -1);
++ glTexCoord2f(1, 1); glVertex3f( 1, -1, 1);
++ glTexCoord2f(0, 1); glVertex3f(-1, -1, 1);
++ glEnd();
++ glBegin(GL_POLYGON);
++ glTexCoord2f(0, 0); glVertex3f(-1, 1, -1);
++ glTexCoord2f(1, 0); glVertex3f( 1, 1, -1);
++ glTexCoord2f(1, 1); glVertex3f( 1, 1, 1);
++ glTexCoord2f(0, 1); glVertex3f(-1, 1, 1);
++ glEnd();
++
++ glBindTexture(GL_TEXTURE_2D, Textures[2]);
++ glBegin(GL_POLYGON);
++ glTexCoord2f(0, 0); glVertex3f(-1, -1, -1);
++ glTexCoord2f(1, 0); glVertex3f( 1, -1, -1);
++ glTexCoord2f(1, 1); glVertex3f( 1, 1, -1);
++ glTexCoord2f(0, 1); glVertex3f(-1, 1, -1);
++ glEnd();
++ glBegin(GL_POLYGON);
++ glTexCoord2f(0, 0); glVertex3f(-1, -1, 1);
++ glTexCoord2f(1, 0); glVertex3f( 1, -1, 1);
++ glTexCoord2f(1, 1); glVertex3f( 1, 1, 1);
++ glTexCoord2f(0, 1); glVertex3f(-1, 1, 1);
++ glEnd();
++
++ glPopMatrix();
++
++ glXSwapBuffers(h->Dpy, h->Win);
++
++ if (!glXMakeCurrent(h->Dpy, None, NULL)) {
++ Error(h->DisplayName, "glXMakeCurrent failed in Redraw");
++ }
++ pthread_mutex_unlock(&h->drawMutex);
++}
++
++static void *threadRunner (void *arg)
++{
++ struct thread_init_arg *tia = (struct thread_init_arg *) arg;
++ struct window *win;
++
++ win = &Windows[tia->id];
++
++ while(!terminate) {
++ usleep(1000);
++ Redraw(win);
++ }
++
++ return NULL;
++}
++
++static void
++Resize(struct window *h, unsigned int width, unsigned int height)
++{
++ pthread_mutex_lock(&h->drawMutex);
++
++ if (!glXMakeCurrent(h->Dpy, h->Win, h->Context)) {
++ Error(h->DisplayName, "glXMakeCurrent failed in Resize()");
++ pthread_mutex_unlock(&h->drawMutex);
++ return;
++ }
++
++ glViewport(0, 0, width, height);
++ glMatrixMode(GL_PROJECTION);
++ glLoadIdentity();
++ glFrustum(-1, 1, -1, 1, 2, 10);
++ glMatrixMode(GL_MODELVIEW);
++ glLoadIdentity();
++ glTranslatef(0, 0, -4.5);
++ if (!glXMakeCurrent(h->Dpy, None, NULL)) {
++ Error(h->DisplayName, "glXMakeCurrent failed in Resize()");
++ }
++ pthread_mutex_unlock(&h->drawMutex);
++}
++
++
++static void
++EventLoop(void)
++{
++ while (1) {
++ int i;
++ XEvent event;
++ XNextEvent(gDpy, &event);
++ for (i = 0; i < NumWindows; i++) {
++ struct window *h = &Windows[i];
++ if (event.xany.window == h->Win) {
++ switch (event.type) {
++ case Expose:
++ Redraw(h);
++ break;
++ case ConfigureNotify:
++ Resize(h, event.xconfigure.width, event.xconfigure.height);
++ break;
++ case KeyPress:
++ terminate = 1;
++ return;
++ default:
++ /*no-op*/ ;
++ }
++ }
++ }
++ }
++}
++
++int
++main(int argc, char *argv[])
++{
++ const char *dpyName = XDisplayName(NULL);
++ pthread_t t0, t1, t2, t3;
++ struct thread_init_arg tia0, tia1, tia2, tia3;
++ struct window *h0;
++
++ XInitThreads();
++
++ gDpy = XOpenDisplay(dpyName);
++ if (!gDpy) {
++ Error(dpyName, "Unable to open display");
++ return -1;
++ }
++
++ if (initMainthread(gDpy, dpyName))
++ return -1;
++
++ /* four windows and contexts sharing display lists and texture objects */
++ h0 = AddWindow(gDpy, dpyName, 10, 10, gCtx);
++ (void) AddWindow(gDpy, dpyName, 330, 10, gCtx);
++ (void) AddWindow(gDpy, dpyName, 10, 350, gCtx);
++ (void) AddWindow(gDpy, dpyName, 330, 350, gCtx);
++
++ if (!glXMakeCurrent(gDpy, h0->Win, gCtx)) {
++ Error(dpyName, "glXMakeCurrent failed for init thread.");
++ return -1;
++ }
++
++ InitGLstuff();
++
++ tia0.id = 0;
++ pthread_create(&t0, NULL, threadRunner, &tia0);
++ tia1.id = 1;
++ pthread_create(&t1, NULL, threadRunner, &tia1);
++ tia2.id = 2;
++ pthread_create(&t2, NULL, threadRunner, &tia2);
++ tia3.id = 3;
++ pthread_create(&t3, NULL, threadRunner, &tia3);
++ EventLoop();
++ return 0;
++}
+diff -Naurp Mesa-7.8.1/progs/xdemos/texture_from_pixmap.c Mesa-7.8.1.patched/progs/xdemos/texture_from_pixmap.c
+--- Mesa-7.8.1/progs/xdemos/texture_from_pixmap.c 1970-01-01 01:00:00.000000000 +0100
++++ Mesa-7.8.1.patched/progs/xdemos/texture_from_pixmap.c 2010-06-13 13:45:06.789793146 +0200
+@@ -0,0 +1,396 @@
++/*
++ * Mesa 3-D graphics library
++ * Version: 7.1
++ *
++ * Copyright (C) 1999-2007 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.
++ */
++
++
++/*
++ * Test the GLX_EXT_texture_from_pixmap extension
++ * Brian Paul
++ * 19 May 2007
++ */
++
++
++#define GL_GLEXT_PROTOTYPES
++#define GLX_GLXEXT_PROTOTYPES
++#include <GL/gl.h>
++#include <GL/glx.h>
++#include <X11/keysym.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <unistd.h>
++
++
++static float top, bottom;
++
++static PFNGLXBINDTEXIMAGEEXTPROC glXBindTexImageEXT_func = NULL;
++static PFNGLXRELEASETEXIMAGEEXTPROC glXReleaseTexImageEXT_func = NULL;
++
++
++static Display *
++OpenDisplay(void)
++{
++ int screen;
++ Display *dpy;
++ const char *ext;
++
++ dpy = XOpenDisplay(NULL);
++ if (!dpy) {
++ printf("Couldn't open default display!\n");
++ exit(1);
++ }
++
++ screen = DefaultScreen(dpy);
++ ext = glXQueryExtensionsString(dpy, screen);
++ if (!strstr(ext, "GLX_EXT_texture_from_pixmap")) {
++ fprintf(stderr, "GLX_EXT_texture_from_pixmap not supported.\n");
++ exit(1);
++ }
++
++ glXBindTexImageEXT_func = (PFNGLXBINDTEXIMAGEEXTPROC)
++ glXGetProcAddress((GLubyte *) "glXBindTexImageEXT");
++ glXReleaseTexImageEXT_func = (PFNGLXRELEASETEXIMAGEEXTPROC)
++ glXGetProcAddress((GLubyte*) "glXReleaseTexImageEXT");
++
++ if (!glXBindTexImageEXT_func || !glXReleaseTexImageEXT_func) {
++ fprintf(stderr, "glXGetProcAddress failed!\n");
++ exit(1);
++ }
++
++ return dpy;
++}
++
++
++static GLXFBConfig
++ChoosePixmapFBConfig(Display *display)
++{
++ int screen = DefaultScreen(display);
++ GLXFBConfig *fbconfigs;
++ int i, nfbconfigs = 0, value;
++
++ fbconfigs = glXGetFBConfigs(display, screen, &nfbconfigs);
++ for (i = 0; i < nfbconfigs; i++) {
++
++ glXGetFBConfigAttrib(display, fbconfigs[i], GLX_DRAWABLE_TYPE, &value);
++ if (!(value & GLX_PIXMAP_BIT))
++ continue;
++
++ glXGetFBConfigAttrib(display, fbconfigs[i],
++ GLX_BIND_TO_TEXTURE_TARGETS_EXT, &value);
++ if (!(value & GLX_TEXTURE_2D_BIT_EXT))
++ continue;
++
++ glXGetFBConfigAttrib(display, fbconfigs[i],
++ GLX_BIND_TO_TEXTURE_RGBA_EXT, &value);
++ if (value == False) {
++ glXGetFBConfigAttrib(display, fbconfigs[i],
++ GLX_BIND_TO_TEXTURE_RGB_EXT, &value);
++ if (value == False)
++ continue;
++ }
++
++ glXGetFBConfigAttrib(display, fbconfigs[i],
++ GLX_Y_INVERTED_EXT, &value);
++ if (value == True) {
++ top = 0.0f;
++ bottom = 1.0f;
++ }
++ else {
++ top = 1.0f;
++ bottom = 0.0f;
++ }
++
++ break;
++ }
++
++ if (i == nfbconfigs) {
++ printf("Unable to find FBconfig for texturing\n");
++ exit(1);
++ }
++
++ return fbconfigs[i];
++}
++
++
++static GLXPixmap
++CreatePixmap(Display *dpy, GLXFBConfig config, int w, int h, Pixmap *p)
++{
++ GLXPixmap gp;
++ const int pixmapAttribs[] = {
++ GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
++ GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGB_EXT,
++ None
++ };
++ Window root = RootWindow(dpy, 0);
++
++ *p = XCreatePixmap(dpy, root, w, h, 24);
++ XSync(dpy, 0);
++ gp = glXCreatePixmap(dpy, config, *p, pixmapAttribs);
++ XSync(dpy, 0);
++
++ return gp;
++}
++
++
++static void
++DrawPixmapImage(Display *dpy, Pixmap pm, int w, int h)
++{
++ XGCValues gcvals;
++ GC gc;
++
++ gcvals.background = 0;
++ gc = XCreateGC(dpy, pm, GCBackground, &gcvals);
++
++ XSetForeground(dpy, gc, 0x0);
++ XFillRectangle(dpy, pm, gc, 0, 0, w, h);
++
++ XSetForeground(dpy, gc, 0xff0000);
++ XFillRectangle(dpy, pm, gc, 0, 0, 50, 50);
++
++ XSetForeground(dpy, gc, 0x00ff00);
++ XFillRectangle(dpy, pm, gc, w - 50, 0, 50, 50);
++
++ XSetForeground(dpy, gc, 0x0000ff);
++ XFillRectangle(dpy, pm, gc, 0, h - 50, 50, 50);
++
++ XSetForeground(dpy, gc, 0xffffff);
++ XFillRectangle(dpy, pm, gc, h - 50, h - 50, 50, 50);
++
++ XSetForeground(dpy, gc, 0xffff00);
++ XSetLineAttributes(dpy, gc, 3, LineSolid, CapButt, JoinBevel);
++ XDrawLine(dpy, pm, gc, 0, 0, w, h);
++ XDrawLine(dpy, pm, gc, 0, h, w, 0);
++
++ XFreeGC(dpy, gc);
++}
++
++
++static XVisualInfo *
++ChooseWindowVisual(Display *dpy)
++{
++ int screen = DefaultScreen(dpy);
++ XVisualInfo *visinfo;
++ int attribs[] = {
++ GLX_RGBA,
++ GLX_RED_SIZE, 1,
++ GLX_GREEN_SIZE, 1,
++ GLX_BLUE_SIZE, 1,
++ GLX_DOUBLEBUFFER,
++ None
++ };
++
++ visinfo = glXChooseVisual(dpy, screen, attribs);
++ if (!visinfo) {
++ printf("Unable to find RGB, double-buffered visual\n");
++ exit(1);
++ }
++
++ return visinfo;
++}
++
++
++static Window
++CreateWindow(Display *dpy, XVisualInfo *visinfo,
++ int width, int height, const char *name)
++{
++ int screen = DefaultScreen(dpy);
++ Window win;
++ XSetWindowAttributes attr;
++ unsigned long mask;
++ Window root;
++
++ root = RootWindow(dpy, screen);
++
++ /* window attributes */
++ attr.background_pixel = 0;
++ attr.border_pixel = 0;
++ attr.colormap = XCreateColormap(dpy, root, visinfo->visual, AllocNone);
++ attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
++ mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
++
++ win = XCreateWindow(dpy, root, 0, 0, width, height,
++ 0, visinfo->depth, InputOutput,
++ visinfo->visual, mask, &attr);
++ if (win) {
++ XSizeHints sizehints;
++ sizehints.width = width;
++ sizehints.height = height;
++ sizehints.flags = USSize;
++ XSetNormalHints(dpy, win, &sizehints);
++ XSetStandardProperties(dpy, win, name, name,
++ None, (char **)NULL, 0, &sizehints);
++
++ XMapWindow(dpy, win);
++ }
++ return win;
++}
++
++
++static void
++BindPixmapTexture(Display *dpy, GLXPixmap gp)
++{
++ GLuint texture;
++
++ glGenTextures(1, &texture);
++ glBindTexture(GL_TEXTURE_2D, texture);
++
++ glXBindTexImageEXT_func(dpy, gp, GLX_FRONT_LEFT_EXT, NULL);
++
++ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
++ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
++
++ glEnable(GL_TEXTURE_2D);
++ /*
++ glXReleaseTexImageEXT_func(display, glxpixmap, GLX_FRONT_LEFT_EXT);
++ */
++}
++
++
++static void
++Resize(Window win, unsigned int width, unsigned int height)
++{
++ float sz = 1.5;
++ glViewport(0, 0, width, height);
++ glMatrixMode(GL_PROJECTION);
++ glLoadIdentity();
++ glOrtho(-sz, sz, -sz, sz, -1.0, 1.0);
++ glMatrixMode(GL_MODELVIEW);
++}
++
++
++static void
++Redraw(Display *dpy, Window win, float rot)
++{
++ glClearColor(0.25, 0.25, 0.25, 0.0);
++ glClear(GL_COLOR_BUFFER_BIT);
++ glPushMatrix();
++ glRotatef(rot, 0, 0, 1);
++ glRotatef(2.0 * rot, 1, 0, 0);
++
++ glBegin(GL_QUADS);
++ glTexCoord2d(0.0, bottom);
++ glVertex2f(-1, -1);
++ glTexCoord2d(1.0, bottom);
++ glVertex2f( 1, -1);
++ glTexCoord2d(1.0, top);
++ glVertex2d(1.0, 1.0);
++ glTexCoord2d(0.0, top);
++ glVertex2f(-1.0, 1.0);
++ glEnd();
++
++ glPopMatrix();
++
++ glXSwapBuffers(dpy, win);
++}
++
++
++static void
++EventLoop(Display *dpy, Window win)
++{
++ GLfloat rot = 0.0;
++ int anim = 0;
++
++ while (1) {
++ if (!anim || XPending(dpy) > 0) {
++ XEvent event;
++ XNextEvent(dpy, &event);
++
++ switch (event.type) {
++ case Expose:
++ Redraw(dpy, win, rot);
++ break;
++ case ConfigureNotify:
++ Resize(event.xany.window,
++ event.xconfigure.width,
++ event.xconfigure.height);
++ break;
++ case KeyPress:
++ {
++ char buf[100];
++ KeySym keySym;
++ XComposeStatus stat;
++ XLookupString(&event.xkey, buf, sizeof(buf), &keySym, &stat);
++ if (keySym == XK_Escape) {
++ return; /* exit */
++ }
++ else if (keySym == XK_r) {
++ rot += 1.0;
++ Redraw(dpy, win, rot);
++ }
++ else if (keySym == XK_a) {
++ anim = !anim;
++ }
++ else if (keySym == XK_R) {
++ rot -= 1.0;
++ Redraw(dpy, win, rot);
++ }
++ }
++ break;
++ default:
++ ; /*no-op*/
++ }
++ }
++ else {
++ /* animate */
++ rot += 1.0;
++ Redraw(dpy, win, rot);
++ }
++ }
++}
++
++
++
++int
++main(int argc, char *argv[])
++{
++ Display *dpy;
++ GLXFBConfig pixmapConfig;
++ XVisualInfo *windowVis;
++ GLXPixmap gp;
++ Window win;
++ GLXContext ctx;
++ Pixmap p;
++
++ dpy = OpenDisplay();
++
++ pixmapConfig = ChoosePixmapFBConfig(dpy);
++ windowVis = ChooseWindowVisual(dpy);
++ win = CreateWindow(dpy, windowVis, 500, 500, "Texture From Pixmap");
++
++ gp = CreatePixmap(dpy, pixmapConfig, 512, 512, &p);
++ DrawPixmapImage(dpy, p, 512, 512);
++
++ ctx = glXCreateContext(dpy, windowVis, NULL, True);
++ if (!ctx) {
++ printf("Couldn't create GLX context\n");
++ exit(1);
++ }
++
++ glXMakeCurrent(dpy, win, ctx);
++
++ BindPixmapTexture(dpy, gp);
++
++ EventLoop(dpy, win);
++
++ return 0;
++}
+diff -Naurp Mesa-7.8.1/progs/xdemos/wincopy.c Mesa-7.8.1.patched/progs/xdemos/wincopy.c
+--- Mesa-7.8.1/progs/xdemos/wincopy.c 1970-01-01 01:00:00.000000000 +0100
++++ Mesa-7.8.1.patched/progs/xdemos/wincopy.c 2010-06-13 13:45:06.789793146 +0200
+@@ -0,0 +1,328 @@
++/*
++ * Mesa 3-D graphics library
++ * Version: 6.5.2
++ *
++ * Copyright (C) 1999-2006 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.
++ */
++
++
++/*
++ * This program opens two GLX windows, renders into one and uses
++ * glCopyPixels to copy the image from the first window into the
++ * second by means of the GLX 1.3 function glxMakeContextCurrent().
++ * This function works just like the glXMakeCurrentReadSGI() function
++ * in the GLX_SGI_make_current_read extension.
++ */
++
++
++#define GL_GLEXT_PROTOTYPES
++#define GLX_GLXEXT_PROTOTYPES
++#include <GL/gl.h>
++#include <GL/glx.h>
++#include <X11/keysym.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <unistd.h>
++
++
++#ifdef GLX_VERSION_1_3
++
++
++static Display *Dpy;
++static int ScrNum;
++static GLXContext Context;
++static Window Win[2]; /* Win[0] = source, Win[1] = dest */
++static GLint Width[2], Height[2];
++static GLboolean TestClipping = GL_FALSE;
++static GLfloat Angle = 0.0;
++
++static GLboolean DrawFront = GL_FALSE;
++
++PFNGLXMAKECURRENTREADSGIPROC make_context_current = NULL;
++
++static Window
++CreateWindow(Display *dpy, int scrnum, XVisualInfo *visinfo,
++ int xpos, int ypos, int width, int height,
++ const char *name)
++{
++ Window win;
++ XSetWindowAttributes attr;
++ unsigned long mask;
++ Window root;
++
++ root = RootWindow(dpy, scrnum);
++
++ /* window attributes */
++ attr.background_pixel = 0;
++ attr.border_pixel = 0;
++ attr.colormap = XCreateColormap(dpy, root, visinfo->visual, AllocNone);
++ attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
++ mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
++
++ win = XCreateWindow(dpy, root, xpos, ypos, width, height,
++ 0, visinfo->depth, InputOutput,
++ visinfo->visual, mask, &attr);
++ if (win) {
++ XSizeHints sizehints;
++ sizehints.x = xpos;
++ sizehints.y = ypos;
++ sizehints.width = width;
++ sizehints.height = height;
++ sizehints.flags = USSize | USPosition;
++ XSetNormalHints(dpy, win, &sizehints);
++ XSetStandardProperties(dpy, win, name, name,
++ None, (char **)NULL, 0, &sizehints);
++
++ XMapWindow(dpy, win);
++ }
++ return win;
++}
++
++
++static void
++Redraw(void)
++{
++ /* make the first window the current one */
++ if (! (*make_context_current)(Dpy, Win[0], Win[0], Context)) {
++ printf("glXMakeContextCurrent failed in Redraw()\n");
++ return;
++ }
++
++ Angle += 1.0;
++
++ if (DrawFront) {
++ glDrawBuffer(GL_FRONT);
++ glReadBuffer(GL_FRONT);
++ }
++ else {
++ glDrawBuffer(GL_BACK);
++ glReadBuffer(GL_BACK);
++ }
++
++ glViewport(0, 0, Width[0], Height[0]);
++ glMatrixMode(GL_PROJECTION);
++ glLoadIdentity();
++ glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
++ glMatrixMode(GL_MODELVIEW);
++
++ glShadeModel(GL_FLAT);
++ glClearColor(0.5, 0.5, 0.5, 0.0);
++ glClear(GL_COLOR_BUFFER_BIT);
++
++ /* draw blue quad */
++ glColor3f(0.3, 0.3, 1.0);
++ glPushMatrix();
++ glRotatef(Angle, 0, 0, 1);
++ glBegin(GL_POLYGON);
++ glVertex2f(-0.5, -0.25);
++ glVertex2f( 0.5, -0.25);
++ glVertex2f( 0.5, 0.25);
++ glVertex2f(-0.5, 0.25);
++ glEnd();
++ glPopMatrix();
++
++ if (DrawFront)
++ glFinish();
++ else
++ glXSwapBuffers(Dpy, Win[0]);
++
++
++ /* copy image from window 0 to window 1 */
++ if (!(*make_context_current)(Dpy, Win[1], Win[0], Context)) {
++ printf("glXMakeContextCurrent failed in Redraw()\n");
++ return;
++ }
++
++ /* copy the image between windows */
++ glClearColor(0.0, 0.0, 0.0, 0.0);
++ glClear(GL_COLOR_BUFFER_BIT);
++
++ if (TestClipping) {
++ glWindowPos2iARB(-2, -2);
++ glCopyPixels(-2, -2, Width[0] + 4, Height[0] + 4, GL_COLOR);
++ }
++ else {
++ glWindowPos2iARB(0, 0);
++ glCopyPixels(0, 0, Width[0], Height[0], GL_COLOR);
++ }
++
++ if (DrawFront)
++ glFinish();
++ else
++ glXSwapBuffers(Dpy, Win[1]);
++}
++
++
++
++static void
++Resize(Window win, unsigned int width, unsigned int height)
++{
++ int i;
++ if (win == Win[0]) {
++ i = 0;
++ }
++ else {
++ i = 1;
++ }
++ Width[i] = width;
++ Height[i] = height;
++ if (!glXMakeCurrent(Dpy, Win[i], Context)) {
++ printf("glXMakeCurrent failed in Resize()\n");
++ return;
++ }
++}
++
++
++
++static void
++EventLoop(void)
++{
++ XEvent event;
++ while (1) {
++ if (XPending(Dpy) > 0) {
++ XNextEvent( Dpy, &event );
++ switch (event.type) {
++ case Expose:
++ Redraw();
++ break;
++ case ConfigureNotify:
++ Resize(event.xany.window, event.xconfigure.width, event.xconfigure.height);
++ break;
++ case KeyPress:
++ {
++ char buf[100];
++ KeySym keySym;
++ XComposeStatus stat;
++ XLookupString(&event.xkey, buf, sizeof(buf), &keySym, &stat);
++ if (keySym == XK_Escape) {
++ /* exit */
++ return;
++ }
++ else if (buf[0] == 'f') {
++ DrawFront = !DrawFront;
++ printf("Drawing to %s buffer\n",
++ DrawFront ? "GL_FRONT" : "GL_BACK");
++ }
++ }
++ break;
++ default:
++ /*no-op*/ ;
++ }
++ }
++ else {
++ /* animate */
++ Redraw();
++ }
++ }
++}
++
++
++static void
++Init(void)
++{
++ XVisualInfo *visinfo;
++ int attrib[] = { GLX_RGBA,
++ GLX_RED_SIZE, 1,
++ GLX_GREEN_SIZE, 1,
++ GLX_BLUE_SIZE, 1,
++ GLX_DOUBLEBUFFER,
++ None };
++ int major, minor;
++
++ Dpy = XOpenDisplay(NULL);
++ if (!Dpy) {
++ printf("Couldn't open default display!\n");
++ exit(1);
++ }
++
++ ScrNum = DefaultScreen(Dpy);
++
++ glXQueryVersion(Dpy, &major, &minor);
++
++ if (major * 100 + minor >= 103) {
++ make_context_current = (PFNGLXMAKECURRENTREADSGIPROC)
++ glXGetProcAddressARB( (GLubyte *) "glXMakeContextCurrent" );
++ }
++ else {
++ const char * const glxExtensions = glXQueryExtensionsString(Dpy, ScrNum);
++ const char * ext = strstr( glxExtensions, "GLX_SGI_make_current_read" );
++ const size_t len = strlen( "GLX_SGI_make_current_read" );
++
++ if ( (ext != NULL)
++ && ((ext[len] == ' ') || (ext[len] == '\0')) ) {
++ make_context_current = (PFNGLXMAKECURRENTREADSGIPROC)
++ glXGetProcAddressARB( (GLubyte *) "glXMakeCurrentReadSGI" );
++ }
++ }
++
++ if (make_context_current == NULL) {
++ fprintf(stderr, "Sorry, this program requires either GLX 1.3 "
++ "or GLX_SGI_make_current_read.\n");
++ exit(1);
++ }
++
++ visinfo = glXChooseVisual(Dpy, ScrNum, attrib);
++ if (!visinfo) {
++ printf("Unable to find RGB, double-buffered visual\n");
++ exit(1);
++ }
++
++ Context = glXCreateContext(Dpy, visinfo, NULL, True);
++ if (!Context) {
++ printf("Couldn't create GLX context\n");
++ exit(1);
++ }
++
++
++ Win[0] = CreateWindow(Dpy, ScrNum, visinfo,
++ 0, 0, 300, 300, "source window");
++
++ Win[1] = CreateWindow(Dpy, ScrNum, visinfo,
++ 350, 0, 300, 300, "dest window");
++
++ printf("Press Esc to exit\n");
++ printf("Press 'f' to toggle front/back buffer drawing\n");
++}
++
++
++int
++main(int argc, char *argv[])
++{
++ if (argc > 1 && strcmp(argv[1], "-clip") == 0)
++ TestClipping = GL_TRUE;
++ Init();
++ EventLoop();
++ return 0;
++}
++
++
++#else
++
++
++int
++main(int argc, char *argv[])
++{
++ printf("This program requires GLX 1.3!\n");
++ return 0;
++}
++
++
++#endif /* GLX_VERSION_1_3 */
+diff -Naurp Mesa-7.8.1/progs/xdemos/xdemo.c Mesa-7.8.1.patched/progs/xdemos/xdemo.c
+--- Mesa-7.8.1/progs/xdemos/xdemo.c 1970-01-01 01:00:00.000000000 +0100
++++ Mesa-7.8.1.patched/progs/xdemos/xdemo.c 2010-06-13 13:45:06.788792936 +0200
+@@ -0,0 +1,334 @@
++
++/*
++ * Very simple demo of how to use the Mesa/X11 interface instead of the
++ * glx, tk or aux toolkits. I highly recommend using the GLX interface
++ * instead of the X/Mesa interface, however.
++ *
++ * This program is in the public domain.
++ *
++ * Brian Paul
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <X11/Xlib.h>
++#include <X11/Xutil.h>
++#include "GL/xmesa.h"
++#include "GL/gl.h"
++
++
++
++static GLint Black, Red, Green, Blue;
++
++
++
++static void make_window( char *title, int color_flag )
++{
++ int x = 10, y = 10, width = 400, height = 300;
++ Display *dpy;
++ int scr;
++ Window root, win;
++ Colormap cmap;
++ XColor xcolor;
++ int attr_flags;
++ XVisualInfo *visinfo;
++ XSetWindowAttributes attr;
++ XTextProperty tp;
++ XSizeHints sh;
++ XEvent e;
++ XMesaContext context;
++ XMesaVisual visual;
++ XMesaBuffer buffer;
++
++
++ /*
++ * Do the usual X things to make a window.
++ */
++
++ dpy = XOpenDisplay(NULL);
++ if (!dpy) {
++ printf("Couldn't open default display!\n");
++ exit(1);
++ }
++
++ scr = DefaultScreen(dpy);
++ root = RootWindow(dpy, scr);
++
++ /* alloc visinfo struct */
++ visinfo = (XVisualInfo *) malloc( sizeof(XVisualInfo) );
++
++ /* Get a visual and colormap */
++ if (color_flag) {
++ /* Open TrueColor window */
++
++/*
++ if (!XMatchVisualInfo( dpy, scr, 24, TrueColor, visinfo )) {
++ printf("Couldn't get 24-bit TrueColor visual!\n");
++ exit(1);
++ }
++*/
++ if (!XMatchVisualInfo( dpy, scr, 8, PseudoColor, visinfo )) {
++ printf("Couldn't get 8-bit PseudoColor visual!\n");
++ exit(1);
++ }
++
++ cmap = XCreateColormap( dpy, root, visinfo->visual, AllocNone );
++ Black = Red = Green = Blue = 0;
++ }
++ else {
++ /* Open color index window */
++
++ if (!XMatchVisualInfo( dpy, scr, 8, PseudoColor, visinfo )) {
++ printf("Couldn't get 8-bit PseudoColor visual\n");
++ exit(1);
++ }
++
++ cmap = XCreateColormap( dpy, root, visinfo->visual, AllocNone );
++
++ /* Allocate colors */
++ xcolor.red = 0x0;
++ xcolor.green = 0x0;
++ xcolor.blue = 0x0;
++ xcolor.flags = DoRed | DoGreen | DoBlue;
++ if (!XAllocColor( dpy, cmap, &xcolor )) {
++ printf("Couldn't allocate black!\n");
++ exit(1);
++ }
++ Black = xcolor.pixel;
++
++ xcolor.red = 0xffff;
++ xcolor.green = 0x0;
++ xcolor.blue = 0x0;
++ xcolor.flags = DoRed | DoGreen | DoBlue;
++ if (!XAllocColor( dpy, cmap, &xcolor )) {
++ printf("Couldn't allocate red!\n");
++ exit(1);
++ }
++ Red = xcolor.pixel;
++
++ xcolor.red = 0x0;
++ xcolor.green = 0xffff;
++ xcolor.blue = 0x0;
++ xcolor.flags = DoRed | DoGreen | DoBlue;
++ if (!XAllocColor( dpy, cmap, &xcolor )) {
++ printf("Couldn't allocate green!\n");
++ exit(1);
++ }
++ Green = xcolor.pixel;
++
++ xcolor.red = 0x0;
++ xcolor.green = 0x0;
++ xcolor.blue = 0xffff;
++ xcolor.flags = DoRed | DoGreen | DoBlue;
++ if (!XAllocColor( dpy, cmap, &xcolor )) {
++ printf("Couldn't allocate blue!\n");
++ exit(1);
++ }
++ Blue = xcolor.pixel;
++ }
++
++ /* set window attributes */
++ attr.colormap = cmap;
++ attr.event_mask = ExposureMask | StructureNotifyMask;
++ attr.border_pixel = BlackPixel( dpy, scr );
++ attr.background_pixel = BlackPixel( dpy, scr );
++ attr_flags = CWColormap | CWEventMask | CWBorderPixel | CWBackPixel;
++
++ /* Create the window */
++ win = XCreateWindow( dpy, root, x,y, width, height, 0,
++ visinfo->depth, InputOutput,
++ visinfo->visual,
++ attr_flags, &attr);
++ if (!win) {
++ printf("Couldn't open window!\n");
++ exit(1);
++ }
++
++ XStringListToTextProperty(&title, 1, &tp);
++ sh.flags = USPosition | USSize;
++ XSetWMProperties(dpy, win, &tp, &tp, 0, 0, &sh, 0, 0);
++ XMapWindow(dpy, win);
++ while (1) {
++ XNextEvent( dpy, &e );
++ if (e.type == MapNotify && e.xmap.window == win) {
++ break;
++ }
++ }
++
++
++ /*
++ * Now do the special Mesa/Xlib stuff!
++ */
++
++ visual = XMesaCreateVisual( dpy, visinfo,
++ (GLboolean) color_flag,
++ GL_FALSE, /* alpha_flag */
++ GL_FALSE, /* db_flag */
++ GL_FALSE, /* stereo flag */
++ GL_FALSE, /* ximage_flag */
++ 0, /* depth size */
++ 0, /* stencil size */
++ 0,0,0,0, /* accum_size */
++ 0, /* num samples */
++ 0, /* level */
++ 0 /* caveat */
++ );
++ if (!visual) {
++ printf("Couldn't create Mesa/X visual!\n");
++ exit(1);
++ }
++
++ /* Create a Mesa rendering context */
++ context = XMesaCreateContext( visual,
++ NULL /* share_list */
++ );
++ if (!context) {
++ printf("Couldn't create Mesa/X context!\n");
++ exit(1);
++ }
++
++ buffer = XMesaCreateWindowBuffer( visual, win );
++ if (!buffer) {
++ printf("Couldn't create Mesa/X buffer!\n");
++ exit(1);
++ }
++
++
++ XMesaMakeCurrent( context, buffer );
++
++ /* Ready to render! */
++}
++
++
++
++static void draw_cube( void )
++{
++ /* X faces */
++ glIndexi( Red );
++ glColor3f( 1.0, 0.0, 0.0 );
++ glBegin( GL_POLYGON );
++ glVertex3f( 1.0, 1.0, 1.0 );
++ glVertex3f( 1.0, -1.0, 1.0 );
++ glVertex3f( 1.0, -1.0, -1.0 );
++ glVertex3f( 1.0, 1.0, -1.0 );
++ glEnd();
++
++ glBegin( GL_POLYGON );
++ glVertex3f( -1.0, 1.0, 1.0 );
++ glVertex3f( -1.0, 1.0, -1.0 );
++ glVertex3f( -1.0, -1.0, -1.0 );
++ glVertex3f( -1.0, -1.0, 1.0 );
++ glEnd();
++
++ /* Y faces */
++ glIndexi( Green );
++ glColor3f( 0.0, 1.0, 0.0 );
++ glBegin( GL_POLYGON );
++ glVertex3f( 1.0, 1.0, 1.0 );
++ glVertex3f( 1.0, 1.0, -1.0 );
++ glVertex3f( -1.0, 1.0, -1.0 );
++ glVertex3f( -1.0, 1.0, 1.0 );
++ glEnd();
++
++ glBegin( GL_POLYGON );
++ glVertex3f( 1.0, -1.0, 1.0 );
++ glVertex3f( -1.0, -1.0, 1.0 );
++ glVertex3f( -1.0, -1.0, -1.0 );
++ glVertex3f( 1.0, -1.0, -1.0 );
++ glEnd();
++
++ /* Z faces */
++ glIndexi( Blue );
++ glColor3f( 0.0, 0.0, 1.0 );
++ glBegin( GL_POLYGON );
++ glVertex3f( 1.0, 1.0, 1.0 );
++ glVertex3f( -1.0, 1.0, 1.0 );
++ glVertex3f( -1.0, -1.0, 1.0 );
++ glVertex3f( 1.0, -1.0, 1.0 );
++ glEnd();
++
++ glBegin( GL_POLYGON );
++ glVertex3f( 1.0, 1.0, -1.0 );
++ glVertex3f( 1.0,-1.0, -1.0 );
++ glVertex3f( -1.0,-1.0, -1.0 );
++ glVertex3f( -1.0, 1.0, -1.0 );
++ glEnd();
++}
++
++
++
++
++static void display_loop( void )
++{
++ GLfloat xrot, yrot, zrot;
++
++ xrot = yrot = zrot = 0.0;
++
++ glClearColor( 0.0, 0.0, 0.0, 0.0 );
++ glClearIndex( Black );
++
++ glMatrixMode( GL_PROJECTION );
++ glLoadIdentity();
++ glFrustum( -1.0, 1.0, -1.0, 1.0, 1.0, 10.0 );
++ glTranslatef( 0.0, 0.0, -5.0 );
++
++ glMatrixMode( GL_MODELVIEW );
++ glLoadIdentity();
++
++ glCullFace( GL_BACK );
++ glEnable( GL_CULL_FACE );
++
++ glShadeModel( GL_FLAT );
++
++ while (1) {
++ glClear( GL_COLOR_BUFFER_BIT );
++ glPushMatrix();
++ glRotatef( xrot, 1.0, 0.0, 0.0 );
++ glRotatef( yrot, 0.0, 1.0, 0.0 );
++ glRotatef( zrot, 0.0, 0.0, 1.0 );
++
++ draw_cube();
++
++ glPopMatrix();
++ glFinish();
++
++ xrot += 10.0;
++ yrot += 7.0;
++ zrot -= 3.0;
++ }
++
++}
++
++
++
++
++int main( int argc, char *argv[] )
++{
++ int mode = 0;
++
++ if (argc >= 2)
++ {
++ if (strcmp(argv[1],"-ci")==0)
++ mode = 0;
++ else if (strcmp(argv[1],"-rgb")==0)
++ mode = 1;
++ else
++ {
++ printf("Bad flag: %s\n", argv[1]);
++ printf("Specify -ci for 8-bit color index or -rgb for RGB mode\n");
++ exit(1);
++ }
++ }
++ else
++ {
++ printf("Specify -ci for 8-bit color index or -rgb for RGB mode\n");
++ printf("Defaulting to 8-bit color index\n");
++ }
++
++ make_window( argv[0], mode );
++
++ display_loop();
++ return 0;
++}
++
+diff -Naurp Mesa-7.8.1/progs/xdemos/xfont.c Mesa-7.8.1.patched/progs/xdemos/xfont.c
+--- Mesa-7.8.1/progs/xdemos/xfont.c 1970-01-01 01:00:00.000000000 +0100
++++ Mesa-7.8.1.patched/progs/xdemos/xfont.c 2010-06-13 13:45:06.788792936 +0200
+@@ -0,0 +1,206 @@
++
++/*
++ * Mesa 3-D graphics library
++ *
++ * Copyright (C) 1999 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.
++ */
++
++
++/*
++ * Example of using glXUseXFont().
++ * 5 November 1999
++ * Brian Paul
++ */
++
++
++#include <GL/gl.h>
++#include <GL/glx.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++
++
++static const char *ProgramName = "xfont";
++
++static const char *FontName = "fixed";
++
++static GLuint FontBase = 0;
++
++
++
++static void redraw( Display *dpy, Window w )
++{
++ static const char *text = "This is glXUseXFont()";
++
++ glClear( GL_COLOR_BUFFER_BIT );
++
++ /* triangle */
++ glColor3f( 0.2, 0.2, 1.0 );
++ glBegin(GL_TRIANGLES);
++ glVertex2f( 0, 0.8 );
++ glVertex2f( -0.8, -0.7 );
++ glVertex2f( 0.8, -0.7 );
++ glEnd();
++
++ /* text */
++ glColor3f( 1, 1, 1 );
++ glRasterPos2f(-0.8, 0);
++ glListBase(FontBase);
++ glCallLists(strlen(text), GL_UNSIGNED_BYTE, (GLubyte *) text);
++
++ glXSwapBuffers( dpy, w );
++}
++
++
++
++static void resize( unsigned int width, unsigned int height )
++{
++ glViewport( 0, 0, width, height );
++ glMatrixMode( GL_PROJECTION );
++ glLoadIdentity();
++ glOrtho( -1.0, 1.0, -1.0, 1.0, -1.0, 1.0 );
++}
++
++
++
++static void setup_font( Display *dpy )
++{
++ XFontStruct *fontInfo;
++ Font id;
++ unsigned int first, last;
++
++ fontInfo = XLoadQueryFont(dpy, FontName);
++ if (!fontInfo) {
++ printf("Error: font %s not found\n", FontName);
++ exit(0);
++ }
++
++ id = fontInfo->fid;
++ first = fontInfo->min_char_or_byte2;
++ last = fontInfo->max_char_or_byte2;
++
++ FontBase = glGenLists((GLuint) last + 1);
++ if (!FontBase) {
++ printf("Error: unable to allocate display lists\n");
++ exit(0);
++ }
++ glXUseXFont(id, first, last - first + 1, FontBase + first);
++}
++
++static Window make_rgb_db_window( Display *dpy, int xpos, int ypos,
++ unsigned int width, unsigned int height )
++{
++ int attrib[] = { GLX_RGBA,
++ GLX_RED_SIZE, 1,
++ GLX_GREEN_SIZE, 1,
++ GLX_BLUE_SIZE, 1,
++ GLX_DOUBLEBUFFER,
++ None };
++ int scrnum;
++ XSetWindowAttributes attr;
++ unsigned long mask;
++ Window root;
++ Window win;
++ GLXContext ctx;
++ XVisualInfo *visinfo;
++
++ scrnum = DefaultScreen( dpy );
++ root = RootWindow( dpy, scrnum );
++
++ visinfo = glXChooseVisual( dpy, scrnum, attrib );
++ if (!visinfo) {
++ printf("Error: couldn't get an RGB, Double-buffered visual\n");
++ exit(1);
++ }
++
++ /* window attributes */
++ attr.background_pixel = 0;
++ attr.border_pixel = 0;
++ attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone);
++ attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
++ mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
++
++ win = XCreateWindow( dpy, root, 0, 0, width, height,
++ 0, visinfo->depth, InputOutput,
++ visinfo->visual, mask, &attr );
++
++ {
++ XSizeHints sizehints;
++ sizehints.x = xpos;
++ sizehints.y = ypos;
++ sizehints.width = width;
++ sizehints.height = height;
++ sizehints.flags = USSize | USPosition;
++ XSetNormalHints(dpy, win, &sizehints);
++ XSetStandardProperties(dpy, win, ProgramName, ProgramName,
++ None, (char **)NULL, 0, &sizehints);
++ }
++
++
++ ctx = glXCreateContext( dpy, visinfo, NULL, True );
++
++ glXMakeCurrent( dpy, win, ctx );
++
++ return win;
++}
++
++
++static void event_loop( Display *dpy )
++{
++ XEvent event;
++
++ while (1) {
++ XNextEvent( dpy, &event );
++
++ switch (event.type) {
++ case Expose:
++ redraw( dpy, event.xany.window );
++ break;
++ case ConfigureNotify:
++ resize( event.xconfigure.width, event.xconfigure.height );
++ break;
++ case KeyPress:
++ exit(0);
++ default:
++ ; /* no-op */
++ }
++ }
++}
++
++
++
++int main( int argc, char *argv[] )
++{
++ Display *dpy;
++ Window win;
++
++ dpy = XOpenDisplay(NULL);
++
++ win = make_rgb_db_window( dpy, 0, 0, 300, 300 );
++ setup_font( dpy );
++
++ glShadeModel( GL_FLAT );
++ glClearColor( 0.5, 0.5, 1.0, 1.0 );
++
++ XMapWindow( dpy, win );
++
++ event_loop( dpy );
++ return 0;
++}
+diff -Naurp Mesa-7.8.1/progs/xdemos/xrotfontdemo.c Mesa-7.8.1.patched/progs/xdemos/xrotfontdemo.c
+--- Mesa-7.8.1/progs/xdemos/xrotfontdemo.c 1970-01-01 01:00:00.000000000 +0100
++++ Mesa-7.8.1.patched/progs/xdemos/xrotfontdemo.c 2010-06-13 13:45:06.789793146 +0200
+@@ -0,0 +1,220 @@
++/*
++ * Mesa 3-D graphics library
++ *
++ * Copyright (C) 1999 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.
++ */
++
++
++/*
++ * Example of using glXUseRotatedXFontMESA().
++ * 24 Jan 2004
++ * Brian Paul
++ */
++
++
++#include <GL/gl.h>
++#include <GL/glx.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include "xuserotfont.h"
++
++
++static const char *ProgramName = "xfont";
++
++static const char *FontName = "fixed";
++
++static GLuint FontBase[4];
++
++
++static void redraw( Display *dpy, Window w )
++{
++ static const char *text = " Rotated bitmap text";
++ int i;
++
++ glClear( GL_COLOR_BUFFER_BIT );
++
++ /* triangle */
++ glColor3f( 0.2, 0.2, 1.0 );
++ glBegin(GL_TRIANGLES);
++ glVertex2f( -0.8, 0.7 );
++ glVertex2f( -0.8, -0.7 );
++ glVertex2f( 0.8, 0.0 );
++ glEnd();
++
++ /* marker */
++ glColor3f( 0, 1, 0 );
++ glBegin(GL_POINTS);
++ glVertex2f(0, 0);
++ glEnd();
++
++ /* text */
++ glColor3f( 1, 1, 1 );
++
++ for (i = 0; i < 4; i++) {
++ glRasterPos2f(0, 0);
++ glListBase(FontBase[i]);
++ glCallLists(strlen(text), GL_UNSIGNED_BYTE, (GLubyte *) text);
++ }
++
++ glXSwapBuffers( dpy, w );
++}
++
++
++
++static void resize( unsigned int width, unsigned int height )
++{
++ glViewport( 0, 0, width, height );
++ glMatrixMode( GL_PROJECTION );
++ glLoadIdentity();
++ glOrtho( -1.0, 1.0, -1.0, 1.0, -1.0, 1.0 );
++}
++
++
++
++static void setup_font( Display *dpy )
++{
++ XFontStruct *fontInfo;
++ Font id;
++ unsigned int first, last;
++ int i;
++
++ fontInfo = XLoadQueryFont(dpy, FontName);
++ if (!fontInfo) {
++ printf("Error: font %s not found\n", FontName);
++ exit(0);
++ }
++
++ id = fontInfo->fid;
++ first = fontInfo->min_char_or_byte2;
++ last = fontInfo->max_char_or_byte2;
++
++ for (i = 0; i < 4; i++) {
++ FontBase[i] = glGenLists((GLuint) last + 1);
++ if (!FontBase[i]) {
++ printf("Error: unable to allocate display lists\n");
++ exit(0);
++ }
++ glXUseRotatedXFontMESA(id, first, last - first + 1, FontBase[i] + first,
++ i * 90);
++ }
++}
++
++
++static Window make_rgb_db_window( Display *dpy, int xpos, int ypos,
++ unsigned int width, unsigned int height )
++{
++ int attrib[] = { GLX_RGBA,
++ GLX_RED_SIZE, 1,
++ GLX_GREEN_SIZE, 1,
++ GLX_BLUE_SIZE, 1,
++ GLX_DOUBLEBUFFER,
++ None };
++ int scrnum;
++ XSetWindowAttributes attr;
++ unsigned long mask;
++ Window root;
++ Window win;
++ GLXContext ctx;
++ XVisualInfo *visinfo;
++
++ scrnum = DefaultScreen( dpy );
++ root = RootWindow( dpy, scrnum );
++
++ visinfo = glXChooseVisual( dpy, scrnum, attrib );
++ if (!visinfo) {
++ printf("Error: couldn't get an RGB, Double-buffered visual\n");
++ exit(1);
++ }
++
++ /* window attributes */
++ attr.background_pixel = 0;
++ attr.border_pixel = 0;
++ attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone);
++ attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
++ mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
++
++ win = XCreateWindow( dpy, root, 0, 0, width, height,
++ 0, visinfo->depth, InputOutput,
++ visinfo->visual, mask, &attr );
++
++ {
++ XSizeHints sizehints;
++ sizehints.x = xpos;
++ sizehints.y = ypos;
++ sizehints.width = width;
++ sizehints.height = height;
++ sizehints.flags = USSize | USPosition;
++ XSetNormalHints(dpy, win, &sizehints);
++ XSetStandardProperties(dpy, win, ProgramName, ProgramName,
++ None, (char **)NULL, 0, &sizehints);
++ }
++
++
++ ctx = glXCreateContext( dpy, visinfo, NULL, True );
++
++ glXMakeCurrent( dpy, win, ctx );
++
++ return win;
++}
++
++
++static void event_loop( Display *dpy )
++{
++ XEvent event;
++
++ while (1) {
++ XNextEvent( dpy, &event );
++
++ switch (event.type) {
++ case Expose:
++ redraw( dpy, event.xany.window );
++ break;
++ case ConfigureNotify:
++ resize( event.xconfigure.width, event.xconfigure.height );
++ break;
++ case KeyPress:
++ exit(0);
++ default:
++ ; /* no-op */
++ }
++ }
++}
++
++
++
++int main( int argc, char *argv[] )
++{
++ Display *dpy;
++ Window win;
++
++ dpy = XOpenDisplay(NULL);
++
++ win = make_rgb_db_window( dpy, 0, 0, 300, 300 );
++ setup_font( dpy );
++
++ glShadeModel( GL_FLAT );
++ glClearColor( 0.5, 0.5, 1.0, 1.0 );
++
++ XMapWindow( dpy, win );
++
++ event_loop( dpy );
++ return 0;
++}
+diff -Naurp Mesa-7.8.1/progs/xdemos/xuserotfont.c Mesa-7.8.1.patched/progs/xdemos/xuserotfont.c
+--- Mesa-7.8.1/progs/xdemos/xuserotfont.c 1970-01-01 01:00:00.000000000 +0100
++++ Mesa-7.8.1.patched/progs/xdemos/xuserotfont.c 2010-06-13 13:45:06.789793146 +0200
+@@ -0,0 +1,399 @@
++/*
++ * Mesa 3-D graphics library
++ * Version: 6.1
++ *
++ * Copyright (C) 1999-2004 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.
++ */
++
++
++/* \file xuserotfont.c
++ *
++ * A function like glXUseXFont() but takes a 0, 90, 180 or 270 degree
++ * rotation angle for rotated text display.
++ *
++ * Based on Mesa's glXUseXFont implementation written by Thorsten Ohl.
++ */
++
++#include <assert.h>
++#include <stdlib.h>
++#include <string.h>
++#include <GL/glx.h>
++#include "xuserotfont.h"
++
++
++/**
++ * Generate OpenGL-compatible bitmap by drawing an X character glyph
++ * to an off-screen pixmap, then getting the image and testing pixels.
++ * \param width bitmap width in pixels
++ * \param height bitmap height in pixels
++ */
++static void
++fill_bitmap(Display *dpy, Pixmap pixmap, GC gc,
++ unsigned int bitmapWidth, unsigned int bitmapHeight,
++ unsigned int charWidth, unsigned int charHeight,
++ int xPos, int yPos, unsigned int c, GLubyte * bitmap,
++ int rotation)
++{
++ const int bytesPerRow = (bitmapWidth + 7) / 8;
++ XImage *image;
++ XChar2b char2b;
++
++ /* clear pixmap to 0 */
++ XSetForeground(dpy, gc, 0);
++ XFillRectangle(dpy, pixmap, gc, 0, 0, charWidth, charHeight);
++
++ /* The glyph is drawn snug up against the left/top edges of the pixmap */
++ XSetForeground(dpy, gc, 1);
++ char2b.byte1 = (c >> 8) & 0xff;
++ char2b.byte2 = (c & 0xff);
++ XDrawString16(dpy, pixmap, gc, xPos, yPos, &char2b, 1);
++
++ /* initialize GL bitmap */
++ memset(bitmap, 0, bytesPerRow * bitmapHeight);
++
++ image = XGetImage(dpy, pixmap, 0, 0, charWidth, charHeight, 1, XYPixmap);
++ if (image) {
++ /* Set appropriate bits in the GL bitmap.
++ * Note: X11 and OpenGL are upside down wrt each other).
++ */
++ unsigned int x, y;
++ if (rotation == 0) {
++ for (y = 0; y < charHeight; y++) {
++ for (x = 0; x < charWidth; x++) {
++ if (XGetPixel(image, x, y)) {
++ int y2 = bitmapHeight - y - 1;
++ bitmap[bytesPerRow * y2 + x / 8] |= (1 << (7 - (x % 8)));
++ }
++ }
++ }
++ }
++ else if (rotation == 90) {
++ for (y = 0; y < charHeight; y++) {
++ for (x = 0; x < charWidth; x++) {
++ if (XGetPixel(image, x, y)) {
++ int x2 = y;
++ int y2 = x;
++ bitmap[bytesPerRow * y2 + x2 / 8] |= (1 << (7 - (x2 % 8)));
++ }
++ }
++ }
++ }
++ else if (rotation == 180) {
++ for (y = 0; y < charHeight; y++) {
++ for (x = 0; x < charWidth; x++) {
++ if (XGetPixel(image, x, y)) {
++ int x2 = charWidth - x - 1;
++ bitmap[bytesPerRow * y + x2 / 8] |= (1 << (7 - (x2 % 8)));
++ }
++ }
++ }
++ }
++ else {
++ assert(rotation == 270);
++ for (y = 0; y < charHeight; y++) {
++ for (x = 0; x < charWidth; x++) {
++ if (XGetPixel(image, x, y)) {
++ int x2 = charHeight - y - 1;
++ int y2 = charWidth - x - 1;
++ bitmap[bytesPerRow * y2 + x2 / 8] |= (1 << (7 - (x2 % 8)));
++ }
++ }
++ }
++ }
++ XDestroyImage(image);
++ }
++}
++
++
++/*
++ * Determine if a given glyph is valid and return the
++ * corresponding XCharStruct.
++ */
++static const XCharStruct *
++isvalid(const XFontStruct * fs, unsigned int which)
++{
++ unsigned int rows, pages;
++ unsigned int byte1 = 0, byte2 = 0;
++ int i, valid = 1;
++
++ rows = fs->max_byte1 - fs->min_byte1 + 1;
++ pages = fs->max_char_or_byte2 - fs->min_char_or_byte2 + 1;
++
++ if (rows == 1) {
++ /* "linear" fonts */
++ if ((fs->min_char_or_byte2 > which) || (fs->max_char_or_byte2 < which))
++ valid = 0;
++ }
++ else {
++ /* "matrix" fonts */
++ byte2 = which & 0xff;
++ byte1 = which >> 8;
++ if ((fs->min_char_or_byte2 > byte2) ||
++ (fs->max_char_or_byte2 < byte2) ||
++ (fs->min_byte1 > byte1) || (fs->max_byte1 < byte1))
++ valid = 0;
++ }
++
++ if (valid) {
++ if (fs->per_char) {
++ if (rows == 1) {
++ /* "linear" fonts */
++ return fs->per_char + (which - fs->min_char_or_byte2);
++ }
++ else {
++ /* "matrix" fonts */
++ i = ((byte1 - fs->min_byte1) * pages) +
++ (byte2 - fs->min_char_or_byte2);
++ return fs->per_char + i;
++ }
++ }
++ else {
++ return &fs->min_bounds;
++ }
++ }
++ return NULL;
++}
++
++
++void
++glXUseRotatedXFontMESA(Font font, int first, int count, int listbase,
++ int rotation)
++{
++ Display *dpy;
++ Window win;
++ Pixmap pixmap;
++ GC gc;
++ XFontStruct *fs;
++ GLint swapbytes, lsbfirst, rowlength;
++ GLint skiprows, skippixels, alignment;
++ unsigned int maxCharWidth, maxCharHeight;
++ GLubyte *bm;
++ int i;
++
++ if (rotation != 0 &&
++ rotation != 90 &&
++ rotation != 180 &&
++ rotation != 270)
++ return;
++
++ dpy = glXGetCurrentDisplay();
++ if (!dpy)
++ return; /* I guess glXMakeCurrent wasn't called */
++ win = RootWindow(dpy, DefaultScreen(dpy));
++
++ fs = XQueryFont(dpy, font);
++ if (!fs) {
++ /*
++ _mesa_error(NULL, GL_INVALID_VALUE,
++ "Couldn't get font structure information");
++ */
++ return;
++ }
++
++ /* Allocate a GL bitmap that can fit any character */
++ maxCharWidth = fs->max_bounds.rbearing - fs->min_bounds.lbearing;
++ maxCharHeight = fs->max_bounds.ascent + fs->max_bounds.descent;
++ /* use max, in case we're rotating */
++ if (rotation == 90 || rotation == 270) {
++ /* swap width/height */
++ bm = (GLubyte *) malloc((maxCharHeight + 7) / 8 * maxCharWidth);
++ }
++ else {
++ /* normal or upside down */
++ bm = (GLubyte *) malloc((maxCharWidth + 7) / 8 * maxCharHeight);
++ }
++ if (!bm) {
++ XFreeFontInfo(NULL, fs, 1);
++ /*
++ _mesa_error(NULL, GL_OUT_OF_MEMORY,
++ "Couldn't allocate bitmap in glXUseXFont()");
++ */
++ return;
++ }
++
++#if 0
++ /* get the page info */
++ pages = fs->max_char_or_byte2 - fs->min_char_or_byte2 + 1;
++ firstchar = (fs->min_byte1 << 8) + fs->min_char_or_byte2;
++ lastchar = (fs->max_byte1 << 8) + fs->max_char_or_byte2;
++ rows = fs->max_byte1 - fs->min_byte1 + 1;
++ unsigned int first_char, last_char, pages, rows;
++#endif
++
++ /* Save the current packing mode for bitmaps. */
++ glGetIntegerv(GL_UNPACK_SWAP_BYTES, &swapbytes);
++ glGetIntegerv(GL_UNPACK_LSB_FIRST, &lsbfirst);
++ glGetIntegerv(GL_UNPACK_ROW_LENGTH, &rowlength);
++ glGetIntegerv(GL_UNPACK_SKIP_ROWS, &skiprows);
++ glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &skippixels);
++ glGetIntegerv(GL_UNPACK_ALIGNMENT, &alignment);
++
++ /* Enforce a standard packing mode which is compatible with
++ fill_bitmap() from above. This is actually the default mode,
++ except for the (non)alignment. */
++ glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
++ glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE);
++ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
++ glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
++ glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
++ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
++
++ /* Create pixmap and GC */
++ pixmap = XCreatePixmap(dpy, win, maxCharWidth, maxCharHeight, 1);
++ {
++ XGCValues values;
++ unsigned long valuemask;
++ values.foreground = BlackPixel(dpy, DefaultScreen(dpy));
++ values.background = WhitePixel(dpy, DefaultScreen(dpy));
++ values.font = fs->fid;
++ valuemask = GCForeground | GCBackground | GCFont;
++ gc = XCreateGC(dpy, pixmap, valuemask, &values);
++ }
++
++#ifdef DEBUG_XROT
++ if (debug_xfonts)
++ dump_font_struct(fs);
++#endif
++
++ for (i = 0; i < count; i++) {
++ const unsigned int c = first + i;
++ const int list = listbase + i;
++ unsigned int charWidth, charHeight;
++ unsigned int bitmapWidth = 0, bitmapHeight = 0;
++ GLfloat xOrig, yOrig, xStep, yStep, dtemp;
++ const XCharStruct *ch;
++ int xPos, yPos;
++ int valid;
++
++ /* check on index validity and get the bounds */
++ ch = isvalid(fs, c);
++ if (!ch) {
++ ch = &fs->max_bounds;
++ valid = 0;
++ }
++ else {
++ valid = 1;
++ }
++
++#ifdef DEBUG_XROT
++ if (debug_xfonts) {
++ char s[7];
++ sprintf(s, isprint(c) ? "%c> " : "\\%03o> ", c);
++ dump_char_struct(ch, s);
++ }
++#endif
++
++ /* glBitmap()' parameters:
++ straight from the glXUseXFont(3) manpage. */
++ charWidth = ch->rbearing - ch->lbearing;
++ charHeight = ch->ascent + ch->descent;
++ xOrig = -ch->lbearing;
++ yOrig = ch->descent;
++ xStep = ch->width;
++ yStep = 0;
++
++ /* X11's starting point. */
++ xPos = -ch->lbearing;
++ yPos = ch->ascent;
++
++ /* Apply rotation */
++ switch (rotation) {
++ case 0:
++ /* nothing */
++ bitmapWidth = charWidth;
++ bitmapHeight = charHeight;
++ break;
++ case 90:
++ /* xStep, yStep */
++ dtemp = xStep;
++ xStep = -yStep;
++ yStep = dtemp;
++ /* xOrig, yOrig */
++ yOrig = xOrig;
++ xOrig = charHeight - (charHeight - yPos);
++ /* width, height */
++ bitmapWidth = charHeight;
++ bitmapHeight = charWidth;
++ break;
++ case 180:
++ /* xStep, yStep */
++ xStep = -xStep;
++ yStep = -yStep;
++ /* xOrig, yOrig */
++ xOrig = charWidth - xOrig - 1;
++ yOrig = charHeight - yOrig - 1;
++ bitmapWidth = charWidth;
++ bitmapHeight = charHeight;
++ break;
++ case 270:
++ /* xStep, yStep */
++ dtemp = xStep;
++ xStep = yStep;
++ yStep = -dtemp;
++ /* xOrig, yOrig */
++ dtemp = yOrig;
++ yOrig = charWidth - xOrig;
++ xOrig = dtemp;
++ /* width, height */
++ bitmapWidth = charHeight;
++ bitmapHeight = charWidth;
++ break;
++ default:
++ /* should never get here */
++ ;
++ }
++
++ glNewList(list, GL_COMPILE);
++ if (valid && bitmapWidth > 0 && bitmapHeight > 0) {
++
++ fill_bitmap(dpy, pixmap, gc, bitmapWidth, bitmapHeight,
++ charWidth, charHeight,
++ xPos, yPos, c, bm, rotation);
++
++ glBitmap(bitmapWidth, bitmapHeight, xOrig, yOrig, xStep, yStep, bm);
++
++#ifdef DEBUG_XROT
++ if (debug_xfonts) {
++ printf("width/height = %u/%u\n", bitmapWidth, bitmapHeight);
++ dump_bitmap(bitmapWidth, bitmapHeight, bm);
++ }
++#endif
++ }
++ else {
++ glBitmap(0, 0, 0.0, 0.0, xStep, yStep, NULL);
++ }
++ glEndList();
++ }
++
++ free(bm);
++ XFreeFontInfo(NULL, fs, 1);
++ XFreePixmap(dpy, pixmap);
++ XFreeGC(dpy, gc);
++
++ /* Restore saved packing modes. */
++ glPixelStorei(GL_UNPACK_SWAP_BYTES, swapbytes);
++ glPixelStorei(GL_UNPACK_LSB_FIRST, lsbfirst);
++ glPixelStorei(GL_UNPACK_ROW_LENGTH, rowlength);
++ glPixelStorei(GL_UNPACK_SKIP_ROWS, skiprows);
++ glPixelStorei(GL_UNPACK_SKIP_PIXELS, skippixels);
++ glPixelStorei(GL_UNPACK_ALIGNMENT, alignment);
++}
++
++
+diff -Naurp Mesa-7.8.1/progs/xdemos/xuserotfont.h Mesa-7.8.1.patched/progs/xdemos/xuserotfont.h
+--- Mesa-7.8.1/progs/xdemos/xuserotfont.h 1970-01-01 01:00:00.000000000 +0100
++++ Mesa-7.8.1.patched/progs/xdemos/xuserotfont.h 2010-06-13 13:45:06.789793146 +0200
+@@ -0,0 +1,12 @@
++#ifndef XUSEROTFONT_H
++#define XUSEROTFONT_H
++
++#include <X11/Xlib.h>
++
++
++extern void
++glXUseRotatedXFontMESA(Font font, int first, int count, int listbase,
++ int rotation);
++
++
++#endif
+diff -Naurp Mesa-7.8.1/progs/xdemos/yuvrect_client.c Mesa-7.8.1.patched/progs/xdemos/yuvrect_client.c
+--- Mesa-7.8.1/progs/xdemos/yuvrect_client.c 1970-01-01 01:00:00.000000000 +0100
++++ Mesa-7.8.1.patched/progs/xdemos/yuvrect_client.c 2010-06-13 13:45:06.789793146 +0200
+@@ -0,0 +1,326 @@
++/*
++ * Test the GL_NV_texture_rectangle and GL_MESA_ycrcb_texture extensions and GLX_MESA_allocate-memory
++ *
++ * Dave Airlie - Feb 2005
++ */
++
++#include <assert.h>
++#include <math.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <X11/Xlib.h>
++#include <X11/keysym.h>
++#define GL_GLEXT_PROTOTYPES
++#include <GL/glx.h>
++
++#include "../util/readtex.c" /* I know, this is a hack. */
++
++#define TEXTURE_FILE "../images/girl2.rgb"
++
++static GLfloat Xrot = 0, Yrot = 0, Zrot = 0;
++static GLint ImgWidth, ImgHeight;
++static GLushort *ImageYUV = NULL;
++static void *glx_memory;
++
++static void DrawObject(void)
++{
++ glBegin(GL_QUADS);
++
++ glTexCoord2f(0, 0);
++ glVertex2f(-1.0, -1.0);
++
++ glTexCoord2f(ImgWidth, 0);
++ glVertex2f(1.0, -1.0);
++
++ glTexCoord2f(ImgWidth, ImgHeight);
++ glVertex2f(1.0, 1.0);
++
++ glTexCoord2f(0, ImgHeight);
++ glVertex2f(-1.0, 1.0);
++
++ glEnd();
++}
++
++
++static void scr_Display( void )
++{
++ glClear( GL_COLOR_BUFFER_BIT );
++
++ glPushMatrix();
++ glRotatef(Xrot, 1.0, 0.0, 0.0);
++ glRotatef(Yrot, 0.0, 1.0, 0.0);
++ glRotatef(Zrot, 0.0, 0.0, 1.0);
++ DrawObject();
++ glPopMatrix();
++
++}
++
++
++static void Reshape( int width, int height )
++{
++ glViewport( 0, 0, width, height );
++ glMatrixMode( GL_PROJECTION );
++ glLoadIdentity();
++ glFrustum( -1.0, 1.0, -1.0, 1.0, 10.0, 100.0 );
++ glMatrixMode( GL_MODELVIEW );
++ glLoadIdentity();
++ glTranslatef( 0.0, 0.0, -15.0 );
++}
++
++static int queryClient(Display *dpy, int screen)
++{
++#ifdef GLX_MESA_allocate_memory
++ char *extensions;
++
++ extensions = (char *)glXQueryExtensionsString(dpy, screen);
++ if (!extensions || !strstr(extensions,"GLX_MESA_allocate_memory")) {
++ return 0;
++ }
++
++ return 1;
++#else
++ return 0;
++#endif
++}
++
++static int
++query_extension(char* extName) {
++ char *p = (char *) glGetString(GL_EXTENSIONS);
++ char *end = p + strlen(p);
++ while (p < end) {
++ int n = strcspn(p, " ");
++ if ((strlen(extName) == n) && (strncmp(extName, p, n) == 0))
++ return GL_TRUE;
++ p += (n + 1);
++ }
++ return GL_FALSE;
++}
++
++static void Init( int argc, char *argv[] , Display *dpy, int screen, Window win)
++{
++ GLuint texObj = 100;
++ const char *file;
++ void *glx_memory;
++
++ if (!query_extension("GL_NV_texture_rectangle")) {
++ printf("Sorry, GL_NV_texture_rectangle is required\n");
++ exit(0);
++ }
++
++ if (!query_extension("GL_MESA_ycbcr_texture")) {
++ printf("Sorry, GL_MESA_ycbcr_texture is required\n");
++ exit(0);
++ }
++
++ if (!queryClient(dpy, screen)) {
++ printf("Sorry, GLX_MESA_allocate_memory is required\n");
++ exit(0);
++ }
++
++ glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, 1);
++ glBindTexture(GL_TEXTURE_RECTANGLE_NV, texObj);
++#ifdef LINEAR_FILTER
++ /* linear filtering looks much nicer but is much slower for Mesa */
++ glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
++ glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
++#else
++ glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
++ glTexParameteri(GL_TEXTURE_RECTANGLE_NV, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
++#endif
++
++ if (argc > 1)
++ file = argv[1];
++ else
++ file = TEXTURE_FILE;
++
++ ImageYUV = LoadYUVImage(file, &ImgWidth, &ImgHeight);
++ if (!ImageYUV) {
++ printf("Couldn't read %s\n", TEXTURE_FILE);
++ exit(0);
++ }
++
++ glx_memory = glXAllocateMemoryMESA(dpy, screen, ImgWidth * ImgHeight * 2, 0, 0 ,0);
++ if (!glx_memory)
++ {
++ fprintf(stderr,"Failed to allocate MESA memory\n");
++ exit(-1);
++ }
++
++ memcpy(glx_memory, ImageYUV, ImgWidth * ImgHeight * 2);
++
++ printf("Image: %dx%d\n", ImgWidth, ImgHeight);
++
++ glTexImage2D(GL_TEXTURE_RECTANGLE_NV, 0,
++ GL_YCBCR_MESA, ImgWidth, ImgHeight, 0,
++ GL_YCBCR_MESA, GL_UNSIGNED_SHORT_8_8_APPLE, glx_memory);
++
++ assert(glGetError() == GL_NO_ERROR);
++
++ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
++
++ glEnable(GL_TEXTURE_RECTANGLE_NV);
++
++ glShadeModel(GL_FLAT);
++ glClearColor(0.3, 0.3, 0.4, 1.0);
++
++}
++
++/*
++ * Create an RGB, double-buffered window.
++ * Return the window and context handles.
++ */
++static void
++make_window( Display *dpy, const char *name,
++ int x, int y, int width, int height,
++ Window *winRet, GLXContext *ctxRet)
++{
++ int attribs[] = { GLX_RGBA,
++ GLX_RED_SIZE, 1,
++ GLX_GREEN_SIZE, 1,
++ GLX_BLUE_SIZE, 1,
++ GLX_DOUBLEBUFFER,
++ GLX_DEPTH_SIZE, 1,
++ None };
++ int scrnum;
++ XSetWindowAttributes attr;
++ unsigned long mask;
++ Window root;
++ Window win;
++ GLXContext ctx;
++ XVisualInfo *visinfo;
++
++ scrnum = DefaultScreen( dpy );
++ root = RootWindow( dpy, scrnum );
++
++ visinfo = glXChooseVisual( dpy, scrnum, attribs );
++ if (!visinfo) {
++ printf("Error: couldn't get an RGB, Double-buffered visual\n");
++ exit(1);
++ }
++
++ /* window attributes */
++ attr.background_pixel = 0;
++ attr.border_pixel = 0;
++ attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone);
++ attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
++ attr.override_redirect = 0;
++ mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect;
++
++ win = XCreateWindow( dpy, root, 0, 0, width, 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(dpy, win, &sizehints);
++ XSetStandardProperties(dpy, win, name, name,
++ None, (char **)NULL, 0, &sizehints);
++ }
++
++ ctx = glXCreateContext( dpy, visinfo, NULL, True );
++ if (!ctx) {
++ printf("Error: glXCreateContext failed\n");
++ exit(1);
++ }
++
++ XFree(visinfo);
++
++ *winRet = win;
++ *ctxRet = ctx;
++}
++
++
++static void
++event_loop(Display *dpy, Window win)
++{
++ while (1) {
++ while (XPending(dpy) > 0) {
++ XEvent event;
++ XNextEvent(dpy, &event);
++ switch (event.type) {
++ case Expose:
++ /* we'll redraw below */
++ break;
++ case ConfigureNotify:
++ Reshape(event.xconfigure.width, event.xconfigure.height);
++ break;
++ case KeyPress:
++ {
++ char buffer[10];
++ int r, code;
++ code = XLookupKeysym(&event.xkey, 0);
++ r = XLookupString(&event.xkey, buffer, sizeof(buffer),
++ NULL, NULL);
++ if (buffer[0] == 27) {
++ /* escape */
++ return;
++
++ }
++ }
++ }
++ }
++
++ }
++}
++
++
++int
++main(int argc, char *argv[])
++{
++ Display *dpy;
++ Window win;
++ GLXContext ctx;
++ char *dpyName = NULL;
++ GLboolean printInfo = GL_FALSE;
++ int i;
++
++ for (i = 1; i < argc; i++) {
++ if (strcmp(argv[i], "-display") == 0) {
++ dpyName = argv[i+1];
++ i++;
++ }
++ else if (strcmp(argv[i], "-info") == 0) {
++ printInfo = GL_TRUE;
++ }
++ else
++ printf("Warrning: unknown parameter: %s\n", argv[i]);
++ }
++
++ dpy = XOpenDisplay(dpyName);
++ if (!dpy) {
++ printf("Error: couldn't open display %s\n",
++ XDisplayName(dpyName));
++ return -1;
++ }
++
++ make_window(dpy, "yuvrect_client", 0, 0, 300, 300, &win, &ctx);
++ XMapWindow(dpy, win);
++ glXMakeCurrent(dpy, win, ctx);
++
++ 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));
++ }
++
++ Init(argc, argv, dpy, DefaultScreen(dpy), win);
++
++ scr_Display();
++ glXSwapBuffers(dpy, win);
++ event_loop(dpy, win);
++
++ glXFreeMemoryMESA(dpy, DefaultScreen(dpy), glx_memory);
++ glXDestroyContext(dpy, ctx);
++ XDestroyWindow(dpy, win);
++ XCloseDisplay(dpy);
++
++ return 0;
++}