17ec3b29aSmrg/* $Id: sharedtex_mt.c,v 1.1.1.2 2019/03/11 06:59:40 mrg Exp $ */
232001f49Smrg
332001f49Smrg/*
432001f49Smrg * Test sharing of display lists and texture objects between GLX contests.
532001f49Smrg * Brian Paul
632001f49Smrg * Summer 2000
732001f49Smrg *
832001f49Smrg *
932001f49Smrg * Copyright (C) 2000  Brian Paul   All Rights Reserved.
1032001f49Smrg *
1132001f49Smrg * Permission is hereby granted, free of charge, to any person obtaining a
1232001f49Smrg * copy of this software and associated documentation files (the "Software"),
1332001f49Smrg * to deal in the Software without restriction, including without limitation
1432001f49Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1532001f49Smrg * and/or sell copies of the Software, and to permit persons to whom the
1632001f49Smrg * Software is furnished to do so, subject to the following conditions:
1732001f49Smrg *
1832001f49Smrg * The above copyright notice and this permission notice shall be included
1932001f49Smrg * in all copies or substantial portions of the Software.
2032001f49Smrg *
2132001f49Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
2232001f49Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2332001f49Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
2432001f49Smrg * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
2532001f49Smrg * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
2632001f49Smrg * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2732001f49Smrg *
2832001f49Smrg *
2932001f49Smrg * Modified 2009 for multithreading by Thomas Hellstrom.
3032001f49Smrg */
3132001f49Smrg
3232001f49Smrg
3332001f49Smrg#include <GL/gl.h>
3432001f49Smrg#include <GL/glx.h>
3532001f49Smrg#include <stdio.h>
3632001f49Smrg#include <stdlib.h>
3732001f49Smrg#include <unistd.h>
3832001f49Smrg#include <string.h>
3932001f49Smrg#include <pthread.h>
4032001f49Smrg#include <X11/X.h>
4132001f49Smrg
4232001f49Smrgstruct thread_init_arg {
4332001f49Smrg   int id;
4432001f49Smrg};
4532001f49Smrg
4632001f49Smrgstruct window {
4732001f49Smrg   pthread_mutex_t drawMutex;
4832001f49Smrg   char DisplayName[1000];
4932001f49Smrg   Display *Dpy;
5032001f49Smrg   Window Win;
5132001f49Smrg   GLXContext Context;
5232001f49Smrg   float Angle;
5332001f49Smrg   int Id;
5432001f49Smrg   XVisualInfo *visInfo;
5532001f49Smrg};
5632001f49Smrg
5732001f49Smrg
5832001f49Smrg#define MAX_WINDOWS 20
5932001f49Smrgstatic struct window Windows[MAX_WINDOWS];
6032001f49Smrgstatic int NumWindows = 0;
6132001f49Smrgstatic int terminate = 0;
6232001f49Smrgstatic GLXContext gCtx;
6332001f49Smrgstatic Display *gDpy;
6432001f49Smrgstatic GLuint Textures[3];
6532001f49Smrg
6632001f49Smrg
6732001f49Smrg
6832001f49Smrgstatic void
6932001f49SmrgError(const char *display, const char *msg)
7032001f49Smrg{
7132001f49Smrg   fprintf(stderr, "Error on display %s - %s\n", display, msg);
7232001f49Smrg   exit(1);
7332001f49Smrg}
7432001f49Smrg
7532001f49Smrg
7632001f49Smrgstatic int
7732001f49SmrginitMainthread(Display *dpy, const char *displayName)
7832001f49Smrg{
7932001f49Smrg   int scrnum;
8032001f49Smrg   XVisualInfo *visinfo;
8132001f49Smrg   int attrib[] = { GLX_RGBA,
8232001f49Smrg		    GLX_RED_SIZE, 1,
8332001f49Smrg		    GLX_GREEN_SIZE, 1,
8432001f49Smrg		    GLX_BLUE_SIZE, 1,
8532001f49Smrg		    GLX_DOUBLEBUFFER,
8632001f49Smrg                    GLX_DEPTH_SIZE, 1,
8732001f49Smrg		    None };
8832001f49Smrg
8932001f49Smrg   scrnum = DefaultScreen(dpy);
9032001f49Smrg   visinfo = glXChooseVisual(dpy, scrnum, attrib);
9132001f49Smrg   if (!visinfo) {
9232001f49Smrg      Error(displayName, "Unable to find RGB, double-buffered visual");
9332001f49Smrg      return -1;
9432001f49Smrg   }
9532001f49Smrg   gCtx = glXCreateContext(dpy, visinfo, NULL, True);
9632001f49Smrg   if (!gCtx) {
9732001f49Smrg      Error(displayName, "Couldn't create GLX context");
9832001f49Smrg      return -1;
9932001f49Smrg   }
10032001f49Smrg   return 0;
10132001f49Smrg}
10232001f49Smrg
10332001f49Smrgstatic struct window *
10432001f49SmrgAddWindow(Display *dpy, const char *displayName, int xpos, int ypos,
10532001f49Smrg          GLXContext sCtx)
10632001f49Smrg{
10732001f49Smrg   Window win;
10832001f49Smrg   GLXContext ctx;
10932001f49Smrg   int attrib[] = { GLX_RGBA,
11032001f49Smrg		    GLX_RED_SIZE, 1,
11132001f49Smrg		    GLX_GREEN_SIZE, 1,
11232001f49Smrg		    GLX_BLUE_SIZE, 1,
11332001f49Smrg		    GLX_DOUBLEBUFFER,
11432001f49Smrg                    GLX_DEPTH_SIZE, 1,
11532001f49Smrg		    None };
11632001f49Smrg   int scrnum;
11732001f49Smrg   XSetWindowAttributes attr;
11832001f49Smrg   unsigned long mask;
11932001f49Smrg   Window root;
12032001f49Smrg   XVisualInfo *visinfo;
12132001f49Smrg   int width = 300, height = 300;
12232001f49Smrg
12332001f49Smrg   if (NumWindows >= MAX_WINDOWS)
12432001f49Smrg      return NULL;
12532001f49Smrg
12632001f49Smrg   scrnum = DefaultScreen(dpy);
12732001f49Smrg   root = RootWindow(dpy, scrnum);
12832001f49Smrg
12932001f49Smrg   visinfo = glXChooseVisual(dpy, scrnum, attrib);
13032001f49Smrg   if (!visinfo) {
13132001f49Smrg      Error(displayName, "Unable to find RGB, double-buffered visual");
13232001f49Smrg      return NULL;
13332001f49Smrg   }
13432001f49Smrg
13532001f49Smrg   /* window attributes */
13632001f49Smrg   attr.background_pixel = 0;
13732001f49Smrg   attr.border_pixel = 0;
13832001f49Smrg   attr.colormap = XCreateColormap(dpy, root, visinfo->visual, AllocNone);
13932001f49Smrg   attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
14032001f49Smrg   mask = CWBorderPixel | CWColormap | CWEventMask;
14132001f49Smrg
14232001f49Smrg   win = XCreateWindow(dpy, root, xpos, ypos, width, height,
14332001f49Smrg		       0, visinfo->depth, InputOutput,
14432001f49Smrg		       visinfo->visual, mask, &attr);
14532001f49Smrg   if (!win) {
14632001f49Smrg      Error(displayName, "Couldn't create window");
14732001f49Smrg      return NULL;
14832001f49Smrg   }
14932001f49Smrg
15032001f49Smrg   {
15132001f49Smrg      XSizeHints sizehints;
15232001f49Smrg      sizehints.x = xpos;
15332001f49Smrg      sizehints.y = ypos;
15432001f49Smrg      sizehints.width  = width;
15532001f49Smrg      sizehints.height = height;
15632001f49Smrg      sizehints.flags = USSize | USPosition;
15732001f49Smrg      XSetNormalHints(dpy, win, &sizehints);
15832001f49Smrg      XSetStandardProperties(dpy, win, displayName, displayName,
15932001f49Smrg			     None, (char **)NULL, 0, &sizehints);
16032001f49Smrg   }
16132001f49Smrg
16232001f49Smrg
16332001f49Smrg   ctx = glXCreateContext(dpy, visinfo,
16432001f49Smrg                          sCtx ? sCtx : NULL, True);
16532001f49Smrg
16632001f49Smrg   if (!ctx) {
16732001f49Smrg      Error(displayName, "Couldn't create GLX context");
16832001f49Smrg      return NULL;
16932001f49Smrg   }
17032001f49Smrg
17132001f49Smrg   XMapWindow(dpy, win);
17232001f49Smrg
17332001f49Smrg   /* save the info for this window */
17432001f49Smrg   {
17532001f49Smrg      static int id = 0;
17632001f49Smrg      struct window *h = &Windows[NumWindows];
17732001f49Smrg      if (strlen(displayName) + 1 > sizeof(h->DisplayName)) {
17832001f49Smrg         Error(displayName, "string overflow");
17932001f49Smrg         return NULL;
18032001f49Smrg      }
18132001f49Smrg      strcpy(h->DisplayName, displayName);
18232001f49Smrg      h->Dpy = dpy;
18332001f49Smrg      h->Win = win;
18432001f49Smrg      h->Context = ctx;
18532001f49Smrg      h->Angle = 0.0;
18632001f49Smrg      h->Id = id++;
18732001f49Smrg      h->visInfo = visinfo;
18832001f49Smrg      pthread_mutex_init(&h->drawMutex, NULL);
18932001f49Smrg      NumWindows++;
19032001f49Smrg      return &Windows[NumWindows-1];
19132001f49Smrg   }
19232001f49Smrg}
19332001f49Smrg
19432001f49Smrg
19532001f49Smrgstatic void
19632001f49SmrgInitGLstuff(void)
19732001f49Smrg
19832001f49Smrg{
19932001f49Smrg   glGenTextures(3, Textures);
20032001f49Smrg
20132001f49Smrg   /* setup first texture object */
20232001f49Smrg   {
20332001f49Smrg      GLubyte image[16][16][4];
20432001f49Smrg      GLint i, j;
20532001f49Smrg      glBindTexture(GL_TEXTURE_2D, Textures[0]);
20632001f49Smrg
20732001f49Smrg      /* red/white checkerboard */
20832001f49Smrg      for (i = 0; i < 16; i++) {
20932001f49Smrg         for (j = 0; j < 16; j++) {
21032001f49Smrg            if ((i ^ j) & 1) {
21132001f49Smrg               image[i][j][0] = 255;
21232001f49Smrg               image[i][j][1] = 255;
21332001f49Smrg               image[i][j][2] = 255;
21432001f49Smrg               image[i][j][3] = 255;
21532001f49Smrg            }
21632001f49Smrg            else {
21732001f49Smrg               image[i][j][0] = 255;
21832001f49Smrg               image[i][j][1] = 0;
21932001f49Smrg               image[i][j][2] = 0;
22032001f49Smrg               image[i][j][3] = 255;
22132001f49Smrg            }
22232001f49Smrg         }
22332001f49Smrg      }
22432001f49Smrg
22532001f49Smrg      glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
22632001f49Smrg      glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA,
22732001f49Smrg                   GL_UNSIGNED_BYTE, image);
22832001f49Smrg      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
22932001f49Smrg      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
23032001f49Smrg   }
23132001f49Smrg
23232001f49Smrg   /* setup second texture object */
23332001f49Smrg   {
23432001f49Smrg      GLubyte image[8][8][3];
23532001f49Smrg      GLint i, j;
23632001f49Smrg      glBindTexture(GL_TEXTURE_2D, Textures[1]);
23732001f49Smrg
23832001f49Smrg      /* green/yellow checkerboard */
23932001f49Smrg      for (i = 0; i < 8; i++) {
24032001f49Smrg         for (j = 0; j < 8; j++) {
24132001f49Smrg            if ((i ^ j) & 1) {
24232001f49Smrg               image[i][j][0] = 0;
24332001f49Smrg               image[i][j][1] = 255;
24432001f49Smrg               image[i][j][2] = 0;
24532001f49Smrg            }
24632001f49Smrg            else {
24732001f49Smrg               image[i][j][0] = 255;
24832001f49Smrg               image[i][j][1] = 255;
24932001f49Smrg               image[i][j][2] = 0;
25032001f49Smrg            }
25132001f49Smrg         }
25232001f49Smrg      }
25332001f49Smrg
25432001f49Smrg      glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
25532001f49Smrg      glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 8, 8, 0, GL_RGB,
25632001f49Smrg                   GL_UNSIGNED_BYTE, image);
25732001f49Smrg      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
25832001f49Smrg      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
25932001f49Smrg   }
26032001f49Smrg
26132001f49Smrg   /* setup second texture object */
26232001f49Smrg   {
26332001f49Smrg      GLubyte image[4][4][3];
26432001f49Smrg      GLint i, j;
26532001f49Smrg      glBindTexture(GL_TEXTURE_2D, Textures[2]);
26632001f49Smrg
26732001f49Smrg      /* blue/gray checkerboard */
26832001f49Smrg      for (i = 0; i < 4; i++) {
26932001f49Smrg         for (j = 0; j < 4; j++) {
27032001f49Smrg            if ((i ^ j) & 1) {
27132001f49Smrg               image[i][j][0] = 0;
27232001f49Smrg               image[i][j][1] = 0;
27332001f49Smrg               image[i][j][2] = 255;
27432001f49Smrg            }
27532001f49Smrg            else {
27632001f49Smrg               image[i][j][0] = 200;
27732001f49Smrg               image[i][j][1] = 200;
27832001f49Smrg               image[i][j][2] = 200;
27932001f49Smrg            }
28032001f49Smrg         }
28132001f49Smrg      }
28232001f49Smrg
28332001f49Smrg      glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
28432001f49Smrg      glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 4, 4, 0, GL_RGB,
28532001f49Smrg                   GL_UNSIGNED_BYTE, image);
28632001f49Smrg      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
28732001f49Smrg      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
28832001f49Smrg   }
28932001f49Smrg
29032001f49Smrg   /* Now make the cube object display list */
29132001f49Smrg
29232001f49Smrg   printf("GL_RENDERER: %s\n", (char *) glGetString(GL_RENDERER));
29332001f49Smrg   printf("GL_VERSION: %s\n", (char *) glGetString(GL_VERSION));
29432001f49Smrg   printf("GL_VENDOR: %s\n", (char *) glGetString(GL_VENDOR));
29532001f49Smrg}
29632001f49Smrg
29732001f49Smrgstatic void
29832001f49SmrgRedraw(struct window *h)
29932001f49Smrg{
30032001f49Smrg   pthread_mutex_lock(&h->drawMutex);
30132001f49Smrg   if (!glXMakeCurrent(h->Dpy, h->Win, h->Context)) {
30232001f49Smrg      Error(h->DisplayName, "glXMakeCurrent failed in Redraw");
30332001f49Smrg      pthread_mutex_unlock(&h->drawMutex);
30432001f49Smrg      return;
30532001f49Smrg   }
30632001f49Smrg
30732001f49Smrg   h->Angle += 1.0;
30832001f49Smrg
30932001f49Smrg   glShadeModel(GL_FLAT);
31032001f49Smrg   glClearColor(0.25, 0.25, 0.25, 1.0);
31132001f49Smrg   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
31232001f49Smrg
31332001f49Smrg   glEnable(GL_TEXTURE_2D);
31432001f49Smrg   glEnable(GL_DEPTH_TEST);
31532001f49Smrg   glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
31632001f49Smrg
31732001f49Smrg   glColor3f(1, 1, 1);
31832001f49Smrg
31932001f49Smrg   glPushMatrix();
32032001f49Smrg   if (h->Id == 0)
32132001f49Smrg      glRotatef(h->Angle, 0, 1, -1);
32232001f49Smrg   else if (h->Id == 1)
32332001f49Smrg      glRotatef(-(h->Angle), 0, 1, -1);
32432001f49Smrg   else if (h->Id == 2)
32532001f49Smrg      glRotatef(h->Angle, 0, 1, 1);
32632001f49Smrg   else if (h->Id == 3)
32732001f49Smrg      glRotatef(-(h->Angle), 0, 1, 1);
32832001f49Smrg   glBindTexture(GL_TEXTURE_2D, Textures[0]);
32932001f49Smrg   glBegin(GL_POLYGON);
33032001f49Smrg   glTexCoord2f(0, 0);  glVertex3f(-1, -1, -1);
33132001f49Smrg   glTexCoord2f(1, 0);  glVertex3f(-1,  1, -1);
33232001f49Smrg   glTexCoord2f(1, 1);  glVertex3f(-1,  1,  1);
33332001f49Smrg   glTexCoord2f(0, 1);  glVertex3f(-1, -1,  1);
33432001f49Smrg   glEnd();
33532001f49Smrg   glBegin(GL_POLYGON);
33632001f49Smrg   glTexCoord2f(0, 0);  glVertex3f(1, -1, -1);
33732001f49Smrg   glTexCoord2f(1, 0);  glVertex3f(1,  1, -1);
33832001f49Smrg   glTexCoord2f(1, 1);  glVertex3f(1,  1,  1);
33932001f49Smrg   glTexCoord2f(0, 1);  glVertex3f(1, -1,  1);
34032001f49Smrg   glEnd();
34132001f49Smrg
34232001f49Smrg   glBindTexture(GL_TEXTURE_2D, Textures[1]);
34332001f49Smrg   glBegin(GL_POLYGON);
34432001f49Smrg   glTexCoord2f(0, 0);  glVertex3f(-1, -1, -1);
34532001f49Smrg   glTexCoord2f(1, 0);  glVertex3f( 1, -1, -1);
34632001f49Smrg   glTexCoord2f(1, 1);  glVertex3f( 1, -1,  1);
34732001f49Smrg   glTexCoord2f(0, 1);  glVertex3f(-1, -1,  1);
34832001f49Smrg   glEnd();
34932001f49Smrg   glBegin(GL_POLYGON);
35032001f49Smrg   glTexCoord2f(0, 0);  glVertex3f(-1, 1, -1);
35132001f49Smrg   glTexCoord2f(1, 0);  glVertex3f( 1, 1, -1);
35232001f49Smrg   glTexCoord2f(1, 1);  glVertex3f( 1, 1,  1);
35332001f49Smrg   glTexCoord2f(0, 1);  glVertex3f(-1, 1,  1);
35432001f49Smrg   glEnd();
35532001f49Smrg
35632001f49Smrg   glBindTexture(GL_TEXTURE_2D, Textures[2]);
35732001f49Smrg   glBegin(GL_POLYGON);
35832001f49Smrg   glTexCoord2f(0, 0);  glVertex3f(-1, -1, -1);
35932001f49Smrg   glTexCoord2f(1, 0);  glVertex3f( 1, -1, -1);
36032001f49Smrg   glTexCoord2f(1, 1);  glVertex3f( 1,  1, -1);
36132001f49Smrg   glTexCoord2f(0, 1);  glVertex3f(-1,  1, -1);
36232001f49Smrg   glEnd();
36332001f49Smrg   glBegin(GL_POLYGON);
36432001f49Smrg   glTexCoord2f(0, 0);  glVertex3f(-1, -1, 1);
36532001f49Smrg   glTexCoord2f(1, 0);  glVertex3f( 1, -1, 1);
36632001f49Smrg   glTexCoord2f(1, 1);  glVertex3f( 1,  1, 1);
36732001f49Smrg   glTexCoord2f(0, 1);  glVertex3f(-1,  1, 1);
36832001f49Smrg   glEnd();
36932001f49Smrg
37032001f49Smrg   glPopMatrix();
37132001f49Smrg
37232001f49Smrg   glXSwapBuffers(h->Dpy, h->Win);
37332001f49Smrg
37432001f49Smrg   if (!glXMakeCurrent(h->Dpy, None, NULL)) {
37532001f49Smrg      Error(h->DisplayName, "glXMakeCurrent failed in Redraw");
37632001f49Smrg   }
37732001f49Smrg   pthread_mutex_unlock(&h->drawMutex);
37832001f49Smrg}
37932001f49Smrg
38032001f49Smrgstatic void *threadRunner (void *arg)
38132001f49Smrg{
38232001f49Smrg   struct thread_init_arg *tia = (struct thread_init_arg *) arg;
38332001f49Smrg   struct window *win;
38432001f49Smrg
38532001f49Smrg   win = &Windows[tia->id];
38632001f49Smrg
38732001f49Smrg   while(!terminate) {
38832001f49Smrg      usleep(1000);
38932001f49Smrg      Redraw(win);
39032001f49Smrg   }
39132001f49Smrg
39232001f49Smrg   return NULL;
39332001f49Smrg}
39432001f49Smrg
39532001f49Smrgstatic void
39632001f49SmrgResize(struct window *h, unsigned int width, unsigned int height)
39732001f49Smrg{
39832001f49Smrg   pthread_mutex_lock(&h->drawMutex);
39932001f49Smrg
40032001f49Smrg   if (!glXMakeCurrent(h->Dpy, h->Win, h->Context)) {
40132001f49Smrg      Error(h->DisplayName, "glXMakeCurrent failed in Resize()");
40232001f49Smrg      pthread_mutex_unlock(&h->drawMutex);
40332001f49Smrg      return;
40432001f49Smrg   }
40532001f49Smrg
40632001f49Smrg   glViewport(0, 0, width, height);
40732001f49Smrg   glMatrixMode(GL_PROJECTION);
40832001f49Smrg   glLoadIdentity();
40932001f49Smrg   glFrustum(-1, 1, -1, 1, 2, 10);
41032001f49Smrg   glMatrixMode(GL_MODELVIEW);
41132001f49Smrg   glLoadIdentity();
41232001f49Smrg   glTranslatef(0, 0, -4.5);
41332001f49Smrg   if (!glXMakeCurrent(h->Dpy, None, NULL)) {
41432001f49Smrg      Error(h->DisplayName, "glXMakeCurrent failed in Resize()");
41532001f49Smrg   }
41632001f49Smrg   pthread_mutex_unlock(&h->drawMutex);
41732001f49Smrg}
41832001f49Smrg
41932001f49Smrg
42032001f49Smrgstatic void
42132001f49SmrgEventLoop(void)
42232001f49Smrg{
42332001f49Smrg   while (1) {
42432001f49Smrg      int i;
42532001f49Smrg      XEvent event;
4267ec3b29aSmrg
4277ec3b29aSmrg      /* Do we have an event? */
4287ec3b29aSmrg      if (XPending(gDpy) == 0) {
4297ec3b29aSmrg         usleep(10000);
4307ec3b29aSmrg         continue;
4317ec3b29aSmrg      }
4327ec3b29aSmrg
43332001f49Smrg      XNextEvent(gDpy, &event);
43432001f49Smrg      for (i = 0; i < NumWindows; i++) {
43532001f49Smrg	 struct window *h = &Windows[i];
43632001f49Smrg	 if (event.xany.window == h->Win) {
43732001f49Smrg	    switch (event.type) {
43832001f49Smrg	    case Expose:
43932001f49Smrg	       Redraw(h);
44032001f49Smrg	       break;
44132001f49Smrg	    case ConfigureNotify:
44232001f49Smrg	       Resize(h, event.xconfigure.width, event.xconfigure.height);
44332001f49Smrg	       break;
44432001f49Smrg	    case KeyPress:
44532001f49Smrg	       terminate = 1;
44632001f49Smrg	       return;
44732001f49Smrg	    default:
44832001f49Smrg	       /*no-op*/ ;
44932001f49Smrg	    }
45032001f49Smrg	 }
45132001f49Smrg      }
45232001f49Smrg   }
45332001f49Smrg}
45432001f49Smrg
45532001f49Smrgint
45632001f49Smrgmain(int argc, char *argv[])
45732001f49Smrg{
45832001f49Smrg   const char *dpyName = XDisplayName(NULL);
45932001f49Smrg   pthread_t t0, t1, t2, t3;
46032001f49Smrg   struct thread_init_arg tia0, tia1, tia2, tia3;
46132001f49Smrg   struct window *h0;
46232001f49Smrg
46332001f49Smrg   XInitThreads();
46432001f49Smrg
46532001f49Smrg   gDpy = XOpenDisplay(dpyName);
46632001f49Smrg   if (!gDpy) {
46732001f49Smrg      Error(dpyName, "Unable to open display");
46832001f49Smrg      return -1;
46932001f49Smrg   }
47032001f49Smrg
47132001f49Smrg   if (initMainthread(gDpy, dpyName))
47232001f49Smrg      return -1;
47332001f49Smrg
47432001f49Smrg   /* four windows and contexts sharing display lists and texture objects */
47532001f49Smrg   h0 = AddWindow(gDpy, dpyName,  10,  10, gCtx);
47632001f49Smrg   (void) AddWindow(gDpy, dpyName, 330,  10, gCtx);
47732001f49Smrg   (void) AddWindow(gDpy, dpyName,  10, 350, gCtx);
47832001f49Smrg   (void) AddWindow(gDpy, dpyName, 330, 350, gCtx);
47932001f49Smrg
48032001f49Smrg   if (!glXMakeCurrent(gDpy, h0->Win, gCtx)) {
48132001f49Smrg      Error(dpyName, "glXMakeCurrent failed for init thread.");
48232001f49Smrg      return -1;
48332001f49Smrg   }
48432001f49Smrg
48532001f49Smrg   InitGLstuff();
48632001f49Smrg
48732001f49Smrg   tia0.id = 0;
48832001f49Smrg   pthread_create(&t0, NULL, threadRunner, &tia0);
48932001f49Smrg   tia1.id = 1;
49032001f49Smrg   pthread_create(&t1, NULL, threadRunner, &tia1);
49132001f49Smrg   tia2.id = 2;
49232001f49Smrg   pthread_create(&t2, NULL, threadRunner, &tia2);
49332001f49Smrg   tia3.id = 3;
49432001f49Smrg   pthread_create(&t3, NULL, threadRunner, &tia3);
49532001f49Smrg   EventLoop();
49632001f49Smrg   return 0;
49732001f49Smrg}
498