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