1/* $Id: sharedtex_mt.c,v 1.1.1.2 2019/03/11 06:59:40 mrg 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 42struct thread_init_arg { 43 int id; 44}; 45 46struct 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 59static struct window Windows[MAX_WINDOWS]; 60static int NumWindows = 0; 61static int terminate = 0; 62static GLXContext gCtx; 63static Display *gDpy; 64static GLuint Textures[3]; 65 66 67 68static void 69Error(const char *display, const char *msg) 70{ 71 fprintf(stderr, "Error on display %s - %s\n", display, msg); 72 exit(1); 73} 74 75 76static int 77initMainthread(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 103static struct window * 104AddWindow(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 195static void 196InitGLstuff(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 297static void 298Redraw(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 380static 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 395static void 396Resize(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 420static void 421EventLoop(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 455int 456main(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