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