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 | |
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')
-rw-r--r-- | package/MesaLib/Makefile | 17 | ||||
-rw-r--r-- | package/MesaLib/patches/000-mesalib-xdemos.patch | 14774 |
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, |