[core] move gl::Context to Backend and refactor View
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
#include <mbgl/benchmark/util.hpp>
|
||||
#include <mbgl/map/map.hpp>
|
||||
#include <mbgl/platform/default/headless_backend.hpp>
|
||||
#include <mbgl/platform/default/headless_view.hpp>
|
||||
#include <mbgl/platform/default/offscreen_view.hpp>
|
||||
#include <mbgl/platform/default/thread_pool.hpp>
|
||||
#include <mbgl/sprite/sprite_image.hpp>
|
||||
#include <mbgl/storage/default_file_source.hpp>
|
||||
@@ -29,17 +29,15 @@ public:
|
||||
auto image = std::make_unique<SpriteImage>(std::move(decoded), 1.0);
|
||||
map.addImage("test-icon", std::move(image));
|
||||
|
||||
view.resize(1000, 1000);
|
||||
|
||||
mbgl::benchmark::render(map);
|
||||
mbgl::benchmark::render(map, view);
|
||||
}
|
||||
|
||||
util::RunLoop loop;
|
||||
HeadlessBackend backend;
|
||||
HeadlessView view;
|
||||
OffscreenView view{ backend.getContext(), {{ 1000, 1000 }} };
|
||||
DefaultFileSource fileSource{ "benchmark/fixtures/api/cache.db", "." };
|
||||
ThreadPool threadPool{ 4 };
|
||||
Map map{ backend, view, view.getPixelRatio(), fileSource, threadPool, MapMode::Still };
|
||||
Map map{ backend, view.getSize(), 1, fileSource, threadPool, MapMode::Still };
|
||||
ScreenBox box{{ 0, 0 }, { 1000, 1000 }};
|
||||
};
|
||||
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
#include <mbgl/benchmark/util.hpp>
|
||||
#include <mbgl/platform/default/offscreen_view.hpp>
|
||||
|
||||
#include <mbgl/map/map.hpp>
|
||||
#include <mbgl/map/view.hpp>
|
||||
#include <mbgl/util/image.hpp>
|
||||
#include <mbgl/util/run_loop.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
namespace benchmark {
|
||||
|
||||
void render(Map& map) {
|
||||
void render(Map& map, OffscreenView& view) {
|
||||
PremultipliedImage result;
|
||||
map.renderStill([&result](std::exception_ptr, PremultipliedImage&& image) {
|
||||
result = std::move(image);
|
||||
map.renderStill(view, [&](std::exception_ptr) {
|
||||
result = view.readStillImage();
|
||||
});
|
||||
|
||||
while (!result.size()) {
|
||||
|
||||
@@ -3,10 +3,11 @@
|
||||
namespace mbgl {
|
||||
|
||||
class Map;
|
||||
class OffscreenView;
|
||||
|
||||
namespace benchmark {
|
||||
|
||||
void render(Map&);
|
||||
void render(Map&, OffscreenView&);
|
||||
|
||||
} // namespace benchmark
|
||||
} // namespace mbgl
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <sstream>
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <array>
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -119,7 +120,9 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
mbgl::ThreadPool threadPool(4);
|
||||
|
||||
mbgl::Map map(backend, backend, backend.getPixelRatio(), fileSource, threadPool);
|
||||
mbgl::Map map(backend, view->getSize(), view->getPixelRatio(), fileSource, threadPool);
|
||||
|
||||
backend.setMap(&map);
|
||||
|
||||
// Load settings
|
||||
mbgl::Settings_JSON settings;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <mbgl/util/run_loop.hpp>
|
||||
|
||||
#include <mbgl/platform/default/headless_backend.hpp>
|
||||
#include <mbgl/platform/default/headless_view.hpp>
|
||||
#include <mbgl/platform/default/offscreen_view.hpp>
|
||||
#include <mbgl/platform/default/thread_pool.hpp>
|
||||
#include <mbgl/storage/default_file_source.hpp>
|
||||
|
||||
@@ -29,7 +29,6 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
int width = 512;
|
||||
int height = 512;
|
||||
double pixelRatio = 1.0;
|
||||
static std::string output = "out.png";
|
||||
std::string cache_file = "cache.sqlite";
|
||||
std::string asset_root = ".";
|
||||
@@ -85,9 +84,9 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
HeadlessBackend backend;
|
||||
HeadlessView view(pixelRatio, width, height);
|
||||
OffscreenView view(backend.getContext(), {{ static_cast<uint16_t>(width), static_cast<uint16_t>(height) }});
|
||||
ThreadPool threadPool(4);
|
||||
Map map(backend, view, view.getPixelRatio(), fileSource, threadPool, MapMode::Still);
|
||||
Map map(backend, view.getSize(), 1, fileSource, threadPool, MapMode::Still);
|
||||
|
||||
map.setStyleJSON(style);
|
||||
map.setClasses(classes);
|
||||
@@ -100,7 +99,7 @@ int main(int argc, char *argv[]) {
|
||||
map.setDebug(debug ? mbgl::MapDebugOptions::TileBorders | mbgl::MapDebugOptions::ParseStatus : mbgl::MapDebugOptions::NoDebug);
|
||||
}
|
||||
|
||||
map.renderStill([&](std::exception_ptr error, PremultipliedImage&& image) {
|
||||
map.renderStill(view, [&](std::exception_ptr error) {
|
||||
try {
|
||||
if (error) {
|
||||
std::rethrow_exception(error);
|
||||
@@ -110,7 +109,7 @@ int main(int argc, char *argv[]) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
util::write_file(output, encodePNG(image));
|
||||
util::write_file(output, encodePNG(view.readStillImage()));
|
||||
loop.stop();
|
||||
});
|
||||
|
||||
|
||||
@@ -62,10 +62,12 @@ set(MBGL_CORE_FILES
|
||||
src/mbgl/gl/debugging.hpp
|
||||
src/mbgl/gl/extension.cpp
|
||||
src/mbgl/gl/extension.hpp
|
||||
src/mbgl/gl/framebuffer.hpp
|
||||
src/mbgl/gl/gl.cpp
|
||||
src/mbgl/gl/index_buffer.hpp
|
||||
src/mbgl/gl/object.cpp
|
||||
src/mbgl/gl/object.hpp
|
||||
src/mbgl/gl/renderbuffer.hpp
|
||||
src/mbgl/gl/shader.cpp
|
||||
src/mbgl/gl/shader.hpp
|
||||
src/mbgl/gl/state.hpp
|
||||
@@ -97,7 +99,6 @@ set(MBGL_CORE_FILES
|
||||
include/mbgl/map/camera.hpp
|
||||
include/mbgl/map/map.hpp
|
||||
include/mbgl/map/mode.hpp
|
||||
include/mbgl/map/update.hpp
|
||||
include/mbgl/map/view.hpp
|
||||
src/mbgl/map/backend.cpp
|
||||
src/mbgl/map/change.hpp
|
||||
@@ -106,7 +107,7 @@ set(MBGL_CORE_FILES
|
||||
src/mbgl/map/transform.hpp
|
||||
src/mbgl/map/transform_state.cpp
|
||||
src/mbgl/map/transform_state.hpp
|
||||
src/mbgl/map/view.cpp
|
||||
src/mbgl/map/update.hpp
|
||||
src/mbgl/map/zoom_history.hpp
|
||||
|
||||
# math
|
||||
@@ -135,8 +136,9 @@ set(MBGL_CORE_FILES
|
||||
include/mbgl/platform/default/glfw_view.hpp
|
||||
include/mbgl/platform/default/headless_backend.hpp
|
||||
include/mbgl/platform/default/headless_display.hpp
|
||||
include/mbgl/platform/default/headless_view.hpp
|
||||
include/mbgl/platform/default/offscreen_view.hpp
|
||||
include/mbgl/platform/default/settings_json.hpp
|
||||
include/mbgl/platform/default/thread_pool.hpp
|
||||
|
||||
# renderer
|
||||
src/mbgl/renderer/bucket.hpp
|
||||
|
||||
@@ -36,7 +36,7 @@ target_include_directories(mbgl-core
|
||||
|
||||
target_add_mason_package(mbgl-core PUBLIC geometry)
|
||||
target_add_mason_package(mbgl-core PUBLIC variant)
|
||||
target_add_mason_package(mbgl-core PRIVATE unique_resource)
|
||||
target_add_mason_package(mbgl-core PUBLIC unique_resource)
|
||||
target_add_mason_package(mbgl-core PRIVATE rapidjson)
|
||||
target_add_mason_package(mbgl-core PRIVATE boost)
|
||||
target_add_mason_package(mbgl-core PRIVATE geojson)
|
||||
|
||||
@@ -2,13 +2,21 @@
|
||||
|
||||
#include <mbgl/map/change.hpp>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
class Map;
|
||||
namespace gl {
|
||||
class Context;
|
||||
} // namespace gl
|
||||
|
||||
class Backend {
|
||||
public:
|
||||
virtual ~Backend() = default;
|
||||
Backend();
|
||||
virtual ~Backend();
|
||||
|
||||
// Returns the backend's context which manages OpenGL state.
|
||||
gl::Context& getContext();
|
||||
|
||||
// Called when the backend's GL context needs to be made active or inactive. These are called,
|
||||
// as a matched pair, in four situations:
|
||||
@@ -29,6 +37,9 @@ public:
|
||||
|
||||
// Notifies a watcher of map x/y/scale/rotation changes.
|
||||
virtual void notifyMapChange(MapChange change);
|
||||
|
||||
private:
|
||||
const std::unique_ptr<gl::Context> context;
|
||||
};
|
||||
|
||||
} // namespace mbgl
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
#include <mbgl/util/optional.hpp>
|
||||
#include <mbgl/util/chrono.hpp>
|
||||
#include <mbgl/util/image.hpp>
|
||||
#include <mbgl/map/update.hpp>
|
||||
#include <mbgl/map/mode.hpp>
|
||||
#include <mbgl/util/geo.hpp>
|
||||
#include <mbgl/util/feature.hpp>
|
||||
@@ -35,7 +33,7 @@ class Layer;
|
||||
class Map : private util::noncopyable {
|
||||
public:
|
||||
explicit Map(Backend&,
|
||||
View&,
|
||||
std::array<uint16_t, 2> size,
|
||||
float pixelRatio,
|
||||
FileSource&,
|
||||
Scheduler&,
|
||||
@@ -47,14 +45,14 @@ public:
|
||||
|
||||
// Register a callback that will get called (on the render thread) when all resources have
|
||||
// been loaded and a complete render occurs.
|
||||
using StillImageCallback = std::function<void (std::exception_ptr, PremultipliedImage&&)>;
|
||||
void renderStill(StillImageCallback callback);
|
||||
using StillImageCallback = std::function<void (std::exception_ptr)>;
|
||||
void renderStill(View&, StillImageCallback callback);
|
||||
|
||||
// Triggers a repaint.
|
||||
void triggerRepaint();
|
||||
|
||||
// Main render function.
|
||||
void render();
|
||||
|
||||
// Notifies the Map that the state has changed and an update might be necessary.
|
||||
void update(Update update);
|
||||
void render(View&);
|
||||
|
||||
// Styling
|
||||
void addClass(const std::string&);
|
||||
@@ -138,6 +136,7 @@ public:
|
||||
ViewportMode getViewportMode() const;
|
||||
|
||||
// Size
|
||||
void setSize(const std::array<uint16_t, 2>&);
|
||||
uint16_t getWidth() const;
|
||||
uint16_t getHeight() const;
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <mbgl/util/image.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <mbgl/util/noncopyable.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
@@ -12,29 +10,11 @@ class View : private util::noncopyable {
|
||||
public:
|
||||
virtual ~View() = default;
|
||||
|
||||
// Called when this View is associated with a Map object.
|
||||
virtual void initialize(Map*);
|
||||
|
||||
// Called when this View is used for rendering. Implementations should ensure that a renderable
|
||||
// object is bound and glClear/glDraw* calls can be done.
|
||||
// object is bound and glClear/glDraw* calls can be done. They should also make sure that
|
||||
// calling .bind() repeatedly is a no-op and that the appropriate gl::Context values are
|
||||
// set to the current state.
|
||||
virtual void bind() = 0;
|
||||
|
||||
// Called when the View signaled a dimension change. Must return the logical dimension
|
||||
// of this map in pixels.
|
||||
virtual std::array<uint16_t, 2> getSize() const = 0;
|
||||
|
||||
// Called for every frame that is being rendered. Must return the absolute dimensions of
|
||||
// the current framebuffer. Typically, this is the logical width scaled by the pixel ratio,
|
||||
// but in case the view was moved to display with a different pixel ratio, it can also be
|
||||
// different from that rule.
|
||||
virtual std::array<uint16_t, 2> getFramebufferSize() const = 0;
|
||||
|
||||
// Reads the pixel data from the current framebuffer. If your View implementation
|
||||
// doesn't support reading from the framebuffer, return a null pointer.
|
||||
virtual PremultipliedImage readStillImage(std::array<uint16_t, 2> size = {{ 0, 0 }});
|
||||
|
||||
protected:
|
||||
mbgl::Map *map = nullptr;
|
||||
};
|
||||
|
||||
} // namespace mbgl
|
||||
|
||||
@@ -19,6 +19,8 @@ public:
|
||||
|
||||
float getPixelRatio() const;
|
||||
|
||||
void setMap(mbgl::Map*);
|
||||
|
||||
// Callback called when the user presses the key mapped to style change.
|
||||
// The expected action is to set a new style, different to the current one.
|
||||
void setChangeStyleCallback(std::function<void()> callback);
|
||||
@@ -29,18 +31,18 @@ public:
|
||||
|
||||
void run();
|
||||
|
||||
private:
|
||||
// mbgl::View implementation
|
||||
void initialize(mbgl::Map*) override;
|
||||
void updateViewBinding();
|
||||
void bind() override;
|
||||
std::array<uint16_t, 2> getSize() const override;
|
||||
std::array<uint16_t, 2> getFramebufferSize() const override;
|
||||
std::array<uint16_t, 2> getSize() const;
|
||||
std::array<uint16_t, 2> getFramebufferSize() const;
|
||||
|
||||
// mbgl::Backend implementation
|
||||
void activate() override;
|
||||
void deactivate() override;
|
||||
void invalidate() override;
|
||||
|
||||
private:
|
||||
// Window callbacks
|
||||
static void onKey(GLFWwindow *window, int key, int scancode, int action, int mods);
|
||||
static void onScroll(GLFWwindow *window, double xoffset, double yoffset);
|
||||
@@ -76,6 +78,8 @@ private:
|
||||
std::function<void(mbgl::MapChange)> mapChangeCallback;
|
||||
|
||||
private:
|
||||
mbgl::Map* map = nullptr;
|
||||
|
||||
bool fullscreen = false;
|
||||
const bool benchmark = false;
|
||||
bool tracking = false;
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <mbgl/map/view.hpp>
|
||||
#include <mbgl/gl/types.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
class HeadlessView : public View {
|
||||
public:
|
||||
HeadlessView(float pixelRatio = 1, uint16_t width = 256, uint16_t height = 256);
|
||||
~HeadlessView() override;
|
||||
|
||||
void bind() override;
|
||||
|
||||
std::array<uint16_t, 2> getSize() const override;
|
||||
std::array<uint16_t, 2> getFramebufferSize() const override;
|
||||
|
||||
|
||||
PremultipliedImage readStillImage(std::array<uint16_t, 2> size = {{ 0, 0 }}) override;
|
||||
|
||||
float getPixelRatio() const;
|
||||
|
||||
void resize(uint16_t width, uint16_t height);
|
||||
|
||||
private:
|
||||
void clearBuffers();
|
||||
void resizeFramebuffer();
|
||||
void bindFramebuffer();
|
||||
|
||||
private:
|
||||
const float pixelRatio;
|
||||
std::array<uint16_t, 2> dimensions;
|
||||
|
||||
bool needsResize = false;
|
||||
|
||||
gl::FramebufferID fbo = 0;
|
||||
gl::RenderbufferID fboDepthStencil = 0;
|
||||
gl::RenderbufferID fboColor = 0;
|
||||
};
|
||||
|
||||
} // namespace mbgl
|
||||
33
include/mbgl/platform/default/offscreen_view.hpp
Normal file
33
include/mbgl/platform/default/offscreen_view.hpp
Normal file
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#include <mbgl/map/view.hpp>
|
||||
#include <mbgl/gl/framebuffer.hpp>
|
||||
#include <mbgl/gl/renderbuffer.hpp>
|
||||
#include <mbgl/util/optional.hpp>
|
||||
#include <mbgl/util/image.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
namespace gl {
|
||||
class Context;
|
||||
} // namespace gl
|
||||
|
||||
class OffscreenView : public View {
|
||||
public:
|
||||
OffscreenView(gl::Context&, std::array<uint16_t, 2> size = {{ 256, 256 }});
|
||||
|
||||
void bind() override;
|
||||
|
||||
PremultipliedImage readStillImage();
|
||||
|
||||
std::array<uint16_t, 2> getSize() const;
|
||||
|
||||
private:
|
||||
gl::Context& context;
|
||||
std::array<uint16_t, 2> size;
|
||||
optional<gl::Framebuffer> framebuffer;
|
||||
optional<gl::Renderbuffer<gl::RenderbufferType::RGBA>> color;
|
||||
optional<gl::Renderbuffer<gl::RenderbufferType::DepthStencil>> depthStencil;
|
||||
};
|
||||
|
||||
} // namespace mbgl
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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::updateViewBinding() {
|
||||
getContext().bindFramebuffer.setCurrentValue(0);
|
||||
getContext().viewport.setCurrentValue({ 0, 0, static_cast<uint16_t>(fbWidth), static_cast<uint16_t>(fbHeight) });
|
||||
}
|
||||
|
||||
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) }};
|
||||
}
|
||||
|
||||
std::array<uint16_t, 2> NativeMapView::getFramebufferSize() const {
|
||||
return {{ static_cast<uint16_t>(fbWidth), static_cast<uint16_t>(fbHeight) }};
|
||||
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_) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
47
platform/default/offscreen_view.cpp
Normal file
47
platform/default/offscreen_view.cpp
Normal file
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 updateViewBinding() {
|
||||
fbo = mbgl::gl::value::BindFramebuffer::Get();
|
||||
getContext().bindFramebuffer.setCurrentValue(fbo);
|
||||
getContext().viewport.setCurrentValue(getViewport());
|
||||
}
|
||||
|
||||
void bind() override {
|
||||
MBGL_CHECK_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, fbo));
|
||||
getContext().bindFramebuffer = fbo;
|
||||
getContext().viewport = getViewport();
|
||||
}
|
||||
|
||||
mbgl::PremultipliedImage readStillImage(std::array<uint16_t, 2> size = {{ 0, 0 }}) override {
|
||||
if (!size[0] || !size[1]) {
|
||||
size = getFramebufferSize();
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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));
|
||||
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::getSize() const
|
||||
#else
|
||||
void QMapboxGLPrivate::bind()
|
||||
{
|
||||
return {{ static_cast<uint16_t>(size.width()), static_cast<uint16_t>(size.height()) }};
|
||||
}
|
||||
|
||||
std::array<uint16_t, 2> QMapboxGLPrivate::getFramebufferSize() const
|
||||
{
|
||||
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()
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ signals:
|
||||
|
||||
private:
|
||||
bool m_initialized = false;
|
||||
qreal m_pixelRatio = 1;
|
||||
|
||||
QScopedPointer<QMapboxGL> m_map;
|
||||
};
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ global.propertyType = 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) {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include <mbgl/map/view.hpp>
|
||||
#include <mbgl/gl/context.hpp>
|
||||
#include <mbgl/gl/gl.hpp>
|
||||
#include <mbgl/gl/vertex_array.hpp>
|
||||
@@ -142,6 +143,113 @@ UniqueFramebuffer Context::createFramebuffer() {
|
||||
return UniqueFramebuffer{ std::move(id), { this } };
|
||||
}
|
||||
|
||||
UniqueRenderbuffer Context::createRenderbuffer(const RenderbufferType type,
|
||||
const uint16_t width,
|
||||
const uint16_t height) {
|
||||
RenderbufferID id = 0;
|
||||
MBGL_CHECK_ERROR(glGenRenderbuffers(1, &id));
|
||||
UniqueRenderbuffer renderbuffer{ std::move(id), { this } };
|
||||
|
||||
bindRenderbuffer = renderbuffer;
|
||||
MBGL_CHECK_ERROR(
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, static_cast<GLenum>(type), width, height));
|
||||
return renderbuffer;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
void checkFramebuffer() {
|
||||
GLenum status = MBGL_CHECK_ERROR(glCheckFramebufferStatus(GL_FRAMEBUFFER));
|
||||
if (status != GL_FRAMEBUFFER_COMPLETE) {
|
||||
switch (status) {
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
|
||||
throw std::runtime_error("Couldn't create framebuffer: incomplete attachment");
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
|
||||
throw std::runtime_error("Couldn't create framebuffer: incomplete missing attachment");
|
||||
#ifdef GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
|
||||
throw std::runtime_error("Couldn't create framebuffer: incomplete draw buffer");
|
||||
#endif
|
||||
#ifdef GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
|
||||
throw std::runtime_error("Couldn't create framebuffer: incomplete read buffer");
|
||||
#endif
|
||||
#ifdef GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
|
||||
throw std::runtime_error("Couldn't create framebuffer: incomplete dimensions");
|
||||
#endif
|
||||
|
||||
case GL_FRAMEBUFFER_UNSUPPORTED:
|
||||
throw std::runtime_error("Couldn't create framebuffer: unsupported");
|
||||
default:
|
||||
throw std::runtime_error("Couldn't create framebuffer: other");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bindDepthStencilRenderbuffer(
|
||||
const Renderbuffer<RenderbufferType::DepthStencil>& depthStencil) {
|
||||
#ifdef GL_DEPTH_STENCIL_ATTACHMENT
|
||||
MBGL_CHECK_ERROR(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
|
||||
GL_RENDERBUFFER, depthStencil.renderbuffer));
|
||||
#else
|
||||
MBGL_CHECK_ERROR(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER,
|
||||
depthStencil.renderbuffer));
|
||||
MBGL_CHECK_ERROR(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
|
||||
GL_RENDERBUFFER, depthStencil.renderbuffer));
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Framebuffer
|
||||
Context::createFramebuffer(const Renderbuffer<RenderbufferType::RGBA>& color,
|
||||
const Renderbuffer<RenderbufferType::DepthStencil>& depthStencil) {
|
||||
if (color.size != depthStencil.size) {
|
||||
throw new std::runtime_error("Renderbuffer size mismatch");
|
||||
}
|
||||
auto fbo = createFramebuffer();
|
||||
bindFramebuffer = fbo;
|
||||
MBGL_CHECK_ERROR(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
GL_RENDERBUFFER, color.renderbuffer));
|
||||
bindDepthStencilRenderbuffer(depthStencil);
|
||||
checkFramebuffer();
|
||||
return { color.size, std::move(fbo) };
|
||||
}
|
||||
|
||||
Framebuffer Context::createFramebuffer(const Renderbuffer<RenderbufferType::RGBA>& color) {
|
||||
auto fbo = createFramebuffer();
|
||||
bindFramebuffer = fbo;
|
||||
MBGL_CHECK_ERROR(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||
GL_RENDERBUFFER, color.renderbuffer));
|
||||
checkFramebuffer();
|
||||
return { color.size, std::move(fbo) };
|
||||
}
|
||||
|
||||
Framebuffer
|
||||
Context::createFramebuffer(const Texture& color,
|
||||
const Renderbuffer<RenderbufferType::DepthStencil>& depthStencil) {
|
||||
if (color.size != depthStencil.size) {
|
||||
throw new std::runtime_error("Renderbuffer size mismatch");
|
||||
}
|
||||
auto fbo = createFramebuffer();
|
||||
bindFramebuffer = fbo;
|
||||
MBGL_CHECK_ERROR(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
|
||||
color.texture, 0));
|
||||
bindDepthStencilRenderbuffer(depthStencil);
|
||||
checkFramebuffer();
|
||||
return { color.size, std::move(fbo) };
|
||||
}
|
||||
|
||||
Framebuffer Context::createFramebuffer(const Texture& color) {
|
||||
auto fbo = createFramebuffer();
|
||||
bindFramebuffer = fbo;
|
||||
MBGL_CHECK_ERROR(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
|
||||
color.texture, 0));
|
||||
checkFramebuffer();
|
||||
return { color.size, std::move(fbo) };
|
||||
}
|
||||
|
||||
UniqueTexture
|
||||
Context::createTexture(uint16_t width, uint16_t height, const void* data, TextureUnit unit) {
|
||||
auto obj = createTexture();
|
||||
@@ -186,50 +294,37 @@ void Context::reset() {
|
||||
performCleanup();
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
template <typename Fn>
|
||||
void applyStateFunction(Context& context, Fn&& fn) {
|
||||
fn(context.stencilFunc);
|
||||
fn(context.stencilMask);
|
||||
fn(context.stencilTest);
|
||||
fn(context.stencilOp);
|
||||
fn(context.depthRange);
|
||||
fn(context.depthMask);
|
||||
fn(context.depthTest);
|
||||
fn(context.depthFunc);
|
||||
fn(context.blend);
|
||||
fn(context.blendFunc);
|
||||
fn(context.blendColor);
|
||||
fn(context.colorMask);
|
||||
fn(context.clearDepth);
|
||||
fn(context.clearColor);
|
||||
fn(context.clearStencil);
|
||||
fn(context.program);
|
||||
fn(context.lineWidth);
|
||||
fn(context.activeTexture);
|
||||
fn(context.bindFramebuffer);
|
||||
fn(context.viewport);
|
||||
#if not MBGL_USE_GLES2
|
||||
fn(context.pixelZoom);
|
||||
fn(context.rasterPos);
|
||||
#endif // MBGL_USE_GLES2
|
||||
for (auto& tex : context.texture) {
|
||||
fn(tex);
|
||||
}
|
||||
fn(context.vertexBuffer);
|
||||
fn(context.elementBuffer);
|
||||
fn(context.vertexArrayObject);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void Context::resetState() {
|
||||
applyStateFunction(*this, [](auto& state) { state.reset(); });
|
||||
}
|
||||
|
||||
void Context::setDirtyState() {
|
||||
applyStateFunction(*this, [](auto& state) { state.setDirty(); });
|
||||
// Note: does not set viewport/bindFramebuffer to dirty since they are handled separately in
|
||||
// the view object.
|
||||
stencilFunc.setDirty();
|
||||
stencilMask.setDirty();
|
||||
stencilTest.setDirty();
|
||||
stencilOp.setDirty();
|
||||
depthRange.setDirty();
|
||||
depthMask.setDirty();
|
||||
depthTest.setDirty();
|
||||
depthFunc.setDirty();
|
||||
blend.setDirty();
|
||||
blendFunc.setDirty();
|
||||
blendColor.setDirty();
|
||||
colorMask.setDirty();
|
||||
clearDepth.setDirty();
|
||||
clearColor.setDirty();
|
||||
clearStencil.setDirty();
|
||||
program.setDirty();
|
||||
lineWidth.setDirty();
|
||||
activeTexture.setDirty();
|
||||
#if not MBGL_USE_GLES2
|
||||
pixelZoom.setDirty();
|
||||
rasterPos.setDirty();
|
||||
#endif // MBGL_USE_GLES2
|
||||
for (auto& tex : texture) {
|
||||
tex.setDirty();
|
||||
}
|
||||
vertexBuffer.setDirty();
|
||||
elementBuffer.setDirty();
|
||||
vertexArrayObject.setDirty();
|
||||
}
|
||||
|
||||
void Context::performCleanup() {
|
||||
@@ -289,6 +384,12 @@ void Context::performCleanup() {
|
||||
glDeleteFramebuffers(int(abandonedFramebuffers.size()), abandonedFramebuffers.data()));
|
||||
abandonedFramebuffers.clear();
|
||||
}
|
||||
|
||||
if (!abandonedRenderbuffers.empty()) {
|
||||
MBGL_CHECK_ERROR(glDeleteRenderbuffers(int(abandonedRenderbuffers.size()),
|
||||
abandonedRenderbuffers.data()));
|
||||
abandonedRenderbuffers.clear();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace gl
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
#include <mbgl/gl/state.hpp>
|
||||
#include <mbgl/gl/value.hpp>
|
||||
#include <mbgl/gl/texture.hpp>
|
||||
#include <mbgl/gl/renderbuffer.hpp>
|
||||
#include <mbgl/gl/framebuffer.hpp>
|
||||
#include <mbgl/gl/vertex_buffer.hpp>
|
||||
#include <mbgl/gl/index_buffer.hpp>
|
||||
#include <mbgl/gl/attribute.hpp>
|
||||
@@ -14,6 +16,9 @@
|
||||
#include <array>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
class View;
|
||||
|
||||
namespace gl {
|
||||
|
||||
constexpr size_t TextureMax = 64;
|
||||
@@ -27,7 +32,6 @@ public:
|
||||
UniqueShader createFragmentShader();
|
||||
UniqueTexture createTexture();
|
||||
UniqueVertexArray createVertexArray();
|
||||
UniqueFramebuffer createFramebuffer();
|
||||
|
||||
template <class V>
|
||||
VertexBuffer<V> createVertexBuffer(std::vector<V>&& v) {
|
||||
@@ -44,6 +48,20 @@ public:
|
||||
};
|
||||
}
|
||||
|
||||
template <RenderbufferType type>
|
||||
Renderbuffer<type> createRenderbuffer(const std::array<uint16_t, 2>& size) {
|
||||
static_assert(type == RenderbufferType::RGBA || type == RenderbufferType::DepthStencil,
|
||||
"invalid renderbuffer type");
|
||||
return { size, createRenderbuffer(type, size[0], size[1]) };
|
||||
}
|
||||
|
||||
Framebuffer createFramebuffer(const Renderbuffer<RenderbufferType::RGBA>&,
|
||||
const Renderbuffer<RenderbufferType::DepthStencil>&);
|
||||
Framebuffer createFramebuffer(const Renderbuffer<RenderbufferType::RGBA>&);
|
||||
Framebuffer createFramebuffer(const Texture&,
|
||||
const Renderbuffer<RenderbufferType::DepthStencil>&);
|
||||
Framebuffer createFramebuffer(const Texture&);
|
||||
|
||||
// Create a texture from an image with data.
|
||||
template <typename Image>
|
||||
Texture createTexture(const Image& image, TextureUnit unit = 0) {
|
||||
@@ -87,8 +105,6 @@ public:
|
||||
&& abandonedFramebuffers.empty();
|
||||
}
|
||||
|
||||
void resetState();
|
||||
|
||||
void setDirtyState();
|
||||
|
||||
State<value::StencilFunc> stencilFunc;
|
||||
@@ -111,6 +127,7 @@ public:
|
||||
State<value::ActiveTexture> activeTexture;
|
||||
State<value::BindFramebuffer> bindFramebuffer;
|
||||
State<value::Viewport> viewport;
|
||||
State<value::BindRenderbuffer> bindRenderbuffer;
|
||||
#if not MBGL_USE_GLES2
|
||||
State<value::PixelZoom> pixelZoom;
|
||||
State<value::RasterPos> rasterPos;
|
||||
@@ -124,6 +141,8 @@ private:
|
||||
UniqueBuffer createVertexBuffer(const void* data, std::size_t size);
|
||||
UniqueBuffer createIndexBuffer(const void* data, std::size_t size);
|
||||
UniqueTexture createTexture(uint16_t width, uint16_t height, const void* data, TextureUnit);
|
||||
UniqueFramebuffer createFramebuffer();
|
||||
UniqueRenderbuffer createRenderbuffer(RenderbufferType, uint16_t width, uint16_t height);
|
||||
void bindAttribute(const AttributeBinding&, std::size_t stride, const int8_t* offset);
|
||||
|
||||
friend detail::ProgramDeleter;
|
||||
@@ -132,6 +151,7 @@ private:
|
||||
friend detail::TextureDeleter;
|
||||
friend detail::VertexArrayDeleter;
|
||||
friend detail::FramebufferDeleter;
|
||||
friend detail::RenderbufferDeleter;
|
||||
|
||||
std::vector<TextureID> pooledTextures;
|
||||
|
||||
@@ -141,6 +161,7 @@ private:
|
||||
std::vector<TextureID> abandonedTextures;
|
||||
std::vector<VertexArrayID> abandonedVertexArrays;
|
||||
std::vector<FramebufferID> abandonedFramebuffers;
|
||||
std::vector<RenderbufferID> abandonedRenderbuffers;
|
||||
};
|
||||
|
||||
} // namespace gl
|
||||
|
||||
17
src/mbgl/gl/framebuffer.hpp
Normal file
17
src/mbgl/gl/framebuffer.hpp
Normal file
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <mbgl/gl/object.hpp>
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace mbgl {
|
||||
namespace gl {
|
||||
|
||||
class Framebuffer {
|
||||
public:
|
||||
std::array<uint16_t, 2> size;
|
||||
gl::UniqueFramebuffer framebuffer;
|
||||
};
|
||||
|
||||
} // namespace gl
|
||||
} // namespace mbgl
|
||||
@@ -51,6 +51,7 @@ constexpr const char* stringFromError(GLenum err) {
|
||||
} // namespace
|
||||
|
||||
void checkError(const char* cmd, const char* file, int line) {
|
||||
// fprintf(stderr, "cmd: %s\n", cmd);
|
||||
GLenum err = GL_NO_ERROR;
|
||||
if ((err = glGetError()) != GL_NO_ERROR) {
|
||||
std::string message = std::string(cmd) + ": Error " + stringFromError(err);
|
||||
|
||||
@@ -41,6 +41,11 @@ void FramebufferDeleter::operator()(FramebufferID id) const {
|
||||
context->abandonedFramebuffers.push_back(id);
|
||||
}
|
||||
|
||||
void RenderbufferDeleter::operator()(RenderbufferID id) const {
|
||||
assert(context);
|
||||
context->abandonedRenderbuffers.push_back(id);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace gl
|
||||
} // namespace mbgl
|
||||
|
||||
@@ -41,6 +41,11 @@ struct FramebufferDeleter {
|
||||
void operator()(FramebufferID) const;
|
||||
};
|
||||
|
||||
struct RenderbufferDeleter {
|
||||
Context* context;
|
||||
void operator()(RenderbufferID) const;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
using UniqueProgram = std_experimental::unique_resource<ProgramID, detail::ProgramDeleter>;
|
||||
@@ -49,6 +54,7 @@ using UniqueBuffer = std_experimental::unique_resource<BufferID, detail::BufferD
|
||||
using UniqueTexture = std_experimental::unique_resource<TextureID, detail::TextureDeleter>;
|
||||
using UniqueVertexArray = std_experimental::unique_resource<VertexArrayID, detail::VertexArrayDeleter>;
|
||||
using UniqueFramebuffer = std_experimental::unique_resource<FramebufferID, detail::FramebufferDeleter>;
|
||||
using UniqueRenderbuffer = std_experimental::unique_resource<RenderbufferID, detail::RenderbufferDeleter>;
|
||||
|
||||
} // namespace gl
|
||||
} // namespace mbgl
|
||||
|
||||
19
src/mbgl/gl/renderbuffer.hpp
Normal file
19
src/mbgl/gl/renderbuffer.hpp
Normal file
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <mbgl/gl/object.hpp>
|
||||
|
||||
#include <array>
|
||||
|
||||
namespace mbgl {
|
||||
namespace gl {
|
||||
|
||||
template <RenderbufferType renderbufferType>
|
||||
class Renderbuffer {
|
||||
public:
|
||||
using type = std::integral_constant<RenderbufferType, renderbufferType>;
|
||||
std::array<uint16_t, 2> size;
|
||||
gl::UniqueRenderbuffer renderbuffer;
|
||||
};
|
||||
|
||||
} // namespace gl
|
||||
} // namespace mbgl
|
||||
@@ -3,20 +3,6 @@
|
||||
namespace mbgl {
|
||||
namespace gl {
|
||||
|
||||
// Helper struct that allows obtaining the default value of a Value class
|
||||
template <typename T, typename = void>
|
||||
struct DefaultValue {
|
||||
static typename T::Type Get() {
|
||||
return T::Get();
|
||||
}
|
||||
};
|
||||
template <typename T>
|
||||
struct DefaultValue<T, decltype((void)T::Default, void())> {
|
||||
static typename T::Type Get() {
|
||||
return T::Default;
|
||||
}
|
||||
};
|
||||
|
||||
// Wraps a piece of OpenGL state and remember its value to avoid redundant state calls.
|
||||
// Wrapped types need to implement to the Value class interface:
|
||||
//
|
||||
@@ -26,17 +12,12 @@ struct DefaultValue<T, decltype((void)T::Default, void())> {
|
||||
// static void Set(const Type& value);
|
||||
// static Type Get();
|
||||
// };
|
||||
//
|
||||
// The Get() function is optional, but if it is omitted, you must provide a Default.
|
||||
// Default is also optional, but if it is omitted, you must provide a Get() function.
|
||||
// If both are present, DefaultValue<T>::Get() will use the Default member.
|
||||
template <typename T>
|
||||
class State {
|
||||
public:
|
||||
void operator=(const typename T::Type& value) {
|
||||
if (*this != value) {
|
||||
dirty = false;
|
||||
currentValue = value;
|
||||
setCurrentValue(value);
|
||||
T::Set(currentValue);
|
||||
}
|
||||
}
|
||||
@@ -49,9 +30,9 @@ public:
|
||||
return dirty || currentValue != value;
|
||||
}
|
||||
|
||||
// Explicitly resets the piece of OpenGL state to its default value.
|
||||
void reset() {
|
||||
*this = defaultValue;
|
||||
void setCurrentValue(const typename T::Type& value) {
|
||||
dirty = false;
|
||||
currentValue = value;
|
||||
}
|
||||
|
||||
// Mark the state as dirty. This means that the next time we are assigning a value to this
|
||||
@@ -68,14 +49,9 @@ public:
|
||||
return dirty;
|
||||
}
|
||||
|
||||
void setDefaultValue(const typename T::Type& value) {
|
||||
defaultValue = value;
|
||||
}
|
||||
|
||||
private:
|
||||
typename T::Type defaultValue = DefaultValue<T>::Get();
|
||||
typename T::Type currentValue = defaultValue;
|
||||
bool dirty = false;
|
||||
typename T::Type currentValue = T::Default;
|
||||
bool dirty = true;
|
||||
};
|
||||
|
||||
// Helper struct that stores the current state and restores it upon destruction. You should not use
|
||||
|
||||
@@ -48,6 +48,11 @@ enum class BufferType : uint32_t {
|
||||
Element = 0x8893
|
||||
};
|
||||
|
||||
enum class RenderbufferType : uint32_t {
|
||||
RGBA = 0x8058,
|
||||
DepthStencil = 0x88F0,
|
||||
};
|
||||
|
||||
enum class TextureMipMap : bool { No = false, Yes = true };
|
||||
enum class TextureFilter : bool { Nearest = false, Linear = true };
|
||||
|
||||
|
||||
@@ -241,6 +241,8 @@ ActiveTexture::Type ActiveTexture::Get() {
|
||||
return static_cast<Type>(activeTexture - GL_TEXTURE0);
|
||||
}
|
||||
|
||||
const constexpr Viewport::Type Viewport::Default;
|
||||
|
||||
void Viewport::Set(const Type& value) {
|
||||
MBGL_CHECK_ERROR(glViewport(value.x, value.y, value.width, value.height));
|
||||
}
|
||||
@@ -252,6 +254,8 @@ Viewport::Type Viewport::Get() {
|
||||
static_cast<uint16_t>(viewport[2]), static_cast<uint16_t>(viewport[3]) };
|
||||
}
|
||||
|
||||
const constexpr BindFramebuffer::Type BindFramebuffer::Default;
|
||||
|
||||
void BindFramebuffer::Set(const Type& value) {
|
||||
MBGL_CHECK_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, value));
|
||||
}
|
||||
@@ -262,6 +266,18 @@ BindFramebuffer::Type BindFramebuffer::Get() {
|
||||
return binding;
|
||||
}
|
||||
|
||||
const constexpr BindRenderbuffer::Type BindRenderbuffer::Default;
|
||||
|
||||
void BindRenderbuffer::Set(const Type& value) {
|
||||
MBGL_CHECK_ERROR(glBindRenderbuffer(GL_RENDERBUFFER, value));
|
||||
}
|
||||
|
||||
BindRenderbuffer::Type BindRenderbuffer::Get() {
|
||||
GLint binding;
|
||||
MBGL_CHECK_ERROR(glGetIntegerv(GL_RENDERBUFFER_BINDING, &binding));
|
||||
return binding;
|
||||
}
|
||||
|
||||
const constexpr BindTexture::Type BindTexture::Default;
|
||||
|
||||
void BindTexture::Set(const Type& value) {
|
||||
|
||||
@@ -180,6 +180,7 @@ struct Viewport {
|
||||
uint16_t width;
|
||||
uint16_t height;
|
||||
};
|
||||
static const constexpr Type Default = { 0, 0, 0, 0 };
|
||||
static void Set(const Type&);
|
||||
static Type Get();
|
||||
};
|
||||
@@ -190,6 +191,14 @@ constexpr bool operator!=(const Viewport::Type& a, const Viewport::Type& b) {
|
||||
|
||||
struct BindFramebuffer {
|
||||
using Type = FramebufferID;
|
||||
static const constexpr Type Default = 0;
|
||||
static void Set(const Type&);
|
||||
static Type Get();
|
||||
};
|
||||
|
||||
struct BindRenderbuffer {
|
||||
using Type = RenderbufferID;
|
||||
static const constexpr Type Default = 0;
|
||||
static void Set(const Type&);
|
||||
static Type Get();
|
||||
};
|
||||
|
||||
@@ -1,9 +1,19 @@
|
||||
#include <mbgl/map/backend.hpp>
|
||||
#include <mbgl/gl/context.hpp>
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
Backend::Backend() : context(std::make_unique<gl::Context>()) {
|
||||
}
|
||||
|
||||
gl::Context& Backend::getContext() {
|
||||
return *context;
|
||||
}
|
||||
|
||||
Backend::~Backend() = default;
|
||||
|
||||
void Backend::notifyMapChange(MapChange) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
@@ -35,10 +35,18 @@ enum class RenderState : uint8_t {
|
||||
Fully,
|
||||
};
|
||||
|
||||
struct StillImageRequest {
|
||||
StillImageRequest(View& view_, Map::StillImageCallback&& callback_)
|
||||
: view(view_), callback(std::move(callback_)) {
|
||||
}
|
||||
|
||||
View& view;
|
||||
Map::StillImageCallback callback;
|
||||
};
|
||||
|
||||
class Map::Impl : public style::Observer {
|
||||
public:
|
||||
Impl(Backend&,
|
||||
View&,
|
||||
float pixelRatio,
|
||||
FileSource&,
|
||||
Scheduler&,
|
||||
@@ -54,12 +62,11 @@ public:
|
||||
void onResourceError(std::exception_ptr) override;
|
||||
|
||||
void update();
|
||||
void render();
|
||||
void render(View&);
|
||||
|
||||
void loadStyleJSON(const std::string&);
|
||||
|
||||
Backend& backend;
|
||||
View& view;
|
||||
FileSource& fileSource;
|
||||
Scheduler& scheduler;
|
||||
|
||||
@@ -85,14 +92,14 @@ public:
|
||||
|
||||
std::unique_ptr<AsyncRequest> styleRequest;
|
||||
|
||||
Map::StillImageCallback callback;
|
||||
std::unique_ptr<StillImageRequest> stillImageRequest;
|
||||
size_t sourceCacheSize;
|
||||
TimePoint timePoint;
|
||||
bool loading = false;
|
||||
};
|
||||
|
||||
Map::Map(Backend& backend,
|
||||
View& view,
|
||||
const std::array<uint16_t, 2> size,
|
||||
const float pixelRatio,
|
||||
FileSource& fileSource,
|
||||
Scheduler& scheduler,
|
||||
@@ -101,7 +108,6 @@ Map::Map(Backend& backend,
|
||||
ConstrainMode constrainMode,
|
||||
ViewportMode viewportMode)
|
||||
: impl(std::make_unique<Impl>(backend,
|
||||
view,
|
||||
pixelRatio,
|
||||
fileSource,
|
||||
scheduler,
|
||||
@@ -109,12 +115,10 @@ Map::Map(Backend& backend,
|
||||
contextMode,
|
||||
constrainMode,
|
||||
viewportMode)) {
|
||||
view.initialize(this);
|
||||
update(Update::Dimensions);
|
||||
impl->transform.resize(size);
|
||||
}
|
||||
|
||||
Map::Impl::Impl(Backend& backend_,
|
||||
View& view_,
|
||||
float pixelRatio_,
|
||||
FileSource& fileSource_,
|
||||
Scheduler& scheduler_,
|
||||
@@ -123,7 +127,6 @@ Map::Impl::Impl(Backend& backend_,
|
||||
ConstrainMode constrainMode_,
|
||||
ViewportMode viewportMode_)
|
||||
: backend(backend_),
|
||||
view(view_),
|
||||
fileSource(fileSource_),
|
||||
scheduler(scheduler_),
|
||||
transform([this](MapChange change) { backend.notifyMapChange(change); },
|
||||
@@ -150,42 +153,38 @@ Map::~Map() {
|
||||
impl->backend.deactivate();
|
||||
}
|
||||
|
||||
void Map::renderStill(StillImageCallback callback) {
|
||||
void Map::renderStill(View& view, StillImageCallback callback) {
|
||||
if (!callback) {
|
||||
Log::Error(Event::General, "StillImageCallback not set");
|
||||
return;
|
||||
}
|
||||
|
||||
if (impl->mode != MapMode::Still) {
|
||||
callback(std::make_exception_ptr(util::MisuseException("Map is not in still image render mode")), {});
|
||||
callback(std::make_exception_ptr(util::MisuseException("Map is not in still image render mode")));
|
||||
return;
|
||||
}
|
||||
|
||||
if (impl->callback) {
|
||||
callback(std::make_exception_ptr(util::MisuseException("Map is currently rendering an image")), {});
|
||||
if (impl->stillImageRequest) {
|
||||
callback(std::make_exception_ptr(util::MisuseException("Map is currently rendering an image")));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!impl->style) {
|
||||
callback(std::make_exception_ptr(util::MisuseException("Map doesn't have a style")), {});
|
||||
callback(std::make_exception_ptr(util::MisuseException("Map doesn't have a style")));
|
||||
return;
|
||||
}
|
||||
|
||||
if (impl->style->getLastError()) {
|
||||
callback(impl->style->getLastError(), {});
|
||||
callback(impl->style->getLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
impl->callback = callback;
|
||||
impl->stillImageRequest = std::make_unique<StillImageRequest>(view, std::move(callback));
|
||||
impl->updateFlags |= Update::RenderStill;
|
||||
impl->asyncUpdate.send();
|
||||
}
|
||||
|
||||
void Map::update(Update flags) {
|
||||
impl->onUpdate(flags);
|
||||
}
|
||||
|
||||
void Map::render() {
|
||||
void Map::render(View& view) {
|
||||
if (!impl->style) {
|
||||
return;
|
||||
}
|
||||
@@ -198,7 +197,7 @@ void Map::render() {
|
||||
|
||||
const Update flags = impl->transform.updateTransitions(Clock::now());
|
||||
|
||||
impl->render();
|
||||
impl->render(view);
|
||||
|
||||
impl->backend.notifyMapChange(isFullyLoaded() ?
|
||||
MapChangeDidFinishRenderingFrameFullyRendered :
|
||||
@@ -218,16 +217,20 @@ void Map::render() {
|
||||
// Triggers an asynchronous update, that eventually triggers a view
|
||||
// invalidation, causing renderSync to be called again if in transition.
|
||||
if (flags != Update::Nothing) {
|
||||
update(flags);
|
||||
impl->onUpdate(flags);
|
||||
}
|
||||
}
|
||||
|
||||
void Map::triggerRepaint() {
|
||||
impl->backend.invalidate();
|
||||
}
|
||||
|
||||
void Map::Impl::update() {
|
||||
if (!style) {
|
||||
updateFlags = Update::Nothing;
|
||||
}
|
||||
|
||||
if (updateFlags == Update::Nothing || (mode == MapMode::Still && !callback)) {
|
||||
if (updateFlags == Update::Nothing || (mode == MapMode::Still && !stillImageRequest)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -270,18 +273,19 @@ void Map::Impl::update() {
|
||||
|
||||
if (mode == MapMode::Continuous) {
|
||||
backend.invalidate();
|
||||
} else if (callback && style->isLoaded()) {
|
||||
} else if (stillImageRequest && style->isLoaded()) {
|
||||
// TODO: determine whether we need activate/deactivate
|
||||
backend.activate();
|
||||
render();
|
||||
render(stillImageRequest->view);
|
||||
backend.deactivate();
|
||||
}
|
||||
|
||||
updateFlags = Update::Nothing;
|
||||
}
|
||||
|
||||
void Map::Impl::render() {
|
||||
void Map::Impl::render(View& view) {
|
||||
if (!painter) {
|
||||
painter = std::make_unique<Painter>(transform.getState());
|
||||
painter = std::make_unique<Painter>(backend.getContext(), transform.getState());
|
||||
}
|
||||
|
||||
FrameData frameData { timePoint,
|
||||
@@ -296,8 +300,8 @@ void Map::Impl::render() {
|
||||
annotationManager->getSpriteAtlas());
|
||||
|
||||
if (mode == MapMode::Still) {
|
||||
callback(nullptr, view.readStillImage());
|
||||
callback = nullptr;
|
||||
auto request = std::move(stillImageRequest);
|
||||
request->callback(nullptr);
|
||||
}
|
||||
|
||||
painter->cleanup();
|
||||
@@ -399,12 +403,12 @@ std::string Map::getStyleJSON() const {
|
||||
|
||||
void Map::cancelTransitions() {
|
||||
impl->transform.cancelTransitions();
|
||||
update(Update::Repaint);
|
||||
impl->onUpdate(Update::Repaint);
|
||||
}
|
||||
|
||||
void Map::setGestureInProgress(bool inProgress) {
|
||||
impl->transform.setGestureInProgress(inProgress);
|
||||
update(Update::Repaint);
|
||||
impl->onUpdate(Update::Repaint);
|
||||
}
|
||||
|
||||
bool Map::isGestureInProgress() const {
|
||||
@@ -431,24 +435,24 @@ CameraOptions Map::getCameraOptions(optional<EdgeInsets> padding) const {
|
||||
|
||||
void Map::jumpTo(const CameraOptions& camera) {
|
||||
impl->transform.jumpTo(camera);
|
||||
update(camera.zoom ? Update::RecalculateStyle : Update::Repaint);
|
||||
impl->onUpdate(camera.zoom ? Update::RecalculateStyle : Update::Repaint);
|
||||
}
|
||||
|
||||
void Map::easeTo(const CameraOptions& camera, const AnimationOptions& animation) {
|
||||
impl->transform.easeTo(camera, animation);
|
||||
update(camera.zoom ? Update::RecalculateStyle : Update::Repaint);
|
||||
impl->onUpdate(camera.zoom ? Update::RecalculateStyle : Update::Repaint);
|
||||
}
|
||||
|
||||
void Map::flyTo(const CameraOptions& camera, const AnimationOptions& animation) {
|
||||
impl->transform.flyTo(camera, animation);
|
||||
update(Update::RecalculateStyle);
|
||||
impl->onUpdate(Update::RecalculateStyle);
|
||||
}
|
||||
|
||||
#pragma mark - Position
|
||||
|
||||
void Map::moveBy(const ScreenCoordinate& point, const Duration& duration) {
|
||||
impl->transform.moveBy(point, duration);
|
||||
update(Update::Repaint);
|
||||
impl->onUpdate(Update::Repaint);
|
||||
}
|
||||
|
||||
void Map::setLatLng(const LatLng& latLng, const Duration& duration) {
|
||||
@@ -457,12 +461,12 @@ void Map::setLatLng(const LatLng& latLng, const Duration& duration) {
|
||||
|
||||
void Map::setLatLng(const LatLng& latLng, optional<EdgeInsets> padding, const Duration& duration) {
|
||||
impl->transform.setLatLng(latLng, padding, duration);
|
||||
update(Update::Repaint);
|
||||
impl->onUpdate(Update::Repaint);
|
||||
}
|
||||
|
||||
void Map::setLatLng(const LatLng& latLng, optional<ScreenCoordinate> anchor, const Duration& duration) {
|
||||
impl->transform.setLatLng(latLng, anchor, duration);
|
||||
update(Update::Repaint);
|
||||
impl->onUpdate(Update::Repaint);
|
||||
}
|
||||
|
||||
LatLng Map::getLatLng(optional<EdgeInsets> padding) const {
|
||||
@@ -477,7 +481,7 @@ void Map::resetPosition(optional<EdgeInsets> padding) {
|
||||
camera.padding = padding;
|
||||
camera.zoom = 0;
|
||||
impl->transform.jumpTo(camera);
|
||||
update(Update::RecalculateStyle);
|
||||
impl->onUpdate(Update::RecalculateStyle);
|
||||
}
|
||||
|
||||
|
||||
@@ -485,12 +489,12 @@ void Map::resetPosition(optional<EdgeInsets> padding) {
|
||||
|
||||
void Map::scaleBy(double ds, optional<ScreenCoordinate> anchor, const Duration& duration) {
|
||||
impl->transform.scaleBy(ds, anchor, duration);
|
||||
update(Update::RecalculateStyle);
|
||||
impl->onUpdate(Update::RecalculateStyle);
|
||||
}
|
||||
|
||||
void Map::setScale(double scale, optional<ScreenCoordinate> anchor, const Duration& duration) {
|
||||
impl->transform.setScale(scale, anchor, duration);
|
||||
update(Update::RecalculateStyle);
|
||||
impl->onUpdate(Update::RecalculateStyle);
|
||||
}
|
||||
|
||||
double Map::getScale() const {
|
||||
@@ -503,7 +507,7 @@ void Map::setZoom(double zoom, const Duration& duration) {
|
||||
|
||||
void Map::setZoom(double zoom, optional<EdgeInsets> padding, const Duration& duration) {
|
||||
impl->transform.setZoom(zoom, padding, duration);
|
||||
update(Update::RecalculateStyle);
|
||||
impl->onUpdate(Update::RecalculateStyle);
|
||||
}
|
||||
|
||||
double Map::getZoom() const {
|
||||
@@ -516,7 +520,7 @@ void Map::setLatLngZoom(const LatLng& latLng, double zoom, const Duration& durat
|
||||
|
||||
void Map::setLatLngZoom(const LatLng& latLng, double zoom, optional<EdgeInsets> padding, const Duration& duration) {
|
||||
impl->transform.setLatLngZoom(latLng, zoom, padding, duration);
|
||||
update(Update::RecalculateStyle);
|
||||
impl->onUpdate(Update::RecalculateStyle);
|
||||
}
|
||||
|
||||
CameraOptions Map::cameraForLatLngBounds(const LatLngBounds& bounds, optional<EdgeInsets> padding) const {
|
||||
@@ -613,6 +617,11 @@ double Map::getMaxZoom() const {
|
||||
|
||||
#pragma mark - Size
|
||||
|
||||
void Map::setSize(const std::array<uint16_t, 2>& size) {
|
||||
impl->transform.resize(size);
|
||||
impl->onUpdate(Update::Repaint);
|
||||
}
|
||||
|
||||
uint16_t Map::getWidth() const {
|
||||
return impl->transform.getState().getWidth();
|
||||
}
|
||||
@@ -625,7 +634,7 @@ uint16_t Map::getHeight() const {
|
||||
|
||||
void Map::rotateBy(const ScreenCoordinate& first, const ScreenCoordinate& second, const Duration& duration) {
|
||||
impl->transform.rotateBy(first, second, duration);
|
||||
update(Update::Repaint);
|
||||
impl->onUpdate(Update::Repaint);
|
||||
}
|
||||
|
||||
void Map::setBearing(double degrees, const Duration& duration) {
|
||||
@@ -634,12 +643,12 @@ void Map::setBearing(double degrees, const Duration& duration) {
|
||||
|
||||
void Map::setBearing(double degrees, optional<ScreenCoordinate> anchor, const Duration& duration) {
|
||||
impl->transform.setAngle(-degrees * util::DEG2RAD, anchor, duration);
|
||||
update(Update::Repaint);
|
||||
impl->onUpdate(Update::Repaint);
|
||||
}
|
||||
|
||||
void Map::setBearing(double degrees, optional<EdgeInsets> padding, const Duration& duration) {
|
||||
impl->transform.setAngle(-degrees * util::DEG2RAD, padding, duration);
|
||||
update(Update::Repaint);
|
||||
impl->onUpdate(Update::Repaint);
|
||||
}
|
||||
|
||||
double Map::getBearing() const {
|
||||
@@ -648,7 +657,7 @@ double Map::getBearing() const {
|
||||
|
||||
void Map::resetNorth(const Duration& duration) {
|
||||
impl->transform.setAngle(0, duration);
|
||||
update(Update::Repaint);
|
||||
impl->onUpdate(Update::Repaint);
|
||||
}
|
||||
|
||||
#pragma mark - Pitch
|
||||
@@ -659,7 +668,7 @@ void Map::setPitch(double pitch, const Duration& duration) {
|
||||
|
||||
void Map::setPitch(double pitch, optional<ScreenCoordinate> anchor, const Duration& duration) {
|
||||
impl->transform.setPitch(pitch * util::DEG2RAD, anchor, duration);
|
||||
update(Update::Repaint);
|
||||
impl->onUpdate(Update::Repaint);
|
||||
}
|
||||
|
||||
double Map::getPitch() const {
|
||||
@@ -670,7 +679,7 @@ double Map::getPitch() const {
|
||||
|
||||
void Map::setNorthOrientation(NorthOrientation orientation) {
|
||||
impl->transform.setNorthOrientation(orientation);
|
||||
update(Update::Repaint);
|
||||
impl->onUpdate(Update::Repaint);
|
||||
}
|
||||
|
||||
NorthOrientation Map::getNorthOrientation() const {
|
||||
@@ -681,7 +690,7 @@ NorthOrientation Map::getNorthOrientation() const {
|
||||
|
||||
void Map::setConstrainMode(mbgl::ConstrainMode mode) {
|
||||
impl->transform.setConstrainMode(mode);
|
||||
update(Update::Repaint);
|
||||
impl->onUpdate(Update::Repaint);
|
||||
}
|
||||
|
||||
ConstrainMode Map::getConstrainMode() const {
|
||||
@@ -692,7 +701,7 @@ ConstrainMode Map::getConstrainMode() const {
|
||||
|
||||
void Map::setViewportMode(mbgl::ViewportMode mode) {
|
||||
impl->transform.setViewportMode(mode);
|
||||
update(Update::Repaint);
|
||||
impl->onUpdate(Update::Repaint);
|
||||
}
|
||||
|
||||
ViewportMode Map::getViewportMode() const {
|
||||
@@ -737,17 +746,17 @@ double Map::getTopOffsetPixelsForAnnotationIcon(const std::string& name) {
|
||||
|
||||
AnnotationID Map::addAnnotation(const Annotation& annotation) {
|
||||
auto result = impl->annotationManager->addAnnotation(annotation, getMaxZoom());
|
||||
update(Update::AnnotationStyle | Update::AnnotationData);
|
||||
impl->onUpdate(Update::AnnotationStyle | Update::AnnotationData);
|
||||
return result;
|
||||
}
|
||||
|
||||
void Map::updateAnnotation(AnnotationID id, const Annotation& annotation) {
|
||||
update(impl->annotationManager->updateAnnotation(id, annotation, getMaxZoom()));
|
||||
impl->onUpdate(impl->annotationManager->updateAnnotation(id, annotation, getMaxZoom()));
|
||||
}
|
||||
|
||||
void Map::removeAnnotation(AnnotationID annotation) {
|
||||
impl->annotationManager->removeAnnotation(annotation);
|
||||
update(Update::AnnotationStyle | Update::AnnotationData);
|
||||
impl->onUpdate(Update::AnnotationStyle | Update::AnnotationData);
|
||||
}
|
||||
|
||||
#pragma mark - Feature query api
|
||||
@@ -833,7 +842,7 @@ void Map::addLayer(std::unique_ptr<Layer> layer, const optional<std::string>& be
|
||||
impl->backend.activate();
|
||||
|
||||
impl->style->addLayer(std::move(layer), before);
|
||||
update(Update::Classes);
|
||||
impl->onUpdate(Update::Classes);
|
||||
|
||||
impl->backend.deactivate();
|
||||
}
|
||||
@@ -847,7 +856,7 @@ void Map::removeLayer(const std::string& id) {
|
||||
impl->backend.activate();
|
||||
|
||||
impl->style->removeLayer(id);
|
||||
update(Update::Classes);
|
||||
impl->onUpdate(Update::Classes);
|
||||
|
||||
impl->backend.deactivate();
|
||||
}
|
||||
@@ -861,7 +870,7 @@ void Map::addImage(const std::string& name, std::unique_ptr<const SpriteImage> i
|
||||
impl->style->spriteAtlas->setSprite(name, std::move(image));
|
||||
impl->style->spriteAtlas->updateDirty();
|
||||
|
||||
update(Update::Repaint);
|
||||
impl->onUpdate(Update::Repaint);
|
||||
}
|
||||
|
||||
void Map::removeImage(const std::string& name) {
|
||||
@@ -873,7 +882,7 @@ void Map::removeImage(const std::string& name) {
|
||||
impl->style->spriteAtlas->removeSprite(name);
|
||||
impl->style->spriteAtlas->updateDirty();
|
||||
|
||||
update(Update::Repaint);
|
||||
impl->onUpdate(Update::Repaint);
|
||||
}
|
||||
|
||||
#pragma mark - Defaults
|
||||
@@ -917,7 +926,7 @@ double Map::getDefaultPitch() const {
|
||||
|
||||
void Map::setDebug(MapDebugOptions debugOptions) {
|
||||
impl->debugOptions = debugOptions;
|
||||
update(Update::Repaint);
|
||||
impl->onUpdate(Update::Repaint);
|
||||
}
|
||||
|
||||
void Map::cycleDebugOptions() {
|
||||
@@ -941,7 +950,7 @@ void Map::cycleDebugOptions() {
|
||||
else
|
||||
impl->debugOptions = MapDebugOptions::TileBorders;
|
||||
|
||||
update(Update::Repaint);
|
||||
impl->onUpdate(Update::Repaint);
|
||||
}
|
||||
|
||||
MapDebugOptions Map::getDebug() const {
|
||||
@@ -954,20 +963,20 @@ bool Map::isFullyLoaded() const {
|
||||
|
||||
void Map::addClass(const std::string& className) {
|
||||
if (impl->style && impl->style->addClass(className)) {
|
||||
update(Update::Classes);
|
||||
impl->onUpdate(Update::Classes);
|
||||
}
|
||||
}
|
||||
|
||||
void Map::removeClass(const std::string& className) {
|
||||
if (impl->style && impl->style->removeClass(className)) {
|
||||
update(Update::Classes);
|
||||
impl->onUpdate(Update::Classes);
|
||||
}
|
||||
}
|
||||
|
||||
void Map::setClasses(const std::vector<std::string>& classNames) {
|
||||
if (impl->style) {
|
||||
impl->style->setClasses(classNames);
|
||||
update(Update::Classes);
|
||||
impl->onUpdate(Update::Classes);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1019,10 +1028,6 @@ void Map::Impl::onSourceAttributionChanged(style::Source&, const std::string&) {
|
||||
}
|
||||
|
||||
void Map::Impl::onUpdate(Update flags) {
|
||||
if (flags & Update::Dimensions) {
|
||||
transform.resize(view.getSize());
|
||||
}
|
||||
|
||||
updateFlags |= flags;
|
||||
asyncUpdate.send();
|
||||
}
|
||||
@@ -1036,9 +1041,9 @@ void Map::Impl::onStyleError() {
|
||||
}
|
||||
|
||||
void Map::Impl::onResourceError(std::exception_ptr error) {
|
||||
if (mode == MapMode::Still && callback) {
|
||||
callback(error, {});
|
||||
callback = nullptr;
|
||||
if (mode == MapMode::Still && stillImageRequest) {
|
||||
auto request = std::move(stillImageRequest);
|
||||
request->callback(error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ namespace mbgl {
|
||||
|
||||
enum class Update {
|
||||
Nothing = 0,
|
||||
Dimensions = 1 << 1,
|
||||
Classes = 1 << 2,
|
||||
RecalculateStyle = 1 << 3,
|
||||
RenderStill = 1 << 4,
|
||||
@@ -1,17 +0,0 @@
|
||||
#include <mbgl/map/view.hpp>
|
||||
#include <mbgl/map/map.hpp>
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
PremultipliedImage View::readStillImage(std::array<uint16_t, 2>) {
|
||||
return {};
|
||||
}
|
||||
|
||||
void View::initialize(Map *map_) {
|
||||
assert(map_);
|
||||
map = map_;
|
||||
}
|
||||
|
||||
} // namespace mbgl
|
||||
@@ -31,6 +31,8 @@
|
||||
#include <mbgl/util/mat3.hpp>
|
||||
#include <mbgl/util/string.hpp>
|
||||
|
||||
#include <mbgl/util/offscreen_texture.hpp>
|
||||
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
@@ -40,8 +42,9 @@ namespace mbgl {
|
||||
|
||||
using namespace style;
|
||||
|
||||
Painter::Painter(const TransformState& state_)
|
||||
: state(state_),
|
||||
Painter::Painter(gl::Context& context_, const TransformState& state_)
|
||||
: context(context_),
|
||||
state(state_),
|
||||
tileTriangleVertexBuffer(context.createVertexBuffer(std::vector<FillVertex> {{
|
||||
{ 0, 0 },
|
||||
{ util::EXTENT, 0 },
|
||||
@@ -71,9 +74,6 @@ Painter::Painter(const TransformState& state_)
|
||||
#ifndef NDEBUG
|
||||
overdrawShaders = std::make_unique<Shaders>(context, gl::Shader::Overdraw);
|
||||
#endif
|
||||
|
||||
// Reset GL values
|
||||
context.setDirtyState();
|
||||
}
|
||||
|
||||
Painter::~Painter() = default;
|
||||
@@ -93,9 +93,10 @@ void Painter::cleanup() {
|
||||
}
|
||||
|
||||
void Painter::render(const Style& style, const FrameData& frame_, View& view, SpriteAtlas& annotationSpriteAtlas) {
|
||||
context.viewport.setDefaultValue(
|
||||
{ 0, 0, view.getFramebufferSize()[0], view.getFramebufferSize()[1] });
|
||||
frame = frame_;
|
||||
if (frame.contextMode == GLContextMode::Shared) {
|
||||
context.setDirtyState();
|
||||
}
|
||||
|
||||
PaintParameters parameters {
|
||||
#ifndef NDEBUG
|
||||
@@ -126,12 +127,14 @@ void Painter::render(const Style& style, const FrameData& frame_, View& view, Sp
|
||||
frameHistory.record(frame.timePoint, state.getZoom(),
|
||||
frame.mapMode == MapMode::Continuous ? util::DEFAULT_FADE_DURATION : Milliseconds(0));
|
||||
|
||||
|
||||
// - UPLOAD PASS -------------------------------------------------------------------------------
|
||||
// Uploads all required buffers and images before we do any actual rendering.
|
||||
{
|
||||
MBGL_DEBUG_GROUP("upload");
|
||||
|
||||
spriteAtlas->upload(context, 0);
|
||||
|
||||
lineAtlas->upload(context, 0);
|
||||
glyphAtlas->upload(context, 0);
|
||||
frameHistory.upload(context, 0);
|
||||
@@ -149,10 +152,8 @@ void Painter::render(const Style& style, const FrameData& frame_, View& view, Sp
|
||||
// tiles whatsoever.
|
||||
{
|
||||
MBGL_DEBUG_GROUP("clear");
|
||||
context.bindFramebuffer.setDirty();
|
||||
view.bind();
|
||||
context.viewport.reset();
|
||||
context.stencilFunc.reset();
|
||||
context.stencilFunc = { gl::StencilTestFunction::Always, 0, ~0u };
|
||||
context.stencilTest = true;
|
||||
context.stencilMask = 0xFF;
|
||||
context.depthTest = false;
|
||||
@@ -249,10 +250,6 @@ void Painter::render(const Style& style, const FrameData& frame_, View& view, Sp
|
||||
|
||||
context.vertexArrayObject = 0;
|
||||
}
|
||||
|
||||
if (frame.contextMode == GLContextMode::Shared) {
|
||||
context.setDirtyState();
|
||||
}
|
||||
}
|
||||
|
||||
template <class Iterator>
|
||||
@@ -296,17 +293,21 @@ void Painter::renderPass(PaintParameters& parameters,
|
||||
renderBackground(parameters, *layer.as<BackgroundLayer>());
|
||||
} else if (layer.is<CustomLayer>()) {
|
||||
MBGL_DEBUG_GROUP(layer.baseImpl->id + " - custom");
|
||||
|
||||
// Reset GL state to a known state so the CustomLayer always has a clean slate.
|
||||
context.vertexArrayObject = 0;
|
||||
context.depthFunc = gl::DepthTestFunction::LessEqual;
|
||||
context.depthTest = true;
|
||||
context.depthMask = false;
|
||||
context.stencilTest = false;
|
||||
setDepthSublayer(0);
|
||||
|
||||
layer.as<CustomLayer>()->impl->render(state);
|
||||
context.setDirtyState();
|
||||
context.bindFramebuffer.setDirty();
|
||||
|
||||
// Reset the view back to our original one, just in case the CustomLayer changed
|
||||
// the viewport or Framebuffer.
|
||||
parameters.view.bind();
|
||||
context.viewport.reset();
|
||||
context.setDirtyState();
|
||||
} else {
|
||||
MBGL_DEBUG_GROUP(layer.baseImpl->id + " - " + util::toString(item.tile->id));
|
||||
if (item.bucket->needsClipping()) {
|
||||
|
||||
@@ -68,7 +68,7 @@ struct FrameData {
|
||||
|
||||
class Painter : private util::noncopyable {
|
||||
public:
|
||||
Painter(const TransformState&);
|
||||
Painter(gl::Context&, const TransformState&);
|
||||
~Painter();
|
||||
|
||||
void render(const style::Style&,
|
||||
@@ -153,6 +153,9 @@ private:
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
gl::Context& context;
|
||||
|
||||
mat4 projMatrix;
|
||||
|
||||
std::array<float, 2> pixelsToGLUnits;
|
||||
@@ -169,8 +172,6 @@ private:
|
||||
|
||||
int indent = 0;
|
||||
|
||||
gl::Context context;
|
||||
|
||||
RenderPass pass = RenderPass::Opaque;
|
||||
|
||||
int numSublayers = 3;
|
||||
|
||||
@@ -89,7 +89,7 @@ void Painter::renderDebugFrame(const mat4 &matrix) {
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
void Painter::renderClipMasks(PaintParameters& parameters) {
|
||||
void Painter::renderClipMasks(PaintParameters&) {
|
||||
context.stencilTest = false;
|
||||
context.depthTest = false;
|
||||
context.program = 0;
|
||||
@@ -100,13 +100,13 @@ void Painter::renderClipMasks(PaintParameters& parameters) {
|
||||
context.rasterPos = { -1, -1, 0, 0 };
|
||||
|
||||
// Read the stencil buffer
|
||||
const auto& fbSize = parameters.view.getFramebufferSize();
|
||||
auto pixels = std::make_unique<uint8_t[]>(fbSize[0] * fbSize[1]);
|
||||
const auto viewport = context.viewport.getCurrentValue();
|
||||
auto pixels = std::make_unique<uint8_t[]>(viewport.width * viewport.height);
|
||||
MBGL_CHECK_ERROR(glReadPixels(
|
||||
0, // GLint x
|
||||
0, // GLint y
|
||||
fbSize[0], // GLsizei width
|
||||
fbSize[1], // GLsizei height
|
||||
viewport.x, // GLint x
|
||||
viewport.y, // GLint y
|
||||
viewport.width, // GLsizei width
|
||||
viewport.height, // GLsizei height
|
||||
GL_STENCIL_INDEX, // GLenum format
|
||||
GL_UNSIGNED_BYTE, // GLenum type
|
||||
pixels.get() // GLvoid * data
|
||||
@@ -114,22 +114,21 @@ void Painter::renderClipMasks(PaintParameters& parameters) {
|
||||
|
||||
// Scale the Stencil buffer to cover the entire color space.
|
||||
auto it = pixels.get();
|
||||
auto end = it + fbSize[0] * fbSize[1];
|
||||
auto end = it + viewport.width * viewport.height;
|
||||
const auto factor = 255.0f / *std::max_element(it, end);
|
||||
for (; it != end; ++it) {
|
||||
*it *= factor;
|
||||
}
|
||||
|
||||
MBGL_CHECK_ERROR(glWindowPos2i(0, 0));
|
||||
MBGL_CHECK_ERROR(glDrawPixels(fbSize[0], fbSize[1], GL_LUMINANCE, GL_UNSIGNED_BYTE, pixels.get()));
|
||||
#else
|
||||
(void)parameters;
|
||||
MBGL_CHECK_ERROR(glWindowPos2i(viewport.x, viewport.y));
|
||||
MBGL_CHECK_ERROR(glDrawPixels(viewport.width, viewport.height, GL_LUMINANCE, GL_UNSIGNED_BYTE,
|
||||
pixels.get()));
|
||||
#endif // MBGL_USE_GLES2
|
||||
}
|
||||
#endif // NDEBUG
|
||||
|
||||
#ifndef NDEBUG
|
||||
void Painter::renderDepthBuffer(PaintParameters& parameters) {
|
||||
void Painter::renderDepthBuffer(PaintParameters&) {
|
||||
context.stencilTest = false;
|
||||
context.depthTest = false;
|
||||
context.program = 0;
|
||||
@@ -140,27 +139,26 @@ void Painter::renderDepthBuffer(PaintParameters& parameters) {
|
||||
context.rasterPos = { -1, -1, 0, 0 };
|
||||
|
||||
// Read the stencil buffer
|
||||
const auto& fbSize = parameters.view.getFramebufferSize();
|
||||
auto pixels = std::make_unique<GLubyte[]>(fbSize[0] * fbSize[1]);
|
||||
const auto viewport = context.viewport.getCurrentValue();
|
||||
auto pixels = std::make_unique<uint8_t[]>(viewport.width * viewport.height);
|
||||
|
||||
const double base = 1.0 / (1.0 - depthRangeSize);
|
||||
glPixelTransferf(GL_DEPTH_SCALE, base);
|
||||
glPixelTransferf(GL_DEPTH_BIAS, 1.0 - base);
|
||||
|
||||
MBGL_CHECK_ERROR(glReadPixels(
|
||||
0, // GLint x
|
||||
0, // GLint y
|
||||
fbSize[0], // GLsizei width
|
||||
fbSize[1], // GLsizei height
|
||||
viewport.x, // GLint x
|
||||
viewport.y, // GLint y
|
||||
viewport.width, // GLsizei width
|
||||
viewport.height, // GLsizei height
|
||||
GL_DEPTH_COMPONENT, // GLenum format
|
||||
GL_UNSIGNED_BYTE, // GLenum type
|
||||
pixels.get() // GLvoid * data
|
||||
));
|
||||
|
||||
MBGL_CHECK_ERROR(glWindowPos2i(0, 0));
|
||||
MBGL_CHECK_ERROR(glDrawPixels(fbSize[0], fbSize[1], GL_LUMINANCE, GL_UNSIGNED_BYTE, pixels.get()));
|
||||
#else
|
||||
(void)parameters;
|
||||
MBGL_CHECK_ERROR(glWindowPos2i(viewport.x, viewport.y));
|
||||
MBGL_CHECK_ERROR(glDrawPixels(viewport.width, viewport.height, GL_LUMINANCE, GL_UNSIGNED_BYTE,
|
||||
pixels.get()));
|
||||
#endif // MBGL_USE_GLES2
|
||||
}
|
||||
#endif // NDEBUG
|
||||
|
||||
@@ -30,7 +30,9 @@ void Painter::renderFill(PaintParameters& parameters,
|
||||
const bool isOutlineColorDefined = !properties.fillOutlineColor.isUndefined();
|
||||
Color strokeColor = isOutlineColorDefined? properties.fillOutlineColor : fillColor;
|
||||
|
||||
auto worldSize = util::convert<GLfloat>(parameters.view.getFramebufferSize());
|
||||
const auto viewport = context.viewport.getCurrentValue();
|
||||
const std::array<GLfloat, 2> worldSize{ { static_cast<GLfloat>(viewport.width),
|
||||
static_cast<GLfloat>(viewport.height) } };
|
||||
|
||||
bool pattern = !properties.fillPattern.value.from.empty();
|
||||
bool outline = properties.fillAntialias && !pattern && isOutlineColorDefined;
|
||||
|
||||
@@ -1,70 +1,48 @@
|
||||
#include <mbgl/util/offscreen_texture.hpp>
|
||||
#include <mbgl/gl/context.hpp>
|
||||
#include <mbgl/gl/gl.hpp>
|
||||
#include <mbgl/util/offscreen_texture.hpp>
|
||||
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
void OffscreenTexture::bind(gl::Context& context,
|
||||
std::array<uint16_t, 2> size) {
|
||||
OffscreenTexture::OffscreenTexture(gl::Context& context_, std::array<uint16_t, 2> size_)
|
||||
: context(context_), size(std::move(size_)) {
|
||||
assert(size[0] > 0 && size[1] > 0);
|
||||
}
|
||||
|
||||
if (!texture || texture->size != size) {
|
||||
texture = context.createTexture(size);
|
||||
}
|
||||
|
||||
void OffscreenTexture::bind() {
|
||||
if (!framebuffer) {
|
||||
framebuffer = context.createFramebuffer();
|
||||
context.bindFramebuffer = *framebuffer;
|
||||
MBGL_CHECK_ERROR(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
|
||||
texture->texture, 0));
|
||||
|
||||
GLenum status = MBGL_CHECK_ERROR(glCheckFramebufferStatus(GL_FRAMEBUFFER));
|
||||
if (status != GL_FRAMEBUFFER_COMPLETE) {
|
||||
switch (status) {
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
|
||||
throw std::runtime_error("Couldn't create framebuffer: incomplete attachment");
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
|
||||
throw std::runtime_error(
|
||||
"Couldn't create framebuffer: incomplete missing attachment");
|
||||
#ifdef GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
|
||||
throw std::runtime_error("Couldn't create framebuffer: incomplete draw buffer");
|
||||
#endif
|
||||
#ifdef GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
|
||||
throw std::runtime_error("Couldn't create framebuffer: incomplete read buffer");
|
||||
#endif
|
||||
#ifdef GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS
|
||||
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
|
||||
throw std::runtime_error("Couldn't create framebuffer: incomplete dimensions");
|
||||
#endif
|
||||
|
||||
case GL_FRAMEBUFFER_UNSUPPORTED:
|
||||
throw std::runtime_error("Couldn't create framebuffer: unsupported");
|
||||
default:
|
||||
throw std::runtime_error("Couldn't create framebuffer: other");
|
||||
}
|
||||
}
|
||||
texture = context.createTexture(size);
|
||||
framebuffer = context.createFramebuffer(*texture);
|
||||
} else {
|
||||
context.bindFramebuffer = *framebuffer;
|
||||
context.bindFramebuffer = framebuffer->framebuffer;
|
||||
}
|
||||
|
||||
context.viewport = { 0, 0, size[0], size[1] };
|
||||
}
|
||||
|
||||
gl::Texture& OffscreenTexture::getTexture() {
|
||||
assert(texture);
|
||||
return *texture;
|
||||
}
|
||||
|
||||
std::array<uint16_t, 2> OffscreenTexture::getSize() const {
|
||||
if (texture) {
|
||||
// Use explicit dereference instead of -> due to clang 3.5 bug
|
||||
return (*texture).size;
|
||||
} else {
|
||||
return {{ 0, 0 }};
|
||||
PremultipliedImage OffscreenTexture::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;
|
||||
}
|
||||
|
||||
|
||||
} // namespace mbgl
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <mbgl/map/view.hpp>
|
||||
#include <mbgl/gl/framebuffer.hpp>
|
||||
#include <mbgl/gl/texture.hpp>
|
||||
#include <mbgl/util/optional.hpp>
|
||||
#include <mbgl/util/image.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
@@ -8,15 +12,20 @@ namespace gl {
|
||||
class Context;
|
||||
} // namespace gl
|
||||
|
||||
class OffscreenTexture {
|
||||
class OffscreenTexture : public View {
|
||||
public:
|
||||
void bind(gl::Context&, std::array<uint16_t, 2> size);
|
||||
OffscreenTexture(gl::Context&, std::array<uint16_t, 2> size = {{ 256, 256 }});
|
||||
|
||||
void bind() override;
|
||||
|
||||
PremultipliedImage readStillImage();
|
||||
|
||||
gl::Texture& getTexture();
|
||||
std::array<uint16_t, 2> getSize() const;
|
||||
|
||||
private:
|
||||
optional<gl::UniqueFramebuffer> framebuffer;
|
||||
gl::Context& context;
|
||||
std::array<uint16_t, 2> size;
|
||||
optional<gl::Framebuffer> framebuffer;
|
||||
optional<gl::Texture> texture;
|
||||
};
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <mbgl/sprite/sprite_image.hpp>
|
||||
#include <mbgl/map/map.hpp>
|
||||
#include <mbgl/platform/default/headless_backend.hpp>
|
||||
#include <mbgl/platform/default/headless_view.hpp>
|
||||
#include <mbgl/platform/default/offscreen_view.hpp>
|
||||
#include <mbgl/util/io.hpp>
|
||||
#include <mbgl/util/run_loop.hpp>
|
||||
#include <mbgl/util/color.hpp>
|
||||
@@ -24,14 +24,14 @@ class AnnotationTest {
|
||||
public:
|
||||
util::RunLoop loop;
|
||||
HeadlessBackend backend;
|
||||
HeadlessView view;
|
||||
OffscreenView view{ backend.getContext() };
|
||||
StubFileSource fileSource;
|
||||
ThreadPool threadPool { 4 };
|
||||
Map map { backend, view, view.getPixelRatio(), fileSource, threadPool, MapMode::Still };
|
||||
Map map { backend, view.getSize(), 1, fileSource, threadPool, MapMode::Still };
|
||||
|
||||
void checkRendering(const char * name) {
|
||||
test::checkImage(std::string("test/fixtures/annotations/") + name,
|
||||
test::render(map), 0.0002, 0.1);
|
||||
test::render(map, view), 0.0002, 0.1);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -162,7 +162,7 @@ TEST(Annotations, AddMultiple) {
|
||||
test.map.addAnnotationIcon("default_marker", namedMarker("default_marker.png"));
|
||||
test.map.addAnnotation(SymbolAnnotation { Point<double> { -10, 0 }, "default_marker" });
|
||||
|
||||
test::render(test.map);
|
||||
test::render(test.map, test.view);
|
||||
|
||||
test.map.addAnnotation(SymbolAnnotation { Point<double> { 10, 0 }, "default_marker" });
|
||||
test.checkRendering("add_multiple");
|
||||
@@ -172,7 +172,7 @@ TEST(Annotations, NonImmediateAdd) {
|
||||
AnnotationTest test;
|
||||
|
||||
test.map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"));
|
||||
test::render(test.map);
|
||||
test::render(test.map, test.view);
|
||||
|
||||
Polygon<double> polygon = {{ {{ { 0, 0 }, { 0, 45 }, { 45, 45 }, { 45, 0 } }} }};
|
||||
FillAnnotation annotation { polygon };
|
||||
@@ -190,7 +190,7 @@ TEST(Annotations, UpdateSymbolAnnotationGeometry) {
|
||||
test.map.addAnnotationIcon("flipped_marker", namedMarker("flipped_marker.png"));
|
||||
AnnotationID point = test.map.addAnnotation(SymbolAnnotation { Point<double> { 0, 0 }, "default_marker" });
|
||||
|
||||
test::render(test.map);
|
||||
test::render(test.map, test.view);
|
||||
|
||||
test.map.updateAnnotation(point, SymbolAnnotation { Point<double> { -10, 0 }, "default_marker" });
|
||||
test.checkRendering("update_point");
|
||||
@@ -204,7 +204,7 @@ TEST(Annotations, UpdateSymbolAnnotationIcon) {
|
||||
test.map.addAnnotationIcon("flipped_marker", namedMarker("flipped_marker.png"));
|
||||
AnnotationID point = test.map.addAnnotation(SymbolAnnotation { Point<double> { 0, 0 }, "default_marker" });
|
||||
|
||||
test::render(test.map);
|
||||
test::render(test.map, test.view);
|
||||
|
||||
test.map.updateAnnotation(point, SymbolAnnotation { Point<double> { 0, 0 }, "flipped_marker" });
|
||||
test.checkRendering("update_icon");
|
||||
@@ -220,7 +220,7 @@ TEST(Annotations, UpdateLineAnnotationGeometry) {
|
||||
test.map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"));
|
||||
AnnotationID line = test.map.addAnnotation(annotation);
|
||||
|
||||
test::render(test.map);
|
||||
test::render(test.map, test.view);
|
||||
|
||||
annotation.geometry = LineString<double> {{ { 0, 0 }, { -45, -45 } }};
|
||||
test.map.updateAnnotation(line, annotation);
|
||||
@@ -237,7 +237,7 @@ TEST(Annotations, UpdateLineAnnotationStyle) {
|
||||
test.map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"));
|
||||
AnnotationID line = test.map.addAnnotation(annotation);
|
||||
|
||||
test::render(test.map);
|
||||
test::render(test.map, test.view);
|
||||
|
||||
annotation.color = { { 0, 255, 0, 1 } };
|
||||
annotation.width = { 2 };
|
||||
@@ -254,7 +254,7 @@ TEST(Annotations, UpdateFillAnnotationGeometry) {
|
||||
test.map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"));
|
||||
AnnotationID fill = test.map.addAnnotation(annotation);
|
||||
|
||||
test::render(test.map);
|
||||
test::render(test.map, test.view);
|
||||
|
||||
annotation.geometry = Polygon<double> {{ {{ { 0, 0 }, { 0, 45 }, { 45, 0 } }} }};
|
||||
test.map.updateAnnotation(fill, annotation);
|
||||
@@ -271,7 +271,7 @@ TEST(Annotations, UpdateFillAnnotationStyle) {
|
||||
test.map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"));
|
||||
AnnotationID fill = test.map.addAnnotation(annotation);
|
||||
|
||||
test::render(test.map);
|
||||
test::render(test.map, test.view);
|
||||
|
||||
annotation.color = { { 0, 255, 0, 1 } };
|
||||
test.map.updateAnnotation(fill, annotation);
|
||||
@@ -285,7 +285,7 @@ TEST(Annotations, RemovePoint) {
|
||||
test.map.addAnnotationIcon("default_marker", namedMarker("default_marker.png"));
|
||||
AnnotationID point = test.map.addAnnotation(SymbolAnnotation { Point<double> { 0, 0 }, "default_marker" });
|
||||
|
||||
test::render(test.map);
|
||||
test::render(test.map, test.view);
|
||||
|
||||
test.map.removeAnnotation(point);
|
||||
test.checkRendering("remove_point");
|
||||
@@ -302,7 +302,7 @@ TEST(Annotations, RemoveShape) {
|
||||
test.map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"));
|
||||
AnnotationID shape = test.map.addAnnotation(annotation);
|
||||
|
||||
test::render(test.map);
|
||||
test::render(test.map, test.view);
|
||||
|
||||
test.map.removeAnnotation(shape);
|
||||
test.checkRendering("remove_shape");
|
||||
@@ -314,7 +314,7 @@ TEST(Annotations, ImmediateRemoveShape) {
|
||||
test.map.removeAnnotation(test.map.addAnnotation(LineAnnotation { LineString<double>() }));
|
||||
test.map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"));
|
||||
|
||||
test::render(test.map);
|
||||
test::render(test.map, test.view);
|
||||
}
|
||||
|
||||
TEST(Annotations, SwitchStyle) {
|
||||
@@ -324,7 +324,7 @@ TEST(Annotations, SwitchStyle) {
|
||||
test.map.addAnnotationIcon("default_marker", namedMarker("default_marker.png"));
|
||||
test.map.addAnnotation(SymbolAnnotation { Point<double> { 0, 0 }, "default_marker" });
|
||||
|
||||
test::render(test.map);
|
||||
test::render(test.map, test.view);
|
||||
|
||||
test.map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"));
|
||||
test.checkRendering("switch_style");
|
||||
@@ -338,7 +338,7 @@ TEST(Annotations, QueryRenderedFeatures) {
|
||||
test.map.addAnnotation(SymbolAnnotation { Point<double> { 0, 0 }, "default_marker" });
|
||||
test.map.addAnnotation(SymbolAnnotation { Point<double> { 0, 50 }, "default_marker" });
|
||||
|
||||
test::render(test.map);
|
||||
test::render(test.map, test.view);
|
||||
|
||||
auto features = test.map.queryRenderedFeatures(test.map.pixelForLatLng({ 0, 0 }));
|
||||
EXPECT_EQ(features.size(), 1u);
|
||||
@@ -370,7 +370,7 @@ TEST(Annotations, QueryFractionalZoomLevels) {
|
||||
test.map.setLatLngZoom({ 5, 5 }, 0);
|
||||
for (uint16_t zoomSteps = 10; zoomSteps <= 20; ++zoomSteps) {
|
||||
test.map.setZoom(zoomSteps / 10.0);
|
||||
test::render(test.map);
|
||||
test::render(test.map, test.view);
|
||||
auto features = test.map.queryRenderedFeatures(box);
|
||||
|
||||
// Filter out repeated features.
|
||||
@@ -402,7 +402,7 @@ TEST(Annotations, VisibleFeatures) {
|
||||
|
||||
// Change bearing *after* adding annotations causes them to be reordered.
|
||||
test.map.setBearing(45);
|
||||
test::render(test.map);
|
||||
test::render(test.map, test.view);
|
||||
|
||||
auto features = test.map.queryRenderedFeatures(box);
|
||||
auto sortID = [](const Feature& lhs, const Feature& rhs) { return lhs.id < rhs.id; };
|
||||
@@ -413,7 +413,7 @@ TEST(Annotations, VisibleFeatures) {
|
||||
|
||||
test.map.setBearing(0);
|
||||
test.map.setZoom(4);
|
||||
test::render(test.map);
|
||||
test::render(test.map, test.view);
|
||||
features = test.map.queryRenderedFeatures(box);
|
||||
std::sort(features.begin(), features.end(), sortID);
|
||||
features.erase(std::unique(features.begin(), features.end(), sameID), features.end());
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#include <mbgl/map/map.hpp>
|
||||
#include <mbgl/platform/default/headless_backend.hpp>
|
||||
#include <mbgl/platform/default/headless_view.hpp>
|
||||
#include <mbgl/platform/default/offscreen_view.hpp>
|
||||
#include <mbgl/storage/online_file_source.hpp>
|
||||
#include <mbgl/platform/default/thread_pool.hpp>
|
||||
#include <mbgl/util/exception.hpp>
|
||||
@@ -21,14 +21,13 @@ TEST(API, RenderWithoutCallback) {
|
||||
util::RunLoop loop;
|
||||
|
||||
HeadlessBackend backend;
|
||||
HeadlessView view;
|
||||
view.resize(128, 512);
|
||||
OffscreenView view(backend.getContext(), {{ 128, 512 }});
|
||||
StubFileSource fileSource;
|
||||
ThreadPool threadPool(4);
|
||||
|
||||
std::unique_ptr<Map> map = std::make_unique<Map>(backend, view, view.getPixelRatio(),
|
||||
fileSource, threadPool, MapMode::Still);
|
||||
map->renderStill(nullptr);
|
||||
std::unique_ptr<Map> map =
|
||||
std::make_unique<Map>(backend, view.getSize(), 1, fileSource, threadPool, MapMode::Still);
|
||||
map->renderStill(view, nullptr);
|
||||
|
||||
// Force Map thread to join.
|
||||
map.reset();
|
||||
@@ -47,15 +46,14 @@ TEST(API, RenderWithoutStyle) {
|
||||
util::RunLoop loop;
|
||||
|
||||
HeadlessBackend backend;
|
||||
HeadlessView view;
|
||||
view.resize(128, 512);
|
||||
OffscreenView view(backend.getContext(), {{ 128, 512 }});
|
||||
StubFileSource fileSource;
|
||||
ThreadPool threadPool(4);
|
||||
|
||||
Map map(backend, view, view.getPixelRatio(), fileSource, threadPool, MapMode::Still);
|
||||
Map map(backend, view.getSize(), 1, fileSource, threadPool, MapMode::Still);
|
||||
|
||||
std::exception_ptr error;
|
||||
map.renderStill([&](std::exception_ptr error_, PremultipliedImage&&) {
|
||||
map.renderStill(view, [&](std::exception_ptr error_) {
|
||||
error = error_;
|
||||
loop.stop();
|
||||
});
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include <mbgl/gl/gl.hpp>
|
||||
#include <mbgl/map/map.hpp>
|
||||
#include <mbgl/platform/default/headless_backend.hpp>
|
||||
#include <mbgl/platform/default/headless_view.hpp>
|
||||
#include <mbgl/platform/default/offscreen_view.hpp>
|
||||
#include <mbgl/platform/default/thread_pool.hpp>
|
||||
#include <mbgl/storage/default_file_source.hpp>
|
||||
#include <mbgl/style/layers/custom_layer.hpp>
|
||||
@@ -86,7 +86,7 @@ TEST(CustomLayer, Basic) {
|
||||
util::RunLoop loop;
|
||||
|
||||
HeadlessBackend backend;
|
||||
HeadlessView view;
|
||||
OffscreenView view(backend.getContext());
|
||||
|
||||
#ifdef MBGL_ASSET_ZIP
|
||||
// Regenerate with `cd test/fixtures/api/ && zip -r assets.zip assets/`
|
||||
@@ -97,7 +97,7 @@ TEST(CustomLayer, Basic) {
|
||||
|
||||
ThreadPool threadPool(4);
|
||||
|
||||
Map map(backend, view, view.getPixelRatio(), fileSource, threadPool, MapMode::Still);
|
||||
Map map(backend, view.getSize(), 1, fileSource, threadPool, MapMode::Still);
|
||||
map.setStyleJSON(util::read_file("test/fixtures/api/water.json"));
|
||||
map.setLatLngZoom({ 37.8, -122.5 }, 10);
|
||||
map.addLayer(std::make_unique<CustomLayer>(
|
||||
@@ -117,5 +117,5 @@ TEST(CustomLayer, Basic) {
|
||||
layer->setFillColor(Color{ 1.0, 1.0, 0.0, 1.0 });
|
||||
map.addLayer(std::move(layer));
|
||||
|
||||
test::checkImage("test/fixtures/custom_layer/basic", test::render(map), 0.0006, 0.1);
|
||||
test::checkImage("test/fixtures/custom_layer/basic", test::render(map, view), 0.0006, 0.1);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include <mbgl/map/map.hpp>
|
||||
#include <mbgl/platform/default/headless_backend.hpp>
|
||||
#include <mbgl/platform/default/headless_view.hpp>
|
||||
#include <mbgl/platform/default/offscreen_view.hpp>
|
||||
#include <mbgl/platform/default/thread_pool.hpp>
|
||||
#include <mbgl/sprite/sprite_image.hpp>
|
||||
#include <mbgl/test/stub_file_source.hpp>
|
||||
@@ -22,15 +22,15 @@ public:
|
||||
map.setStyleJSON(util::read_file("test/fixtures/api/query_style.json"));
|
||||
map.addImage("test-icon", std::move(image));
|
||||
|
||||
test::render(map);
|
||||
test::render(map, view);
|
||||
}
|
||||
|
||||
util::RunLoop loop;
|
||||
HeadlessBackend backend;
|
||||
HeadlessView view;
|
||||
OffscreenView view { backend.getContext() };
|
||||
StubFileSource fileSource;
|
||||
ThreadPool threadPool { 4 };
|
||||
Map map { backend, view, view.getPixelRatio(), fileSource, threadPool, MapMode::Still };
|
||||
Map map { backend, view.getSize(), 1, fileSource, threadPool, MapMode::Still };
|
||||
};
|
||||
|
||||
} // end namespace
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#include <mbgl/map/map.hpp>
|
||||
#include <mbgl/platform/default/headless_backend.hpp>
|
||||
#include <mbgl/platform/default/headless_view.hpp>
|
||||
#include <mbgl/platform/default/offscreen_view.hpp>
|
||||
#include <mbgl/platform/default/thread_pool.hpp>
|
||||
#include <mbgl/storage/default_file_source.hpp>
|
||||
#include <mbgl/util/image.hpp>
|
||||
@@ -26,7 +26,7 @@ TEST(API, TEST_REQUIRES_SERVER(RenderMissingTile)) {
|
||||
const auto style = util::read_file("test/fixtures/api/water_missing_tiles.json");
|
||||
|
||||
HeadlessBackend backend;
|
||||
HeadlessView view(1, 256, 512);
|
||||
OffscreenView view(backend.getContext(), {{ 256, 512 }});
|
||||
#ifdef MBGL_ASSET_ZIP
|
||||
// Regenerate with `cd test/fixtures/api/ && zip -r assets.zip assets/`
|
||||
DefaultFileSource fileSource(":memory:", "test/fixtures/api/assets.zip");
|
||||
@@ -38,14 +38,14 @@ TEST(API, TEST_REQUIRES_SERVER(RenderMissingTile)) {
|
||||
|
||||
Log::setObserver(std::make_unique<FixtureLogObserver>());
|
||||
|
||||
Map map(backend, view, view.getPixelRatio(), fileSource, threadPool, MapMode::Still);
|
||||
Map map(backend, view.getSize(), 1, fileSource, threadPool, MapMode::Still);
|
||||
|
||||
std::string message;
|
||||
|
||||
// This host does not respond (== connection error).
|
||||
// Are you seeing this test fail? Make sure you don't have a server running on port 3001!
|
||||
map.setStyleJSON(style);
|
||||
map.renderStill([&](std::exception_ptr err, PremultipliedImage&&) {
|
||||
map.renderStill(view, [&](std::exception_ptr err) {
|
||||
ASSERT_TRUE(err.operator bool());
|
||||
try {
|
||||
std::rethrow_exception(err);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#include <mbgl/map/map.hpp>
|
||||
#include <mbgl/platform/default/headless_backend.hpp>
|
||||
#include <mbgl/platform/default/headless_view.hpp>
|
||||
#include <mbgl/platform/default/offscreen_view.hpp>
|
||||
#include <mbgl/platform/default/thread_pool.hpp>
|
||||
#include <mbgl/storage/default_file_source.hpp>
|
||||
#include <mbgl/util/image.hpp>
|
||||
@@ -20,7 +20,7 @@ TEST(API, RepeatedRender) {
|
||||
const auto style = util::read_file("test/fixtures/api/water.json");
|
||||
|
||||
HeadlessBackend backend;
|
||||
HeadlessView view(1, 256, 512);
|
||||
OffscreenView view(backend.getContext(), {{ 256, 512 }});
|
||||
#ifdef MBGL_ASSET_ZIP
|
||||
// Regenerate with `cd test/fixtures/api/ && zip -r assets.zip assets/`
|
||||
DefaultFileSource fileSource(":memory:", "test/fixtures/api/assets.zip");
|
||||
@@ -32,13 +32,13 @@ TEST(API, RepeatedRender) {
|
||||
|
||||
Log::setObserver(std::make_unique<FixtureLogObserver>());
|
||||
|
||||
Map map(backend, view, view.getPixelRatio(), fileSource, threadPool, MapMode::Still);
|
||||
Map map(backend, view.getSize(), 1, fileSource, threadPool, MapMode::Still);
|
||||
|
||||
{
|
||||
map.setStyleJSON(style);
|
||||
PremultipliedImage result;
|
||||
map.renderStill([&result](std::exception_ptr, PremultipliedImage&& image) {
|
||||
result = std::move(image);
|
||||
map.renderStill(view, [&](std::exception_ptr) {
|
||||
result = view.readStillImage();
|
||||
});
|
||||
|
||||
while (!result.size()) {
|
||||
@@ -55,8 +55,8 @@ TEST(API, RepeatedRender) {
|
||||
{
|
||||
map.setStyleJSON(style);
|
||||
PremultipliedImage result;
|
||||
map.renderStill([&result](std::exception_ptr, PremultipliedImage&& image) {
|
||||
result = std::move(image);
|
||||
map.renderStill(view, [&](std::exception_ptr) {
|
||||
result = view.readStillImage();
|
||||
});
|
||||
|
||||
while (!result.size()) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include <mbgl/test/util.hpp>
|
||||
|
||||
#include <mbgl/platform/default/headless_backend.hpp>
|
||||
#include <mbgl/platform/default/headless_view.hpp>
|
||||
#include <mbgl/platform/default/offscreen_view.hpp>
|
||||
|
||||
#include <mbgl/gl/gl.hpp>
|
||||
#include <mbgl/gl/context.hpp>
|
||||
@@ -43,11 +43,8 @@ TEST(GLObject, Value) {
|
||||
|
||||
auto object = std::make_unique<mbgl::gl::State<MockGLObject>>();
|
||||
EXPECT_EQ(object->getCurrentValue(), false);
|
||||
EXPECT_FALSE(object->isDirty());
|
||||
EXPECT_FALSE(setFlag);
|
||||
|
||||
object->setDirty();
|
||||
EXPECT_TRUE(object->isDirty());
|
||||
EXPECT_FALSE(setFlag);
|
||||
|
||||
*object = false;
|
||||
EXPECT_EQ(object->getCurrentValue(), false);
|
||||
@@ -59,16 +56,11 @@ TEST(GLObject, Value) {
|
||||
EXPECT_EQ(object->getCurrentValue(), true);
|
||||
EXPECT_FALSE(object->isDirty());
|
||||
EXPECT_TRUE(setFlag);
|
||||
|
||||
object->reset();
|
||||
EXPECT_EQ(object->getCurrentValue(), false);
|
||||
EXPECT_FALSE(object->isDirty());
|
||||
EXPECT_TRUE(setFlag);
|
||||
}
|
||||
|
||||
TEST(GLObject, Store) {
|
||||
mbgl::HeadlessBackend backend;
|
||||
mbgl::HeadlessView view;
|
||||
mbgl::OffscreenView view(backend.getContext());
|
||||
|
||||
mbgl::gl::Context context;
|
||||
EXPECT_TRUE(context.empty());
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
#include <mbgl/map/map.hpp>
|
||||
#include <mbgl/platform/default/headless_backend.hpp>
|
||||
#include <mbgl/platform/default/headless_view.hpp>
|
||||
#include <mbgl/platform/default/offscreen_view.hpp>
|
||||
#include <mbgl/platform/default/thread_pool.hpp>
|
||||
#include <mbgl/sprite/sprite_image.hpp>
|
||||
#include <mbgl/storage/network_status.hpp>
|
||||
@@ -23,15 +23,14 @@ using namespace std::literals::string_literals;
|
||||
struct MapTest {
|
||||
util::RunLoop runLoop;
|
||||
HeadlessBackend backend;
|
||||
HeadlessView view;
|
||||
OffscreenView view { backend.getContext() };
|
||||
StubFileSource fileSource;
|
||||
ThreadPool threadPool { 4 };
|
||||
};
|
||||
|
||||
TEST(Map, LatLngBehavior) {
|
||||
MapTest test;
|
||||
Map map(test.backend, test.view, test.view.getPixelRatio(), test.fileSource, test.threadPool,
|
||||
MapMode::Still);
|
||||
Map map(test.backend, test.view.getSize(), 1, test.fileSource, test.threadPool, MapMode::Still);
|
||||
|
||||
map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"));
|
||||
|
||||
@@ -65,12 +64,11 @@ TEST(Map, Offline) {
|
||||
fileSource.put(Resource::glyphs(prefix + "{fontstack}/{range}.pbf", {{"Helvetica"}}, {0, 255}), expiredItem("glyph.pbf"));
|
||||
NetworkStatus::Set(NetworkStatus::Status::Offline);
|
||||
|
||||
Map map(test.backend, test.view, test.view.getPixelRatio(), fileSource, test.threadPool,
|
||||
MapMode::Still);
|
||||
Map map(test.backend, test.view.getSize(), 1, fileSource, test.threadPool, MapMode::Still);
|
||||
map.setStyleURL(prefix + "style.json");
|
||||
|
||||
test::checkImage("test/fixtures/map/offline",
|
||||
test::render(map),
|
||||
test::render(map, test.view),
|
||||
0.0015,
|
||||
0.1);
|
||||
|
||||
@@ -90,8 +88,8 @@ TEST(Map, SetStyleInvalidJSON) {
|
||||
});
|
||||
|
||||
{
|
||||
Map map(test.backend, test.view, test.view.getPixelRatio(), test.fileSource,
|
||||
test.threadPool, MapMode::Still);
|
||||
Map map(test.backend, test.view.getSize(), 1, test.fileSource, test.threadPool,
|
||||
MapMode::Still);
|
||||
map.setStyleJSON("invalid");
|
||||
}
|
||||
|
||||
@@ -122,8 +120,7 @@ TEST(Map, SetStyleInvalidURL) {
|
||||
}
|
||||
});
|
||||
|
||||
Map map(test.backend, test.view, test.view.getPixelRatio(), test.fileSource, test.threadPool,
|
||||
MapMode::Still);
|
||||
Map map(test.backend, test.view.getSize(), 1, test.fileSource, test.threadPool, MapMode::Still);
|
||||
map.setStyleURL("mapbox://bar");
|
||||
|
||||
test.runLoop.run();
|
||||
@@ -132,8 +129,7 @@ TEST(Map, SetStyleInvalidURL) {
|
||||
TEST(Map, DoubleStyleLoad) {
|
||||
MapTest test;
|
||||
|
||||
Map map(test.backend, test.view, test.view.getPixelRatio(), test.fileSource, test.threadPool,
|
||||
MapMode::Still);
|
||||
Map map(test.backend, test.view.getSize(), 1, test.fileSource, test.threadPool, MapMode::Still);
|
||||
map.setStyleJSON("");
|
||||
map.setStyleJSON("");
|
||||
}
|
||||
@@ -144,8 +140,7 @@ TEST(Map, StyleFresh) {
|
||||
MapTest test;
|
||||
FakeFileSource fileSource;
|
||||
|
||||
Map map(test.backend, test.view, test.view.getPixelRatio(), fileSource, test.threadPool,
|
||||
MapMode::Still);
|
||||
Map map(test.backend, test.view.getSize(), 1, fileSource, test.threadPool, MapMode::Still);
|
||||
map.setStyleURL("mapbox://styles/test");
|
||||
EXPECT_EQ(1u, fileSource.requests.size());
|
||||
|
||||
@@ -165,8 +160,7 @@ TEST(Map, StyleExpired) {
|
||||
MapTest test;
|
||||
FakeFileSource fileSource;
|
||||
|
||||
Map map(test.backend, test.view, test.view.getPixelRatio(), fileSource, test.threadPool,
|
||||
MapMode::Still);
|
||||
Map map(test.backend, test.view.getSize(), 1, fileSource, test.threadPool, MapMode::Still);
|
||||
map.setStyleURL("mapbox://styles/test");
|
||||
EXPECT_EQ(1u, fileSource.requests.size());
|
||||
|
||||
@@ -193,8 +187,7 @@ TEST(Map, StyleExpiredWithAnnotations) {
|
||||
MapTest test;
|
||||
FakeFileSource fileSource;
|
||||
|
||||
Map map(test.backend, test.view, test.view.getPixelRatio(), fileSource, test.threadPool,
|
||||
MapMode::Still);
|
||||
Map map(test.backend, test.view.getSize(), 1, fileSource, test.threadPool, MapMode::Still);
|
||||
map.setStyleURL("mapbox://styles/test");
|
||||
EXPECT_EQ(1u, fileSource.requests.size());
|
||||
|
||||
@@ -218,8 +211,7 @@ TEST(Map, StyleEarlyMutation) {
|
||||
MapTest test;
|
||||
FakeFileSource fileSource;
|
||||
|
||||
Map map(test.backend, test.view, test.view.getPixelRatio(), fileSource, test.threadPool,
|
||||
MapMode::Still);
|
||||
Map map(test.backend, test.view.getSize(), 1, fileSource, test.threadPool, MapMode::Still);
|
||||
map.setStyleURL("mapbox://styles/test");
|
||||
map.addLayer(std::make_unique<style::BackgroundLayer>("bg"));
|
||||
|
||||
@@ -233,8 +225,7 @@ TEST(Map, StyleEarlyMutation) {
|
||||
|
||||
TEST(Map, StyleLoadedSignal) {
|
||||
MapTest test;
|
||||
Map map(test.backend, test.view, test.view.getPixelRatio(), test.fileSource, test.threadPool,
|
||||
MapMode::Still);
|
||||
Map map(test.backend, test.view.getSize(), 1, test.fileSource, test.threadPool, MapMode::Still);
|
||||
|
||||
// The map should emit a signal on style loaded
|
||||
bool emitted = false;
|
||||
@@ -255,22 +246,20 @@ TEST(Map, StyleLoadedSignal) {
|
||||
TEST(Map, AddLayer) {
|
||||
MapTest test;
|
||||
|
||||
Map map(test.backend, test.view, test.view.getPixelRatio(), test.fileSource, test.threadPool,
|
||||
MapMode::Still);
|
||||
Map map(test.backend, test.view.getSize(), 1, test.fileSource, test.threadPool, MapMode::Still);
|
||||
map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"));
|
||||
|
||||
auto layer = std::make_unique<BackgroundLayer>("background");
|
||||
layer->setBackgroundColor({{ 1, 0, 0, 1 }});
|
||||
layer->setBackgroundColor({ { 1, 0, 0, 1 } });
|
||||
map.addLayer(std::move(layer));
|
||||
|
||||
test::checkImage("test/fixtures/map/add_layer", test::render(map));
|
||||
test::checkImage("test/fixtures/map/add_layer", test::render(map, test.view));
|
||||
}
|
||||
|
||||
TEST(Map, RemoveLayer) {
|
||||
MapTest test;
|
||||
|
||||
Map map(test.backend, test.view, test.view.getPixelRatio(), test.fileSource, test.threadPool,
|
||||
MapMode::Still);
|
||||
Map map(test.backend, test.view.getSize(), 1, test.fileSource, test.threadPool, MapMode::Still);
|
||||
map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"));
|
||||
|
||||
auto layer = std::make_unique<BackgroundLayer>("background");
|
||||
@@ -278,7 +267,7 @@ TEST(Map, RemoveLayer) {
|
||||
map.addLayer(std::move(layer));
|
||||
map.removeLayer("background");
|
||||
|
||||
test::checkImage("test/fixtures/map/remove_layer", test::render(map));
|
||||
test::checkImage("test/fixtures/map/remove_layer", test::render(map, test.view));
|
||||
}
|
||||
|
||||
TEST(Map, DisabledSources) {
|
||||
@@ -295,8 +284,7 @@ TEST(Map, DisabledSources) {
|
||||
return {};
|
||||
};
|
||||
|
||||
Map map(test.backend, test.view, test.view.getPixelRatio(), test.fileSource, test.threadPool,
|
||||
MapMode::Still);
|
||||
Map map(test.backend, test.view.getSize(), 1, test.fileSource, test.threadPool, MapMode::Still);
|
||||
map.setZoom(1);
|
||||
|
||||
// This stylesheet has two raster layers, one that starts at zoom 1, the other at zoom 0.
|
||||
@@ -338,16 +326,15 @@ TEST(Map, DisabledSources) {
|
||||
}
|
||||
)STYLE");
|
||||
|
||||
test::checkImage("test/fixtures/map/disabled_layers/first", test::render(map));
|
||||
test::checkImage("test/fixtures/map/disabled_layers/first", test::render(map, test.view));
|
||||
map.setZoom(0.5);
|
||||
test::checkImage("test/fixtures/map/disabled_layers/second", test::render(map));
|
||||
test::checkImage("test/fixtures/map/disabled_layers/second", test::render(map, test.view));
|
||||
}
|
||||
|
||||
TEST(Map, Classes) {
|
||||
MapTest test;
|
||||
|
||||
Map map(test.backend, test.view, test.view.getPixelRatio(), test.fileSource, test.threadPool,
|
||||
MapMode::Still);
|
||||
Map map(test.backend, test.view.getSize(), 1, test.fileSource, test.threadPool, MapMode::Still);
|
||||
map.setStyleJSON(util::read_file("test/fixtures/api/empty.json"));
|
||||
|
||||
EXPECT_FALSE(map.getTransitionOptions().duration);
|
||||
@@ -381,8 +368,7 @@ TEST(Map, Classes) {
|
||||
TEST(Map, AddImage) {
|
||||
MapTest test;
|
||||
|
||||
Map map(test.backend, test.view, test.view.getPixelRatio(), test.fileSource, test.threadPool,
|
||||
MapMode::Still);
|
||||
Map map(test.backend, test.view.getSize(), 1, test.fileSource, test.threadPool, MapMode::Still);
|
||||
auto decoded1 = decodeImage(util::read_file("test/fixtures/sprites/default_marker.png"));
|
||||
auto decoded2 = decodeImage(util::read_file("test/fixtures/sprites/default_marker.png"));
|
||||
auto image1 = std::make_unique<SpriteImage>(std::move(decoded1), 1.0);
|
||||
@@ -393,20 +379,18 @@ TEST(Map, AddImage) {
|
||||
|
||||
map.setStyleJSON(util::read_file("test/fixtures/api/icon_style.json"));
|
||||
map.addImage("test-icon", std::move(image2));
|
||||
test::checkImage("test/fixtures/map/add_icon", test::render(map));
|
||||
test::checkImage("test/fixtures/map/add_icon", test::render(map, test.view));
|
||||
}
|
||||
|
||||
TEST(Map, RemoveImage) {
|
||||
MapTest test;
|
||||
|
||||
Map map(test.backend, test.view, test.view.getPixelRatio(), test.fileSource, test.threadPool,
|
||||
MapMode::Still);
|
||||
Map map(test.backend, test.view.getSize(), 1, test.fileSource, test.threadPool, MapMode::Still);
|
||||
auto decoded = decodeImage(util::read_file("test/fixtures/sprites/default_marker.png"));
|
||||
auto image = std::make_unique<SpriteImage>(std::move(decoded), 1.0);
|
||||
|
||||
map.setStyleJSON(util::read_file("test/fixtures/api/icon_style.json"));
|
||||
map.addImage("test-icon", std::move(image));
|
||||
map.removeImage("test-icon");
|
||||
test::checkImage("test/fixtures/map/remove_icon", test::render(map));
|
||||
test::checkImage("test/fixtures/map/remove_icon", test::render(map, test.view));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include <mbgl/test/util.hpp>
|
||||
|
||||
#include <mbgl/map/map.hpp>
|
||||
#include <mbgl/platform/default/offscreen_view.hpp>
|
||||
#include <mbgl/platform/log.hpp>
|
||||
#include <mbgl/util/image.hpp>
|
||||
#include <mbgl/util/io.hpp>
|
||||
@@ -97,10 +98,10 @@ Server::~Server() {
|
||||
}
|
||||
}
|
||||
|
||||
PremultipliedImage render(Map& map) {
|
||||
PremultipliedImage render(Map& map, OffscreenView& view) {
|
||||
PremultipliedImage result;
|
||||
map.renderStill([&result](std::exception_ptr, PremultipliedImage&& image) {
|
||||
result = std::move(image);
|
||||
map.renderStill(view, [&](std::exception_ptr) {
|
||||
result = view.readStillImage();
|
||||
});
|
||||
|
||||
while (!result.size()) {
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
namespace mbgl {
|
||||
|
||||
class Map;
|
||||
class OffscreenView;
|
||||
|
||||
namespace test {
|
||||
|
||||
@@ -64,7 +65,7 @@ private:
|
||||
int fd = -1;
|
||||
};
|
||||
|
||||
PremultipliedImage render(Map&);
|
||||
PremultipliedImage render(Map&, OffscreenView&);
|
||||
|
||||
void checkImage(const std::string& base,
|
||||
const PremultipliedImage& actual,
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#include <mbgl/map/map.hpp>
|
||||
#include <mbgl/platform/default/headless_backend.hpp>
|
||||
#include <mbgl/platform/default/headless_view.hpp>
|
||||
#include <mbgl/platform/default/offscreen_view.hpp>
|
||||
#include <mbgl/platform/default/thread_pool.hpp>
|
||||
#include <mbgl/util/io.hpp>
|
||||
#include <mbgl/util/run_loop.hpp>
|
||||
@@ -57,7 +57,7 @@ public:
|
||||
|
||||
util::RunLoop runLoop;
|
||||
HeadlessBackend backend;
|
||||
HeadlessView view{ 2 };
|
||||
OffscreenView view{ backend.getContext(), {{ 512, 512 }} };
|
||||
StubFileSource fileSource;
|
||||
ThreadPool threadPool { 4 };
|
||||
|
||||
@@ -93,22 +93,20 @@ private:
|
||||
TEST(Memory, Vector) {
|
||||
MemoryTest test;
|
||||
|
||||
Map map(test.backend, test.view, test.view.getPixelRatio(), test.fileSource, test.threadPool,
|
||||
MapMode::Still);
|
||||
Map map(test.backend, { { 256, 256 } }, 2, test.fileSource, test.threadPool, MapMode::Still);
|
||||
map.setZoom(16); // more map features
|
||||
map.setStyleURL("mapbox://streets");
|
||||
|
||||
test::render(map);
|
||||
test::render(map, test.view);
|
||||
}
|
||||
|
||||
TEST(Memory, Raster) {
|
||||
MemoryTest test;
|
||||
|
||||
Map map(test.backend, test.view, test.view.getPixelRatio(), test.fileSource, test.threadPool,
|
||||
MapMode::Still);
|
||||
Map map(test.backend, { { 256, 256 } }, 2, test.fileSource, test.threadPool, MapMode::Still);
|
||||
map.setStyleURL("mapbox://satellite");
|
||||
|
||||
test::render(map);
|
||||
test::render(map, test.view);
|
||||
}
|
||||
|
||||
// This test will measure the size of a Map object
|
||||
@@ -123,19 +121,17 @@ TEST(Memory, Footprint) {
|
||||
|
||||
MemoryTest test;
|
||||
|
||||
auto renderMap = [](Map* map, const char* style){
|
||||
map->setZoom(16);
|
||||
|
||||
map->setStyleURL(style);
|
||||
test::render(*map);
|
||||
auto renderMap = [&](Map& map, const char* style){
|
||||
map.setZoom(16);
|
||||
map.setStyleURL(style);
|
||||
test::render(map, test.view);
|
||||
};
|
||||
|
||||
// Warm up buffers and cache.
|
||||
for (unsigned i = 0; i < 10; ++i) {
|
||||
Map map(test.backend, test.view, test.view.getPixelRatio(), test.fileSource,
|
||||
test.threadPool, MapMode::Still);
|
||||
renderMap(&map, "mapbox://streets");
|
||||
renderMap(&map, "mapbox://satellite");
|
||||
Map map(test.backend, {{ 256, 256 }}, 2, test.fileSource, test.threadPool, MapMode::Still);
|
||||
renderMap(map, "mapbox://streets");
|
||||
renderMap(map, "mapbox://satellite");
|
||||
};
|
||||
|
||||
// Process close callbacks, mostly needed by
|
||||
@@ -147,9 +143,9 @@ TEST(Memory, Footprint) {
|
||||
|
||||
long vectorInitialRSS = getRSS();
|
||||
for (unsigned i = 0; i < runs; ++i) {
|
||||
auto vector = std::make_unique<Map>(test.backend, test.view, test.view.getPixelRatio(),
|
||||
test.fileSource, test.threadPool, MapMode::Still);
|
||||
renderMap(vector.get(), "mapbox://streets");
|
||||
auto vector = std::make_unique<Map>(test.backend, std::array<uint16_t, 2>{ { 256, 256 } },
|
||||
2, test.fileSource, test.threadPool, MapMode::Still);
|
||||
renderMap(*vector, "mapbox://streets");
|
||||
maps.push_back(std::move(vector));
|
||||
};
|
||||
|
||||
@@ -157,9 +153,9 @@ TEST(Memory, Footprint) {
|
||||
|
||||
long rasterInitialRSS = getRSS();
|
||||
for (unsigned i = 0; i < runs; ++i) {
|
||||
auto raster = std::make_unique<Map>(test.backend, test.view, test.view.getPixelRatio(),
|
||||
test.fileSource, test.threadPool, MapMode::Still);
|
||||
renderMap(raster.get(), "mapbox://satellite");
|
||||
auto raster = std::make_unique<Map>(test.backend, std::array<uint16_t, 2>{ { 256, 256 } },
|
||||
2, test.fileSource, test.threadPool, MapMode::Still);
|
||||
renderMap(*raster, "mapbox://satellite");
|
||||
maps.push_back(std::move(raster));
|
||||
};
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include <mbgl/gl/context.hpp>
|
||||
#include <mbgl/platform/default/headless_backend.hpp>
|
||||
#include <mbgl/platform/default/headless_view.hpp>
|
||||
#include <mbgl/platform/default/offscreen_view.hpp>
|
||||
#include <mbgl/gl/gl.hpp>
|
||||
|
||||
#include <mbgl/util/offscreen_texture.hpp>
|
||||
@@ -11,7 +11,7 @@ using namespace mbgl;
|
||||
|
||||
TEST(OffscreenTexture, EmptyRed) {
|
||||
HeadlessBackend backend;
|
||||
HeadlessView view(1.0f, 512, 256);
|
||||
OffscreenView view(backend.getContext(), {{ 512, 256 }});
|
||||
view.bind();
|
||||
|
||||
MBGL_CHECK_ERROR(glClearColor(1.0f, 0.0f, 0.0f, 1.0f));
|
||||
@@ -68,10 +68,7 @@ struct Buffer {
|
||||
|
||||
TEST(OffscreenTexture, RenderToTexture) {
|
||||
HeadlessBackend backend;
|
||||
HeadlessView view(1.0f, 512, 256);
|
||||
view.bind();
|
||||
gl::Context context;
|
||||
context.viewport.setDefaultValue(gl::value::Viewport::Get());
|
||||
auto& context = backend.getContext();
|
||||
|
||||
MBGL_CHECK_ERROR(glEnable(GL_BLEND));
|
||||
MBGL_CHECK_ERROR(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
|
||||
@@ -109,14 +106,17 @@ void main() {
|
||||
|
||||
// Make sure the texture gets destructed before we call context.reset();
|
||||
{
|
||||
OffscreenView view(context, {{ 512, 256 }});
|
||||
|
||||
// First, draw red to the bound FBO.
|
||||
context.clearColor = { 1, 0, 0, 1 };
|
||||
view.bind();
|
||||
MBGL_CHECK_ERROR(glClear(GL_COLOR_BUFFER_BIT));
|
||||
|
||||
// Then, create a texture, bind it, and render yellow to that texture. This should not
|
||||
// affect the originally bound FBO.
|
||||
OffscreenTexture texture;
|
||||
texture.bind(context, {{ 128, 128 }});
|
||||
OffscreenTexture texture(context, {{ 128, 128 }});
|
||||
texture.bind();
|
||||
|
||||
context.clearColor = { 0, 0, 0, 0 };
|
||||
MBGL_CHECK_ERROR(glClear(GL_COLOR_BUFFER_BIT));
|
||||
@@ -128,12 +128,10 @@ void main() {
|
||||
glVertexAttribPointer(paintShader.a_pos, 2, GL_FLOAT, GL_FALSE, 0, nullptr));
|
||||
MBGL_CHECK_ERROR(glDrawArrays(GL_TRIANGLE_STRIP, 0, 3));
|
||||
|
||||
auto image = view.readStillImage(texture.getSize());
|
||||
auto image = texture.readStillImage();
|
||||
test::checkImage("test/fixtures/offscreen_texture/render-to-texture", image, 0, 0);
|
||||
|
||||
// Now reset the FBO back to normal and retrieve the original (restored) framebuffer.
|
||||
context.resetState();
|
||||
context.bindFramebuffer.setDirty();
|
||||
view.bind();
|
||||
|
||||
image = view.readStillImage();
|
||||
|
||||
Reference in New Issue
Block a user