From 967dd0f58b419a5c9f967d511bd5b5270055fa96 Mon Sep 17 00:00:00 2001 From: Chia-I Wu Date: Mon, 7 Nov 2011 14:33:25 -0700 Subject: glws: Add EGL/Xlib-based implementation This is based on glws_glx, with GLX replaced by EGL. This is also the only glws implementation that supports GLESv1 and GLESv2 profiles. --- glws_egl_xlib.cpp | 385 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 385 insertions(+) create mode 100644 glws_egl_xlib.cpp (limited to 'glws_egl_xlib.cpp') diff --git a/glws_egl_xlib.cpp b/glws_egl_xlib.cpp new file mode 100644 index 00000000..da232bdd --- /dev/null +++ b/glws_egl_xlib.cpp @@ -0,0 +1,385 @@ +/************************************************************************** + * + * Copyright 2011 LunarG, Inc. + * All Rights Reserved. + * + * Based on glws_glx.cpp, which has + * + * Copyright 2011 Jose Fonseca + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + **************************************************************************/ + +#include +#include + +#include + +#include "glws.hpp" + +#include "glproc.hpp" + + +namespace glws { + + +static Display *display = NULL; +static EGLDisplay eglDisplay = EGL_NO_DISPLAY; +static int screen = 0; + + +class EglVisual : public Visual +{ +public: + EGLConfig config; + XVisualInfo *visinfo; + + EglVisual() : + config(0), + visinfo(0) + {} + + ~EglVisual() { + XFree(visinfo); + } +}; + + +static void describeEvent(const XEvent &event) { + if (0) { + switch (event.type) { + case ConfigureNotify: + std::cerr << "ConfigureNotify"; + break; + case Expose: + std::cerr << "Expose"; + break; + case KeyPress: + std::cerr << "KeyPress"; + break; + case MapNotify: + std::cerr << "MapNotify"; + break; + case ReparentNotify: + std::cerr << "ReparentNotify"; + break; + default: + std::cerr << "Event " << event.type; + } + std::cerr << " " << event.xany.window << "\n"; + } +} + +class EglDrawable : public Drawable +{ +public: + Window window; + EGLSurface surface; + EGLint api; + + EglDrawable(const Visual *vis, int w, int h) : + Drawable(vis, w, h), api(EGL_OPENGL_ES_API) + { + XVisualInfo *visinfo = dynamic_cast(visual)->visinfo; + + Window root = RootWindow(display, screen); + + /* window attributes */ + XSetWindowAttributes attr; + attr.background_pixel = 0; + attr.border_pixel = 0; + attr.colormap = XCreateColormap(display, root, visinfo->visual, AllocNone); + attr.event_mask = StructureNotifyMask; + + unsigned long mask; + mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask; + + int x = 0, y = 0; + + window = XCreateWindow( + display, root, + x, y, width, height, + 0, + visinfo->depth, + InputOutput, + visinfo->visual, + mask, + &attr); + + XSizeHints sizehints; + sizehints.x = x; + sizehints.y = y; + sizehints.width = width; + sizehints.height = height; + sizehints.flags = USSize | USPosition; + XSetNormalHints(display, window, &sizehints); + + const char *name = "glretrace"; + XSetStandardProperties( + display, window, name, name, + None, (char **)NULL, 0, &sizehints); + + eglWaitNative(EGL_CORE_NATIVE_ENGINE); + + EGLConfig config = dynamic_cast(visual)->config; + surface = eglCreateWindowSurface(eglDisplay, config, window, NULL); + } + + void waitForEvent(int type) { + XEvent event; + do { + XWindowEvent(display, window, StructureNotifyMask, &event); + describeEvent(event); + } while (event.type != type); + } + + ~EglDrawable() { + eglDestroySurface(eglDisplay, surface); + XDestroyWindow(display, window); + } + + void + resize(int w, int h) { + if (w == width && h == height) { + return; + } + + eglWaitClient(); + + // We need to ensure that pending events are processed here, and XSync + // with discard = True guarantees that, but it appears the limited + // event processing we do so far is sufficient + //XSync(display, True); + + Drawable::resize(w, h); + + XResizeWindow(display, window, w, h); + + // Tell the window manager to respect the requested size + XSizeHints size_hints; + size_hints.max_width = size_hints.min_width = w; + size_hints.max_height = size_hints.min_height = h; + size_hints.flags = PMinSize | PMaxSize; + XSetWMNormalHints(display, window, &size_hints); + + waitForEvent(ConfigureNotify); + + eglWaitNative(EGL_CORE_NATIVE_ENGINE); + } + + void show(void) { + if (visible) { + return; + } + + eglWaitClient(); + + XMapWindow(display, window); + + waitForEvent(MapNotify); + + eglWaitNative(EGL_CORE_NATIVE_ENGINE); + + Drawable::show(); + } + + void swapBuffers(void) { + eglBindAPI(api); + eglSwapBuffers(eglDisplay, surface); + } +}; + + +class EglContext : public Context +{ +public: + EGLContext context; + + EglContext(const Visual *vis, EGLContext ctx) : + Context(vis), + context(ctx) + {} + + ~EglContext() { + eglDestroyContext(eglDisplay, context); + } +}; + +void +init(void) { + display = XOpenDisplay(NULL); + if (!display) { + std::cerr << "error: unable to open display " << XDisplayName(NULL) << "\n"; + exit(1); + } + + screen = DefaultScreen(display); + + eglDisplay = eglGetDisplay(display); + if (eglDisplay == EGL_NO_DISPLAY) { + std::cerr << "error: unable to get EGL display\n"; + XCloseDisplay(display); + exit(1); + } + + EGLint major, minor; + if (!eglInitialize(eglDisplay, &major, &minor)) { + std::cerr << "error: unable to initialize EGL display\n"; + XCloseDisplay(display); + exit(1); + } +} + +void +cleanup(void) { + if (display) { + eglTerminate(eglDisplay); + XCloseDisplay(display); + display = NULL; + } +} + +Visual * +createVisual(bool doubleBuffer) { + EglVisual *visual = new EglVisual(); + // possible combinations + const EGLint api_bits[7] = { + EGL_OPENGL_BIT | EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT, + EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT, + EGL_OPENGL_BIT | EGL_OPENGL_ES_BIT, + EGL_OPENGL_BIT | EGL_OPENGL_ES2_BIT, + EGL_OPENGL_ES_BIT, + EGL_OPENGL_ES2_BIT, + EGL_OPENGL_BIT, + }; + + for (int i = 0; i < 7; i++) { + Attributes attribs; + + attribs.add(EGL_SURFACE_TYPE, EGL_WINDOW_BIT); + attribs.add(EGL_RED_SIZE, 1); + attribs.add(EGL_GREEN_SIZE, 1); + attribs.add(EGL_BLUE_SIZE, 1); + attribs.add(EGL_ALPHA_SIZE, 1); + attribs.add(EGL_DEPTH_SIZE, 1); + attribs.add(EGL_STENCIL_SIZE, 1); + attribs.add(EGL_RENDERABLE_TYPE, api_bits[i]); + attribs.end(EGL_NONE); + + EGLint num_configs, vid; + if (eglChooseConfig(eglDisplay, attribs, &visual->config, 1, &num_configs) && + num_configs == 1 && + eglGetConfigAttrib(eglDisplay, visual->config, EGL_NATIVE_VISUAL_ID, &vid)) { + XVisualInfo templ; + int num_visuals; + + templ.visualid = vid; + visual->visinfo = XGetVisualInfo(display, VisualIDMask, &templ, &num_visuals); + break; + } + } + + assert(visual->visinfo); + + return visual; +} + +Drawable * +createDrawable(const Visual *visual, int width, int height) +{ + return new EglDrawable(visual, width, height); +} + +Context * +createContext(const Visual *_visual, Context *shareContext, Profile profile) +{ + const EglVisual *visual = dynamic_cast(_visual); + EGLContext share_context = EGL_NO_CONTEXT; + EGLContext context; + Attributes attribs; + + if (shareContext) { + share_context = dynamic_cast(shareContext)->context; + } + + EGLint api = eglQueryAPI(); + + switch (profile) { + case PROFILE_COMPAT: + eglBindAPI(EGL_OPENGL_API); + break; + case PROFILE_ES1: + eglBindAPI(EGL_OPENGL_ES_API); + break; + case PROFILE_ES2: + eglBindAPI(EGL_OPENGL_ES_API); + attribs.add(EGL_CONTEXT_CLIENT_VERSION, 2); + break; + } + + attribs.end(EGL_NONE); + + context = eglCreateContext(eglDisplay, visual->config, share_context, attribs); + if (!context) + return NULL; + + eglBindAPI(api); + + return new EglContext(visual, context); +} + +bool +makeCurrent(Drawable *drawable, Context *context) +{ + if (!drawable || !context) { + return eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + } else { + EglDrawable *eglDrawable = dynamic_cast(drawable); + EglContext *eglContext = dynamic_cast(context); + EGLBoolean ok; + + ok = eglMakeCurrent(eglDisplay, eglDrawable->surface, + eglDrawable->surface, eglContext->context); + + if (ok) { + EGLint api; + + eglQueryContext(eglDisplay, eglContext->context, + EGL_CONTEXT_CLIENT_TYPE, &api); + + eglDrawable->api = api; + } + + return ok; + } +} + +bool +processEvents(void) { + while (XPending(display) > 0) { + XEvent event; + XNextEvent(display, &event); + describeEvent(event); + } + return true; +} + + +} /* namespace glws */ -- cgit v1.2.3