wglgears: add srgb-mode to usage
[mesa-demos.git] / src / wgl / wglthreads.c
blob95a648d04dacee6abcf2bece3c6f4e5b21f361cf
1 /*
2 * Copyright (C) 2000 Brian Paul All Rights Reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included
12 * in all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 * Port to windows done by Michal Krol.
27 * This program tests WGL thread safety.
28 * Command line options:
29 * -h Print usage
30 * -l Enable application-side locking
31 * -n <num threads> Number of threads to create (default is 2)
32 * -t Use texture mapping
33 * -s Force single-threaded.
35 * Brian Paul 20 July 2000
40 * Notes:
41 * - Each thread gets its own WGL context.
43 * - The WGL contexts share texture objects.
45 * - When 't' is pressed to update the texture image, the window/thread which
46 * has input focus is signalled to change the texture. The other threads
47 * should see the updated texture the next time they call glBindTexture.
51 #include <assert.h>
52 #include <windows.h>
53 #include <GL/gl.h>
54 #include <math.h>
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <string.h>
61 * Each window/thread/context:
63 struct winthread {
64 int Index;
65 HANDLE Thread;
66 HWND Win;
67 HDC hDC;
68 HGLRC Context;
69 float Angle;
70 int WinWidth, WinHeight;
71 GLboolean NewSize;
72 HANDLE hEventInitialised;
73 GLboolean Initialized;
74 GLboolean MakeNewTexture;
75 HANDLE hEventRedraw;
79 #define MAX_WINTHREADS 128
80 static struct winthread WinThreads[MAX_WINTHREADS];
81 static int NumWinThreads = 2;
82 static HANDLE ExitEvent = NULL;
84 static GLboolean Locking = 0;
85 static GLboolean Texture = GL_FALSE;
86 static GLboolean SingleThreaded = GL_FALSE;
87 static GLuint TexObj = 12;
88 static GLboolean Animate = GL_TRUE;
90 static CRITICAL_SECTION Mutex;
93 static void
94 Error(const char *msg)
96 fprintf(stderr, "Error: %s\n", msg);
97 exit(1);
101 static void
102 signal_redraw(void)
104 int i;
106 for (i = 0; i < NumWinThreads; i++) {
107 SetEvent(WinThreads[i].hEventRedraw);
112 static void
113 MakeNewTexture(struct winthread *wt)
115 #define TEX_SIZE 128
116 static float step = 0.0f;
117 GLfloat image[TEX_SIZE][TEX_SIZE][4];
118 GLint width;
119 int i, j;
121 for (j = 0; j < TEX_SIZE; j++) {
122 for (i = 0; i < TEX_SIZE; i++) {
123 float dt = 5.0f * (j - 0.5f * TEX_SIZE) / TEX_SIZE;
124 float ds = 5.0f * (i - 0.5f * TEX_SIZE) / TEX_SIZE;
125 float r = dt * dt + ds * ds + step;
126 image[j][i][0] =
127 image[j][i][1] =
128 image[j][i][2] = 0.75f + 0.25f * (float) cos(r);
129 image[j][i][3] = 1.0f;
133 step += 0.5;
135 glBindTexture(GL_TEXTURE_2D, TexObj);
137 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
138 if (width) {
139 assert(width == TEX_SIZE);
140 /* sub-tex replace */
141 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, TEX_SIZE, TEX_SIZE,
142 GL_RGBA, GL_FLOAT, image);
144 else {
145 /* create new */
146 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
147 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
149 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TEX_SIZE, TEX_SIZE, 0,
150 GL_RGBA, GL_FLOAT, image);
156 /* draw a colored cube */
157 static void
158 draw_object(void)
160 glPushMatrix();
161 glScalef(0.75f, 0.75f, 0.75f);
163 glColor3f(1, 0, 0);
165 if (Texture) {
166 glBindTexture(GL_TEXTURE_2D, TexObj);
167 glEnable(GL_TEXTURE_2D);
169 else {
170 glDisable(GL_TEXTURE_2D);
173 glBegin(GL_QUADS);
175 /* -X */
176 glColor3f(0, 1, 1);
177 glTexCoord2f(0, 0); glVertex3f(-1, -1, -1);
178 glTexCoord2f(1, 0); glVertex3f(-1, 1, -1);
179 glTexCoord2f(1, 1); glVertex3f(-1, 1, 1);
180 glTexCoord2f(0, 1); glVertex3f(-1, -1, 1);
182 /* +X */
183 glColor3f(1, 0, 0);
184 glTexCoord2f(0, 0); glVertex3f(1, -1, -1);
185 glTexCoord2f(1, 0); glVertex3f(1, 1, -1);
186 glTexCoord2f(1, 1); glVertex3f(1, 1, 1);
187 glTexCoord2f(0, 1); glVertex3f(1, -1, 1);
189 /* -Y */
190 glColor3f(1, 0, 1);
191 glTexCoord2f(0, 0); glVertex3f(-1, -1, -1);
192 glTexCoord2f(1, 0); glVertex3f( 1, -1, -1);
193 glTexCoord2f(1, 1); glVertex3f( 1, -1, 1);
194 glTexCoord2f(0, 1); glVertex3f(-1, -1, 1);
196 /* +Y */
197 glColor3f(0, 1, 0);
198 glTexCoord2f(0, 0); glVertex3f(-1, 1, -1);
199 glTexCoord2f(1, 0); glVertex3f( 1, 1, -1);
200 glTexCoord2f(1, 1); glVertex3f( 1, 1, 1);
201 glTexCoord2f(0, 1); glVertex3f(-1, 1, 1);
203 /* -Z */
204 glColor3f(1, 1, 0);
205 glTexCoord2f(0, 0); glVertex3f(-1, -1, -1);
206 glTexCoord2f(1, 0); glVertex3f( 1, -1, -1);
207 glTexCoord2f(1, 1); glVertex3f( 1, 1, -1);
208 glTexCoord2f(0, 1); glVertex3f(-1, 1, -1);
210 /* +Y */
211 glColor3f(0, 0, 1);
212 glTexCoord2f(0, 0); glVertex3f(-1, -1, 1);
213 glTexCoord2f(1, 0); glVertex3f( 1, -1, 1);
214 glTexCoord2f(1, 1); glVertex3f( 1, 1, 1);
215 glTexCoord2f(0, 1); glVertex3f(-1, 1, 1);
217 glEnd();
219 glPopMatrix();
223 /* signal resize of given window */
224 static void
225 resize(struct winthread *wt, int w, int h)
227 wt->NewSize = GL_TRUE;
228 wt->WinWidth = w;
229 wt->WinHeight = h;
230 if (!Animate)
231 SetEvent(wt->hEventRedraw);
236 * We have an instance of this for each thread.
238 static void
239 draw_loop(struct winthread *wt)
241 while (1) {
242 GLboolean draw = Animate;
243 MSG msg;
245 if (Animate) {
246 /* wait 5 ms for signal either to exit or process messages */
247 switch (MsgWaitForMultipleObjects(1, &ExitEvent, FALSE, 5, QS_ALLINPUT)) {
248 case WAIT_OBJECT_0:
249 SendMessage(wt->Win, WM_CLOSE, 0, 0);
250 break;
251 case WAIT_OBJECT_0 + 1:
252 break;
255 else {
256 HANDLE events[2];
258 events[0] = wt->hEventRedraw;
259 events[1] = ExitEvent;
261 /* wait for signal either to draw, exit or process messages */
262 switch (MsgWaitForMultipleObjects(2, events, FALSE, INFINITE, QS_ALLINPUT)) {
263 case WAIT_OBJECT_0:
264 draw = GL_TRUE;
265 break;
266 case WAIT_OBJECT_0 + 1:
267 SendMessage(wt->Win, WM_CLOSE, 0, 0);
268 break;
269 case WAIT_OBJECT_0 + 2:
270 break;
274 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
275 if (msg.message == WM_QUIT) {
276 return;
278 TranslateMessage(&msg);
279 DispatchMessage(&msg);
282 if (!draw)
283 continue;
285 if (Locking)
286 EnterCriticalSection(&Mutex);
288 wglMakeCurrent(wt->hDC, wt->Context);
290 if (!wt->Initialized) {
291 printf("wglthreads: %d: GL_RENDERER = %s\n", wt->Index,
292 (char *) glGetString(GL_RENDERER));
293 if (Texture /*&& wt->Index == 0*/) {
294 MakeNewTexture(wt);
296 wt->Initialized = GL_TRUE;
299 if (Locking)
300 LeaveCriticalSection(&Mutex);
302 glEnable(GL_DEPTH_TEST);
304 if (wt->NewSize) {
305 GLfloat w = (float) wt->WinWidth / (float) wt->WinHeight;
306 glViewport(0, 0, wt->WinWidth, wt->WinHeight);
307 glMatrixMode(GL_PROJECTION);
308 glLoadIdentity();
309 glFrustum(-w, w, -1.0, 1.0, 1.5, 10);
310 glMatrixMode(GL_MODELVIEW);
311 glLoadIdentity();
312 glTranslatef(0, 0, -2.5);
313 wt->NewSize = GL_FALSE;
316 if (wt->MakeNewTexture) {
317 MakeNewTexture(wt);
318 wt->MakeNewTexture = GL_FALSE;
321 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
323 glPushMatrix();
324 glRotatef(wt->Angle, 0, 1, 0);
325 glRotatef(wt->Angle, 1, 0, 0);
326 glScalef(0.7f, 0.7f, 0.7f);
327 draw_object();
328 glPopMatrix();
330 if (Locking)
331 EnterCriticalSection(&Mutex);
333 SwapBuffers(wt->hDC);
335 if (Locking)
336 LeaveCriticalSection(&Mutex);
338 wt->Angle += 1.0;
343 static void
344 keypress(WPARAM keySym, struct winthread *wt)
346 switch (keySym) {
347 case VK_ESCAPE:
348 /* tell all threads to exit */
349 SetEvent(ExitEvent);
350 /*printf("exit draw_loop %d\n", wt->Index);*/
351 return;
352 case 't':
353 case 'T':
354 if (Texture) {
355 wt->MakeNewTexture = GL_TRUE;
356 if (!Animate)
357 signal_redraw();
359 break;
360 case 'a':
361 case 'A':
362 Animate = !Animate;
363 if (Animate)
364 signal_redraw();
365 break;
366 case 's':
367 case 'S':
368 if (!Animate)
369 signal_redraw();
370 break;
371 default:
372 ; /* nop */
377 static LRESULT CALLBACK
378 WndProc(HWND hWnd,
379 UINT uMsg,
380 WPARAM wParam,
381 LPARAM lParam )
383 struct winthread *wt = (struct winthread *)(INT_PTR)GetWindowLongPtr(hWnd, GWLP_USERDATA);
385 switch (uMsg) {
386 case WM_KEYDOWN:
387 keypress(wParam, wt);
388 break;
389 case WM_SIZE:
391 RECT r;
392 GetClientRect(hWnd, &r);
393 resize(wt, r.right, r.bottom);
395 break;
396 case WM_DESTROY:
397 PostQuitMessage(0);
398 break;
399 default:
400 return DefWindowProc(hWnd, uMsg, wParam, lParam);
403 return 0;
407 * we'll call this once for each thread, before the threads are created.
409 static void
410 create_window(struct winthread *wt, HGLRC shareCtx)
412 WNDCLASS wc = {0};
413 int width = 160, height = 160;
414 int xpos = (wt->Index % 8) * (width + 10);
415 int ypos = (wt->Index / 8) * (width + 20);
416 HWND win;
417 HDC hdc;
418 PIXELFORMATDESCRIPTOR pfd;
419 int visinfo;
420 HGLRC ctx;
422 wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
423 wc.hCursor = LoadCursor(NULL, IDC_ARROW);
424 wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
425 wc.lpfnWndProc = WndProc;
426 wc.lpszClassName = "wglthreads";
427 wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
428 RegisterClass(&wc);
430 win = CreateWindowEx(0,
431 wc.lpszClassName,
432 "wglthreads",
433 WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TILEDWINDOW,
434 xpos,
435 ypos,
436 width,
437 height,
438 NULL,
439 NULL,
440 wc.hInstance,
441 (LPVOID) wt);
442 if (!win) {
443 Error("Couldn't create window");
446 SetWindowLongPtr(win, GWLP_USERDATA, (LONG_PTR)wt);
448 hdc = GetDC(win);
449 if (!hdc) {
450 Error("Couldn't obtain HDC");
453 memset(&pfd, 0, sizeof(pfd));
454 pfd.cColorBits = 24;
455 pfd.cDepthBits = 24;
456 pfd.dwFlags = PFD_DOUBLEBUFFER | PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
457 pfd.iLayerType = PFD_MAIN_PLANE;
458 pfd.iPixelType = PFD_TYPE_RGBA;
459 pfd.nSize = sizeof(pfd);
460 pfd.nVersion = 1;
462 visinfo = ChoosePixelFormat(hdc, &pfd);
463 if (!visinfo) {
464 Error("Unable to find RGB, Z, double-buffered visual");
467 SetPixelFormat(hdc, visinfo, &pfd);
468 ctx = wglCreateContext(hdc);
469 if (!ctx) {
470 Error("Couldn't create WGL context");
473 if (shareCtx) {
474 if(!wglShareLists(shareCtx, ctx))
475 Error("Couldn't share WGL context lists");
478 /* save the info for this window/context */
479 wt->Win = win;
480 wt->hDC = hdc;
481 wt->Context = ctx;
482 wt->Angle = 0.0;
483 wt->WinWidth = width;
484 wt->WinHeight = height;
485 wt->NewSize = GL_TRUE;
490 * Called by pthread_create()
492 static DWORD WINAPI
493 ThreadProc(void *p)
495 struct winthread *wt = (struct winthread *) p;
496 HGLRC share;
498 /* Wait for the previous thread */
499 if(Texture && wt->Index > 0) {
500 WaitForSingleObject(WinThreads[wt->Index - 1].hEventInitialised, INFINITE);
501 share = WinThreads[0].Context;
503 else
504 share = 0;
506 share = (Texture && wt->Index > 0) ? WinThreads[0].Context : 0;
507 create_window(wt, share);
508 SetEvent(wt->hEventInitialised);
510 /* Wait for all threads to initialize otherwise wglShareLists will fail */
511 if(wt->Index < NumWinThreads - 1)
512 WaitForSingleObject(WinThreads[NumWinThreads - 1].hEventInitialised, INFINITE);
514 draw_loop(wt);
515 return 0;
519 static void
520 usage(void)
522 printf("wglthreads: test of GL thread safety (any key = exit)\n");
523 printf("Usage:\n");
524 printf(" wglthreads [options]\n");
525 printf("Options:\n");
526 printf(" -h Show this usage screen\n");
527 printf(" -n NUMTHREADS Number of threads to create\n");
528 printf(" -l Use application-side locking\n");
529 printf(" -t Enable texturing\n");
530 printf(" -s Force single-threaded\n");
531 printf("Keyboard:\n");
532 printf(" Esc Exit\n");
533 printf(" t Change texture image (requires -t option)\n");
534 printf(" a Toggle animation\n");
535 printf(" s Step rotation (when not animating)\n");
540 main(int argc, char *argv[])
542 int i;
544 for (i = 1; i < argc; i++) {
545 if (strcmp(argv[i], "-h") == 0) {
546 usage();
547 exit(0);
549 else if (strcmp(argv[i], "-l") == 0) {
550 Locking = 1;
552 else if (strcmp(argv[i], "-t") == 0) {
553 Texture = 1;
555 else if (strcmp(argv[i], "-n") == 0 && i + 1 < argc) {
556 NumWinThreads = atoi(argv[i + 1]);
557 if (NumWinThreads < 1)
558 NumWinThreads = 1;
559 else if (NumWinThreads > MAX_WINTHREADS)
560 NumWinThreads = MAX_WINTHREADS;
561 i++;
563 else if (strcmp(argv[i], "-s") == 0) {
564 SingleThreaded = GL_TRUE;
566 else {
567 usage();
568 exit(1);
572 if (SingleThreaded)
573 printf("wglthreads: Forcing single-threaded, no other threads will be created.\n");
575 if (Locking)
576 printf("wglthreads: Using explicit locks around WGL calls.\n");
577 else
578 printf("wglthreads: No explict locking.\n");
580 InitializeCriticalSection(&Mutex);
581 ExitEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
583 if (SingleThreaded) {
584 NumWinThreads = 1;
586 WinThreads[0].Index = 0;
587 WinThreads[0].hEventInitialised = CreateEvent(NULL, TRUE, FALSE, NULL);
588 WinThreads[0].hEventRedraw = CreateEvent(NULL, FALSE, FALSE, NULL);
590 ThreadProc((void*) &WinThreads[0]);
592 else {
593 HANDLE threads[MAX_WINTHREADS];
595 printf("wglthreads: creating threads\n");
597 /* Create the events */
598 for (i = 0; i < NumWinThreads; i++) {
599 WinThreads[i].Index = i;
600 WinThreads[i].hEventInitialised = CreateEvent(NULL, TRUE, FALSE, NULL);
601 WinThreads[i].hEventRedraw = CreateEvent(NULL, FALSE, FALSE, NULL);
604 /* Create the threads */
605 for (i = 0; i < NumWinThreads; i++) {
606 DWORD id;
608 WinThreads[i].Thread = CreateThread(NULL,
610 ThreadProc,
611 (void*) &WinThreads[i],
613 &id);
614 printf("wglthreads: Created thread %p\n", (void *) WinThreads[i].Thread);
616 threads[i] = WinThreads[i].Thread;
619 /* Wait for all threads to finish. */
620 WaitForMultipleObjects(NumWinThreads, threads, TRUE, INFINITE);
623 return 0;