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