]> git.cworth.org Git - apitrace/blob - glws_egl_xlib.cpp
Encode format as a member and not part of the label.
[apitrace] / glws_egl_xlib.cpp
1 /**************************************************************************
2  *
3  * Copyright 2011 LunarG, Inc.
4  * Copyright 2011 Jose Fonseca
5  * All Rights Reserved.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy
8  * of this software and associated documentation files (the "Software"), to deal
9  * in the Software without restriction, including without limitation the rights
10  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11  * copies of the Software, and to permit persons to whom the Software is
12  * furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in
15  * all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23  * THE SOFTWARE.
24  *
25  **************************************************************************/
26
27 #include <assert.h>
28 #include <stdlib.h>
29
30 #include <iostream>
31
32 #include "glws.hpp"
33
34 #include "glproc.hpp"
35
36
37 namespace glws {
38
39
40 static Display *display = NULL;
41 static EGLDisplay eglDisplay = EGL_NO_DISPLAY;
42 static int screen = 0;
43
44
45 class EglVisual : public Visual
46 {
47 public:
48     EGLConfig config;
49     XVisualInfo *visinfo;
50
51     EglVisual() :
52         config(0),
53         visinfo(0)
54     {}
55
56     ~EglVisual() {
57         XFree(visinfo);
58     }
59 };
60
61
62 static void describeEvent(const XEvent &event) {
63     if (0) {
64         switch (event.type) {
65         case ConfigureNotify:
66             std::cerr << "ConfigureNotify";
67             break;
68         case Expose:
69             std::cerr << "Expose";
70             break;
71         case KeyPress:
72             std::cerr << "KeyPress";
73             break;
74         case MapNotify:
75             std::cerr << "MapNotify";
76             break;
77         case ReparentNotify:
78             std::cerr << "ReparentNotify";
79             break;
80         default:
81             std::cerr << "Event " << event.type;
82         }
83         std::cerr << " " << event.xany.window << "\n";
84     }
85 }
86
87 class EglDrawable : public Drawable
88 {
89 public:
90     Window window;
91     EGLSurface surface;
92     EGLint api;
93
94     EglDrawable(const Visual *vis, int w, int h) :
95         Drawable(vis, w, h), api(EGL_OPENGL_ES_API)
96     {
97         XVisualInfo *visinfo = dynamic_cast<const EglVisual *>(visual)->visinfo;
98
99         Window root = RootWindow(display, screen);
100
101         /* window attributes */
102         XSetWindowAttributes attr;
103         attr.background_pixel = 0;
104         attr.border_pixel = 0;
105         attr.colormap = XCreateColormap(display, root, visinfo->visual, AllocNone);
106         attr.event_mask = StructureNotifyMask;
107
108         unsigned long mask;
109         mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
110
111         int x = 0, y = 0;
112
113         window = XCreateWindow(
114             display, root,
115             x, y, width, height,
116             0,
117             visinfo->depth,
118             InputOutput,
119             visinfo->visual,
120             mask,
121             &attr);
122
123         XSizeHints sizehints;
124         sizehints.x = x;
125         sizehints.y = y;
126         sizehints.width  = width;
127         sizehints.height = height;
128         sizehints.flags = USSize | USPosition;
129         XSetNormalHints(display, window, &sizehints);
130
131         const char *name = "glretrace";
132         XSetStandardProperties(
133             display, window, name, name,
134             None, (char **)NULL, 0, &sizehints);
135
136         eglWaitNative(EGL_CORE_NATIVE_ENGINE);
137
138         EGLConfig config = dynamic_cast<const EglVisual *>(visual)->config;
139         surface = eglCreateWindowSurface(eglDisplay, config, window, NULL);
140     }
141
142     void waitForEvent(int type) {
143         XEvent event;
144         do {
145             XWindowEvent(display, window, StructureNotifyMask, &event);
146             describeEvent(event);
147         } while (event.type != type);
148     }
149
150     ~EglDrawable() {
151         eglDestroySurface(eglDisplay, surface);
152         XDestroyWindow(display, window);
153     }
154
155     void
156     resize(int w, int h) {
157         if (w == width && h == height) {
158             return;
159         }
160
161         eglWaitClient();
162
163         // We need to ensure that pending events are processed here, and XSync
164         // with discard = True guarantees that, but it appears the limited
165         // event processing we do so far is sufficient
166         //XSync(display, True);
167
168         Drawable::resize(w, h);
169
170         XResizeWindow(display, window, w, h);
171
172         // Tell the window manager to respect the requested size
173         XSizeHints size_hints;
174         size_hints.max_width  = size_hints.min_width  = w;
175         size_hints.max_height = size_hints.min_height = h;
176         size_hints.flags = PMinSize | PMaxSize;
177         XSetWMNormalHints(display, window, &size_hints);
178
179         waitForEvent(ConfigureNotify);
180
181         eglWaitNative(EGL_CORE_NATIVE_ENGINE);
182     }
183
184     void show(void) {
185         if (visible) {
186             return;
187         }
188
189         eglWaitClient();
190
191         XMapWindow(display, window);
192
193         waitForEvent(MapNotify);
194
195         eglWaitNative(EGL_CORE_NATIVE_ENGINE);
196
197         Drawable::show();
198     }
199
200     void swapBuffers(void) {
201         eglBindAPI(api);
202         eglSwapBuffers(eglDisplay, surface);
203     }
204 };
205
206
207 class EglContext : public Context
208 {
209 public:
210     EGLContext context;
211
212     EglContext(const Visual *vis, EGLContext ctx) :
213         Context(vis),
214         context(ctx)
215     {}
216
217     ~EglContext() {
218         eglDestroyContext(eglDisplay, context);
219     }
220 };
221
222 void
223 init(void) {
224     display = XOpenDisplay(NULL);
225     if (!display) {
226         std::cerr << "error: unable to open display " << XDisplayName(NULL) << "\n";
227         exit(1);
228     }
229
230     screen = DefaultScreen(display);
231
232     eglDisplay = eglGetDisplay(display);
233     if (eglDisplay == EGL_NO_DISPLAY) {
234         std::cerr << "error: unable to get EGL display\n";
235         XCloseDisplay(display);
236         exit(1);
237     }
238
239     EGLint major, minor;
240     if (!eglInitialize(eglDisplay, &major, &minor)) {
241         std::cerr << "error: unable to initialize EGL display\n";
242         XCloseDisplay(display);
243         exit(1);
244     }
245 }
246
247 void
248 cleanup(void) {
249     if (display) {
250         eglTerminate(eglDisplay);
251         XCloseDisplay(display);
252         display = NULL;
253     }
254 }
255
256 Visual *
257 createVisual(bool doubleBuffer) {
258     EglVisual *visual = new EglVisual();
259     // possible combinations
260     const EGLint api_bits[7] = {
261         EGL_OPENGL_BIT | EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT,
262         EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT,
263         EGL_OPENGL_BIT | EGL_OPENGL_ES_BIT,
264         EGL_OPENGL_BIT | EGL_OPENGL_ES2_BIT,
265         EGL_OPENGL_ES_BIT,
266         EGL_OPENGL_ES2_BIT,
267         EGL_OPENGL_BIT,
268     };
269
270     for (int i = 0; i < 7; i++) {
271         Attributes<EGLint> attribs;
272
273         attribs.add(EGL_SURFACE_TYPE, EGL_WINDOW_BIT);
274         attribs.add(EGL_RED_SIZE, 1);
275         attribs.add(EGL_GREEN_SIZE, 1);
276         attribs.add(EGL_BLUE_SIZE, 1);
277         attribs.add(EGL_ALPHA_SIZE, 1);
278         attribs.add(EGL_DEPTH_SIZE, 1);
279         attribs.add(EGL_STENCIL_SIZE, 1);
280         attribs.add(EGL_RENDERABLE_TYPE, api_bits[i]);
281         attribs.end(EGL_NONE);
282
283         EGLint num_configs, vid;
284         if (eglChooseConfig(eglDisplay, attribs, &visual->config, 1, &num_configs) &&
285             num_configs == 1 &&
286             eglGetConfigAttrib(eglDisplay, visual->config, EGL_NATIVE_VISUAL_ID, &vid)) {
287             XVisualInfo templ;
288             int num_visuals;
289
290             templ.visualid = vid;
291             visual->visinfo = XGetVisualInfo(display, VisualIDMask, &templ, &num_visuals);
292             break;
293         }
294     }
295
296     assert(visual->visinfo);
297
298     return visual;
299 }
300
301 Drawable *
302 createDrawable(const Visual *visual, int width, int height)
303 {
304     return new EglDrawable(visual, width, height);
305 }
306
307 Context *
308 createContext(const Visual *_visual, Context *shareContext, Profile profile)
309 {
310     const EglVisual *visual = dynamic_cast<const EglVisual *>(_visual);
311     EGLContext share_context = EGL_NO_CONTEXT;
312     EGLContext context;
313     Attributes<EGLint> attribs;
314
315     if (shareContext) {
316         share_context = dynamic_cast<EglContext*>(shareContext)->context;
317     }
318
319     EGLint api = eglQueryAPI();
320
321     switch (profile) {
322     case PROFILE_COMPAT:
323         eglBindAPI(EGL_OPENGL_API);
324         break;
325     case PROFILE_ES1:
326         eglBindAPI(EGL_OPENGL_ES_API);
327         break;
328     case PROFILE_ES2:
329         eglBindAPI(EGL_OPENGL_ES_API);
330         attribs.add(EGL_CONTEXT_CLIENT_VERSION, 2);
331         break;
332     }
333
334     attribs.end(EGL_NONE);
335
336     context = eglCreateContext(eglDisplay, visual->config, share_context, attribs);
337     if (!context)
338         return NULL;
339
340     eglBindAPI(api);
341
342     return new EglContext(visual, context);
343 }
344
345 bool
346 makeCurrent(Drawable *drawable, Context *context)
347 {
348     if (!drawable || !context) {
349         return eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
350     } else {
351         EglDrawable *eglDrawable = dynamic_cast<EglDrawable *>(drawable);
352         EglContext *eglContext = dynamic_cast<EglContext *>(context);
353         EGLBoolean ok;
354
355         ok = eglMakeCurrent(eglDisplay, eglDrawable->surface,
356                             eglDrawable->surface, eglContext->context);
357
358         if (ok) {
359             EGLint api;
360
361             eglQueryContext(eglDisplay, eglContext->context,
362                             EGL_CONTEXT_CLIENT_TYPE, &api);
363
364             eglDrawable->api = api;
365         }
366
367         return ok;
368     }
369 }
370
371 bool
372 processEvents(void) {
373     while (XPending(display) > 0) {
374         XEvent event;
375         XNextEvent(display, &event);
376         describeEvent(event);
377     }
378     return true;
379 }
380
381
382 } /* namespace glws */