diff options
author | Phil Sutter <phil@nwl.cc> | 2010-06-15 22:28:54 +0200 |
---|---|---|
committer | Phil Sutter <phil@nwl.cc> | 2010-06-20 16:23:52 +0200 |
commit | 48ad3e135426d7f0116e4ad8efc85d20aad64910 (patch) | |
tree | 08b2fb27aa77da0ead2f90eaa94b80f52ccaa54b /package/MesaLib/patches | |
parent | 0549414af010737828696592acec9b263cd0513a (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/MesaLib/patches')
-rw-r--r-- | package/MesaLib/patches/000-mesalib-xdemos.patch | 14774 |
1 files changed, 14774 insertions, 0 deletions
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; ++} |