renumber ARB_shader_objects and ARB_vertex_shader offsets
[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 * -n <num threads> Number of threads to create (default is 2)
27 * -display <display name> Specify X display (default is :0.0)
28 *
29 * Brian Paul 20 July 2000
30 */
31
32
33 #if defined(PTHREADS) /* defined by Mesa on Linux and other platforms */
34
35 #include <GL/gl.h>
36 #include <GL/glx.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <unistd.h>
41 #include <pthread.h>
42
43
44 /*
45 * Each window/thread/context:
46 */
47 struct winthread {
48 Display *Dpy;
49 int Index;
50 pthread_t Thread;
51 Window Win;
52 GLXContext Context;
53 float Angle;
54 int WinWidth, WinHeight;
55 GLboolean NewSize;
56 };
57
58
59 #define MAX_WINTHREADS 100
60 static struct winthread WinThreads[MAX_WINTHREADS];
61 static int NumWinThreads = 0;
62 static volatile GLboolean ExitFlag = GL_FALSE;
63
64
65
66 static void
67 Error(const char *msg)
68 {
69 fprintf(stderr, "Error: %s\n", msg);
70 exit(1);
71 }
72
73
74 /* draw a colored cube */
75 static void
76 draw_object(void)
77 {
78 glPushMatrix();
79 glScalef(0.75, 0.75, 0.75);
80
81 glColor3f(1, 0, 0);
82 glBegin(GL_POLYGON);
83 glVertex3f(1, -1, -1);
84 glVertex3f(1, 1, -1);
85 glVertex3f(1, 1, 1);
86 glVertex3f(1, -1, 1);
87 glEnd();
88
89 glColor3f(0, 1, 1);
90 glBegin(GL_POLYGON);
91 glVertex3f(-1, -1, -1);
92 glVertex3f(-1, 1, -1);
93 glVertex3f(-1, 1, 1);
94 glVertex3f(-1, -1, 1);
95 glEnd();
96
97 glColor3f(0, 1, 0);
98 glBegin(GL_POLYGON);
99 glVertex3f(-1, 1, -1);
100 glVertex3f( 1, 1, -1);
101 glVertex3f( 1, 1, 1);
102 glVertex3f(-1, 1, 1);
103 glEnd();
104
105 glColor3f(1, 0, 1);
106 glBegin(GL_POLYGON);
107 glVertex3f(-1, -1, -1);
108 glVertex3f( 1, -1, -1);
109 glVertex3f( 1, -1, 1);
110 glVertex3f(-1, -1, 1);
111 glEnd();
112
113 glColor3f(0, 0, 1);
114 glBegin(GL_POLYGON);
115 glVertex3f(-1, -1, 1);
116 glVertex3f( 1, -1, 1);
117 glVertex3f( 1, 1, 1);
118 glVertex3f(-1, 1, 1);
119 glEnd();
120
121 glColor3f(1, 1, 0);
122 glBegin(GL_POLYGON);
123 glVertex3f(-1, -1, -1);
124 glVertex3f( 1, -1, -1);
125 glVertex3f( 1, 1, -1);
126 glVertex3f(-1, 1, -1);
127 glEnd();
128 glPopMatrix();
129 }
130
131
132 /* signal resize of given window */
133 static void
134 resize(struct winthread *wt, int w, int h)
135 {
136 wt->NewSize = GL_TRUE;
137 wt->WinWidth = w;
138 wt->WinHeight = h;
139 }
140
141
142 /*
143 * We have an instance of this for each thread.
144 */
145 static void
146 draw_loop(struct winthread *wt)
147 {
148 while (!ExitFlag) {
149
150 glXMakeCurrent(wt->Dpy, wt->Win, wt->Context);
151
152 glEnable(GL_DEPTH_TEST);
153
154 if (wt->NewSize) {
155 GLfloat w = (float) wt->WinWidth / (float) wt->WinHeight;
156 glViewport(0, 0, wt->WinWidth, wt->WinHeight);
157 glMatrixMode(GL_PROJECTION);
158 glLoadIdentity();
159 glFrustum(-w, w, -1.0, 1.0, 1.5, 10);
160 glMatrixMode(GL_MODELVIEW);
161 glLoadIdentity();
162 glTranslatef(0, 0, -2.5);
163 wt->NewSize = GL_FALSE;
164 }
165
166 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
167
168 glPushMatrix();
169 glRotatef(wt->Angle, 0, 0, 1);
170 glRotatef(wt->Angle, 1, 0, 0);
171 glScalef(0.7, 0.7, 0.7);
172 draw_object();
173 glPopMatrix();
174
175 glXSwapBuffers(wt->Dpy, wt->Win);
176
177 wt->Angle += 1.0;
178 }
179 }
180
181
182 /*
183 * The main process thread runs this loop.
184 */
185 static void
186 event_loop(Display *dpy)
187 {
188 XEvent event;
189 int i;
190
191 while (!ExitFlag) {
192 XNextEvent(dpy, &event);
193 switch (event.type) {
194 case ConfigureNotify:
195 /* Find winthread for this event's window */
196 for (i = 0; i < NumWinThreads; i++) {
197 struct winthread *wt = &WinThreads[i];
198 if (event.xconfigure.window == wt->Win) {
199 resize(wt, event.xconfigure.width,
200 event.xconfigure.height);
201 break;
202 }
203 }
204 break;
205 case KeyPress:
206 /* tell all threads to exit */
207 ExitFlag = GL_TRUE;
208 /*printf("exit draw_loop %d\n", wt->Index);*/
209 return;
210 default:
211 /*no-op*/ ;
212 }
213 }
214 }
215
216
217 /*
218 * we'll call this once for each thread, before the threads are created.
219 */
220 static void
221 create_window(struct winthread *wt)
222 {
223 Window win;
224 GLXContext ctx;
225 int attrib[] = { GLX_RGBA,
226 GLX_RED_SIZE, 1,
227 GLX_GREEN_SIZE, 1,
228 GLX_BLUE_SIZE, 1,
229 GLX_DEPTH_SIZE, 1,
230 GLX_DOUBLEBUFFER,
231 None };
232 int scrnum;
233 XSetWindowAttributes attr;
234 unsigned long mask;
235 Window root;
236 XVisualInfo *visinfo;
237 int width = 80, height = 80;
238 int xpos = (wt->Index % 10) * 90;
239 int ypos = (wt->Index / 10) * 100;
240
241 scrnum = DefaultScreen(wt->Dpy);
242 root = RootWindow(wt->Dpy, scrnum);
243
244 visinfo = glXChooseVisual(wt->Dpy, scrnum, attrib);
245 if (!visinfo) {
246 Error("Unable to find RGB, Z, double-buffered visual");
247 }
248
249 /* window attributes */
250 attr.background_pixel = 0;
251 attr.border_pixel = 0;
252 attr.colormap = XCreateColormap(wt->Dpy, root, visinfo->visual, AllocNone);
253 attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
254 mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
255
256 win = XCreateWindow(wt->Dpy, root, xpos, ypos, width, height,
257 0, visinfo->depth, InputOutput,
258 visinfo->visual, mask, &attr);
259 if (!win) {
260 Error("Couldn't create window");
261 }
262
263 {
264 XSizeHints sizehints;
265 sizehints.x = xpos;
266 sizehints.y = ypos;
267 sizehints.width = width;
268 sizehints.height = height;
269 sizehints.flags = USSize | USPosition;
270 XSetNormalHints(wt->Dpy, win, &sizehints);
271 XSetStandardProperties(wt->Dpy, win, "glthreads", "glthreads",
272 None, (char **)NULL, 0, &sizehints);
273 }
274
275
276 ctx = glXCreateContext(wt->Dpy, visinfo, NULL, True);
277 if (!ctx) {
278 Error("Couldn't create GLX context");
279 }
280
281 XMapWindow(wt->Dpy, win);
282 XSync(wt->Dpy, 0);
283
284 /* save the info for this window/context */
285 wt->Win = win;
286 wt->Context = ctx;
287 wt->Angle = 0.0;
288 wt->WinWidth = width;
289 wt->WinHeight = height;
290 wt->NewSize = GL_TRUE;
291 }
292
293
294 /*
295 * Called by pthread_create()
296 */
297 static void *
298 thread_function(void *p)
299 {
300 struct winthread *wt = (struct winthread *) p;
301 draw_loop(wt);
302 return NULL;
303 }
304
305
306 /*
307 * called before exit to wait for all threads to finish
308 */
309 static void
310 clean_up(void)
311 {
312 int i;
313
314 /* wait for threads to finish */
315 for (i = 0; i < NumWinThreads; i++) {
316 pthread_join(WinThreads[i].Thread, NULL);
317 }
318
319 for (i = 0; i < NumWinThreads; i++) {
320 glXDestroyContext(WinThreads[i].Dpy, WinThreads[i].Context);
321 XDestroyWindow(WinThreads[i].Dpy, WinThreads[i].Win);
322 }
323 }
324
325
326
327 int
328 main(int argc, char *argv[])
329 {
330 char *displayName = ":0.0";
331 int numThreads = 2;
332 Display *dpy;
333 int i;
334 Status threadStat;
335
336 if (argc == 1) {
337 printf("threadgl: test of GL thread safety (any key = exit)\n");
338 printf("Usage:\n");
339 printf(" threadgl [-display dpyName] [-n numthreads]\n");
340 }
341 else {
342 int i;
343 for (i = 1; i < argc; i++) {
344 if (strcmp(argv[i], "-display") == 0 && i + 1 < argc) {
345 displayName = argv[i + 1];
346 i++;
347 }
348 else if (strcmp(argv[i], "-n") == 0 && i + 1 < argc) {
349 numThreads = atoi(argv[i + 1]);
350 if (numThreads < 1)
351 numThreads = 1;
352 else if (numThreads > MAX_WINTHREADS)
353 numThreads = MAX_WINTHREADS;
354 i++;
355 }
356 }
357 }
358
359 /*
360 * VERY IMPORTANT: call XInitThreads() before any other Xlib functions.
361 */
362 threadStat = XInitThreads();
363 if (threadStat) {
364 printf("XInitThreads() returned %d (success)\n", (int) threadStat);
365 }
366 else {
367 printf("XInitThreads() returned 0 (failure- this program may fail)\n");
368 }
369
370
371 dpy = XOpenDisplay(displayName);
372 if (!dpy) {
373 fprintf(stderr, "Unable to open display %s\n", displayName);
374 return -1;
375 }
376
377 NumWinThreads = numThreads;
378
379 /* Create the GLX windows and contexts */
380 for (i = 0; i < numThreads; i++) {
381 WinThreads[i].Dpy = dpy;
382 WinThreads[i].Index = i;
383 create_window(&WinThreads[i]);
384 }
385
386 /* Create the threads */
387 for (i = 0; i < numThreads; i++) {
388 pthread_create(&WinThreads[i].Thread, NULL, thread_function,
389 (void*) &WinThreads[i]);
390 printf("Created Thread %d\n", (int) WinThreads[i].Thread);
391 }
392
393 event_loop(dpy);
394
395 clean_up();
396
397 XCloseDisplay(dpy);
398
399 return 0;
400 }
401
402
403 #else /* PTHREADS */
404
405
406 #include <stdio.h>
407
408 int
409 main(int argc, char *argv[])
410 {
411 printf("Sorry, this program wasn't compiled with PTHREADS defined.\n");
412 return 0;
413 }
414
415
416 #endif /* PTHREADS */