sharedtex_mt.c revision 7ec3b29a
1/*
2 * Test sharing of display lists and texture objects between GLX contests.
3 * Brian Paul
4 * Summer 2000
5 *
6 *
7 * Copyright (C) 2000  Brian Paul   All Rights Reserved.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 *
27 * Modified 2009 for multithreading by Thomas Hellstrom.
28 *
29 * Port to windows by Michal Krol.
30 */
31
32
33#include <windows.h>
34#include <GL/gl.h>
35#include <stdio.h>
36#include <stdlib.h>
37#include <string.h>
38
39struct thread_init_arg {
40   int id;
41};
42
43struct window {
44   CRITICAL_SECTION drawMutex;
45   HDC hDC;
46   HWND Win;
47   HGLRC Context;
48   float Angle;
49   int Id;
50   HGLRC sharedContext;
51   HANDLE hEventInitialised;
52};
53
54
55#define MAX_WINDOWS 20
56static struct window Windows[MAX_WINDOWS];
57static int NumWindows = 0;
58static HANDLE terminate = NULL;
59static HGLRC gCtx = NULL;
60static HDC gHDC = NULL;
61static GLuint Textures[3];
62
63
64
65static void
66Error(const char *msg)
67{
68   fprintf(stderr, "Error - %s\n", msg);
69   exit(1);
70}
71
72static void
73Resize(struct window *h, unsigned int width, unsigned int height);
74
75static LRESULT CALLBACK
76WndProc(HWND hWnd,
77        UINT uMsg,
78        WPARAM wParam,
79        LPARAM lParam )
80{
81   switch (uMsg) {
82   case WM_KEYDOWN:
83      SetEvent(terminate);
84      break;
85   case WM_SIZE:
86      {
87         LONG_PTR index = GetWindowLongPtr(hWnd, GWLP_USERDATA);
88
89         if (index >= 0 && index < MAX_WINDOWS) {
90            RECT r;
91
92            GetClientRect(hWnd, &r);
93            Resize(&Windows[index], r.right, r.bottom);
94         }
95      }
96      break;
97   case WM_CREATE:
98      {
99         CREATESTRUCT *pcs = (CREATESTRUCT *) lParam;
100
101         SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) pcs->lpCreateParams);
102      }
103      break;
104   case WM_DESTROY:
105      PostQuitMessage(0);
106      break;
107   default:
108      return DefWindowProc(hWnd, uMsg, wParam, lParam);
109   }
110
111   return 0;
112}
113
114static int
115initMainthread(void)
116{
117   WNDCLASS wc = {0};
118   HWND win;
119   PIXELFORMATDESCRIPTOR pfd;
120   int visinfo;
121
122   wc.lpfnWndProc = WndProc;
123   wc.lpszClassName = "sharedtex_mt.hidden";
124   wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
125   RegisterClass(&wc);
126
127   win = CreateWindowEx(0,
128                        wc.lpszClassName,
129                        "sharedtex_mt.hidden",
130                        WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
131                        CW_USEDEFAULT,
132                        CW_USEDEFAULT,
133                        CW_USEDEFAULT,
134                        CW_USEDEFAULT,
135                        NULL,
136                        NULL,
137                        wc.hInstance,
138                        (LPVOID) -1);
139   if (!win) {
140      Error("Couldn't create window");
141   }
142
143   gHDC = GetDC(win);
144   if (!gHDC) {
145      Error("Couldn't obtain HDC");
146   }
147
148   memset(&pfd, 0, sizeof(pfd));
149   pfd.cColorBits = 24;
150   pfd.cDepthBits = 24;
151   pfd.dwFlags = PFD_DOUBLEBUFFER | PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
152   pfd.iLayerType = PFD_MAIN_PLANE;
153   pfd.iPixelType = PFD_TYPE_RGBA;
154   pfd.nSize = sizeof(pfd);
155   pfd.nVersion = 1;
156
157   visinfo = ChoosePixelFormat(gHDC, &pfd);
158   if (!visinfo) {
159      Error("Unable to find RGB, Z, double-buffered visual");
160   }
161
162   SetPixelFormat(gHDC, visinfo, &pfd);
163   gCtx = wglCreateContext(gHDC);
164   if (!gCtx) {
165      Error("Couldn't create WGL context");
166   }
167
168   return 0;
169}
170
171static struct window *
172AddWindow(int xpos, int ypos, HGLRC sCtx)
173{
174   struct window *win = &Windows[NumWindows];
175   WNDCLASS wc = {0};
176   int width = 300, height = 300;
177
178   if (NumWindows >= MAX_WINDOWS)
179      return NULL;
180
181   memset(win, 0, sizeof(*win));
182   InitializeCriticalSection(&win->drawMutex);
183   win->Angle = 0.0;
184   win->Id = NumWindows++;
185
186   wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
187   wc.hCursor = LoadCursor(NULL, IDC_ARROW);
188   wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
189   wc.lpfnWndProc = WndProc;
190   wc.lpszClassName = "sharedtex_mt";
191   wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
192   RegisterClass(&wc);
193
194   win->Win = CreateWindowEx(0,
195                             wc.lpszClassName,
196                             "sharedtex_mt",
197                             WS_SIZEBOX | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
198                             xpos,
199                             ypos,
200                             width,
201                             height,
202                             NULL,
203                             NULL,
204                             wc.hInstance,
205                             (LPVOID) win->Id);
206   if (!win->Win) {
207      Error("Couldn't create window");
208   }
209
210   win->sharedContext = sCtx;
211
212   ShowWindow(win->Win, SW_SHOW);
213
214   return win;
215}
216
217
218static void
219InitGLstuff(void)
220{
221   glGenTextures(3, Textures);
222
223   /* setup first texture object */
224   {
225      GLubyte image[16][16][4];
226      GLint i, j;
227      glBindTexture(GL_TEXTURE_2D, Textures[0]);
228
229      /* red/white checkerboard */
230      for (i = 0; i < 16; i++) {
231         for (j = 0; j < 16; j++) {
232            if ((i ^ j) & 1) {
233               image[i][j][0] = 255;
234               image[i][j][1] = 255;
235               image[i][j][2] = 255;
236               image[i][j][3] = 255;
237            }
238            else {
239               image[i][j][0] = 255;
240               image[i][j][1] = 0;
241               image[i][j][2] = 0;
242               image[i][j][3] = 255;
243            }
244         }
245      }
246
247      glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
248      glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA,
249                   GL_UNSIGNED_BYTE, image);
250      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
251      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
252   }
253
254   /* setup second texture object */
255   {
256      GLubyte image[8][8][3];
257      GLint i, j;
258      glBindTexture(GL_TEXTURE_2D, Textures[1]);
259
260      /* green/yellow checkerboard */
261      for (i = 0; i < 8; i++) {
262         for (j = 0; j < 8; j++) {
263            if ((i ^ j) & 1) {
264               image[i][j][0] = 0;
265               image[i][j][1] = 255;
266               image[i][j][2] = 0;
267            }
268            else {
269               image[i][j][0] = 255;
270               image[i][j][1] = 255;
271               image[i][j][2] = 0;
272            }
273         }
274      }
275
276      glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
277      glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 8, 8, 0, GL_RGB,
278                   GL_UNSIGNED_BYTE, image);
279      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
280      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
281   }
282
283   /* setup second texture object */
284   {
285      GLubyte image[4][4][3];
286      GLint i, j;
287      glBindTexture(GL_TEXTURE_2D, Textures[2]);
288
289      /* blue/gray checkerboard */
290      for (i = 0; i < 4; i++) {
291         for (j = 0; j < 4; j++) {
292            if ((i ^ j) & 1) {
293               image[i][j][0] = 0;
294               image[i][j][1] = 0;
295               image[i][j][2] = 255;
296            }
297            else {
298               image[i][j][0] = 200;
299               image[i][j][1] = 200;
300               image[i][j][2] = 200;
301            }
302         }
303      }
304
305      glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
306      glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 4, 4, 0, GL_RGB,
307                   GL_UNSIGNED_BYTE, image);
308      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
309      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
310   }
311
312   /* Now make the cube object display list */
313
314   printf("GL_RENDERER: %s\n", (char *) glGetString(GL_RENDERER));
315   printf("GL_VERSION: %s\n", (char *) glGetString(GL_VERSION));
316   printf("GL_VENDOR: %s\n", (char *) glGetString(GL_VENDOR));
317}
318
319static void
320Redraw(struct window *h)
321{
322   EnterCriticalSection(&h->drawMutex);
323   if (!wglMakeCurrent(h->hDC, h->Context)) {
324      LeaveCriticalSection(&h->drawMutex);
325      Error("wglMakeCurrent failed in Redraw");
326      return;
327   }
328
329   h->Angle += 1.0;
330
331   glShadeModel(GL_FLAT);
332   glClearColor(0.25, 0.25, 0.25, 1.0);
333   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
334
335   glEnable(GL_TEXTURE_2D);
336   glEnable(GL_DEPTH_TEST);
337   glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
338
339   glColor3f(1, 1, 1);
340
341   glPushMatrix();
342   if (h->Id == 0)
343      glRotatef(h->Angle, 0, 1, -1);
344   else if (h->Id == 1)
345      glRotatef(-(h->Angle), 0, 1, -1);
346   else if (h->Id == 2)
347      glRotatef(h->Angle, 0, 1, 1);
348   else if (h->Id == 3)
349      glRotatef(-(h->Angle), 0, 1, 1);
350   glBindTexture(GL_TEXTURE_2D, Textures[0]);
351   glBegin(GL_POLYGON);
352   glTexCoord2f(0, 0);  glVertex3f(-1, -1, -1);
353   glTexCoord2f(1, 0);  glVertex3f(-1,  1, -1);
354   glTexCoord2f(1, 1);  glVertex3f(-1,  1,  1);
355   glTexCoord2f(0, 1);  glVertex3f(-1, -1,  1);
356   glEnd();
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
364   glBindTexture(GL_TEXTURE_2D, Textures[1]);
365   glBegin(GL_POLYGON);
366   glTexCoord2f(0, 0);  glVertex3f(-1, -1, -1);
367   glTexCoord2f(1, 0);  glVertex3f( 1, -1, -1);
368   glTexCoord2f(1, 1);  glVertex3f( 1, -1,  1);
369   glTexCoord2f(0, 1);  glVertex3f(-1, -1,  1);
370   glEnd();
371   glBegin(GL_POLYGON);
372   glTexCoord2f(0, 0);  glVertex3f(-1, 1, -1);
373   glTexCoord2f(1, 0);  glVertex3f( 1, 1, -1);
374   glTexCoord2f(1, 1);  glVertex3f( 1, 1,  1);
375   glTexCoord2f(0, 1);  glVertex3f(-1, 1,  1);
376   glEnd();
377
378   glBindTexture(GL_TEXTURE_2D, Textures[2]);
379   glBegin(GL_POLYGON);
380   glTexCoord2f(0, 0);  glVertex3f(-1, -1, -1);
381   glTexCoord2f(1, 0);  glVertex3f( 1, -1, -1);
382   glTexCoord2f(1, 1);  glVertex3f( 1,  1, -1);
383   glTexCoord2f(0, 1);  glVertex3f(-1,  1, -1);
384   glEnd();
385   glBegin(GL_POLYGON);
386   glTexCoord2f(0, 0);  glVertex3f(-1, -1, 1);
387   glTexCoord2f(1, 0);  glVertex3f( 1, -1, 1);
388   glTexCoord2f(1, 1);  glVertex3f( 1,  1, 1);
389   glTexCoord2f(0, 1);  glVertex3f(-1,  1, 1);
390   glEnd();
391
392   glPopMatrix();
393
394   SwapBuffers(h->hDC);
395
396   if (!wglMakeCurrent(NULL, NULL)) {
397      Error("wglMakeCurrent failed in Redraw");
398   }
399   LeaveCriticalSection(&h->drawMutex);
400}
401
402static DWORD WINAPI
403threadRunner (void *arg)
404{
405   struct thread_init_arg *tia = (struct thread_init_arg *) arg;
406   struct window *win;
407   PIXELFORMATDESCRIPTOR pfd;
408   int visinfo;
409
410   win = &Windows[tia->id];
411
412   win->hDC = GetDC(win->Win);
413   if (!win->hDC) {
414      Error("Couldn't obtain HDC");
415   }
416
417   /* Wait for the previous thread */
418   if(tia->id > 0)
419      WaitForSingleObject(Windows[tia->id - 1].hEventInitialised, INFINITE);
420
421   memset(&pfd, 0, sizeof(pfd));
422   pfd.cColorBits = 24;
423   pfd.cDepthBits = 24;
424   pfd.dwFlags = PFD_DOUBLEBUFFER | PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
425   pfd.iLayerType = PFD_MAIN_PLANE;
426   pfd.iPixelType = PFD_TYPE_RGBA;
427   pfd.nSize = sizeof(pfd);
428   pfd.nVersion = 1;
429
430   visinfo = ChoosePixelFormat(win->hDC, &pfd);
431   if (!visinfo) {
432      Error("Unable to find RGB, Z, double-buffered visual");
433   }
434
435   SetPixelFormat(win->hDC, visinfo, &pfd);
436   win->Context = wglCreateContext(win->hDC);
437   if (!win->Context) {
438      Error("Couldn't create WGL context");
439   }
440
441   if (win->sharedContext) {
442      if(!wglShareLists(win->sharedContext, win->Context))
443         Error("Couldn't share WGL context lists");
444   }
445
446   SetEvent(win->hEventInitialised);
447
448   /* Wait for all threads to initialize otherwise wglShareLists will fail */
449   if(tia->id < NumWindows - 1)
450      WaitForSingleObject(Windows[NumWindows - 1].hEventInitialised, INFINITE);
451
452   SendMessage(win->Win, WM_SIZE, 0, 0);
453
454   while (1) {
455      MSG msg;
456
457      /* wait 1 ms for signal either to exit or process messages */
458      switch (MsgWaitForMultipleObjects(1, &terminate, FALSE, 1, QS_ALLINPUT)) {
459      case WAIT_OBJECT_0:
460         SendMessage(win->Win, WM_CLOSE, 0, 0);
461         break;
462      case WAIT_OBJECT_0 + 1:
463         break;
464      }
465
466      while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
467         if (msg.message == WM_QUIT) {
468            return 0;
469         }
470         TranslateMessage(&msg);
471         DispatchMessage(&msg);
472      }
473
474      Redraw(win);
475   }
476
477   return 0;
478}
479
480static void
481Resize(struct window *h, unsigned int width, unsigned int height)
482{
483   if (!h->Context)
484      return;
485
486   EnterCriticalSection(&h->drawMutex);
487
488   if (!wglMakeCurrent(h->hDC, h->Context)) {
489      LeaveCriticalSection(&h->drawMutex);
490      Error("wglMakeCurrent failed in Resize()");
491      return;
492   }
493
494   glViewport(0, 0, width, height);
495   glMatrixMode(GL_PROJECTION);
496   glLoadIdentity();
497   glFrustum(-1, 1, -1, 1, 2, 10);
498   glMatrixMode(GL_MODELVIEW);
499   glLoadIdentity();
500   glTranslatef(0, 0, -4.5);
501   if (!wglMakeCurrent(NULL, NULL)) {
502      Error("wglMakeCurrent failed in Resize()");
503   }
504   LeaveCriticalSection(&h->drawMutex);
505}
506
507int
508main(int argc, char *argv[])
509{
510   struct thread_init_arg tia[MAX_WINDOWS];
511   HANDLE threads[MAX_WINDOWS];
512   int i;
513
514   terminate = CreateEvent(NULL, TRUE, FALSE, NULL);
515
516   if (initMainthread())
517      return -1;
518
519   /* four windows and contexts sharing display lists and texture objects */
520   AddWindow( 10,  10, gCtx);
521   AddWindow(330,  10, gCtx);
522   AddWindow( 10, 350, gCtx);
523   AddWindow(330, 350, gCtx);
524
525   for (i = 0; i < NumWindows; i++) {
526      Windows[i].hEventInitialised = CreateEvent(NULL, TRUE, FALSE, NULL);
527   }
528
529   for (i = 0; i < NumWindows; i++) {
530      DWORD id;
531
532      tia[i].id = i;
533      threads[i] = CreateThread(NULL, 0, threadRunner, &tia[i], 0, &id);
534
535      WaitForSingleObject(Windows[i].hEventInitialised, INFINITE);
536   }
537
538   if (!wglMakeCurrent(gHDC, gCtx)) {
539      Error("wglMakeCurrent failed for init thread.");
540      return -1;
541   }
542
543   InitGLstuff();
544
545   while (1) {
546      MSG msg;
547
548      /* wait 1 ms for signal either to exit or process messages */
549      switch (MsgWaitForMultipleObjects(NumWindows, threads, TRUE, 1, QS_ALLINPUT)) {
550      case WAIT_OBJECT_0:
551         return 0;
552      }
553
554      while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
555         if (msg.message == WM_QUIT) {
556            return 0;
557         }
558         TranslateMessage(&msg);
559         DispatchMessage(&msg);
560      }
561   }
562
563   return 0;
564}
565