~ubuntu-branches/ubuntu/oneiric/mesa-demos/oneiric

« back to all changes in this revision

Viewing changes to src/egl/opengl/xeglthreads.c

  • Committer: Bazaar Package Importer
  • Author(s): Christopher James Halse Rogers
  • Date: 2010-09-27 16:18:27 UTC
  • Revision ID: james.westby@ubuntu.com-20100927161827-1yfgolc1oy9sjhi8
Tags: upstream-8.0.1
ImportĀ upstreamĀ versionĀ 8.0.1

Show diffs side-by-side

added added

removed removed

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