summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKonstantin Käfer <mail@kkaefer.com>2016-02-17 18:23:23 +0100
committerJohn Firebaugh <john.firebaugh@gmail.com>2016-03-22 11:56:01 -0700
commit61920071cd221d0d0627e01893185f0f19b55a98 (patch)
treee07358ba8bc9867ae979fd958d4eed3a7164230a
parent1dd81d9776baf9b9ef61b05d29f7acbb0f2a1508 (diff)
downloadqtlocation-mapboxgl-61920071cd221d0d0627e01893185f0f19b55a98.tar.gz
[core] split headless_view.cpp into implementation-specific files
also adds a EAGL implementation for iOS
-rw-r--r--gyp/headless-cgl.gypi1
-rw-r--r--gyp/headless-eagl.gypi19
-rw-r--r--gyp/headless-glx.gypi1
-rw-r--r--gyp/mbgl.gyp1
-rw-r--r--include/mbgl/platform/default/headless_view.hpp19
-rw-r--r--platform/darwin/src/headless_view_cgl.cpp113
-rw-r--r--platform/darwin/src/headless_view_eagl.mm103
-rw-r--r--platform/default/headless_view.cpp218
-rw-r--r--platform/default/headless_view_glx.cpp128
-rw-r--r--platform/ios/scripts/defaults.mk2
10 files changed, 406 insertions, 199 deletions
diff --git a/gyp/headless-cgl.gypi b/gyp/headless-cgl.gypi
index bcb677c6ed..4b92bdeb54 100644
--- a/gyp/headless-cgl.gypi
+++ b/gyp/headless-cgl.gypi
@@ -7,6 +7,7 @@
'sources': [
'../platform/default/headless_view.cpp',
+ '../platform/darwin/src/headless_view_cgl.cpp',
'../platform/default/headless_display.cpp',
],
diff --git a/gyp/headless-eagl.gypi b/gyp/headless-eagl.gypi
new file mode 100644
index 0000000000..0dc482563f
--- /dev/null
+++ b/gyp/headless-eagl.gypi
@@ -0,0 +1,19 @@
+{
+ 'targets': [
+ { 'target_name': 'headless-eagl',
+ 'product_name': 'mbgl-headless-eagl',
+ 'type': 'static_library',
+ 'standalone_static_library': 1,
+
+ 'sources': [
+ '../platform/default/headless_view.cpp',
+ '../platform/darwin/src/headless_view_eagl.mm',
+ '../platform/default/headless_display.cpp',
+ ],
+
+ 'include_dirs': [
+ '../include',
+ ],
+ },
+ ],
+}
diff --git a/gyp/headless-glx.gypi b/gyp/headless-glx.gypi
index 5b9f3e136f..65dedf7ade 100644
--- a/gyp/headless-glx.gypi
+++ b/gyp/headless-glx.gypi
@@ -7,6 +7,7 @@
'sources': [
'../platform/default/headless_view.cpp',
+ '../platform/default/headless_view_glx.cpp',
'../platform/default/headless_display.cpp',
],
diff --git a/gyp/mbgl.gyp b/gyp/mbgl.gyp
index 2a43afed8b..2acee2833f 100644
--- a/gyp/mbgl.gyp
+++ b/gyp/mbgl.gyp
@@ -10,6 +10,7 @@
],
'conditions': [
['headless_lib == "cgl" and host == "osx"', { 'includes': [ 'headless-cgl.gypi' ] } ],
+ ['headless_lib == "eagl" and host == "ios"', { 'includes': [ 'headless-eagl.gypi' ] } ],
['headless_lib == "glx" and host == "linux"', { 'includes': [ 'headless-glx.gypi' ] } ],
['platform_lib == "osx" and host == "osx"', { 'includes': [ 'platform-osx.gypi' ] } ],
['platform_lib == "ios" and host == "ios"', { 'includes': [ 'platform-ios.gypi' ] } ],
diff --git a/include/mbgl/platform/default/headless_view.hpp b/include/mbgl/platform/default/headless_view.hpp
index 8347aa51fe..edaa08d01d 100644
--- a/include/mbgl/platform/default/headless_view.hpp
+++ b/include/mbgl/platform/default/headless_view.hpp
@@ -2,7 +2,12 @@
#define MBGL_COMMON_HEADLESS_VIEW
#ifdef __APPLE__
+#include <TargetConditionals.h>
+#if TARGET_OS_IOS
+#define MBGL_USE_EAGL 1
+#else
#define MBGL_USE_CGL 1
+#endif
#else
#define GL_GLEXT_PROTOTYPES
#define MBGL_USE_GLX 1
@@ -45,11 +50,17 @@ public:
void resize(uint16_t width, uint16_t height);
private:
- void createContext();
void loadExtensions();
- void clearBuffers();
bool isActive() const;
+ // Implementation specific functions
+ static gl::glProc initializeExtension(const char*);
+ void createContext();
+ void destroyContext();
+ void clearBuffers();
+ void activateContext();
+ void deactivateContext();
+
private:
std::shared_ptr<HeadlessDisplay> display;
const float pixelRatio;
@@ -60,6 +71,10 @@ private:
CGLContextObj glContext = nullptr;
#endif
+#if MBGL_USE_EAGL
+ void *glContext = nullptr;
+#endif
+
#if MBGL_USE_GLX
Display *xDisplay = nullptr;
GLXFBConfig *fbConfigs = nullptr;
diff --git a/platform/darwin/src/headless_view_cgl.cpp b/platform/darwin/src/headless_view_cgl.cpp
new file mode 100644
index 0000000000..9f408fcbe8
--- /dev/null
+++ b/platform/darwin/src/headless_view_cgl.cpp
@@ -0,0 +1,113 @@
+#include <mbgl/platform/default/headless_view.hpp>
+#include <mbgl/platform/default/headless_display.hpp>
+
+#include <CoreFoundation/CoreFoundation.h>
+
+namespace mbgl {
+
+gl::glProc HeadlessView::initializeExtension(const char* name) {
+ static CFBundleRef framework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl"));
+ if (!framework) {
+ throw std::runtime_error("Failed to load OpenGL framework.");
+ }
+
+ CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, name, kCFStringEncodingASCII);
+ void* symbol = CFBundleGetFunctionPointerForName(framework, str);
+ CFRelease(str);
+
+ return reinterpret_cast<gl::glProc>(symbol);
+}
+
+void HeadlessView::createContext() {
+ CGLError error = CGLCreateContext(display->pixelFormat, NULL, &glContext);
+ if (error != kCGLNoError) {
+ throw std::runtime_error(std::string("Error creating GL context object:") + CGLErrorString(error) + "\n");
+ }
+
+ error = CGLEnable(glContext, kCGLCEMPEngine);
+ if (error != kCGLNoError) {
+ throw std::runtime_error(std::string("Error enabling OpenGL multithreading:") + CGLErrorString(error) + "\n");
+ }
+}
+
+void HeadlessView::destroyContext() {
+ CGLDestroyContext(glContext);
+}
+
+void HeadlessView::resizeFramebuffer() {
+ const unsigned int w = dimensions[0] * pixelRatio;
+ const unsigned int h = dimensions[1] * pixelRatio;
+
+ // Create depth/stencil buffer
+ MBGL_CHECK_ERROR(glGenRenderbuffersEXT(1, &fboDepthStencil));
+ MBGL_CHECK_ERROR(glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, fboDepthStencil));
+ MBGL_CHECK_ERROR(glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, w, h));
+ MBGL_CHECK_ERROR(glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0));
+
+ MBGL_CHECK_ERROR(glGenRenderbuffersEXT(1, &fboColor));
+ MBGL_CHECK_ERROR(glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, fboColor));
+ MBGL_CHECK_ERROR(glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGBA8, w, h));
+ MBGL_CHECK_ERROR(glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0));
+
+ MBGL_CHECK_ERROR(glGenFramebuffersEXT(1, &fbo));
+ MBGL_CHECK_ERROR(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo));
+
+ MBGL_CHECK_ERROR(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, fboColor));
+ MBGL_CHECK_ERROR(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER_EXT, fboDepthStencil));
+
+ GLenum status = MBGL_CHECK_ERROR(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
+
+ if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
+ std::string error("Couldn't create framebuffer: ");
+ switch (status) {
+ case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: (error += "incomplete attachment"); break;
+ case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: error += "incomplete missing attachment"; break;
+ case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: error += "incomplete dimensions"; break;
+ case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: error += "incomplete formats"; break;
+ case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: error += "incomplete draw buffer"; break;
+ case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: error += "incomplete read buffer"; 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() {
+ assert(isActive());
+
+ MBGL_CHECK_ERROR(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
+
+ if (fbo) {
+ MBGL_CHECK_ERROR(glDeleteFramebuffersEXT(1, &fbo));
+ fbo = 0;
+ }
+
+ if (fboColor) {
+ MBGL_CHECK_ERROR(glDeleteRenderbuffersEXT(1, &fboColor));
+ fboColor = 0;
+ }
+
+ if (fboDepthStencil) {
+ MBGL_CHECK_ERROR(glDeleteRenderbuffersEXT(1, &fboDepthStencil));
+ fboDepthStencil = 0;
+ }
+}
+
+void HeadlessView::activateContext() {
+ CGLError error = CGLSetCurrentContext(glContext);
+ if (error != kCGLNoError) {
+ throw std::runtime_error(std::string("Switching OpenGL context failed:") + CGLErrorString(error) + "\n");
+ }
+}
+
+void HeadlessView::deactivateContext() {
+ CGLError error = CGLSetCurrentContext(nullptr);
+ if (error != kCGLNoError) {
+ throw std::runtime_error(std::string("Removing OpenGL context failed:") + CGLErrorString(error) + "\n");
+ }
+}
+
+} // namespace mbgl
diff --git a/platform/darwin/src/headless_view_eagl.mm b/platform/darwin/src/headless_view_eagl.mm
new file mode 100644
index 0000000000..26b7922168
--- /dev/null
+++ b/platform/darwin/src/headless_view_eagl.mm
@@ -0,0 +1,103 @@
+#include <mbgl/platform/default/headless_view.hpp>
+#include <mbgl/platform/default/headless_display.hpp>
+
+#include <OpenGLES/EAGL.h>
+
+namespace mbgl {
+
+gl::glProc HeadlessView::initializeExtension(const char* name) {
+ static CFBundleRef framework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengles"));
+ if (!framework) {
+ throw std::runtime_error("Failed to load OpenGL framework.");
+ }
+
+ CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, name, kCFStringEncodingASCII);
+ void* symbol = CFBundleGetFunctionPointerForName(framework, str);
+ CFRelease(str);
+
+ return reinterpret_cast<gl::glProc>(symbol);
+}
+
+void HeadlessView::createContext() {
+ 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 HeadlessView::destroyContext() {
+ [reinterpret_cast<EAGLContext*>(glContext) release];
+ glContext = nil;
+}
+
+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() {
+ assert(isActive());
+
+ 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() {
+ [EAGLContext setCurrentContext:reinterpret_cast<EAGLContext*>(glContext)];
+}
+
+void HeadlessView::deactivateContext() {
+ [EAGLContext setCurrentContext:nil];
+}
+
+} // namespace mbgl
diff --git a/platform/default/headless_view.cpp b/platform/default/headless_view.cpp
index 7fd3c37f3a..9465f8ba9b 100644
--- a/platform/default/headless_view.cpp
+++ b/platform/default/headless_view.cpp
@@ -1,19 +1,8 @@
#include <mbgl/platform/default/headless_view.hpp>
#include <mbgl/platform/default/headless_display.hpp>
-#include <mbgl/platform/log.hpp>
-#include <stdexcept>
-#include <sstream>
-#include <string>
-#include <cstring>
#include <cassert>
-#include <utility>
-
-#ifdef MBGL_USE_CGL
-#include <CoreFoundation/CoreFoundation.h>
-#elif MBGL_USE_GLX
-#include <GL/glx.h>
-#endif
+#include <cstring>
namespace mbgl {
@@ -30,136 +19,30 @@ HeadlessView::HeadlessView(std::shared_ptr<HeadlessDisplay> display_,
resize(width, height);
}
+HeadlessView::~HeadlessView() {
+ activate();
+ clearBuffers();
+ deactivate();
+
+ destroyContext();
+}
+
+
void HeadlessView::loadExtensions() {
if (extensionsLoaded) {
return;
}
-#ifdef MBGL_USE_CGL
- gl::InitializeExtensions([](const char * name) {
- static CFBundleRef framework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl"));
- if (!framework) {
- throw std::runtime_error("Failed to load OpenGL framework.");
- }
-
- CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, name, kCFStringEncodingASCII);
- void* symbol = CFBundleGetFunctionPointerForName(framework, str);
- CFRelease(str);
-
- return reinterpret_cast<gl::glProc>(symbol);
- });
-#endif
-
-#ifdef MBGL_USE_GLX
- gl::InitializeExtensions([](const char * name) {
- return glXGetProcAddress(reinterpret_cast<const GLubyte *>(name));
- });
-#endif
+ gl::InitializeExtensions(initializeExtension);
extensionsLoaded = true;
}
-void HeadlessView::createContext() {
- if (!display) {
- throw std::runtime_error("Display is not set");
- }
-
-#if MBGL_USE_CGL
- CGLError error = CGLCreateContext(display->pixelFormat, NULL, &glContext);
- if (error != kCGLNoError) {
- throw std::runtime_error(std::string("Error creating GL context object:") + CGLErrorString(error) + "\n");
- }
-
- error = CGLEnable(glContext, kCGLCEMPEngine);
- if (error != kCGLNoError) {
- throw std::runtime_error(std::string("Error enabling OpenGL multithreading:") + CGLErrorString(error) + "\n");
- }
-#endif
-
-#if MBGL_USE_GLX
- xDisplay = display->xDisplay;
- fbConfigs = display->fbConfigs;
-
- 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 = 0;
- }
- }
- }
-
- if (glContext == 0) {
- throw std::runtime_error("Error creating GL context object.");
- }
-
- // Create a dummy pbuffer. We will render to framebuffers anyway, but we need a pbuffer to
- // activate the context.
- int pbufferAttributes[] = {
- GLX_PBUFFER_WIDTH, 8,
- GLX_PBUFFER_HEIGHT, 8,
- None
- };
- glxPbuffer = glXCreatePbuffer(xDisplay, fbConfigs[0], pbufferAttributes);
-#endif
-}
bool HeadlessView::isActive() const {
return std::this_thread::get_id() == thread;
}
-void HeadlessView::resizeFramebuffer() {
- assert(isActive());
-
- if (!needsResize) return;
-
- clearBuffers();
-
- const unsigned int w = dimensions[0] * pixelRatio;
- const unsigned int h = dimensions[1] * pixelRatio;
-
- // Create depth/stencil buffer
- MBGL_CHECK_ERROR(glGenRenderbuffersEXT(1, &fboDepthStencil));
- MBGL_CHECK_ERROR(glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, fboDepthStencil));
- MBGL_CHECK_ERROR(glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, w, h));
- MBGL_CHECK_ERROR(glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0));
-
- MBGL_CHECK_ERROR(glGenRenderbuffersEXT(1, &fboColor));
- MBGL_CHECK_ERROR(glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, fboColor));
- MBGL_CHECK_ERROR(glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGBA8, w, h));
- MBGL_CHECK_ERROR(glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0));
-
- MBGL_CHECK_ERROR(glGenFramebuffersEXT(1, &fbo));
- MBGL_CHECK_ERROR(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo));
-
- MBGL_CHECK_ERROR(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, fboColor));
- MBGL_CHECK_ERROR(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER_EXT, fboDepthStencil));
-
- GLenum status = MBGL_CHECK_ERROR(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
-
- if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
- std::string error("Couldn't create framebuffer: ");
- switch (status) {
- case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: (error += "incomplete attachment"); break;
- case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: error += "incomplete missing attachment"; break;
- case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: error += "incomplete dimensions"; break;
- case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: error += "incomplete formats"; break;
- case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: error += "incomplete draw buffer"; break;
- case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: error += "incomplete read buffer"; 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));
-
- needsResize = false;
-}
-
void HeadlessView::resize(const uint16_t width, const uint16_t height) {
if(dimensions[0] == width &&
dimensions[1] == height) {
@@ -178,7 +61,7 @@ PremultipliedImage HeadlessView::readStillImage() {
PremultipliedImage image { w, h };
MBGL_CHECK_ERROR(glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, image.data.get()));
- const int stride = image.stride();
+ const auto stride = image.stride();
auto tmp = std::make_unique<uint8_t[]>(stride);
uint8_t* rgba = image.data.get();
for (int i = 0, j = h - 1; i < j; i++, j--) {
@@ -189,47 +72,6 @@ PremultipliedImage HeadlessView::readStillImage() {
return image;
}
-
-void HeadlessView::clearBuffers() {
- assert(isActive());
-
- MBGL_CHECK_ERROR(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
-
- if (fbo) {
- MBGL_CHECK_ERROR(glDeleteFramebuffersEXT(1, &fbo));
- fbo = 0;
- }
-
- if (fboColor) {
- MBGL_CHECK_ERROR(glDeleteRenderbuffersEXT(1, &fboColor));
- fboColor = 0;
- }
-
- if (fboDepthStencil) {
- MBGL_CHECK_ERROR(glDeleteRenderbuffersEXT(1, &fboDepthStencil));
- fboDepthStencil = 0;
- }
-}
-
-HeadlessView::~HeadlessView() {
- activate();
- clearBuffers();
- deactivate();
-
-#if MBGL_USE_CGL
- CGLDestroyContext(glContext);
-#endif
-
-#if MBGL_USE_GLX
- if (glxPbuffer) {
- glXDestroyPbuffer(xDisplay, glxPbuffer);
- glxPbuffer = 0;
- }
-
- glXDestroyContext(xDisplay, glContext);
-#endif
-}
-
void HeadlessView::notify() {
// no-op
}
@@ -254,22 +96,13 @@ void HeadlessView::activate() {
thread = std::this_thread::get_id();
if (!glContext) {
+ if (!display) {
+ throw std::runtime_error("Display is not set");
+ }
createContext();
}
-#if MBGL_USE_CGL
- CGLError error = CGLSetCurrentContext(glContext);
- if (error != kCGLNoError) {
- throw std::runtime_error(std::string("Switching OpenGL context failed:") + CGLErrorString(error) + "\n");
- }
-#endif
-
-#if MBGL_USE_GLX
- if (!glXMakeContextCurrent(xDisplay, glxPbuffer, glxPbuffer, glContext)) {
- throw std::runtime_error("Switching OpenGL context failed.\n");
- }
-#endif
-
+ activateContext();
loadExtensions();
}
@@ -279,18 +112,7 @@ void HeadlessView::deactivate() {
}
thread = std::thread::id();
-#if MBGL_USE_CGL
- CGLError error = CGLSetCurrentContext(nullptr);
- if (error != kCGLNoError) {
- throw std::runtime_error(std::string("Removing OpenGL context failed:") + CGLErrorString(error) + "\n");
- }
-#endif
-
-#if MBGL_USE_GLX
- if (!glXMakeContextCurrent(xDisplay, 0, 0, nullptr)) {
- throw std::runtime_error("Removing OpenGL context failed.\n");
- }
-#endif
+ deactivateContext();
}
void HeadlessView::invalidate() {
@@ -298,7 +120,11 @@ void HeadlessView::invalidate() {
}
void HeadlessView::beforeRender() {
- resizeFramebuffer();
+ if (needsResize) {
+ clearBuffers();
+ resizeFramebuffer();
+ needsResize = false;
+ }
}
void HeadlessView::afterRender() {
diff --git a/platform/default/headless_view_glx.cpp b/platform/default/headless_view_glx.cpp
new file mode 100644
index 0000000000..d7ad9f5e55
--- /dev/null
+++ b/platform/default/headless_view_glx.cpp
@@ -0,0 +1,128 @@
+#include <mbgl/platform/default/headless_view.hpp>
+#include <mbgl/platform/default/headless_display.hpp>
+#include <mbgl/platform/log.hpp>
+
+#include <cassert>
+
+#include <GL/glx.h>
+
+namespace mbgl {
+
+gl::glProc HeadlessView::initializeExtension(const char* name) {
+ return glXGetProcAddress(reinterpret_cast<const GLubyte*>(name));
+}
+
+void HeadlessView::createContext() {
+ xDisplay = display->xDisplay;
+ fbConfigs = display->fbConfigs;
+
+ 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 = 0;
+ }
+ }
+ }
+
+ if (glContext == 0) {
+ throw std::runtime_error("Error creating GL context object.");
+ }
+
+ // Create a dummy pbuffer. We will render to framebuffers anyway, but we need a pbuffer to
+ // activate the context.
+ int pbufferAttributes[] = {
+ GLX_PBUFFER_WIDTH, 8,
+ GLX_PBUFFER_HEIGHT, 8,
+ None
+ };
+ glxPbuffer = glXCreatePbuffer(xDisplay, fbConfigs[0], pbufferAttributes);
+}
+
+void HeadlessView::destroyContext() {
+ if (glxPbuffer) {
+ glXDestroyPbuffer(xDisplay, glxPbuffer);
+ glxPbuffer = 0;
+ }
+
+ glXDestroyContext(xDisplay, glContext);
+}
+
+void HeadlessView::resizeFramebuffer() {
+ const unsigned int w = dimensions[0] * pixelRatio;
+ const unsigned int h = dimensions[1] * pixelRatio;
+
+ // Create depth/stencil buffer
+ MBGL_CHECK_ERROR(glGenRenderbuffersEXT(1, &fboDepthStencil));
+ MBGL_CHECK_ERROR(glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, fboDepthStencil));
+ MBGL_CHECK_ERROR(glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, w, h));
+ MBGL_CHECK_ERROR(glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0));
+
+ MBGL_CHECK_ERROR(glGenRenderbuffersEXT(1, &fboColor));
+ MBGL_CHECK_ERROR(glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, fboColor));
+ MBGL_CHECK_ERROR(glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGBA8, w, h));
+ MBGL_CHECK_ERROR(glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0));
+
+ MBGL_CHECK_ERROR(glGenFramebuffersEXT(1, &fbo));
+ MBGL_CHECK_ERROR(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo));
+
+ MBGL_CHECK_ERROR(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, fboColor));
+ MBGL_CHECK_ERROR(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER_EXT, fboDepthStencil));
+
+ GLenum status = MBGL_CHECK_ERROR(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
+
+ if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
+ std::string error("Couldn't create framebuffer: ");
+ switch (status) {
+ case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: (error += "incomplete attachment"); break;
+ case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: error += "incomplete missing attachment"; break;
+ case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: error += "incomplete dimensions"; break;
+ case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: error += "incomplete formats"; break;
+ case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: error += "incomplete draw buffer"; break;
+ case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: error += "incomplete read buffer"; 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() {
+ assert(isActive());
+
+ MBGL_CHECK_ERROR(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
+
+ if (fbo) {
+ MBGL_CHECK_ERROR(glDeleteFramebuffersEXT(1, &fbo));
+ fbo = 0;
+ }
+
+ if (fboColor) {
+ MBGL_CHECK_ERROR(glDeleteRenderbuffersEXT(1, &fboColor));
+ fboColor = 0;
+ }
+
+ if (fboDepthStencil) {
+ MBGL_CHECK_ERROR(glDeleteRenderbuffersEXT(1, &fboDepthStencil));
+ fboDepthStencil = 0;
+ }
+}
+
+void HeadlessView::activateContext() {
+ if (!glXMakeContextCurrent(xDisplay, glxPbuffer, glxPbuffer, glContext)) {
+ throw std::runtime_error("Switching OpenGL context failed.\n");
+ }
+}
+
+void HeadlessView::deactivateContext() {
+ if (!glXMakeContextCurrent(xDisplay, 0, 0, nullptr)) {
+ throw std::runtime_error("Removing OpenGL context failed.\n");
+ }
+}
+
+} // namespace mbgl
diff --git a/platform/ios/scripts/defaults.mk b/platform/ios/scripts/defaults.mk
index 6d7b9a6d13..ae4c815b74 100644
--- a/platform/ios/scripts/defaults.mk
+++ b/platform/ios/scripts/defaults.mk
@@ -1,4 +1,4 @@
-HEADLESS = none
+HEADLESS = eagl
PLATFORM ?= ios
ASSET ?= fs
HTTP ?= nsurl