summaryrefslogtreecommitdiff
path: root/common/headless_view.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'common/headless_view.cpp')
-rw-r--r--common/headless_view.cpp139
1 files changed, 76 insertions, 63 deletions
diff --git a/common/headless_view.cpp b/common/headless_view.cpp
index ace41d38c0..c2084ac90d 100644
--- a/common/headless_view.cpp
+++ b/common/headless_view.cpp
@@ -1,61 +1,38 @@
#include "headless_view.hpp"
-#include <mbgl/util/timer.hpp>
+#include "headless_display.hpp"
#include <stdexcept>
+#include <sstream>
+#include <string>
namespace mbgl {
-HeadlessView::HeadlessView() {
+HeadlessView::HeadlessView()
+ : display_(std::make_shared<HeadlessDisplay>()) {
+ createContext();
+}
+
+HeadlessView::HeadlessView(std::shared_ptr<HeadlessDisplay> display)
+ : display_(display) {
+ createContext();
+}
+
+void HeadlessView::createContext() {
#if MBGL_USE_CGL
- // TODO: test if OpenGL 4.1 with GL_ARB_ES2_compatibility is supported
- // If it is, use kCGLOGLPVersion_3_2_Core and enable that extension.
- CGLPixelFormatAttribute attributes[] = {
- kCGLPFAOpenGLProfile,
- (CGLPixelFormatAttribute) kCGLOGLPVersion_Legacy,
- kCGLPFAAccelerated,
- (CGLPixelFormatAttribute) 0
- };
-
- CGLPixelFormatObj pixelFormat;
- GLint num;
- CGLError error = CGLChoosePixelFormat(attributes, &pixelFormat, &num);
+ CGLError error = CGLCreateContext(display_->pixelFormat, NULL, &gl_context);
if (error) {
- fprintf(stderr, "Error pixel format\n");
- return;
+ throw std::runtime_error("Error creating GL context object\n");
}
- error = CGLCreateContext(pixelFormat, NULL, &gl_context);
- CGLDestroyPixelFormat(pixelFormat);
- if (error) {
- fprintf(stderr, "Error creating GL context object\n");
- return;
+ error = CGLEnable(gl_context, kCGLCEMPEngine);
+ if (error != kCGLNoError ) {
+ throw std::runtime_error("Error enabling OpenGL multithreading\n");
}
#endif
#if MBGL_USE_GLX
- x_display = XOpenDisplay(0);
-
- if (x_display == nullptr) {
- throw std::runtime_error("Failed to open X display");
- }
-
- static int pixelFormat[] = {
- GLX_RGBA,
- GLX_DOUBLEBUFFER,
- GLX_RED_SIZE, 8,
- GLX_GREEN_SIZE, 8,
- GLX_BLUE_SIZE, 8,
- GLX_ALPHA_SIZE, 8,
- GLX_DEPTH_SIZE, 24,
- GLX_STENCIL_SIZE, 8,
- None
- };
-
- x_info = glXChooseVisual(x_display, DefaultScreen(x_display), pixelFormat);
-
- if (x_info == nullptr) {
- throw std::runtime_error("Error pixel format");
- }
+ x_display = display_->x_display;
+ x_info = display_->x_info;
gl_context = glXCreateContext(x_display, x_info, 0, GL_TRUE);
if (gl_context == nullptr) {
@@ -64,12 +41,15 @@ HeadlessView::HeadlessView() {
#endif
}
-
void HeadlessView::resize(uint16_t width, uint16_t height, float pixelRatio) {
clear_buffers();
- width *= pixelRatio;
- height *= pixelRatio;
+ width_ = width;
+ height_ = height;
+ pixelRatio_ = pixelRatio;
+
+ const unsigned int w = width_ * pixelRatio_;
+ const unsigned int h = height_ * pixelRatio_;
#if MBGL_USE_CGL
make_active();
@@ -77,12 +57,12 @@ void HeadlessView::resize(uint16_t width, uint16_t height, float pixelRatio) {
// Create depth/stencil buffer
glGenRenderbuffersEXT(1, &fbo_depth_stencil);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, fbo_depth_stencil);
- glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, width, height);
+ glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, w, h);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
glGenRenderbuffersEXT(1, &fbo_color);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, fbo_color);
- glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGBA8, width, height);
+ glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGBA8, w, h);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
glGenFramebuffersEXT(1, &fbo);
@@ -94,29 +74,46 @@ void HeadlessView::resize(uint16_t width, uint16_t height, float pixelRatio) {
GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
- fprintf(stderr, "Couldn't create framebuffer: ");
+ std::stringstream error("Couldn't create framebuffer: ");
switch (status) {
- case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: fprintf(stderr, "incomplete attachment\n"); break;
- case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: fprintf(stderr, "incomplete missing attachment\n"); break;
- case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: fprintf(stderr, "incomplete draw buffer\n"); break;
- case GL_FRAMEBUFFER_UNSUPPORTED: fprintf(stderr, "unsupported\n"); break;
- default: fprintf(stderr, "other\n"); break;
+ case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: (error << "incomplete attachment\n"); break;
+ case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: error << "incomplete missing attachment\n"; break;
+ case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: error << "incomplete dimensions\n"; break;
+ case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: error << "incomplete formats\n"; break;
+ case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT: error << "incomplete draw buffer\n"; break;
+ case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT: error << "incomplete read buffer\n"; break;
+ case GL_FRAMEBUFFER_UNSUPPORTED: error << "unsupported\n"; break;
+ default: error << "other\n"; break;
}
- return;
+ throw std::runtime_error(error.str());
}
+
+ make_inactive();
#endif
#if MBGL_USE_GLX
- x_pixmap = XCreatePixmap(x_display, DefaultRootWindow(x_display), width, height, 32);
+ x_pixmap = XCreatePixmap(x_display, DefaultRootWindow(x_display), w, h, 32);
glx_pixmap = glXCreateGLXPixmap(x_display, x_info, x_pixmap);
+#endif
+}
+
+const std::unique_ptr<uint32_t[]> HeadlessView::readPixels() {
+ const unsigned int w = width_ * pixelRatio_;
+ const unsigned int h = height_ * pixelRatio_;
+
+ std::unique_ptr<uint32_t[]> pixels(new uint32_t[w * h]);
make_active();
-#endif
+ glReadPixels(0, 0, width_, height_, GL_RGBA, GL_UNSIGNED_BYTE, pixels.get());
+ make_inactive();
+ return pixels;
}
void HeadlessView::clear_buffers() {
#if MBGL_USE_CGL
+ make_active();
+
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
if (fbo) {
@@ -133,6 +130,8 @@ void HeadlessView::clear_buffers() {
glDeleteRenderbuffersEXT(1, &fbo_depth_stencil);
fbo_depth_stencil = 0;
}
+
+ make_inactive();
#endif
#if MBGL_USE_GLX
@@ -145,6 +144,8 @@ void HeadlessView::clear_buffers() {
XFreePixmap(x_display, x_pixmap);
x_pixmap = 0;
}
+
+ make_inactive();
#endif
}
@@ -156,10 +157,7 @@ HeadlessView::~HeadlessView() {
#endif
#if MBGL_USE_GLX
- glXMakeCurrent(x_display, None, NULL);
glXDestroyContext(x_display, gl_context);
- XFree(x_info);
- XCloseDisplay(x_display);
#endif
}
@@ -175,13 +173,28 @@ void HeadlessView::make_active() {
#if MBGL_USE_CGL
CGLError error = CGLSetCurrentContext(gl_context);
if (error) {
- fprintf(stderr, "Switching OpenGL context failed\n");
+ throw std::runtime_error("Switching OpenGL context failed\n");
}
#endif
#if MBGL_USE_GLX
if (!glXMakeCurrent(x_display, glx_pixmap, gl_context)) {
- fprintf(stderr, "Switching OpenGL context failed\n");
+ throw std::runtime_error("Switching OpenGL context failed\n");
+ }
+#endif
+}
+
+void HeadlessView::make_inactive() {
+#if MBGL_USE_CGL
+ CGLError error = CGLSetCurrentContext(nullptr);
+ if (error) {
+ throw std::runtime_error("Removing OpenGL context failed\n");
+ }
+#endif
+
+#if MBGL_USE_GLX
+ if (!glXMakeCurrent(x_display, 0, NULL)) {
+ throw std::runtime_error("Removing OpenGL context failed\n");
}
#endif
}