]> git.cworth.org Git - apitrace/blob - retrace/glws_wgl.cpp
glretrace: Silence warning on wgl.
[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         Drawable::resize(w, h);
192
193         RECT rClient, rWindow;
194         GetClientRect(hWnd, &rClient);
195         GetWindowRect(hWnd, &rWindow);
196         w += (rWindow.right  - rWindow.left) - rClient.right;
197         h += (rWindow.bottom - rWindow.top)  - rClient.bottom;
198         SetWindowPos(hWnd, NULL, rWindow.left, rWindow.top, w, h, SWP_NOMOVE);
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         profile != PROFILE_ES2) {
309         return NULL;
310     }
311
312     Visual *visual = new Visual();
313
314     visual->doubleBuffer = doubleBuffer;
315
316     return visual;
317 }
318
319 Drawable *
320 createDrawable(const Visual *visual, int width, int height, bool pbuffer)
321 {
322     return new WglDrawable(visual, width, height, pbuffer);
323 }
324
325 Context *
326 createContext(const Visual *visual, Context *shareContext, Profile profile, bool debug)
327 {
328     if (profile != PROFILE_COMPAT &&
329         profile != PROFILE_CORE &&
330         profile != PROFILE_ES2) {
331         return NULL;
332     }
333
334     switch (profile) {
335     case PROFILE_CORE:
336         std::cerr << "warning: ignoring OpenGL core profile request\n";
337         break;
338     case PROFILE_ES2:
339         std::cerr << "warning: ignoring OpenGL ES 2.0 profile request\n";
340         break;
341     default:
342         break;
343     }
344
345     return new WglContext(visual, profile, static_cast<WglContext *>(shareContext));
346 }
347
348 bool
349 makeCurrent(Drawable *drawable, Context *context)
350 {
351     if (!drawable || !context) {
352         return wglMakeCurrent(NULL, NULL);
353     } else {
354         WglDrawable *wglDrawable = static_cast<WglDrawable *>(drawable);
355         WglContext *wglContext = static_cast<WglContext *>(context);
356
357         wglContext->create(wglDrawable);
358
359         return wglMakeCurrent(wglDrawable->hDC, wglContext->hglrc);
360     }
361 }
362
363 bool
364 processEvents(void) {
365     MSG uMsg;
366     while (PeekMessage(&uMsg, NULL, 0, 0, PM_REMOVE)) {
367         if (uMsg.message == WM_QUIT) {
368             return false;
369         }
370
371         if (!TranslateAccelerator(uMsg.hwnd, NULL, &uMsg)) {
372             TranslateMessage(&uMsg);
373             DispatchMessage(&uMsg);
374         }
375     }
376     return true;
377 }
378
379
380 } /* namespace glws */