]> git.cworth.org Git - apitrace/blob - retrace/glws_wgl.cpp
b4fd922fc1412f0180b0d611ee8d00f3f13cb408
[apitrace] / retrace / glws_wgl.cpp
1 /**************************************************************************
2  *
3  * Copyright 2011 Jose Fonseca
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  *
24  **************************************************************************/
25
26
27 /*
28  * WGL bindings.
29  */
30
31
32 #include <iostream>
33
34 #include "glproc.hpp"
35 #include "glws.hpp"
36
37
38 namespace glws {
39
40
41 /*
42  * Several WGL functions come in two flavors:
43  * - GDI (ChoosePixelFormat, SetPixelFormat, SwapBuffers, etc)
44  * - WGL (wglChoosePixelFormat, wglSetPixelFormat, wglSwapBuffers, etc)
45  *
46  * The GDI entrypoints will inevitably dispatch to the first module named
47  * "OPENGL32", loading "C:\Windows\System32\opengl32.dll" if none was loaded so
48  * far.
49  *
50  * In order to use a implementation other than the one installed in the system
51  * (when specified via the TRACE_LIBGL environment variable), we need to use
52  * WGL entrypoints.
53  *
54  * See also:
55  * - http://www.opengl.org/archives/resources/faq/technical/mswindows.htm
56  */
57 static PFN_WGLCHOOSEPIXELFORMAT pfnChoosePixelFormat = &ChoosePixelFormat;
58 static PFN_WGLSETPIXELFORMAT pfnSetPixelFormat = &SetPixelFormat;
59 static PFN_WGLSWAPBUFFERS pfnSwapBuffers = &SwapBuffers;
60
61
62 static LRESULT CALLBACK
63 WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
64 {
65     MINMAXINFO *pMMI;
66     switch (uMsg) {
67     case WM_KEYDOWN:
68         switch (wParam) {
69         case VK_ESCAPE:
70             PostMessage(hWnd, WM_CLOSE, 0, 0);
71             break;
72         }
73         break;
74     case WM_GETMINMAXINFO:
75         // Allow to create a window bigger than the desktop
76         pMMI = (MINMAXINFO *)lParam;
77         pMMI->ptMaxSize.x = 60000;
78         pMMI->ptMaxSize.y = 60000;
79         pMMI->ptMaxTrackSize.x = 60000;
80         pMMI->ptMaxTrackSize.y = 60000;
81         break;
82     case WM_CLOSE:
83         exit(0);
84         break;
85     default:
86         break;
87     }
88
89     return DefWindowProc(hWnd, uMsg, wParam, lParam);
90 }
91
92
93 class WglDrawable : public Drawable
94 {
95 public:
96     DWORD dwExStyle;
97     DWORD dwStyle;
98     HWND hWnd;
99     HDC hDC;
100     PIXELFORMATDESCRIPTOR pfd;
101     int iPixelFormat;
102
103     WglDrawable(const Visual *vis, int width, int height, bool pbuffer) :
104         Drawable(vis, width, height, pbuffer)
105     {
106         static bool first = TRUE;
107         RECT rect;
108         BOOL bRet;
109
110         if (first) {
111             WNDCLASS wc;
112             memset(&wc, 0, sizeof wc);
113             wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
114             wc.hCursor = LoadCursor(NULL, IDC_ARROW);
115             wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
116             wc.lpfnWndProc = WndProc;
117             wc.lpszClassName = "glretrace";
118             wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
119             RegisterClass(&wc);
120             first = FALSE;
121         }
122
123         dwExStyle = 0;
124         dwStyle = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW;
125
126         int x = 0, y = 0;
127
128         rect.left = x;
129         rect.top = y;
130         rect.right = rect.left + width;
131         rect.bottom = rect.top + height;
132
133         AdjustWindowRectEx(&rect, dwStyle, FALSE, dwExStyle);
134
135         hWnd = CreateWindowEx(dwExStyle,
136                               "glretrace", /* wc.lpszClassName */
137                               NULL,
138                               dwStyle,
139                               0, /* x */
140                               0, /* y */
141                               rect.right - rect.left, /* width */
142                               rect.bottom - rect.top, /* height */
143                               NULL,
144                               NULL,
145                               NULL,
146                               NULL);
147         hDC = GetDC(hWnd);
148    
149         memset(&pfd, 0, sizeof pfd);
150         pfd.cColorBits = 4;
151         pfd.cRedBits = 1;
152         pfd.cGreenBits = 1;
153         pfd.cBlueBits = 1;
154         pfd.cAlphaBits = 1;
155         pfd.cDepthBits = 1;
156         pfd.cStencilBits = 1;
157         pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL;
158         pfd.iLayerType = PFD_MAIN_PLANE;
159         pfd.iPixelType = PFD_TYPE_RGBA;
160         pfd.nSize = sizeof(pfd);
161         pfd.nVersion = 1;
162
163         if (visual->doubleBuffer) {
164            pfd.dwFlags |= PFD_DOUBLEBUFFER;
165         }
166
167         iPixelFormat = pfnChoosePixelFormat(hDC, &pfd);
168         if (iPixelFormat <= 0) {
169             std::cerr << "error: ChoosePixelFormat failed\n";
170             exit(1);
171         }
172
173         bRet = pfnSetPixelFormat(hDC, iPixelFormat, &pfd);
174         if (!bRet) {
175             std::cerr << "error: SetPixelFormat failed\n";
176             exit(1);
177         }
178     }
179
180     ~WglDrawable() {
181         ReleaseDC(hWnd, hDC);
182         DestroyWindow(hWnd);
183     }
184     
185     void
186     resize(int w, int h) {
187         if (w == width && h == height) {
188             return;
189         }
190
191         RECT rClient, rWindow;
192         GetClientRect(hWnd, &rClient);
193         GetWindowRect(hWnd, &rWindow);
194         w += (rWindow.right  - rWindow.left) - rClient.right;
195         h += (rWindow.bottom - rWindow.top)  - rClient.bottom;
196         SetWindowPos(hWnd, NULL, rWindow.left, rWindow.top, w, h, SWP_NOMOVE);
197
198         Drawable::resize(w, h);
199     }
200
201     void show(void) {
202         if (visible) {
203             return;
204         }
205
206         ShowWindow(hWnd, SW_SHOW);
207
208         Drawable::show();
209     }
210
211     void swapBuffers(void) {
212         BOOL bRet;
213         bRet = pfnSwapBuffers(hDC);
214         if (!bRet) {
215             std::cerr << "warning: SwapBuffers failed\n";
216         }
217
218         // Drain message queue to prevent window from being considered
219         // non-responsive
220         MSG msg;
221         while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
222             TranslateMessage(&msg);
223             DispatchMessage(&msg);
224         }
225     }
226 };
227
228
229 class WglContext : public Context
230 {
231 public:
232     HGLRC hglrc;
233     WglContext *shareContext;
234
235     WglContext(const Visual *vis, Profile prof, WglContext *share) :
236         Context(vis, prof),
237         hglrc(0),
238         shareContext(share)
239     {}
240
241     ~WglContext() {
242         if (hglrc) {
243             wglDeleteContext(hglrc);
244         }
245     }
246 };
247
248
249 void
250 init(void) {
251     /*
252      * OpenGL library must be loaded by the time we call GDI.
253      */
254
255     const char * libgl_filename = getenv("TRACE_LIBGL");
256
257     if (libgl_filename) {
258         pfnChoosePixelFormat = &wglChoosePixelFormat;
259         pfnSetPixelFormat = &wglSetPixelFormat;
260         pfnSwapBuffers = &wglSwapBuffers;
261     } else {
262         libgl_filename = "OPENGL32";
263     }
264
265     _libGlHandle = LoadLibraryA(libgl_filename);
266     if (!_libGlHandle) {
267         std::cerr << "error: unable to open " << libgl_filename << "\n";
268         exit(1);
269     }
270 }
271
272 void
273 cleanup(void) {
274 }
275
276 Visual *
277 createVisual(bool doubleBuffer, Profile profile) {
278     if (profile != PROFILE_COMPAT) {
279         return NULL;
280     }
281
282     Visual *visual = new Visual();
283
284     visual->doubleBuffer = doubleBuffer;
285
286     return visual;
287 }
288
289 Drawable *
290 createDrawable(const Visual *visual, int width, int height, bool pbuffer)
291 {
292     return new WglDrawable(visual, width, height, pbuffer);
293 }
294
295 Context *
296 createContext(const Visual *visual, Context *shareContext, Profile profile, bool debug)
297 {
298     if (profile != PROFILE_COMPAT) {
299         return NULL;
300     }
301
302     return new WglContext(visual, profile, static_cast<WglContext *>(shareContext));
303 }
304
305 bool
306 makeCurrent(Drawable *drawable, Context *context)
307 {
308     if (!drawable || !context) {
309         return wglMakeCurrent(NULL, NULL);
310     } else {
311         WglDrawable *wglDrawable = static_cast<WglDrawable *>(drawable);
312         WglContext *wglContext = static_cast<WglContext *>(context);
313
314         if (!wglContext->hglrc) {
315             wglContext->hglrc = wglCreateContext(wglDrawable->hDC);
316             if (!wglContext->hglrc) {
317                 std::cerr << "error: wglCreateContext failed\n";
318                 exit(1);
319                 return false;
320             }
321             if (wglContext->shareContext) {
322                 BOOL bRet;
323                 bRet = wglShareLists(wglContext->shareContext->hglrc,
324                                      wglContext->hglrc);
325                 if (!bRet) {
326                     std::cerr << "warning: wglShareLists failed\n";
327                 }
328             }
329         }
330
331         return wglMakeCurrent(wglDrawable->hDC, wglContext->hglrc);
332     }
333 }
334
335 bool
336 processEvents(void) {
337     MSG uMsg;
338     while (PeekMessage(&uMsg, NULL, 0, 0, PM_REMOVE)) {
339         if (uMsg.message == WM_QUIT) {
340             return false;
341         }
342
343         if (!TranslateAccelerator(uMsg.hwnd, NULL, &uMsg)) {
344             TranslateMessage(&uMsg);
345             DispatchMessage(&uMsg);
346         }
347     }
348     return true;
349 }
350
351
352 } /* namespace glws */