]> git.cworth.org Git - apitrace/blob - retrace/glws_glx.cpp
Use skiplist-based FastCallSet within trace::CallSet
[apitrace] / retrace / 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
64 processEvent(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     switch (event.type) {
89     case KeyPress:
90         {
91             char buffer[32];
92             KeySym keysym;
93             XLookupString(&event.xkey, buffer, sizeof buffer - 1, &keysym, NULL);
94             if (keysym == XK_Escape) {
95                 exit(0);
96             }
97         }
98         break;
99     }
100 }
101
102 class GlxDrawable : public Drawable
103 {
104 public:
105     Window window;
106
107     GlxDrawable(const Visual *vis, int w, int h, bool pbuffer) :
108         Drawable(vis, w, h, pbuffer)
109     {
110         XVisualInfo *visinfo = static_cast<const GlxVisual *>(visual)->visinfo;
111
112         Window root = RootWindow(display, screen);
113
114         /* window attributes */
115         XSetWindowAttributes attr;
116         attr.background_pixel = 0;
117         attr.border_pixel = 0;
118         attr.colormap = XCreateColormap(display, root, visinfo->visual, AllocNone);
119         attr.event_mask = StructureNotifyMask | KeyPressMask;
120
121         unsigned long mask;
122         mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
123
124         int x = 0, y = 0;
125
126         window = XCreateWindow(
127             display, root,
128             x, y, width, height,
129             0,
130             visinfo->depth,
131             InputOutput,
132             visinfo->visual,
133             mask,
134             &attr);
135
136         XSizeHints sizehints;
137         sizehints.x = x;
138         sizehints.y = y;
139         sizehints.width  = width;
140         sizehints.height = height;
141         sizehints.flags = USSize | USPosition;
142         XSetNormalHints(display, window, &sizehints);
143
144         const char *name = "glretrace";
145         XSetStandardProperties(
146             display, window, name, name,
147             None, (char **)NULL, 0, &sizehints);
148
149         glXWaitX();
150     }
151
152     void processKeys(void) {
153         XEvent event;
154         while (XCheckWindowEvent(display, window, StructureNotifyMask | KeyPressMask, &event)) {
155             processEvent(event);
156         }
157     }
158
159     void waitForEvent(int type) {
160         XEvent event;
161         do {
162             XWindowEvent(display, window, StructureNotifyMask | KeyPressMask, &event);
163             processEvent(event);
164         } while (event.type != type);
165     }
166
167     ~GlxDrawable() {
168         XDestroyWindow(display, window);
169     }
170
171     void
172     resize(int w, int h) {
173         if (w == width && h == height) {
174             return;
175         }
176
177         glXWaitGL();
178
179         // We need to ensure that pending events are processed here, and XSync
180         // with discard = True guarantees that, but it appears the limited
181         // event processing we do so far is sufficient
182         //XSync(display, True);
183
184         Drawable::resize(w, h);
185
186         XResizeWindow(display, window, w, h);
187
188         // Tell the window manager to respect the requested size
189         XSizeHints size_hints;
190         size_hints.max_width  = size_hints.min_width  = w;
191         size_hints.max_height = size_hints.min_height = h;
192         size_hints.flags = PMinSize | PMaxSize;
193         XSetWMNormalHints(display, window, &size_hints);
194
195         waitForEvent(ConfigureNotify);
196
197         glXWaitX();
198     }
199
200     void show(void) {
201         if (visible) {
202             return;
203         }
204
205         glXWaitGL();
206
207         XMapWindow(display, window);
208
209         waitForEvent(MapNotify);
210
211         glXWaitX();
212
213         Drawable::show();
214     }
215
216     void swapBuffers(void) {
217         glXSwapBuffers(display, window);
218
219         processKeys();
220     }
221 };
222
223
224 class GlxContext : public Context
225 {
226 public:
227     GLXContext context;
228
229     GlxContext(const Visual *vis, Profile prof, GLXContext ctx) :
230         Context(vis, prof),
231         context(ctx)
232     {}
233
234     ~GlxContext() {
235         glXDestroyContext(display, context);
236     }
237 };
238
239 void
240 init(void) {
241     XInitThreads();
242
243     display = XOpenDisplay(NULL);
244     if (!display) {
245         std::cerr << "error: unable to open display " << XDisplayName(NULL) << "\n";
246         exit(1);
247     }
248
249     screen = DefaultScreen(display);
250
251     int major = 0, minor = 0;
252     glXQueryVersion(display, &major, &minor);
253     glxVersion = (major << 8) | minor;
254
255     extensions = glXQueryExtensionsString(display, screen);
256     has_GLX_ARB_create_context = checkExtension("GLX_ARB_create_context", extensions);
257 }
258
259 void
260 cleanup(void) {
261     if (display) {
262         XCloseDisplay(display);
263         display = NULL;
264     }
265 }
266
267 Visual *
268 createVisual(bool doubleBuffer, Profile profile) {
269     if (profile != PROFILE_COMPAT &&
270         profile != PROFILE_CORE) {
271         return NULL;
272     }
273
274     GlxVisual *visual = new GlxVisual;
275
276     if (glxVersion >= 0x0103) {
277         Attributes<int> attribs;
278         attribs.add(GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT);
279         attribs.add(GLX_RENDER_TYPE, GLX_RGBA_BIT);
280         attribs.add(GLX_RED_SIZE, 1);
281         attribs.add(GLX_GREEN_SIZE, 1);
282         attribs.add(GLX_BLUE_SIZE, 1);
283         attribs.add(GLX_ALPHA_SIZE, 1);
284         attribs.add(GLX_DOUBLEBUFFER, doubleBuffer ? GL_TRUE : GL_FALSE);
285         attribs.add(GLX_DEPTH_SIZE, 1);
286         attribs.add(GLX_STENCIL_SIZE, 1);
287         attribs.end();
288
289         int num_configs = 0;
290         GLXFBConfig * fbconfigs;
291         fbconfigs = glXChooseFBConfig(display, screen, attribs, &num_configs);
292         assert(num_configs && fbconfigs);
293         visual->fbconfig = fbconfigs[0];
294         assert(visual->fbconfig);
295         visual->visinfo = glXGetVisualFromFBConfig(display, visual->fbconfig);
296         assert(visual->visinfo);
297     } else {
298         Attributes<int> attribs;
299         attribs.add(GLX_RGBA);
300         attribs.add(GLX_RED_SIZE, 1);
301         attribs.add(GLX_GREEN_SIZE, 1);
302         attribs.add(GLX_BLUE_SIZE, 1);
303         attribs.add(GLX_ALPHA_SIZE, 1);
304         if (doubleBuffer) {
305             attribs.add(GLX_DOUBLEBUFFER);
306         }
307         attribs.add(GLX_DEPTH_SIZE, 1);
308         attribs.add(GLX_STENCIL_SIZE, 1);
309         attribs.end();
310
311         visual->visinfo = glXChooseVisual(display, screen, attribs);
312     }
313
314     return visual;
315 }
316
317 Drawable *
318 createDrawable(const Visual *visual, int width, int height, bool pbuffer)
319 {
320     return new GlxDrawable(visual, width, height, pbuffer);
321 }
322
323 Context *
324 createContext(const Visual *_visual, Context *shareContext, Profile profile, bool debug)
325 {
326     const GlxVisual *visual = static_cast<const GlxVisual *>(_visual);
327     GLXContext share_context = NULL;
328     GLXContext context;
329
330     if (shareContext) {
331         share_context = static_cast<GlxContext*>(shareContext)->context;
332     }
333
334     if (glxVersion >= 0x0104 && has_GLX_ARB_create_context) {
335         Attributes<int> attribs;
336         
337         attribs.add(GLX_RENDER_TYPE, GLX_RGBA_TYPE);
338         if (debug) {
339             attribs.add(GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB);
340         }
341
342         switch (profile) {
343         case PROFILE_COMPAT:
344             break;
345         case PROFILE_CORE:
346             // XXX: This will invariable return a 3.2 context, when supported.
347             // We probably should have a PROFILE_CORE_XX per version.
348             attribs.add(GLX_CONTEXT_MAJOR_VERSION_ARB, 3);
349             attribs.add(GLX_CONTEXT_MINOR_VERSION_ARB, 2);
350             attribs.add(GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB);
351             break;
352         default:
353             return NULL;
354         }
355         
356         attribs.end();
357
358         context = glXCreateContextAttribsARB(display, visual->fbconfig, share_context, True, attribs);
359     } else {
360         if (profile != PROFILE_COMPAT) {
361             return NULL;
362         }
363
364         if (glxVersion >= 0x103) {
365             context = glXCreateNewContext(display, visual->fbconfig, GLX_RGBA_TYPE, share_context, True);
366         } else {
367             context = glXCreateContext(display, visual->visinfo, share_context, True);
368         }
369     }
370
371     if (!context) {
372         return NULL;
373     }
374
375     return new GlxContext(visual, profile, context);
376 }
377
378 bool
379 makeCurrent(Drawable *drawable, Context *context)
380 {
381     if (!drawable || !context) {
382         return glXMakeCurrent(display, None, NULL);
383     } else {
384         GlxDrawable *glxDrawable = static_cast<GlxDrawable *>(drawable);
385         GlxContext *glxContext = static_cast<GlxContext *>(context);
386
387         return glXMakeCurrent(display, glxDrawable->window, glxContext->context);
388     }
389 }
390
391 bool
392 processEvents(void) {
393     while (XPending(display) > 0) {
394         XEvent event;
395         XNextEvent(display, &event);
396         processEvent(event);
397     }
398     return true;
399 }
400
401
402 } /* namespace glws */