summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/mbgl/platform/default/headless_backend.hpp59
-rw-r--r--platform/darwin/src/headless_backend_cgl.cpp58
-rw-r--r--platform/darwin/src/headless_backend_eagl.mm42
-rw-r--r--platform/default/headless_backend.cpp24
-rw-r--r--platform/default/headless_backend_osmesa.cpp61
-rw-r--r--platform/linux/src/headless_backend_glx.cpp92
-rw-r--r--platform/qt/test/headless_backend_qt.cpp35
7 files changed, 213 insertions, 158 deletions
diff --git a/include/mbgl/platform/default/headless_backend.hpp b/include/mbgl/platform/default/headless_backend.hpp
index b6c654943f..2fef321d85 100644
--- a/include/mbgl/platform/default/headless_backend.hpp
+++ b/include/mbgl/platform/default/headless_backend.hpp
@@ -1,23 +1,9 @@
#pragma once
#include <mbgl/gl/implementation.hpp>
-
-#if MBGL_USE_QT
-class QGLWidget;
-#elif MBGL_USE_CGL
-#include <OpenGL/OpenGL.h>
-#elif MBGL_USE_GLX
-typedef struct _XDisplay Display;
-typedef struct __GLXcontextRec* GLXContext;
-typedef struct __GLXFBConfigRec* GLXFBConfig;
-typedef long unsigned int XID;
-typedef XID GLXPbuffer;
-#elif MBGL_USE_OSMESA
-#include <GL/osmesa.h>
-#endif
+#include <mbgl/gl/extension.hpp>
#include <mbgl/map/backend.hpp>
-#include <mbgl/gl/extension.hpp>
#include <memory>
#include <functional>
@@ -39,47 +25,34 @@ public:
void setMapChangeCallback(std::function<void(MapChange)>&& cb) { mapChangeCallback = std::move(cb); }
-private:
- void activateContext();
- void deactivateContext();
+ struct Impl {
+ virtual ~Impl() {}
+ virtual void activateContext() = 0;
+ virtual void deactivateContext() {}
+ };
private:
// Implementation specific functions
static gl::glProc initializeExtension(const char*);
+
+ bool hasContext() const { return bool(impl); }
+ bool hasDisplay();
+
void createContext();
+
+private:
void destroyContext();
+ void activateContext();
+ void deactivateContext();
+
+ std::unique_ptr<Impl> impl;
std::shared_ptr<HeadlessDisplay> display;
bool extensionsLoaded = false;
bool active = false;
-#if MBGL_USE_QT
- QGLWidget* glContext = nullptr;
-#endif
-
-#if MBGL_USE_CGL
- CGLContextObj glContext = nullptr;
-#endif
-
-#if MBGL_USE_EAGL
- void *glContext = nullptr;
-#endif
-
-#if MBGL_USE_GLX
- Display *xDisplay = nullptr;
- GLXFBConfig *fbConfigs = nullptr;
- GLXContext glContext = nullptr;
- GLXPbuffer glxPbuffer = 0;
-#endif
-
-#if MBGL_USE_OSMESA
- OSMesaContext glContext = nullptr;
- GLubyte fakeBuffer = 0;
-#endif
-
std::function<void(MapChange)> mapChangeCallback;
-
};
} // namespace mbgl
diff --git a/platform/darwin/src/headless_backend_cgl.cpp b/platform/darwin/src/headless_backend_cgl.cpp
index 081156e8aa..dd062dd6af 100644
--- a/platform/darwin/src/headless_backend_cgl.cpp
+++ b/platform/darwin/src/headless_backend_cgl.cpp
@@ -1,6 +1,7 @@
#include <mbgl/platform/default/headless_backend.hpp>
#include <mbgl/platform/default/headless_display.hpp>
+#include <OpenGL/OpenGL.h>
#include <CoreFoundation/CoreFoundation.h>
#include <string>
@@ -8,6 +9,33 @@
namespace mbgl {
+struct CGLImpl : public HeadlessBackend::Impl {
+ CGLImpl(CGLContextObj glContext_) : glContext(glContext_) {
+ }
+
+ ~CGLImpl() {
+ CGLDestroyContext(glContext);
+ }
+
+ void activateContext() final {
+ CGLError error = CGLSetCurrentContext(glContext);
+ if (error != kCGLNoError) {
+ throw std::runtime_error(std::string("Switching OpenGL context failed:") +
+ CGLErrorString(error) + "\n");
+ }
+ }
+
+ void deactivateContext() final {
+ CGLError error = CGLSetCurrentContext(nullptr);
+ if (error != kCGLNoError) {
+ throw std::runtime_error(std::string("Removing OpenGL context failed:") +
+ CGLErrorString(error) + "\n");
+ }
+ }
+
+ CGLContextObj glContext = nullptr;
+};
+
gl::glProc HeadlessBackend::initializeExtension(const char* name) {
static CFBundleRef framework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl"));
if (!framework) {
@@ -21,7 +49,17 @@ gl::glProc HeadlessBackend::initializeExtension(const char* name) {
return reinterpret_cast<gl::glProc>(symbol);
}
+bool HeadlessBackend::hasDisplay() {
+ if (!display) {
+ display.reset(new HeadlessDisplay);
+ }
+ return bool(display);
+}
+
void HeadlessBackend::createContext() {
+ assert(!hasContext());
+
+ CGLContextObj glContext = nullptr;
CGLError error = CGLCreateContext(display->attribute<CGLPixelFormatObj>(), nullptr, &glContext);
if (error != kCGLNoError) {
throw std::runtime_error(std::string("Error creating GL context object:") +
@@ -33,26 +71,8 @@ void HeadlessBackend::createContext() {
throw std::runtime_error(std::string("Error enabling OpenGL multithreading:") +
CGLErrorString(error) + "\n");
}
-}
-
-void HeadlessBackend::destroyContext() {
- CGLDestroyContext(glContext);
-}
-
-void HeadlessBackend::activateContext() {
- CGLError error = CGLSetCurrentContext(glContext);
- if (error != kCGLNoError) {
- throw std::runtime_error(std::string("Switching OpenGL context failed:") +
- CGLErrorString(error) + "\n");
- }
-}
-void HeadlessBackend::deactivateContext() {
- CGLError error = CGLSetCurrentContext(nullptr);
- if (error != kCGLNoError) {
- throw std::runtime_error(std::string("Removing OpenGL context failed:") +
- CGLErrorString(error) + "\n");
- }
+ impl.reset(new CGLImpl(glContext));
}
} // namespace mbgl
diff --git a/platform/darwin/src/headless_backend_eagl.mm b/platform/darwin/src/headless_backend_eagl.mm
index 0a1ae706b8..aa5efe6de3 100644
--- a/platform/darwin/src/headless_backend_eagl.mm
+++ b/platform/darwin/src/headless_backend_eagl.mm
@@ -8,6 +8,27 @@
namespace mbgl {
+struct EAGLImpl : public HeadlessBackend::Impl {
+ EAGLImpl(EAGLContext* glContext_) : glContext(glContext_) {
+ [reinterpret_cast<EAGLContext*>(glContext) retain];
+ reinterpret_cast<EAGLContext*>(glContext).multiThreaded = YES;
+ }
+
+ ~EAGLImpl() {
+ [glContext release];
+ }
+
+ void activateContext() {
+ [EAGLContext setCurrentContext:glContext];
+ }
+
+ void deactivateContext() {
+ [EAGLContext setCurrentContext:nil];
+ }
+
+ EAGLContext* glContext = nullptr;
+};
+
gl::glProc HeadlessBackend::initializeExtension(const char* name) {
static CFBundleRef framework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengles"));
if (!framework) {
@@ -21,26 +42,17 @@ gl::glProc HeadlessBackend::initializeExtension(const char* name) {
return reinterpret_cast<gl::glProc>(symbol);
}
+bool HeadlessBackend::hasDisplay() {
+ return true;
+}
+
void HeadlessBackend::createContext() {
- glContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
+ EAGLContext* glContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
if (glContext == nil) {
throw std::runtime_error("Error creating GL context object");
}
- [reinterpret_cast<EAGLContext*>(glContext) retain];
- reinterpret_cast<EAGLContext*>(glContext).multiThreaded = YES;
-}
-
-void HeadlessBackend::destroyContext() {
- [reinterpret_cast<EAGLContext*>(glContext) release];
- glContext = nil;
-}
-
-void HeadlessBackend::activateContext() {
- [EAGLContext setCurrentContext:reinterpret_cast<EAGLContext*>(glContext)];
-}
-void HeadlessBackend::deactivateContext() {
- [EAGLContext setCurrentContext:nil];
+ impl.reset(new EAGLImpl(glContext));
}
} // namespace mbgl
diff --git a/platform/default/headless_backend.cpp b/platform/default/headless_backend.cpp
index 279a7973c9..30ce8d2230 100644
--- a/platform/default/headless_backend.cpp
+++ b/platform/default/headless_backend.cpp
@@ -3,15 +3,16 @@
#include <cassert>
#include <stdexcept>
+#include <type_traits>
namespace mbgl {
-HeadlessBackend::HeadlessBackend() : display(std::make_shared<HeadlessDisplay>()) {
+HeadlessBackend::HeadlessBackend() {
activate();
}
HeadlessBackend::HeadlessBackend(std::shared_ptr<HeadlessDisplay> display_)
- : display(std::move(display_)) {
+ : display(std::move(display_)) {
activate();
}
@@ -23,8 +24,8 @@ HeadlessBackend::~HeadlessBackend() {
void HeadlessBackend::activate() {
active = true;
- if (!glContext) {
- if (!display) {
+ if (!hasContext()) {
+ if (!hasDisplay()) {
throw std::runtime_error("Display is not set");
}
createContext();
@@ -47,6 +48,21 @@ void HeadlessBackend::invalidate() {
assert(false);
}
+void HeadlessBackend::destroyContext() {
+ assert(hasContext());
+ impl.reset();
+}
+
+void HeadlessBackend::activateContext() {
+ assert(hasContext());
+ impl->activateContext();
+}
+
+void HeadlessBackend::deactivateContext() {
+ assert(hasContext());
+ impl->deactivateContext();
+}
+
void HeadlessBackend::notifyMapChange(MapChange change) {
if (mapChangeCallback) {
mapChangeCallback(change);
diff --git a/platform/default/headless_backend_osmesa.cpp b/platform/default/headless_backend_osmesa.cpp
index e0e385fcc6..04709d4a1b 100644
--- a/platform/default/headless_backend_osmesa.cpp
+++ b/platform/default/headless_backend_osmesa.cpp
@@ -1,47 +1,54 @@
#include <mbgl/platform/default/headless_backend.hpp>
#include <mbgl/platform/log.hpp>
-namespace mbgl {
+#include <GL/osmesa.h>
-gl::glProc HeadlessBackend::initializeExtension(const char* name) {
- return OSMesaGetProcAddress(name);
-}
+#include <cassert>
-void HeadlessBackend::createContext() {
- if (glContext == nullptr) {
-#if OSMESA_MAJOR_VERSION * 100 + OSMESA_MINOR_VERSION >= 305
- glContext = OSMesaCreateContextExt(OSMESA_RGBA, 16, 0, 0, nullptr);
-#else
- glContext = OSMesaCreateContext(OSMESA_RGBA, nullptr);
-#endif
- if (glContext == nullptr) {
- Log::Error(Event::OpenGL, "failed to create OSMesa context");
- }
- }
+namespace mbgl {
- if (glContext == nullptr) {
- throw std::runtime_error("Error creating GL context object.");
+struct OSMesaImpl : public HeadlessBackend::Impl {
+ OSMesaImpl(OSMesaContext glContext_) : glContext(glContext_) {
}
-}
-void HeadlessBackend::destroyContext() {
- if (glContext) {
+ ~OSMesaImpl() {
if (glContext != OSMesaGetCurrentContext()) {
activateContext();
}
OSMesaDestroyContext(glContext);
- glContext = nullptr;
}
-}
-void HeadlessBackend::activateContext() {
- if (!OSMesaMakeCurrent(glContext, &fakeBuffer, GL_UNSIGNED_BYTE, 1, 1)) {
- throw std::runtime_error("Switching OpenGL context failed.\n");
+ void activateContext() final {
+ if (!OSMesaMakeCurrent(glContext, &fakeBuffer, GL_UNSIGNED_BYTE, 1, 1)) {
+ throw std::runtime_error("Switching OpenGL context failed.\n");
+ }
}
+
+ OSMesaContext glContext = nullptr;
+ GLubyte fakeBuffer = 0;
+};
+
+gl::glProc HeadlessBackend::initializeExtension(const char* name) {
+ return OSMesaGetProcAddress(name);
}
-void HeadlessBackend::deactivateContext() {
- // no-op.
+bool HeadlessBackend::hasDisplay() {
+ return true;
+};
+
+void HeadlessBackend::createContext() {
+ assert(!hasContext());
+
+#if OSMESA_MAJOR_VERSION * 100 + OSMESA_MINOR_VERSION >= 305
+ OSMesaContext glContext = OSMesaCreateContextExt(OSMESA_RGBA, 16, 0, 0, nullptr);
+#else
+ OSMesaContext glContext = OSMesaCreateContext(OSMESA_RGBA, nullptr);
+#endif
+ if (glContext == nullptr) {
+ throw std::runtime_error("Error creating GL context object.");
+ }
+
+ impl.reset(new OSMesaImpl(glContext));
}
} // namespace mbgl
diff --git a/platform/linux/src/headless_backend_glx.cpp b/platform/linux/src/headless_backend_glx.cpp
index 929eb73f5a..e1ea9cef15 100644
--- a/platform/linux/src/headless_backend_glx.cpp
+++ b/platform/linux/src/headless_backend_glx.cpp
@@ -3,32 +3,71 @@
#include <mbgl/platform/log.hpp>
-// #include <cassert>
+#include <cassert>
#include <GL/glx.h>
namespace mbgl {
+struct GLXImpl : public HeadlessBackend::Impl {
+ GLXImpl(GLXContext glContext_, GLXPbuffer glxPbuffer_, Display* xDisplay_, GLXFBConfig* fbConfigs_)
+ : glContext(glContext_),
+ glxPbuffer(glxPbuffer_),
+ xDisplay(xDisplay_),
+ fbConfigs(fbConfigs_) {
+ }
+
+ ~GLXImpl() {
+ if (glxPbuffer) {
+ glXDestroyPbuffer(xDisplay, glxPbuffer);
+ }
+ glXDestroyContext(xDisplay, glContext);
+ }
+
+ void activateContext() final {
+ if (!glXMakeContextCurrent(xDisplay, glxPbuffer, glxPbuffer, glContext)) {
+ throw std::runtime_error("Switching OpenGL context failed.\n");
+ }
+ }
+
+ void deactivateContext() final {
+ if (!glXMakeContextCurrent(xDisplay, 0, 0, nullptr)) {
+ throw std::runtime_error("Removing OpenGL context failed.\n");
+ }
+ }
+
+ GLXContext glContext = nullptr;
+ GLXPbuffer glxPbuffer = 0;
+
+ // Needed for ImplDeleter.
+ Display* xDisplay = nullptr;
+ GLXFBConfig* fbConfigs = nullptr;
+};
+
gl::glProc HeadlessBackend::initializeExtension(const char* name) {
return glXGetProcAddress(reinterpret_cast<const GLubyte*>(name));
}
-void HeadlessBackend::createContext() {
- xDisplay = display->attribute<Display*>();
- fbConfigs = display->attribute<GLXFBConfig*>();
-
- if (!glContext) {
- // Try to create a legacy context
- glContext = glXCreateNewContext(xDisplay, fbConfigs[0], GLX_RGBA_TYPE, None, True);
- if (glContext) {
- if (!glXIsDirect(xDisplay, glContext)) {
- Log::Error(Event::OpenGL, "failed to create direct OpenGL Legacy context");
- glXDestroyContext(xDisplay, glContext);
- glContext = nullptr;
- }
- }
+bool HeadlessBackend::hasDisplay() {
+ if (!display) {
+ display.reset(new HeadlessDisplay);
}
+ return bool(display);
+};
+
+void HeadlessBackend::createContext() {
+ assert(!hasContext());
+
+ Display* xDisplay = display->attribute<Display*>();
+ GLXFBConfig* fbConfigs = display->attribute<GLXFBConfig*>();
+ // Try to create a legacy context.
+ GLXContext glContext = glXCreateNewContext(xDisplay, fbConfigs[0], GLX_RGBA_TYPE, None, True);
+ if (glContext && !glXIsDirect(xDisplay, glContext)) {
+ Log::Error(Event::OpenGL, "failed to create direct OpenGL Legacy context");
+ glXDestroyContext(xDisplay, glContext);
+ glContext = nullptr;
+ }
if (glContext == nullptr) {
throw std::runtime_error("Error creating GL context object.");
}
@@ -40,28 +79,9 @@ void HeadlessBackend::createContext() {
GLX_PBUFFER_HEIGHT, 8,
None
};
- glxPbuffer = glXCreatePbuffer(xDisplay, fbConfigs[0], pbufferAttributes);
-}
-
-void HeadlessBackend::destroyContext() {
- if (glxPbuffer) {
- glXDestroyPbuffer(xDisplay, glxPbuffer);
- glxPbuffer = 0;
- }
-
- glXDestroyContext(xDisplay, glContext);
-}
+ GLXPbuffer glxPbuffer = glXCreatePbuffer(xDisplay, fbConfigs[0], pbufferAttributes);
-void HeadlessBackend::activateContext() {
- if (!glXMakeContextCurrent(xDisplay, glxPbuffer, glxPbuffer, glContext)) {
- throw std::runtime_error("Switching OpenGL context failed.\n");
- }
-}
-
-void HeadlessBackend::deactivateContext() {
- if (!glXMakeContextCurrent(xDisplay, 0, 0, nullptr)) {
- throw std::runtime_error("Removing OpenGL context failed.\n");
- }
+ impl.reset(new GLXImpl(glContext, glxPbuffer, xDisplay, fbConfigs));
}
} // namespace mbgl
diff --git a/platform/qt/test/headless_backend_qt.cpp b/platform/qt/test/headless_backend_qt.cpp
index 3f287ae578..f6552c4557 100644
--- a/platform/qt/test/headless_backend_qt.cpp
+++ b/platform/qt/test/headless_backend_qt.cpp
@@ -1,5 +1,4 @@
#include <mbgl/platform/default/headless_backend.hpp>
-#include <mbgl/platform/default/headless_display.hpp>
#include <QApplication>
#include <QGLContext>
@@ -9,8 +8,22 @@
#include <QOpenGLContext>
#endif
+#include <cassert>
+
namespace mbgl {
+struct QtImpl : public HeadlessBackend::Impl {
+ void activateContext() final {
+ widget.makeCurrent();
+ }
+
+ void deactivateContext() final {
+ widget.doneCurrent();
+ }
+
+ QGLWidget widget;
+};
+
gl::glProc HeadlessBackend::initializeExtension(const char* name) {
#if QT_VERSION >= 0x050000
QOpenGLContext* thisContext = QOpenGLContext::currentContext();
@@ -21,26 +34,20 @@ gl::glProc HeadlessBackend::initializeExtension(const char* name) {
#endif
}
+bool HeadlessBackend::hasDisplay() {
+ return true;
+};
+
void HeadlessBackend::createContext() {
+ assert(!hasContext());
+
static const char* argv[] = { "mbgl" };
static int argc = 1;
static auto* app = new QApplication(argc, const_cast<char**>(argv));
Q_UNUSED(app);
- glContext = new QGLWidget;
-}
-
-void HeadlessBackend::destroyContext() {
- delete glContext;
-}
-
-void HeadlessBackend::activateContext() {
- glContext->makeCurrent();
-}
-
-void HeadlessBackend::deactivateContext() {
- glContext->doneCurrent();
+ impl.reset(new QtImpl);
}
} // namespace mbgl