summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIvo van Dongen <info@ivovandongen.nl>2016-07-01 16:48:43 +0200
committerIvo van Dongen <info@ivovandongen.nl>2016-10-25 16:48:26 +0200
commitc590d31fac54c20418acacb22afd47fd87f992ca (patch)
tree73b8b37cbdee237db184b0d9e1fee7e06e427b5b
parent848f2c24cfbe9d1c32cfdd6988067cb58cd691c8 (diff)
downloadqtlocation-mapboxgl-c590d31fac54c20418acacb22afd47fd87f992ca.tar.gz
[android] headless view for egl
-rw-r--r--include/mbgl/platform/default/headless_view.hpp10
-rw-r--r--platform/android/src/headless_view_egl.cpp177
2 files changed, 187 insertions, 0 deletions
diff --git a/include/mbgl/platform/default/headless_view.hpp b/include/mbgl/platform/default/headless_view.hpp
index 23f1e8251a..0a921b93f2 100644
--- a/include/mbgl/platform/default/headless_view.hpp
+++ b/include/mbgl/platform/default/headless_view.hpp
@@ -10,6 +10,9 @@ class QGLWidget;
#else
#define MBGL_USE_CGL 1
#endif
+#elif __ANDROID__
+#include <EGL/egl.h>
+#define MBGL_USE_EGL 1
#else
#define GL_GLEXT_PROTOTYPES
#define MBGL_USE_GLX 1
@@ -89,6 +92,13 @@ private:
GLXPbuffer glxPbuffer = 0;
#endif
+#if MBGL_USE_EGL
+ EGLDisplay glDisplay = EGL_NO_DISPLAY;
+ EGLConfig glConfig = nullptr;
+ EGLSurface glSurface = EGL_NO_SURFACE;
+ EGLContext glContext = EGL_NO_CONTEXT;
+#endif
+
std::function<void(MapChange)> mapChangeCallback;
gl::FramebufferID fbo = 0;
diff --git a/platform/android/src/headless_view_egl.cpp b/platform/android/src/headless_view_egl.cpp
new file mode 100644
index 0000000000..51a8509f31
--- /dev/null
+++ b/platform/android/src/headless_view_egl.cpp
@@ -0,0 +1,177 @@
+#include <mbgl/platform/default/headless_view.hpp>
+#include <mbgl/platform/default/headless_display.hpp>
+#include <mbgl/platform/log.hpp>
+
+#include <cassert>
+
+#include <EGL/egl.h>
+
+namespace mbgl {
+
+//Android seems to be very specific here...,
+static const EGLint configAttribs[] = {
+ EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL_RED_SIZE, 8,
+ EGL_GREEN_SIZE, 8,
+ EGL_BLUE_SIZE, 8,
+ EGL_ALPHA_SIZE, 8,
+ EGL_DEPTH_SIZE, 0,
+ EGL_STENCIL_SIZE, 0,
+ EGL_NONE
+};
+
+gl::glProc HeadlessView::initializeExtension(const char* name) {
+ Log::Info(Event::Android, "Initialize extension: %s", name);
+ return eglGetProcAddress(name);
+}
+
+void HeadlessView::createContext() {
+ Log::Info(Event::Android, "Create context");
+
+ //Connect to display system
+ glDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ if(glDisplay == EGL_NO_DISPLAY){
+ throw std::runtime_error("Could not connect to display");
+ }
+
+ //Initialize
+ EGLint major, minor;
+ if(!eglInitialize(glDisplay, &major, &minor)) {
+ Log::Error(Event::Android, "Could not initialize egl");
+ }
+
+ //Choose a matching configuration
+ EGLint numConfigs;
+ if(!eglChooseConfig(glDisplay, configAttribs, &glConfig, 1, &numConfigs)) {
+ throw std::runtime_error( "Could not choose config");
+ }
+
+ //Create a PBuffer surface (in conjunction with EGL_SURFACE_TYPE, EGL_PBUFFER_BIT)
+ EGLint surfAttribs[] = {
+ EGL_WIDTH, 512,
+ EGL_HEIGHT, 512,
+ EGL_LARGEST_PBUFFER, EGL_TRUE,
+ EGL_NONE
+ };
+
+ glSurface = eglCreatePbufferSurface(glDisplay, glConfig, surfAttribs);
+ if(glSurface == EGL_NO_SURFACE) {
+ throw std::runtime_error("Could not create surface: " + std::to_string(eglGetError()));
+ }
+
+ //Bind
+ eglBindAPI(EGL_OPENGL_API);
+
+
+ //And, create the context finally
+ GLint contextAttrs[] =
+ {
+ EGL_CONTEXT_CLIENT_VERSION, 2,
+ EGL_NONE
+ };
+ glContext = eglCreateContext(glDisplay, glConfig, EGL_NO_CONTEXT, contextAttrs);
+
+ if (glContext == EGL_NO_CONTEXT) {
+ throw std::runtime_error("Could not create context");
+ }
+}
+
+void HeadlessView::destroyContext() {
+ Log::Info(Event::Android, "Destroy context");
+
+ //Destroy context
+ if (glContext != EGL_NO_CONTEXT) {
+ eglDestroyContext(glDisplay, glContext);
+ glContext = EGL_NO_CONTEXT;
+ }
+
+ //Destroy surface
+ if (glSurface != EGL_NO_SURFACE) {
+ eglDestroySurface(glDisplay, glSurface);
+ glSurface = EGL_NO_SURFACE;
+ }
+
+ //Terminate display
+ if(glDisplay != EGL_NO_DISPLAY) {
+ eglTerminate(glDisplay);
+ glDisplay = EGL_NO_DISPLAY;
+ }
+}
+
+void HeadlessView::resizeFramebuffer() {
+ const unsigned int w = dimensions[0] * pixelRatio;
+ const unsigned int h = dimensions[1] * pixelRatio;
+
+ // Create depth/stencil buffer
+ MBGL_CHECK_ERROR(glGenRenderbuffers(1, &fboDepthStencil));
+ MBGL_CHECK_ERROR(glBindRenderbuffer(GL_RENDERBUFFER, fboDepthStencil));
+ MBGL_CHECK_ERROR(glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES, w, h));
+ MBGL_CHECK_ERROR(glBindRenderbuffer(GL_RENDERBUFFER, 0));
+
+ MBGL_CHECK_ERROR(glGenRenderbuffers(1, &fboColor));
+ MBGL_CHECK_ERROR(glBindRenderbuffer(GL_RENDERBUFFER, fboColor));
+ MBGL_CHECK_ERROR(glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8_OES, w, h));
+ MBGL_CHECK_ERROR(glBindRenderbuffer(GL_RENDERBUFFER, 0));
+
+ MBGL_CHECK_ERROR(glGenFramebuffers(1, &fbo));
+ MBGL_CHECK_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, fbo));
+
+ MBGL_CHECK_ERROR(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, fboColor));
+ MBGL_CHECK_ERROR(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, fboDepthStencil));
+ MBGL_CHECK_ERROR(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fboDepthStencil));
+
+ GLenum status = MBGL_CHECK_ERROR(glCheckFramebufferStatus(GL_FRAMEBUFFER));
+
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ std::string error("Couldn't create framebuffer: ");
+ switch (status) {
+ case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: (error += "incomplete attachment"); break;
+ case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: error += "incomplete missing attachment"; break;
+ case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: error += "incomplete dimensions"; break;
+ case GL_FRAMEBUFFER_UNSUPPORTED: error += "unsupported"; break;
+ default: error += "other"; break;
+ }
+ throw std::runtime_error(error);
+ }
+
+ MBGL_CHECK_ERROR(glViewport(0, 0, w, h));
+}
+
+void HeadlessView::clearBuffers() {
+ Log::Info(Event::Android, "Clear buffers");
+ MBGL_CHECK_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, 0));
+
+ if (fbo) {
+ MBGL_CHECK_ERROR(glDeleteFramebuffers(1, &fbo));
+ fbo = 0;
+ }
+
+ if (fboColor) {
+ MBGL_CHECK_ERROR(glDeleteRenderbuffers(1, &fboColor));
+ fboColor = 0;
+ }
+
+ if (fboDepthStencil) {
+ MBGL_CHECK_ERROR(glDeleteRenderbuffers(1, &fboDepthStencil));
+ fboDepthStencil = 0;
+ }
+}
+
+void HeadlessView::activateContext() {
+ Log::Info(Event::Android, "Activate context");
+ if(eglMakeCurrent(glDisplay, glSurface, glSurface, glContext) != EGL_TRUE) {
+ Log::Info(Event::Android, "Error activating context");
+ throw std::runtime_error("Error activating context");
+ }
+}
+
+void HeadlessView::deactivateContext() {
+ Log::Info(Event::Android, "Deactivate context");
+ if(eglMakeCurrent(glDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT) != EGL_TRUE) {
+ Log::Info(Event::Android, "Error deactivating context");
+ throw std::runtime_error("Error deactivating context");
+ }
+}
+
+} // namespace mbgl