sharedtex_mt.c revision 32001f49
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
39#pragma comment(lib, "opengl32.lib")
40
41struct thread_init_arg {
42   int id;
43};
44
45struct window {
46   CRITICAL_SECTION drawMutex;
47   HDC hDC;
48   HWND Win;
49   HGLRC Context;
50   float Angle;
51   int Id;
52   HGLRC sharedContext;
53   HANDLE hEventInitialised;
54};
55
56
57#define MAX_WINDOWS 20
58static struct window Windows[MAX_WINDOWS];
59static int NumWindows = 0;
60static HANDLE terminate = NULL;
61static HGLRC gCtx = NULL;
62static HDC gHDC = NULL;
63static GLuint Textures[3];
64
65
66
67static void
68Error(const char *msg)
69{
70   fprintf(stderr, "Error - %s\n", msg);
71   exit(1);
72}
73
74static void
75Resize(struct window *h, unsigned int width, unsigned int height);
76
77static LRESULT CALLBACK
78WndProc(HWND hWnd,
79        UINT uMsg,
80        WPARAM wParam,
81        LPARAM lParam )
82{
83   switch (uMsg) {
84   case WM_KEYDOWN:
85      SetEvent(terminate);
86      break;
87   case WM_SIZE:
88      {
89         LONG_PTR index = GetWindowLongPtr(hWnd, GWLP_USERDATA);
90
91         if (index >= 0 && index < MAX_WINDOWS) {
92            RECT r;
93
94            GetClientRect(hWnd, &r);
95            Resize(&Windows[index], r.right, r.bottom);
96         }
97      }
98      break;
99   case WM_CREATE:
100      {
101         CREATESTRUCT *pcs = (CREATESTRUCT *) lParam;
102
103         SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) pcs->lpCreateParams);
104      }
105      break;
106   case WM_DESTROY:
107      PostQuitMessage(0);
108      break;
109   default:
110      return DefWindowProc(hWnd, uMsg, wParam, lParam);
111   }
112
113   return 0;
114}
115
116static int
117initMainthread(void)
118{
119   WNDCLASS wc = {0};
120   HWND win;
121   PIXELFORMATDESCRIPTOR pfd = {0};
122   int visinfo;
123
124   wc.lpfnWndProc = WndProc;
125   wc.lpszClassName = "sharedtex_mt.hidden";
126   wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
127   RegisterClass(&wc);
128
129   win = CreateWindowEx(0,
130                        wc.lpszClassName,
131                        "sharedtex_mt.hidden",
132                        WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
133                        CW_USEDEFAULT,
134                        CW_USEDEFAULT,
135                        CW_USEDEFAULT,
136                        CW_USEDEFAULT,
137                        NULL,
138                        NULL,
139                        wc.hInstance,
140                        (LPVOID) -1);
141   if (!win) {
142      Error("Couldn't create window");
143   }
144
145   gHDC = GetDC(win);
146   if (!gHDC) {
147      Error("Couldn't obtain HDC");
148   }
149
150   pfd.cColorBits = 24;
151   pfd.cDepthBits = 24;
152   pfd.dwFlags = PFD_DOUBLEBUFFER | PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
153   pfd.iLayerType = PFD_MAIN_PLANE;
154   pfd.iPixelType = PFD_TYPE_RGBA;
155   pfd.nSize = sizeof(pfd);
156   pfd.nVersion = 1;
157
158   visinfo = ChoosePixelFormat(gHDC, &pfd);
159   if (!visinfo) {
160      Error("Unable to find RGB, Z, double-buffered visual");
161   }
162
163   SetPixelFormat(gHDC, visinfo, &pfd);
164   gCtx = wglCreateContext(gHDC);
165   if (!gCtx) {
166      Error("Couldn't create WGL context");
167   }
168
169   return 0;
170}
171
172static struct window *
173AddWindow(int xpos, int ypos, HGLRC sCtx)
174{
175   struct window *win = &Windows[NumWindows];
176   WNDCLASS wc = {0};
177   int width = 300, height = 300;
178
179   if (NumWindows >= MAX_WINDOWS)
180      return NULL;
181
182   memset(win, 0, sizeof(*win));
183   InitializeCriticalSection(&win->drawMutex);
184   win->Angle = 0.0;
185   win->Id = NumWindows++;
186
187   wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
188   wc.hCursor = LoadCursor(NULL, IDC_ARROW);
189   wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
190   wc.lpfnWndProc = WndProc;
191   wc.lpszClassName = "sharedtex_mt";
192   wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
193   RegisterClass(&wc);
194
195   win->Win = CreateWindowEx(0,
196                             wc.lpszClassName,
197                             "sharedtex_mt",
198                             WS_SIZEBOX | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
199                             xpos,
200                             ypos,
201                             width,
202                             height,
203                             NULL,
204                             NULL,
205                             wc.hInstance,
206                             (LPVOID) win->Id);
207   if (!win->Win) {
208      Error("Couldn't create window");
209   }
210
211   win->sharedContext = sCtx;
212
213   ShowWindow(win->Win, SW_SHOW);
214
215   return win;
216}
217
218
219static void
220InitGLstuff(void)
221{
222   glGenTextures(3, Textures);
223
224   /* setup first texture object */
225   {
226      GLubyte image[16][16][4];
227      GLint i, j;
228      glBindTexture(GL_TEXTURE_2D, Textures[0]);
229
230      /* red/white checkerboard */
231      for (i = 0; i < 16; i++) {
232         for (j = 0; j < 16; j++) {
233            if ((i ^ j) & 1) {
234               image[i][j][0] = 255;
235               image[i][j][1] = 255;
236               image[i][j][2] = 255;
237               image[i][j][3] = 255;
238            }
239            else {
240               image[i][j][0] = 255;
241               image[i][j][1] = 0;
242               image[i][j][2] = 0;
243               image[i][j][3] = 255;
244            }
245         }
246      }
247
248      glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
249      glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA,
250                   GL_UNSIGNED_BYTE, image);
251      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
252      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
253   }
254
255   /* setup second texture object */
256   {
257      GLubyte image[8][8][3];
258      GLint i, j;
259      glBindTexture(GL_TEXTURE_2D, Textures[1]);
260
261      /* green/yellow checkerboard */
262      for (i = 0; i < 8; i++) {
263         for (j = 0; j < 8; j++) {
264            if ((i ^ j) & 1) {
265               image[i][j][0] = 0;
266               image[i][j][1] = 255;
267               image[i][j][2] = 0;
268            }
269            else {
270               image[i][j][0] = 255;
271               image[i][j][1] = 255;
272               image[i][j][2] = 0;
273            }
274         }
275      }
276
277      glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
278      glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 8, 8, 0, GL_RGB,
279                   GL_UNSIGNED_BYTE, image);
280      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
281      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
282   }
283
284   /* setup second texture object */
285   {
286      GLubyte image[4][4][3];
287      GLint i, j;
288      glBindTexture(GL_TEXTURE_2D, Textures[2]);
289
290      /* blue/gray checkerboard */
291      for (i = 0; i < 4; i++) {
292         for (j = 0; j < 4; j++) {
293            if ((i ^ j) & 1) {
294               image[i][j][0] = 0;
295               image[i][j][1] = 0;
296               image[i][j][2] = 255;
297            }
298            else {
299               image[i][j][0] = 200;
300               image[i][j][1] = 200;
301               image[i][j][2] = 200;
302            }
303         }
304      }
305
306      glPixelStorei(GL_UNPACK_ALIGNMENT, 2);
307      glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 4, 4, 0, GL_RGB,
308                   GL_UNSIGNED_BYTE, image);
309      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
310      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
311   }
312
313   /* Now make the cube object display list */
314
315   printf("GL_RENDERER: %s\n", (char *) glGetString(GL_RENDERER));
316   printf("GL_VERSION: %s\n", (char *) glGetString(GL_VERSION));
317   printf("GL_VENDOR: %s\n", (char *) glGetString(GL_VENDOR));
318}
319
320static void
321Redraw(struct window *h)
322{
323   EnterCriticalSection(&h->drawMutex);
324   if (!wglMakeCurrent(h->hDC, h->Context)) {
325      LeaveCriticalSection(&h->drawMutex);
326      Error("wglMakeCurrent failed in Redraw");
327      return;
328   }
329
330   h->Angle += 1.0;
331
332   glShadeModel(GL_FLAT);
333   glClearColor(0.25, 0.25, 0.25, 1.0);
334   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
335
336   glEnable(GL_TEXTURE_2D);
337   glEnable(GL_DEPTH_TEST);
338   glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
339
340   glColor3f(1, 1, 1);
341
342   glPushMatrix();
343   if (h->Id == 0)
344      glRotatef(h->Angle, 0, 1, -1);
345   else if (h->Id == 1)
346      glRotatef(-(h->Angle), 0, 1, -1);
347   else if (h->Id == 2)
348      glRotatef(h->Angle, 0, 1, 1);
349   else if (h->Id == 3)
350      glRotatef(-(h->Angle), 0, 1, 1);
351   glBindTexture(GL_TEXTURE_2D, Textures[0]);
352   glBegin(GL_POLYGON);
353   glTexCoord2f(0, 0);  glVertex3f(-1, -1, -1);
354   glTexCoord2f(1, 0);  glVertex3f(-1,  1, -1);
355   glTexCoord2f(1, 1);  glVertex3f(-1,  1,  1);
356   glTexCoord2f(0, 1);  glVertex3f(-1, -1,  1);
357   glEnd();
358   glBegin(GL_POLYGON);
359   glTexCoord2f(0, 0);  glVertex3f(1, -1, -1);
360   glTexCoord2f(1, 0);  glVertex3f(1,  1, -1);
361   glTexCoord2f(1, 1);  glVertex3f(1,  1,  1);
362   glTexCoord2f(0, 1);  glVertex3f(1, -1,  1);
363   glEnd();
364
365   glBindTexture(GL_TEXTURE_2D, Textures[1]);
366   glBegin(GL_POLYGON);
367   glTexCoord2f(0, 0);  glVertex3f(-1, -1, -1);
368   glTexCoord2f(1, 0);  glVertex3f( 1, -1, -1);
369   glTexCoord2f(1, 1);  glVertex3f( 1, -1,  1);
370   glTexCoord2f(0, 1);  glVertex3f(-1, -1,  1);
371   glEnd();
372   glBegin(GL_POLYGON);
373   glTexCoord2f(0, 0);  glVertex3f(-1, 1, -1);
374   glTexCoord2f(1, 0);  glVertex3f( 1, 1, -1);
375   glTexCoord2f(1, 1);  glVertex3f( 1, 1,  1);
376   glTexCoord2f(0, 1);  glVertex3f(-1, 1,  1);
377   glEnd();
378
379   glBindTexture(GL_TEXTURE_2D, Textures[2]);
380   glBegin(GL_POLYGON);
381   glTexCoord2f(0, 0);  glVertex3f(-1, -1, -1);
382   glTexCoord2f(1, 0);  glVertex3f( 1, -1, -1);
383   glTexCoord2f(1, 1);  glVertex3f( 1,  1, -1);
384   glTexCoord2f(0, 1);  glVertex3f(-1,  1, -1);
385   glEnd();
386   glBegin(GL_POLYGON);
387   glTexCoord2f(0, 0);  glVertex3f(-1, -1, 1);
388   glTexCoord2f(1, 0);  glVertex3f( 1, -1, 1);
389   glTexCoord2f(1, 1);  glVertex3f( 1,  1, 1);
390   glTexCoord2f(0, 1);  glVertex3f(-1,  1, 1);
391   glEnd();
392
393   glPopMatrix();
394
395   SwapBuffers(h->hDC);
396
397   if (!wglMakeCurrent(NULL, NULL)) {
398      Error("wglMakeCurrent failed in Redraw");
399   }
400   LeaveCriticalSection(&h->drawMutex);
401}
402
403static DWORD WINAPI
404threadRunner (void *arg)
405{
406   struct thread_init_arg *tia = (struct thread_init_arg *) arg;
407   struct window *win;
408   PIXELFORMATDESCRIPTOR pfd = {0};
409   int visinfo;
410
411   win = &Windows[tia->id];
412
413   win->hDC = GetDC(win->Win);
414   if (!win->hDC) {
415      Error("Couldn't obtain HDC");
416   }
417
418   /* Wait for the previous thread */
419   if(tia->id > 0)
420      WaitForSingleObject(Windows[tia->id - 1].hEventInitialised, INFINITE);
421
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   struct window *h[MAX_WINDOWS];
512   HANDLE threads[MAX_WINDOWS];
513   int i;
514
515   terminate = CreateEvent(NULL, TRUE, FALSE, NULL);
516
517   if (initMainthread())
518      return -1;
519
520   /* four windows and contexts sharing display lists and texture objects */
521   h[0] = AddWindow( 10,  10, gCtx);
522   h[1] = AddWindow(330,  10, gCtx);
523   h[2] = AddWindow( 10, 350, gCtx);
524   h[3] = AddWindow(330, 350, gCtx);
525
526   for (i = 0; i < NumWindows; i++) {
527      Windows[i].hEventInitialised = CreateEvent(NULL, TRUE, FALSE, NULL);
528   }
529
530   for (i = 0; i < NumWindows; i++) {
531      DWORD id;
532
533      tia[i].id = i;
534      threads[i] = CreateThread(NULL, 0, threadRunner, &tia[i], 0, &id);
535
536      WaitForSingleObject(Windows[i].hEventInitialised, INFINITE);
537   }
538
539   if (!wglMakeCurrent(gHDC, gCtx)) {
540      Error("wglMakeCurrent failed for init thread.");
541      return -1;
542   }
543
544   InitGLstuff();
545
546   while (1) {
547      MSG msg;
548
549      /* wait 1 ms for signal either to exit or process messages */
550      switch (MsgWaitForMultipleObjects(NumWindows, threads, TRUE, 1, QS_ALLINPUT)) {
551      case WAIT_OBJECT_0:
552         return 0;
553      }
554
555      while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
556         if (msg.message == WM_QUIT) {
557            return 0;
558         }
559         TranslateMessage(&msg);
560         DispatchMessage(&msg);
561      }
562   }
563
564   return 0;
565}
566