1 /**************************************************************************
3 * Copyright 2011 LunarG, Inc.
4 * Copyright 2011 Jose Fonseca
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:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
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
25 **************************************************************************/
41 static Display *display = NULL;
42 static EGLDisplay eglDisplay = EGL_NO_DISPLAY;
43 static int screen = 0;
46 class EglVisual : public Visual
63 static void describeEvent(const XEvent &event) {
67 std::cerr << "ConfigureNotify";
70 std::cerr << "Expose";
73 std::cerr << "KeyPress";
76 std::cerr << "MapNotify";
79 std::cerr << "ReparentNotify";
82 std::cerr << "Event " << event.type;
84 std::cerr << " " << event.xany.window << "\n";
88 class EglDrawable : public Drawable
95 EglDrawable(const Visual *vis, int w, int h, bool pbuffer) :
96 Drawable(vis, w, h, pbuffer),
97 api(EGL_OPENGL_ES_API)
99 XVisualInfo *visinfo = static_cast<const EglVisual *>(visual)->visinfo;
101 Window root = RootWindow(display, screen);
103 /* window attributes */
104 XSetWindowAttributes attr;
105 attr.background_pixel = 0;
106 attr.border_pixel = 0;
107 attr.colormap = XCreateColormap(display, root, visinfo->visual, AllocNone);
108 attr.event_mask = StructureNotifyMask;
111 mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
115 window = XCreateWindow(
125 XSizeHints sizehints;
128 sizehints.width = width;
129 sizehints.height = height;
130 sizehints.flags = USSize | USPosition;
131 XSetNormalHints(display, window, &sizehints);
133 const char *name = "glretrace";
134 XSetStandardProperties(
135 display, window, name, name,
136 None, (char **)NULL, 0, &sizehints);
138 eglWaitNative(EGL_CORE_NATIVE_ENGINE);
140 EGLConfig config = static_cast<const EglVisual *>(visual)->config;
141 surface = eglCreateWindowSurface(eglDisplay, config, (EGLNativeWindowType)window, NULL);
144 void waitForEvent(int type) {
147 XWindowEvent(display, window, StructureNotifyMask, &event);
148 describeEvent(event);
149 } while (event.type != type);
153 eglDestroySurface(eglDisplay, surface);
155 XDestroyWindow(display, window);
156 eglWaitNative(EGL_CORE_NATIVE_ENGINE);
161 EGLContext currentContext = eglGetCurrentContext();
162 EGLSurface currentDrawSurface = eglGetCurrentSurface(EGL_DRAW);
163 EGLSurface currentReadSurface = eglGetCurrentSurface(EGL_READ);
164 bool rebindDrawSurface = currentDrawSurface == surface;
165 bool rebindReadSurface = currentReadSurface == surface;
167 if (rebindDrawSurface || rebindReadSurface) {
168 eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
171 eglDestroySurface(eglDisplay, surface);
173 EGLConfig config = static_cast<const EglVisual *>(visual)->config;
174 surface = eglCreateWindowSurface(eglDisplay, config, (EGLNativeWindowType)window, NULL);
176 if (rebindDrawSurface || rebindReadSurface) {
177 eglMakeCurrent(eglDisplay, surface, surface, currentContext);
182 resize(int w, int h) {
183 if (w == width && h == height) {
189 // We need to ensure that pending events are processed here, and XSync
190 // with discard = True guarantees that, but it appears the limited
191 // event processing we do so far is sufficient
192 //XSync(display, True);
194 Drawable::resize(w, h);
196 // Tell the window manager to respect the requested size
197 XSizeHints size_hints;
198 size_hints.max_width = size_hints.min_width = w;
199 size_hints.max_height = size_hints.min_height = h;
200 size_hints.flags = PMinSize | PMaxSize;
201 XSetWMNormalHints(display, window, &size_hints);
203 XResizeWindow(display, window, w, h);
205 waitForEvent(ConfigureNotify);
207 eglWaitNative(EGL_CORE_NATIVE_ENGINE);
210 * Some implementations won't update the backbuffer unless we recreate
217 eglQuerySurface(eglDisplay, surface, EGL_WIDTH, &eglWidth);
218 eglQuerySurface(eglDisplay, surface, EGL_HEIGHT, &eglHeight);
220 if (eglWidth != width || eglHeight != height) {
223 eglQuerySurface(eglDisplay, surface, EGL_WIDTH, &eglWidth);
224 eglQuerySurface(eglDisplay, surface, EGL_HEIGHT, &eglHeight);
227 assert(eglWidth == width);
228 assert(eglHeight == height);
238 XMapWindow(display, window);
240 waitForEvent(MapNotify);
242 eglWaitNative(EGL_CORE_NATIVE_ENGINE);
247 void copySubBuffer(int x, int y, int width, int height) {
248 printf("glws_egl_xlib:copySubBuffer: Not yet implemented\n");
252 void swapBuffers(void) {
254 eglSwapBuffers(eglDisplay, surface);
259 class EglContext : public Context
264 EglContext(const Visual *vis, Profile prof, EGLContext ctx) :
270 eglDestroyContext(eglDisplay, context);
275 * Load the symbols from the specified shared object into global namespace, so
276 * that they can be later found by dlsym(RTLD_NEXT, ...);
279 load(const char *filename)
281 if (!dlopen(filename, RTLD_GLOBAL | RTLD_LAZY)) {
282 std::cerr << "error: unable to open " << filename << "\n";
291 display = XOpenDisplay(NULL);
293 std::cerr << "error: unable to open display " << XDisplayName(NULL) << "\n";
297 screen = DefaultScreen(display);
299 eglDisplay = eglGetDisplay((EGLNativeDisplayType)display);
300 if (eglDisplay == EGL_NO_DISPLAY) {
301 std::cerr << "error: unable to get EGL display\n";
302 XCloseDisplay(display);
307 if (!eglInitialize(eglDisplay, &major, &minor)) {
308 std::cerr << "error: unable to initialize EGL display\n";
309 XCloseDisplay(display);
317 eglTerminate(eglDisplay);
318 XCloseDisplay(display);
324 createVisual(bool doubleBuffer, Profile profile) {
325 EglVisual *visual = new EglVisual();
326 // possible combinations
327 const EGLint api_bits_gl[7] = {
328 EGL_OPENGL_BIT | EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT,
329 EGL_OPENGL_BIT | EGL_OPENGL_ES_BIT,
330 EGL_OPENGL_BIT | EGL_OPENGL_ES2_BIT,
332 EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT,
336 const EGLint api_bits_gles1[7] = {
337 EGL_OPENGL_BIT | EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT,
338 EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT,
339 EGL_OPENGL_BIT | EGL_OPENGL_ES_BIT,
341 EGL_OPENGL_BIT | EGL_OPENGL_ES2_BIT,
345 const EGLint api_bits_gles2[7] = {
346 EGL_OPENGL_BIT | EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT,
347 EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT,
348 EGL_OPENGL_BIT | EGL_OPENGL_ES2_BIT,
350 EGL_OPENGL_BIT | EGL_OPENGL_ES_BIT,
354 const EGLint *api_bits;
358 api_bits = api_bits_gl;
361 api_bits = api_bits_gles1;
364 api_bits = api_bits_gles2;
370 for (int i = 0; i < 7; i++) {
371 Attributes<EGLint> attribs;
373 attribs.add(EGL_SURFACE_TYPE, EGL_WINDOW_BIT);
374 attribs.add(EGL_RED_SIZE, 1);
375 attribs.add(EGL_GREEN_SIZE, 1);
376 attribs.add(EGL_BLUE_SIZE, 1);
377 attribs.add(EGL_ALPHA_SIZE, 1);
378 attribs.add(EGL_DEPTH_SIZE, 1);
379 attribs.add(EGL_STENCIL_SIZE, 1);
380 attribs.add(EGL_RENDERABLE_TYPE, api_bits[i]);
381 attribs.end(EGL_NONE);
383 EGLint num_configs, vid;
384 if (eglChooseConfig(eglDisplay, attribs, &visual->config, 1, &num_configs) &&
386 eglGetConfigAttrib(eglDisplay, visual->config, EGL_NATIVE_VISUAL_ID, &vid)) {
390 templ.visualid = vid;
391 visual->visinfo = XGetVisualInfo(display, VisualIDMask, &templ, &num_visuals);
396 assert(visual->visinfo);
402 createDrawable(const Visual *visual, int width, int height, bool pbuffer)
404 return new EglDrawable(visual, width, height, pbuffer);
408 createContext(const Visual *_visual, Context *shareContext, Profile profile, bool debug)
410 const EglVisual *visual = static_cast<const EglVisual *>(_visual);
411 EGLContext share_context = EGL_NO_CONTEXT;
413 Attributes<EGLint> attribs;
416 share_context = static_cast<EglContext*>(shareContext)->context;
419 EGLint api = eglQueryAPI();
424 eglBindAPI(EGL_OPENGL_API);
430 load("libGLESv1_CM.so.1");
431 eglBindAPI(EGL_OPENGL_ES_API);
434 load("libGLESv2.so.2");
435 eglBindAPI(EGL_OPENGL_ES_API);
436 attribs.add(EGL_CONTEXT_CLIENT_VERSION, 2);
442 attribs.end(EGL_NONE);
444 context = eglCreateContext(eglDisplay, visual->config, share_context, attribs);
450 return new EglContext(visual, profile, context);
454 makeCurrent(Drawable *drawable, Context *context)
456 if (!drawable || !context) {
457 return eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
459 EglDrawable *eglDrawable = static_cast<EglDrawable *>(drawable);
460 EglContext *eglContext = static_cast<EglContext *>(context);
463 ok = eglMakeCurrent(eglDisplay, eglDrawable->surface,
464 eglDrawable->surface, eglContext->context);
469 eglQueryContext(eglDisplay, eglContext->context,
470 EGL_CONTEXT_CLIENT_TYPE, &api);
472 eglDrawable->api = api;
480 processEvents(void) {
481 while (XPending(display) > 0) {
483 XNextEvent(display, &event);
484 describeEvent(event);
490 } /* namespace glws */