]> git.cworth.org Git - apitrace/blob - glws_glx.cpp
apitrace diff-images: Print one line for each file being compared.
[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 "glproc.hpp"
32 #include "glws.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     }
60 };
61
62
63 static void describeEvent(const XEvent &event) {
64     if (0) {
65         switch (event.type) {
66         case ConfigureNotify:
67             std::cerr << "ConfigureNotify";
68             break;
69         case Expose:
70             std::cerr << "Expose";
71             break;
72         case KeyPress:
73             std::cerr << "KeyPress";
74             break;
75         case MapNotify:
76             std::cerr << "MapNotify";
77             break;
78         case ReparentNotify:
79             std::cerr << "ReparentNotify";
80             break;
81         default:
82             std::cerr << "Event " << event.type;
83         }
84         std::cerr << " " << event.xany.window << "\n";
85     }
86 }
87
88 class GlxDrawable : public Drawable
89 {
90 public:
91     Window window;
92
93     GlxDrawable(const Visual *vis, int w, int h) :
94         Drawable(vis, w, h)
95     {
96         XVisualInfo *visinfo = static_cast<const GlxVisual *>(visual)->visinfo;
97
98         Window root = RootWindow(display, screen);
99
100         /* window attributes */
101         XSetWindowAttributes attr;
102         attr.background_pixel = 0;
103         attr.border_pixel = 0;
104         attr.colormap = XCreateColormap(display, root, visinfo->visual, AllocNone);
105         attr.event_mask = StructureNotifyMask;
106
107         unsigned long mask;
108         mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
109
110         int x = 0, y = 0;
111
112         window = XCreateWindow(
113             display, root,
114             x, y, width, height,
115             0,
116             visinfo->depth,
117             InputOutput,
118             visinfo->visual,
119             mask,
120             &attr);
121
122         XSizeHints sizehints;
123         sizehints.x = x;
124         sizehints.y = y;
125         sizehints.width  = width;
126         sizehints.height = height;
127         sizehints.flags = USSize | USPosition;
128         XSetNormalHints(display, window, &sizehints);
129
130         const char *name = "glretrace";
131         XSetStandardProperties(
132             display, window, name, name,
133             None, (char **)NULL, 0, &sizehints);
134
135         glXWaitX();
136     }
137
138     void waitForEvent(int type) {
139         XEvent event;
140         do {
141             XWindowEvent(display, window, StructureNotifyMask, &event);
142             describeEvent(event);
143         } while (event.type != type);
144     }
145
146     ~GlxDrawable() {
147         XDestroyWindow(display, window);
148     }
149
150     void
151     resize(int w, int h) {
152         if (w == width && h == height) {
153             return;
154         }
155
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.max_width  = size_hints.min_width  = w;
170         size_hints.max_height = size_hints.min_height = h;
171         size_hints.flags = PMinSize | PMaxSize;
172         XSetWMNormalHints(display, window, &size_hints);
173
174         waitForEvent(ConfigureNotify);
175
176         glXWaitX();
177     }
178
179     void show(void) {
180         if (visible) {
181             return;
182         }
183
184         glXWaitGL();
185
186         XMapWindow(display, window);
187
188         waitForEvent(MapNotify);
189
190         glXWaitX();
191
192         Drawable::show();
193     }
194
195     void swapBuffers(void) {
196         glXSwapBuffers(display, window);
197     }
198 };
199
200
201 class GlxContext : public Context
202 {
203 public:
204     GLXContext context;
205
206     GlxContext(const Visual *vis, Profile prof, GLXContext ctx) :
207         Context(vis, prof),
208         context(ctx)
209     {}
210
211     ~GlxContext() {
212         glXDestroyContext(display, context);
213     }
214 };
215
216 void
217 init(void) {
218     display = XOpenDisplay(NULL);
219     if (!display) {
220         std::cerr << "error: unable to open display " << XDisplayName(NULL) << "\n";
221         exit(1);
222     }
223
224     screen = DefaultScreen(display);
225
226     int major = 0, minor = 0;
227     glXQueryVersion(display, &major, &minor);
228     glxVersion = (major << 8) | minor;
229
230     extensions = glXQueryExtensionsString(display, screen);
231     has_GLX_ARB_create_context = checkExtension("GLX_ARB_create_context", extensions);
232 }
233
234 void
235 cleanup(void) {
236     if (display) {
237         XCloseDisplay(display);
238         display = NULL;
239     }
240 }
241
242 Visual *
243 createVisual(bool doubleBuffer, Profile profile) {
244     if (profile != PROFILE_COMPAT &&
245         profile != PROFILE_CORE) {
246         return NULL;
247     }
248
249     GlxVisual *visual = new GlxVisual;
250
251     if (glxVersion >= 0x0103) {
252         Attributes<int> attribs;
253         attribs.add(GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT);
254         attribs.add(GLX_RENDER_TYPE, GLX_RGBA_BIT);
255         attribs.add(GLX_RED_SIZE, 1);
256         attribs.add(GLX_GREEN_SIZE, 1);
257         attribs.add(GLX_BLUE_SIZE, 1);
258         attribs.add(GLX_ALPHA_SIZE, 1);
259         attribs.add(GLX_DOUBLEBUFFER, doubleBuffer ? GL_TRUE : GL_FALSE);
260         attribs.add(GLX_DEPTH_SIZE, 1);
261         attribs.add(GLX_STENCIL_SIZE, 1);
262         attribs.end();
263
264         int num_configs = 0;
265         GLXFBConfig * fbconfigs;
266         fbconfigs = glXChooseFBConfig(display, screen, attribs, &num_configs);
267         assert(num_configs && fbconfigs);
268         visual->fbconfig = fbconfigs[0];
269         assert(visual->fbconfig);
270         visual->visinfo = glXGetVisualFromFBConfig(display, visual->fbconfig);
271         assert(visual->visinfo);
272     } else {
273         Attributes<int> attribs;
274         attribs.add(GLX_RGBA);
275         attribs.add(GLX_RED_SIZE, 1);
276         attribs.add(GLX_GREEN_SIZE, 1);
277         attribs.add(GLX_BLUE_SIZE, 1);
278         attribs.add(GLX_ALPHA_SIZE, 1);
279         if (doubleBuffer) {
280             attribs.add(GLX_DOUBLEBUFFER);
281         }
282         attribs.add(GLX_DEPTH_SIZE, 1);
283         attribs.add(GLX_STENCIL_SIZE, 1);
284         attribs.end();
285
286         visual->visinfo = glXChooseVisual(display, screen, attribs);
287     }
288
289     return visual;
290 }
291
292 Drawable *
293 createDrawable(const Visual *visual, int width, int height)
294 {
295     return new GlxDrawable(visual, width, height);
296 }
297
298 Context *
299 createContext(const Visual *_visual, Context *shareContext, Profile profile)
300 {
301     const GlxVisual *visual = static_cast<const GlxVisual *>(_visual);
302     GLXContext share_context = NULL;
303     GLXContext context;
304
305     if (shareContext) {
306         share_context = static_cast<GlxContext*>(shareContext)->context;
307     }
308
309     if (glxVersion >= 0x0104 && has_GLX_ARB_create_context) {
310         Attributes<int> attribs;
311         
312         attribs.add(GLX_RENDER_TYPE, GLX_RGBA_TYPE);
313         if (debug) {
314             attribs.add(GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB);
315         }
316
317         switch (profile) {
318         case PROFILE_COMPAT:
319             break;
320         case PROFILE_CORE:
321             // XXX: This will invariable return a 3.2 context, when supported.
322             // We probably should have a PROFILE_CORE_XX per version.
323             attribs.add(GLX_CONTEXT_MAJOR_VERSION_ARB, 3);
324             attribs.add(GLX_CONTEXT_MINOR_VERSION_ARB, 2);
325             attribs.add(GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB);
326             break;
327         default:
328             return NULL;
329         }
330         
331         attribs.end();
332
333         context = glXCreateContextAttribsARB(display, visual->fbconfig, share_context, True, attribs);
334     } else {
335         if (profile != PROFILE_COMPAT) {
336             return NULL;
337         }
338
339         if (glxVersion >= 0x103) {
340             context = glXCreateNewContext(display, visual->fbconfig, GLX_RGBA_TYPE, share_context, True);
341         } else {
342             context = glXCreateContext(display, visual->visinfo, share_context, True);
343         }
344     }
345
346     if (!context) {
347         return NULL;
348     }
349
350     return new GlxContext(visual, profile, context);
351 }
352
353 bool
354 makeCurrent(Drawable *drawable, Context *context)
355 {
356     if (!drawable || !context) {
357         return glXMakeCurrent(display, None, NULL);
358     } else {
359         GlxDrawable *glxDrawable = static_cast<GlxDrawable *>(drawable);
360         GlxContext *glxContext = static_cast<GlxContext *>(context);
361
362         return glXMakeCurrent(display, glxDrawable->window, glxContext->context);
363     }
364 }
365
366 bool
367 processEvents(void) {
368     while (XPending(display) > 0) {
369         XEvent event;
370         XNextEvent(display, &event);
371         describeEvent(event);
372     }
373     return true;
374 }
375
376
377 } /* namespace glws */