summaryrefslogtreecommitdiff
path: root/glws_egl_xlib.cpp
diff options
context:
space:
mode:
authorChia-I Wu <olvaffe@gmail.com>2011-11-07 14:33:25 -0700
committerJosé Fonseca <jose.r.fonseca@gmail.com>2011-11-17 15:50:26 +0000
commit967dd0f58b419a5c9f967d511bd5b5270055fa96 (patch)
tree8ed81f46d61ec9f3eefccea5619ff4112959e88e /glws_egl_xlib.cpp
parentd56c5318f7ba4855ee79b0deaf4549212f3e4780 (diff)
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.
Diffstat (limited to 'glws_egl_xlib.cpp')
-rw-r--r--glws_egl_xlib.cpp385
1 files changed, 385 insertions, 0 deletions
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 <assert.h>
+#include <stdlib.h>
+
+#include <iostream>
+
+#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<const EglVisual *>(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<const EglVisual *>(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<EGLint> 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<const EglVisual *>(_visual);
+ EGLContext share_context = EGL_NO_CONTEXT;
+ EGLContext context;
+ Attributes<EGLint> attribs;
+
+ if (shareContext) {
+ share_context = dynamic_cast<EglContext*>(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<EglDrawable *>(drawable);
+ EglContext *eglContext = dynamic_cast<EglContext *>(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 */