diff --git a/platform/android/src/headless_view_egl.cpp b/platform/android/src/headless_view_egl.cpp index 9ceec8f8852..928400388c3 100644 --- a/platform/android/src/headless_view_egl.cpp +++ b/platform/android/src/headless_view_egl.cpp @@ -7,148 +7,195 @@ #include namespace mbgl { - -static const EGLint configAttribs[] = { - EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, - EGL_BLUE_SIZE, 8, - EGL_GREEN_SIZE, 8, - EGL_RED_SIZE, 8, - EGL_DEPTH_SIZE, 8, - EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, - 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"); - - glDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); - - EGLint major, minor; - eglInitialize(glDisplay, &major, &minor); - - EGLint numConfigs; - eglChooseConfig(glDisplay, configAttribs, &glConfig, 1, &numConfigs); - - eglBindAPI(EGL_OPENGL_API); - - glContext = eglCreateContext(glDisplay, glConfig, EGL_NO_CONTEXT, NULL); + //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"); + } + + EGLint numConfigs; + if(!eglChooseConfig(glDisplay, configAttribs, &glConfig, 1, &numConfigs)) { + throw std::runtime_error( "Could not choose config"); + } + + 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())); + } + + eglBindAPI(EGL_OPENGL_API); + + 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"); + 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; + } + */ + + //Release thread? + //eglReleaseThread(); + } + + 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::resizeFramebuffer() { + Log::Info(Event::Android, "Resize FB"); + +//Make sure we're clean +if(glSurface != EGL_NO_SURFACE) { +eglDestroySurface(glDisplay, glSurface); } -void HeadlessView::destroyContext() { - Log::Info(Event::Android, "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; - } - */ - - //Release thread? - //eglReleaseThread(); -} - -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)); -} +const int32_t w = dimensions[0] * pixelRatio; +const int32_t h = dimensions[1] * pixelRatio; -/* -void HeadlessView::resizeFramebuffer() { - Log::Info(Event::Android, "Resize FB"); - - //Make sure we're clean - if(glSurface != EGL_NO_SURFACE) { - eglDestroySurface(glDisplay, glSurface); - } - - const int32_t w = dimensions[0] * pixelRatio; - const int32_t h = dimensions[1] * pixelRatio; - - const EGLint pbufferAttribs[] = { - EGL_WIDTH, w, - EGL_HEIGHT, h, - EGL_NONE, - }; +const EGLint pbufferAttribs[] = { +EGL_WIDTH, w, +EGL_HEIGHT, h, +EGL_NONE, +}; - Log::Info(Event::Android, "Resizing pbuffer to %dx%d", w, h); +Log::Info(Event::Android, "Resizing pbuffer to %dx%d", w, h); - glSurface = eglCreatePbufferSurface(glDisplay, glConfig, pbufferAttribs); +glSurface = eglCreatePbufferSurface(glDisplay, glConfig, pbufferAttribs); - this->activateContext(); +this->activateContext(); } */ void HeadlessView::clearBuffers() { - Log::Info(Event::Android, "Clear buffers"); + 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"); - } + 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"); - } + 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