wgl: Port glthreads to WGL.
authorMichal Krol <michal@vmware.com>
Mon, 16 Mar 2009 08:45:23 +0000 (09:45 +0100)
committerMichal Krol <michal@vmware.com>
Mon, 16 Mar 2009 08:45:23 +0000 (09:45 +0100)
progs/wgl/wglthreads/wglthreads.c [new file with mode: 0644]
windows/VC7/progs/progs.sln [new file with mode: 0644]
windows/VC7/progs/wgl/wglthreads.vcproj [new file with mode: 0644]

diff --git a/progs/wgl/wglthreads/wglthreads.c b/progs/wgl/wglthreads/wglthreads.c
new file mode 100644 (file)
index 0000000..710a175
--- /dev/null
@@ -0,0 +1,593 @@
+/*
+ * Copyright (C) 2000  Brian Paul   All Rights Reserved.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ *
+ * Port to windows done by Michal Krol.
+ */
+
+
+/*
+ * This program tests WGL thread safety.
+ * Command line options:
+ *  -h                       Print usage
+ *  -l                       Enable application-side locking
+ *  -n <num threads>         Number of threads to create (default is 2)
+ *  -t                       Use texture mapping
+ *
+ * Brian Paul  20 July 2000
+ */
+
+
+/*
+ * Notes:
+ * - Each thread gets its own WGL context.
+ *
+ * - The WGL contexts share texture objects.
+ *
+ * - When 't' is pressed to update the texture image, the window/thread which
+ *   has input focus is signalled to change the texture.  The other threads
+ *   should see the updated texture the next time they call glBindTexture.
+ */
+
+
+#include <assert.h>
+#include <windows.h>
+#include <GL/gl.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#pragma comment(lib, "opengl32.lib")
+
+
+/*
+ * Each window/thread/context:
+ */
+struct winthread {
+   int Index;
+   HANDLE Thread;
+   HWND Win;
+   HDC hDC;
+   HGLRC Context;
+   float Angle;
+   int WinWidth, WinHeight;
+   GLboolean NewSize;
+   HANDLE hEventInitialised;
+   GLboolean MakeNewTexture;
+   HANDLE hEventRedraw;
+};
+
+
+#define MAX_WINTHREADS 100
+static struct winthread WinThreads[MAX_WINTHREADS];
+static int NumWinThreads = 2;
+static HANDLE ExitEvent = NULL;
+
+static GLboolean Locking = 0;
+static GLboolean Texture = GL_FALSE;
+static GLuint TexObj = 12;
+static GLboolean Animate = GL_TRUE;
+
+static CRITICAL_SECTION Mutex;
+
+
+static void
+Error(const char *msg)
+{
+   fprintf(stderr, "Error: %s\n", msg);
+   exit(1);
+}
+
+
+static void
+signal_redraw(void)
+{
+   int i;
+
+   for (i = 0; i < NumWinThreads; i++) {
+      SetEvent(WinThreads[i].hEventRedraw);
+   }
+}
+
+
+static void
+MakeNewTexture(struct winthread *wt)
+{
+#define TEX_SIZE 128
+   static float step = 0.0;
+   GLfloat image[TEX_SIZE][TEX_SIZE][4];
+   GLint width;
+   int i, j;
+
+   for (j = 0; j < TEX_SIZE; j++) {
+      for (i = 0; i < TEX_SIZE; i++) {
+         float dt = 5.0 * (j - 0.5 * TEX_SIZE) / TEX_SIZE;
+         float ds = 5.0 * (i - 0.5 * TEX_SIZE) / TEX_SIZE;
+         float r = dt * dt + ds * ds + step;
+         image[j][i][0] = 
+         image[j][i][1] = 
+         image[j][i][2] = 0.75 + 0.25 * cos(r);
+         image[j][i][3] = 1.0;
+      }
+   }
+
+   step += 0.5;
+
+   glBindTexture(GL_TEXTURE_2D, TexObj);
+
+   glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
+   if (width) {
+      assert(width == TEX_SIZE);
+      /* sub-tex replace */
+      glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, TEX_SIZE, TEX_SIZE,
+                   GL_RGBA, GL_FLOAT, image);
+   }
+   else {
+      /* create new */
+      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+      glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TEX_SIZE, TEX_SIZE, 0, 
+                   GL_RGBA, GL_FLOAT, image);
+   }
+}
+
+
+
+/* draw a colored cube */
+static void
+draw_object(void)
+{
+   glPushMatrix();
+   glScalef(0.75, 0.75, 0.75);
+
+   glColor3f(1, 0, 0);
+
+   if (Texture) {
+      glBindTexture(GL_TEXTURE_2D, TexObj);
+      glEnable(GL_TEXTURE_2D);
+   }
+   else {
+      glDisable(GL_TEXTURE_2D);
+   }
+
+   glBegin(GL_QUADS);
+
+   /* -X */
+   glColor3f(0, 1, 1);
+   glTexCoord2f(0, 0);  glVertex3f(-1, -1, -1);
+   glTexCoord2f(1, 0);  glVertex3f(-1,  1, -1);
+   glTexCoord2f(1, 1);  glVertex3f(-1,  1,  1);
+   glTexCoord2f(0, 1);  glVertex3f(-1, -1,  1);
+
+   /* +X */
+   glColor3f(1, 0, 0);
+   glTexCoord2f(0, 0);  glVertex3f(1, -1, -1);
+   glTexCoord2f(1, 0);  glVertex3f(1,  1, -1);
+   glTexCoord2f(1, 1);  glVertex3f(1,  1,  1);
+   glTexCoord2f(0, 1);  glVertex3f(1, -1,  1);
+
+   /* -Y */
+   glColor3f(1, 0, 1);
+   glTexCoord2f(0, 0);  glVertex3f(-1, -1, -1);
+   glTexCoord2f(1, 0);  glVertex3f( 1, -1, -1);
+   glTexCoord2f(1, 1);  glVertex3f( 1, -1,  1);
+   glTexCoord2f(0, 1);  glVertex3f(-1, -1,  1);
+
+   /* +Y */
+   glColor3f(0, 1, 0);
+   glTexCoord2f(0, 0);  glVertex3f(-1, 1, -1);
+   glTexCoord2f(1, 0);  glVertex3f( 1, 1, -1);
+   glTexCoord2f(1, 1);  glVertex3f( 1, 1,  1);
+   glTexCoord2f(0, 1);  glVertex3f(-1, 1,  1);
+
+   /* -Z */
+   glColor3f(1, 1, 0);
+   glTexCoord2f(0, 0);  glVertex3f(-1, -1, -1);
+   glTexCoord2f(1, 0);  glVertex3f( 1, -1, -1);
+   glTexCoord2f(1, 1);  glVertex3f( 1,  1, -1);
+   glTexCoord2f(0, 1);  glVertex3f(-1,  1, -1);
+
+   /* +Y */
+   glColor3f(0, 0, 1);
+   glTexCoord2f(0, 0);  glVertex3f(-1, -1, 1);
+   glTexCoord2f(1, 0);  glVertex3f( 1, -1, 1);
+   glTexCoord2f(1, 1);  glVertex3f( 1,  1, 1);
+   glTexCoord2f(0, 1);  glVertex3f(-1,  1, 1);
+
+   glEnd();
+
+   glPopMatrix();
+}
+
+
+/* signal resize of given window */
+static void
+resize(struct winthread *wt, int w, int h)
+{
+   wt->NewSize = GL_TRUE;
+   wt->WinWidth = w;
+   wt->WinHeight = h;
+   if (!Animate)
+      SetEvent(wt->hEventRedraw);
+}
+
+
+/*
+ * We have an instance of this for each thread.
+ */
+static void
+draw_loop(struct winthread *wt)
+{
+   while (1) {
+      GLboolean draw = Animate;
+      MSG msg;
+
+      if (Animate) {
+         /* wait 5 ms for signal either to exit or process messages */
+         switch (MsgWaitForMultipleObjects(1, &ExitEvent, FALSE, 5, QS_ALLINPUT)) {
+         case WAIT_OBJECT_0:
+            SendMessage(wt->Win, WM_CLOSE, 0, 0);
+            break;
+         case WAIT_OBJECT_0 + 1:
+            break;
+         }
+      }
+      else {
+         HANDLE events[2];
+
+         events[0] = wt->hEventRedraw;
+         events[1] = ExitEvent;
+
+         /* wait for signal either to draw, exit or process messages */
+         switch (MsgWaitForMultipleObjects(2, events, FALSE, INFINITE, QS_ALLINPUT)) {
+         case WAIT_OBJECT_0:
+            draw = GL_TRUE;
+            break;
+         case WAIT_OBJECT_0 + 1:
+            SendMessage(wt->Win, WM_CLOSE, 0, 0);
+            break;
+         case WAIT_OBJECT_0 + 2:
+            break;
+         }
+      }
+
+      while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
+         if (msg.message == WM_QUIT) {
+            return;
+         }
+         TranslateMessage(&msg);
+         DispatchMessage(&msg);
+      }
+
+      if (!draw)
+         continue;
+
+      if (Locking)
+         EnterCriticalSection(&Mutex);
+
+      wglMakeCurrent(wt->hDC, wt->Context);
+
+      if (Locking)
+         LeaveCriticalSection(&Mutex);
+
+      glEnable(GL_DEPTH_TEST);
+
+      if (wt->NewSize) {
+         GLfloat w = (float) wt->WinWidth / (float) wt->WinHeight;
+         glViewport(0, 0, wt->WinWidth, wt->WinHeight);
+         glMatrixMode(GL_PROJECTION);
+         glLoadIdentity();
+         glFrustum(-w, w, -1.0, 1.0, 1.5, 10);
+         glMatrixMode(GL_MODELVIEW);
+         glLoadIdentity();
+         glTranslatef(0, 0, -2.5);
+         wt->NewSize = GL_FALSE;
+      }
+
+      if (wt->MakeNewTexture) {
+         MakeNewTexture(wt);
+         wt->MakeNewTexture = GL_FALSE;
+      }
+
+      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+      glPushMatrix();
+         glRotatef(wt->Angle, 0, 1, 0);
+         glRotatef(wt->Angle, 1, 0, 0);
+         glScalef(0.7, 0.7, 0.7);
+         draw_object();
+      glPopMatrix();
+
+      if (Locking)
+         EnterCriticalSection(&Mutex);
+      SwapBuffers(wt->hDC);
+      if (Locking)
+         LeaveCriticalSection(&Mutex);
+
+      wt->Angle += 1.0;
+   }
+}
+
+
+static void
+keypress(WPARAM keySym, struct winthread *wt)
+{
+   switch (keySym) {
+   case VK_ESCAPE:
+      /* tell all threads to exit */
+      SetEvent(ExitEvent);
+      /*printf("exit draw_loop %d\n", wt->Index);*/
+      return;
+   case 't':
+   case 'T':
+      if (Texture) {
+         wt->MakeNewTexture = GL_TRUE;
+         if (!Animate)
+            signal_redraw();
+      }
+      break;
+   case 'a':
+   case 'A':
+      Animate = !Animate;
+      if (Animate)
+         signal_redraw();
+      break;
+   case 's':
+   case 'S':
+      if (!Animate)
+         signal_redraw();
+      break;
+   default:
+      ; /* nop */
+   }
+}
+
+
+static LRESULT CALLBACK
+WndProc(HWND hWnd,
+        UINT uMsg,
+        WPARAM wParam,
+        LPARAM lParam )
+{
+   int i;
+
+   switch (uMsg) {
+   case WM_KEYDOWN:
+      for (i = 0; i < NumWinThreads; i++) {
+         struct winthread *wt = &WinThreads[i];
+
+         if (hWnd == wt->Win) {
+            keypress(wParam, wt);
+            break;
+         }
+      }
+      break;
+   case WM_SIZE:
+      for (i = 0; i < NumWinThreads; i++) {
+         struct winthread *wt = &WinThreads[i];
+
+         if (hWnd == wt->Win) {
+            RECT r;
+
+            GetClientRect(hWnd, &r);
+            resize(wt, r.right, r.bottom);
+            break;
+         }
+      }
+      break;
+   case WM_DESTROY:
+      PostQuitMessage(0);
+      break;
+   default:
+      return DefWindowProc(hWnd, uMsg, wParam, lParam);
+   }
+
+   return 0;
+}
+
+/*
+ * we'll call this once for each thread, before the threads are created.
+ */
+static void
+create_window(struct winthread *wt, HGLRC shareCtx)
+{
+   WNDCLASS wc = {0};
+   int width = 160, height = 160;
+   int xpos = (wt->Index % 8) * (width + 10);
+   int ypos = (wt->Index / 8) * (width + 20);
+   HWND win;
+   HDC hdc;
+   PIXELFORMATDESCRIPTOR pfd = {0};
+   int visinfo;
+   HGLRC ctx;
+
+   wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
+   wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+   wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
+   wc.lpfnWndProc = WndProc;
+   wc.lpszClassName = "wglthreads";
+   wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
+   RegisterClass(&wc);
+
+   win = CreateWindowEx(0,
+                        wc.lpszClassName,
+                        "wglthreads",
+                        WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
+                        xpos,
+                        ypos,
+                        width,
+                        height,
+                        NULL,
+                        NULL,
+                        wc.hInstance,
+                        (LPVOID) wt);
+   if (!win) {
+      Error("Couldn't create window");
+   }
+
+   hdc = GetDC(win);
+   if (!hdc) {
+      Error("Couldn't obtain HDC");
+   }
+
+   pfd.cColorBits = 24;
+   pfd.cDepthBits = 24;
+   pfd.dwFlags = PFD_DOUBLEBUFFER | PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
+   pfd.iLayerType = PFD_MAIN_PLANE;
+   pfd.iPixelType = PFD_TYPE_RGBA;
+   pfd.nSize = sizeof(pfd);
+   pfd.nVersion = 1;
+
+   visinfo = ChoosePixelFormat(hdc, &pfd);
+   if (!visinfo) {
+      Error("Unable to find RGB, Z, double-buffered visual");
+   }
+
+   SetPixelFormat(hdc, visinfo, &pfd);
+   ctx = wglCreateContext(hdc);
+   if (!ctx) {
+      Error("Couldn't create WGL context");
+   }
+
+   if (shareCtx) {
+      wglShareLists(shareCtx, ctx);
+   }
+
+   /* save the info for this window/context */
+   wt->Win = win;
+   wt->hDC = hdc;
+   wt->Context = ctx;
+   wt->Angle = 0.0;
+   wt->WinWidth = width;
+   wt->WinHeight = height;
+   wt->NewSize = GL_TRUE;
+
+   printf("wglthreads: %d: GL_RENDERER = %s\n", wt->Index, (char *) glGetString(GL_RENDERER));
+
+   if (Texture/* && wt->Index == 0*/) {
+      MakeNewTexture(wt);
+   }
+}
+
+
+/*
+ * Called by pthread_create()
+ */
+static DWORD WINAPI
+ThreadProc(void *p)
+{
+   struct winthread *wt = (struct winthread *) p;
+   HGLRC share;
+
+   share = (Texture && wt->Index > 0) ? WinThreads[0].Context : 0;
+   create_window(wt, share);
+   SetEvent(wt->hEventInitialised);
+
+   draw_loop(wt);
+   return 0;
+}
+
+
+static void
+usage(void)
+{
+   printf("wglthreads: test of GL thread safety (any key = exit)\n");
+   printf("Usage:\n");
+   printf("  wglthreads [options]\n");
+   printf("Options:\n");
+   printf("   -h  Show this usage screen\n");
+   printf("   -n NUMTHREADS  Number of threads to create\n");
+   printf("   -l  Use application-side locking\n");
+   printf("   -t  Enable texturing\n");
+   printf("Keyboard:\n");
+   printf("   Esc  Exit\n");
+   printf("   t    Change texture image (requires -t option)\n");
+   printf("   a    Toggle animation\n");
+   printf("   s    Step rotation (when not animating)\n");
+}
+
+
+int
+main(int argc, char *argv[])
+{
+   int i;
+   HANDLE threads[MAX_WINTHREADS];
+
+   for (i = 1; i < argc; i++) {
+      if (strcmp(argv[i], "-h") == 0) {
+         usage();
+      }
+      else if (strcmp(argv[i], "-l") == 0) {
+         Locking = 1;
+      }
+      else if (strcmp(argv[i], "-t") == 0) {
+         Texture = 1;
+      }
+      else if (strcmp(argv[i], "-n") == 0 && i + 1 < argc) {
+         NumWinThreads = atoi(argv[i + 1]);
+         if (NumWinThreads < 1)
+            NumWinThreads = 1;
+         else if (NumWinThreads > MAX_WINTHREADS)
+            NumWinThreads = MAX_WINTHREADS;
+         i++;
+      }
+      else {
+         usage();
+         exit(1);
+      }
+   }
+   
+   if (Locking)
+      printf("wglthreads: Using explicit locks around WGL calls.\n");
+   else
+      printf("wglthreads: No explict locking.\n");
+
+   InitializeCriticalSection(&Mutex);
+   ExitEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+
+   printf("wglthreads: creating threads\n");
+
+   /* Create the threads */
+   for (i = 0; i < NumWinThreads; i++) {
+      DWORD id;
+
+      WinThreads[i].Index = i;
+      WinThreads[i].hEventInitialised = CreateEvent(NULL, TRUE, FALSE, NULL);
+      WinThreads[i].hEventRedraw = CreateEvent(NULL, FALSE, FALSE, NULL);
+      WinThreads[i].Thread = CreateThread(NULL,
+                                          0,
+                                          ThreadProc,
+                                          (void*) &WinThreads[i],
+                                          0,
+                                          &id);
+      printf("wglthreads: Created thread %p\n", (void *) WinThreads[i].Thread);
+
+      WaitForSingleObject(WinThreads[i].hEventInitialised, INFINITE);
+
+      threads[i] = WinThreads[i].Thread;
+   }
+
+   /* Wait for all threads to finish. */
+   WaitForMultipleObjects(NumWinThreads, threads, TRUE, INFINITE);
+
+   return 0;
+}
diff --git a/windows/VC7/progs/progs.sln b/windows/VC7/progs/progs.sln
new file mode 100644 (file)
index 0000000..18f0c04
--- /dev/null
@@ -0,0 +1,21 @@
+Microsoft Visual Studio Solution File, Format Version 8.00\r
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wglthreads", "wgl\wglthreads.vcproj", "{ADDFBA10-B159-4884-9FAF-5E60A64903AE}"\r
+       ProjectSection(ProjectDependencies) = postProject\r
+       EndProjectSection\r
+EndProject\r
+Global\r
+       GlobalSection(SolutionConfiguration) = preSolution\r
+               Debug = Debug\r
+               Release = Release\r
+       EndGlobalSection\r
+       GlobalSection(ProjectConfiguration) = postSolution\r
+               {ADDFBA10-B159-4884-9FAF-5E60A64903AE}.Debug.ActiveCfg = Debug|Win32\r
+               {ADDFBA10-B159-4884-9FAF-5E60A64903AE}.Debug.Build.0 = Debug|Win32\r
+               {ADDFBA10-B159-4884-9FAF-5E60A64903AE}.Release.ActiveCfg = Release|Win32\r
+               {ADDFBA10-B159-4884-9FAF-5E60A64903AE}.Release.Build.0 = Release|Win32\r
+       EndGlobalSection\r
+       GlobalSection(ExtensibilityGlobals) = postSolution\r
+       EndGlobalSection\r
+       GlobalSection(ExtensibilityAddIns) = postSolution\r
+       EndGlobalSection\r
+EndGlobal\r
diff --git a/windows/VC7/progs/wgl/wglthreads.vcproj b/windows/VC7/progs/wgl/wglthreads.vcproj
new file mode 100644 (file)
index 0000000..25ea377
--- /dev/null
@@ -0,0 +1,132 @@
+<?xml version="1.0" encoding="Windows-1252"?>\r
+<VisualStudioProject\r
+       ProjectType="Visual C++"\r
+       Version="7.10"\r
+       Name="wglthreads"\r
+       ProjectGUID="{ADDFBA10-B159-4884-9FAF-5E60A64903AE}"\r
+       Keyword="Win32Proj">\r
+       <Platforms>\r
+               <Platform\r
+                       Name="Win32"/>\r
+       </Platforms>\r
+       <Configurations>\r
+               <Configuration\r
+                       Name="Debug|Win32"\r
+                       OutputDirectory="Debug"\r
+                       IntermediateDirectory="Debug"\r
+                       ConfigurationType="1"\r
+                       CharacterSet="2">\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               Optimization="0"\r
+                               PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"\r
+                               MinimalRebuild="TRUE"\r
+                               BasicRuntimeChecks="3"\r
+                               RuntimeLibrary="5"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="TRUE"\r
+                               DebugInformationFormat="4"/>\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"/>\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               OutputFile="$(OutDir)/wglthreads.exe"\r
+                               LinkIncremental="2"\r
+                               GenerateDebugInformation="TRUE"\r
+                               ProgramDatabaseFile="$(OutDir)/wglthreads.pdb"\r
+                               SubSystem="1"\r
+                               TargetMachine="1"/>\r
+                       <Tool\r
+                               Name="VCMIDLTool"/>\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"/>\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"/>\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"/>\r
+                       <Tool\r
+                               Name="VCManagedWrapperGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCAuxiliaryManagedWrapperGeneratorTool"/>\r
+               </Configuration>\r
+               <Configuration\r
+                       Name="Release|Win32"\r
+                       OutputDirectory="Release"\r
+                       IntermediateDirectory="Release"\r
+                       ConfigurationType="1"\r
+                       CharacterSet="2">\r
+                       <Tool\r
+                               Name="VCCLCompilerTool"\r
+                               PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"\r
+                               RuntimeLibrary="4"\r
+                               UsePrecompiledHeader="0"\r
+                               WarningLevel="3"\r
+                               Detect64BitPortabilityProblems="TRUE"\r
+                               DebugInformationFormat="3"/>\r
+                       <Tool\r
+                               Name="VCCustomBuildTool"/>\r
+                       <Tool\r
+                               Name="VCLinkerTool"\r
+                               OutputFile="$(OutDir)/wglthreads.exe"\r
+                               LinkIncremental="1"\r
+                               GenerateDebugInformation="TRUE"\r
+                               SubSystem="1"\r
+                               OptimizeReferences="2"\r
+                               EnableCOMDATFolding="2"\r
+                               TargetMachine="1"/>\r
+                       <Tool\r
+                               Name="VCMIDLTool"/>\r
+                       <Tool\r
+                               Name="VCPostBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreBuildEventTool"/>\r
+                       <Tool\r
+                               Name="VCPreLinkEventTool"/>\r
+                       <Tool\r
+                               Name="VCResourceCompilerTool"/>\r
+                       <Tool\r
+                               Name="VCWebServiceProxyGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCXMLDataGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCWebDeploymentTool"/>\r
+                       <Tool\r
+                               Name="VCManagedWrapperGeneratorTool"/>\r
+                       <Tool\r
+                               Name="VCAuxiliaryManagedWrapperGeneratorTool"/>\r
+               </Configuration>\r
+       </Configurations>\r
+       <References>\r
+       </References>\r
+       <Files>\r
+               <Filter\r
+                       Name="Source Files"\r
+                       Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"\r
+                       UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">\r
+                       <File\r
+                               RelativePath="..\..\..\..\progs\wgl\wglthreads\wglthreads.c">\r
+                       </File>\r
+               </Filter>\r
+               <Filter\r
+                       Name="Header Files"\r
+                       Filter="h;hpp;hxx;hm;inl;inc;xsd"\r
+                       UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">\r
+               </Filter>\r
+               <Filter\r
+                       Name="Resource Files"\r
+                       Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"\r
+                       UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">\r
+               </Filter>\r
+       </Files>\r
+       <Globals>\r
+       </Globals>\r
+</VisualStudioProject>\r