1 /* $Id: sharedtex.c,v 1.2 2002/01/16 14:32:46 joukj Exp $ */
2 
3 /*
4  * Test sharing of display lists and texture objects between GLX contests.
5  * Brian Paul
6  * Summer 2000
7  *
8  *
9  * Copyright (C) 2000  Brian Paul   All Rights Reserved.
10  *
11  * Permission is hereby granted, free of charge, to any person obtaining a
12  * copy of this software and associated documentation files (the "Software"),
13  * to deal in the Software without restriction, including without limitation
14  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15  * and/or sell copies of the Software, and to permit persons to whom the
16  * Software is furnished to do so, subject to the following conditions:
17  *
18  * The above copyright notice and this permission notice shall be included
19  * in all copies or substantial portions of the Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
24  * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
25  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
26  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27  *
28  *
29  * Modified 2009 for multithreading by Thomas Hellstrom.
30  */
31 
32 
33 #include <GL/gl.h>
34 #include <GL/glx.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <unistd.h>
38 #include <string.h>
39 #include <pthread.h>
40 #include <X11/X.h>
41 
42 struct thread_init_arg {
43    int id;
44 };
45 
46 struct window {
47    pthread_mutex_t drawMutex;
48    char DisplayName[1000];
49    Display *Dpy;
50    Window Win;
51    GLXContext Context;
52    float Angle;
53    int Id;
54    XVisualInfo *visInfo;
55 };
56 
57 
58 #define MAX_WINDOWS 20
59 static struct window Windows[MAX_WINDOWS];
60 static int NumWindows = 0;
61 static int terminate = 0;
62 static GLXContext gCtx;
63 static Display *gDpy;
64 static GLuint Textures[3];
65 
66 
67 
68 static void
Error(const char * display,const char * msg)69 Error(const char *display, const char *msg)
70 {
71    fprintf(stderr, "Error on display %s - %s\n", display, msg);
72    exit(1);
73 }
74 
75 
76 static int
initMainthread(Display * dpy,const char * displayName)77 initMainthread(Display *dpy, const char *displayName)
78 {
79    int scrnum;
80    XVisualInfo *visinfo;
81    int attrib[] = { GLX_RGBA,
82                     GLX_RED_SIZE, 1,
83                     GLX_GREEN_SIZE, 1,
84                     GLX_BLUE_SIZE, 1,
85                     GLX_DOUBLEBUFFER,
86                     GLX_DEPTH_SIZE, 1,
87                     None };
88 
89    scrnum = DefaultScreen(dpy);
90    visinfo = glXChooseVisual(dpy, scrnum, attrib);
91    if (!visinfo) {
92       Error(displayName, "Unable to find RGB, double-buffered visual");
93       return -1;
94    }
95    gCtx = glXCreateContext(dpy, visinfo, NULL, True);
96    if (!gCtx) {
97       Error(displayName, "Couldn't create GLX context");
98       return -1;
99    }
100    return 0;
101 }
102 
103 static struct window *
AddWindow(Display * dpy,const char * displayName,int xpos,int ypos,GLXContext sCtx)104 AddWindow(Display *dpy, const char *displayName, int xpos, int ypos,
105           GLXContext sCtx)
106 {
107    Window win;
108    GLXContext ctx;
109    int attrib[] = { GLX_RGBA,
110                     GLX_RED_SIZE, 1,
111                     GLX_GREEN_SIZE, 1,
112                     GLX_BLUE_SIZE, 1,
113                     GLX_DOUBLEBUFFER,
114                     GLX_DEPTH_SIZE, 1,
115                     None };
116    int scrnum;
117    XSetWindowAttributes attr;
118    unsigned long mask;
119    Window root;
120    XVisualInfo *visinfo;
121    int width = 300, height = 300;
122 
123    if (NumWindows >= MAX_WINDOWS)
124       return NULL;
125 
126    scrnum = DefaultScreen(dpy);
127    root = RootWindow(dpy, scrnum);
128 
129    visinfo = glXChooseVisual(dpy, scrnum, attrib);
130    if (!visinfo) {
131       Error(displayName, "Unable to find RGB, double-buffered visual");
132       return NULL;
133    }
134 
135    /* window attributes */
136    attr.background_pixel = 0;
137    attr.border_pixel = 0;
138    attr.colormap = XCreateColormap(dpy, root, visinfo->visual, AllocNone);
139    attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
140    mask = CWBorderPixel | CWColormap | CWEventMask;
141 
142    win = XCreateWindow(dpy, root, xpos, ypos, width, height,
143                        0, visinfo->depth, InputOutput,
144                        visinfo->visual, mask, &attr);
145    if (!win) {
146       Error(displayName, "Couldn't create window");
147       return NULL;
148    }
149 
150    {
151       XSizeHints sizehints;
152       sizehints.x = xpos;
153       sizehints.y = ypos;
154       sizehints.width  = width;
155       sizehints.height = height;
156       sizehints.flags = USSize | USPosition;
157       XSetNormalHints(dpy, win, &sizehints);
158       XSetStandardProperties(dpy, win, displayName, displayName,
159                              None, (char **)NULL, 0, &sizehints);
160    }
161 
162 
163    ctx = glXCreateContext(dpy, visinfo,
164                           sCtx ? sCtx : NULL, True);
165 
166    if (!ctx) {
167       Error(displayName, "Couldn't create GLX context");
168       return NULL;
169    }
170 
171    XMapWindow(dpy, win);
172 
173    /* save the info for this window */
174    {
175       static int id = 0;
176       struct window *h = &Windows[NumWindows];
177       if (strlen(displayName) + 1 > sizeof(h->DisplayName)) {
178          Error(displayName, "string overflow");
179          return NULL;
180       }
181       strcpy(h->DisplayName, displayName);
182       h->Dpy = dpy;
183       h->Win = win;
184       h->Context = ctx;
185       h->Angle = 0.0;
186       h->Id = id++;
187       h->visInfo = visinfo;
188       pthread_mutex_init(&h->drawMutex, NULL);
189       NumWindows++;
190       return &Windows[NumWindows-1];
191    }
192 }
193 
194 
195 static void
InitGLstuff(void)196 InitGLstuff(void)
197 
198 {
199    glGenTextures(3, Textures);
200 
201    /* setup first texture object */
202    {
203       GLubyte image[16][16][4];
204       GLint i, j;
205       glBindTexture(GL_TEXTURE_2D, Textures[0]);
206 
207       /* red/white checkerboard */
208       for (i = 0; i < 16; i++) {
209          for (j = 0; j < 16; j++) {
210             if ((i ^ j) & 1) {
211                image[i][j][0] = 255;
212                image[i][j][1] = 255;
213                image[i][j][2] = 255;
214                image[i][j][3] = 255;
215             }
216             else {
217                image[i][j][0] = 255;
218                image[i][j][1] = 0;
219                image[i][j][2] = 0;
220                image[i][j][3] = 255;
221             }
222          }
223       }
224 
225       glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
226       glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA,
227                    GL_UNSIGNED_BYTE, image);
228       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
229       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
230    }
231 
232    /* setup second texture object */
233    {
234       GLubyte image[8][8][3];
235       GLint i, j;
236       glBindTexture(GL_TEXTURE_2D, Textures[1]);
237 
238       /* green/yellow checkerboard */
239       for (i = 0; i < 8; i++) {
240          for (j = 0; j < 8; j++) {
241             if ((i ^ j) & 1) {
242                image[i][j][0] = 0;
243                image[i][j][1] = 255;
244                image[i][j][2] = 0;
245             }
246             else {
247                image[i][j][0] = 255;
248                image[i][j][1] = 255;
249                image[i][j][2] = 0;
250             }
251          }
252       }
253 
254       glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
255       glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 8, 8, 0, GL_RGB,
256                    GL_UNSIGNED_BYTE, image);
257       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
258       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
259    }
260 
261    /* setup second texture object */
262    {
263       GLubyte image[4][4][3];
264       GLint i, j;
265       glBindTexture(GL_TEXTURE_2D, Textures[2]);
266 
267       /* blue/gray checkerboard */
268       for (i = 0; i < 4; i++) {
269          for (j = 0; j < 4; j++) {
270             if ((i ^ j) & 1) {
271                image[i][j][0] = 0;
272                image[i][j][1] = 0;
273                image[i][j][2] = 255;
274             }
275             else {
276                image[i][j][0] = 200;
277                image[i][j][1] = 200;
278                image[i][j][2] = 200;
279             }
280          }
281       }
282 
283       glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
284       glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 4, 4, 0, GL_RGB,
285                    GL_UNSIGNED_BYTE, image);
286       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
287       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
288    }
289 
290    /* Now make the cube object display list */
291 
292    printf("GL_RENDERER: %s\n", (char *) glGetString(GL_RENDERER));
293    printf("GL_VERSION: %s\n", (char *) glGetString(GL_VERSION));
294    printf("GL_VENDOR: %s\n", (char *) glGetString(GL_VENDOR));
295 }
296 
297 static void
Redraw(struct window * h)298 Redraw(struct window *h)
299 {
300    pthread_mutex_lock(&h->drawMutex);
301    if (!glXMakeCurrent(h->Dpy, h->Win, h->Context)) {
302       Error(h->DisplayName, "glXMakeCurrent failed in Redraw");
303       pthread_mutex_unlock(&h->drawMutex);
304       return;
305    }
306 
307    h->Angle += 1.0;
308 
309    glShadeModel(GL_FLAT);
310    glClearColor(0.25, 0.25, 0.25, 1.0);
311    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
312 
313    glEnable(GL_TEXTURE_2D);
314    glEnable(GL_DEPTH_TEST);
315    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
316 
317    glColor3f(1, 1, 1);
318 
319    glPushMatrix();
320    if (h->Id == 0)
321       glRotatef(h->Angle, 0, 1, -1);
322    else if (h->Id == 1)
323       glRotatef(-(h->Angle), 0, 1, -1);
324    else if (h->Id == 2)
325       glRotatef(h->Angle, 0, 1, 1);
326    else if (h->Id == 3)
327       glRotatef(-(h->Angle), 0, 1, 1);
328    glBindTexture(GL_TEXTURE_2D, Textures[0]);
329    glBegin(GL_POLYGON);
330    glTexCoord2f(0, 0);  glVertex3f(-1, -1, -1);
331    glTexCoord2f(1, 0);  glVertex3f(-1,  1, -1);
332    glTexCoord2f(1, 1);  glVertex3f(-1,  1,  1);
333    glTexCoord2f(0, 1);  glVertex3f(-1, -1,  1);
334    glEnd();
335    glBegin(GL_POLYGON);
336    glTexCoord2f(0, 0);  glVertex3f(1, -1, -1);
337    glTexCoord2f(1, 0);  glVertex3f(1,  1, -1);
338    glTexCoord2f(1, 1);  glVertex3f(1,  1,  1);
339    glTexCoord2f(0, 1);  glVertex3f(1, -1,  1);
340    glEnd();
341 
342    glBindTexture(GL_TEXTURE_2D, Textures[1]);
343    glBegin(GL_POLYGON);
344    glTexCoord2f(0, 0);  glVertex3f(-1, -1, -1);
345    glTexCoord2f(1, 0);  glVertex3f( 1, -1, -1);
346    glTexCoord2f(1, 1);  glVertex3f( 1, -1,  1);
347    glTexCoord2f(0, 1);  glVertex3f(-1, -1,  1);
348    glEnd();
349    glBegin(GL_POLYGON);
350    glTexCoord2f(0, 0);  glVertex3f(-1, 1, -1);
351    glTexCoord2f(1, 0);  glVertex3f( 1, 1, -1);
352    glTexCoord2f(1, 1);  glVertex3f( 1, 1,  1);
353    glTexCoord2f(0, 1);  glVertex3f(-1, 1,  1);
354    glEnd();
355 
356    glBindTexture(GL_TEXTURE_2D, Textures[2]);
357    glBegin(GL_POLYGON);
358    glTexCoord2f(0, 0);  glVertex3f(-1, -1, -1);
359    glTexCoord2f(1, 0);  glVertex3f( 1, -1, -1);
360    glTexCoord2f(1, 1);  glVertex3f( 1,  1, -1);
361    glTexCoord2f(0, 1);  glVertex3f(-1,  1, -1);
362    glEnd();
363    glBegin(GL_POLYGON);
364    glTexCoord2f(0, 0);  glVertex3f(-1, -1, 1);
365    glTexCoord2f(1, 0);  glVertex3f( 1, -1, 1);
366    glTexCoord2f(1, 1);  glVertex3f( 1,  1, 1);
367    glTexCoord2f(0, 1);  glVertex3f(-1,  1, 1);
368    glEnd();
369 
370    glPopMatrix();
371 
372    glXSwapBuffers(h->Dpy, h->Win);
373 
374    if (!glXMakeCurrent(h->Dpy, None, NULL)) {
375       Error(h->DisplayName, "glXMakeCurrent failed in Redraw");
376    }
377    pthread_mutex_unlock(&h->drawMutex);
378 }
379 
threadRunner(void * arg)380 static void *threadRunner (void *arg)
381 {
382    struct thread_init_arg *tia = (struct thread_init_arg *) arg;
383    struct window *win;
384 
385    win = &Windows[tia->id];
386 
387    while(!terminate) {
388       usleep(1000);
389       Redraw(win);
390    }
391 
392    return NULL;
393 }
394 
395 static void
Resize(struct window * h,unsigned int width,unsigned int height)396 Resize(struct window *h, unsigned int width, unsigned int height)
397 {
398    pthread_mutex_lock(&h->drawMutex);
399 
400    if (!glXMakeCurrent(h->Dpy, h->Win, h->Context)) {
401       Error(h->DisplayName, "glXMakeCurrent failed in Resize()");
402       pthread_mutex_unlock(&h->drawMutex);
403       return;
404    }
405 
406    glViewport(0, 0, width, height);
407    glMatrixMode(GL_PROJECTION);
408    glLoadIdentity();
409    glFrustum(-1, 1, -1, 1, 2, 10);
410    glMatrixMode(GL_MODELVIEW);
411    glLoadIdentity();
412    glTranslatef(0, 0, -4.5);
413    if (!glXMakeCurrent(h->Dpy, None, NULL)) {
414       Error(h->DisplayName, "glXMakeCurrent failed in Resize()");
415    }
416    pthread_mutex_unlock(&h->drawMutex);
417 }
418 
419 
420 static void
EventLoop(void)421 EventLoop(void)
422 {
423    while (1) {
424       int i;
425       XEvent event;
426 
427       /* Do we have an event? */
428       if (XPending(gDpy) == 0) {
429          usleep(10000);
430          continue;
431       }
432 
433       XNextEvent(gDpy, &event);
434       for (i = 0; i < NumWindows; i++) {
435          struct window *h = &Windows[i];
436          if (event.xany.window == h->Win) {
437             switch (event.type) {
438             case Expose:
439                Redraw(h);
440                break;
441             case ConfigureNotify:
442                Resize(h, event.xconfigure.width, event.xconfigure.height);
443                break;
444             case KeyPress:
445                terminate = 1;
446                return;
447             default:
448                /*no-op*/ ;
449             }
450          }
451       }
452    }
453 }
454 
455 int
main(int argc,char * argv[])456 main(int argc, char *argv[])
457 {
458    const char *dpyName = XDisplayName(NULL);
459    pthread_t t0, t1, t2, t3;
460    struct thread_init_arg tia0, tia1, tia2, tia3;
461    struct window *h0;
462 
463    XInitThreads();
464 
465    gDpy = XOpenDisplay(dpyName);
466    if (!gDpy) {
467       Error(dpyName, "Unable to open display");
468       return -1;
469    }
470 
471    if (initMainthread(gDpy, dpyName))
472       return -1;
473 
474    /* four windows and contexts sharing display lists and texture objects */
475    h0 = AddWindow(gDpy, dpyName,  10,  10, gCtx);
476    (void) AddWindow(gDpy, dpyName, 330,  10, gCtx);
477    (void) AddWindow(gDpy, dpyName,  10, 350, gCtx);
478    (void) AddWindow(gDpy, dpyName, 330, 350, gCtx);
479 
480    if (!glXMakeCurrent(gDpy, h0->Win, gCtx)) {
481       Error(dpyName, "glXMakeCurrent failed for init thread.");
482       return -1;
483    }
484 
485    InitGLstuff();
486 
487    tia0.id = 0;
488    pthread_create(&t0, NULL, threadRunner, &tia0);
489    tia1.id = 1;
490    pthread_create(&t1, NULL, threadRunner, &tia1);
491    tia2.id = 2;
492    pthread_create(&t2, NULL, threadRunner, &tia2);
493    tia3.id = 3;
494    pthread_create(&t3, NULL, threadRunner, &tia3);
495    EventLoop();
496    return 0;
497 }
498