132001f49Smrg/* 232001f49Smrg * Copyright (C) 2000 Brian Paul All Rights Reserved. 332001f49Smrg * 432001f49Smrg * Permission is hereby granted, free of charge, to any person obtaining a 532001f49Smrg * copy of this software and associated documentation files (the "Software"), 632001f49Smrg * to deal in the Software without restriction, including without limitation 732001f49Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 832001f49Smrg * and/or sell copies of the Software, and to permit persons to whom the 932001f49Smrg * Software is furnished to do so, subject to the following conditions: 1032001f49Smrg * 1132001f49Smrg * The above copyright notice and this permission notice shall be included 1232001f49Smrg * in all copies or substantial portions of the Software. 1332001f49Smrg * 1432001f49Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 1532001f49Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1632001f49Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1732001f49Smrg * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 1832001f49Smrg * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 1932001f49Smrg * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 2032001f49Smrg */ 2132001f49Smrg 2232001f49Smrg 2332001f49Smrg/* 2432001f49Smrg * This program tests GLX thread safety. 2532001f49Smrg * Command line options: 2632001f49Smrg * -p Open a display connection for each thread 2732001f49Smrg * -l Enable application-side locking 2832001f49Smrg * -n <num threads> Number of threads to create (default is 2) 2932001f49Smrg * -display <display name> Specify X display (default is $DISPLAY) 3032001f49Smrg * -t Use texture mapping 3132001f49Smrg * 3232001f49Smrg * Brian Paul 20 July 2000 3332001f49Smrg */ 3432001f49Smrg 3532001f49Smrg 3632001f49Smrg/* 3732001f49Smrg * Notes: 3832001f49Smrg * - Each thread gets its own GLX context. 3932001f49Smrg * 4032001f49Smrg * - The GLX contexts share texture objects. 4132001f49Smrg * 4232001f49Smrg * - When 't' is pressed to update the texture image, the window/thread which 4332001f49Smrg * has input focus is signalled to change the texture. The other threads 4432001f49Smrg * should see the updated texture the next time they call glBindTexture. 4532001f49Smrg */ 4632001f49Smrg 4732001f49Smrg 4832001f49Smrg#include <assert.h> 4932001f49Smrg#include <GL/gl.h> 5032001f49Smrg#include <GL/glx.h> 5132001f49Smrg#include <math.h> 5232001f49Smrg#include <stdio.h> 5332001f49Smrg#include <stdlib.h> 5432001f49Smrg#include <string.h> 5532001f49Smrg#include <unistd.h> 5632001f49Smrg#include <pthread.h> 5732001f49Smrg 5832001f49Smrg 5932001f49Smrg/* 6032001f49Smrg * Each window/thread/context: 6132001f49Smrg */ 6232001f49Smrgstruct winthread { 6332001f49Smrg Display *Dpy; 6432001f49Smrg int Index; 6532001f49Smrg pthread_t Thread; 6632001f49Smrg Window Win; 6732001f49Smrg GLXContext Context; 6832001f49Smrg float Angle; 6932001f49Smrg int WinWidth, WinHeight; 7032001f49Smrg GLboolean NewSize; 7132001f49Smrg GLboolean Initialized; 7232001f49Smrg GLboolean MakeNewTexture; 7332001f49Smrg}; 7432001f49Smrg 7532001f49Smrg 7632001f49Smrg#define MAX_WINTHREADS 100 7732001f49Smrgstatic struct winthread WinThreads[MAX_WINTHREADS]; 7832001f49Smrgstatic int NumWinThreads = 0; 7932001f49Smrgstatic volatile GLboolean ExitFlag = GL_FALSE; 8032001f49Smrg 8132001f49Smrgstatic GLboolean MultiDisplays = 0; 8232001f49Smrgstatic GLboolean Locking = 0; 8332001f49Smrgstatic GLboolean Texture = GL_FALSE; 8432001f49Smrgstatic GLuint TexObj = 12; 8532001f49Smrgstatic GLboolean Animate = GL_TRUE; 8632001f49Smrg 8732001f49Smrgstatic pthread_mutex_t Mutex; 8832001f49Smrgstatic pthread_cond_t CondVar; 8932001f49Smrgstatic pthread_mutex_t CondMutex; 9032001f49Smrg 9132001f49Smrg 9232001f49Smrgstatic void 9332001f49SmrgError(const char *msg) 9432001f49Smrg{ 9532001f49Smrg fprintf(stderr, "Error: %s\n", msg); 9632001f49Smrg exit(1); 9732001f49Smrg} 9832001f49Smrg 9932001f49Smrg 10032001f49Smrgstatic void 10132001f49Smrgsignal_redraw(void) 10232001f49Smrg{ 10332001f49Smrg pthread_mutex_lock(&CondMutex); 10432001f49Smrg pthread_cond_broadcast(&CondVar); 10532001f49Smrg pthread_mutex_unlock(&CondMutex); 10632001f49Smrg} 10732001f49Smrg 10832001f49Smrg 10932001f49Smrgstatic void 11032001f49SmrgMakeNewTexture(struct winthread *wt) 11132001f49Smrg{ 11232001f49Smrg#define TEX_SIZE 128 11332001f49Smrg static float step = 0.0; 11432001f49Smrg GLfloat image[TEX_SIZE][TEX_SIZE][4]; 11532001f49Smrg GLint width; 11632001f49Smrg int i, j; 11732001f49Smrg 11832001f49Smrg for (j = 0; j < TEX_SIZE; j++) { 11932001f49Smrg for (i = 0; i < TEX_SIZE; i++) { 12032001f49Smrg float dt = 5.0 * (j - 0.5 * TEX_SIZE) / TEX_SIZE; 12132001f49Smrg float ds = 5.0 * (i - 0.5 * TEX_SIZE) / TEX_SIZE; 12232001f49Smrg float r = dt * dt + ds * ds + step; 12332001f49Smrg image[j][i][0] = 12432001f49Smrg image[j][i][1] = 12532001f49Smrg image[j][i][2] = 0.75 + 0.25 * cos(r); 12632001f49Smrg image[j][i][3] = 1.0; 12732001f49Smrg } 12832001f49Smrg } 12932001f49Smrg 13032001f49Smrg step += 0.5; 13132001f49Smrg 13232001f49Smrg glBindTexture(GL_TEXTURE_2D, TexObj); 13332001f49Smrg 13432001f49Smrg glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width); 13532001f49Smrg if (width) { 13632001f49Smrg assert(width == TEX_SIZE); 13732001f49Smrg /* sub-tex replace */ 13832001f49Smrg glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, TEX_SIZE, TEX_SIZE, 13932001f49Smrg GL_RGBA, GL_FLOAT, image); 14032001f49Smrg } 14132001f49Smrg else { 14232001f49Smrg /* create new */ 14332001f49Smrg glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 14432001f49Smrg glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 14532001f49Smrg 14632001f49Smrg glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TEX_SIZE, TEX_SIZE, 0, 14732001f49Smrg GL_RGBA, GL_FLOAT, image); 14832001f49Smrg } 14932001f49Smrg} 15032001f49Smrg 15132001f49Smrg 15232001f49Smrg 15332001f49Smrg/* draw a colored cube */ 15432001f49Smrgstatic void 15532001f49Smrgdraw_object(void) 15632001f49Smrg{ 15732001f49Smrg glPushMatrix(); 15832001f49Smrg glScalef(0.75, 0.75, 0.75); 15932001f49Smrg 16032001f49Smrg glColor3f(1, 0, 0); 16132001f49Smrg 16232001f49Smrg if (Texture) { 16332001f49Smrg glBindTexture(GL_TEXTURE_2D, TexObj); 16432001f49Smrg glEnable(GL_TEXTURE_2D); 16532001f49Smrg } 16632001f49Smrg else { 16732001f49Smrg glDisable(GL_TEXTURE_2D); 16832001f49Smrg } 16932001f49Smrg 17032001f49Smrg glBegin(GL_QUADS); 17132001f49Smrg 17232001f49Smrg /* -X */ 17332001f49Smrg glColor3f(0, 1, 1); 17432001f49Smrg glTexCoord2f(0, 0); glVertex3f(-1, -1, -1); 17532001f49Smrg glTexCoord2f(1, 0); glVertex3f(-1, 1, -1); 17632001f49Smrg glTexCoord2f(1, 1); glVertex3f(-1, 1, 1); 17732001f49Smrg glTexCoord2f(0, 1); glVertex3f(-1, -1, 1); 17832001f49Smrg 17932001f49Smrg /* +X */ 18032001f49Smrg glColor3f(1, 0, 0); 18132001f49Smrg glTexCoord2f(0, 0); glVertex3f(1, -1, -1); 18232001f49Smrg glTexCoord2f(1, 0); glVertex3f(1, 1, -1); 18332001f49Smrg glTexCoord2f(1, 1); glVertex3f(1, 1, 1); 18432001f49Smrg glTexCoord2f(0, 1); glVertex3f(1, -1, 1); 18532001f49Smrg 18632001f49Smrg /* -Y */ 18732001f49Smrg glColor3f(1, 0, 1); 18832001f49Smrg glTexCoord2f(0, 0); glVertex3f(-1, -1, -1); 18932001f49Smrg glTexCoord2f(1, 0); glVertex3f( 1, -1, -1); 19032001f49Smrg glTexCoord2f(1, 1); glVertex3f( 1, -1, 1); 19132001f49Smrg glTexCoord2f(0, 1); glVertex3f(-1, -1, 1); 19232001f49Smrg 19332001f49Smrg /* +Y */ 19432001f49Smrg glColor3f(0, 1, 0); 19532001f49Smrg glTexCoord2f(0, 0); glVertex3f(-1, 1, -1); 19632001f49Smrg glTexCoord2f(1, 0); glVertex3f( 1, 1, -1); 19732001f49Smrg glTexCoord2f(1, 1); glVertex3f( 1, 1, 1); 19832001f49Smrg glTexCoord2f(0, 1); glVertex3f(-1, 1, 1); 19932001f49Smrg 20032001f49Smrg /* -Z */ 20132001f49Smrg glColor3f(1, 1, 0); 20232001f49Smrg glTexCoord2f(0, 0); glVertex3f(-1, -1, -1); 20332001f49Smrg glTexCoord2f(1, 0); glVertex3f( 1, -1, -1); 20432001f49Smrg glTexCoord2f(1, 1); glVertex3f( 1, 1, -1); 20532001f49Smrg glTexCoord2f(0, 1); glVertex3f(-1, 1, -1); 20632001f49Smrg 20732001f49Smrg /* +Y */ 20832001f49Smrg glColor3f(0, 0, 1); 20932001f49Smrg glTexCoord2f(0, 0); glVertex3f(-1, -1, 1); 21032001f49Smrg glTexCoord2f(1, 0); glVertex3f( 1, -1, 1); 21132001f49Smrg glTexCoord2f(1, 1); glVertex3f( 1, 1, 1); 21232001f49Smrg glTexCoord2f(0, 1); glVertex3f(-1, 1, 1); 21332001f49Smrg 21432001f49Smrg glEnd(); 21532001f49Smrg 21632001f49Smrg glPopMatrix(); 21732001f49Smrg} 21832001f49Smrg 21932001f49Smrg 22032001f49Smrg/* signal resize of given window */ 22132001f49Smrgstatic void 22232001f49Smrgresize(struct winthread *wt, int w, int h) 22332001f49Smrg{ 22432001f49Smrg wt->NewSize = GL_TRUE; 22532001f49Smrg wt->WinWidth = w; 22632001f49Smrg wt->WinHeight = h; 22732001f49Smrg if (!Animate) 22832001f49Smrg signal_redraw(); 22932001f49Smrg} 23032001f49Smrg 23132001f49Smrg 23232001f49Smrg/* 23332001f49Smrg * We have an instance of this for each thread. 23432001f49Smrg */ 23532001f49Smrgstatic void 23632001f49Smrgdraw_loop(struct winthread *wt) 23732001f49Smrg{ 23832001f49Smrg while (!ExitFlag) { 23932001f49Smrg 24032001f49Smrg if (Locking) 24132001f49Smrg pthread_mutex_lock(&Mutex); 24232001f49Smrg 24332001f49Smrg glXMakeCurrent(wt->Dpy, wt->Win, wt->Context); 24432001f49Smrg if (!wt->Initialized) { 24532001f49Smrg printf("glthreads: %d: GL_RENDERER = %s\n", wt->Index, 24632001f49Smrg (char *) glGetString(GL_RENDERER)); 24732001f49Smrg if (Texture /*&& wt->Index == 0*/) { 24832001f49Smrg MakeNewTexture(wt); 24932001f49Smrg } 25032001f49Smrg wt->Initialized = GL_TRUE; 25132001f49Smrg } 25232001f49Smrg 25332001f49Smrg if (Locking) 25432001f49Smrg pthread_mutex_unlock(&Mutex); 25532001f49Smrg 25632001f49Smrg glEnable(GL_DEPTH_TEST); 25732001f49Smrg 25832001f49Smrg if (wt->NewSize) { 25932001f49Smrg GLfloat w = (float) wt->WinWidth / (float) wt->WinHeight; 26032001f49Smrg glViewport(0, 0, wt->WinWidth, wt->WinHeight); 26132001f49Smrg glMatrixMode(GL_PROJECTION); 26232001f49Smrg glLoadIdentity(); 26332001f49Smrg glFrustum(-w, w, -1.0, 1.0, 1.5, 10); 26432001f49Smrg glMatrixMode(GL_MODELVIEW); 26532001f49Smrg glLoadIdentity(); 26632001f49Smrg glTranslatef(0, 0, -2.5); 26732001f49Smrg wt->NewSize = GL_FALSE; 26832001f49Smrg } 26932001f49Smrg 27032001f49Smrg if (wt->MakeNewTexture) { 27132001f49Smrg MakeNewTexture(wt); 27232001f49Smrg wt->MakeNewTexture = GL_FALSE; 27332001f49Smrg } 27432001f49Smrg 27532001f49Smrg glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 27632001f49Smrg 27732001f49Smrg glPushMatrix(); 27832001f49Smrg glRotatef(wt->Angle, 0, 1, 0); 27932001f49Smrg glRotatef(wt->Angle, 1, 0, 0); 28032001f49Smrg glScalef(0.7, 0.7, 0.7); 28132001f49Smrg draw_object(); 28232001f49Smrg glPopMatrix(); 28332001f49Smrg 28432001f49Smrg if (Locking) 28532001f49Smrg pthread_mutex_lock(&Mutex); 28632001f49Smrg 28732001f49Smrg glXSwapBuffers(wt->Dpy, wt->Win); 28832001f49Smrg 28932001f49Smrg if (Locking) 29032001f49Smrg pthread_mutex_unlock(&Mutex); 29132001f49Smrg 29232001f49Smrg if (Animate) { 29332001f49Smrg usleep(5000); 29432001f49Smrg } 29532001f49Smrg else { 29632001f49Smrg /* wait for signal to draw */ 29732001f49Smrg pthread_mutex_lock(&CondMutex); 29832001f49Smrg pthread_cond_wait(&CondVar, &CondMutex); 29932001f49Smrg pthread_mutex_unlock(&CondMutex); 30032001f49Smrg } 30132001f49Smrg wt->Angle += 1.0; 30232001f49Smrg } 30332001f49Smrg} 30432001f49Smrg 30532001f49Smrg 30632001f49Smrgstatic void 30732001f49Smrgkeypress(XEvent *event, struct winthread *wt) 30832001f49Smrg{ 30932001f49Smrg char buf[100]; 31032001f49Smrg KeySym keySym; 31132001f49Smrg XComposeStatus stat; 31232001f49Smrg 31332001f49Smrg XLookupString(&event->xkey, buf, sizeof(buf), &keySym, &stat); 31432001f49Smrg 31532001f49Smrg switch (keySym) { 31632001f49Smrg case XK_Escape: 31732001f49Smrg /* tell all threads to exit */ 31832001f49Smrg if (!Animate) { 31932001f49Smrg signal_redraw(); 32032001f49Smrg } 32132001f49Smrg ExitFlag = GL_TRUE; 32232001f49Smrg /*printf("exit draw_loop %d\n", wt->Index);*/ 32332001f49Smrg return; 32432001f49Smrg case XK_t: 32532001f49Smrg case XK_T: 32632001f49Smrg if (Texture) { 32732001f49Smrg wt->MakeNewTexture = GL_TRUE; 32832001f49Smrg if (!Animate) 32932001f49Smrg signal_redraw(); 33032001f49Smrg } 33132001f49Smrg break; 33232001f49Smrg case XK_a: 33332001f49Smrg case XK_A: 33432001f49Smrg Animate = !Animate; 33532001f49Smrg if (Animate) /* yes, prev Animate state! */ 33632001f49Smrg signal_redraw(); 33732001f49Smrg break; 33832001f49Smrg case XK_s: 33932001f49Smrg case XK_S: 34032001f49Smrg if (!Animate) 34132001f49Smrg signal_redraw(); 34232001f49Smrg break; 34332001f49Smrg default: 34432001f49Smrg ; /* nop */ 34532001f49Smrg } 34632001f49Smrg} 34732001f49Smrg 34832001f49Smrg 34932001f49Smrg/* 35032001f49Smrg * The main process thread runs this loop. 35132001f49Smrg * Single display connection for all threads. 35232001f49Smrg */ 35332001f49Smrgstatic void 35432001f49Smrgevent_loop(Display *dpy) 35532001f49Smrg{ 35632001f49Smrg XEvent event; 35732001f49Smrg int i; 35832001f49Smrg 35932001f49Smrg assert(!MultiDisplays); 36032001f49Smrg 36132001f49Smrg while (!ExitFlag) { 36232001f49Smrg 36332001f49Smrg if (Locking) { 36432001f49Smrg while (1) { 36532001f49Smrg int k; 36632001f49Smrg pthread_mutex_lock(&Mutex); 36732001f49Smrg k = XPending(dpy); 36832001f49Smrg if (k) { 36932001f49Smrg XNextEvent(dpy, &event); 37032001f49Smrg pthread_mutex_unlock(&Mutex); 37132001f49Smrg break; 37232001f49Smrg } 37332001f49Smrg pthread_mutex_unlock(&Mutex); 37432001f49Smrg usleep(5000); 37532001f49Smrg } 37632001f49Smrg } 37732001f49Smrg else { 37832001f49Smrg XNextEvent(dpy, &event); 37932001f49Smrg } 38032001f49Smrg 38132001f49Smrg switch (event.type) { 38232001f49Smrg case ConfigureNotify: 38332001f49Smrg /* Find winthread for this event's window */ 38432001f49Smrg for (i = 0; i < NumWinThreads; i++) { 38532001f49Smrg struct winthread *wt = &WinThreads[i]; 38632001f49Smrg if (event.xconfigure.window == wt->Win) { 38732001f49Smrg resize(wt, event.xconfigure.width, 38832001f49Smrg event.xconfigure.height); 38932001f49Smrg break; 39032001f49Smrg } 39132001f49Smrg } 39232001f49Smrg break; 39332001f49Smrg case KeyPress: 39432001f49Smrg for (i = 0; i < NumWinThreads; i++) { 39532001f49Smrg struct winthread *wt = &WinThreads[i]; 39632001f49Smrg if (event.xkey.window == wt->Win) { 39732001f49Smrg keypress(&event, wt); 39832001f49Smrg break; 39932001f49Smrg } 40032001f49Smrg } 40132001f49Smrg break; 40232001f49Smrg default: 40332001f49Smrg /*no-op*/ ; 40432001f49Smrg } 40532001f49Smrg } 40632001f49Smrg} 40732001f49Smrg 40832001f49Smrg 40932001f49Smrg/* 41032001f49Smrg * Separate display connection for each thread. 41132001f49Smrg */ 41232001f49Smrgstatic void 41332001f49Smrgevent_loop_multi(void) 41432001f49Smrg{ 41532001f49Smrg XEvent event; 41632001f49Smrg int w = 0; 41732001f49Smrg 41832001f49Smrg assert(MultiDisplays); 41932001f49Smrg 42032001f49Smrg while (!ExitFlag) { 42132001f49Smrg struct winthread *wt = &WinThreads[w]; 42232001f49Smrg if (XPending(wt->Dpy)) { 42332001f49Smrg XNextEvent(wt->Dpy, &event); 42432001f49Smrg switch (event.type) { 42532001f49Smrg case ConfigureNotify: 42632001f49Smrg resize(wt, event.xconfigure.width, event.xconfigure.height); 42732001f49Smrg break; 42832001f49Smrg case KeyPress: 42932001f49Smrg keypress(&event, wt); 43032001f49Smrg break; 43132001f49Smrg default: 43232001f49Smrg ; /* nop */ 43332001f49Smrg } 43432001f49Smrg } 43532001f49Smrg w = (w + 1) % NumWinThreads; 43632001f49Smrg usleep(5000); 43732001f49Smrg } 43832001f49Smrg} 43932001f49Smrg 44032001f49Smrg 44132001f49Smrg 44232001f49Smrg/* 44332001f49Smrg * we'll call this once for each thread, before the threads are created. 44432001f49Smrg */ 44532001f49Smrgstatic void 44632001f49Smrgcreate_window(struct winthread *wt, GLXContext shareCtx) 44732001f49Smrg{ 44832001f49Smrg Window win; 44932001f49Smrg GLXContext ctx; 45032001f49Smrg int attrib[] = { GLX_RGBA, 45132001f49Smrg GLX_RED_SIZE, 1, 45232001f49Smrg GLX_GREEN_SIZE, 1, 45332001f49Smrg GLX_BLUE_SIZE, 1, 45432001f49Smrg GLX_DEPTH_SIZE, 1, 45532001f49Smrg GLX_DOUBLEBUFFER, 45632001f49Smrg None }; 45732001f49Smrg int scrnum; 45832001f49Smrg XSetWindowAttributes attr; 45932001f49Smrg unsigned long mask; 46032001f49Smrg Window root; 46132001f49Smrg XVisualInfo *visinfo; 46232001f49Smrg int width = 160, height = 160; 46332001f49Smrg int xpos = (wt->Index % 8) * (width + 10); 46432001f49Smrg int ypos = (wt->Index / 8) * (width + 20); 46532001f49Smrg 46632001f49Smrg scrnum = DefaultScreen(wt->Dpy); 46732001f49Smrg root = RootWindow(wt->Dpy, scrnum); 46832001f49Smrg 46932001f49Smrg visinfo = glXChooseVisual(wt->Dpy, scrnum, attrib); 47032001f49Smrg if (!visinfo) { 47132001f49Smrg Error("Unable to find RGB, Z, double-buffered visual"); 47232001f49Smrg } 47332001f49Smrg 47432001f49Smrg /* window attributes */ 47532001f49Smrg attr.background_pixel = 0; 47632001f49Smrg attr.border_pixel = 0; 47732001f49Smrg attr.colormap = XCreateColormap(wt->Dpy, root, visinfo->visual, AllocNone); 47832001f49Smrg attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask; 47932001f49Smrg mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask; 48032001f49Smrg 48132001f49Smrg win = XCreateWindow(wt->Dpy, root, xpos, ypos, width, height, 48232001f49Smrg 0, visinfo->depth, InputOutput, 48332001f49Smrg visinfo->visual, mask, &attr); 48432001f49Smrg if (!win) { 48532001f49Smrg Error("Couldn't create window"); 48632001f49Smrg } 48732001f49Smrg 48832001f49Smrg { 48932001f49Smrg XSizeHints sizehints; 49032001f49Smrg sizehints.x = xpos; 49132001f49Smrg sizehints.y = ypos; 49232001f49Smrg sizehints.width = width; 49332001f49Smrg sizehints.height = height; 49432001f49Smrg sizehints.flags = USSize | USPosition; 49532001f49Smrg XSetNormalHints(wt->Dpy, win, &sizehints); 49632001f49Smrg XSetStandardProperties(wt->Dpy, win, "glthreads", "glthreads", 49732001f49Smrg None, (char **)NULL, 0, &sizehints); 49832001f49Smrg } 49932001f49Smrg 50032001f49Smrg 50132001f49Smrg ctx = glXCreateContext(wt->Dpy, visinfo, shareCtx, True); 50232001f49Smrg if (!ctx) { 50332001f49Smrg Error("Couldn't create GLX context"); 50432001f49Smrg } 50532001f49Smrg 50632001f49Smrg XMapWindow(wt->Dpy, win); 50732001f49Smrg XSync(wt->Dpy, 0); 50832001f49Smrg 50932001f49Smrg /* save the info for this window/context */ 51032001f49Smrg wt->Win = win; 51132001f49Smrg wt->Context = ctx; 51232001f49Smrg wt->Angle = 0.0; 51332001f49Smrg wt->WinWidth = width; 51432001f49Smrg wt->WinHeight = height; 51532001f49Smrg wt->NewSize = GL_TRUE; 51632001f49Smrg} 51732001f49Smrg 51832001f49Smrg 51932001f49Smrg/* 52032001f49Smrg * Called by pthread_create() 52132001f49Smrg */ 52232001f49Smrgstatic void * 52332001f49Smrgthread_function(void *p) 52432001f49Smrg{ 52532001f49Smrg struct winthread *wt = (struct winthread *) p; 52632001f49Smrg draw_loop(wt); 52732001f49Smrg return NULL; 52832001f49Smrg} 52932001f49Smrg 53032001f49Smrg 53132001f49Smrg/* 53232001f49Smrg * called before exit to wait for all threads to finish 53332001f49Smrg */ 53432001f49Smrgstatic void 53532001f49Smrgclean_up(void) 53632001f49Smrg{ 53732001f49Smrg int i; 53832001f49Smrg 53932001f49Smrg /* wait for threads to finish */ 54032001f49Smrg for (i = 0; i < NumWinThreads; i++) { 54132001f49Smrg pthread_join(WinThreads[i].Thread, NULL); 54232001f49Smrg } 54332001f49Smrg 54432001f49Smrg for (i = 0; i < NumWinThreads; i++) { 54532001f49Smrg glXDestroyContext(WinThreads[i].Dpy, WinThreads[i].Context); 54632001f49Smrg XDestroyWindow(WinThreads[i].Dpy, WinThreads[i].Win); 54732001f49Smrg } 54832001f49Smrg} 54932001f49Smrg 55032001f49Smrg 55132001f49Smrgstatic void 55232001f49Smrgusage(void) 55332001f49Smrg{ 55432001f49Smrg printf("glthreads: test of GL thread safety (any key = exit)\n"); 55532001f49Smrg printf("Usage:\n"); 55632001f49Smrg printf(" glthreads [options]\n"); 55732001f49Smrg printf("Options:\n"); 55832001f49Smrg printf(" -display DISPLAYNAME Specify display string\n"); 55932001f49Smrg printf(" -n NUMTHREADS Number of threads to create\n"); 56032001f49Smrg printf(" -p Use a separate display connection for each thread\n"); 56132001f49Smrg printf(" -l Use application-side locking\n"); 56232001f49Smrg printf(" -t Enable texturing\n"); 56332001f49Smrg printf("Keyboard:\n"); 56432001f49Smrg printf(" Esc Exit\n"); 56532001f49Smrg printf(" t Change texture image (requires -t option)\n"); 56632001f49Smrg printf(" a Toggle animation\n"); 56732001f49Smrg printf(" s Step rotation (when not animating)\n"); 56832001f49Smrg} 56932001f49Smrg 57032001f49Smrg 57132001f49Smrgint 57232001f49Smrgmain(int argc, char *argv[]) 57332001f49Smrg{ 57432001f49Smrg char *displayName = NULL; 57532001f49Smrg int numThreads = 2; 57632001f49Smrg Display *dpy = NULL; 57732001f49Smrg int i; 57832001f49Smrg Status threadStat; 57932001f49Smrg 58032001f49Smrg if (argc == 1) { 58132001f49Smrg usage(); 58232001f49Smrg } 58332001f49Smrg else { 58432001f49Smrg int i; 58532001f49Smrg for (i = 1; i < argc; i++) { 58632001f49Smrg if (strcmp(argv[i], "-display") == 0 && i + 1 < argc) { 58732001f49Smrg displayName = argv[i + 1]; 58832001f49Smrg i++; 58932001f49Smrg } 59032001f49Smrg else if (strcmp(argv[i], "-p") == 0) { 59132001f49Smrg MultiDisplays = 1; 59232001f49Smrg } 59332001f49Smrg else if (strcmp(argv[i], "-l") == 0) { 59432001f49Smrg Locking = 1; 59532001f49Smrg } 59632001f49Smrg else if (strcmp(argv[i], "-t") == 0) { 59732001f49Smrg Texture = 1; 59832001f49Smrg } 59932001f49Smrg else if (strcmp(argv[i], "-n") == 0 && i + 1 < argc) { 60032001f49Smrg numThreads = atoi(argv[i + 1]); 60132001f49Smrg if (numThreads < 1) 60232001f49Smrg numThreads = 1; 60332001f49Smrg else if (numThreads > MAX_WINTHREADS) 60432001f49Smrg numThreads = MAX_WINTHREADS; 60532001f49Smrg i++; 60632001f49Smrg } 60732001f49Smrg else { 60832001f49Smrg usage(); 60932001f49Smrg exit(1); 61032001f49Smrg } 61132001f49Smrg } 61232001f49Smrg } 61332001f49Smrg 61432001f49Smrg if (Locking) 61532001f49Smrg printf("glthreads: Using explicit locks around Xlib calls.\n"); 61632001f49Smrg else 61732001f49Smrg printf("glthreads: No explict locking.\n"); 61832001f49Smrg 61932001f49Smrg if (MultiDisplays) 62032001f49Smrg printf("glthreads: Per-thread display connections.\n"); 62132001f49Smrg else 62232001f49Smrg printf("glthreads: Single display connection.\n"); 62332001f49Smrg 62432001f49Smrg /* 62532001f49Smrg * VERY IMPORTANT: call XInitThreads() before any other Xlib functions. 62632001f49Smrg */ 62732001f49Smrg if (!MultiDisplays) { 62832001f49Smrg if (!Locking) { 62932001f49Smrg threadStat = XInitThreads(); 63032001f49Smrg if (threadStat) { 63132001f49Smrg printf("XInitThreads() returned %d (success)\n", (int) threadStat); 63232001f49Smrg } 63332001f49Smrg else { 63432001f49Smrg printf("XInitThreads() returned 0 (failure- this program may fail)\n"); 63532001f49Smrg } 63632001f49Smrg } 63732001f49Smrg 63832001f49Smrg dpy = XOpenDisplay(displayName); 63932001f49Smrg if (!dpy) { 64032001f49Smrg fprintf(stderr, "Unable to open display %s\n", XDisplayName(displayName)); 64132001f49Smrg return -1; 64232001f49Smrg } 64332001f49Smrg } 64432001f49Smrg 64532001f49Smrg pthread_mutex_init(&Mutex, NULL); 64632001f49Smrg pthread_mutex_init(&CondMutex, NULL); 64732001f49Smrg pthread_cond_init(&CondVar, NULL); 64832001f49Smrg 64932001f49Smrg printf("glthreads: creating windows\n"); 65032001f49Smrg 65132001f49Smrg NumWinThreads = numThreads; 65232001f49Smrg 65332001f49Smrg /* Create the GLX windows and contexts */ 65432001f49Smrg for (i = 0; i < numThreads; i++) { 65532001f49Smrg GLXContext share; 65632001f49Smrg 65732001f49Smrg if (MultiDisplays) { 65832001f49Smrg WinThreads[i].Dpy = XOpenDisplay(displayName); 65932001f49Smrg assert(WinThreads[i].Dpy); 66032001f49Smrg } 66132001f49Smrg else { 66232001f49Smrg WinThreads[i].Dpy = dpy; 66332001f49Smrg } 66432001f49Smrg WinThreads[i].Index = i; 66532001f49Smrg WinThreads[i].Initialized = GL_FALSE; 66632001f49Smrg 66732001f49Smrg share = (Texture && i > 0) ? WinThreads[0].Context : 0; 66832001f49Smrg 66932001f49Smrg create_window(&WinThreads[i], share); 67032001f49Smrg } 67132001f49Smrg 67232001f49Smrg printf("glthreads: creating threads\n"); 67332001f49Smrg 67432001f49Smrg /* Create the threads */ 67532001f49Smrg for (i = 0; i < numThreads; i++) { 67632001f49Smrg pthread_create(&WinThreads[i].Thread, NULL, thread_function, 67732001f49Smrg (void*) &WinThreads[i]); 67832001f49Smrg printf("glthreads: Created thread %p\n", (void *) WinThreads[i].Thread); 67932001f49Smrg } 68032001f49Smrg 68132001f49Smrg if (MultiDisplays) 68232001f49Smrg event_loop_multi(); 68332001f49Smrg else 68432001f49Smrg event_loop(dpy); 68532001f49Smrg 68632001f49Smrg clean_up(); 68732001f49Smrg 68832001f49Smrg if (MultiDisplays) { 68932001f49Smrg for (i = 0; i < numThreads; i++) { 69032001f49Smrg XCloseDisplay(WinThreads[i].Dpy); 69132001f49Smrg } 69232001f49Smrg } 69332001f49Smrg else { 69432001f49Smrg XCloseDisplay(dpy); 69532001f49Smrg } 69632001f49Smrg 69732001f49Smrg return 0; 69832001f49Smrg} 699