diff options
Diffstat (limited to 'platform')
29 files changed, 288 insertions, 521 deletions
diff --git a/platform/android/scripts/generate-style-code.js b/platform/android/scripts/generate-style-code.js index 166f102f18..1216bd4cbe 100644 --- a/platform/android/scripts/generate-style-code.js +++ b/platform/android/scripts/generate-style-code.js @@ -103,7 +103,7 @@ global.propertyNativeType = function (property) { if (/-translate-anchor$/.test(property.name)) { return 'TranslateAnchorType'; } - if (/-(rotation|pitch)-alignment$/.test(property.name)) { + if (/-(rotation|pitch|illumination)-alignment$/.test(property.name)) { return 'AlignmentType'; } switch (property.type) { diff --git a/platform/android/src/jni.cpp b/platform/android/src/jni.cpp index a145841b47..6dcd177cd6 100755 --- a/platform/android/src/jni.cpp +++ b/platform/android/src/jni.cpp @@ -358,7 +358,7 @@ void nativeDestroySurface(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr void nativeUpdate(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) { assert(nativeMapViewPtr != 0); NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr); - nativeMapView->getMap().update(mbgl::Update::Repaint); + nativeMapView->invalidate(); } void nativeRender(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) { diff --git a/platform/android/src/native_map_view.cpp b/platform/android/src/native_map_view.cpp index fe201ac069..8f594f2c0e 100755 --- a/platform/android/src/native_map_view.cpp +++ b/platform/android/src/native_map_view.cpp @@ -17,7 +17,9 @@ #include <mbgl/platform/log.hpp> #include <mbgl/gl/extension.hpp> #include <mbgl/gl/gl.hpp> +#include <mbgl/gl/context.hpp> #include <mbgl/util/constants.hpp> +#include <mbgl/util/image.hpp> namespace mbgl { namespace android { @@ -80,7 +82,10 @@ NativeMapView::NativeMapView(JNIEnv *env_, jobject obj_, float pixelRatio, int a mbgl::android::cachePath + "/mbgl-offline.db", mbgl::android::apkPath); - map = std::make_unique<mbgl::Map>(*this, *this, pixelRatio, *fileSource, threadPool, MapMode::Continuous); + map = std::make_unique<mbgl::Map>( + *this, + std::array<uint16_t, 2>{{ static_cast<uint16_t>(width), static_cast<uint16_t>(height) }}, + pixelRatio, *fileSource, threadPool, MapMode::Continuous); float zoomFactor = map->getMaxZoom() - map->getMinZoom() + 1; float cpuFactor = availableProcessors; @@ -112,16 +117,14 @@ NativeMapView::~NativeMapView() { vm = nullptr; } -void NativeMapView::bind() { - MBGL_CHECK_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, 0)); -} - -std::array<uint16_t, 2> NativeMapView::getSize() const { - return {{ static_cast<uint16_t>(width), static_cast<uint16_t>(height) }}; +void NativeMapView::updateViewBinding() { + getContext().bindFramebuffer.setCurrentValue(0); + getContext().viewport.setCurrentValue({ 0, 0, static_cast<uint16_t>(fbWidth), static_cast<uint16_t>(fbHeight) }); } -std::array<uint16_t, 2> NativeMapView::getFramebufferSize() const { - return {{ static_cast<uint16_t>(fbWidth), static_cast<uint16_t>(fbHeight) }}; +void NativeMapView::bind() { + getContext().bindFramebuffer = 0; + getContext().viewport = { 0, 0, static_cast<uint16_t>(fbWidth), static_cast<uint16_t>(fbHeight) }; } void NativeMapView::activate() { @@ -189,12 +192,8 @@ void NativeMapView::invalidate() { void NativeMapView::render() { activate(); - if(sizeChanged){ - sizeChanged = false; - glViewport(0, 0, fbWidth, fbHeight); - } - - map->render(); + updateViewBinding(); + map->render(*this); if(snapshot){ snapshot = false; @@ -719,14 +718,13 @@ void NativeMapView::updateFps() { void NativeMapView::resizeView(int w, int h) { width = w; height = h; - sizeChanged = true; - map->update(mbgl::Update::Dimensions); + map->setSize({{ static_cast<uint16_t>(width), static_cast<uint16_t>(height) }}); } void NativeMapView::resizeFramebuffer(int w, int h) { fbWidth = w; fbHeight = h; - map->update(mbgl::Update::Repaint); + invalidate(); } void NativeMapView::setInsets(mbgl::EdgeInsets insets_) { diff --git a/platform/android/src/native_map_view.hpp b/platform/android/src/native_map_view.hpp index 42a9a10ad4..43fb0c1ccd 100755 --- a/platform/android/src/native_map_view.hpp +++ b/platform/android/src/native_map_view.hpp @@ -20,10 +20,9 @@ public: NativeMapView(JNIEnv *env, jobject obj, float pixelRatio, int availableProcessors, size_t totalMemory); virtual ~NativeMapView(); + void updateViewBinding(); void bind() override; - std::array<uint16_t, 2> getSize() const override; - std::array<uint16_t, 2> getFramebufferSize() const override; void activate() override; void deactivate() override; void invalidate() override; @@ -83,7 +82,6 @@ private: bool firstTime = false; bool fpsEnabled = false; - bool sizeChanged = false; bool snapshot = false; double fps = 0.0; diff --git a/platform/android/src/style/layers/custom_layer.cpp b/platform/android/src/style/layers/custom_layer.cpp index aeabb4e19d..6568455c67 100644 --- a/platform/android/src/style/layers/custom_layer.cpp +++ b/platform/android/src/style/layers/custom_layer.cpp @@ -26,7 +26,7 @@ namespace android { void CustomLayer::update(jni::JNIEnv&) { Log::Debug(mbgl::Event::JNI, "Updating map"); if (map) { - map->update(mbgl::Update::Repaint); + map->triggerRepaint(); } else { Log::Error(mbgl::Event::JNI, "No map reference, cannot update"); } diff --git a/platform/android/src/style/sources/source.hpp b/platform/android/src/style/sources/source.hpp index 5794cd4e62..0785e4d4e0 100644 --- a/platform/android/src/style/sources/source.hpp +++ b/platform/android/src/style/sources/source.hpp @@ -40,11 +40,9 @@ public: std::unique_ptr<mbgl::style::Source> releaseCoreSource(); protected: - std::unique_ptr<mbgl::style::Source> ownedSource; mbgl::style::Source& source; mbgl::Map* map; - }; } //android diff --git a/platform/darwin/src/headless_view_cgl.cpp b/platform/darwin/src/headless_view_cgl.cpp deleted file mode 100644 index 08f0da8751..0000000000 --- a/platform/darwin/src/headless_view_cgl.cpp +++ /dev/null @@ -1,74 +0,0 @@ -#include <mbgl/platform/default/headless_view.hpp> - -#include <mbgl/gl/gl.hpp> - -#include <cassert> - -namespace mbgl { - -void HeadlessView::bindFramebuffer() { - assert(fbo); - MBGL_CHECK_ERROR(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo)); -} - -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() { - 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; - } -} - -} // namespace mbgl diff --git a/platform/darwin/src/headless_view_eagl.cpp b/platform/darwin/src/headless_view_eagl.cpp deleted file mode 100644 index cc378912f9..0000000000 --- a/platform/darwin/src/headless_view_eagl.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#include <mbgl/platform/default/headless_view.hpp> - -#include <mbgl/gl/gl.hpp> - -#include <cassert> - -namespace mbgl { - -void HeadlessView::bindFramebuffer() { - assert(fbo); - MBGL_CHECK_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, fbo)); -} - -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() { - 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; - } -} - -} // namespace mbgl diff --git a/platform/default/glfw_view.cpp b/platform/default/glfw_view.cpp index 044181e8c8..47551d786f 100644 --- a/platform/default/glfw_view.cpp +++ b/platform/default/glfw_view.cpp @@ -4,6 +4,7 @@ #include <mbgl/style/transition_options.hpp> #include <mbgl/gl/gl.hpp> #include <mbgl/gl/extension.hpp> +#include <mbgl/gl/context.hpp> #include <mbgl/platform/log.hpp> #include <mbgl/platform/platform.hpp> #include <mbgl/util/string.hpp> @@ -124,13 +125,21 @@ GLFWView::~GLFWView() { glfwTerminate(); } -void GLFWView::initialize(mbgl::Map *map_) { - View::initialize(map_); +void GLFWView::setMap(mbgl::Map *map_) { + map = map_; map->addAnnotationIcon("default_marker", makeSpriteImage(22, 22, 1)); } +void GLFWView::updateViewBinding() { + getContext().bindFramebuffer.setCurrentValue(0); + getContext().viewport.setCurrentValue( + { 0, 0, static_cast<uint16_t>(fbWidth), static_cast<uint16_t>(fbHeight) }); +} + void GLFWView::bind() { - MBGL_CHECK_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, 0)); + getContext().bindFramebuffer = 0; + getContext().viewport = { 0, 0, static_cast<uint16_t>(fbWidth), + static_cast<uint16_t>(fbHeight) }; } void GLFWView::onKey(GLFWwindow *window, int key, int /*scancode*/, int action, int mods) { @@ -365,8 +374,8 @@ void GLFWView::onWindowResize(GLFWwindow *window, int width, int height) { GLFWView *view = reinterpret_cast<GLFWView *>(glfwGetWindowUserPointer(window)); view->width = width; view->height = height; - - view->map->update(mbgl::Update::Dimensions); + view->map->setSize({{ static_cast<uint16_t>(view->width), + static_cast<uint16_t>(view->height) }}); } void GLFWView::onFramebufferResize(GLFWwindow *window, int width, int height) { @@ -374,7 +383,11 @@ void GLFWView::onFramebufferResize(GLFWwindow *window, int width, int height) { view->fbWidth = width; view->fbHeight = height; - view->map->update(mbgl::Update::Repaint); + // This is only triggered when the framebuffer is resized, but not the window. It can + // happen when you move the window between screens with a different pixel ratio. + // We are forcing a repaint my invalidating the view, which triggers a rerender with the + // new framebuffer dimensions. + view->invalidate(); } void GLFWView::onMouseClick(GLFWwindow *window, int button, int action, int modifiers) { @@ -440,15 +453,15 @@ void GLFWView::run() { const double started = glfwGetTime(); glfwMakeContextCurrent(window); - glViewport(0, 0, fbWidth, fbHeight); - map->render(); + updateViewBinding(); + map->render(*this); glfwSwapBuffers(window); report(1000 * (glfwGetTime() - started)); if (benchmark) { - map->update(mbgl::Update::Repaint); + invalidate(); } dirty = false; diff --git a/platform/default/headless_view.cpp b/platform/default/headless_view.cpp deleted file mode 100644 index f96b0a7f6d..0000000000 --- a/platform/default/headless_view.cpp +++ /dev/null @@ -1,70 +0,0 @@ -#include <mbgl/platform/default/headless_view.hpp> - -#include <mbgl/gl/gl.hpp> - -#include <cstring> - -namespace mbgl { - -HeadlessView::HeadlessView(float pixelRatio_, uint16_t width, uint16_t height) - : pixelRatio(pixelRatio_), dimensions({ { width, height } }), needsResize(true) { -} - -HeadlessView::~HeadlessView() { - clearBuffers(); -} - -void HeadlessView::bind() { - if (needsResize) { - clearBuffers(); - resizeFramebuffer(); - needsResize = false; - } else { - bindFramebuffer(); - } -} - -void HeadlessView::resize(const uint16_t width, const uint16_t height) { - if(dimensions[0] == width && - dimensions[1] == height) { - return; - } - dimensions = {{ width, height }}; - needsResize = true; -} - -PremultipliedImage HeadlessView::readStillImage(std::array<uint16_t, 2> size) { - if (!size[0] || !size[1]) { - size[0] = dimensions[0] * pixelRatio; - size[1] = dimensions[1] * pixelRatio; - } - - PremultipliedImage image { size[0], size[1] }; - MBGL_CHECK_ERROR(glReadPixels(0, 0, size[0], size[1], GL_RGBA, GL_UNSIGNED_BYTE, image.data.get())); - - const auto stride = image.stride(); - auto tmp = std::make_unique<uint8_t[]>(stride); - uint8_t* rgba = image.data.get(); - for (int i = 0, j = size[1] - 1; i < j; i++, j--) { - std::memcpy(tmp.get(), rgba + i * stride, stride); - std::memcpy(rgba + i * stride, rgba + j * stride, stride); - std::memcpy(rgba + j * stride, tmp.get(), stride); - } - - return image; -} - -float HeadlessView::getPixelRatio() const { - return pixelRatio; -} - -std::array<uint16_t, 2> HeadlessView::getSize() const { - return dimensions; -} - -std::array<uint16_t, 2> HeadlessView::getFramebufferSize() const { - return {{ static_cast<uint16_t>(dimensions[0] * pixelRatio), - static_cast<uint16_t>(dimensions[1] * pixelRatio) }}; -} - -} // namespace mbgl diff --git a/platform/default/headless_view_glx.cpp b/platform/default/headless_view_glx.cpp deleted file mode 100644 index 08f0da8751..0000000000 --- a/platform/default/headless_view_glx.cpp +++ /dev/null @@ -1,74 +0,0 @@ -#include <mbgl/platform/default/headless_view.hpp> - -#include <mbgl/gl/gl.hpp> - -#include <cassert> - -namespace mbgl { - -void HeadlessView::bindFramebuffer() { - assert(fbo); - MBGL_CHECK_ERROR(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo)); -} - -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() { - 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; - } -} - -} // namespace mbgl diff --git a/platform/default/offscreen_view.cpp b/platform/default/offscreen_view.cpp new file mode 100644 index 0000000000..eaf87d0f87 --- /dev/null +++ b/platform/default/offscreen_view.cpp @@ -0,0 +1,47 @@ +#include <mbgl/platform/default/offscreen_view.hpp> +#include <mbgl/gl/context.hpp> +#include <mbgl/gl/gl.hpp> + +#include <cstring> +#include <cassert> + +namespace mbgl { + +OffscreenView::OffscreenView(gl::Context& context_, std::array<uint16_t, 2> size_) + : context(context_), size(std::move(size_)) { + assert(size[0] > 0 && size[1] > 0); +} + +void OffscreenView::bind() { + if (!framebuffer) { + color = context.createRenderbuffer<gl::RenderbufferType::RGBA>(size); + depthStencil = context.createRenderbuffer<gl::RenderbufferType::DepthStencil>(size); + framebuffer = context.createFramebuffer(*color, *depthStencil); + } else { + context.bindFramebuffer = framebuffer->framebuffer; + } + + context.viewport = { 0, 0, size[0], size[1] }; +} + +PremultipliedImage OffscreenView::readStillImage() { + PremultipliedImage image { size[0], size[1] }; + MBGL_CHECK_ERROR(glReadPixels(0, 0, size[0], size[1], GL_RGBA, GL_UNSIGNED_BYTE, image.data.get())); + + const auto stride = image.stride(); + auto tmp = std::make_unique<uint8_t[]>(stride); + uint8_t* rgba = image.data.get(); + for (int i = 0, j = size[1] - 1; i < j; i++, j--) { + std::memcpy(tmp.get(), rgba + i * stride, stride); + std::memcpy(rgba + i * stride, rgba + j * stride, stride); + std::memcpy(rgba + j * stride, tmp.get(), stride); + } + + return image; +} + +std::array<uint16_t, 2> OffscreenView::getSize() const { + return size; +} + +} // namespace mbgl diff --git a/platform/ios/config.cmake b/platform/ios/config.cmake index db75d7a4de..0813d0338f 100644 --- a/platform/ios/config.cmake +++ b/platform/ios/config.cmake @@ -38,10 +38,9 @@ macro(mbgl_platform_core) # Headless view 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 + PRIVATE platform/default/offscreen_view.cpp # Thread pool PRIVATE platform/default/thread_pool.cpp diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm index 3d93dc8fc9..41e049ad61 100644 --- a/platform/ios/src/MGLMapView.mm +++ b/platform/ios/src/MGLMapView.mm @@ -2,6 +2,7 @@ #include <mbgl/platform/log.hpp> #include <mbgl/gl/extension.hpp> +#include <mbgl/gl/context.hpp> #import <GLKit/GLKit.h> #import <OpenGLES/EAGL.h> @@ -26,7 +27,7 @@ #include <mbgl/util/projection.hpp> #include <mbgl/util/default_styles.hpp> #include <mbgl/util/chrono.hpp> -#import <mbgl/util/run_loop.hpp> +#include <mbgl/util/run_loop.hpp> #import "Mapbox.h" #import "MGLFeature_Private.h" @@ -398,10 +399,12 @@ public: [[NSFileManager defaultManager] removeItemAtPath:fileCachePath error:NULL]; // setup mbgl map - const float scaleFactor = [UIScreen instancesRespondToSelector:@selector(nativeScale)] ? [[UIScreen mainScreen] nativeScale] : [[UIScreen mainScreen] scale]; + const std::array<uint16_t, 2> size = {{ static_cast<uint16_t>(self.bounds.size.width), + static_cast<uint16_t>(self.bounds.size.height) }}; mbgl::DefaultFileSource *mbglFileSource = [MGLOfflineStorage sharedOfflineStorage].mbglFileSource; + const float scaleFactor = [UIScreen instancesRespondToSelector:@selector(nativeScale)] ? [[UIScreen mainScreen] nativeScale] : [[UIScreen mainScreen] scale]; _mbglThreadPool = new mbgl::ThreadPool(4); - _mbglMap = new mbgl::Map(*_mbglView, *_mbglView, scaleFactor, *mbglFileSource, *_mbglThreadPool, mbgl::MapMode::Continuous, mbgl::GLContextMode::Unique, mbgl::ConstrainMode::None, mbgl::ViewportMode::Default); + _mbglMap = new mbgl::Map(*_mbglView, size, scaleFactor, *mbglFileSource, *_mbglThreadPool, mbgl::MapMode::Continuous, mbgl::GLContextMode::Unique, mbgl::ConstrainMode::None, mbgl::ViewportMode::Default); [self validateTileCacheSize]; // start paused if in IB @@ -868,7 +871,8 @@ public: { if ( ! self.dormant) { - _mbglMap->render(); + _mbglView->updateViewBinding(); + _mbglMap->render(*_mbglView); [self updateUserLocationAnnotationView]; } @@ -883,7 +887,8 @@ public: if ( ! _isTargetingInterfaceBuilder) { - _mbglMap->update(mbgl::Update::Dimensions); + _mbglMap->setSize({{ static_cast<uint16_t>(self.bounds.size.width), + static_cast<uint16_t>(self.bounds.size.height) }}); } if (self.attributionSheet.visible) @@ -4946,18 +4951,32 @@ public: : nativeView(nativeView_) { } - std::array<uint16_t, 2> getSize() const override { - return {{ static_cast<uint16_t>([nativeView bounds].size.width), - static_cast<uint16_t>([nativeView bounds].size.height) }}; + mbgl::gl::value::Viewport::Type getViewport() const { + return { 0, 0, static_cast<uint16_t>(nativeView.glView.drawableWidth), + static_cast<uint16_t>(nativeView.glView.drawableHeight) }; } - std::array<uint16_t, 2> getFramebufferSize() const override { - return {{ static_cast<uint16_t>([[nativeView glView] drawableWidth]), - static_cast<uint16_t>([[nativeView glView] drawableHeight]) }}; + /// This function is called before we start rendering, when iOS invokes our rendering method. + /// iOS already sets the correct framebuffer and viewport for us, so we need to update the + /// context state with the anticipated values. + void updateViewBinding() { + // We are using 0 as the placeholder value for the GLKView's framebuffer. + getContext().bindFramebuffer.setCurrentValue(0); + getContext().viewport.setCurrentValue(getViewport()); } void bind() override { - [nativeView.glView bindDrawable]; + if (getContext().bindFramebuffer != 0) { + // Something modified our state, and we need to bind the original drawable again. + // Doing this also sets the viewport to the full framebuffer. + // Note that in reality, iOS does not use the Framebuffer 0 (it's typically 1), and we + // only use this is a placeholder value. + [nativeView.glView bindDrawable]; + updateViewBinding(); + } else { + // Our framebuffer is still bound, but the viewport might have changed. + getContext().viewport = getViewport(); + } } void notifyMapChange(mbgl::MapChange change) override @@ -5195,7 +5214,7 @@ void MGLFinishCustomStyleLayer(void *context) - (void)setCustomStyleLayersNeedDisplay { - _mbglMap->update(mbgl::Update::Repaint); + [self setNeedsGLDisplay]; } - (mbgl::Map *)mbglMap { diff --git a/platform/linux/config.cmake b/platform/linux/config.cmake index d033f9df21..6bde3136f2 100644 --- a/platform/linux/config.cmake +++ b/platform/linux/config.cmake @@ -42,10 +42,9 @@ macro(mbgl_platform_core) # 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/offscreen_view.cpp # Thread pool PRIVATE platform/default/thread_pool.cpp diff --git a/platform/macos/config.cmake b/platform/macos/config.cmake index 198dfc7083..27bf555ec6 100644 --- a/platform/macos/config.cmake +++ b/platform/macos/config.cmake @@ -36,10 +36,9 @@ macro(mbgl_platform_core) # 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 + PRIVATE platform/default/offscreen_view.cpp # Thread pool PRIVATE platform/default/thread_pool.cpp diff --git a/platform/macos/src/MGLMapView.mm b/platform/macos/src/MGLMapView.mm index 475ca2d259..ebcd8e00b0 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/gl/context.hpp> #import <mbgl/map/backend.hpp> #import <mbgl/sprite/sprite_image.hpp> #import <mbgl/storage/default_file_source.hpp> @@ -263,9 +264,12 @@ public: NSURL *legacyCacheURL = [cachesDirectoryURL URLByAppendingPathComponent:@"cache.db"]; [[NSFileManager defaultManager] removeItemAtURL:legacyCacheURL error:NULL]; - mbgl::DefaultFileSource *mbglFileSource = [MGLOfflineStorage sharedOfflineStorage].mbglFileSource; + mbgl::DefaultFileSource* mbglFileSource = [MGLOfflineStorage sharedOfflineStorage].mbglFileSource; + + const std::array<uint16_t, 2> size = {{ static_cast<uint16_t>(self.bounds.size.width), + static_cast<uint16_t>(self.bounds.size.height) }}; _mbglThreadPool = new mbgl::ThreadPool(4); - _mbglMap = new mbgl::Map(*_mbglView, *_mbglView, [NSScreen mainScreen].backingScaleFactor, *mbglFileSource, *_mbglThreadPool, mbgl::MapMode::Continuous, mbgl::GLContextMode::Unique, mbgl::ConstrainMode::None, mbgl::ViewportMode::Default); + _mbglMap = new mbgl::Map(*_mbglView, size, [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 @@ -635,7 +639,8 @@ public: [self validateTileCacheSize]; } if (!_isTargetingInterfaceBuilder) { - _mbglMap->update(mbgl::Update::Dimensions); + _mbglMap->setSize({{ static_cast<uint16_t>(self.bounds.size.width), + static_cast<uint16_t>(self.bounds.size.height) }}); } } @@ -746,9 +751,8 @@ public: return reinterpret_cast<mbgl::gl::glProc>(symbol); }); - _mbglView->updateFramebufferBinding(); - - _mbglMap->render(); + _mbglView->updateViewBinding(); + _mbglMap->render(*_mbglView); if (_isPrinting) { _isPrinting = NO; @@ -2539,17 +2543,6 @@ public: MGLMapViewImpl(MGLMapView *nativeView_) : nativeView(nativeView_) {} - std::array<uint16_t, 2> getSize() const override { - return {{ static_cast<uint16_t>(nativeView.bounds.size.width), - static_cast<uint16_t>(nativeView.bounds.size.height) }}; - } - - std::array<uint16_t, 2> getFramebufferSize() const override { - NSRect bounds = [nativeView convertRectToBacking:nativeView.bounds]; - return {{ static_cast<uint16_t>(bounds.size.width), - static_cast<uint16_t>(bounds.size.height) }}; - } - void notifyMapChange(mbgl::MapChange change) override { [nativeView notifyMapChange:change]; } @@ -2567,26 +2560,34 @@ public: [NSOpenGLContext clearCurrentContext]; } - void updateFramebufferBinding() { - MBGL_CHECK_ERROR(glGetIntegerv(GL_FRAMEBUFFER_BINDING, &fbo)); + mbgl::gl::value::Viewport::Type getViewport() const { + return { 0, 0, static_cast<uint16_t>(nativeView.bounds.size.width), + static_cast<uint16_t>(nativeView.bounds.size.height) }; } - void bind() override { - MBGL_CHECK_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, fbo)); + void updateViewBinding() { + fbo = mbgl::gl::value::BindFramebuffer::Get(); + getContext().bindFramebuffer.setCurrentValue(fbo); + getContext().viewport.setCurrentValue(getViewport()); } - mbgl::PremultipliedImage readStillImage(std::array<uint16_t, 2> size = {{ 0, 0 }}) override { - if (!size[0] || !size[1]) { - size = getFramebufferSize(); - } + void bind() override { + getContext().bindFramebuffer = fbo; + getContext().viewport = getViewport(); + } - mbgl::PremultipliedImage image { size[0], size[1] }; - MBGL_CHECK_ERROR(glReadPixels(0, 0, size[0], size[1], GL_RGBA, GL_UNSIGNED_BYTE, image.data.get())); + mbgl::PremultipliedImage readStillImage() { + NSRect bounds = [nativeView convertRectToBacking:nativeView.bounds]; + const uint16_t width = bounds.size.width; + const uint16_t height = bounds.size.height; + mbgl::PremultipliedImage image{ width, height }; + MBGL_CHECK_ERROR( + glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, image.data.get())); const size_t stride = image.stride(); auto tmp = std::make_unique<uint8_t[]>(stride); uint8_t *rgba = image.data.get(); - for (int i = 0, j = size[1] - 1; i < j; i++, j--) { + for (int i = 0, j = height - 1; i < j; i++, j--) { std::memcpy(tmp.get(), rgba + i * stride, stride); std::memcpy(rgba + i * stride, rgba + j * stride, stride); std::memcpy(rgba + j * stride, tmp.get(), stride); diff --git a/platform/node/src/node_map.cpp b/platform/node/src/node_map.cpp index ebdf8d62c3..671bf3e0fd 100644 --- a/platform/node/src/node_map.cpp +++ b/platform/node/src/node_map.cpp @@ -356,21 +356,28 @@ void NodeMap::Render(const Nan::FunctionCallbackInfo<v8::Value>& info) { } void NodeMap::startRender(NodeMap::RenderOptions options) { - view.resize(options.width, options.height); - map->update(mbgl::Update::Dimensions); + map->setSize(std::array<uint16_t, 2>{{ static_cast<uint16_t>(options.width), + static_cast<uint16_t>(options.height) }}); + + const std::array<uint16_t, 2> fbSize{{ static_cast<uint16_t>(options.width * pixelRatio), + static_cast<uint16_t>(options.height * pixelRatio) }}; + if (!view || view->getSize() != fbSize) { + view.reset(); + view = std::make_unique<mbgl::OffscreenView>(backend.getContext(), fbSize); + } map->setClasses(options.classes); map->setLatLngZoom(mbgl::LatLng(options.latitude, options.longitude), options.zoom); map->setBearing(options.bearing); map->setPitch(options.pitch); map->setDebug(options.debugOptions); - map->renderStill([this](const std::exception_ptr eptr, mbgl::PremultipliedImage&& result) { + map->renderStill(*view, [this](const std::exception_ptr eptr) { if (eptr) { error = std::move(eptr); uv_async_send(async); } else { assert(!image.data); - image = std::move(result); + image = view->readStillImage(); uv_async_send(async); } }); @@ -772,15 +779,23 @@ void NodeMap::QueryRenderedFeatures(const Nan::FunctionCallbackInfo<v8::Value>& } } -NodeMap::NodeMap(v8::Local<v8::Object> options) : - 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>(backend, view, view.getPixelRatio(), *this, threadpool, mbgl::MapMode::Still)), - async(new uv_async_t) { +NodeMap::NodeMap(v8::Local<v8::Object> options) + : pixelRatio([&] { + Nan::HandleScope scope; + return Nan::Has(options, Nan::New("ratio").ToLocalChecked()).FromJust() + ? Nan::Get(options, Nan::New("ratio").ToLocalChecked()) + .ToLocalChecked() + ->NumberValue() + : 1.0; + }()), + backend(sharedDisplay()), + map(std::make_unique<mbgl::Map>(backend, + std::array<uint16_t, 2>{{ 256, 256 }}, + pixelRatio, + *this, + threadpool, + mbgl::MapMode::Still)), + async(new uv_async_t) { backend.setMapChangeCallback([&](mbgl::MapChange change) { if (change == mbgl::MapChangeDidFailLoadingMap) { diff --git a/platform/node/src/node_map.hpp b/platform/node/src/node_map.hpp index 48ff2caab1..45de2733cc 100644 --- a/platform/node/src/node_map.hpp +++ b/platform/node/src/node_map.hpp @@ -5,7 +5,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> +#include <mbgl/platform/default/offscreen_view.hpp> #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-parameter" @@ -54,8 +54,9 @@ public: std::unique_ptr<mbgl::AsyncRequest> request(const mbgl::Resource&, mbgl::FileSource::Callback); + const float pixelRatio; mbgl::HeadlessBackend backend; - mbgl::HeadlessView view; + std::unique_ptr<mbgl::OffscreenView> view; NodeThreadPool threadpool; std::unique_ptr<mbgl::Map> map; diff --git a/platform/qt/app/mapwindow.cpp b/platform/qt/app/mapwindow.cpp index 0cce6caaed..e8e3a13489 100644 --- a/platform/qt/app/mapwindow.cpp +++ b/platform/qt/app/mapwindow.cpp @@ -9,10 +9,15 @@ #include <QMouseEvent> #include <QString> +#if QT_VERSION >= 0x050000 +#include <QWindow> +#endif + int kAnimationDuration = 10000; + MapWindow::MapWindow(const QMapboxGLSettings &settings) - : m_map(nullptr, settings) + : m_map(nullptr, settings, size(), pixelRatio()) , m_bearingAnimation(&m_map, "bearing") , m_zoomAnimation(&m_map, "zoom") { @@ -46,6 +51,17 @@ void MapWindow::selfTest() m_zoomAnimation.start(); } +qreal MapWindow::pixelRatio() { +#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) + return devicePixelRatioF(); +#elif (QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)) + return devicePixelRatio(); +#else + return 1; +#endif +} + + void MapWindow::animationFinished() { qDebug() << "Animation ticks/s: " << m_animationTicks / static_cast<float>(kAnimationDuration) * 1000.; @@ -288,16 +304,12 @@ void MapWindow::initializeGL() QMapbox::initializeGLExtensions(); } -void MapWindow::resizeGL(int w, int h) -{ - QSize size(w, h); - m_map.resize(size); -} - void MapWindow::paintGL() { m_frameDraws++; + m_map.resize(size(), size() * pixelRatio()); + #if QT_VERSION < 0x050400 && defined(__APPLE__) // XXX GL framebuffer is valid only after first attempt of painting on // older versions of Qt on macOS. diff --git a/platform/qt/app/mapwindow.hpp b/platform/qt/app/mapwindow.hpp index fa1c3f4b3b..a579a5bcc5 100644 --- a/platform/qt/app/mapwindow.hpp +++ b/platform/qt/app/mapwindow.hpp @@ -24,6 +24,7 @@ protected slots: private: void changeStyle(); + qreal pixelRatio(); // QGLWidget implementation. void keyPressEvent(QKeyEvent *ev) final; @@ -32,7 +33,6 @@ private: void wheelEvent(QWheelEvent *ev) final; void initializeGL() final; - void resizeGL(int w, int h) final; void paintGL() final; QPointF m_lastPos; diff --git a/platform/qt/config.cmake b/platform/qt/config.cmake index 6df311f885..ff86a0dee1 100644 --- a/platform/qt/config.cmake +++ b/platform/qt/config.cmake @@ -44,11 +44,10 @@ 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 + PRIVATE platform/default/offscreen_view.cpp ) set_source_files_properties( diff --git a/platform/qt/include/qmapboxgl.hpp b/platform/qt/include/qmapboxgl.hpp index ba5631e1e4..d3937ce083 100644 --- a/platform/qt/include/qmapboxgl.hpp +++ b/platform/qt/include/qmapboxgl.hpp @@ -3,6 +3,7 @@ #include <QMapbox> #include <QObject> +#include <QSize> #include <QPointF> class QImage; @@ -10,6 +11,7 @@ class QMargins; class QSize; class QString; class QStringList; +class QOpenGLFramebufferObject; class QMapboxGLPrivate; @@ -95,7 +97,10 @@ public: NorthLeftwards, }; - QMapboxGL(QObject *parent = 0, const QMapboxGLSettings& = QMapboxGLSettings()); + QMapboxGL(QObject* parent = 0, + const QMapboxGLSettings& = QMapboxGLSettings(), + const QSize& size = QSize(), + qreal pixelRatio = 1); virtual ~QMapboxGL(); void cycleDebugOptions(); @@ -167,7 +172,7 @@ public: void scaleBy(double scale, const QPointF ¢er = QPointF()); void rotateBy(const QPointF &first, const QPointF &second); - void resize(const QSize &size); + void resize(const QSize &size, const QSize &framebufferSize); void addAnnotationIcon(const QString &name, const QImage &sprite); @@ -198,7 +203,11 @@ public: void setFilter(const QString &layer, const QVariant &filter); public slots: +#if QT_VERSION >= 0x050000 + void render(QOpenGLFramebufferObject *fbo = NULL); +#else void render(); +#endif void connectionEstablished(); signals: diff --git a/platform/qt/src/qmapboxgl.cpp b/platform/qt/src/qmapboxgl.cpp index 73a1771908..edda1f9599 100644 --- a/platform/qt/src/qmapboxgl.cpp +++ b/platform/qt/src/qmapboxgl.cpp @@ -6,6 +6,7 @@ #include <mbgl/annotation/annotation.hpp> #include <mbgl/gl/gl.hpp> +#include <mbgl/gl/context.hpp> #include <mbgl/map/camera.hpp> #include <mbgl/map/map.hpp> #include <mbgl/style/conversion.hpp> @@ -23,6 +24,7 @@ #if QT_VERSION >= 0x050000 #include <QGuiApplication> #include <QWindow> +#include <QOpenGLFramebufferObject> #else #include <QCoreApplication> #endif @@ -271,7 +273,7 @@ void QMapboxGLSettings::setAccessToken(const QString &token) Constructs a QMapboxGL object with \a settings and sets \a parent as the parent object. The \a settings cannot be changed after the object is constructed. */ -QMapboxGL::QMapboxGL(QObject *parent, const QMapboxGLSettings &settings) +QMapboxGL::QMapboxGL(QObject *parent, const QMapboxGLSettings &settings, const QSize& size, qreal pixelRatio) : QObject(parent) { // Multiple QMapboxGL running on the same thread @@ -280,7 +282,7 @@ QMapboxGL::QMapboxGL(QObject *parent, const QMapboxGLSettings &settings) loop.setLocalData(std::make_shared<mbgl::util::RunLoop>()); } - d_ptr = new QMapboxGLPrivate(this, settings); + d_ptr = new QMapboxGLPrivate(this, settings, size, pixelRatio); } QMapboxGL::~QMapboxGL() @@ -602,15 +604,14 @@ void QMapboxGL::rotateBy(const QPointF &first, const QPointF &second) mbgl::ScreenCoordinate { second.x(), second.y() }); } -void QMapboxGL::resize(const QSize& size) +void QMapboxGL::resize(const QSize& size, const QSize& framebufferSize) { - QSize converted = size / d_ptr->getPixelRatio(); - if (d_ptr->size == converted) return; + if (d_ptr->size == size && d_ptr->fbSize == framebufferSize) return; - glViewport(0, 0, converted.width(), converted.height()); + d_ptr->size = size; + d_ptr->fbSize = framebufferSize; - d_ptr->size = converted; - d_ptr->mapObj->update(mbgl::Update::Dimensions); + d_ptr->mapObj->setSize({{ static_cast<uint16_t>(size.width()), static_cast<uint16_t>(size.height()) }}); } void QMapboxGL::addAnnotationIcon(const QString &name, const QImage &sprite) @@ -793,19 +794,29 @@ void QMapboxGL::setFilter(const QString& layer_, const QVariant& filter_) qWarning() << "Layer doesn't support filters"; } +#if QT_VERSION >= 0x050000 +void QMapboxGL::render(QOpenGLFramebufferObject *fbo) +{ + d_ptr->dirty = false; + d_ptr->updateFramebufferBinding(fbo); + d_ptr->mapObj->render(*d_ptr); +} +#else void QMapboxGL::render() { d_ptr->dirty = false; - d_ptr->mapObj->render(); + d_ptr->mapObj->render(*d_ptr); } +#endif void QMapboxGL::connectionEstablished() { d_ptr->connectionEstablished(); } -QMapboxGLPrivate::QMapboxGLPrivate(QMapboxGL *q, const QMapboxGLSettings &settings) +QMapboxGLPrivate::QMapboxGLPrivate(QMapboxGL *q, const QMapboxGLSettings &settings, const QSize &size_, qreal pixelRatio) : QObject(q) + , size(size_) , q_ptr(q) , fileSourceObj(std::make_unique<mbgl::DefaultFileSource>( settings.cacheDatabasePath().toStdString(), @@ -813,7 +824,8 @@ QMapboxGLPrivate::QMapboxGLPrivate(QMapboxGL *q, const QMapboxGLSettings &settin settings.cacheDatabaseMaximumSize())) , threadPool(4) , mapObj(std::make_unique<mbgl::Map>( - *this, *this, getPixelRatio(), *fileSourceObj, threadPool, + *this, std::array<uint16_t, 2>{{ static_cast<uint16_t>(size.width()), static_cast<uint16_t>(size.height()) }}, + pixelRatio, *fileSourceObj, threadPool, static_cast<mbgl::MapMode>(settings.mapMode()), static_cast<mbgl::GLContextMode>(settings.contextMode()), static_cast<mbgl::ConstrainMode>(settings.constrainMode()), @@ -830,36 +842,42 @@ QMapboxGLPrivate::~QMapboxGLPrivate() { } -float QMapboxGLPrivate::getPixelRatio() const -{ #if QT_VERSION >= 0x050000 - // QWindow is the most reliable pixel ratio because QGuiApplication returns - // the maximum pixel ratio of all available QScreen objects - this is not - // valid for cases e.g. where two or more QScreen objects with different - // pixel ratios are present and the window shows on the screen with lower - // pixel ratio. - static const float pixelRatio = QGuiApplication::allWindows().first()->devicePixelRatio(); -#else - static const float pixelRatio = 1.0; -#endif - return pixelRatio; +void QMapboxGLPrivate::updateFramebufferBinding(QOpenGLFramebufferObject *fbo_) +{ + fbo = fbo_; + if (fbo) { + getContext().bindFramebuffer.setDirty(); + getContext().viewport.setCurrentValue( + { 0, 0, static_cast<uint16_t>(fbo->width()), static_cast<uint16_t>(fbo->height()) }); + } else { + getContext().bindFramebuffer.setCurrentValue(0); + getContext().viewport.setCurrentValue({ 0, 0, static_cast<uint16_t>(fbSize.width()), + static_cast<uint16_t>(fbSize.height()) }); + } } 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()) }}; + if (fbo) { + fbo->bind(); + getContext().bindFramebuffer.setDirty(); + getContext().viewport = { 0, 0, static_cast<uint16_t>(fbo->width()), + static_cast<uint16_t>(fbo->height()) }; + } else { + getContext().bindFramebuffer = 0; + getContext().viewport = { 0, 0, static_cast<uint16_t>(fbSize.width()), + static_cast<uint16_t>(fbSize.height()) }; + } } - -std::array<uint16_t, 2> QMapboxGLPrivate::getFramebufferSize() const +#else +void QMapboxGLPrivate::bind() { - return {{ static_cast<uint16_t>(size.width() * getPixelRatio()), - static_cast<uint16_t>(size.height() * getPixelRatio()) }}; + getContext().bindFramebuffer = 0; + getContext().viewport = { 0, 0, static_cast<uint16_t>(fbSize.width()), + static_cast<uint16_t>(fbSize.height()) }; } +#endif void QMapboxGLPrivate::invalidate() { diff --git a/platform/qt/src/qmapboxgl_p.hpp b/platform/qt/src/qmapboxgl_p.hpp index 5a228896dc..e7a14601c1 100644 --- a/platform/qt/src/qmapboxgl_p.hpp +++ b/platform/qt/src/qmapboxgl_p.hpp @@ -17,22 +17,27 @@ class QMapboxGLPrivate : public QObject, public mbgl::View, public mbgl::Backend Q_OBJECT public: - explicit QMapboxGLPrivate(QMapboxGL *, const QMapboxGLSettings &); + explicit QMapboxGLPrivate(QMapboxGL *, const QMapboxGLSettings &, const QSize &size, qreal pixelRatio); virtual ~QMapboxGLPrivate(); // mbgl::View implementation. float getPixelRatio() const; void bind() final; - std::array<uint16_t, 2> getSize() const final; - std::array<uint16_t, 2> getFramebufferSize() const final; + std::array<uint16_t, 2> getSize() const; + std::array<uint16_t, 2> getFramebufferSize() const; void activate() final {} void deactivate() final {} void invalidate() final; void notifyMapChange(mbgl::MapChange) final; +#if QT_VERSION >= 0x050000 + void updateFramebufferBinding(QOpenGLFramebufferObject *); +#endif + mbgl::EdgeInsets margins; QSize size { 0, 0 }; + QSize fbSize { 0, 0 }; QMapboxGL *q_ptr { nullptr }; @@ -42,6 +47,8 @@ public: bool dirty { false }; + QOpenGLFramebufferObject *fbo { nullptr }; + public slots: void connectionEstablished(); diff --git a/platform/qt/src/qquickmapboxglrenderer.cpp b/platform/qt/src/qquickmapboxglrenderer.cpp index d550794d64..903e1c0b05 100644 --- a/platform/qt/src/qquickmapboxglrenderer.cpp +++ b/platform/qt/src/qquickmapboxglrenderer.cpp @@ -19,7 +19,7 @@ QQuickMapboxGLRenderer::QQuickMapboxGLRenderer() settings.setCacheDatabaseMaximumSize(20 * 1024 * 1024); settings.setViewportMode(QMapboxGLSettings::FlippedYViewport); - m_map.reset(new QMapboxGL(nullptr, settings)); + m_map.reset(new QMapboxGL(nullptr, settings, QSize(256, 256), 1)); } QQuickMapboxGLRenderer::~QQuickMapboxGLRenderer() @@ -28,7 +28,7 @@ QQuickMapboxGLRenderer::~QQuickMapboxGLRenderer() QOpenGLFramebufferObject* QQuickMapboxGLRenderer::createFramebufferObject(const QSize &size) { - m_map->resize(size); + m_map->resize(size / m_pixelRatio, size); QOpenGLFramebufferObjectFormat format; format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); @@ -38,7 +38,7 @@ QOpenGLFramebufferObject* QQuickMapboxGLRenderer::createFramebufferObject(const void QQuickMapboxGLRenderer::render() { - m_map->render(); + m_map->render(framebufferObject()); } void QQuickMapboxGLRenderer::synchronize(QQuickFramebufferObject *item) @@ -51,6 +51,12 @@ void QQuickMapboxGLRenderer::synchronize(QQuickFramebufferObject *item) m_initialized = true; } + if (auto window = quickMap->window()) { + m_pixelRatio = window->devicePixelRatio(); + } else { + m_pixelRatio = 1; + } + auto syncStatus = quickMap->m_syncState; quickMap->m_syncState = QQuickMapboxGL::NothingNeedsSync; diff --git a/platform/qt/src/qquickmapboxglrenderer.hpp b/platform/qt/src/qquickmapboxglrenderer.hpp index e0fc767d58..7adeea0421 100644 --- a/platform/qt/src/qquickmapboxglrenderer.hpp +++ b/platform/qt/src/qquickmapboxglrenderer.hpp @@ -29,6 +29,7 @@ signals: private: bool m_initialized = false; + qreal m_pixelRatio = 1; QScopedPointer<QMapboxGL> m_map; }; diff --git a/platform/qt/test/headless_view_qt.cpp b/platform/qt/test/headless_view_qt.cpp deleted file mode 100644 index 133b4a2371..0000000000 --- a/platform/qt/test/headless_view_qt.cpp +++ /dev/null @@ -1,82 +0,0 @@ -#include <mbgl/platform/default/headless_view.hpp> - -#include <mbgl/gl/gl.hpp> - -#include <QApplication> -#include <QGLContext> -#include <QGLWidget> - -#if QT_VERSION >= 0x050000 -#include <QOpenGLContext> -#endif - -#include <cassert> - -namespace mbgl { - -void HeadlessView::bindFramebuffer() { - assert(fbo); - MBGL_CHECK_ERROR(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo)); -} - -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() { - 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; - } -} - -} // namespace mbgl diff --git a/platform/qt/test/qmapboxgl.cpp b/platform/qt/test/qmapboxgl.cpp index 8bcc485d89..597aef5df3 100644 --- a/platform/qt/test/qmapboxgl.cpp +++ b/platform/qt/test/qmapboxgl.cpp @@ -19,7 +19,7 @@ public: widget.makeCurrent(); QMapbox::initializeGLExtensions(); - map.resize(QSize(512, 512)); + map.resize(QSize(512, 512), QSize(512, 512)); map.setCoordinateZoom(QMapbox::Coordinate(60.170448, 24.942046), 14); } |