summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
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