]> git.tdb.fi Git - libs/gui.git/blobdiff - source/graphics/egl_android/glcontext.cpp
Android support
[libs/gui.git] / source / graphics / egl_android / glcontext.cpp
diff --git a/source/graphics/egl_android/glcontext.cpp b/source/graphics/egl_android/glcontext.cpp
new file mode 100644 (file)
index 0000000..ecf9a63
--- /dev/null
@@ -0,0 +1,136 @@
+#include <vector>
+#include <EGL/egl.h>
+#include <GLES2/gl2.h>
+#include <android/native_window.h>
+#include "display.h"
+#include "glcontext.h"
+#include "window_private.h"
+
+using namespace std;
+
+namespace Msp {
+namespace Graphics {
+
+struct GLContext::Private
+{
+       EGLDisplay display;
+       EGLConfig config;
+       EGLSurface surface;
+       EGLContext context;
+
+       void attach(WindowHandle);
+       void detach();
+};
+
+
+void GLContext::platform_init(const GLOptions &opts)
+{
+       EGLDisplay egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+       if(egl_display==EGL_NO_DISPLAY)
+               throw runtime_error("no egl display");
+
+       if(!eglInitialize(egl_display, 0, 0))
+               throw runtime_error("could not initialize egl");
+
+       vector<int> attribs;
+
+       attribs.push_back(EGL_COLOR_BUFFER_TYPE);
+       attribs.push_back(EGL_RGB_BUFFER);
+       attribs.push_back(EGL_RENDERABLE_TYPE);
+       attribs.push_back(EGL_OPENGL_ES2_BIT);
+       attribs.push_back(EGL_SURFACE_TYPE);
+       attribs.push_back(EGL_WINDOW_BIT);
+       attribs.push_back(EGL_DEPTH_SIZE);
+       attribs.push_back(1);
+
+       if(opts.alpha)
+       {
+               attribs.push_back(EGL_ALPHA_SIZE);
+               attribs.push_back(1);
+       }
+
+       if(opts.stencil)
+       {
+               attribs.push_back(EGL_STENCIL_SIZE);
+               attribs.push_back(1);
+       }
+
+       if(opts.multisample>0)
+       {
+               attribs.push_back(EGL_SAMPLE_BUFFERS);
+               attribs.push_back(1);
+               attribs.push_back(EGL_SAMPLES);
+               attribs.push_back(opts.multisample);
+       }
+
+       attribs.push_back(EGL_NONE);
+
+       EGLConfig config;
+       int num_configs;
+       if(!eglChooseConfig(egl_display, &attribs.front(), &config, 1, &num_configs))
+       {
+               eglTerminate(egl_display);
+               throw unsupported_gl_mode(opts);
+       }
+
+       priv = new Private;
+       priv->display = egl_display;
+       priv->config = config;
+
+       /* Must wait for the window to be available, because the calling code
+       expects GL to be usable after creation of the context. */
+       WindowHandle native_window;
+       const Window::Private &window_priv = window.get_private();
+       while(!(native_window = window_priv.window))
+               display.tick();
+
+       int format;
+       eglGetConfigAttrib(priv->display, config, EGL_NATIVE_VISUAL_ID, &format);
+       ANativeWindow_setBuffersGeometry(native_window, 0, 0, format);
+
+       priv->surface = eglCreateWindowSurface(priv->display, config, native_window, 0);
+
+       eglBindAPI(EGL_OPENGL_ES_API);
+       int context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
+       priv->context = eglCreateContext(priv->display, config, 0, context_attribs);
+
+       eglMakeCurrent(priv->display, priv->surface, priv->surface, priv->context);
+
+       window_priv.signal_window_acquired.connect(sigc::mem_fun(priv, &Private::attach));
+       window_priv.signal_window_lost.connect(sigc::mem_fun(priv, &Private::detach));
+}
+
+GLContext::~GLContext()
+{
+       eglDestroyContext(priv->display, priv->context);
+       if(priv->surface!=EGL_NO_SURFACE)
+               eglDestroySurface(priv->display, priv->surface);
+       eglTerminate(priv->display);
+       delete priv;
+}
+
+void GLContext::swap_buffers()
+{
+       eglSwapBuffers(priv->display, priv->surface);
+}
+
+void GLContext::window_resized(unsigned w, unsigned h)
+{
+       glViewport(0, 0, w, h);
+}
+
+
+void GLContext::Private::attach(WindowHandle native_window)
+{
+       surface = eglCreateWindowSurface(display, config, native_window, 0);
+       eglMakeCurrent(display, surface, surface, context);
+}
+
+void GLContext::Private::detach()
+{
+       eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+       eglDestroySurface(display, surface);
+}
+
+} // namespace Graphics
+} // namespace Msp