]> git.cworth.org Git - apitrace/blob - glws_glx.cpp
Use Cocoa on Mac OS X.
[apitrace] / glws_glx.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 #include <assert.h>
27 #include <stdlib.h>
28
29 #include <iostream>
30
31 #include "glws.hpp"
32
33 #include "glproc.hpp"
34
35
36 namespace glws {
37
38
39 static Display *display = NULL;
40 static int screen = 0;
41
42 static unsigned glxVersion = 0;
43 static const char *extensions = 0;
44 static bool has_GLX_ARB_create_context = false;
45
46
47 class GlxVisual : public Visual
48 {
49 public:
50     GLXFBConfig fbconfig;
51     XVisualInfo *visinfo;
52
53     GlxVisual() :
54         fbconfig(0),
55         visinfo(0)
56     {}
57
58     ~GlxVisual() {
59         XFree(visinfo);
60         XFree(fbconfig);
61     }
62 };
63
64
65 static void describeEvent(const XEvent &event) {
66     if (0) {
67         switch (event.type) {
68         case ConfigureNotify:
69             std::cerr << "ConfigureNotify";
70             break;
71         case Expose:
72             std::cerr << "Expose";
73             break;
74         case KeyPress:
75             std::cerr << "KeyPress";
76             break;
77         case MapNotify:
78             std::cerr << "MapNotify";
79             break;
80         case ReparentNotify:
81             std::cerr << "ReparentNotify";
82             break;
83         default:
84             std::cerr << "Event " << event.type;
85         }
86         std::cerr << " " << event.xany.window << "\n";
87     }
88 }
89
90 static void waitForEvent(Window window, int type) {
91     XFlush(display);
92     XEvent event;
93     do {
94         XNextEvent(display, &event);
95         describeEvent(event);
96     } while (event.type != type ||
97              event.xany.window != window);
98 }
99
100
101 class GlxDrawable : public Drawable
102 {
103 public:
104     Window window;
105
106     GlxDrawable(const Visual *vis, int w, int h) :
107         Drawable(vis, w, h)
108     {
109         XVisualInfo *visinfo = dynamic_cast<const GlxVisual *>(visual)->visinfo;
110
111         Window root = RootWindow(display, screen);
112
113         /* window attributes */
114         XSetWindowAttributes attr;
115         attr.background_pixel = 0;
116         attr.border_pixel = 0;
117         attr.colormap = XCreateColormap(display, root, visinfo->visual, AllocNone);
118         attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
119
120         unsigned long mask;
121         mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
122
123         int x = 0, y = 0;
124
125         window = XCreateWindow(
126             display, root,
127             x, y, width, height,
128             0,
129             visinfo->depth,
130             InputOutput,
131             visinfo->visual,
132             mask,
133             &attr);
134
135         XSizeHints sizehints;
136         sizehints.x = x;
137         sizehints.y = y;
138         sizehints.width  = width;
139         sizehints.height = height;
140         sizehints.flags = USSize | USPosition;
141         XSetNormalHints(display, window, &sizehints);
142
143         const char *name = "glretrace";
144         XSetStandardProperties(
145             display, window, name, name,
146             None, (char **)NULL, 0, &sizehints);
147
148         glXWaitX();
149     }
150
151     ~GlxDrawable() {
152         XDestroyWindow(display, window);
153     }
154
155     void
156     resize(int w, int h) {
157         glXWaitGL();
158
159         // We need to ensure that pending events are processed here, and XSync
160         // with discard = True guarantees that, but it appears the limited
161         // event processing we do so far is sufficient
162         //XSync(display, True);
163
164         Drawable::resize(w, h);
165
166         XResizeWindow(display, window, w, h);
167
168         // Tell the window manager to respect the requested size
169         XSizeHints *size_hints;
170         size_hints = XAllocSizeHints();
171         size_hints->max_width  = size_hints->min_width  = w;
172         size_hints->max_height = size_hints->min_height = h;
173         size_hints->flags = PMinSize | PMaxSize;
174         XSetWMNormalHints(display, window, size_hints);
175         XFree(size_hints);
176
177         waitForEvent(window, ConfigureNotify);
178
179         glXWaitX();
180     }
181
182     void show(void) {
183         if (!visible) {
184             XMapWindow(display, window);
185
186             waitForEvent(window, Expose);
187
188             Drawable::show();
189         }
190     }
191
192     void swapBuffers(void) {
193         glXSwapBuffers(display, window);
194     }
195 };
196
197
198 class GlxContext : public Context
199 {
200 public:
201     GLXContext context;
202
203     GlxContext(const Visual *vis, GLXContext ctx) :
204         Context(vis),
205         context(ctx)
206     {}
207
208     ~GlxContext() {
209         glXDestroyContext(display, context);
210     }
211 };
212
213 void
214 init(void) {
215     display = XOpenDisplay(NULL);
216     if (!display) {
217         std::cerr << "error: unable to open display " << XDisplayName(NULL) << "\n";
218         exit(1);
219     }
220
221     screen = DefaultScreen(display);
222
223     int major = 0, minor = 0;
224     glXQueryVersion(display, &major, &minor);
225     glxVersion = (major << 8) | minor;
226
227     extensions = glXQueryExtensionsString(display, screen);
228     has_GLX_ARB_create_context = checkExtension("GLX_ARB_create_context", extensions);
229 }
230
231 void
232 cleanup(void) {
233     if (display) {
234         XCloseDisplay(display);
235         display = NULL;
236     }
237 }
238
239 Visual *
240 createVisual(bool doubleBuffer) {
241     GlxVisual *visual = new GlxVisual;
242
243     if (glxVersion >= 0x0103) {
244         Attributes<int> attribs;
245         attribs.add(GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT);
246         attribs.add(GLX_RENDER_TYPE, GLX_RGBA_BIT);
247         attribs.add(GLX_RED_SIZE, 1);
248         attribs.add(GLX_GREEN_SIZE, 1);
249         attribs.add(GLX_BLUE_SIZE, 1);
250         attribs.add(GLX_ALPHA_SIZE, 1);
251         attribs.add(GLX_DOUBLEBUFFER, doubleBuffer ? GL_TRUE : GL_FALSE);
252         attribs.add(GLX_DEPTH_SIZE, 1);
253         attribs.add(GLX_STENCIL_SIZE, 1);
254         attribs.end();
255
256         int num_configs = 0;
257         GLXFBConfig * fbconfigs;
258         fbconfigs = glXChooseFBConfig(display, screen, attribs, &num_configs);
259         assert(num_configs && fbconfigs);
260         visual->fbconfig = fbconfigs[0];
261         assert(visual->fbconfig);
262         visual->visinfo = glXGetVisualFromFBConfig(display, visual->fbconfig);
263         assert(visual->visinfo);
264     } else {
265         Attributes<int> attribs;
266         attribs.add(GLX_RGBA);
267         attribs.add(GLX_RED_SIZE, 1);
268         attribs.add(GLX_GREEN_SIZE, 1);
269         attribs.add(GLX_BLUE_SIZE, 1);
270         attribs.add(GLX_ALPHA_SIZE, 1);
271         if (doubleBuffer) {
272             attribs.add(GLX_DOUBLEBUFFER);
273         }
274         attribs.add(GLX_DEPTH_SIZE, 1);
275         attribs.add(GLX_STENCIL_SIZE, 1);
276         attribs.end();
277
278         visual->visinfo = glXChooseVisual(display, screen, attribs);
279     }
280
281     return visual;
282 }
283
284 Drawable *
285 createDrawable(const Visual *visual, int width, int height)
286 {
287     return new GlxDrawable(visual, width, height);
288 }
289
290 Context *
291 createContext(const Visual *_visual, Context *shareContext)
292 {
293     const GlxVisual *visual = dynamic_cast<const GlxVisual *>(_visual);
294     GLXContext share_context = NULL;
295     GLXContext context;
296
297     if (shareContext) {
298         share_context = dynamic_cast<GlxContext*>(shareContext)->context;
299     }
300
301     if (glxVersion >= 0x0104 && has_GLX_ARB_create_context) {
302         Attributes<int> attribs;
303         attribs.add(GLX_RENDER_TYPE, GLX_RGBA_TYPE);
304         if (debug) {
305             attribs.add(GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB);
306         }
307         attribs.end();
308
309         context = glXCreateContextAttribsARB(display, visual->fbconfig, share_context, True, attribs);
310     } else 
311            if (glxVersion >= 0x103) {
312         context = glXCreateNewContext(display, visual->fbconfig, GLX_RGBA_TYPE, share_context, True);
313     } else {
314         context = glXCreateContext(display, visual->visinfo, share_context, True);
315     }
316
317     return new GlxContext(visual, context);
318 }
319
320 bool
321 makeCurrent(Drawable *drawable, Context *context)
322 {
323     if (!drawable || !context) {
324         return glXMakeCurrent(display, None, NULL);
325     } else {
326         GlxDrawable *glxDrawable = dynamic_cast<GlxDrawable *>(drawable);
327         GlxContext *glxContext = dynamic_cast<GlxContext *>(context);
328
329         return glXMakeCurrent(display, glxDrawable->window, glxContext->context);
330     }
331 }
332
333 bool
334 processEvents(void) {
335     XFlush(display);
336     while (XPending(display) > 0) {
337         XEvent event;
338         XNextEvent(display, &event);
339         describeEvent(event);
340     }
341     return true;
342 }
343
344
345 } /* namespace glws */