get rid of unused span->start field
[mesa.git] / progs / xdemos / glthreads.c
index 63a94c55681327e7e60ebe6a2967c050ee808a9c..83413383dd4d8f66c43708a3453d32d35394f38a 100644 (file)
@@ -1,4 +1,3 @@
-
 /*
  * Copyright (C) 2000  Brian Paul   All Rights Reserved.
  * 
@@ -24,6 +23,7 @@
 /*
  * This program tests GLX thread safety.
  * Command line options:
+ *  -p                       Open a display connection for each thread
  *  -n <num threads>         Number of threads to create (default is 2)
  *  -display <display name>  Specify X display (default is :0.0)
  *
@@ -33,6 +33,7 @@
 
 #if defined(PTHREADS)   /* defined by Mesa on Linux and other platforms */
 
+#include <assert.h>
 #include <GL/gl.h>
 #include <GL/glx.h>
 #include <stdio.h>
@@ -60,8 +61,12 @@ struct winthread {
 #define MAX_WINTHREADS 100
 static struct winthread WinThreads[MAX_WINTHREADS];
 static int NumWinThreads = 0;
-static GLboolean ExitFlag = GL_FALSE;
+static volatile GLboolean ExitFlag = GL_FALSE;
+
+static GLboolean MultiDisplays = 0;
+static GLboolean Locking = 0;
 
+static pthread_mutex_t Mutex;
 
 
 static void
@@ -146,9 +151,22 @@ resize(struct winthread *wt, int w, int h)
 static void
 draw_loop(struct winthread *wt)
 {
+   GLboolean firstIter = GL_TRUE;
+
    while (!ExitFlag) {
 
+      if (Locking)
+         pthread_mutex_lock(&Mutex);
+
       glXMakeCurrent(wt->Dpy, wt->Win, wt->Context);
+      if (firstIter) {
+         printf("glthreads: %d: GL_RENDERER = %s\n", wt->Index,
+                (char *) glGetString(GL_RENDERER));
+         firstIter = GL_FALSE;
+      }
+
+      if (Locking)
+         pthread_mutex_unlock(&Mutex);
 
       glEnable(GL_DEPTH_TEST);
 
@@ -173,8 +191,15 @@ draw_loop(struct winthread *wt)
          draw_object();
       glPopMatrix();
 
+      if (Locking)
+         pthread_mutex_lock(&Mutex);
+
       glXSwapBuffers(wt->Dpy, wt->Win);
 
+      if (Locking)
+         pthread_mutex_unlock(&Mutex);
+
+      usleep(5000);
       wt->Angle += 1.0;
    }
 }
@@ -182,42 +207,95 @@ draw_loop(struct winthread *wt)
 
 /*
  * 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) {
-      static long mask = StructureNotifyMask | ExposureMask | KeyPressMask;
-      XEvent event;
-      int i;
 
-      for (i = 0; i < NumWinThreads; i++) {
-         struct winthread *wt = &WinThreads[i];
-         while (XCheckWindowEvent(dpy, wt->Win, mask, &event)) {
-            if (event.xany.window == wt->Win) {
-               switch (event.type) {
-                  case ConfigureNotify:
-                     resize(wt, event.xconfigure.width,
-                            event.xconfigure.height);
-                     break;
-                  case KeyPress:
-                     /* tell all threads to exit */
-                     ExitFlag = GL_TRUE;
-                     /*printf("exit draw_loop %d\n", wt->Index);*/
-                     return;
-                  default:
-                     /*no-op*/ ;
-               }
+      if (Locking) {
+         while (1) {
+            int k;
+            pthread_mutex_lock(&Mutex);
+            k = XPending(dpy);
+            if (k) {
+               XNextEvent(dpy, &event);
+               pthread_mutex_unlock(&Mutex);
+               break;
             }
-            else {
-               printf("window mismatch\n");
+            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:
+            /* tell all threads to exit */
+            ExitFlag = GL_TRUE;
+            /*printf("exit draw_loop %d\n", wt->Index);*/
+            return;
+         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:
+            /* tell all threads to exit */
+            ExitFlag = GL_TRUE;
+            /*printf("exit draw_loop %d\n", wt->Index);*/
+            return;
+         default:
+            /*no-op*/ ;
          }
       }
+      w = (w + 1) % NumWinThreads;
+      usleep(5000);
    }
 }
 
 
+
 /*
  * we'll call this once for each thread, before the threads are created.
  */
@@ -333,14 +411,14 @@ main(int argc, char *argv[])
 {
    char *displayName = ":0.0";
    int numThreads = 2;
-   Display *dpy;
+   Display *dpy = NULL;
    int i;
    Status threadStat;
 
    if (argc == 1) {
-      printf("threadgl: test of GL thread safety (any key = exit)\n");
+      printf("glthreads: test of GL thread safety (any key = exit)\n");
       printf("Usage:\n");
-      printf("  threadgl [-display dpyName] [-n numthreads]\n");
+      printf("  glthreads [-display dpyName] [-n numthreads]\n");
    }
    else {
       int i;
@@ -349,6 +427,12 @@ main(int argc, char *argv[])
             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], "-n") == 0 && i + 1 < argc) {
             numThreads = atoi(argv[i + 1]);
             if (numThreads < 1)
@@ -357,48 +441,88 @@ main(int argc, char *argv[])
                numThreads = MAX_WINTHREADS;
             i++;
          }
+         else {
+            fprintf(stderr, "glthreads: unexpected flag: %s\n", argv[i]);
+         }
       }
    }
    
+   if (Locking)
+      printf("glthreads: Using explict 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.
     */
-   threadStat = XInitThreads();
-   if (threadStat) {
-      printf("XInitThreads() returned %d (success)\n", (int) threadStat);
-   }
-   else {
-      printf("XInitThreads() returned 0 (failure- this program may fail)\n");
-   }
+   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", displayName);
+         return -1;
+      }
+   }
 
-   dpy = XOpenDisplay(displayName);
-   if (!dpy) {
-      fprintf(stderr, "Unable to open display %s\n", displayName);
-      return -1;
+   if (Locking) {
+      pthread_mutex_init(&Mutex, NULL);
    }
 
+   printf("glthreads: creating windows\n");
+
    NumWinThreads = numThreads;
 
    /* Create the GLX windows and contexts */
    for (i = 0; i < numThreads; i++) {
-      WinThreads[i].Dpy = dpy;
+      if (MultiDisplays) {
+         WinThreads[i].Dpy = XOpenDisplay(displayName);
+         assert(WinThreads[i].Dpy);
+      }
+      else {
+         WinThreads[i].Dpy = dpy;
+      }
       WinThreads[i].Index = i;
       create_window(&WinThreads[i]);
    }
 
+   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("Created Thread %p\n", WinThreads[i].Thread);
+      printf("glthreads: Created thread %u\n", (unsigned int) WinThreads[i].Thread);
    }
 
-   event_loop(dpy);
+   if (MultiDisplays)
+      event_loop_multi();
+   else
+      event_loop(dpy);
 
    clean_up();
 
-   XCloseDisplay(dpy);
+   if (MultiDisplays) {
+      for (i = 0; i < numThreads; i++) {
+         XCloseDisplay(WinThreads[i].Dpy);
+      }
+   }
+   else {
+      XCloseDisplay(dpy);
+   }
 
    return 0;
 }