summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTiago Vignatti <tvignatti@gmail.com>2016-08-01 17:30:43 +0300
committerBruno de Oliveira Abinader <bruno@mapbox.com>2016-11-17 01:01:15 +0100
commit32b6f2fa0383f04855a181f6db61df84968ec97c (patch)
treeb47e1f03cb06924d16ac1a514dc4727ea0053b75
parent50f0f919c38a905b8b169fcbd3e77c03bf48d17b (diff)
downloadqtlocation-mapboxgl-32b6f2fa0383f04855a181f6db61df84968ec97c.tar.gz
[linux] Implement EGL headless backend
Original author: Tiago Vignatti <tvignatti@gmail.com> Calling X11 window system is superfluous for headless rendering. This patch implements EGL platform using GBM, which is slightly more simple than the GLX path when using X11. In principle there are no big advantages in terms of performance etc. My motivation behind this was to get in touch with the code and the project. For testing I'm using: $ unset DISPLAY && ./build/linux-x86_64/Debug/mbgl-test v2: rebased patch against the new cmake changes; walk through render node to find a valid one; remove EGLSurface completely cause windows are not needed here.
m---------.mason0
-rw-r--r--CMakeLists.txt8
-rw-r--r--Makefile3
-rw-r--r--platform/default/glfw_view.cpp2
-rw-r--r--platform/linux/config.cmake16
-rw-r--r--platform/linux/src/headless_backend_egl.cpp75
-rw-r--r--platform/linux/src/headless_display_egl.cpp56
7 files changed, 157 insertions, 3 deletions
diff --git a/.mason b/.mason
-Subproject 43933edabaca8f877f270466d20759fe84e62b2
+Subproject 4fff08aefa99f79252c4bb5a0c6c42ca32534eb
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 10d1076e29..064710780f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -15,15 +15,23 @@ include(.mason/mason.cmake)
option(WITH_CXX11ABI "Use cxx11abi mason packages" OFF)
option(WITH_COVERAGE "Enable coverage reports" OFF)
option(WITH_OSMESA "Use OSMesa headless backend" OFF)
+option(WITH_EGL "Use EGL backend" OFF)
option(IS_CI_BUILD "Continuous integration build" OFF)
if(WITH_CXX11ABI)
set(MASON_CXXABI_SUFFIX -cxx11abi)
endif()
+if(WITH_OSMESA AND WITH_EGL)
+ message(FATAL_ERROR "WITH_OSMESA and WITH_EGL are mutually exclusive.")
+endif()
+
if(WITH_OSMESA)
# Default mesa mason binary is OSMesa.
set(MASON_MESA_SUFFIX "")
+elseif(WITH_EGL)
+ add_definitions(-DMBGL_USE_GLES2=1)
+ set(MASON_MESA_SUFFIX "-egl")
else()
set(MASON_MESA_SUFFIX "-glx")
endif()
diff --git a/Makefile b/Makefile
index b061f2a3f2..999a4efa79 100644
--- a/Makefile
+++ b/Makefile
@@ -295,7 +295,8 @@ $(LINUX_BUILD): $(BUILD_DEPS)
-DWITH_CXX11ABI=$(shell scripts/check-cxx11abi.sh) \
-DWITH_COVERAGE=${WITH_COVERAGE} \
-DIS_CI_BUILD=${CI} \
- -DWITH_OSMESA=${WITH_OSMESA})
+ -DWITH_OSMESA=${WITH_OSMESA} \
+ -DWITH_EGL=${WITH_EGL})
.PHONY: linux
linux: glfw-app render offline
diff --git a/platform/default/glfw_view.cpp b/platform/default/glfw_view.cpp
index a8fa17548d..07959b2002 100644
--- a/platform/default/glfw_view.cpp
+++ b/platform/default/glfw_view.cpp
@@ -172,6 +172,7 @@ void GLFWView::onKey(GLFWwindow *window, int key, int /*scancode*/, int action,
}
}
break;
+#if not MBGL_USE_GLES2
case GLFW_KEY_B: {
auto debug = view->map->getDebug();
if (debug & mbgl::MapDebugOptions::StencilClip) {
@@ -184,6 +185,7 @@ void GLFWView::onKey(GLFWwindow *window, int key, int /*scancode*/, int action,
}
view->map->setDebug(debug);
} break;
+#endif // MBGL_USE_GLES2
case GLFW_KEY_N:
if (!mods)
view->map->resetNorth();
diff --git a/platform/linux/config.cmake b/platform/linux/config.cmake
index b4bc030064..d2f3d3aa94 100644
--- a/platform/linux/config.cmake
+++ b/platform/linux/config.cmake
@@ -1,5 +1,5 @@
mason_use(glfw VERSION 3.2.1)
-if (WITH_OSMESA OR IS_CI_BUILD)
+if(IS_CI_BUILD)
mason_use(mesa VERSION 13.0.0${MASON_MESA_SUFFIX}${MASON_CXXABI_SUFFIX})
endif()
mason_use(boost_libprogram_options VERSION 1.60.0)
@@ -15,12 +15,24 @@ mason_use(benchmark VERSION 1.0.0)
include(cmake/loop-uv.cmake)
macro(mbgl_platform_core)
- if (WITH_OSMESA)
+ if(WITH_OSMESA)
target_sources(mbgl-core
PRIVATE platform/default/headless_backend_osmesa.cpp
PRIVATE platform/default/headless_display.cpp
)
target_add_mason_package(mbgl-core PUBLIC mesa)
+ elseif(WITH_EGL)
+ target_sources(mbgl-core
+ PRIVATE platform/linux/src/headless_backend_egl.cpp
+ PRIVATE platform/linux/src/headless_display_egl.cpp
+ )
+ # TODO: Provide surface-less EGL mesa for CI builds.
+ # https://github.com/mapbox/mapbox-gl-native/issues/7020
+ target_link_libraries(mbgl-core
+ PUBLIC -lGLESv2
+ PUBLIC -lEGL
+ PUBLIC -lgbm
+ )
else()
target_sources(mbgl-core
PRIVATE platform/linux/src/headless_backend_glx.cpp
diff --git a/platform/linux/src/headless_backend_egl.cpp b/platform/linux/src/headless_backend_egl.cpp
new file mode 100644
index 0000000000..5c68976ada
--- /dev/null
+++ b/platform/linux/src/headless_backend_egl.cpp
@@ -0,0 +1,75 @@
+#include <mbgl/platform/default/headless_backend.hpp>
+#include <mbgl/platform/default/headless_display.hpp>
+
+#include <mbgl/platform/log.hpp>
+
+#include <EGL/egl.h>
+
+#include <cassert>
+
+namespace mbgl {
+
+struct EGLImpl : public HeadlessBackend::Impl {
+ EGLImpl(EGLContext glContext_, EGLDisplay display_)
+ : glContext(glContext_),
+ display(display_) {
+ }
+
+ ~EGLImpl() {
+ if (glContext != eglGetCurrentContext()) {
+ activateContext();
+ }
+ if (!eglDestroyContext(display, glContext)) {
+ throw std::runtime_error("Failed to destroy EGL context.\n");
+ }
+ }
+
+ void activateContext() final {
+ if (!eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, glContext)) {
+ throw std::runtime_error("Switching OpenGL context failed.\n");
+ }
+ }
+
+ void deactivateContext() final {
+ if (!eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
+ throw std::runtime_error("Removing OpenGL context failed.\n");
+ }
+ }
+
+ EGLContext glContext = EGL_NO_CONTEXT;
+ EGLDisplay display = EGL_NO_DISPLAY;
+};
+
+gl::glProc HeadlessBackend::initializeExtension(const char* name) {
+ return eglGetProcAddress(name);
+}
+
+bool HeadlessBackend::hasDisplay() {
+ if (!display) {
+ display.reset(new HeadlessDisplay);
+ }
+ return bool(display);
+};
+
+void HeadlessBackend::createContext() {
+ assert(!hasContext());
+ assert(hasDisplay());
+
+ EGLDisplay display_ = display->attribute<EGLDisplay>();
+ EGLConfig& config = display->attribute<EGLConfig&>();
+
+ if (!eglBindAPI(EGL_OPENGL_API)) {
+ throw std::runtime_error("Error setting the EGL rendering API.\n");
+ }
+
+ EGLContext glContext = eglCreateContext(display_, config, EGL_NO_CONTEXT, NULL);
+ if (glContext == EGL_NO_CONTEXT) {
+ mbgl::Log::Error(mbgl::Event::OpenGL, "eglCreateContext() returned error 0x%04x",
+ eglGetError());
+ throw std::runtime_error("Error creating the EGL context object.\n");
+ }
+
+ impl.reset(new EGLImpl(glContext, display_));
+}
+
+} // namespace mbgl
diff --git a/platform/linux/src/headless_display_egl.cpp b/platform/linux/src/headless_display_egl.cpp
new file mode 100644
index 0000000000..2c0481ddd1
--- /dev/null
+++ b/platform/linux/src/headless_display_egl.cpp
@@ -0,0 +1,56 @@
+#include <mbgl/platform/default/headless_display.hpp>
+#include <mbgl/util/string.hpp>
+
+#include <EGL/egl.h>
+
+namespace mbgl {
+
+class HeadlessDisplay::Impl {
+public:
+ Impl();
+ ~Impl();
+
+ EGLDisplay display = EGL_NO_DISPLAY;
+ EGLConfig config = 0;
+};
+
+HeadlessDisplay::Impl::Impl() {
+ display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ if (display == EGL_NO_DISPLAY) {
+ throw std::runtime_error("Failed to obtain a valid EGL display.\n");
+ }
+
+ EGLint major, minor, numConfigs;
+ if (!eglInitialize(display, &major, &minor)) {
+ throw std::runtime_error("eglInitialize() failed.\n");
+ }
+
+ // This shouldn't matter as we're rendering to a framebuffer.
+ const EGLint attribs[] = { EGL_NONE };
+ if (!eglChooseConfig(display, attribs, &config, 1, &numConfigs) || numConfigs != 1) {
+ throw std::runtime_error("Failed to choose ARGB config.\n");
+ }
+}
+
+HeadlessDisplay::Impl::~Impl() {
+ eglTerminate(display);
+}
+
+template <>
+EGLDisplay HeadlessDisplay::attribute() const {
+ return impl->display;
+}
+
+template <>
+EGLConfig& HeadlessDisplay::attribute() const {
+ return impl->config;
+}
+
+HeadlessDisplay::HeadlessDisplay()
+ : impl(std::make_unique<Impl>()) {
+}
+
+HeadlessDisplay::~HeadlessDisplay() {
+}
+
+} // namespace mbgl