diff options
author | Konstantin Käfer <mail@kkaefer.com> | 2016-10-06 13:23:50 +0200 |
---|---|---|
committer | Konstantin Käfer <mail@kkaefer.com> | 2016-10-25 13:52:36 -0700 |
commit | 5cc390d694fc7510d445310d8eb9e32429a5e67b (patch) | |
tree | 7a24706f919ac3e8154be8b4ce33aed5bf42188d /platform | |
parent | 45f4dc0166f2d609d014d2174209fdbe1994c943 (diff) | |
download | qtlocation-mapboxgl-5cc390d694fc7510d445310d8eb9e32429a5e67b.tar.gz |
[core] separate Backend from View for headless rendering
Diffstat (limited to 'platform')
24 files changed, 382 insertions, 276 deletions
diff --git a/platform/android/src/native_map_view.cpp b/platform/android/src/native_map_view.cpp index 5bd2694932..fe201ac069 100755 --- a/platform/android/src/native_map_view.cpp +++ b/platform/android/src/native_map_view.cpp @@ -55,10 +55,8 @@ void log_gl_string(GLenum name, const char *label) { } } -NativeMapView::NativeMapView(JNIEnv *env_, jobject obj_, float pixelRatio_, int availableProcessors_, size_t totalMemory_) - : mbgl::View(*this), - env(env_), - pixelRatio(pixelRatio_), +NativeMapView::NativeMapView(JNIEnv *env_, jobject obj_, float pixelRatio, int availableProcessors_, size_t totalMemory_) + : env(env_), availableProcessors(availableProcessors_), totalMemory(totalMemory_), threadPool(4) { @@ -82,7 +80,7 @@ NativeMapView::NativeMapView(JNIEnv *env_, jobject obj_, float pixelRatio_, int mbgl::android::cachePath + "/mbgl-offline.db", mbgl::android::apkPath); - map = std::make_unique<mbgl::Map>(*this, *fileSource, threadPool, MapMode::Continuous); + map = std::make_unique<mbgl::Map>(*this, *this, pixelRatio, *fileSource, threadPool, MapMode::Continuous); float zoomFactor = map->getMaxZoom() - map->getMinZoom() + 1; float cpuFactor = availableProcessors; @@ -114,8 +112,8 @@ NativeMapView::~NativeMapView() { vm = nullptr; } -float NativeMapView::getPixelRatio() const { - return pixelRatio; +void NativeMapView::bind() { + MBGL_CHECK_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, 0)); } std::array<uint16_t, 2> NativeMapView::getSize() const { diff --git a/platform/android/src/native_map_view.hpp b/platform/android/src/native_map_view.hpp index d42890dae2..42a9a10ad4 100755 --- a/platform/android/src/native_map_view.hpp +++ b/platform/android/src/native_map_view.hpp @@ -2,6 +2,7 @@ #include <mbgl/map/map.hpp> #include <mbgl/map/view.hpp> +#include <mbgl/map/backend.hpp> #include <mbgl/util/noncopyable.hpp> #include <mbgl/platform/default/thread_pool.hpp> #include <mbgl/storage/default_file_source.hpp> @@ -14,12 +15,13 @@ namespace mbgl { namespace android { -class NativeMapView : public mbgl::View, private mbgl::util::noncopyable { +class NativeMapView : public mbgl::View, public mbgl::Backend { public: NativeMapView(JNIEnv *env, jobject obj, float pixelRatio, int availableProcessors, size_t totalMemory); virtual ~NativeMapView(); - float getPixelRatio() const override; + void bind() override; + std::array<uint16_t, 2> getSize() const override; std::array<uint16_t, 2> getFramebufferSize() const override; void activate() override; @@ -89,7 +91,6 @@ private: int height = 0; int fbWidth = 0; int fbHeight = 0; - const float pixelRatio; int availableProcessors = 0; size_t totalMemory = 0; diff --git a/platform/darwin/src/headless_backend_cgl.cpp b/platform/darwin/src/headless_backend_cgl.cpp new file mode 100644 index 0000000000..4ca567f55c --- /dev/null +++ b/platform/darwin/src/headless_backend_cgl.cpp @@ -0,0 +1,58 @@ +#include <mbgl/platform/default/headless_backend.hpp> +#include <mbgl/platform/default/headless_display.hpp> + +#include <CoreFoundation/CoreFoundation.h> + +#include <string> +#include <stdexcept> + +namespace mbgl { + +gl::glProc HeadlessBackend::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 HeadlessBackend::createContext() { + CGLError error = CGLCreateContext(display->pixelFormat, nullptr, &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 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"); + } +} + +} // namespace mbgl diff --git a/platform/darwin/src/headless_backend_eagl.mm b/platform/darwin/src/headless_backend_eagl.mm new file mode 100644 index 0000000000..0a1ae706b8 --- /dev/null +++ b/platform/darwin/src/headless_backend_eagl.mm @@ -0,0 +1,46 @@ +#include <mbgl/platform/default/headless_backend.hpp> + +#include <mbgl/gl/extension.hpp> + +#include <OpenGLES/EAGL.h> + +#include <stdexcept> + +namespace mbgl { + +gl::glProc HeadlessBackend::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 HeadlessBackend::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 HeadlessBackend::destroyContext() { + [reinterpret_cast<EAGLContext*>(glContext) release]; + glContext = nil; +} + +void HeadlessBackend::activateContext() { + [EAGLContext setCurrentContext:reinterpret_cast<EAGLContext*>(glContext)]; +} + +void HeadlessBackend::deactivateContext() { + [EAGLContext setCurrentContext:nil]; +} + +} // namespace mbgl diff --git a/platform/darwin/src/headless_view_cgl.cpp b/platform/darwin/src/headless_view_cgl.cpp index dc58463b5d..08f0da8751 100644 --- a/platform/darwin/src/headless_view_cgl.cpp +++ b/platform/darwin/src/headless_view_cgl.cpp @@ -1,37 +1,14 @@ #include <mbgl/platform/default/headless_view.hpp> -#include <mbgl/platform/default/headless_display.hpp> -#include <CoreFoundation/CoreFoundation.h> +#include <mbgl/gl/gl.hpp> -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, nullptr, &glContext); - if (error != kCGLNoError) { - throw std::runtime_error(std::string("Error creating GL context object:") + CGLErrorString(error) + "\n"); - } +#include <cassert> - error = CGLEnable(glContext, kCGLCEMPEngine); - if (error != kCGLNoError) { - throw std::runtime_error(std::string("Error enabling OpenGL multithreading:") + CGLErrorString(error) + "\n"); - } -} +namespace mbgl { -void HeadlessView::destroyContext() { - CGLDestroyContext(glContext); +void HeadlessView::bindFramebuffer() { + assert(fbo); + MBGL_CHECK_ERROR(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo)); } void HeadlessView::resizeFramebuffer() { @@ -76,8 +53,6 @@ void HeadlessView::resizeFramebuffer() { } void HeadlessView::clearBuffers() { - assert(active); - MBGL_CHECK_ERROR(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0)); if (fbo) { @@ -96,18 +71,4 @@ void HeadlessView::clearBuffers() { } } -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.cpp index a1f335fc6e..cc378912f9 100644 --- a/platform/darwin/src/headless_view_eagl.mm +++ b/platform/darwin/src/headless_view_eagl.cpp @@ -1,35 +1,14 @@ #include <mbgl/platform/default/headless_view.hpp> -#include <mbgl/platform/default/headless_display.hpp> -#include <OpenGLES/EAGL.h> +#include <mbgl/gl/gl.hpp> -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); +#include <cassert> - 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; -} +namespace mbgl { -void HeadlessView::destroyContext() { - [reinterpret_cast<EAGLContext*>(glContext) release]; - glContext = nil; +void HeadlessView::bindFramebuffer() { + assert(fbo); + MBGL_CHECK_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, fbo)); } void HeadlessView::resizeFramebuffer() { @@ -72,8 +51,6 @@ void HeadlessView::resizeFramebuffer() { } void HeadlessView::clearBuffers() { - assert(active); - MBGL_CHECK_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, 0)); if (fbo) { @@ -92,12 +69,4 @@ void HeadlessView::clearBuffers() { } } -void HeadlessView::activateContext() { - [EAGLContext setCurrentContext:reinterpret_cast<EAGLContext*>(glContext)]; -} - -void HeadlessView::deactivateContext() { - [EAGLContext setCurrentContext:nil]; -} - } // namespace mbgl diff --git a/platform/default/glfw_view.cpp b/platform/default/glfw_view.cpp index 9c54fc4ebf..044181e8c8 100644 --- a/platform/default/glfw_view.cpp +++ b/platform/default/glfw_view.cpp @@ -129,6 +129,10 @@ void GLFWView::initialize(mbgl::Map *map_) { map->addAnnotationIcon("default_marker", makeSpriteImage(22, 22, 1)); } +void GLFWView::bind() { + MBGL_CHECK_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, 0)); +} + void GLFWView::onKey(GLFWwindow *window, int key, int /*scancode*/, int action, int mods) { GLFWView *view = reinterpret_cast<GLFWView *>(glfwGetWindowUserPointer(window)); diff --git a/platform/default/headless_backend.cpp b/platform/default/headless_backend.cpp new file mode 100644 index 0000000000..279a7973c9 --- /dev/null +++ b/platform/default/headless_backend.cpp @@ -0,0 +1,56 @@ +#include <mbgl/platform/default/headless_backend.hpp> +#include <mbgl/platform/default/headless_display.hpp> + +#include <cassert> +#include <stdexcept> + +namespace mbgl { + +HeadlessBackend::HeadlessBackend() : display(std::make_shared<HeadlessDisplay>()) { + activate(); +} + +HeadlessBackend::HeadlessBackend(std::shared_ptr<HeadlessDisplay> display_) + : display(std::move(display_)) { + activate(); +} + +HeadlessBackend::~HeadlessBackend() { + deactivate(); + destroyContext(); +} + +void HeadlessBackend::activate() { + active = true; + + if (!glContext) { + if (!display) { + throw std::runtime_error("Display is not set"); + } + createContext(); + } + + activateContext(); + + if (!extensionsLoaded) { + gl::InitializeExtensions(initializeExtension); + extensionsLoaded = true; + } +} + +void HeadlessBackend::deactivate() { + deactivateContext(); + active = false; +} + +void HeadlessBackend::invalidate() { + assert(false); +} + +void HeadlessBackend::notifyMapChange(MapChange change) { + if (mapChangeCallback) { + mapChangeCallback(change); + } +} + +} // namespace mbgl diff --git a/platform/default/headless_backend_glx.cpp b/platform/default/headless_backend_glx.cpp new file mode 100644 index 0000000000..bbfd19345b --- /dev/null +++ b/platform/default/headless_backend_glx.cpp @@ -0,0 +1,67 @@ +#include <mbgl/platform/default/headless_backend.hpp> +#include <mbgl/platform/default/headless_display.hpp> + +#include <mbgl/platform/log.hpp> + +// #include <cassert> + +#include <GL/glx.h> + +namespace mbgl { + +gl::glProc HeadlessBackend::initializeExtension(const char* name) { + return glXGetProcAddress(reinterpret_cast<const GLubyte*>(name)); +} + +void HeadlessBackend::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 = nullptr; + } + } + } + + if (glContext == nullptr) { + 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 HeadlessBackend::destroyContext() { + if (glxPbuffer) { + glXDestroyPbuffer(xDisplay, glxPbuffer); + glxPbuffer = 0; + } + + glXDestroyContext(xDisplay, glContext); +} + +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"); + } +} + +} // namespace mbgl diff --git a/platform/default/headless_display.cpp b/platform/default/headless_display.cpp index 8b9f3fe04b..b98aef7903 100644 --- a/platform/default/headless_display.cpp +++ b/platform/default/headless_display.cpp @@ -1,12 +1,13 @@ #include <mbgl/platform/default/headless_display.hpp> -#include <cstring> -#include <stdexcept> - #if MBGL_USE_GLX #include <GL/glx.h> #endif +#include <cstring> +#include <stdexcept> +#include <string> + namespace mbgl { HeadlessDisplay::HeadlessDisplay() { diff --git a/platform/default/headless_view.cpp b/platform/default/headless_view.cpp index 95b196b746..f96b0a7f6d 100644 --- a/platform/default/headless_view.cpp +++ b/platform/default/headless_view.cpp @@ -1,34 +1,27 @@ #include <mbgl/platform/default/headless_view.hpp> -#include <mbgl/platform/default/headless_display.hpp> -#include <cassert> +#include <mbgl/gl/gl.hpp> + #include <cstring> namespace mbgl { HeadlessView::HeadlessView(float pixelRatio_, uint16_t width, uint16_t height) - : display(std::make_shared<HeadlessDisplay>()) - , pixelRatio(pixelRatio_) - , dimensions({{ width, height }}) - , needsResize(true) { -} - -HeadlessView::HeadlessView(std::shared_ptr<HeadlessDisplay> display_, - float pixelRatio_, - uint16_t width, - uint16_t height) - : display(std::move(display_)) - , pixelRatio(pixelRatio_) - , dimensions({{ width, height }}) - , needsResize(true) { + : pixelRatio(pixelRatio_), dimensions({ { width, height } }), needsResize(true) { } HeadlessView::~HeadlessView() { - activate(); clearBuffers(); - deactivate(); +} - destroyContext(); +void HeadlessView::bind() { + if (needsResize) { + clearBuffers(); + resizeFramebuffer(); + needsResize = false; + } else { + bindFramebuffer(); + } } void HeadlessView::resize(const uint16_t width, const uint16_t height) { @@ -41,8 +34,6 @@ void HeadlessView::resize(const uint16_t width, const uint16_t height) { } PremultipliedImage HeadlessView::readStillImage(std::array<uint16_t, 2> size) { - assert(active); - if (!size[0] || !size[1]) { size[0] = dimensions[0] * pixelRatio; size[1] = dimensions[1] * pixelRatio; @@ -76,43 +67,4 @@ std::array<uint16_t, 2> HeadlessView::getFramebufferSize() const { static_cast<uint16_t>(dimensions[1] * pixelRatio) }}; } -void HeadlessView::activate() { - active = true; - - if (!glContext) { - if (!display) { - throw std::runtime_error("Display is not set"); - } - createContext(); - } - - activateContext(); - - if (!extensionsLoaded) { - gl::InitializeExtensions(initializeExtension); - extensionsLoaded = true; - } - - if (needsResize) { - clearBuffers(); - resizeFramebuffer(); - needsResize = false; - } -} - -void HeadlessView::deactivate() { - deactivateContext(); - active = false; -} - -void HeadlessView::invalidate() { - assert(false); -} - -void HeadlessView::notifyMapChange(MapChange change) { - if (mapChangeCallback) { - mapChangeCallback(change); - } -} - } // namespace mbgl diff --git a/platform/default/headless_view_glx.cpp b/platform/default/headless_view_glx.cpp index 55d9313f99..08f0da8751 100644 --- a/platform/default/headless_view_glx.cpp +++ b/platform/default/headless_view_glx.cpp @@ -1,54 +1,14 @@ #include <mbgl/platform/default/headless_view.hpp> -#include <mbgl/platform/default/headless_display.hpp> -#include <mbgl/platform/log.hpp> -#include <cassert> +#include <mbgl/gl/gl.hpp> -#include <GL/glx.h> +#include <cassert> 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 = nullptr; - } - } - } - - if (glContext == nullptr) { - 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::bindFramebuffer() { + assert(fbo); + MBGL_CHECK_ERROR(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo)); } void HeadlessView::resizeFramebuffer() { @@ -93,8 +53,6 @@ void HeadlessView::resizeFramebuffer() { } void HeadlessView::clearBuffers() { - assert(active); - MBGL_CHECK_ERROR(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0)); if (fbo) { @@ -113,16 +71,4 @@ void HeadlessView::clearBuffers() { } } -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/config.cmake b/platform/ios/config.cmake index e5480e37df..db75d7a4de 100644 --- a/platform/ios/config.cmake +++ b/platform/ios/config.cmake @@ -37,7 +37,9 @@ macro(mbgl_platform_core) PRIVATE platform/darwin/src/image.mm # Headless view - PRIVATE platform/darwin/src/headless_view_eagl.mm + PRIVATE platform/darwin/src/headless_backend_eagl.mm + PRIVATE platform/darwin/src/headless_view_eagl.cpp + PRIVATE platform/default/headless_backend.cpp PRIVATE platform/default/headless_display.cpp PRIVATE platform/default/headless_view.cpp @@ -53,7 +55,7 @@ macro(mbgl_platform_core) # TODO: Remove this by converting to ARC set_source_files_properties( - platform/darwin/src/headless_view_eagl.mm + platform/darwin/src/headless_backend_eagl.mm PROPERTIES COMPILE_FLAGS -fno-objc-arc ) diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm index 194f1a88d4..3d93dc8fc9 100644 --- a/platform/ios/src/MGLMapView.mm +++ b/platform/ios/src/MGLMapView.mm @@ -18,6 +18,7 @@ #include <mbgl/storage/network_status.hpp> #include <mbgl/style/transition_options.hpp> #include <mbgl/style/layers/custom_layer.hpp> +#include <mbgl/map/backend.hpp> #include <mbgl/math/wrap.hpp> #include <mbgl/util/geo.hpp> #include <mbgl/util/constants.hpp> @@ -389,8 +390,7 @@ public: self.clipsToBounds = YES; // setup mbgl view - const float scaleFactor = [UIScreen instancesRespondToSelector:@selector(nativeScale)] ? [[UIScreen mainScreen] nativeScale] : [[UIScreen mainScreen] scale]; - _mbglView = new MBGLView(self, scaleFactor); + _mbglView = new MBGLView(self); // Delete the pre-offline ambient cache at ~/Library/Caches/cache.db. NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); @@ -398,9 +398,10 @@ public: [[NSFileManager defaultManager] removeItemAtPath:fileCachePath error:NULL]; // setup mbgl map + const float scaleFactor = [UIScreen instancesRespondToSelector:@selector(nativeScale)] ? [[UIScreen mainScreen] nativeScale] : [[UIScreen mainScreen] scale]; mbgl::DefaultFileSource *mbglFileSource = [MGLOfflineStorage sharedOfflineStorage].mbglFileSource; _mbglThreadPool = new mbgl::ThreadPool(4); - _mbglMap = new mbgl::Map(*_mbglView, *mbglFileSource, *_mbglThreadPool, mbgl::MapMode::Continuous, mbgl::GLContextMode::Unique, mbgl::ConstrainMode::None, mbgl::ViewportMode::Default); + _mbglMap = new mbgl::Map(*_mbglView, *_mbglView, scaleFactor, *mbglFileSource, *_mbglThreadPool, mbgl::MapMode::Continuous, mbgl::GLContextMode::Unique, mbgl::ConstrainMode::None, mbgl::ViewportMode::Default); [self validateTileCacheSize]; // start paused if in IB @@ -4938,15 +4939,11 @@ public: return _annotationViewReuseQueueByIdentifier[identifier]; } -class MBGLView : public mbgl::View +class MBGLView : public mbgl::View, public mbgl::Backend { public: - MBGLView(MGLMapView* nativeView_, const float scaleFactor_) - : nativeView(nativeView_), scaleFactor(scaleFactor_) { - } - - float getPixelRatio() const override { - return scaleFactor; + MBGLView(MGLMapView* nativeView_) + : nativeView(nativeView_) { } std::array<uint16_t, 2> getSize() const override { @@ -4959,6 +4956,10 @@ public: static_cast<uint16_t>([[nativeView glView] drawableHeight]) }}; } + void bind() override { + [nativeView.glView bindDrawable]; + } + void notifyMapChange(mbgl::MapChange change) override { [nativeView notifyMapChange:change]; @@ -4981,7 +4982,6 @@ public: private: __weak MGLMapView *nativeView = nullptr; - const float scaleFactor; }; @end diff --git a/platform/linux/config.cmake b/platform/linux/config.cmake index 86e8697f8c..d033f9df21 100644 --- a/platform/linux/config.cmake +++ b/platform/linux/config.cmake @@ -41,9 +41,11 @@ macro(mbgl_platform_core) PRIVATE platform/default/webp_reader.cpp # Headless view + PRIVATE platform/default/headless_backend_glx.cpp + PRIVATE platform/default/headless_view_glx.cpp + PRIVATE platform/default/headless_backend.cpp PRIVATE platform/default/headless_display.cpp PRIVATE platform/default/headless_view.cpp - PRIVATE platform/default/headless_view_glx.cpp # Thread pool PRIVATE platform/default/thread_pool.cpp diff --git a/platform/macos/config.cmake b/platform/macos/config.cmake index 645feb90c3..198dfc7083 100644 --- a/platform/macos/config.cmake +++ b/platform/macos/config.cmake @@ -35,7 +35,9 @@ macro(mbgl_platform_core) PRIVATE platform/darwin/src/image.mm # Headless view + PRIVATE platform/darwin/src/headless_backend_cgl.cpp PRIVATE platform/darwin/src/headless_view_cgl.cpp + PRIVATE platform/default/headless_backend.cpp PRIVATE platform/default/headless_display.cpp PRIVATE platform/default/headless_view.cpp diff --git a/platform/macos/src/MGLMapView.mm b/platform/macos/src/MGLMapView.mm index 46766b573b..475ca2d259 100644 --- a/platform/macos/src/MGLMapView.mm +++ b/platform/macos/src/MGLMapView.mm @@ -25,6 +25,7 @@ #import <mbgl/platform/default/thread_pool.hpp> #import <mbgl/gl/extension.hpp> #import <mbgl/gl/gl.hpp> +#import <mbgl/map/backend.hpp> #import <mbgl/sprite/sprite_image.hpp> #import <mbgl/storage/default_file_source.hpp> #import <mbgl/storage/network_status.hpp> @@ -248,7 +249,7 @@ public: _isTargetingInterfaceBuilder = NSProcessInfo.processInfo.mgl_isInterfaceBuilderDesignablesAgent; // Set up cross-platform controllers and resources. - _mbglView = new MGLMapViewImpl(self, [NSScreen mainScreen].backingScaleFactor); + _mbglView = new MGLMapViewImpl(self); // Delete the pre-offline ambient cache at // ~/Library/Caches/com.mapbox.sdk.ios/cache.db. @@ -264,7 +265,7 @@ public: mbgl::DefaultFileSource *mbglFileSource = [MGLOfflineStorage sharedOfflineStorage].mbglFileSource; _mbglThreadPool = new mbgl::ThreadPool(4); - _mbglMap = new mbgl::Map(*_mbglView, *mbglFileSource, *_mbglThreadPool, mbgl::MapMode::Continuous, mbgl::GLContextMode::Unique, mbgl::ConstrainMode::None, mbgl::ViewportMode::Default); + _mbglMap = new mbgl::Map(*_mbglView, *_mbglView, [NSScreen mainScreen].backingScaleFactor, *mbglFileSource, *_mbglThreadPool, mbgl::MapMode::Continuous, mbgl::GLContextMode::Unique, mbgl::ConstrainMode::None, mbgl::ViewportMode::Default); [self validateTileCacheSize]; // Install the OpenGL layer. Interface Builder’s synchronous drawing means @@ -745,6 +746,8 @@ public: return reinterpret_cast<mbgl::gl::glProc>(symbol); }); + _mbglView->updateFramebufferBinding(); + _mbglMap->render(); if (_isPrinting) { @@ -2531,14 +2534,10 @@ public: } /// Adapter responsible for bridging calls from mbgl to MGLMapView and Cocoa. -class MGLMapViewImpl : public mbgl::View { +class MGLMapViewImpl : public mbgl::View, public mbgl::Backend { public: - MGLMapViewImpl(MGLMapView *nativeView_, const float scaleFactor_) - : nativeView(nativeView_), scaleFactor(scaleFactor_) {} - - float getPixelRatio() const override { - return scaleFactor; - } + MGLMapViewImpl(MGLMapView *nativeView_) + : nativeView(nativeView_) {} std::array<uint16_t, 2> getSize() const override { return {{ static_cast<uint16_t>(nativeView.bounds.size.width), @@ -2568,6 +2567,14 @@ public: [NSOpenGLContext clearCurrentContext]; } + void updateFramebufferBinding() { + MBGL_CHECK_ERROR(glGetIntegerv(GL_FRAMEBUFFER_BINDING, &fbo)); + } + + void bind() override { + MBGL_CHECK_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, fbo)); + } + mbgl::PremultipliedImage readStillImage(std::array<uint16_t, 2> size = {{ 0, 0 }}) override { if (!size[0] || !size[1]) { size = getFramebufferSize(); @@ -2592,8 +2599,8 @@ private: /// Cocoa map view that this adapter bridges to. __weak MGLMapView *nativeView = nullptr; - /// Backing scale factor of the view. - const float scaleFactor; + /// The current framebuffer of the NSOpenGLLayer we are painting to. + GLint fbo = 0; }; @end diff --git a/platform/node/src/node_map.cpp b/platform/node/src/node_map.cpp index a13adbc417..ebdf8d62c3 100644 --- a/platform/node/src/node_map.cpp +++ b/platform/node/src/node_map.cpp @@ -773,15 +773,16 @@ void NodeMap::QueryRenderedFeatures(const Nan::FunctionCallbackInfo<v8::Value>& } NodeMap::NodeMap(v8::Local<v8::Object> options) : - view(sharedDisplay(), [&] { + backend(sharedDisplay()), + view([&] { Nan::HandleScope scope; return Nan::Has(options, Nan::New("ratio").ToLocalChecked()).FromJust() ? Nan::Get(options, Nan::New("ratio").ToLocalChecked()).ToLocalChecked()->NumberValue() : 1.0; }()), threadpool(), - map(std::make_unique<mbgl::Map>(view, *this, threadpool, mbgl::MapMode::Still)), + map(std::make_unique<mbgl::Map>(backend, view, view.getPixelRatio(), *this, threadpool, mbgl::MapMode::Still)), async(new uv_async_t) { - view.setMapChangeCallback([&](mbgl::MapChange change) { + backend.setMapChangeCallback([&](mbgl::MapChange change) { if (change == mbgl::MapChangeDidFailLoadingMap) { throw std::runtime_error("Requires a map style to be a valid style JSON"); } diff --git a/platform/node/src/node_map.hpp b/platform/node/src/node_map.hpp index 588ece2c74..48ff2caab1 100644 --- a/platform/node/src/node_map.hpp +++ b/platform/node/src/node_map.hpp @@ -4,6 +4,7 @@ #include <mbgl/map/map.hpp> #include <mbgl/storage/file_source.hpp> +#include <mbgl/platform/default/headless_backend.hpp> #include <mbgl/platform/default/headless_view.hpp> #pragma GCC diagnostic push @@ -53,6 +54,7 @@ public: std::unique_ptr<mbgl::AsyncRequest> request(const mbgl::Resource&, mbgl::FileSource::Callback); + mbgl::HeadlessBackend backend; mbgl::HeadlessView view; NodeThreadPool threadpool; std::unique_ptr<mbgl::Map> map; diff --git a/platform/qt/config.cmake b/platform/qt/config.cmake index d8ede6b450..6df311f885 100644 --- a/platform/qt/config.cmake +++ b/platform/qt/config.cmake @@ -43,8 +43,10 @@ endmacro() macro(mbgl_platform_test) target_sources(mbgl-test PRIVATE test/src/main.cpp + PRIVATE platform/qt/test/headless_backend_qt.cpp PRIVATE platform/qt/test/headless_view_qt.cpp PRIVATE platform/qt/test/qmapboxgl.cpp + PRIVATE platform/default/headless_backend.cpp PRIVATE platform/default/headless_display.cpp PRIVATE platform/default/headless_view.cpp ) diff --git a/platform/qt/src/qmapboxgl.cpp b/platform/qt/src/qmapboxgl.cpp index d0a05301f8..73a1771908 100644 --- a/platform/qt/src/qmapboxgl.cpp +++ b/platform/qt/src/qmapboxgl.cpp @@ -813,7 +813,7 @@ QMapboxGLPrivate::QMapboxGLPrivate(QMapboxGL *q, const QMapboxGLSettings &settin settings.cacheDatabaseMaximumSize())) , threadPool(4) , mapObj(std::make_unique<mbgl::Map>( - *this, *fileSourceObj, threadPool, + *this, *this, getPixelRatio(), *fileSourceObj, threadPool, static_cast<mbgl::MapMode>(settings.mapMode()), static_cast<mbgl::GLContextMode>(settings.contextMode()), static_cast<mbgl::ConstrainMode>(settings.constrainMode()), @@ -845,6 +845,11 @@ float QMapboxGLPrivate::getPixelRatio() const return pixelRatio; } +void QMapboxGLPrivate::bind() +{ + MBGL_CHECK_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, 0)); +} + std::array<uint16_t, 2> QMapboxGLPrivate::getSize() const { return {{ static_cast<uint16_t>(size.width()), static_cast<uint16_t>(size.height()) }}; diff --git a/platform/qt/src/qmapboxgl_p.hpp b/platform/qt/src/qmapboxgl_p.hpp index c35ac4e7ba..5a228896dc 100644 --- a/platform/qt/src/qmapboxgl_p.hpp +++ b/platform/qt/src/qmapboxgl_p.hpp @@ -3,6 +3,7 @@ #include "qmapboxgl.hpp" #include <mbgl/map/map.hpp> +#include <mbgl/map/backend.hpp> #include <mbgl/map/view.hpp> #include <mbgl/platform/default/thread_pool.hpp> #include <mbgl/storage/default_file_source.hpp> @@ -11,7 +12,7 @@ #include <QObject> #include <QSize> -class QMapboxGLPrivate : public QObject, public mbgl::View +class QMapboxGLPrivate : public QObject, public mbgl::View, public mbgl::Backend { Q_OBJECT @@ -20,7 +21,8 @@ public: virtual ~QMapboxGLPrivate(); // mbgl::View implementation. - float getPixelRatio() const final; + float getPixelRatio() const; + void bind() final; std::array<uint16_t, 2> getSize() const final; std::array<uint16_t, 2> getFramebufferSize() const final; diff --git a/platform/qt/test/headless_backend_qt.cpp b/platform/qt/test/headless_backend_qt.cpp new file mode 100644 index 0000000000..3f287ae578 --- /dev/null +++ b/platform/qt/test/headless_backend_qt.cpp @@ -0,0 +1,46 @@ +#include <mbgl/platform/default/headless_backend.hpp> +#include <mbgl/platform/default/headless_display.hpp> + +#include <QApplication> +#include <QGLContext> +#include <QGLWidget> + +#if QT_VERSION >= 0x050000 +#include <QOpenGLContext> +#endif + +namespace mbgl { + +gl::glProc HeadlessBackend::initializeExtension(const char* name) { +#if QT_VERSION >= 0x050000 + QOpenGLContext* thisContext = QOpenGLContext::currentContext(); + return thisContext->getProcAddress(name); +#else + const QGLContext* thisContext = QGLContext::currentContext(); + return reinterpret_cast<mbgl::gl::glProc>(thisContext->getProcAddress(name)); +#endif +} + +void HeadlessBackend::createContext() { + 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(); +} + +} // namespace mbgl diff --git a/platform/qt/test/headless_view_qt.cpp b/platform/qt/test/headless_view_qt.cpp index 03ecb741ab..133b4a2371 100644 --- a/platform/qt/test/headless_view_qt.cpp +++ b/platform/qt/test/headless_view_qt.cpp @@ -1,6 +1,7 @@ -#include <mbgl/platform/default/headless_display.hpp> #include <mbgl/platform/default/headless_view.hpp> +#include <mbgl/gl/gl.hpp> + #include <QApplication> #include <QGLContext> #include <QGLWidget> @@ -9,30 +10,13 @@ #include <QOpenGLContext> #endif -namespace mbgl { - -gl::glProc HeadlessView::initializeExtension(const char* name) { -#if QT_VERSION >= 0x050000 - QOpenGLContext* thisContext = QOpenGLContext::currentContext(); - return thisContext->getProcAddress(name); -#else - const QGLContext* thisContext = QGLContext::currentContext(); - return reinterpret_cast<mbgl::gl::glProc>(thisContext->getProcAddress(name)); -#endif -} - -void HeadlessView::createContext() { - static const char* argv[] = { "mbgl" }; - static int argc = 1; - static auto* app = new QApplication(argc, const_cast<char**>(argv)); - - Q_UNUSED(app); +#include <cassert> - glContext = new QGLWidget; -} +namespace mbgl { -void HeadlessView::destroyContext() { - delete glContext; +void HeadlessView::bindFramebuffer() { + assert(fbo); + MBGL_CHECK_ERROR(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo)); } void HeadlessView::resizeFramebuffer() { @@ -95,12 +79,4 @@ void HeadlessView::clearBuffers() { } } -void HeadlessView::activateContext() { - glContext->makeCurrent(); -} - -void HeadlessView::deactivateContext() { - glContext->doneCurrent(); -} - } // namespace mbgl |