summaryrefslogtreecommitdiff
path: root/package
diff options
context:
space:
mode:
authorPhil Sutter <phil@nwl.cc>2010-06-15 22:28:54 +0200
committerPhil Sutter <phil@nwl.cc>2010-06-20 16:23:52 +0200
commit48ad3e135426d7f0116e4ad8efc85d20aad64910 (patch)
tree08b2fb27aa77da0ead2f90eaa94b80f52ccaa54b /package
parent0549414af010737828696592acec9b263cd0513a (diff)
MesaLib: add glxinfo and glxgears subpackages
As these xdemos reside in their own package but without the necessary infrastructure (this config thingy), I've created a patch from the addon-package.
Diffstat (limited to 'package')
-rw-r--r--package/MesaLib/Makefile17
-rw-r--r--package/MesaLib/patches/000-mesalib-xdemos.patch14774
2 files changed, 14789 insertions, 2 deletions
diff --git a/package/MesaLib/Makefile b/package/MesaLib/Makefile
index a5f624374..5836f994f 100644
--- a/package/MesaLib/Makefile
+++ b/package/MesaLib/Makefile
@@ -15,6 +15,11 @@ PKG_BUILDDEP+= dri2proto glproto expat
PKG_URL:= http://www.mesa3d.org/
PKG_SITES:= ftp://ftp.freedesktop.org/pub/mesa/7.8.1/
+PKG_DESCR_GLXINFO:= Display various GLX information
+PKG_SECT_GLXINFO:= x11
+PKG_DESCR_GLXGEARS:= Nice little OpenGL demo application
+PKG_SECT_GLXGEARS:= x11
+
WRKDIST= ${WRKDIR}/Mesa-${PKG_VERSION}
PKG_TARGET_DEPENDS:= ibmx40 lemote
@@ -22,6 +27,8 @@ PKG_TARGET_DEPENDS:= ibmx40 lemote
include $(TOPDIR)/mk/package.mk
$(eval $(call PKG_template,MESALIB,mesalib,$(PKG_VERSION)-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION}))
+$(eval $(call PKG_template,GLXINFO,glxinfo,$(PKG_VERSION)-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR_GLXINFO},${PKG_SECT_GLXINFO}))
+$(eval $(call PKG_template,GLXGEARS,glxgears,$(PKG_VERSION)-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR_GLXGEARS},${PKG_SECT_GLXGEARS}))
ifeq (${ADK_LINUX_X86_IBMX40},y)
DRI_DRIVERS:=i810
@@ -39,7 +46,7 @@ CONFIGURE_ARGS+= --disable-static \
--disable-glw \
--with-driver=dri \
--with-dri-drivers=${DRI_DRIVERS} \
- --without-demos
+ --with-demos=xdemos
XAKE_FLAGS+= APP_CC=${HOSTCC} HOST_CC=${HOSTCC}
@@ -50,7 +57,7 @@ pre-configure:
--disable-glw \
--disable-gallium \
--with-driver=xlib \
- --without-demos \
+ --with-demos=xdemos \
);
${MAKE} -C ${WRKBUILD}/src/glsl
${MAKE} -C ${WRKBUILD}/src/glsl/apps
@@ -66,5 +73,11 @@ ifeq (${ADK_LINUX_MIPS64_LEMOTE},y)
$(INSTALL_BIN) $(WRKINST)/usr/lib/dri/swrast_dri.so \
${IDIR_MESALIB}/usr/lib/dri/
endif
+ ${INSTALL_DIR} ${IDIR_GLXINFO}/usr/bin
+ ${INSTALL_BIN} ${WRKBUILD}/progs/xdemos/glxinfo \
+ ${IDIR_GLXINFO}/usr/bin/
+ ${INSTALL_DIR} ${IDIR_GLXGEARS}/usr/bin
+ ${INSTALL_BIN} ${WRKBUILD}/progs/xdemos/glxgears \
+ ${IDIR_GLXGEARS}/usr/bin/
include ${TOPDIR}/mk/pkg-bottom.mk
diff --git a/package/MesaLib/patches/000-mesalib-xdemos.patch b/package/MesaLib/patches/000-mesalib-xdemos.patch
new file mode 100644
index 000000000..866e68c2e
--- /dev/null
+++ b/package/MesaLib/patches/000-mesalib-xdemos.patch
@@ -0,0 +1,14774 @@
+diff -Naurp Mesa-7.8.1/progs/xdemos/corender.c Mesa-7.8.1.patched/progs/xdemos/corender.c
+--- Mesa-7.8.1/progs/xdemos/corender.c 1970-01-01 01:00:00.000000000 +0100
++++ Mesa-7.8.1.patched/progs/xdemos/corender.c 2010-06-13 13:45:06.789793146 +0200
+@@ -0,0 +1,400 @@
++/**
++ * Example of cooperative rendering into one window by two processes.
++ * The first instance of the program creates the GLX window.
++ * The second instance of the program gets the window ID from the first
++ * and draws into it.
++ * Socket IPC is used for synchronization.
++ *
++ * Usage:
++ * 1. run 'corender &'
++ * 2. run 'corender 2' (any arg will do)
++ *
++ * Brian Paul
++ * 11 Oct 2007
++ */
++
++
++#include <GL/gl.h>
++#include <GL/glx.h>
++#include <assert.h>
++#include <math.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <X11/keysym.h>
++#include <unistd.h>
++#include "ipc.h"
++
++
++#ifndef M_PI
++#define M_PI 3.14159265358979323846
++#endif
++
++static int MyID = 0; /* 0 or 1 */
++static int WindowID = 0;
++static GLXContext Context = 0;
++static int Width = 700, Height = 350;
++static int Rot = 0;
++static int Sock = 0;
++
++static GLfloat Red[4] = {1.0, 0.2, 0.2, 1.0};
++static GLfloat Blue[4] = {0.2, 0.2, 1.0, 1.0};
++
++static int Sync = 1; /** synchronized rendering? */
++
++
++static void
++setup_ipc(void)
++{
++ int k, port = 10001;
++
++ if (MyID == 0) {
++ /* I'm the first one, wait for connection from second */
++ k = CreatePort(&port);
++ assert(k != -1);
++
++ printf("Waiting for connection from another 'corender'\n");
++ Sock = AcceptConnection(k);
++ assert(Sock != -1);
++
++ printf("Got connection, sending windowID\n");
++
++ /* send windowID */
++ SendData(Sock, &WindowID, sizeof(WindowID));
++ }
++ else {
++ /* I'm the second one, connect to first */
++ char hostname[1000];
++
++ MyHostName(hostname, 1000);
++ Sock = Connect(hostname, port);
++ assert(Sock != -1);
++
++ /* get windowID */
++ ReceiveData(Sock, &WindowID, sizeof(WindowID));
++ printf("Contacted first 'corender', getting WindowID\n");
++ }
++}
++
++
++
++/** from GLUT */
++static void
++doughnut(GLfloat r, GLfloat R, GLint nsides, GLint rings)
++{
++ int i, j;
++ GLfloat theta, phi, theta1;
++ GLfloat cosTheta, sinTheta;
++ GLfloat cosTheta1, sinTheta1;
++ GLfloat ringDelta, sideDelta;
++
++ ringDelta = 2.0 * M_PI / rings;
++ sideDelta = 2.0 * M_PI / nsides;
++
++ theta = 0.0;
++ cosTheta = 1.0;
++ sinTheta = 0.0;
++ for (i = rings - 1; i >= 0; i--) {
++ theta1 = theta + ringDelta;
++ cosTheta1 = cos(theta1);
++ sinTheta1 = sin(theta1);
++ glBegin(GL_QUAD_STRIP);
++ phi = 0.0;
++ for (j = nsides; j >= 0; j--) {
++ GLfloat cosPhi, sinPhi, dist;
++
++ phi += sideDelta;
++ cosPhi = cos(phi);
++ sinPhi = sin(phi);
++ dist = R + r * cosPhi;
++
++ glNormal3f(cosTheta1 * cosPhi, -sinTheta1 * cosPhi, sinPhi);
++ glVertex3f(cosTheta1 * dist, -sinTheta1 * dist, r * sinPhi);
++ glNormal3f(cosTheta * cosPhi, -sinTheta * cosPhi, sinPhi);
++ glVertex3f(cosTheta * dist, -sinTheta * dist, r * sinPhi);
++ }
++ glEnd();
++ theta = theta1;
++ cosTheta = cosTheta1;
++ sinTheta = sinTheta1;
++ }
++}
++
++
++static void
++redraw(Display *dpy)
++{
++ int dbg = 0;
++
++ glXMakeCurrent(dpy, WindowID, Context);
++ glEnable(GL_LIGHTING);
++ glEnable(GL_LIGHT0);
++ glEnable(GL_DEPTH_TEST);
++ glClearColor(0.5, 0.5, 0.5, 0.0);
++
++ if (MyID == 0) {
++ /* First process */
++
++ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
++
++ glPushMatrix();
++ glTranslatef(-1, 0, 0);
++ glRotatef(Rot, 1, 0, 0);
++ glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, Red);
++ doughnut(0.5, 2.0, 20, 30);
++ glPopMatrix();
++
++ glFinish();
++ if (!Sync) {
++ usleep(1000*10);
++ }
++
++ /* signal second process to render */
++ if (Sync) {
++ int code = 1;
++ if (dbg) printf("0: send signal\n");
++ SendData(Sock, &code, sizeof(code));
++ SendData(Sock, &Rot, sizeof(Rot));
++ }
++
++ /* wait for second process to finish rendering */
++ if (Sync) {
++ int code = 0;
++ if (dbg) printf("0: wait signal\n");
++ ReceiveData(Sock, &code, sizeof(code));
++ if (dbg) printf("0: got signal\n");
++ assert(code == 2);
++ }
++
++ }
++ else {
++ /* Second process */
++
++ /* wait for first process's signal for me to render */
++ if (Sync) {
++ int code = 0;
++ if (dbg) printf("1: wait signal\n");
++ ReceiveData(Sock, &code, sizeof(code));
++ ReceiveData(Sock, &Rot, sizeof(Rot));
++
++ if (dbg) printf("1: got signal\n");
++ assert(code == 1);
++ }
++
++ /* XXX this clear should not be here, but for some reason, it
++ * makes things _mostly_ work correctly w/ NVIDIA's driver.
++ * There's only occasional glitches.
++ * Without this glClear(), depth buffer for the second process
++ * is pretty much broken.
++ */
++ /* glClear(GL_DEPTH_BUFFER_BIT); */
++
++ glPushMatrix();
++ glTranslatef(1, 0, 0);
++ glRotatef(Rot + 90 , 1, 0, 0);
++ glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, Blue);
++ doughnut(0.5, 2.0, 20, 30);
++ glPopMatrix();
++ glFinish();
++
++ glXSwapBuffers(dpy, WindowID);
++ usleep(1000*10);
++
++ /* signal first process that I'm done rendering */
++ if (Sync) {
++ int code = 2;
++ if (dbg) printf("1: send signal\n");
++ SendData(Sock, &code, sizeof(code));
++ }
++ }
++}
++
++
++static void
++resize(Display *dpy, int width, int height)
++{
++ float ar = (float) width / height;
++
++ glXMakeCurrent(dpy, WindowID, Context);
++
++ glViewport(0, 0, width, height);
++ glMatrixMode(GL_PROJECTION);
++ glLoadIdentity();
++ glFrustum(-ar, ar, 1.0, -1.0, 5.0, 200.0);
++ glMatrixMode(GL_MODELVIEW);
++ glLoadIdentity();
++ glTranslatef(0, 0, -15);
++
++ Width = width;
++ Height = height;
++}
++
++
++
++static void
++set_window_title(Display *dpy, Window win, const char *title)
++{
++ XSizeHints sizehints;
++ sizehints.flags = 0;
++ XSetStandardProperties(dpy, win, title, title,
++ None, (char **)NULL, 0, &sizehints);
++}
++
++
++static Window
++make_gl_window(Display *dpy, XVisualInfo *visinfo, int width, int height)
++{
++ int scrnum;
++ XSetWindowAttributes attr;
++ unsigned long mask;
++ Window root;
++ Window win;
++ int x = 0, y = 0;
++ char *name = NULL;
++
++ scrnum = DefaultScreen( dpy );
++ root = RootWindow( dpy, scrnum );
++
++ /* window attributes */
++ attr.background_pixel = 0;
++ attr.border_pixel = 0;
++ attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone);
++ attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
++ mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
++
++ win = XCreateWindow( dpy, root, x, y, width, height,
++ 0, visinfo->depth, InputOutput,
++ visinfo->visual, mask, &attr );
++
++ /* set hints and properties */
++ {
++ XSizeHints sizehints;
++ sizehints.x = x;
++ sizehints.y = y;
++ sizehints.width = width;
++ sizehints.height = height;
++ sizehints.flags = USSize | USPosition;
++ XSetNormalHints(dpy, win, &sizehints);
++ XSetStandardProperties(dpy, win, name, name,
++ None, (char **)NULL, 0, &sizehints);
++ }
++
++ return win;
++}
++
++
++static void
++set_event_mask(Display *dpy, Window win)
++{
++ XSetWindowAttributes attr;
++ attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
++ XChangeWindowAttributes(dpy, win, CWEventMask, &attr);
++}
++
++
++static void
++event_loop(Display *dpy)
++{
++ while (1) {
++ while (XPending(dpy) > 0) {
++ XEvent event;
++ XNextEvent(dpy, &event);
++
++ switch (event.type) {
++ case Expose:
++ redraw(dpy);
++ break;
++ case ConfigureNotify:
++ resize(dpy, event.xconfigure.width, event.xconfigure.height);
++ break;
++ case KeyPress:
++ {
++ char buffer[10];
++ int r, code;
++ code = XLookupKeysym(&event.xkey, 0);
++ if (code == XK_Left) {
++ }
++ else {
++ r = XLookupString(&event.xkey, buffer, sizeof(buffer),
++ NULL, NULL);
++ if (buffer[0] == 27) {
++ exit(0);
++ }
++ }
++ }
++ default:
++ /* nothing */
++ ;
++ }
++ }
++
++ if (MyID == 0 || !Sync)
++ Rot += 1;
++ redraw(dpy);
++ }
++}
++
++
++static XVisualInfo *
++choose_visual(Display *dpy)
++{
++ int attribs[] = { GLX_RGBA,
++ GLX_RED_SIZE, 1,
++ GLX_GREEN_SIZE, 1,
++ GLX_BLUE_SIZE, 1,
++ GLX_DOUBLEBUFFER,
++ GLX_DEPTH_SIZE, 1,
++ None };
++ int scrnum = DefaultScreen( dpy );
++ return glXChooseVisual(dpy, scrnum, attribs);
++}
++
++
++static void
++parse_opts(int argc, char *argv[])
++{
++ if (argc > 1) {
++ MyID = 1;
++ }
++}
++
++
++int
++main( int argc, char *argv[] )
++{
++ Display *dpy;
++ XVisualInfo *visinfo;
++
++ parse_opts(argc, argv);
++
++ dpy = XOpenDisplay(NULL);
++
++ visinfo = choose_visual(dpy);
++
++ Context = glXCreateContext( dpy, visinfo, NULL, True );
++ if (!Context) {
++ printf("Error: glXCreateContext failed\n");
++ exit(1);
++ }
++
++ if (MyID == 0) {
++ WindowID = make_gl_window(dpy, visinfo, Width, Height);
++ set_window_title(dpy, WindowID, "corender");
++ XMapWindow(dpy, WindowID);
++ /*printf("WindowID 0x%x\n", (int) WindowID);*/
++ }
++
++ /* do ipc hand-shake here */
++ setup_ipc();
++ assert(Sock);
++ assert(WindowID);
++
++ if (MyID == 1) {
++ set_event_mask(dpy, WindowID);
++ }
++
++ resize(dpy, Width, Height);
++
++ event_loop(dpy);
++
++ return 0;
++}
+diff -Naurp Mesa-7.8.1/progs/xdemos/glsync.c Mesa-7.8.1.patched/progs/xdemos/glsync.c
+--- Mesa-7.8.1/progs/xdemos/glsync.c 1970-01-01 01:00:00.000000000 +0100
++++ Mesa-7.8.1.patched/progs/xdemos/glsync.c 2010-06-13 13:45:06.789793146 +0200
+@@ -0,0 +1,295 @@
++/*
++ * Copyright © 2007 Intel Corporation
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice (including the next
++ * paragraph) shall be included in all copies or substantial portions of the
++ * Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ *
++ * Authors:
++ * Jesse Barnes <jesse.barnes@intel.com>
++ *
++ */
++
++/** @file glsync.c
++ * The program is simple: it paints a window alternating colors (red &
++ * white) either as fast as possible or synchronized to vblank events
++ *
++ * If run normally, the program should display a window that exhibits
++ * significant tearing between red and white colors (e.g. you might get
++ * a "waterfall" effect of red and white horizontal bars).
++ *
++ * If run with the '-s b' option, the program should synchronize the
++ * window color changes with the vertical blank period, resulting in a
++ * window that looks orangish with a high frequency flicker (which may
++ * be invisible). If the window is moved to another screen, this
++ * property should be preserved. If the window spans two screens, it
++ * shouldn't tear on whichever screen most of the window is on; the
++ * portion on the other screen may show some tearing (like the
++ * waterfall effect above).
++ *
++ * Other options include '-w <width>' and '-h <height' to set the
++ * window size.
++ */
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <unistd.h>
++#include <GL/gl.h>
++#include <GL/glu.h>
++#include <GL/glx.h>
++#include <GL/glxext.h>
++#include <X11/X.h>
++#include <X11/Xlib.h>
++#include <X11/Xutil.h>
++
++void (*video_sync_get)();
++void (*video_sync)();
++void (*swap_interval)();
++
++static int GLXExtensionSupported(Display *dpy, const char *extension)
++{
++ const char *extensionsString, *pos;
++
++ extensionsString = glXQueryExtensionsString(dpy, DefaultScreen(dpy));
++
++ pos = strstr(extensionsString, extension);
++
++ if (pos != NULL && (pos == extensionsString || pos[-1] == ' ') &&
++ (pos[strlen(extension)] == ' ' || pos[strlen(extension)] == '\0'))
++ return 1;
++
++ return 0;
++}
++
++extern char *optarg;
++extern int optind, opterr, optopt;
++static char optstr[] = "w:h:s:vi:";
++
++enum sync_type {
++ none = 0,
++ sgi_video_sync,
++ buffer_swap
++};
++
++static void usage(char *name)
++{
++ printf("usage: %s [-w <width>] [-h <height>] [-s<sync method>] "
++ "[-v]\n", name);
++ printf("\t-s<sync method>:\n");
++ printf("\t\tn: none\n");
++ printf("\t\ts: SGI video sync extension\n");
++ printf("\t\tb: buffer swap\n");
++ printf("\t-i<swap interval>\n");
++ printf("\t-v: verbose (print count)\n");
++ exit(-1);
++}
++
++int main(int argc, char *argv[])
++{
++ Display *disp;
++ XVisualInfo *pvi;
++ XSetWindowAttributes swa;
++ GLint last_val = -1, count = 0;
++ Window winGL;
++ GLXContext context;
++ int dummy;
++ Atom wmDelete;
++ enum sync_type waitforsync = none;
++ int width = 500, height = 500, verbose = 0, interval = 1;
++ int c, i = 1;
++ int ret;
++ int attribs[] = { GLX_RGBA,
++ GLX_RED_SIZE, 1,
++ GLX_GREEN_SIZE, 1,
++ GLX_BLUE_SIZE, 1,
++ None };
++ int db_attribs[] = { GLX_RGBA,
++ GLX_RED_SIZE, 1,
++ GLX_GREEN_SIZE, 1,
++ GLX_BLUE_SIZE, 1,
++ GLX_DOUBLEBUFFER,
++ GLX_DEPTH_SIZE, 1,
++ None };
++ XSizeHints sizehints;
++
++ opterr = 0;
++ while ((c = getopt(argc, argv, optstr)) != -1) {
++ switch (c) {
++ case 'w':
++ width = atoi(optarg);
++ break;
++ case 'h':
++ height = atoi(optarg);
++ break;
++ case 's':
++ switch (optarg[0]) {
++ case 'n':
++ waitforsync = none;
++ break;
++ case 's':
++ waitforsync = sgi_video_sync;
++ break;
++ case 'b':
++ waitforsync = buffer_swap;
++ break;
++ default:
++ usage(argv[0]);
++ break;
++ }
++ break;
++ case 'v':
++ verbose = 1;
++ break;
++ case 'i':
++ interval = atoi(optarg);
++ break;
++ default:
++ usage(argv[0]);
++ break;
++ }
++ }
++
++ disp = XOpenDisplay(NULL);
++ if (!disp) {
++ fprintf(stderr, "failed to open display\n");
++ return -1;
++ }
++
++ if (!glXQueryExtension(disp, &dummy, &dummy)) {
++ fprintf(stderr, "glXQueryExtension failed\n");
++ return -1;
++ }
++
++ if (!GLXExtensionSupported(disp, "GLX_SGI_video_sync")) {
++ fprintf(stderr, "GLX_SGI_video_sync not supported, exiting\n");
++ return -1;
++ }
++
++ if (waitforsync != buffer_swap) {
++ pvi = glXChooseVisual(disp, DefaultScreen(disp), attribs);
++ } else {
++ pvi = glXChooseVisual(disp, DefaultScreen(disp), db_attribs);
++ }
++
++ if (!pvi) {
++ fprintf(stderr, "failed to choose visual, exiting\n");
++ return -1;
++ }
++
++ pvi->screen = DefaultScreen(disp);
++
++ swa.colormap = XCreateColormap(disp, RootWindow(disp, pvi->screen),
++ pvi->visual, AllocNone);
++ swa.border_pixel = 0;
++ swa.event_mask = ExposureMask | KeyPressMask | ButtonPressMask |
++ StructureNotifyMask;
++ winGL = XCreateWindow(disp, RootWindow(disp, pvi->screen),
++ 0, 0,
++ width, height,
++ 0, pvi->depth, InputOutput, pvi->visual,
++ CWBorderPixel | CWColormap | CWEventMask, &swa);
++ if (!winGL) {
++ fprintf(stderr, "window creation failed\n");
++ return -1;
++ }
++ wmDelete = XInternAtom(disp, "WM_DELETE_WINDOW", True);
++ XSetWMProtocols(disp, winGL, &wmDelete, 1);
++
++ sizehints.x = 0;
++ sizehints.y = 0;
++ sizehints.width = width;
++ sizehints.height = height;
++ sizehints.flags = USSize | USPosition;
++
++ XSetNormalHints(disp, winGL, &sizehints);
++ XSetStandardProperties(disp, winGL, "glsync test", "glsync text",
++ None, NULL, 0, &sizehints);
++
++ context = glXCreateContext(disp, pvi, NULL, GL_TRUE);
++ if (!context) {
++ fprintf(stderr, "failed to create glx context\n");
++ return -1;
++ }
++
++ XMapWindow(disp, winGL);
++ ret = glXMakeCurrent(disp, winGL, context);
++ if (!ret) {
++ fprintf(stderr, "failed to make context current: %d\n", ret);
++ }
++
++ video_sync_get = glXGetProcAddress((unsigned char *)"glXGetVideoSyncSGI");
++ video_sync = glXGetProcAddress((unsigned char *)"glXWaitVideoSyncSGI");
++
++ swap_interval = glXGetProcAddress((unsigned char *)"glXSwapIntervalSGI");
++
++ if (!video_sync_get || !video_sync || !swap_interval) {
++ fprintf(stderr, "failed to get sync functions\n");
++ return -1;
++ }
++
++ if (waitforsync == buffer_swap) {
++ swap_interval(interval);
++ fprintf(stderr, "set swap interval to %d\n", interval);
++ }
++ video_sync_get(&count);
++ count++;
++ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
++ while (i++) {
++ /* Alternate colors to make tearing obvious */
++ if (i & 1) {
++ glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
++ glColor3f(1.0f, 1.0f, 1.0f);
++ } else {
++ glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
++ glColor3f(1.0f, 0.0f, 0.0f);
++ }
++
++ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
++ glRectf(0, 0, width, height);
++
++ /* Wait for vsync */
++ if (waitforsync == sgi_video_sync) {
++ if (verbose)
++ fprintf(stderr, "waiting on count %d\n", count);
++ video_sync(2, (count + 1) % 2, &count);
++ if (count < last_val)
++ fprintf(stderr, "error: vblank count went backwards: %d -> %d\n", last_val, count);
++ if (count == last_val)
++ fprintf(stderr, "error: count didn't change: %d\n", count);
++ last_val = count;
++ glFlush();
++ } else if (waitforsync == buffer_swap) {
++ glXSwapBuffers(disp, winGL);
++ } else {
++ video_sync_get(&count);
++ sleep(1);
++ glFinish();
++ }
++
++ if (verbose) {
++ video_sync_get(&count);
++ fprintf(stderr, "current count: %d\n", count);
++ }
++ }
++
++ XDestroyWindow(disp, winGL);
++ glXDestroyContext(disp, context);
++ XCloseDisplay(disp);
++
++ return 0;
++}
+diff -Naurp Mesa-7.8.1/progs/xdemos/glthreads.c Mesa-7.8.1.patched/progs/xdemos/glthreads.c
+--- Mesa-7.8.1/progs/xdemos/glthreads.c 1970-01-01 01:00:00.000000000 +0100
++++ Mesa-7.8.1.patched/progs/xdemos/glthreads.c 2010-06-13 13:45:06.789793146 +0200
+@@ -0,0 +1,716 @@
++/*
++ * Copyright (C) 2000 Brian Paul All Rights Reserved.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included
++ * in all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
++ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
++ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
++ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
++ */
++
++
++/*
++ * This program tests GLX thread safety.
++ * Command line options:
++ * -p Open a display connection for each thread
++ * -l Enable application-side locking
++ * -n <num threads> Number of threads to create (default is 2)
++ * -display <display name> Specify X display (default is $DISPLAY)
++ * -t Use texture mapping
++ *
++ * Brian Paul 20 July 2000
++ */
++
++
++/*
++ * Notes:
++ * - Each thread gets its own GLX context.
++ *
++ * - The GLX contexts share texture objects.
++ *
++ * - When 't' is pressed to update the texture image, the window/thread which
++ * has input focus is signalled to change the texture. The other threads
++ * should see the updated texture the next time they call glBindTexture.
++ */
++
++
++#if defined(PTHREADS) /* defined by Mesa on Linux and other platforms */
++
++#include <assert.h>
++#include <GL/gl.h>
++#include <GL/glx.h>
++#include <math.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <unistd.h>
++#include <pthread.h>
++
++
++/*
++ * Each window/thread/context:
++ */
++struct winthread {
++ Display *Dpy;
++ int Index;
++ pthread_t Thread;
++ Window Win;
++ GLXContext Context;
++ float Angle;
++ int WinWidth, WinHeight;
++ GLboolean NewSize;
++ GLboolean Initialized;
++ GLboolean MakeNewTexture;
++};
++
++
++#define MAX_WINTHREADS 100
++static struct winthread WinThreads[MAX_WINTHREADS];
++static int NumWinThreads = 0;
++static volatile GLboolean ExitFlag = GL_FALSE;
++
++static GLboolean MultiDisplays = 0;
++static GLboolean Locking = 0;
++static GLboolean Texture = GL_FALSE;
++static GLuint TexObj = 12;
++static GLboolean Animate = GL_TRUE;
++
++static pthread_mutex_t Mutex;
++static pthread_cond_t CondVar;
++static pthread_mutex_t CondMutex;
++
++
++static void
++Error(const char *msg)
++{
++ fprintf(stderr, "Error: %s\n", msg);
++ exit(1);
++}
++
++
++static void
++signal_redraw(void)
++{
++ pthread_mutex_lock(&CondMutex);
++ pthread_cond_broadcast(&CondVar);
++ pthread_mutex_unlock(&CondMutex);
++}
++
++
++static void
++MakeNewTexture(struct winthread *wt)
++{
++#define TEX_SIZE 128
++ static float step = 0.0;
++ GLfloat image[TEX_SIZE][TEX_SIZE][4];
++ GLint width;
++ int i, j;
++
++ for (j = 0; j < TEX_SIZE; j++) {
++ for (i = 0; i < TEX_SIZE; i++) {
++ float dt = 5.0 * (j - 0.5 * TEX_SIZE) / TEX_SIZE;
++ float ds = 5.0 * (i - 0.5 * TEX_SIZE) / TEX_SIZE;
++ float r = dt * dt + ds * ds + step;
++ image[j][i][0] =
++ image[j][i][1] =
++ image[j][i][2] = 0.75 + 0.25 * cos(r);
++ image[j][i][3] = 1.0;
++ }
++ }
++
++ step += 0.5;
++
++ glBindTexture(GL_TEXTURE_2D, TexObj);
++
++ glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
++ if (width) {
++ assert(width == TEX_SIZE);
++ /* sub-tex replace */
++ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, TEX_SIZE, TEX_SIZE,
++ GL_RGBA, GL_FLOAT, image);
++ }
++ else {
++ /* create new */
++ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
++ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
++
++ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TEX_SIZE, TEX_SIZE, 0,
++ GL_RGBA, GL_FLOAT, image);
++ }
++}
++
++
++
++/* draw a colored cube */
++static void
++draw_object(void)
++{
++ glPushMatrix();
++ glScalef(0.75, 0.75, 0.75);
++
++ glColor3f(1, 0, 0);
++
++ if (Texture) {
++ glBindTexture(GL_TEXTURE_2D, TexObj);
++ glEnable(GL_TEXTURE_2D);
++ }
++ else {
++ glDisable(GL_TEXTURE_2D);
++ }
++
++ glBegin(GL_QUADS);
++
++ /* -X */
++ glColor3f(0, 1, 1);
++ glTexCoord2f(0, 0); glVertex3f(-1, -1, -1);
++ glTexCoord2f(1, 0); glVertex3f(-1, 1, -1);
++ glTexCoord2f(1, 1); glVertex3f(-1, 1, 1);
++ glTexCoord2f(0, 1); glVertex3f(-1, -1, 1);
++
++ /* +X */
++ glColor3f(1, 0, 0);
++ glTexCoord2f(0, 0); glVertex3f(1, -1, -1);
++ glTexCoord2f(1, 0); glVertex3f(1, 1, -1);
++ glTexCoord2f(1, 1); glVertex3f(1, 1, 1);
++ glTexCoord2f(0, 1); glVertex3f(1, -1, 1);
++
++ /* -Y */
++ glColor3f(1, 0, 1);
++ glTexCoord2f(0, 0); glVertex3f(-1, -1, -1);
++ glTexCoord2f(1, 0); glVertex3f( 1, -1, -1);
++ glTexCoord2f(1, 1); glVertex3f( 1, -1, 1);
++ glTexCoord2f(0, 1); glVertex3f(-1, -1, 1);
++
++ /* +Y */
++ glColor3f(0, 1, 0);
++ glTexCoord2f(0, 0); glVertex3f(-1, 1, -1);
++ glTexCoord2f(1, 0); glVertex3f( 1, 1, -1);
++ glTexCoord2f(1, 1); glVertex3f( 1, 1, 1);
++ glTexCoord2f(0, 1); glVertex3f(-1, 1, 1);
++
++ /* -Z */
++ glColor3f(1, 1, 0);
++ glTexCoord2f(0, 0); glVertex3f(-1, -1, -1);
++ glTexCoord2f(1, 0); glVertex3f( 1, -1, -1);
++ glTexCoord2f(1, 1); glVertex3f( 1, 1, -1);
++ glTexCoord2f(0, 1); glVertex3f(-1, 1, -1);
++
++ /* +Y */
++ glColor3f(0, 0, 1);
++ glTexCoord2f(0, 0); glVertex3f(-1, -1, 1);
++ glTexCoord2f(1, 0); glVertex3f( 1, -1, 1);
++ glTexCoord2f(1, 1); glVertex3f( 1, 1, 1);
++ glTexCoord2f(0, 1); glVertex3f(-1, 1, 1);
++
++ glEnd();
++
++ glPopMatrix();
++}
++
++
++/* signal resize of given window */
++static void
++resize(struct winthread *wt, int w, int h)
++{
++ wt->NewSize = GL_TRUE;
++ wt->WinWidth = w;
++ wt->WinHeight = h;
++ if (!Animate)
++ signal_redraw();
++}
++
++
++/*
++ * We have an instance of this for each thread.
++ */
++static void
++draw_loop(struct winthread *wt)
++{
++ while (!ExitFlag) {
++
++ if (Locking)
++ pthread_mutex_lock(&Mutex);
++
++ glXMakeCurrent(wt->Dpy, wt->Win, wt->Context);
++ if (!wt->Initialized) {
++ printf("glthreads: %d: GL_RENDERER = %s\n", wt->Index,
++ (char *) glGetString(GL_RENDERER));
++ if (Texture /*&& wt->Index == 0*/) {
++ MakeNewTexture(wt);
++ }
++ wt->Initialized = GL_TRUE;
++ }
++
++ if (Locking)
++ pthread_mutex_unlock(&Mutex);
++
++ glEnable(GL_DEPTH_TEST);
++
++ if (wt->NewSize) {
++ GLfloat w = (float) wt->WinWidth / (float) wt->WinHeight;
++ glViewport(0, 0, wt->WinWidth, wt->WinHeight);
++ glMatrixMode(GL_PROJECTION);
++ glLoadIdentity();
++ glFrustum(-w, w, -1.0, 1.0, 1.5, 10);
++ glMatrixMode(GL_MODELVIEW);
++ glLoadIdentity();
++ glTranslatef(0, 0, -2.5);
++ wt->NewSize = GL_FALSE;
++ }
++
++ if (wt->MakeNewTexture) {
++ MakeNewTexture(wt);
++ wt->MakeNewTexture = GL_FALSE;
++ }
++
++ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
++
++ glPushMatrix();
++ glRotatef(wt->Angle, 0, 1, 0);
++ glRotatef(wt->Angle, 1, 0, 0);
++ glScalef(0.7, 0.7, 0.7);
++ draw_object();
++ glPopMatrix();
++
++ if (Locking)
++ pthread_mutex_lock(&Mutex);
++
++ glXSwapBuffers(wt->Dpy, wt->Win);
++
++ if (Locking)
++ pthread_mutex_unlock(&Mutex);
++
++ if (Animate) {
++ usleep(5000);
++ }
++ else {
++ /* wait for signal to draw */
++ pthread_mutex_lock(&CondMutex);
++ pthread_cond_wait(&CondVar, &CondMutex);
++ pthread_mutex_unlock(&CondMutex);
++ }
++ wt->Angle += 1.0;
++ }
++}
++
++
++static void
++keypress(XEvent *event, struct winthread *wt)
++{
++ char buf[100];
++ KeySym keySym;
++ XComposeStatus stat;
++
++ XLookupString(&event->xkey, buf, sizeof(buf), &keySym, &stat);
++
++ switch (keySym) {
++ case XK_Escape:
++ /* tell all threads to exit */
++ if (!Animate) {
++ signal_redraw();
++ }
++ ExitFlag = GL_TRUE;
++ /*printf("exit draw_loop %d\n", wt->Index);*/
++ return;
++ case XK_t:
++ case XK_T:
++ if (Texture) {
++ wt->MakeNewTexture = GL_TRUE;
++ if (!Animate)
++ signal_redraw();
++ }
++ break;
++ case XK_a:
++ case XK_A:
++ Animate = !Animate;
++ if (Animate) /* yes, prev Animate state! */
++ signal_redraw();
++ break;
++ case XK_s:
++ case XK_S:
++ if (!Animate)
++ signal_redraw();
++ break;
++ default:
++ ; /* nop */
++ }
++}
++
++
++/*
++ * The main process thread runs this loop.
++ * Single display connection for all threads.
++ */
++static void
++event_loop(Display *dpy)
++{
++ XEvent event;
++ int i;
++
++ assert(!MultiDisplays);
++
++ while (!ExitFlag) {
++
++ if (Locking) {
++ while (1) {
++ int k;
++ pthread_mutex_lock(&Mutex);
++ k = XPending(dpy);
++ if (k) {
++ XNextEvent(dpy, &event);
++ pthread_mutex_unlock(&Mutex);
++ break;
++ }
++ pthread_mutex_unlock(&Mutex);
++ usleep(5000);
++ }
++ }
++ else {
++ XNextEvent(dpy, &event);
++ }
++
++ switch (event.type) {
++ case ConfigureNotify:
++ /* Find winthread for this event's window */
++ for (i = 0; i < NumWinThreads; i++) {
++ struct winthread *wt = &WinThreads[i];
++ if (event.xconfigure.window == wt->Win) {
++ resize(wt, event.xconfigure.width,