Clone of mesa.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

wglthreads.c 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636
  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:
  10. *
  11. * The above copyright notice and this permission notice shall be included
  12. * in all copies or substantial portions of the Software.
  13. *
  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.
  20. *
  21. *
  22. * Port to windows done by Michal Krol.
  23. */
  24. /*
  25. * This program tests WGL thread safety.
  26. * Command line options:
  27. * -h Print usage
  28. * -l Enable application-side locking
  29. * -n <num threads> Number of threads to create (default is 2)
  30. * -t Use texture mapping
  31. * -s Force single-threaded.
  32. *
  33. * Brian Paul 20 July 2000
  34. */
  35. /*
  36. * Notes:
  37. * - Each thread gets its own WGL context.
  38. *
  39. * - The WGL contexts share texture objects.
  40. *
  41. * - When 't' is pressed to update the texture image, the window/thread which
  42. * has input focus is signalled to change the texture. The other threads
  43. * should see the updated texture the next time they call glBindTexture.
  44. */
  45. #include <assert.h>
  46. #include <windows.h>
  47. #include <GL/gl.h>
  48. #include <math.h>
  49. #include <stdio.h>
  50. #include <stdlib.h>
  51. #include <string.h>
  52. #pragma comment(lib, "opengl32.lib")
  53. /*
  54. * Each window/thread/context:
  55. */
  56. struct winthread {
  57. int Index;
  58. HANDLE Thread;
  59. HWND Win;
  60. HDC hDC;
  61. HGLRC Context;
  62. float Angle;
  63. int WinWidth, WinHeight;
  64. GLboolean NewSize;
  65. HANDLE hEventInitialised;
  66. GLboolean Initialized;
  67. GLboolean MakeNewTexture;
  68. HANDLE hEventRedraw;
  69. };
  70. #define MAX_WINTHREADS 100
  71. static struct winthread WinThreads[MAX_WINTHREADS];
  72. static int NumWinThreads = 2;
  73. static HANDLE ExitEvent = NULL;
  74. static GLboolean Locking = 0;
  75. static GLboolean Texture = GL_FALSE;
  76. static GLboolean SingleThreaded = GL_FALSE;
  77. static GLuint TexObj = 12;
  78. static GLboolean Animate = GL_TRUE;
  79. static CRITICAL_SECTION Mutex;
  80. static void
  81. Error(const char *msg)
  82. {
  83. fprintf(stderr, "Error: %s\n", msg);
  84. exit(1);
  85. }
  86. static void
  87. signal_redraw(void)
  88. {
  89. int i;
  90. for (i = 0; i < NumWinThreads; i++) {
  91. SetEvent(WinThreads[i].hEventRedraw);
  92. }
  93. }
  94. static void
  95. MakeNewTexture(struct winthread *wt)
  96. {
  97. #define TEX_SIZE 128
  98. static float step = 0.0f;
  99. GLfloat image[TEX_SIZE][TEX_SIZE][4];
  100. GLint width;
  101. int i, j;
  102. for (j = 0; j < TEX_SIZE; j++) {
  103. for (i = 0; i < TEX_SIZE; i++) {
  104. float dt = 5.0f * (j - 0.5f * TEX_SIZE) / TEX_SIZE;
  105. float ds = 5.0f * (i - 0.5f * TEX_SIZE) / TEX_SIZE;
  106. float r = dt * dt + ds * ds + step;
  107. image[j][i][0] =
  108. image[j][i][1] =
  109. image[j][i][2] = 0.75f + 0.25f * (float) cos(r);
  110. image[j][i][3] = 1.0f;
  111. }
  112. }
  113. step += 0.5;
  114. glBindTexture(GL_TEXTURE_2D, TexObj);
  115. glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
  116. if (width) {
  117. assert(width == TEX_SIZE);
  118. /* sub-tex replace */
  119. glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, TEX_SIZE, TEX_SIZE,
  120. GL_RGBA, GL_FLOAT, image);
  121. }
  122. else {
  123. /* create new */
  124. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  125. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  126. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TEX_SIZE, TEX_SIZE, 0,
  127. GL_RGBA, GL_FLOAT, image);
  128. }
  129. }
  130. /* draw a colored cube */
  131. static void
  132. draw_object(void)
  133. {
  134. glPushMatrix();
  135. glScalef(0.75f, 0.75f, 0.75f);
  136. glColor3f(1, 0, 0);
  137. if (Texture) {
  138. glBindTexture(GL_TEXTURE_2D, TexObj);
  139. glEnable(GL_TEXTURE_2D);
  140. }
  141. else {
  142. glDisable(GL_TEXTURE_2D);
  143. }
  144. glBegin(GL_QUADS);
  145. /* -X */
  146. glColor3f(0, 1, 1);
  147. glTexCoord2f(0, 0); glVertex3f(-1, -1, -1);
  148. glTexCoord2f(1, 0); glVertex3f(-1, 1, -1);
  149. glTexCoord2f(1, 1); glVertex3f(-1, 1, 1);
  150. glTexCoord2f(0, 1); glVertex3f(-1, -1, 1);
  151. /* +X */
  152. glColor3f(1, 0, 0);
  153. glTexCoord2f(0, 0); glVertex3f(1, -1, -1);
  154. glTexCoord2f(1, 0); glVertex3f(1, 1, -1);
  155. glTexCoord2f(1, 1); glVertex3f(1, 1, 1);
  156. glTexCoord2f(0, 1); glVertex3f(1, -1, 1);
  157. /* -Y */
  158. glColor3f(1, 0, 1);
  159. glTexCoord2f(0, 0); glVertex3f(-1, -1, -1);
  160. glTexCoord2f(1, 0); glVertex3f( 1, -1, -1);
  161. glTexCoord2f(1, 1); glVertex3f( 1, -1, 1);
  162. glTexCoord2f(0, 1); glVertex3f(-1, -1, 1);
  163. /* +Y */
  164. glColor3f(0, 1, 0);
  165. glTexCoord2f(0, 0); glVertex3f(-1, 1, -1);
  166. glTexCoord2f(1, 0); glVertex3f( 1, 1, -1);
  167. glTexCoord2f(1, 1); glVertex3f( 1, 1, 1);
  168. glTexCoord2f(0, 1); glVertex3f(-1, 1, 1);
  169. /* -Z */
  170. glColor3f(1, 1, 0);
  171. glTexCoord2f(0, 0); glVertex3f(-1, -1, -1);
  172. glTexCoord2f(1, 0); glVertex3f( 1, -1, -1);
  173. glTexCoord2f(1, 1); glVertex3f( 1, 1, -1);
  174. glTexCoord2f(0, 1); glVertex3f(-1, 1, -1);
  175. /* +Y */
  176. glColor3f(0, 0, 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);
  181. glEnd();
  182. glPopMatrix();
  183. }
  184. /* signal resize of given window */
  185. static void
  186. resize(struct winthread *wt, int w, int h)
  187. {
  188. wt->NewSize = GL_TRUE;
  189. wt->WinWidth = w;
  190. wt->WinHeight = h;
  191. if (!Animate)
  192. SetEvent(wt->hEventRedraw);
  193. }
  194. /*
  195. * We have an instance of this for each thread.
  196. */
  197. static void
  198. draw_loop(struct winthread *wt)
  199. {
  200. while (1) {
  201. GLboolean draw = Animate;
  202. MSG msg;
  203. if (Animate) {
  204. /* wait 5 ms for signal either to exit or process messages */
  205. switch (MsgWaitForMultipleObjects(1, &ExitEvent, FALSE, 5, QS_ALLINPUT)) {
  206. case WAIT_OBJECT_0:
  207. SendMessage(wt->Win, WM_CLOSE, 0, 0);
  208. break;
  209. case WAIT_OBJECT_0 + 1:
  210. break;
  211. }
  212. }
  213. else {
  214. HANDLE events[2];
  215. events[0] = wt->hEventRedraw;
  216. events[1] = ExitEvent;
  217. /* wait for signal either to draw, exit or process messages */
  218. switch (MsgWaitForMultipleObjects(2, events, FALSE, INFINITE, QS_ALLINPUT)) {
  219. case WAIT_OBJECT_0:
  220. draw = GL_TRUE;
  221. break;
  222. case WAIT_OBJECT_0 + 1:
  223. SendMessage(wt->Win, WM_CLOSE, 0, 0);
  224. break;
  225. case WAIT_OBJECT_0 + 2:
  226. break;
  227. }
  228. }
  229. while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
  230. if (msg.message == WM_QUIT) {
  231. return;
  232. }
  233. TranslateMessage(&msg);
  234. DispatchMessage(&msg);
  235. }
  236. if (!draw)
  237. continue;
  238. if (Locking)
  239. EnterCriticalSection(&Mutex);
  240. wglMakeCurrent(wt->hDC, wt->Context);
  241. if (!wt->Initialized) {
  242. printf("wglthreads: %d: GL_RENDERER = %s\n", wt->Index,
  243. (char *) glGetString(GL_RENDERER));
  244. if (Texture /*&& wt->Index == 0*/) {
  245. MakeNewTexture(wt);
  246. }
  247. wt->Initialized = GL_TRUE;
  248. }
  249. if (Locking)
  250. LeaveCriticalSection(&Mutex);
  251. glEnable(GL_DEPTH_TEST);
  252. if (wt->NewSize) {
  253. GLfloat w = (float) wt->WinWidth / (float) wt->WinHeight;
  254. glViewport(0, 0, wt->WinWidth, wt->WinHeight);
  255. glMatrixMode(GL_PROJECTION);
  256. glLoadIdentity();
  257. glFrustum(-w, w, -1.0, 1.0, 1.5, 10);
  258. glMatrixMode(GL_MODELVIEW);
  259. glLoadIdentity();
  260. glTranslatef(0, 0, -2.5);
  261. wt->NewSize = GL_FALSE;
  262. }
  263. if (wt->MakeNewTexture) {
  264. MakeNewTexture(wt);
  265. wt->MakeNewTexture = GL_FALSE;
  266. }
  267. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  268. glPushMatrix();
  269. glRotatef(wt->Angle, 0, 1, 0);
  270. glRotatef(wt->Angle, 1, 0, 0);
  271. glScalef(0.7f, 0.7f, 0.7f);
  272. draw_object();
  273. glPopMatrix();
  274. if (Locking)
  275. EnterCriticalSection(&Mutex);
  276. SwapBuffers(wt->hDC);
  277. if (Locking)
  278. LeaveCriticalSection(&Mutex);
  279. wt->Angle += 1.0;
  280. }
  281. }
  282. static void
  283. keypress(WPARAM keySym, struct winthread *wt)
  284. {
  285. switch (keySym) {
  286. case VK_ESCAPE:
  287. /* tell all threads to exit */
  288. SetEvent(ExitEvent);
  289. /*printf("exit draw_loop %d\n", wt->Index);*/
  290. return;
  291. case 't':
  292. case 'T':
  293. if (Texture) {
  294. wt->MakeNewTexture = GL_TRUE;
  295. if (!Animate)
  296. signal_redraw();
  297. }
  298. break;
  299. case 'a':
  300. case 'A':
  301. Animate = !Animate;
  302. if (Animate)
  303. signal_redraw();
  304. break;
  305. case 's':
  306. case 'S':
  307. if (!Animate)
  308. signal_redraw();
  309. break;
  310. default:
  311. ; /* nop */
  312. }
  313. }
  314. static LRESULT CALLBACK
  315. WndProc(HWND hWnd,
  316. UINT uMsg,
  317. WPARAM wParam,
  318. LPARAM lParam )
  319. {
  320. int i;
  321. switch (uMsg) {
  322. case WM_KEYDOWN:
  323. for (i = 0; i < NumWinThreads; i++) {
  324. struct winthread *wt = &WinThreads[i];
  325. if (hWnd == wt->Win) {
  326. keypress(wParam, wt);
  327. break;
  328. }
  329. }
  330. break;
  331. case WM_SIZE:
  332. for (i = 0; i < NumWinThreads; i++) {
  333. struct winthread *wt = &WinThreads[i];
  334. if (hWnd == wt->Win) {
  335. RECT r;
  336. GetClientRect(hWnd, &r);
  337. resize(wt, r.right, r.bottom);
  338. break;
  339. }
  340. }
  341. break;
  342. case WM_DESTROY:
  343. PostQuitMessage(0);
  344. break;
  345. default:
  346. return DefWindowProc(hWnd, uMsg, wParam, lParam);
  347. }
  348. return 0;
  349. }
  350. /*
  351. * we'll call this once for each thread, before the threads are created.
  352. */
  353. static void
  354. create_window(struct winthread *wt, HGLRC shareCtx)
  355. {
  356. WNDCLASS wc = {0};
  357. int width = 160, height = 160;
  358. int xpos = (wt->Index % 8) * (width + 10);
  359. int ypos = (wt->Index / 8) * (width + 20);
  360. HWND win;
  361. HDC hdc;
  362. PIXELFORMATDESCRIPTOR pfd = {0};
  363. int visinfo;
  364. HGLRC ctx;
  365. wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
  366. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  367. wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  368. wc.lpfnWndProc = WndProc;
  369. wc.lpszClassName = "wglthreads";
  370. wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
  371. RegisterClass(&wc);
  372. win = CreateWindowEx(0,
  373. wc.lpszClassName,
  374. "wglthreads",
  375. WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_TILEDWINDOW,
  376. xpos,
  377. ypos,
  378. width,
  379. height,
  380. NULL,
  381. NULL,
  382. wc.hInstance,
  383. (LPVOID) wt);
  384. if (!win) {
  385. Error("Couldn't create window");
  386. }
  387. hdc = GetDC(win);
  388. if (!hdc) {
  389. Error("Couldn't obtain HDC");
  390. }
  391. pfd.cColorBits = 24;
  392. pfd.cDepthBits = 24;
  393. pfd.dwFlags = PFD_DOUBLEBUFFER | PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
  394. pfd.iLayerType = PFD_MAIN_PLANE;
  395. pfd.iPixelType = PFD_TYPE_RGBA;
  396. pfd.nSize = sizeof(pfd);
  397. pfd.nVersion = 1;
  398. visinfo = ChoosePixelFormat(hdc, &pfd);
  399. if (!visinfo) {
  400. Error("Unable to find RGB, Z, double-buffered visual");
  401. }
  402. SetPixelFormat(hdc, visinfo, &pfd);
  403. ctx = wglCreateContext(hdc);
  404. if (!ctx) {
  405. Error("Couldn't create WGL context");
  406. }
  407. if (shareCtx) {
  408. if(!wglShareLists(shareCtx, ctx))
  409. Error("Couldn't share WGL context lists");
  410. }
  411. /* save the info for this window/context */
  412. wt->Win = win;
  413. wt->hDC = hdc;
  414. wt->Context = ctx;
  415. wt->Angle = 0.0;
  416. wt->WinWidth = width;
  417. wt->WinHeight = height;
  418. wt->NewSize = GL_TRUE;
  419. }
  420. /*
  421. * Called by pthread_create()
  422. */
  423. static DWORD WINAPI
  424. ThreadProc(void *p)
  425. {
  426. struct winthread *wt = (struct winthread *) p;
  427. HGLRC share;
  428. /* Wait for the previous thread */
  429. if(Texture && wt->Index > 0) {
  430. WaitForSingleObject(WinThreads[wt->Index - 1].hEventInitialised, INFINITE);
  431. share = WinThreads[0].Context;
  432. }
  433. else
  434. share = 0;
  435. share = (Texture && wt->Index > 0) ? WinThreads[0].Context : 0;
  436. create_window(wt, share);
  437. SetEvent(wt->hEventInitialised);
  438. /* Wait for all threads to initialize otherwise wglShareLists will fail */
  439. if(wt->Index < NumWinThreads - 1)
  440. WaitForSingleObject(WinThreads[NumWinThreads - 1].hEventInitialised, INFINITE);
  441. draw_loop(wt);
  442. return 0;
  443. }
  444. static void
  445. usage(void)
  446. {
  447. printf("wglthreads: test of GL thread safety (any key = exit)\n");
  448. printf("Usage:\n");
  449. printf(" wglthreads [options]\n");
  450. printf("Options:\n");
  451. printf(" -h Show this usage screen\n");
  452. printf(" -n NUMTHREADS Number of threads to create\n");
  453. printf(" -l Use application-side locking\n");
  454. printf(" -t Enable texturing\n");
  455. printf(" -s Force single-threaded\n");
  456. printf("Keyboard:\n");
  457. printf(" Esc Exit\n");
  458. printf(" t Change texture image (requires -t option)\n");
  459. printf(" a Toggle animation\n");
  460. printf(" s Step rotation (when not animating)\n");
  461. }
  462. int
  463. main(int argc, char *argv[])
  464. {
  465. int i;
  466. for (i = 1; i < argc; i++) {
  467. if (strcmp(argv[i], "-h") == 0) {
  468. usage();
  469. exit(0);
  470. }
  471. else if (strcmp(argv[i], "-l") == 0) {
  472. Locking = 1;
  473. }
  474. else if (strcmp(argv[i], "-t") == 0) {
  475. Texture = 1;
  476. }
  477. else if (strcmp(argv[i], "-n") == 0 && i + 1 < argc) {
  478. NumWinThreads = atoi(argv[i + 1]);
  479. if (NumWinThreads < 1)
  480. NumWinThreads = 1;
  481. else if (NumWinThreads > MAX_WINTHREADS)
  482. NumWinThreads = MAX_WINTHREADS;
  483. i++;
  484. }
  485. else if (strcmp(argv[i], "-s") == 0) {
  486. SingleThreaded = GL_TRUE;
  487. }
  488. else {
  489. usage();
  490. exit(1);
  491. }
  492. }
  493. if (SingleThreaded)
  494. printf("wglthreads: Forcing single-threaded, no other threads will be created.\n");
  495. if (Locking)
  496. printf("wglthreads: Using explicit locks around WGL calls.\n");
  497. else
  498. printf("wglthreads: No explict locking.\n");
  499. InitializeCriticalSection(&Mutex);
  500. ExitEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  501. if (SingleThreaded) {
  502. NumWinThreads = 1;
  503. WinThreads[0].Index = 0;
  504. WinThreads[0].hEventInitialised = CreateEvent(NULL, TRUE, FALSE, NULL);
  505. WinThreads[0].hEventRedraw = CreateEvent(NULL, FALSE, FALSE, NULL);
  506. ThreadProc((void*) &WinThreads[0]);
  507. }
  508. else {
  509. HANDLE threads[MAX_WINTHREADS];
  510. printf("wglthreads: creating threads\n");
  511. /* Create the events */
  512. for (i = 0; i < NumWinThreads; i++) {
  513. WinThreads[i].Index = i;
  514. WinThreads[i].hEventInitialised = CreateEvent(NULL, TRUE, FALSE, NULL);
  515. WinThreads[i].hEventRedraw = CreateEvent(NULL, FALSE, FALSE, NULL);
  516. }
  517. /* Create the threads */
  518. for (i = 0; i < NumWinThreads; i++) {
  519. DWORD id;
  520. WinThreads[i].Thread = CreateThread(NULL,
  521. 0,
  522. ThreadProc,
  523. (void*) &WinThreads[i],
  524. 0,
  525. &id);
  526. printf("wglthreads: Created thread %p\n", (void *) WinThreads[i].Thread);
  527. threads[i] = WinThreads[i].Thread;
  528. }
  529. /* Wait for all threads to finish. */
  530. WaitForMultipleObjects(NumWinThreads, threads, TRUE, INFINITE);
  531. }
  532. return 0;
  533. }