]> git.cworth.org Git - apitrace/blob - retrace/glws_wgl.cpp
Use skiplist-based FastCallSet within trace::CallSet
[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     bool
248     create(WglDrawable *wglDrawable) {
249         if (!hglrc) {
250             hglrc = wglCreateContext(wglDrawable->hDC);
251             if (!hglrc) {
252                 std::cerr << "error: wglCreateContext failed\n";
253                 exit(1);
254                 return false;
255             }
256             if (shareContext) {
257                 if (shareContext->create(wglDrawable)) {
258                     BOOL bRet;
259                     bRet = wglShareLists(shareContext->hglrc,
260                                          hglrc);
261                     if (!bRet) {
262                         std::cerr
263                             << "warning: wglShareLists failed: "
264                             << std::hex << GetLastError() << std::dec
265                             << "\n";
266                     }
267                 }
268             }
269         }
270
271         return true;
272     }
273
274 };
275
276
277 void
278 init(void) {
279     /*
280      * OpenGL library must be loaded by the time we call GDI.
281      */
282
283     const char * libgl_filename = getenv("TRACE_LIBGL");
284
285     if (libgl_filename) {
286         pfnChoosePixelFormat = &wglChoosePixelFormat;
287         pfnSetPixelFormat = &wglSetPixelFormat;
288         pfnSwapBuffers = &wglSwapBuffers;
289     } else {
290         libgl_filename = "OPENGL32";
291     }
292
293     _libGlHandle = LoadLibraryA(libgl_filename);
294     if (!_libGlHandle) {
295         std::cerr << "error: unable to open " << libgl_filename << "\n";
296         exit(1);
297     }
298 }
299
300 void
301 cleanup(void) {
302 }
303
304 Visual *
305 createVisual(bool doubleBuffer, Profile profile) {
306     if (profile != PROFILE_COMPAT &&
307         profile != PROFILE_CORE) {
308         return NULL;
309     }
310
311     Visual *visual = new Visual();
312
313     visual->doubleBuffer = doubleBuffer;
314
315     return visual;
316 }
317
318 Drawable *
319 createDrawable(const Visual *visual, int width, int height, bool pbuffer)
320 {
321     return new WglDrawable(visual, width, height, pbuffer);
322 }
323
324 Context *
325 createContext(const Visual *visual, Context *shareContext, Profile profile, bool debug)
326 {
327     if (profile != PROFILE_COMPAT &&
328         profile != PROFILE_CORE) {
329         return NULL;
330     }
331
332     if (profile == PROFILE_CORE) {
333         std::cerr << "warning: ignoring OpenGL core profile request\n";
334     }
335
336     return new WglContext(visual, profile, static_cast<WglContext *>(shareContext));
337 }
338
339 bool
340 makeCurrent(Drawable *drawable, Context *context)
341 {
342     if (!drawable || !context) {
343         return wglMakeCurrent(NULL, NULL);
344     } else {
345         WglDrawable *wglDrawable = static_cast<WglDrawable *>(drawable);
346         WglContext *wglContext = static_cast<WglContext *>(context);
347
348         wglContext->create(wglDrawable);
349
350         return wglMakeCurrent(wglDrawable->hDC, wglContext->hglrc);
351     }
352 }
353
354 bool
355 processEvents(void) {
356     MSG uMsg;
357     while (PeekMessage(&uMsg, NULL, 0, 0, PM_REMOVE)) {
358         if (uMsg.message == WM_QUIT) {
359             return false;
360         }
361
362         if (!TranslateAccelerator(uMsg.hwnd, NULL, &uMsg)) {
363             TranslateMessage(&uMsg);
364             DispatchMessage(&uMsg);
365         }
366     }
367     return true;
368 }
369
370
371 } /* namespace glws */