summaryrefslogtreecommitdiff
path: root/platform
diff options
context:
space:
mode:
authorKonstantin Käfer <mail@kkaefer.com>2016-10-10 17:16:37 +0200
committerKonstantin Käfer <mail@kkaefer.com>2016-10-25 13:52:36 -0700
commita4d259c33f9bb890bba97fd89552720e3e0ec09b (patch)
tree342ecc27a6993c48f3a2e1d739fce890350bc44d /platform
parent5cc390d694fc7510d445310d8eb9e32429a5e67b (diff)
downloadqtlocation-mapboxgl-a4d259c33f9bb890bba97fd89552720e3e0ec09b.tar.gz
[core] move gl::Context to Backend and refactor View
Diffstat (limited to 'platform')
-rw-r--r--platform/android/scripts/generate-style-code.js2
-rwxr-xr-xplatform/android/src/jni.cpp2
-rwxr-xr-xplatform/android/src/native_map_view.cpp34
-rwxr-xr-xplatform/android/src/native_map_view.hpp4
-rw-r--r--platform/android/src/style/layers/custom_layer.cpp2
-rw-r--r--platform/android/src/style/sources/source.hpp2
-rw-r--r--platform/darwin/src/headless_view_cgl.cpp74
-rw-r--r--platform/darwin/src/headless_view_eagl.cpp72
-rw-r--r--platform/default/glfw_view.cpp31
-rw-r--r--platform/default/headless_view.cpp70
-rw-r--r--platform/default/headless_view_glx.cpp74
-rw-r--r--platform/default/offscreen_view.cpp47
-rw-r--r--platform/ios/config.cmake3
-rw-r--r--platform/ios/src/MGLMapView.mm45
-rw-r--r--platform/linux/config.cmake3
-rw-r--r--platform/macos/config.cmake3
-rw-r--r--platform/macos/src/MGLMapView.mm57
-rw-r--r--platform/node/src/node_map.cpp41
-rw-r--r--platform/node/src/node_map.hpp5
-rw-r--r--platform/qt/app/mapwindow.cpp26
-rw-r--r--platform/qt/app/mapwindow.hpp2
-rw-r--r--platform/qt/config.cmake3
-rw-r--r--platform/qt/include/qmapboxgl.hpp13
-rw-r--r--platform/qt/src/qmapboxgl.cpp84
-rw-r--r--platform/qt/src/qmapboxgl_p.hpp13
-rw-r--r--platform/qt/src/qquickmapboxglrenderer.cpp12
-rw-r--r--platform/qt/src/qquickmapboxglrenderer.hpp1
-rw-r--r--platform/qt/test/headless_view_qt.cpp82
-rw-r--r--platform/qt/test/qmapboxgl.cpp2
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 &center = 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);
}