get rid of unused span->start field
[mesa.git] / progs / xdemos / glthreads.c
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:
26 * -p Open a display connection for each thread
27 * -n <num threads> Number of threads to create (default is 2)
28 * -display <display name> Specify X display (default is :0.0)
29 *
30 * Brian Paul 20 July 2000
31 */
32
33
34 #if defined(PTHREADS) /* defined by Mesa on Linux and other platforms */
35
36 #include <assert.h>
37 #include <GL/gl.h>
38 #include <GL/glx.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <unistd.h>
43 #include <pthread.h>
44
45
46 /*
47 * Each window/thread/context:
48 */
49 struct winthread {
50 Display *Dpy;
51 int Index;
52 pthread_t Thread;
53 Window Win;
54 GLXContext Context;
55 float Angle;
56 int WinWidth, WinHeight;
57 GLboolean NewSize;
58 };
59
60
61 #define MAX_WINTHREADS 100
62 static struct winthread WinThreads[MAX_WINTHREADS];
63 static int NumWinThreads = 0;
64 static volatile GLboolean ExitFlag = GL_FALSE;
65
66 static GLboolean MultiDisplays = 0;
67 static GLboolean Locking = 0;
68
69 static pthread_mutex_t Mutex;
70
71
72 static void
73 Error(const char *msg)
74 {
75 fprintf(stderr, "Error: %s\n", msg);
76 exit(1);
77 }
78
79
80 /* draw a colored cube */
81 static void
82 draw_object(void)
83 {
84 glPushMatrix();
85 glScalef(0.75, 0.75, 0.75);
86
87 glColor3f(1, 0, 0);
88 glBegin(GL_POLYGON);
89 glVertex3f(1, -1, -1);
90 glVertex3f(1, 1, -1);
91 glVertex3f(1, 1, 1);
92 glVertex3f(1, -1, 1);
93 glEnd();
94
95 glColor3f(0, 1, 1);
96 glBegin(GL_POLYGON);
97 glVertex3f(-1, -1, -1);
98 glVertex3f(-1, 1, -1);
99 glVertex3f(-1, 1, 1);
100 glVertex3f(-1, -1, 1);
101 glEnd();
102
103 glColor3f(0, 1, 0);
104 glBegin(GL_POLYGON);
105 glVertex3f(-1, 1, -1);
106 glVertex3f( 1, 1, -1);
107 glVertex3f( 1, 1, 1);
108 glVertex3f(-1, 1, 1);
109 glEnd();
110
111 glColor3f(1, 0, 1);
112 glBegin(GL_POLYGON);
113 glVertex3f(-1, -1, -1);
114 glVertex3f( 1, -1, -1);
115 glVertex3f( 1, -1, 1);
116 glVertex3f(-1, -1, 1);
117 glEnd();
118
119 glColor3f(0, 0, 1);
120 glBegin(GL_POLYGON);
121 glVertex3f(-1, -1, 1);
122 glVertex3f( 1, -1, 1);
123 glVertex3f( 1, 1, 1);
124 glVertex3f(-1, 1, 1);
125 glEnd();
126
127 glColor3f(1, 1, 0);
128 glBegin(GL_POLYGON);
129 glVertex3f(-1, -1, -1);
130 glVertex3f( 1, -1, -1);
131 glVertex3f( 1, 1, -1);
132 glVertex3f(-1, 1, -1);
133 glEnd();
134 glPopMatrix();
135 }
136
137
138 /* signal resize of given window */
139 static void
140 resize(struct winthread *wt, int w, int h)
141 {
142 wt->NewSize = GL_TRUE;
143 wt->WinWidth = w;
144 wt->WinHeight = h;
145 }
146
147
148 /*
149 * We have an instance of this for each thread.
150 */
151 static void
152 draw_loop(struct winthread *wt)
153 {
154 GLboolean firstIter = GL_TRUE;
155
156 while (!ExitFlag) {
157
158 if (Locking)
159 pthread_mutex_lock(&Mutex);
160
161 glXMakeCurrent(wt->Dpy, wt->Win, wt->Context);
162 if (firstIter) {
163 printf("glthreads: %d: GL_RENDERER = %s\n", wt->Index,
164 (char *) glGetString(GL_RENDERER));
165 firstIter = GL_FALSE;
166 }
167
168 if (Locking)
169 pthread_mutex_unlock(&Mutex);
170
171 glEnable(GL_DEPTH_TEST);
172
173 if (wt->NewSize) {
174 GLfloat w = (float) wt->WinWidth / (float) wt->WinHeight;
175 glViewport(0, 0, wt->WinWidth, wt->WinHeight);
176 glMatrixMode(GL_PROJECTION);
177 glLoadIdentity();
178 glFrustum(-w, w, -1.0, 1.0, 1.5, 10);
179 glMatrixMode(GL_MODELVIEW);
180 glLoadIdentity();
181 glTranslatef(0, 0, -2.5);
182 wt->NewSize = GL_FALSE;
183 }
184
185 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
186
187 glPushMatrix();
188 glRotatef(wt->Angle, 0, 0, 1);
189 glRotatef(wt->Angle, 1, 0, 0);
190 glScalef(0.7, 0.7, 0.7);
191 draw_object();
192 glPopMatrix();
193
194 if (Locking)
195 pthread_mutex_lock(&Mutex);
196
197 glXSwapBuffers(wt->Dpy, wt->Win);
198
199 if (Locking)
200 pthread_mutex_unlock(&Mutex);
201
202 usleep(5000);
203 wt->Angle += 1.0;
204 }
205 }
206
207
208 /*
209 * The main process thread runs this loop.
210 * Single display connection for all threads.
211 */
212 static void
213 event_loop(Display *dpy)
214 {
215 XEvent event;
216 int i;
217
218 assert(!MultiDisplays);
219
220 while (!ExitFlag) {
221
222 if (Locking) {
223 while (1) {
224 int k;
225 pthread_mutex_lock(&Mutex);
226 k = XPending(dpy);
227 if (k) {
228 XNextEvent(dpy, &event);
229 pthread_mutex_unlock(&Mutex);
230 break;
231 }
232 pthread_mutex_unlock(&Mutex);
233 usleep(5000);
234 }
235 }
236 else {
237 XNextEvent(dpy, &event);
238 }
239
240 switch (event.type) {
241 case ConfigureNotify:
242 /* Find winthread for this event's window */
243 for (i = 0; i < NumWinThreads; i++) {
244 struct winthread *wt = &WinThreads[i];
245 if (event.xconfigure.window == wt->Win) {
246 resize(wt, event.xconfigure.width,
247 event.xconfigure.height);
248 break;
249 }
250 }
251 break;
252 case KeyPress:
253 /* tell all threads to exit */
254 ExitFlag = GL_TRUE;
255 /*printf("exit draw_loop %d\n", wt->Index);*/
256 return;
257 default:
258 /*no-op*/ ;
259 }
260 }
261 }
262
263
264 /*
265 * Separate display connection for each thread.
266 */
267 static void
268 event_loop_multi(void)
269 {
270 XEvent event;
271 int w = 0;
272
273 assert(MultiDisplays);
274
275 while (!ExitFlag) {
276 struct winthread *wt = &WinThreads[w];
277 if (XPending(wt->Dpy)) {
278 XNextEvent(wt->Dpy, &event);
279 switch (event.type) {
280 case ConfigureNotify:
281 resize(wt, event.xconfigure.width, event.xconfigure.height);
282 break;
283 case KeyPress:
284 /* tell all threads to exit */
285 ExitFlag = GL_TRUE;
286 /*printf("exit draw_loop %d\n", wt->Index);*/
287 return;
288 default:
289 /*no-op*/ ;
290 }
291 }
292 w = (w + 1) % NumWinThreads;
293 usleep(5000);
294 }
295 }
296
297
298
299 /*
300 * we'll call this once for each thread, before the threads are created.
301 */
302 static void
303 create_window(struct winthread *wt)
304 {
305 Window win;
306 GLXContext ctx;
307 int attrib[] = { GLX_RGBA,
308 GLX_RED_SIZE, 1,
309 GLX_GREEN_SIZE, 1,
310 GLX_BLUE_SIZE, 1,
311 GLX_DEPTH_SIZE, 1,
312 GLX_DOUBLEBUFFER,
313 None };
314 int scrnum;
315 XSetWindowAttributes attr;
316 unsigned long mask;
317 Window root;
318 XVisualInfo *visinfo;
319 int width = 80, height = 80;
320 int xpos = (wt->Index % 10) * 90;
321 int ypos = (wt->Index / 10) * 100;
322
323 scrnum = DefaultScreen(wt->Dpy);
324 root = RootWindow(wt->Dpy, scrnum);
325
326 visinfo = glXChooseVisual(wt->Dpy, scrnum, attrib);
327 if (!visinfo) {
328 Error("Unable to find RGB, Z, double-buffered visual");
329 }
330
331 /* window attributes */
332 attr.background_pixel = 0;
333 attr.border_pixel = 0;
334 attr.colormap = XCreateColormap(wt->Dpy, root, visinfo->visual, AllocNone);
335 attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
336 mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
337
338 win = XCreateWindow(wt->Dpy, root, xpos, ypos, width, height,
339 0, visinfo->depth, InputOutput,
340 visinfo->visual, mask, &attr);
341 if (!win) {
342 Error("Couldn't create window");
343 }
344
345 {
346 XSizeHints sizehints;
347 sizehints.x = xpos;
348 sizehints.y = ypos;
349 sizehints.width = width;
350 sizehints.height = height;
351 sizehints.flags = USSize | USPosition;
352 XSetNormalHints(wt->Dpy, win, &sizehints);
353 XSetStandardProperties(wt->Dpy, win, "glthreads", "glthreads",
354 None, (char **)NULL, 0, &sizehints);
355 }
356
357
358 ctx = glXCreateContext(wt->Dpy, visinfo, NULL, True);
359 if (!ctx) {
360 Error("Couldn't create GLX context");
361 }
362
363 XMapWindow(wt->Dpy, win);
364 XSync(wt->Dpy, 0);
365
366 /* save the info for this window/context */
367 wt->Win = win;
368 wt->Context = ctx;
369 wt->Angle = 0.0;
370 wt->WinWidth = width;
371 wt->WinHeight = height;
372 wt->NewSize = GL_TRUE;
373 }
374
375
376 /*
377 * Called by pthread_create()
378 */
379 static void *
380 thread_function(void *p)
381 {
382 struct winthread *wt = (struct winthread *) p;
383 draw_loop(wt);
384 return NULL;
385 }
386
387
388 /*
389 * called before exit to wait for all threads to finish
390 */
391 static void
392 clean_up(void)
393 {
394 int i;
395
396 /* wait for threads to finish */
397 for (i = 0; i < NumWinThreads; i++) {
398 pthread_join(WinThreads[i].Thread, NULL);
399 }
400
401 for (i = 0; i < NumWinThreads; i++) {
402 glXDestroyContext(WinThreads[i].Dpy, WinThreads[i].Context);
403 XDestroyWindow(WinThreads[i].Dpy, WinThreads[i].Win);
404 }
405 }
406
407
408
409 int
410 main(int argc, char *argv[])
411 {
412 char *displayName = ":0.0";
413 int numThreads = 2;
414 Display *dpy = NULL;
415 int i;
416 Status threadStat;
417
418 if (argc == 1) {
419 printf("glthreads: test of GL thread safety (any key = exit)\n");
420 printf("Usage:\n");
421 printf(" glthreads [-display dpyName] [-n numthreads]\n");
422 }
423 else {
424 int i;
425 for (i = 1; i < argc; i++) {
426 if (strcmp(argv[i], "-display") == 0 && i + 1 < argc) {
427 displayName = argv[i + 1];
428 i++;
429 }
430 else if (strcmp(argv[i], "-p") == 0) {
431 MultiDisplays = 1;
432 }
433 else if (strcmp(argv[i], "-l") == 0) {
434 Locking = 1;
435 }
436 else if (strcmp(argv[i], "-n") == 0 && i + 1 < argc) {
437 numThreads = atoi(argv[i + 1]);
438 if (numThreads < 1)
439 numThreads = 1;
440 else if (numThreads > MAX_WINTHREADS)
441 numThreads = MAX_WINTHREADS;
442 i++;
443 }
444 else {
445 fprintf(stderr, "glthreads: unexpected flag: %s\n", argv[i]);
446 }
447 }
448 }
449
450 if (Locking)
451 printf("glthreads: Using explict locks around Xlib calls.\n");
452 else
453 printf("glthreads: No explict locking.\n");
454
455 if (MultiDisplays)
456 printf("glthreads: Per-thread display connections.\n");
457 else
458 printf("glthreads: Single display connection.\n");
459
460 /*
461 * VERY IMPORTANT: call XInitThreads() before any other Xlib functions.
462 */
463 if (!MultiDisplays) {
464 if (!Locking) {
465 threadStat = XInitThreads();
466 if (threadStat) {
467 printf("XInitThreads() returned %d (success)\n", (int) threadStat);
468 }
469 else {
470 printf("XInitThreads() returned 0 (failure- this program may fail)\n");
471 }
472 }
473
474 dpy = XOpenDisplay(displayName);
475 if (!dpy) {
476 fprintf(stderr, "Unable to open display %s\n", displayName);
477 return -1;
478 }
479 }
480
481 if (Locking) {
482 pthread_mutex_init(&Mutex, NULL);
483 }
484
485 printf("glthreads: creating windows\n");
486
487 NumWinThreads = numThreads;
488
489 /* Create the GLX windows and contexts */
490 for (i = 0; i < numThreads; i++) {
491 if (MultiDisplays) {
492 WinThreads[i].Dpy = XOpenDisplay(displayName);
493 assert(WinThreads[i].Dpy);
494 }
495 else {
496 WinThreads[i].Dpy = dpy;
497 }
498 WinThreads[i].Index = i;
499 create_window(&WinThreads[i]);
500 }
501
502 printf("glthreads: creating threads\n");
503
504 /* Create the threads */
505 for (i = 0; i < numThreads; i++) {
506 pthread_create(&WinThreads[i].Thread, NULL, thread_function,
507 (void*) &WinThreads[i]);
508 printf("glthreads: Created thread %u\n", (unsigned int) WinThreads[i].Thread);
509 }
510
511 if (MultiDisplays)
512 event_loop_multi();
513 else
514 event_loop(dpy);
515
516 clean_up();
517
518 if (MultiDisplays) {
519 for (i = 0; i < numThreads; i++) {
520 XCloseDisplay(WinThreads[i].Dpy);
521 }
522 }
523 else {
524 XCloseDisplay(dpy);
525 }
526
527 return 0;
528 }
529
530
531 #else /* PTHREADS */
532
533
534 #include <stdio.h>
535
536 int
537 main(int argc, char *argv[])
538 {
539 printf("Sorry, this program wasn't compiled with PTHREADS defined.\n");
540 return 0;
541 }
542
543
544 #endif /* PTHREADS */