Brian Paul | c7d1444 | 2000-07-20 20:12:17 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2000 Brian Paul All Rights Reserved. |
| 3 | * |
| 4 | * Permission is hereby granted, free of charge, to any person obtaining a |
| 5 | * copy of this software and associated documentation files (the "Software"), |
| 6 | * to deal in the Software without restriction, including without limitation |
| 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| 8 | * and/or sell copies of the Software, and to permit persons to whom the |
| 9 | * Software is furnished to do so, subject to the following conditions: |
| 10 | * |
| 11 | * The above copyright notice and this permission notice shall be included |
| 12 | * in all copies or substantial portions of the Software. |
| 13 | * |
| 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
| 15 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| 17 | * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN |
| 18 | * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
| 19 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| 20 | */ |
| 21 | |
| 22 | |
| 23 | /* |
| 24 | * This program tests GLX thread safety. |
| 25 | * Command line options: |
Brian Paul | 436d72e | 2006-03-23 16:58:22 +0000 | [diff] [blame] | 26 | * -p Open a display connection for each thread |
Brian Paul | f34a30b | 2008-05-07 11:56:24 -0600 | [diff] [blame] | 27 | * -l Enable application-side locking |
Brian Paul | c7d1444 | 2000-07-20 20:12:17 +0000 | [diff] [blame] | 28 | * -n <num threads> Number of threads to create (default is 2) |
Jon TURNEY | 5795545 | 2009-06-21 11:58:25 +0100 | [diff] [blame] | 29 | * -display <display name> Specify X display (default is $DISPLAY) |
Brian Paul | f34a30b | 2008-05-07 11:56:24 -0600 | [diff] [blame] | 30 | * -t Use texture mapping |
Brian Paul | c7d1444 | 2000-07-20 20:12:17 +0000 | [diff] [blame] | 31 | * |
| 32 | * Brian Paul 20 July 2000 |
| 33 | */ |
| 34 | |
| 35 | |
Brian Paul | f34a30b | 2008-05-07 11:56:24 -0600 | [diff] [blame] | 36 | /* |
| 37 | * Notes: |
| 38 | * - Each thread gets its own GLX context. |
| 39 | * |
| 40 | * - The GLX contexts share texture objects. |
| 41 | * |
| 42 | * - When 't' is pressed to update the texture image, the window/thread which |
| 43 | * has input focus is signalled to change the texture. The other threads |
| 44 | * should see the updated texture the next time they call glBindTexture. |
| 45 | */ |
| 46 | |
| 47 | |
Brian Paul | c7d1444 | 2000-07-20 20:12:17 +0000 | [diff] [blame] | 48 | #if defined(PTHREADS) /* defined by Mesa on Linux and other platforms */ |
| 49 | |
Brian Paul | 436d72e | 2006-03-23 16:58:22 +0000 | [diff] [blame] | 50 | #include <assert.h> |
Brian Paul | c7d1444 | 2000-07-20 20:12:17 +0000 | [diff] [blame] | 51 | #include <GL/gl.h> |
| 52 | #include <GL/glx.h> |
Brian Paul | f34a30b | 2008-05-07 11:56:24 -0600 | [diff] [blame] | 53 | #include <math.h> |
Brian Paul | c7d1444 | 2000-07-20 20:12:17 +0000 | [diff] [blame] | 54 | #include <stdio.h> |
| 55 | #include <stdlib.h> |
Brian Paul | a3e44f4 | 2002-03-08 19:44:28 +0000 | [diff] [blame] | 56 | #include <string.h> |
Brian Paul | c7d1444 | 2000-07-20 20:12:17 +0000 | [diff] [blame] | 57 | #include <unistd.h> |
| 58 | #include <pthread.h> |
| 59 | |
| 60 | |
| 61 | /* |
| 62 | * Each window/thread/context: |
| 63 | */ |
| 64 | struct winthread { |
| 65 | Display *Dpy; |
| 66 | int Index; |
| 67 | pthread_t Thread; |
| 68 | Window Win; |
| 69 | GLXContext Context; |
| 70 | float Angle; |
| 71 | int WinWidth, WinHeight; |
| 72 | GLboolean NewSize; |
Brian Paul | f34a30b | 2008-05-07 11:56:24 -0600 | [diff] [blame] | 73 | GLboolean Initialized; |
| 74 | GLboolean MakeNewTexture; |
Brian Paul | c7d1444 | 2000-07-20 20:12:17 +0000 | [diff] [blame] | 75 | }; |
| 76 | |
| 77 | |
| 78 | #define MAX_WINTHREADS 100 |
| 79 | static struct winthread WinThreads[MAX_WINTHREADS]; |
| 80 | static int NumWinThreads = 0; |
Brian Paul | d07859e | 2004-07-02 14:35:05 +0000 | [diff] [blame] | 81 | static volatile GLboolean ExitFlag = GL_FALSE; |
Brian Paul | c7d1444 | 2000-07-20 20:12:17 +0000 | [diff] [blame] | 82 | |
Brian Paul | 436d72e | 2006-03-23 16:58:22 +0000 | [diff] [blame] | 83 | static GLboolean MultiDisplays = 0; |
Brian Paul | c4f2710 | 2006-03-23 17:17:23 +0000 | [diff] [blame] | 84 | static GLboolean Locking = 0; |
Brian Paul | f34a30b | 2008-05-07 11:56:24 -0600 | [diff] [blame] | 85 | static GLboolean Texture = GL_FALSE; |
| 86 | static GLuint TexObj = 12; |
| 87 | static GLboolean Animate = GL_TRUE; |
Brian Paul | c4f2710 | 2006-03-23 17:17:23 +0000 | [diff] [blame] | 88 | |
| 89 | static pthread_mutex_t Mutex; |
Brian Paul | f34a30b | 2008-05-07 11:56:24 -0600 | [diff] [blame] | 90 | static pthread_cond_t CondVar; |
| 91 | static pthread_mutex_t CondMutex; |
Brian Paul | c7d1444 | 2000-07-20 20:12:17 +0000 | [diff] [blame] | 92 | |
| 93 | |
| 94 | static void |
| 95 | Error(const char *msg) |
| 96 | { |
| 97 | fprintf(stderr, "Error: %s\n", msg); |
| 98 | exit(1); |
| 99 | } |
| 100 | |
| 101 | |
Brian Paul | f34a30b | 2008-05-07 11:56:24 -0600 | [diff] [blame] | 102 | static void |
| 103 | signal_redraw(void) |
| 104 | { |
| 105 | pthread_mutex_lock(&CondMutex); |
| 106 | pthread_cond_broadcast(&CondVar); |
| 107 | pthread_mutex_unlock(&CondMutex); |
| 108 | } |
| 109 | |
| 110 | |
| 111 | static void |
| 112 | MakeNewTexture(struct winthread *wt) |
| 113 | { |
| 114 | #define TEX_SIZE 128 |
| 115 | static float step = 0.0; |
| 116 | GLfloat image[TEX_SIZE][TEX_SIZE][4]; |
| 117 | GLint width; |
| 118 | int i, j; |
| 119 | |
| 120 | for (j = 0; j < TEX_SIZE; j++) { |
| 121 | for (i = 0; i < TEX_SIZE; i++) { |
| 122 | float dt = 5.0 * (j - 0.5 * TEX_SIZE) / TEX_SIZE; |
| 123 | float ds = 5.0 * (i - 0.5 * TEX_SIZE) / TEX_SIZE; |
| 124 | float r = dt * dt + ds * ds + step; |
| 125 | image[j][i][0] = |
| 126 | image[j][i][1] = |
| 127 | image[j][i][2] = 0.75 + 0.25 * cos(r); |
| 128 | image[j][i][3] = 1.0; |
| 129 | } |
| 130 | } |
| 131 | |
| 132 | step += 0.5; |
| 133 | |
| 134 | glBindTexture(GL_TEXTURE_2D, TexObj); |
| 135 | |
| 136 | glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width); |
| 137 | if (width) { |
| 138 | assert(width == TEX_SIZE); |
| 139 | /* sub-tex replace */ |
| 140 | glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, TEX_SIZE, TEX_SIZE, |
| 141 | GL_RGBA, GL_FLOAT, image); |
| 142 | } |
| 143 | else { |
| 144 | /* create new */ |
| 145 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
| 146 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
| 147 | |
| 148 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TEX_SIZE, TEX_SIZE, 0, |
| 149 | GL_RGBA, GL_FLOAT, image); |
| 150 | } |
| 151 | } |
| 152 | |
| 153 | |
| 154 | |
Brian Paul | c7d1444 | 2000-07-20 20:12:17 +0000 | [diff] [blame] | 155 | /* draw a colored cube */ |
| 156 | static void |
| 157 | draw_object(void) |
| 158 | { |
| 159 | glPushMatrix(); |
| 160 | glScalef(0.75, 0.75, 0.75); |
| 161 | |
| 162 | glColor3f(1, 0, 0); |
Brian Paul | c7d1444 | 2000-07-20 20:12:17 +0000 | [diff] [blame] | 163 | |
Brian Paul | f34a30b | 2008-05-07 11:56:24 -0600 | [diff] [blame] | 164 | if (Texture) { |
| 165 | glBindTexture(GL_TEXTURE_2D, TexObj); |
| 166 | glEnable(GL_TEXTURE_2D); |
| 167 | } |
| 168 | else { |
| 169 | glDisable(GL_TEXTURE_2D); |
| 170 | } |
| 171 | |
| 172 | glBegin(GL_QUADS); |
| 173 | |
| 174 | /* -X */ |
Brian Paul | c7d1444 | 2000-07-20 20:12:17 +0000 | [diff] [blame] | 175 | glColor3f(0, 1, 1); |
Brian Paul | f34a30b | 2008-05-07 11:56:24 -0600 | [diff] [blame] | 176 | glTexCoord2f(0, 0); glVertex3f(-1, -1, -1); |
| 177 | glTexCoord2f(1, 0); glVertex3f(-1, 1, -1); |
| 178 | glTexCoord2f(1, 1); glVertex3f(-1, 1, 1); |
| 179 | glTexCoord2f(0, 1); glVertex3f(-1, -1, 1); |
Brian Paul | c7d1444 | 2000-07-20 20:12:17 +0000 | [diff] [blame] | 180 | |
Brian Paul | f34a30b | 2008-05-07 11:56:24 -0600 | [diff] [blame] | 181 | /* +X */ |
| 182 | glColor3f(1, 0, 0); |
| 183 | glTexCoord2f(0, 0); glVertex3f(1, -1, -1); |
| 184 | glTexCoord2f(1, 0); glVertex3f(1, 1, -1); |
| 185 | glTexCoord2f(1, 1); glVertex3f(1, 1, 1); |
| 186 | glTexCoord2f(0, 1); glVertex3f(1, -1, 1); |
Brian Paul | c7d1444 | 2000-07-20 20:12:17 +0000 | [diff] [blame] | 187 | |
Brian Paul | f34a30b | 2008-05-07 11:56:24 -0600 | [diff] [blame] | 188 | /* -Y */ |
Brian Paul | c7d1444 | 2000-07-20 20:12:17 +0000 | [diff] [blame] | 189 | glColor3f(1, 0, 1); |
Brian Paul | f34a30b | 2008-05-07 11:56:24 -0600 | [diff] [blame] | 190 | glTexCoord2f(0, 0); glVertex3f(-1, -1, -1); |
| 191 | glTexCoord2f(1, 0); glVertex3f( 1, -1, -1); |
| 192 | glTexCoord2f(1, 1); glVertex3f( 1, -1, 1); |
| 193 | glTexCoord2f(0, 1); glVertex3f(-1, -1, 1); |
Brian Paul | c7d1444 | 2000-07-20 20:12:17 +0000 | [diff] [blame] | 194 | |
Brian Paul | f34a30b | 2008-05-07 11:56:24 -0600 | [diff] [blame] | 195 | /* +Y */ |
| 196 | glColor3f(0, 1, 0); |
| 197 | glTexCoord2f(0, 0); glVertex3f(-1, 1, -1); |
| 198 | glTexCoord2f(1, 0); glVertex3f( 1, 1, -1); |
| 199 | glTexCoord2f(1, 1); glVertex3f( 1, 1, 1); |
| 200 | glTexCoord2f(0, 1); glVertex3f(-1, 1, 1); |
Brian Paul | c7d1444 | 2000-07-20 20:12:17 +0000 | [diff] [blame] | 201 | |
Brian Paul | f34a30b | 2008-05-07 11:56:24 -0600 | [diff] [blame] | 202 | /* -Z */ |
Brian Paul | c7d1444 | 2000-07-20 20:12:17 +0000 | [diff] [blame] | 203 | glColor3f(1, 1, 0); |
Brian Paul | f34a30b | 2008-05-07 11:56:24 -0600 | [diff] [blame] | 204 | glTexCoord2f(0, 0); glVertex3f(-1, -1, -1); |
| 205 | glTexCoord2f(1, 0); glVertex3f( 1, -1, -1); |
| 206 | glTexCoord2f(1, 1); glVertex3f( 1, 1, -1); |
| 207 | glTexCoord2f(0, 1); glVertex3f(-1, 1, -1); |
| 208 | |
| 209 | /* +Y */ |
| 210 | glColor3f(0, 0, 1); |
| 211 | glTexCoord2f(0, 0); glVertex3f(-1, -1, 1); |
| 212 | glTexCoord2f(1, 0); glVertex3f( 1, -1, 1); |
| 213 | glTexCoord2f(1, 1); glVertex3f( 1, 1, 1); |
| 214 | glTexCoord2f(0, 1); glVertex3f(-1, 1, 1); |
| 215 | |
Brian Paul | c7d1444 | 2000-07-20 20:12:17 +0000 | [diff] [blame] | 216 | glEnd(); |
Brian Paul | f34a30b | 2008-05-07 11:56:24 -0600 | [diff] [blame] | 217 | |
Brian Paul | c7d1444 | 2000-07-20 20:12:17 +0000 | [diff] [blame] | 218 | glPopMatrix(); |
| 219 | } |
| 220 | |
| 221 | |
| 222 | /* signal resize of given window */ |
| 223 | static void |
| 224 | resize(struct winthread *wt, int w, int h) |
| 225 | { |
| 226 | wt->NewSize = GL_TRUE; |
| 227 | wt->WinWidth = w; |
| 228 | wt->WinHeight = h; |
Brian Paul | f34a30b | 2008-05-07 11:56:24 -0600 | [diff] [blame] | 229 | if (!Animate) |
| 230 | signal_redraw(); |
Brian Paul | c7d1444 | 2000-07-20 20:12:17 +0000 | [diff] [blame] | 231 | } |
| 232 | |
| 233 | |
| 234 | /* |
| 235 | * We have an instance of this for each thread. |
| 236 | */ |
| 237 | static void |
| 238 | draw_loop(struct winthread *wt) |
| 239 | { |
| 240 | while (!ExitFlag) { |
| 241 | |
Brian Paul | c4f2710 | 2006-03-23 17:17:23 +0000 | [diff] [blame] | 242 | if (Locking) |
| 243 | pthread_mutex_lock(&Mutex); |
| 244 | |
Brian Paul | c7d1444 | 2000-07-20 20:12:17 +0000 | [diff] [blame] | 245 | glXMakeCurrent(wt->Dpy, wt->Win, wt->Context); |
Brian Paul | f34a30b | 2008-05-07 11:56:24 -0600 | [diff] [blame] | 246 | if (!wt->Initialized) { |
Brian Paul | c4f2710 | 2006-03-23 17:17:23 +0000 | [diff] [blame] | 247 | printf("glthreads: %d: GL_RENDERER = %s\n", wt->Index, |
| 248 | (char *) glGetString(GL_RENDERER)); |
Brian Paul | f34a30b | 2008-05-07 11:56:24 -0600 | [diff] [blame] | 249 | if (Texture /*&& wt->Index == 0*/) { |
| 250 | MakeNewTexture(wt); |
| 251 | } |
| 252 | wt->Initialized = GL_TRUE; |
Brian Paul | c4f2710 | 2006-03-23 17:17:23 +0000 | [diff] [blame] | 253 | } |
| 254 | |
| 255 | if (Locking) |
| 256 | pthread_mutex_unlock(&Mutex); |
Brian Paul | c7d1444 | 2000-07-20 20:12:17 +0000 | [diff] [blame] | 257 | |
| 258 | glEnable(GL_DEPTH_TEST); |
| 259 | |
| 260 | if (wt->NewSize) { |
| 261 | GLfloat w = (float) wt->WinWidth / (float) wt->WinHeight; |
| 262 | glViewport(0, 0, wt->WinWidth, wt->WinHeight); |
| 263 | glMatrixMode(GL_PROJECTION); |
| 264 | glLoadIdentity(); |
| 265 | glFrustum(-w, w, -1.0, 1.0, 1.5, 10); |
| 266 | glMatrixMode(GL_MODELVIEW); |
| 267 | glLoadIdentity(); |
| 268 | glTranslatef(0, 0, -2.5); |
| 269 | wt->NewSize = GL_FALSE; |
| 270 | } |
| 271 | |
Brian Paul | f34a30b | 2008-05-07 11:56:24 -0600 | [diff] [blame] | 272 | if (wt->MakeNewTexture) { |
| 273 | MakeNewTexture(wt); |
| 274 | wt->MakeNewTexture = GL_FALSE; |
| 275 | } |
| 276 | |
Brian Paul | c7d1444 | 2000-07-20 20:12:17 +0000 | [diff] [blame] | 277 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
| 278 | |
| 279 | glPushMatrix(); |
Brian Paul | f34a30b | 2008-05-07 11:56:24 -0600 | [diff] [blame] | 280 | glRotatef(wt->Angle, 0, 1, 0); |
Brian Paul | c7d1444 | 2000-07-20 20:12:17 +0000 | [diff] [blame] | 281 | glRotatef(wt->Angle, 1, 0, 0); |
| 282 | glScalef(0.7, 0.7, 0.7); |
| 283 | draw_object(); |
| 284 | glPopMatrix(); |
| 285 | |
Brian Paul | c4f2710 | 2006-03-23 17:17:23 +0000 | [diff] [blame] | 286 | if (Locking) |
| 287 | pthread_mutex_lock(&Mutex); |
| 288 | |
Brian Paul | c7d1444 | 2000-07-20 20:12:17 +0000 | [diff] [blame] | 289 | glXSwapBuffers(wt->Dpy, wt->Win); |
| 290 | |
Brian Paul | c4f2710 | 2006-03-23 17:17:23 +0000 | [diff] [blame] | 291 | if (Locking) |
| 292 | pthread_mutex_unlock(&Mutex); |
| 293 | |
Brian Paul | f34a30b | 2008-05-07 11:56:24 -0600 | [diff] [blame] | 294 | if (Animate) { |
| 295 | usleep(5000); |
| 296 | } |
| 297 | else { |
| 298 | /* wait for signal to draw */ |
| 299 | pthread_mutex_lock(&CondMutex); |
| 300 | pthread_cond_wait(&CondVar, &CondMutex); |
| 301 | pthread_mutex_unlock(&CondMutex); |
| 302 | } |
Brian Paul | c7d1444 | 2000-07-20 20:12:17 +0000 | [diff] [blame] | 303 | wt->Angle += 1.0; |
| 304 | } |
| 305 | } |
| 306 | |
| 307 | |
Brian Paul | f34a30b | 2008-05-07 11:56:24 -0600 | [diff] [blame] | 308 | static void |
| 309 | keypress(XEvent *event, struct winthread *wt) |
| 310 | { |
| 311 | char buf[100]; |
| 312 | KeySym keySym; |
| 313 | XComposeStatus stat; |
| 314 | |
| 315 | XLookupString(&event->xkey, buf, sizeof(buf), &keySym, &stat); |
| 316 | |
| 317 | switch (keySym) { |
| 318 | case XK_Escape: |
| 319 | /* tell all threads to exit */ |
| 320 | if (!Animate) { |
| 321 | signal_redraw(); |
| 322 | } |
| 323 | ExitFlag = GL_TRUE; |
| 324 | /*printf("exit draw_loop %d\n", wt->Index);*/ |
| 325 | return; |
| 326 | case XK_t: |
| 327 | case XK_T: |
| 328 | if (Texture) { |
| 329 | wt->MakeNewTexture = GL_TRUE; |
| 330 | if (!Animate) |
| 331 | signal_redraw(); |
| 332 | } |
| 333 | break; |
| 334 | case XK_a: |
| 335 | case XK_A: |
| 336 | Animate = !Animate; |
| 337 | if (Animate) /* yes, prev Animate state! */ |
| 338 | signal_redraw(); |
| 339 | break; |
| 340 | case XK_s: |
| 341 | case XK_S: |
| 342 | if (!Animate) |
| 343 | signal_redraw(); |
| 344 | break; |
| 345 | default: |
| 346 | ; /* nop */ |
| 347 | } |
| 348 | } |
| 349 | |
| 350 | |
Brian Paul | c7d1444 | 2000-07-20 20:12:17 +0000 | [diff] [blame] | 351 | /* |
| 352 | * The main process thread runs this loop. |
Brian Paul | 436d72e | 2006-03-23 16:58:22 +0000 | [diff] [blame] | 353 | * Single display connection for all threads. |
Brian Paul | c7d1444 | 2000-07-20 20:12:17 +0000 | [diff] [blame] | 354 | */ |
| 355 | static void |
| 356 | event_loop(Display *dpy) |
| 357 | { |
Brian Paul | d07859e | 2004-07-02 14:35:05 +0000 | [diff] [blame] | 358 | XEvent event; |
| 359 | int i; |
Brian Paul | c7d1444 | 2000-07-20 20:12:17 +0000 | [diff] [blame] | 360 | |
Brian Paul | 436d72e | 2006-03-23 16:58:22 +0000 | [diff] [blame] | 361 | assert(!MultiDisplays); |
| 362 | |
Brian Paul | d07859e | 2004-07-02 14:35:05 +0000 | [diff] [blame] | 363 | while (!ExitFlag) { |
Brian Paul | c4f2710 | 2006-03-23 17:17:23 +0000 | [diff] [blame] | 364 | |
| 365 | if (Locking) { |
| 366 | while (1) { |
| 367 | int k; |
| 368 | pthread_mutex_lock(&Mutex); |
| 369 | k = XPending(dpy); |
| 370 | if (k) { |
| 371 | XNextEvent(dpy, &event); |
| 372 | pthread_mutex_unlock(&Mutex); |
| 373 | break; |
| 374 | } |
| 375 | pthread_mutex_unlock(&Mutex); |
| 376 | usleep(5000); |
| 377 | } |
| 378 | } |
| 379 | else { |
| 380 | XNextEvent(dpy, &event); |
| 381 | } |
| 382 | |
Brian Paul | d07859e | 2004-07-02 14:35:05 +0000 | [diff] [blame] | 383 | switch (event.type) { |
| 384 | case ConfigureNotify: |
| 385 | /* Find winthread for this event's window */ |
| 386 | for (i = 0; i < NumWinThreads; i++) { |
| 387 | struct winthread *wt = &WinThreads[i]; |
| 388 | if (event.xconfigure.window == wt->Win) { |
| 389 | resize(wt, event.xconfigure.width, |
| 390 | event.xconfigure.height); |
| 391 | break; |
Brian Paul | c7d1444 | 2000-07-20 20:12:17 +0000 | [diff] [blame] | 392 | } |
| 393 | } |
Brian Paul | d07859e | 2004-07-02 14:35:05 +0000 | [diff] [blame] | 394 | break; |
| 395 | case KeyPress: |
Brian Paul | f34a30b | 2008-05-07 11:56:24 -0600 | [diff] [blame] | 396 | for (i = 0; i < NumWinThreads; i++) { |
| 397 | struct winthread *wt = &WinThreads[i]; |
| 398 | if (event.xkey.window == wt->Win) { |
| 399 | keypress(&event, wt); |
| 400 | break; |
| 401 | } |
| 402 | } |
| 403 | break; |
Brian Paul | d07859e | 2004-07-02 14:35:05 +0000 | [diff] [blame] | 404 | default: |
| 405 | /*no-op*/ ; |
Brian Paul | c7d1444 | 2000-07-20 20:12:17 +0000 | [diff] [blame] | 406 | } |
| 407 | } |
| 408 | } |
| 409 | |
| 410 | |
| 411 | /* |
Brian Paul | 436d72e | 2006-03-23 16:58:22 +0000 | [diff] [blame] | 412 | * Separate display connection for each thread. |
| 413 | */ |
| 414 | static void |
| 415 | event_loop_multi(void) |
| 416 | { |
| 417 | XEvent event; |
| 418 | int w = 0; |
| 419 | |
| 420 | assert(MultiDisplays); |
| 421 | |
| 422 | while (!ExitFlag) { |
| 423 | struct winthread *wt = &WinThreads[w]; |
| 424 | if (XPending(wt->Dpy)) { |
| 425 | XNextEvent(wt->Dpy, &event); |
| 426 | switch (event.type) { |
| 427 | case ConfigureNotify: |
| 428 | resize(wt, event.xconfigure.width, event.xconfigure.height); |
| 429 | break; |
| 430 | case KeyPress: |
Brian Paul | f34a30b | 2008-05-07 11:56:24 -0600 | [diff] [blame] | 431 | keypress(&event, wt); |
| 432 | break; |
Brian Paul | 436d72e | 2006-03-23 16:58:22 +0000 | [diff] [blame] | 433 | default: |
Brian Paul | f34a30b | 2008-05-07 11:56:24 -0600 | [diff] [blame] | 434 | ; /* nop */ |
Brian Paul | 436d72e | 2006-03-23 16:58:22 +0000 | [diff] [blame] | 435 | } |
| 436 | } |
| 437 | w = (w + 1) % NumWinThreads; |
| 438 | usleep(5000); |
| 439 | } |
| 440 | } |
| 441 | |
| 442 | |
| 443 | |
| 444 | /* |
Brian Paul | c7d1444 | 2000-07-20 20:12:17 +0000 | [diff] [blame] | 445 | * we'll call this once for each thread, before the threads are created. |
| 446 | */ |
| 447 | static void |
Brian Paul | f34a30b | 2008-05-07 11:56:24 -0600 | [diff] [blame] | 448 | create_window(struct winthread *wt, GLXContext shareCtx) |
Brian Paul | c7d1444 | 2000-07-20 20:12:17 +0000 | [diff] [blame] | 449 | { |
| 450 | Window win; |
| 451 | GLXContext ctx; |
| 452 | int attrib[] = { GLX_RGBA, |
| 453 | GLX_RED_SIZE, 1, |
| 454 | GLX_GREEN_SIZE, 1, |
| 455 | GLX_BLUE_SIZE, 1, |
| 456 | GLX_DEPTH_SIZE, 1, |
| 457 | GLX_DOUBLEBUFFER, |
| 458 | None }; |
| 459 | int scrnum; |
| 460 | XSetWindowAttributes attr; |
| 461 | unsigned long mask; |
| 462 | Window root; |
| 463 | XVisualInfo *visinfo; |
Brian Paul | f34a30b | 2008-05-07 11:56:24 -0600 | [diff] [blame] | 464 | int width = 160, height = 160; |
| 465 | int xpos = (wt->Index % 8) * (width + 10); |
| 466 | int ypos = (wt->Index / 8) * (width + 20); |
Brian Paul | c7d1444 | 2000-07-20 20:12:17 +0000 | [diff] [blame] | 467 | |
| 468 | scrnum = DefaultScreen(wt->Dpy); |
| 469 | root = RootWindow(wt->Dpy, scrnum); |
| 470 | |
| 471 | visinfo = glXChooseVisual(wt->Dpy, scrnum, attrib); |
| 472 | if (!visinfo) { |
| 473 | Error("Unable to find RGB, Z, double-buffered visual"); |
| 474 | } |
| 475 | |
| 476 | /* window attributes */ |
| 477 | attr.background_pixel = 0; |
| 478 | attr.border_pixel = 0; |
| 479 | attr.colormap = XCreateColormap(wt->Dpy, root, visinfo->visual, AllocNone); |
| 480 | attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask; |
| 481 | mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask; |
| 482 | |
| 483 | win = XCreateWindow(wt->Dpy, root, xpos, ypos, width, height, |
| 484 | 0, visinfo->depth, InputOutput, |
| 485 | visinfo->visual, mask, &attr); |
| 486 | if (!win) { |
| 487 | Error("Couldn't create window"); |
| 488 | } |
| 489 | |
| 490 | { |
| 491 | XSizeHints sizehints; |
| 492 | sizehints.x = xpos; |
| 493 | sizehints.y = ypos; |
| 494 | sizehints.width = width; |
| 495 | sizehints.height = height; |
| 496 | sizehints.flags = USSize | USPosition; |
| 497 | XSetNormalHints(wt->Dpy, win, &sizehints); |
| 498 | XSetStandardProperties(wt->Dpy, win, "glthreads", "glthreads", |
| 499 | None, (char **)NULL, 0, &sizehints); |
| 500 | } |
| 501 | |
| 502 | |
Brian Paul | f34a30b | 2008-05-07 11:56:24 -0600 | [diff] [blame] | 503 | ctx = glXCreateContext(wt->Dpy, visinfo, shareCtx, True); |
Brian Paul | c7d1444 | 2000-07-20 20:12:17 +0000 | [diff] [blame] | 504 | if (!ctx) { |
| 505 | Error("Couldn't create GLX context"); |
| 506 | } |
| 507 | |
| 508 | XMapWindow(wt->Dpy, win); |
| 509 | XSync(wt->Dpy, 0); |
| 510 | |
| 511 | /* save the info for this window/context */ |
| 512 | wt->Win = win; |
| 513 | wt->Context = ctx; |
| 514 | wt->Angle = 0.0; |
| 515 | wt->WinWidth = width; |
| 516 | wt->WinHeight = height; |
| 517 | wt->NewSize = GL_TRUE; |
| 518 | } |
| 519 | |
| 520 | |
| 521 | /* |
| 522 | * Called by pthread_create() |
| 523 | */ |
| 524 | static void * |
| 525 | thread_function(void *p) |
| 526 | { |
| 527 | struct winthread *wt = (struct winthread *) p; |
| 528 | draw_loop(wt); |
| 529 | return NULL; |
| 530 | } |
| 531 | |
| 532 | |
| 533 | /* |
| 534 | * called before exit to wait for all threads to finish |
| 535 | */ |
| 536 | static void |
| 537 | clean_up(void) |
| 538 | { |
| 539 | int i; |
| 540 | |
| 541 | /* wait for threads to finish */ |
| 542 | for (i = 0; i < NumWinThreads; i++) { |
| 543 | pthread_join(WinThreads[i].Thread, NULL); |
| 544 | } |
| 545 | |
| 546 | for (i = 0; i < NumWinThreads; i++) { |
| 547 | glXDestroyContext(WinThreads[i].Dpy, WinThreads[i].Context); |
| 548 | XDestroyWindow(WinThreads[i].Dpy, WinThreads[i].Win); |
| 549 | } |
| 550 | } |
| 551 | |
| 552 | |
Brian Paul | f34a30b | 2008-05-07 11:56:24 -0600 | [diff] [blame] | 553 | static void |
| 554 | usage(void) |
| 555 | { |
| 556 | printf("glthreads: test of GL thread safety (any key = exit)\n"); |
| 557 | printf("Usage:\n"); |
| 558 | printf(" glthreads [options]\n"); |
| 559 | printf("Options:\n"); |
| 560 | printf(" -display DISPLAYNAME Specify display string\n"); |
| 561 | printf(" -n NUMTHREADS Number of threads to create\n"); |
| 562 | printf(" -p Use a separate display connection for each thread\n"); |
| 563 | printf(" -l Use application-side locking\n"); |
| 564 | printf(" -t Enable texturing\n"); |
| 565 | printf("Keyboard:\n"); |
| 566 | printf(" Esc Exit\n"); |
| 567 | printf(" t Change texture image (requires -t option)\n"); |
Brian Paul | 8f76459 | 2008-05-07 11:57:03 -0600 | [diff] [blame] | 568 | printf(" a Toggle animation\n"); |
| 569 | printf(" s Step rotation (when not animating)\n"); |
Brian Paul | f34a30b | 2008-05-07 11:56:24 -0600 | [diff] [blame] | 570 | } |
| 571 | |
Brian Paul | c7d1444 | 2000-07-20 20:12:17 +0000 | [diff] [blame] | 572 | |
| 573 | int |
| 574 | main(int argc, char *argv[]) |
| 575 | { |
Jon TURNEY | 5795545 | 2009-06-21 11:58:25 +0100 | [diff] [blame] | 576 | char *displayName = NULL; |
Brian Paul | c7d1444 | 2000-07-20 20:12:17 +0000 | [diff] [blame] | 577 | int numThreads = 2; |
Brian Paul | 436d72e | 2006-03-23 16:58:22 +0000 | [diff] [blame] | 578 | Display *dpy = NULL; |
Brian Paul | c7d1444 | 2000-07-20 20:12:17 +0000 | [diff] [blame] | 579 | int i; |
| 580 | Status threadStat; |
| 581 | |
| 582 | if (argc == 1) { |
Brian Paul | f34a30b | 2008-05-07 11:56:24 -0600 | [diff] [blame] | 583 | usage(); |
Brian Paul | c7d1444 | 2000-07-20 20:12:17 +0000 | [diff] [blame] | 584 | } |
| 585 | else { |
| 586 | int i; |
| 587 | for (i = 1; i < argc; i++) { |
| 588 | if (strcmp(argv[i], "-display") == 0 && i + 1 < argc) { |
| 589 | displayName = argv[i + 1]; |
| 590 | i++; |
| 591 | } |
Brian Paul | 436d72e | 2006-03-23 16:58:22 +0000 | [diff] [blame] | 592 | else if (strcmp(argv[i], "-p") == 0) { |
| 593 | MultiDisplays = 1; |
| 594 | } |
Brian Paul | c4f2710 | 2006-03-23 17:17:23 +0000 | [diff] [blame] | 595 | else if (strcmp(argv[i], "-l") == 0) { |
| 596 | Locking = 1; |
| 597 | } |
Brian Paul | f34a30b | 2008-05-07 11:56:24 -0600 | [diff] [blame] | 598 | else if (strcmp(argv[i], "-t") == 0) { |
| 599 | Texture = 1; |
| 600 | } |
Brian Paul | c7d1444 | 2000-07-20 20:12:17 +0000 | [diff] [blame] | 601 | else if (strcmp(argv[i], "-n") == 0 && i + 1 < argc) { |
| 602 | numThreads = atoi(argv[i + 1]); |
| 603 | if (numThreads < 1) |
| 604 | numThreads = 1; |
| 605 | else if (numThreads > MAX_WINTHREADS) |
| 606 | numThreads = MAX_WINTHREADS; |
| 607 | i++; |
| 608 | } |
Brian Paul | 436d72e | 2006-03-23 16:58:22 +0000 | [diff] [blame] | 609 | else { |
Brian Paul | f34a30b | 2008-05-07 11:56:24 -0600 | [diff] [blame] | 610 | usage(); |
| 611 | exit(1); |
Brian Paul | 436d72e | 2006-03-23 16:58:22 +0000 | [diff] [blame] | 612 | } |
Brian Paul | c7d1444 | 2000-07-20 20:12:17 +0000 | [diff] [blame] | 613 | } |
| 614 | } |
| 615 | |
Brian Paul | c4f2710 | 2006-03-23 17:17:23 +0000 | [diff] [blame] | 616 | if (Locking) |
Brian Paul | f34a30b | 2008-05-07 11:56:24 -0600 | [diff] [blame] | 617 | printf("glthreads: Using explicit locks around Xlib calls.\n"); |
Brian Paul | c4f2710 | 2006-03-23 17:17:23 +0000 | [diff] [blame] | 618 | else |
| 619 | printf("glthreads: No explict locking.\n"); |
| 620 | |
| 621 | if (MultiDisplays) |
| 622 | printf("glthreads: Per-thread display connections.\n"); |
| 623 | else |
| 624 | printf("glthreads: Single display connection.\n"); |
| 625 | |
Brian Paul | c7d1444 | 2000-07-20 20:12:17 +0000 | [diff] [blame] | 626 | /* |
| 627 | * VERY IMPORTANT: call XInitThreads() before any other Xlib functions. |
| 628 | */ |
Brian Paul | 436d72e | 2006-03-23 16:58:22 +0000 | [diff] [blame] | 629 | if (!MultiDisplays) { |
Brian Paul | c4f2710 | 2006-03-23 17:17:23 +0000 | [diff] [blame] | 630 | if (!Locking) { |
| 631 | threadStat = XInitThreads(); |
Brian Paul | 436d72e | 2006-03-23 16:58:22 +0000 | [diff] [blame] | 632 | if (threadStat) { |
| 633 | printf("XInitThreads() returned %d (success)\n", (int) threadStat); |
| 634 | } |
| 635 | else { |
| 636 | printf("XInitThreads() returned 0 (failure- this program may fail)\n"); |
| 637 | } |
Brian Paul | c4f2710 | 2006-03-23 17:17:23 +0000 | [diff] [blame] | 638 | } |
Brian Paul | 436d72e | 2006-03-23 16:58:22 +0000 | [diff] [blame] | 639 | |
| 640 | dpy = XOpenDisplay(displayName); |
| 641 | if (!dpy) { |
Brian | 73eee24 | 2006-12-13 08:30:26 -0700 | [diff] [blame] | 642 | fprintf(stderr, "Unable to open display %s\n", XDisplayName(displayName)); |
Brian Paul | 436d72e | 2006-03-23 16:58:22 +0000 | [diff] [blame] | 643 | return -1; |
| 644 | } |
Brian Paul | c7d1444 | 2000-07-20 20:12:17 +0000 | [diff] [blame] | 645 | } |
| 646 | |
Brian Paul | f34a30b | 2008-05-07 11:56:24 -0600 | [diff] [blame] | 647 | pthread_mutex_init(&Mutex, NULL); |
| 648 | pthread_mutex_init(&CondMutex, NULL); |
| 649 | pthread_cond_init(&CondVar, NULL); |
Brian Paul | c4f2710 | 2006-03-23 17:17:23 +0000 | [diff] [blame] | 650 | |
Brian Paul | 436d72e | 2006-03-23 16:58:22 +0000 | [diff] [blame] | 651 | printf("glthreads: creating windows\n"); |
Brian Paul | c7d1444 | 2000-07-20 20:12:17 +0000 | [diff] [blame] | 652 | |
| 653 | NumWinThreads = numThreads; |
| 654 | |
| 655 | /* Create the GLX windows and contexts */ |
| 656 | for (i = 0; i < numThreads; i++) { |
Brian Paul | f34a30b | 2008-05-07 11:56:24 -0600 | [diff] [blame] | 657 | GLXContext share; |
| 658 | |
Brian Paul | 436d72e | 2006-03-23 16:58:22 +0000 | [diff] [blame] | 659 | if (MultiDisplays) { |
| 660 | WinThreads[i].Dpy = XOpenDisplay(displayName); |
| 661 | assert(WinThreads[i].Dpy); |
| 662 | } |
| 663 | else { |
| 664 | WinThreads[i].Dpy = dpy; |
| 665 | } |
Brian Paul | c7d1444 | 2000-07-20 20:12:17 +0000 | [diff] [blame] | 666 | WinThreads[i].Index = i; |
Brian Paul | f34a30b | 2008-05-07 11:56:24 -0600 | [diff] [blame] | 667 | WinThreads[i].Initialized = GL_FALSE; |
| 668 | |
| 669 | share = (Texture && i > 0) ? WinThreads[0].Context : 0; |
| 670 | |
| 671 | create_window(&WinThreads[i], share); |
Brian Paul | c7d1444 | 2000-07-20 20:12:17 +0000 | [diff] [blame] | 672 | } |
| 673 | |
Brian Paul | 436d72e | 2006-03-23 16:58:22 +0000 | [diff] [blame] | 674 | printf("glthreads: creating threads\n"); |
| 675 | |
Brian Paul | c7d1444 | 2000-07-20 20:12:17 +0000 | [diff] [blame] | 676 | /* Create the threads */ |
| 677 | for (i = 0; i < numThreads; i++) { |
| 678 | pthread_create(&WinThreads[i].Thread, NULL, thread_function, |
| 679 | (void*) &WinThreads[i]); |
Brian Paul | f34a30b | 2008-05-07 11:56:24 -0600 | [diff] [blame] | 680 | printf("glthreads: Created thread %p\n", (void *) WinThreads[i].Thread); |
Brian Paul | c7d1444 | 2000-07-20 20:12:17 +0000 | [diff] [blame] | 681 | } |
| 682 | |
Brian Paul | 436d72e | 2006-03-23 16:58:22 +0000 | [diff] [blame] | 683 | if (MultiDisplays) |
| 684 | event_loop_multi(); |
| 685 | else |
| 686 | event_loop(dpy); |
Brian Paul | c7d1444 | 2000-07-20 20:12:17 +0000 | [diff] [blame] | 687 | |
| 688 | clean_up(); |
| 689 | |
Brian Paul | 436d72e | 2006-03-23 16:58:22 +0000 | [diff] [blame] | 690 | if (MultiDisplays) { |
| 691 | for (i = 0; i < numThreads; i++) { |
| 692 | XCloseDisplay(WinThreads[i].Dpy); |
| 693 | } |
| 694 | } |
| 695 | else { |
| 696 | XCloseDisplay(dpy); |
| 697 | } |
Brian Paul | c7d1444 | 2000-07-20 20:12:17 +0000 | [diff] [blame] | 698 | |
| 699 | return 0; |
| 700 | } |
| 701 | |
| 702 | |
| 703 | #else /* PTHREADS */ |
| 704 | |
| 705 | |
| 706 | #include <stdio.h> |
| 707 | |
| 708 | int |
| 709 | main(int argc, char *argv[]) |
| 710 | { |
| 711 | printf("Sorry, this program wasn't compiled with PTHREADS defined.\n"); |
| 712 | return 0; |
| 713 | } |
| 714 | |
| 715 | |
| 716 | #endif /* PTHREADS */ |