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