[core] Render from the main thread
Do not create a thread for the MapContext anymore.
This commit is contained in:
@@ -32,10 +32,6 @@ class ShapeAnnotation;
|
||||
struct CameraOptions;
|
||||
struct AnimationOptions;
|
||||
|
||||
namespace util {
|
||||
template <class T> class Thread;
|
||||
} // namespace util
|
||||
|
||||
class Map : private util::noncopyable {
|
||||
friend class View;
|
||||
|
||||
@@ -46,22 +42,15 @@ public:
|
||||
ConstrainMode constrainMode = ConstrainMode::HeightOnly);
|
||||
~Map();
|
||||
|
||||
// Pauses the render thread. The render thread will stop running but will not be terminated and will not lose state until resumed.
|
||||
void pause();
|
||||
bool isPaused();
|
||||
|
||||
// Resumes a paused render thread
|
||||
void resume();
|
||||
|
||||
// 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);
|
||||
|
||||
// Triggers a synchronous render.
|
||||
void renderSync();
|
||||
// Main render function.
|
||||
void render();
|
||||
|
||||
// Notifies the Map thread that the state has changed and an update might be necessary.
|
||||
// Notifies the Map that the state has changed and an update might be necessary.
|
||||
void update(Update update);
|
||||
|
||||
// Styling
|
||||
@@ -189,7 +178,7 @@ public:
|
||||
private:
|
||||
View& view;
|
||||
const std::unique_ptr<Transform> transform;
|
||||
const std::unique_ptr<util::Thread<MapContext>> context;
|
||||
const std::unique_ptr<MapContext> context;
|
||||
MapData* data;
|
||||
|
||||
enum class RenderState {
|
||||
|
||||
@@ -30,44 +30,42 @@ enum MapChange : uint8_t {
|
||||
|
||||
class View {
|
||||
public:
|
||||
// Called from the main thread directly after initialization. Must always return the same value,
|
||||
// i.e. it may not change over time.
|
||||
virtual ~View() = default;
|
||||
|
||||
// Called directly after initialization. Must always return the same value, i.e. it may
|
||||
// not change over time.
|
||||
virtual float getPixelRatio() const = 0;
|
||||
|
||||
// Called from the main thread when the View signaled a dimension change. Must return the
|
||||
// logical dimension of this map in pixels.
|
||||
// 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 from the main thread 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.
|
||||
// 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;
|
||||
|
||||
// Called from the main thread when this View is associated with a Map object.
|
||||
virtual void initialize(Map *map_);
|
||||
// Called when this View is associated with a Map object.
|
||||
virtual void initialize(Map*);
|
||||
|
||||
// Called from the render thread. Makes the GL context active in the current
|
||||
// thread. This is typically just called once at the beginning of the
|
||||
// renderer setup since the render thread doesn't switch the contexts.
|
||||
// Called when the view's GL context needs to be made active or inactive. These are called,
|
||||
// as a matched pair, in four situations:
|
||||
//
|
||||
// 1. When releasing GL resources during Map destruction
|
||||
// 2. When calling a CustomLayerInitializeFunction, during Map::addCustomLayer
|
||||
// 3. When calling a CustomLayerDeinitializeFunction, during Map::removeCustomLayer
|
||||
// 4. When rendering for Map::renderStill
|
||||
//
|
||||
// They are *not* called for Map::render; it is assumed that the correct context is already
|
||||
// activated prior to calling Map::render.
|
||||
virtual void activate() = 0;
|
||||
|
||||
// Called from the render thread. Makes the GL context inactive in the current
|
||||
// thread. This is called once just before the rendering thread terminates.
|
||||
virtual void deactivate() = 0;
|
||||
|
||||
virtual void notify() = 0;
|
||||
|
||||
// Called from the render thread. The implementation must trigger a rerender.
|
||||
// (map->renderSync() from the main thread must be called as a result of this)
|
||||
// Called when the map needs to be rendered; the view should call Map::render() at some point
|
||||
// in the near future. (Not called for Map::renderStill() mode.)
|
||||
virtual void invalidate() = 0;
|
||||
|
||||
// Called from the render thread before the render begins.
|
||||
virtual void beforeRender() = 0;
|
||||
|
||||
// Called from the render thread after the render is complete.
|
||||
virtual void afterRender() = 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();
|
||||
|
||||
@@ -22,13 +22,10 @@ public:
|
||||
std::array<uint16_t, 2> getSize() const override;
|
||||
std::array<uint16_t, 2> getFramebufferSize() const override;
|
||||
|
||||
void initialize(mbgl::Map *map) override;
|
||||
void initialize(mbgl::Map*) override;
|
||||
void activate() override;
|
||||
void deactivate() override;
|
||||
void notify() override;
|
||||
void invalidate() override;
|
||||
void beforeRender() override;
|
||||
void afterRender() override;
|
||||
|
||||
static void onKey(GLFWwindow *window, int key, int scancode, int action, int mods);
|
||||
static void onScroll(GLFWwindow *window, double xoffset, double yoffset);
|
||||
|
||||
@@ -38,34 +38,31 @@ public:
|
||||
std::array<uint16_t, 2> getSize() const override;
|
||||
std::array<uint16_t, 2> getFramebufferSize() const override;
|
||||
|
||||
void invalidate() override;
|
||||
void activate() override;
|
||||
void deactivate() override;
|
||||
void notify() override;
|
||||
void invalidate() override;
|
||||
void beforeRender() override;
|
||||
void afterRender() override;
|
||||
|
||||
PremultipliedImage readStillImage() override;
|
||||
|
||||
void resizeFramebuffer();
|
||||
void resize(uint16_t width, uint16_t height);
|
||||
|
||||
private:
|
||||
void loadExtensions();
|
||||
bool isActive() const;
|
||||
|
||||
// Implementation specific functions
|
||||
static gl::glProc initializeExtension(const char*);
|
||||
void createContext();
|
||||
void destroyContext();
|
||||
void clearBuffers();
|
||||
void resizeFramebuffer();
|
||||
void activateContext();
|
||||
void deactivateContext();
|
||||
|
||||
private:
|
||||
std::shared_ptr<HeadlessDisplay> display;
|
||||
const float pixelRatio;
|
||||
std::array<uint16_t, 2> dimensions;
|
||||
|
||||
bool needsResize = false;
|
||||
bool extensionsLoaded = false;
|
||||
bool active = false;
|
||||
|
||||
#if MBGL_USE_CGL
|
||||
CGLContextObj glContext = nullptr;
|
||||
@@ -82,13 +79,9 @@ private:
|
||||
GLXPbuffer glxPbuffer = 0;
|
||||
#endif
|
||||
|
||||
bool extensionsLoaded = false;
|
||||
|
||||
GLuint fbo = 0;
|
||||
GLuint fboDepthStencil = 0;
|
||||
GLuint fboColor = 0;
|
||||
|
||||
std::thread::id thread;
|
||||
};
|
||||
|
||||
} // namespace mbgl
|
||||
|
||||
@@ -521,7 +521,6 @@ public class MapView extends FrameLayout {
|
||||
mConnectivityReceiver = null;
|
||||
|
||||
mUserLocationView.onPause();
|
||||
mNativeMapView.pause();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -533,7 +532,6 @@ public class MapView extends FrameLayout {
|
||||
mConnectivityReceiver = new ConnectivityReceiver();
|
||||
getContext().registerReceiver(mConnectivityReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
|
||||
|
||||
mNativeMapView.resume();
|
||||
mNativeMapView.update();
|
||||
mUserLocationView.onResume();
|
||||
|
||||
@@ -1094,9 +1092,7 @@ public class MapView extends FrameLayout {
|
||||
}
|
||||
|
||||
int getTopOffsetPixelsForIcon(Icon icon) {
|
||||
// This method will dead lock if map paused. Causes a freeze if you add a marker in an
|
||||
// activity's onCreate()
|
||||
if (mDestroyed || mNativeMapView.isPaused()) {
|
||||
if (mDestroyed) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1243,11 +1239,11 @@ public class MapView extends FrameLayout {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mDestroyed || mNativeMapView.isPaused()) {
|
||||
if (mDestroyed) {
|
||||
return;
|
||||
}
|
||||
|
||||
mNativeMapView.renderSync();
|
||||
mNativeMapView.render();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -119,24 +119,12 @@ final class NativeMapView {
|
||||
nativeDestroySurface(mNativeMapViewPtr);
|
||||
}
|
||||
|
||||
public void pause() {
|
||||
nativePause(mNativeMapViewPtr);
|
||||
}
|
||||
|
||||
public boolean isPaused() {
|
||||
return nativeIsPaused(mNativeMapViewPtr);
|
||||
}
|
||||
|
||||
public void resume() {
|
||||
nativeResume(mNativeMapViewPtr);
|
||||
}
|
||||
|
||||
public void update() {
|
||||
nativeUpdate(mNativeMapViewPtr);
|
||||
}
|
||||
|
||||
public void renderSync() {
|
||||
nativeRenderSync(mNativeMapViewPtr);
|
||||
public void render() {
|
||||
nativeRender(mNativeMapViewPtr);
|
||||
}
|
||||
|
||||
public void resizeView(int width, int height) {
|
||||
@@ -515,15 +503,9 @@ final class NativeMapView {
|
||||
|
||||
private native void nativeDestroySurface(long nativeMapViewPtr);
|
||||
|
||||
private native void nativePause(long nativeMapViewPtr);
|
||||
|
||||
private native boolean nativeIsPaused(long nativeMapViewPtr);
|
||||
|
||||
private native void nativeResume(long nativeMapViewPtr);
|
||||
|
||||
private native void nativeUpdate(long nativeMapViewPtr);
|
||||
|
||||
private native void nativeRenderSync(long nativeMapViewPtr);
|
||||
private native void nativeRender(long nativeMapViewPtr);
|
||||
|
||||
private native void nativeViewResize(long nativeMapViewPtr, int width, int height);
|
||||
|
||||
|
||||
@@ -404,27 +404,6 @@ void nativeDestroySurface(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr
|
||||
nativeMapView->destroySurface();
|
||||
}
|
||||
|
||||
void nativePause(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
|
||||
mbgl::Log::Debug(mbgl::Event::JNI, "nativePause");
|
||||
assert(nativeMapViewPtr != 0);
|
||||
NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
|
||||
nativeMapView->pause();
|
||||
}
|
||||
|
||||
jboolean nativeIsPaused(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
|
||||
mbgl::Log::Debug(mbgl::Event::JNI, "nativeIsPaused");
|
||||
assert(nativeMapViewPtr != 0);
|
||||
NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
|
||||
return nativeMapView->getMap().isPaused();
|
||||
}
|
||||
|
||||
void nativeResume(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
|
||||
mbgl::Log::Debug(mbgl::Event::JNI, "nativeResume");
|
||||
assert(nativeMapViewPtr != 0);
|
||||
NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
|
||||
nativeMapView->resume();
|
||||
}
|
||||
|
||||
void nativeUpdate(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
|
||||
mbgl::Log::Debug(mbgl::Event::JNI, "nativeUpdate");
|
||||
assert(nativeMapViewPtr != 0);
|
||||
@@ -432,11 +411,11 @@ void nativeUpdate(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
|
||||
nativeMapView->getMap().update(mbgl::Update::Repaint);
|
||||
}
|
||||
|
||||
void nativeRenderSync(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
|
||||
mbgl::Log::Debug(mbgl::Event::JNI, "nativeRenderSync");
|
||||
void nativeRender(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr) {
|
||||
mbgl::Log::Debug(mbgl::Event::JNI, "nativeRender");
|
||||
assert(nativeMapViewPtr != 0);
|
||||
NativeMapView *nativeMapView = reinterpret_cast<NativeMapView *>(nativeMapViewPtr);
|
||||
nativeMapView->getMap().renderSync();
|
||||
nativeMapView->render();
|
||||
}
|
||||
|
||||
void nativeViewResize(JNIEnv *env, jni::jobject* obj, jlong nativeMapViewPtr, jint width, jint height) {
|
||||
@@ -1815,11 +1794,8 @@ extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
|
||||
MAKE_NATIVE_METHOD(nativeTerminateContext, "(J)V"),
|
||||
MAKE_NATIVE_METHOD(nativeCreateSurface, "(JLandroid/view/Surface;)V"),
|
||||
MAKE_NATIVE_METHOD(nativeDestroySurface, "(J)V"),
|
||||
MAKE_NATIVE_METHOD(nativePause, "(J)V"),
|
||||
MAKE_NATIVE_METHOD(nativeIsPaused, "(J)Z"),
|
||||
MAKE_NATIVE_METHOD(nativeResume, "(J)V"),
|
||||
MAKE_NATIVE_METHOD(nativeUpdate, "(J)V"),
|
||||
MAKE_NATIVE_METHOD(nativeRenderSync, "(J)V"),
|
||||
MAKE_NATIVE_METHOD(nativeRender, "(J)V"),
|
||||
MAKE_NATIVE_METHOD(nativeViewResize, "(JII)V"),
|
||||
MAKE_NATIVE_METHOD(nativeFramebufferResize, "(JII)V"),
|
||||
MAKE_NATIVE_METHOD(nativeAddClass, "(JLjava/lang/String;)V"),
|
||||
|
||||
@@ -90,8 +90,6 @@ NativeMapView::NativeMapView(JNIEnv *env, jobject obj_, float pixelRatio_, int a
|
||||
size_t cacheSize = zoomFactor * cpuFactor * memoryFactor * sizeFactor * 0.5f;
|
||||
|
||||
map->setSourceTileCacheSize(cacheSize);
|
||||
|
||||
map->pause();
|
||||
}
|
||||
|
||||
NativeMapView::~NativeMapView() {
|
||||
@@ -189,20 +187,15 @@ void NativeMapView::invalidate() {
|
||||
detach_jni_thread(vm, &env, detach);
|
||||
}
|
||||
|
||||
void NativeMapView::beforeRender() {
|
||||
mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::beforeRender()");
|
||||
void NativeMapView::render() {
|
||||
activate();
|
||||
|
||||
if(sizeChanged){
|
||||
sizeChanged = false;
|
||||
glViewport(0, 0, fbWidth, fbHeight);
|
||||
}
|
||||
}
|
||||
|
||||
void NativeMapView::afterRender() {
|
||||
mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::afterRender()");
|
||||
|
||||
assert(vm != nullptr);
|
||||
assert(obj != nullptr);
|
||||
map->render();
|
||||
|
||||
if ((display != EGL_NO_DISPLAY) && (surface != EGL_NO_SURFACE)) {
|
||||
if (!eglSwapBuffers(display, surface)) {
|
||||
@@ -215,11 +208,8 @@ void NativeMapView::afterRender() {
|
||||
} else {
|
||||
mbgl::Log::Info(mbgl::Event::Android, "Not swapping as we are not ready");
|
||||
}
|
||||
}
|
||||
|
||||
void NativeMapView::notify() {
|
||||
mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::notify()");
|
||||
// noop
|
||||
deactivate();
|
||||
}
|
||||
|
||||
mbgl::Map &NativeMapView::getMap() { return *map; }
|
||||
@@ -444,15 +434,11 @@ void NativeMapView::createSurface(ANativeWindow *window_) {
|
||||
throw std::runtime_error("eglMakeCurrent() failed");
|
||||
}
|
||||
}
|
||||
|
||||
resume();
|
||||
}
|
||||
|
||||
void NativeMapView::destroySurface() {
|
||||
mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::destroySurface");
|
||||
|
||||
pause();
|
||||
|
||||
if (surface != EGL_NO_SURFACE) {
|
||||
if (!eglDestroySurface(display, surface)) {
|
||||
mbgl::Log::Error(mbgl::Event::OpenGL, "eglDestroySurface() returned error %d",
|
||||
@@ -669,27 +655,6 @@ EGLConfig NativeMapView::chooseConfig(const EGLConfig configs[], EGLint numConfi
|
||||
return configId;
|
||||
}
|
||||
|
||||
void NativeMapView::pause() {
|
||||
mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::pause");
|
||||
|
||||
if ((display != EGL_NO_DISPLAY) && (context != EGL_NO_CONTEXT)) {
|
||||
map->pause();
|
||||
}
|
||||
}
|
||||
|
||||
void NativeMapView::resume() {
|
||||
mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::resume");
|
||||
|
||||
assert(display != EGL_NO_DISPLAY);
|
||||
assert(context != EGL_NO_CONTEXT);
|
||||
|
||||
if (surface != EGL_NO_SURFACE) {
|
||||
map->resume();
|
||||
} else {
|
||||
mbgl::Log::Debug(mbgl::Event::Android, "Not resuming because we are not ready");
|
||||
}
|
||||
}
|
||||
|
||||
void NativeMapView::notifyMapChange(mbgl::MapChange change) {
|
||||
mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::notifyMapChange()");
|
||||
|
||||
|
||||
@@ -24,10 +24,7 @@ public:
|
||||
std::array<uint16_t, 2> getFramebufferSize() const override;
|
||||
void activate() override;
|
||||
void deactivate() override;
|
||||
void notify() override;
|
||||
void invalidate() override;
|
||||
void beforeRender() override;
|
||||
void afterRender() override;
|
||||
|
||||
void notifyMapChange(mbgl::MapChange) override;
|
||||
|
||||
@@ -43,8 +40,7 @@ public:
|
||||
void createSurface(ANativeWindow *window);
|
||||
void destroySurface();
|
||||
|
||||
void resume();
|
||||
void pause();
|
||||
void render();
|
||||
|
||||
void enableFps(bool enable);
|
||||
void updateFps();
|
||||
|
||||
@@ -76,7 +76,7 @@ void HeadlessView::resizeFramebuffer() {
|
||||
}
|
||||
|
||||
void HeadlessView::clearBuffers() {
|
||||
assert(isActive());
|
||||
assert(active);
|
||||
|
||||
MBGL_CHECK_ERROR(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ void HeadlessView::resizeFramebuffer() {
|
||||
}
|
||||
|
||||
void HeadlessView::clearBuffers() {
|
||||
assert(isActive());
|
||||
assert(active);
|
||||
|
||||
MBGL_CHECK_ERROR(glBindFramebuffer(GL_FRAMEBUFFER, 0));
|
||||
|
||||
|
||||
@@ -428,7 +428,18 @@ void GLFWView::run() {
|
||||
const bool dirty = !clean.test_and_set();
|
||||
if (dirty) {
|
||||
const double started = glfwGetTime();
|
||||
map->renderSync();
|
||||
|
||||
glfwMakeContextCurrent(window);
|
||||
glViewport(0, 0, fbWidth, fbHeight);
|
||||
|
||||
map->render();
|
||||
|
||||
if (showClipMasks) {
|
||||
renderClipMasks();
|
||||
}
|
||||
|
||||
glfwSwapBuffers(window);
|
||||
|
||||
report(1000 * (glfwGetTime() - started));
|
||||
if (benchmark) {
|
||||
map->update(mbgl::Update::Repaint);
|
||||
@@ -460,31 +471,11 @@ void GLFWView::deactivate() {
|
||||
glfwMakeContextCurrent(nullptr);
|
||||
}
|
||||
|
||||
void GLFWView::notify() {
|
||||
glfwPostEmptyEvent();
|
||||
}
|
||||
|
||||
void GLFWView::invalidate() {
|
||||
clean.clear();
|
||||
glfwPostEmptyEvent();
|
||||
}
|
||||
|
||||
void GLFWView::beforeRender() {
|
||||
// This is called from the map thread but `width` and `height`
|
||||
// can be accessed with no race because the main thread is blocked
|
||||
// when we render. This will be more straightforward when we move
|
||||
// rendering to the main thread.
|
||||
glViewport(0, 0, fbWidth, fbHeight);
|
||||
}
|
||||
|
||||
void GLFWView::afterRender() {
|
||||
if (showClipMasks) {
|
||||
renderClipMasks();
|
||||
}
|
||||
|
||||
glfwSwapBuffers(window);
|
||||
}
|
||||
|
||||
void GLFWView::renderClipMasks() {
|
||||
// Read the stencil buffer
|
||||
auto pixels = std::make_unique<uint8_t[]>(fbWidth * fbHeight);
|
||||
|
||||
@@ -31,22 +31,6 @@ HeadlessView::~HeadlessView() {
|
||||
destroyContext();
|
||||
}
|
||||
|
||||
|
||||
void HeadlessView::loadExtensions() {
|
||||
if (extensionsLoaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
gl::InitializeExtensions(initializeExtension);
|
||||
|
||||
extensionsLoaded = true;
|
||||
}
|
||||
|
||||
|
||||
bool HeadlessView::isActive() const {
|
||||
return std::this_thread::get_id() == thread;
|
||||
}
|
||||
|
||||
void HeadlessView::resize(const uint16_t width, const uint16_t height) {
|
||||
if(dimensions[0] == width &&
|
||||
dimensions[1] == height) {
|
||||
@@ -57,7 +41,7 @@ void HeadlessView::resize(const uint16_t width, const uint16_t height) {
|
||||
}
|
||||
|
||||
PremultipliedImage HeadlessView::readStillImage() {
|
||||
assert(isActive());
|
||||
assert(active);
|
||||
|
||||
const unsigned int w = dimensions[0] * pixelRatio;
|
||||
const unsigned int h = dimensions[1] * pixelRatio;
|
||||
@@ -76,9 +60,6 @@ PremultipliedImage HeadlessView::readStillImage() {
|
||||
|
||||
return image;
|
||||
}
|
||||
void HeadlessView::notify() {
|
||||
// no-op
|
||||
}
|
||||
|
||||
float HeadlessView::getPixelRatio() const {
|
||||
return pixelRatio;
|
||||
@@ -94,10 +75,7 @@ std::array<uint16_t, 2> HeadlessView::getFramebufferSize() const {
|
||||
}
|
||||
|
||||
void HeadlessView::activate() {
|
||||
if (thread != std::thread::id()) {
|
||||
throw std::runtime_error("OpenGL context was already current");
|
||||
}
|
||||
thread = std::this_thread::get_id();
|
||||
active = true;
|
||||
|
||||
if (!glContext) {
|
||||
if (!display) {
|
||||
@@ -107,23 +85,12 @@ void HeadlessView::activate() {
|
||||
}
|
||||
|
||||
activateContext();
|
||||
loadExtensions();
|
||||
}
|
||||
|
||||
void HeadlessView::deactivate() {
|
||||
if (thread == std::thread::id()) {
|
||||
throw std::runtime_error("OpenGL context was not current");
|
||||
if (!extensionsLoaded) {
|
||||
gl::InitializeExtensions(initializeExtension);
|
||||
extensionsLoaded = true;
|
||||
}
|
||||
thread = std::thread::id();
|
||||
|
||||
deactivateContext();
|
||||
}
|
||||
|
||||
void HeadlessView::invalidate() {
|
||||
// no-op
|
||||
}
|
||||
|
||||
void HeadlessView::beforeRender() {
|
||||
if (needsResize) {
|
||||
clearBuffers();
|
||||
resizeFramebuffer();
|
||||
@@ -131,8 +98,13 @@ void HeadlessView::beforeRender() {
|
||||
}
|
||||
}
|
||||
|
||||
void HeadlessView::afterRender() {
|
||||
// no-op
|
||||
void HeadlessView::deactivate() {
|
||||
deactivateContext();
|
||||
active = false;
|
||||
}
|
||||
|
||||
void HeadlessView::invalidate() {
|
||||
assert(false);
|
||||
}
|
||||
|
||||
} // namespace mbgl
|
||||
|
||||
@@ -93,7 +93,7 @@ void HeadlessView::resizeFramebuffer() {
|
||||
}
|
||||
|
||||
void HeadlessView::clearBuffers() {
|
||||
assert(isActive());
|
||||
assert(active);
|
||||
|
||||
MBGL_CHECK_ERROR(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
|
||||
|
||||
|
||||
@@ -320,7 +320,6 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
|
||||
// start paused if in IB
|
||||
if (_isTargetingInterfaceBuilder || background) {
|
||||
self.dormant = YES;
|
||||
_mbglMap->pause();
|
||||
}
|
||||
|
||||
// Notify map object when network reachability status changes.
|
||||
@@ -751,8 +750,7 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
|
||||
NSUInteger cacheSize = zoomFactor * cpuFactor * memoryFactor * sizeFactor * 0.5;
|
||||
|
||||
_mbglMap->setSourceTileCacheSize(cacheSize);
|
||||
|
||||
_mbglMap->renderSync();
|
||||
_mbglMap->render();
|
||||
|
||||
[self updateUserLocationAnnotationView];
|
||||
}
|
||||
@@ -895,7 +893,6 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
|
||||
{
|
||||
[self validateDisplayLink];
|
||||
self.dormant = YES;
|
||||
_mbglMap->pause();
|
||||
[self.glView deleteDrawable];
|
||||
}
|
||||
}
|
||||
@@ -967,8 +964,6 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
|
||||
[self.glSnapshotView addSubview:snapshotTint];
|
||||
}
|
||||
|
||||
_mbglMap->pause();
|
||||
|
||||
[self.glView deleteDrawable];
|
||||
}
|
||||
}
|
||||
@@ -988,8 +983,6 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
|
||||
[self.glSnapshotView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
|
||||
|
||||
[self.glView bindDrawable];
|
||||
|
||||
_mbglMap->resume();
|
||||
|
||||
_displayLink.paused = NO;
|
||||
|
||||
@@ -3957,12 +3950,10 @@ mbgl::Duration MGLDurationInSeconds(NSTimeInterval duration)
|
||||
|
||||
class MBGLView : public mbgl::View
|
||||
{
|
||||
public:
|
||||
MBGLView(MGLMapView* nativeView_, const float scaleFactor_)
|
||||
: nativeView(nativeView_), scaleFactor(scaleFactor_) {
|
||||
}
|
||||
virtual ~MBGLView() {}
|
||||
|
||||
public:
|
||||
MBGLView(MGLMapView* nativeView_, const float scaleFactor_)
|
||||
: nativeView(nativeView_), scaleFactor(scaleFactor_) {
|
||||
}
|
||||
|
||||
float getPixelRatio() const override {
|
||||
return scaleFactor;
|
||||
@@ -3970,7 +3961,7 @@ class MBGLView : public mbgl::View
|
||||
|
||||
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) }};
|
||||
static_cast<uint16_t>([nativeView bounds].size.height) }};
|
||||
}
|
||||
|
||||
std::array<uint16_t, 2> getFramebufferSize() const override {
|
||||
@@ -3978,17 +3969,16 @@ class MBGLView : public mbgl::View
|
||||
static_cast<uint16_t>([[nativeView glView] drawableHeight]) }};
|
||||
}
|
||||
|
||||
void notify() override
|
||||
{
|
||||
// no-op
|
||||
}
|
||||
|
||||
void notifyMapChange(mbgl::MapChange change) override
|
||||
{
|
||||
assert([[NSThread currentThread] isMainThread]);
|
||||
[nativeView notifyMapChange:change];
|
||||
}
|
||||
|
||||
void invalidate() override
|
||||
{
|
||||
[nativeView setNeedsGLDisplay];
|
||||
}
|
||||
|
||||
void activate() override
|
||||
{
|
||||
[EAGLContext setCurrentContext:nativeView.context];
|
||||
@@ -3999,26 +3989,9 @@ class MBGLView : public mbgl::View
|
||||
[EAGLContext setCurrentContext:nil];
|
||||
}
|
||||
|
||||
void invalidate() override
|
||||
{
|
||||
[nativeView performSelectorOnMainThread:@selector(setNeedsGLDisplay)
|
||||
withObject:nil
|
||||
waitUntilDone:NO];
|
||||
}
|
||||
|
||||
void beforeRender() override
|
||||
{
|
||||
// no-op
|
||||
}
|
||||
|
||||
void afterRender() override
|
||||
{
|
||||
// no-op
|
||||
}
|
||||
|
||||
private:
|
||||
__weak MGLMapView *nativeView = nullptr;
|
||||
const float scaleFactor;
|
||||
private:
|
||||
__weak MGLMapView *nativeView = nullptr;
|
||||
const float scaleFactor;
|
||||
};
|
||||
|
||||
@end
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
#include "node_map.hpp"
|
||||
#include "node_request.hpp"
|
||||
#include "node_mapbox_gl_native.hpp"
|
||||
|
||||
#include <mbgl/platform/default/headless_display.hpp>
|
||||
#include <mbgl/util/exception.hpp>
|
||||
#include <mbgl/util/work_request.hpp>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
@@ -474,18 +472,16 @@ NodeMap::~NodeMap() {
|
||||
if (valid) release();
|
||||
}
|
||||
|
||||
std::unique_ptr<mbgl::AsyncRequest> NodeMap::request(const mbgl::Resource& resource, Callback cb1) {
|
||||
// This function can be called from any thread. Make sure we're executing the
|
||||
// JS implementation in the node event loop.
|
||||
return NodeRunLoop().invokeWithCallback([this] (mbgl::Resource res, Callback cb2) {
|
||||
Nan::HandleScope scope;
|
||||
std::unique_ptr<mbgl::AsyncRequest> NodeMap::request(const mbgl::Resource& resource, Callback callback_) {
|
||||
Nan::HandleScope scope;
|
||||
|
||||
auto requestHandle = NodeRequest::Create(res, cb2)->ToObject();
|
||||
auto callbackHandle = Nan::New<v8::Function>(NodeRequest::Respond, requestHandle);
|
||||
auto requestHandle = NodeRequest::Create(resource, callback_)->ToObject();
|
||||
auto callbackHandle = Nan::New<v8::Function>(NodeRequest::Respond, requestHandle);
|
||||
|
||||
v8::Local<v8::Value> argv[] = { requestHandle, callbackHandle };
|
||||
Nan::MakeCallback(handle()->GetInternalField(1)->ToObject(), "request", 2, argv);
|
||||
}, cb1, resource);
|
||||
v8::Local<v8::Value> argv[] = { requestHandle, callbackHandle };
|
||||
Nan::MakeCallback(handle()->GetInternalField(1)->ToObject(), "request", 2, argv);
|
||||
|
||||
return std::make_unique<mbgl::AsyncRequest>();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,25 +5,18 @@
|
||||
#include <nan.h>
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
#include "node_mapbox_gl_native.hpp"
|
||||
#include <mbgl/util/run_loop.hpp>
|
||||
|
||||
#include "node_map.hpp"
|
||||
#include "node_log.hpp"
|
||||
#include "node_request.hpp"
|
||||
|
||||
namespace node_mbgl {
|
||||
|
||||
mbgl::util::RunLoop& NodeRunLoop() {
|
||||
static mbgl::util::RunLoop nodeRunLoop;
|
||||
return nodeRunLoop;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void RegisterModule(v8::Local<v8::Object> target, v8::Local<v8::Object> module) {
|
||||
// This has the effect of:
|
||||
// a) Ensuring that the static local variable is initialized before any thread contention.
|
||||
// b) unreffing an async handle, which otherwise would keep the default loop running.
|
||||
node_mbgl::NodeRunLoop().stop();
|
||||
static mbgl::util::RunLoop nodeRunLoop;
|
||||
nodeRunLoop.stop();
|
||||
|
||||
node_mbgl::NodeMap::Init(target);
|
||||
node_mbgl::NodeRequest::Init(target);
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <mbgl/util/run_loop.hpp>
|
||||
|
||||
namespace node_mbgl {
|
||||
|
||||
mbgl::util::RunLoop& NodeRunLoop();
|
||||
|
||||
}
|
||||
@@ -298,7 +298,9 @@ test('Map', function(t) {
|
||||
t.test('returning an error', function(t) {
|
||||
var map = new mbgl.Map({
|
||||
request: function(req, callback) {
|
||||
callback(new Error('request error'));
|
||||
setImmediate(function () {
|
||||
callback(new Error('request error'));
|
||||
});
|
||||
},
|
||||
});
|
||||
map.load(style);
|
||||
|
||||
@@ -540,7 +540,6 @@ public:
|
||||
[self deselectAnnotation:self.selectedAnnotation];
|
||||
if (!self.dormant && !newWindow) {
|
||||
self.dormant = YES;
|
||||
_mbglMap->pause();
|
||||
}
|
||||
|
||||
[self.window removeObserver:self forKeyPath:@"contentLayoutRect"];
|
||||
@@ -550,7 +549,6 @@ public:
|
||||
- (void)viewDidMoveToWindow {
|
||||
NSWindow *window = self.window;
|
||||
if (self.dormant && window) {
|
||||
_mbglMap->resume();
|
||||
self.dormant = NO;
|
||||
}
|
||||
|
||||
@@ -686,8 +684,31 @@ public:
|
||||
NSUInteger cacheSize = zoomFactor * cpuFactor * memoryFactor * sizeFactor * 0.5;
|
||||
|
||||
_mbglMap->setSourceTileCacheSize(cacheSize);
|
||||
_mbglMap->renderSync();
|
||||
|
||||
|
||||
// Enable vertex buffer objects.
|
||||
mbgl::gl::InitializeExtensions([](const char *name) {
|
||||
static CFBundleRef framework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl"));
|
||||
if (!framework) {
|
||||
throw std::runtime_error("Failed to load OpenGL framework.");
|
||||
}
|
||||
|
||||
CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, name, kCFStringEncodingASCII);
|
||||
void *symbol = CFBundleGetFunctionPointerForName(framework, str);
|
||||
CFRelease(str);
|
||||
|
||||
return reinterpret_cast<mbgl::gl::glProc>(symbol);
|
||||
});
|
||||
|
||||
_mbglMap->render();
|
||||
|
||||
if (_isPrinting) {
|
||||
_isPrinting = NO;
|
||||
std::string png = encodePNG(_mbglView->readStillImage());
|
||||
NSData *data = [[NSData alloc] initWithBytes:png.data() length:png.size()];
|
||||
NSImage *image = [[NSImage alloc] initWithData:data];
|
||||
[self printWithImage:image];
|
||||
}
|
||||
|
||||
// [self updateUserLocationAnnotationView];
|
||||
}
|
||||
}
|
||||
@@ -2270,85 +2291,39 @@ class MGLMapViewImpl : public mbgl::View {
|
||||
public:
|
||||
MGLMapViewImpl(MGLMapView *nativeView_, const float scaleFactor_)
|
||||
: nativeView(nativeView_), scaleFactor(scaleFactor_) {}
|
||||
virtual ~MGLMapViewImpl() {}
|
||||
|
||||
|
||||
|
||||
float getPixelRatio() const override {
|
||||
return scaleFactor;
|
||||
}
|
||||
|
||||
|
||||
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) }};
|
||||
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) }};
|
||||
static_cast<uint16_t>(bounds.size.height) }};
|
||||
}
|
||||
|
||||
void notify() override {}
|
||||
|
||||
|
||||
void notifyMapChange(mbgl::MapChange change) override {
|
||||
assert([[NSThread currentThread] isMainThread]);
|
||||
[nativeView notifyMapChange:change];
|
||||
}
|
||||
|
||||
|
||||
void invalidate() override {
|
||||
[nativeView invalidate];
|
||||
}
|
||||
|
||||
void activate() override {
|
||||
MGLOpenGLLayer *layer = (MGLOpenGLLayer *)nativeView.layer;
|
||||
if ([NSOpenGLContext currentContext] != layer.openGLContext) {
|
||||
// Enable our OpenGL context on the Map thread.
|
||||
[layer.openGLContext makeCurrentContext];
|
||||
|
||||
// Enable vertex buffer objects.
|
||||
mbgl::gl::InitializeExtensions([](const char *name) {
|
||||
static CFBundleRef framework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl"));
|
||||
if (!framework) {
|
||||
throw std::runtime_error("Failed to load OpenGL framework.");
|
||||
}
|
||||
|
||||
CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, name, kCFStringEncodingASCII);
|
||||
void *symbol = CFBundleGetFunctionPointerForName(framework, str);
|
||||
CFRelease(str);
|
||||
|
||||
return reinterpret_cast<mbgl::gl::glProc>(symbol);
|
||||
});
|
||||
}
|
||||
[layer.openGLContext makeCurrentContext];
|
||||
}
|
||||
|
||||
|
||||
void deactivate() override {
|
||||
[NSOpenGLContext clearCurrentContext];
|
||||
}
|
||||
|
||||
void invalidate() override {
|
||||
[nativeView performSelectorOnMainThread:@selector(invalidate)
|
||||
withObject:nil
|
||||
waitUntilDone:NO];
|
||||
}
|
||||
|
||||
void beforeRender() override {
|
||||
// This normally gets called right away by mbgl::Map, but only on the
|
||||
// main thread. OpenGL contexts and extensions are thread-local, so this
|
||||
// has to happen on the Map thread too.
|
||||
activate();
|
||||
|
||||
// auto size = getFramebufferSize();
|
||||
// MBGL_CHECK_ERROR(glViewport(0, 0, size[0], size[1]));
|
||||
}
|
||||
|
||||
void afterRender() override {
|
||||
if (nativeView->_isPrinting) {
|
||||
nativeView->_isPrinting = NO;
|
||||
std::string png = encodePNG(readStillImage());
|
||||
NSData *data = [[NSData alloc] initWithBytes:png.data() length:png.size()];
|
||||
NSImage *image = [[NSImage alloc] initWithData:data];
|
||||
[nativeView performSelectorOnMainThread:@selector(printWithImage:)
|
||||
withObject:image
|
||||
waitUntilDone:NO];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
mbgl::PremultipliedImage readStillImage() override {
|
||||
auto size = getFramebufferSize();
|
||||
const unsigned int w = size[0];
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include <mbgl/layer/custom_layer.hpp>
|
||||
|
||||
#include <mbgl/util/projection.hpp>
|
||||
#include <mbgl/util/thread.hpp>
|
||||
#include <mbgl/util/math.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
@@ -20,46 +19,24 @@ namespace mbgl {
|
||||
Map::Map(View& view_, FileSource& fileSource, MapMode mapMode, GLContextMode contextMode, ConstrainMode constrainMode)
|
||||
: view(view_),
|
||||
transform(std::make_unique<Transform>(view, constrainMode)),
|
||||
context(std::make_unique<util::Thread<MapContext>>(
|
||||
util::ThreadContext{"Map", util::ThreadType::Map, util::ThreadPriority::Regular},
|
||||
context(std::make_unique<MapContext>(
|
||||
view, fileSource, mapMode, contextMode, view.getPixelRatio())),
|
||||
data(&context->invokeSync<MapData&>(&MapContext::getData))
|
||||
data(&context->getData())
|
||||
{
|
||||
view.initialize(this);
|
||||
update(Update::Dimensions);
|
||||
}
|
||||
|
||||
Map::~Map() {
|
||||
resume();
|
||||
context->invokeSync(&MapContext::cleanup);
|
||||
}
|
||||
|
||||
void Map::pause() {
|
||||
assert(data->mode == MapMode::Continuous);
|
||||
|
||||
std::unique_lock<std::mutex> lockPause(data->mutexPause);
|
||||
if (!data->paused) {
|
||||
context->invoke(&MapContext::pause);
|
||||
data->condPause.wait(lockPause, [&]{ return data->paused; });
|
||||
}
|
||||
}
|
||||
|
||||
bool Map::isPaused() {
|
||||
return data->paused;
|
||||
}
|
||||
|
||||
void Map::resume() {
|
||||
std::unique_lock<std::mutex> lockPause(data->mutexPause);
|
||||
data->paused = false;
|
||||
data->condPause.notify_all();
|
||||
context->cleanup();
|
||||
}
|
||||
|
||||
void Map::renderStill(StillImageCallback callback) {
|
||||
context->invoke(&MapContext::renderStill, transform->getState(),
|
||||
context->renderStill(transform->getState(),
|
||||
FrameData { view.getFramebufferSize(), Clock::now() }, callback);
|
||||
}
|
||||
|
||||
void Map::renderSync() {
|
||||
void Map::render() {
|
||||
if (renderState == RenderState::never) {
|
||||
view.notifyMapChange(MapChangeWillStartRenderingMap);
|
||||
}
|
||||
@@ -67,8 +44,7 @@ void Map::renderSync() {
|
||||
view.notifyMapChange(MapChangeWillStartRenderingFrame);
|
||||
|
||||
const Update flags = transform->updateTransitions(Clock::now());
|
||||
const bool fullyLoaded = context->invokeSync<bool>(
|
||||
&MapContext::renderSync, transform->getState(), FrameData { view.getFramebufferSize(), Clock::now() });
|
||||
const bool fullyLoaded = context->renderSync(transform->getState(), FrameData { view.getFramebufferSize(), Clock::now() });
|
||||
|
||||
view.notifyMapChange(fullyLoaded ?
|
||||
MapChangeDidFinishRenderingFrameFullyRendered :
|
||||
@@ -94,7 +70,7 @@ void Map::renderSync() {
|
||||
|
||||
void Map::update(Update flags) {
|
||||
if (flags & Update::Dimensions) transform->resize(view.getSize());
|
||||
context->invoke(&MapContext::triggerUpdate, transform->getState(), flags);
|
||||
context->triggerUpdate(transform->getState(), flags);
|
||||
}
|
||||
|
||||
#pragma mark - Style
|
||||
@@ -102,21 +78,21 @@ void Map::update(Update flags) {
|
||||
void Map::setStyleURL(const std::string &url) {
|
||||
loading = true;
|
||||
view.notifyMapChange(MapChangeWillStartLoadingMap);
|
||||
context->invoke(&MapContext::setStyleURL, url);
|
||||
context->setStyleURL(url);
|
||||
}
|
||||
|
||||
void Map::setStyleJSON(const std::string& json, const std::string& base) {
|
||||
loading = true;
|
||||
view.notifyMapChange(MapChangeWillStartLoadingMap);
|
||||
context->invoke(&MapContext::setStyleJSON, json, base);
|
||||
context->setStyleJSON(json, base);
|
||||
}
|
||||
|
||||
std::string Map::getStyleURL() const {
|
||||
return context->invokeSync<std::string>(&MapContext::getStyleURL);
|
||||
return context->getStyleURL();
|
||||
}
|
||||
|
||||
std::string Map::getStyleJSON() const {
|
||||
return context->invokeSync<std::string>(&MapContext::getStyleJSON);
|
||||
return context->getStyleJSON();
|
||||
}
|
||||
|
||||
#pragma mark - Transitions
|
||||
@@ -436,15 +412,15 @@ LatLng Map::latLngForPixel(const ScreenCoordinate& pixel) const {
|
||||
#pragma mark - Annotations
|
||||
|
||||
void Map::addAnnotationIcon(const std::string& name, std::shared_ptr<const SpriteImage> sprite) {
|
||||
context->invoke(&MapContext::addAnnotationIcon, name, sprite);
|
||||
context->addAnnotationIcon(name, sprite);
|
||||
}
|
||||
|
||||
void Map::removeAnnotationIcon(const std::string& name) {
|
||||
context->invoke(&MapContext::removeAnnotationIcon, name);
|
||||
context->removeAnnotationIcon(name);
|
||||
}
|
||||
|
||||
double Map::getTopOffsetPixelsForAnnotationIcon(const std::string& symbol) {
|
||||
return context->invokeSync<double>(&MapContext::getTopOffsetPixelsForAnnotationIcon, symbol);
|
||||
return context->getTopOffsetPixelsForAnnotationIcon(symbol);
|
||||
}
|
||||
|
||||
AnnotationID Map::addPointAnnotation(const PointAnnotation& annotation) {
|
||||
@@ -489,17 +465,21 @@ AnnotationIDs Map::getPointAnnotationsInBounds(const LatLngBounds& bounds) {
|
||||
|
||||
void Map::addCustomLayer(const std::string& id,
|
||||
CustomLayerInitializeFunction initialize,
|
||||
CustomLayerRenderFunction render,
|
||||
CustomLayerRenderFunction render_,
|
||||
CustomLayerDeinitializeFunction deinitialize,
|
||||
void* context_,
|
||||
const char* before) {
|
||||
context->invoke(&MapContext::addLayer,
|
||||
std::make_unique<CustomLayer>(id, initialize, render, deinitialize, context_),
|
||||
view.activate();
|
||||
context->addLayer(
|
||||
std::make_unique<CustomLayer>(id, initialize, render_, deinitialize, context_),
|
||||
before ? std::string(before) : optional<std::string>());
|
||||
view.deactivate();
|
||||
}
|
||||
|
||||
void Map::removeCustomLayer(const std::string& id) {
|
||||
context->invoke(&MapContext::removeLayer, id);
|
||||
view.activate();
|
||||
context->removeLayer(id);
|
||||
view.deactivate();
|
||||
}
|
||||
|
||||
#pragma mark - Toggles
|
||||
@@ -519,39 +499,39 @@ MapDebugOptions Map::getDebug() const {
|
||||
}
|
||||
|
||||
bool Map::isFullyLoaded() const {
|
||||
return context->invokeSync<bool>(&MapContext::isLoaded);
|
||||
return context->isLoaded();
|
||||
}
|
||||
|
||||
void Map::addClass(const std::string& className, const PropertyTransition& properties) {
|
||||
context->invoke(&MapContext::addClass, className, properties);
|
||||
context->addClass(className, properties);
|
||||
}
|
||||
|
||||
void Map::removeClass(const std::string& className, const PropertyTransition& properties) {
|
||||
context->invoke(&MapContext::removeClass, className, properties);
|
||||
context->removeClass(className, properties);
|
||||
}
|
||||
|
||||
void Map::setClasses(const std::vector<std::string>& classNames, const PropertyTransition& properties) {
|
||||
context->invoke(&MapContext::setClasses, classNames, properties);
|
||||
context->setClasses(classNames, properties);
|
||||
}
|
||||
|
||||
bool Map::hasClass(const std::string& className) const {
|
||||
return context->invokeSync<bool>(&MapContext::hasClass, className);
|
||||
return context->hasClass(className);
|
||||
}
|
||||
|
||||
std::vector<std::string> Map::getClasses() const {
|
||||
return context->invokeSync<std::vector<std::string>>(&MapContext::getClasses);
|
||||
return context->getClasses();
|
||||
}
|
||||
|
||||
void Map::setSourceTileCacheSize(size_t size) {
|
||||
context->invoke(&MapContext::setSourceTileCacheSize, size);
|
||||
context->setSourceTileCacheSize(size);
|
||||
}
|
||||
|
||||
void Map::onLowMemory() {
|
||||
context->invoke(&MapContext::onLowMemory);
|
||||
context->onLowMemory();
|
||||
}
|
||||
|
||||
void Map::dumpDebugLogs() const {
|
||||
context->invokeSync(&MapContext::dumpDebugLogs);
|
||||
context->dumpDebugLogs();
|
||||
}
|
||||
|
||||
} // namespace mbgl
|
||||
|
||||
@@ -35,11 +35,7 @@ MapContext::MapContext(View& view_, FileSource& fileSource_, MapMode mode_, GLCo
|
||||
dataPtr(std::make_unique<MapData>(mode_, contextMode_, pixelRatio_)),
|
||||
data(*dataPtr),
|
||||
asyncUpdate([this] { update(); }),
|
||||
asyncInvalidate([&view_] { view_.invalidate(); }),
|
||||
texturePool(std::make_unique<gl::TexturePool>()) {
|
||||
assert(util::ThreadContext::currentlyOn(util::ThreadType::Map));
|
||||
|
||||
view.activate();
|
||||
}
|
||||
|
||||
MapContext::~MapContext() {
|
||||
@@ -48,7 +44,7 @@ MapContext::~MapContext() {
|
||||
}
|
||||
|
||||
void MapContext::cleanup() {
|
||||
view.notify();
|
||||
view.activate();
|
||||
|
||||
styleRequest = nullptr;
|
||||
|
||||
@@ -64,21 +60,6 @@ void MapContext::cleanup() {
|
||||
view.deactivate();
|
||||
}
|
||||
|
||||
void MapContext::pause() {
|
||||
MBGL_CHECK_ERROR(glFinish());
|
||||
|
||||
view.deactivate();
|
||||
|
||||
std::unique_lock<std::mutex> lockPause(data.mutexPause);
|
||||
data.paused = true;
|
||||
data.condPause.notify_all();
|
||||
data.condPause.wait(lockPause, [&]{ return !data.paused; });
|
||||
|
||||
view.activate();
|
||||
|
||||
asyncInvalidate.send();
|
||||
}
|
||||
|
||||
void MapContext::updateAsync(Update flags) {
|
||||
updateFlags |= flags;
|
||||
asyncUpdate.send();
|
||||
@@ -180,9 +161,11 @@ void MapContext::update() {
|
||||
style->update(transformState, frameData.timePoint, *texturePool);
|
||||
|
||||
if (data.mode == MapMode::Continuous) {
|
||||
asyncInvalidate.send();
|
||||
view.invalidate();
|
||||
} else if (callback && isLoaded()) {
|
||||
view.activate();
|
||||
renderSync(transformState, frameData);
|
||||
view.deactivate();
|
||||
}
|
||||
|
||||
updateFlags = Update::Nothing;
|
||||
@@ -229,8 +212,6 @@ bool MapContext::renderSync(const TransformState& state, const FrameData& frame)
|
||||
return false;
|
||||
}
|
||||
|
||||
view.beforeRender();
|
||||
|
||||
transformState = state;
|
||||
frameData = frame;
|
||||
|
||||
@@ -245,8 +226,6 @@ bool MapContext::renderSync(const TransformState& state, const FrameData& frame)
|
||||
// Cleanup OpenGL objects that we abandoned since the last render call.
|
||||
glObjectStore.performCleanup();
|
||||
|
||||
view.afterRender();
|
||||
|
||||
if (style->hasTransitions()) {
|
||||
updateAsync(Update::RecalculateStyle);
|
||||
} else if (painter->needsAnimation()) {
|
||||
@@ -312,7 +291,7 @@ void MapContext::setSourceTileCacheSize(size_t size) {
|
||||
sourceCacheSize = size;
|
||||
if (!style) return;
|
||||
style->setSourceTileCacheSize(size);
|
||||
asyncInvalidate.send();
|
||||
view.invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -320,7 +299,7 @@ void MapContext::onLowMemory() {
|
||||
assert(util::ThreadContext::currentlyOn(util::ThreadType::Map));
|
||||
if (!style) return;
|
||||
style->onLowMemory();
|
||||
asyncInvalidate.send();
|
||||
view.invalidate();
|
||||
}
|
||||
|
||||
void MapContext::onResourceLoaded() {
|
||||
|
||||
@@ -37,8 +37,6 @@ public:
|
||||
|
||||
MapData& getData() { return data; }
|
||||
|
||||
void pause();
|
||||
|
||||
void triggerUpdate(const TransformState&, Update = Update::Nothing);
|
||||
void renderStill(const TransformState&, const FrameData&, Map::StillImageCallback callback);
|
||||
|
||||
@@ -97,7 +95,6 @@ private:
|
||||
|
||||
Update updateFlags = Update::Nothing;
|
||||
util::AsyncTask asyncUpdate;
|
||||
util::AsyncTask asyncInvalidate;
|
||||
|
||||
std::unique_ptr<gl::TexturePool> texturePool;
|
||||
std::unique_ptr<Painter> painter;
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
#ifndef MBGL_MAP_MAP_DATA
|
||||
#define MBGL_MAP_MAP_DATA
|
||||
|
||||
#include <mutex>
|
||||
#include <atomic>
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
#include <condition_variable>
|
||||
|
||||
#include <mbgl/map/mode.hpp>
|
||||
#include <mbgl/annotation/annotation_manager.hpp>
|
||||
@@ -14,8 +11,6 @@
|
||||
namespace mbgl {
|
||||
|
||||
class MapData {
|
||||
using Lock = std::lock_guard<std::mutex>;
|
||||
|
||||
public:
|
||||
inline MapData(MapMode mode_, GLContextMode contextMode_, const float pixelRatio_)
|
||||
: mode(mode_)
|
||||
@@ -46,10 +41,8 @@ public:
|
||||
debugOptions = debugOptions_;
|
||||
}
|
||||
|
||||
util::exclusive<AnnotationManager> getAnnotationManager() {
|
||||
return util::exclusive<AnnotationManager>(
|
||||
&annotationManager,
|
||||
std::make_unique<std::lock_guard<std::mutex>>(annotationManagerMutex));
|
||||
AnnotationManager* getAnnotationManager() {
|
||||
return &annotationManager;
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -58,16 +51,12 @@ public:
|
||||
const float pixelRatio;
|
||||
|
||||
private:
|
||||
mutable std::mutex annotationManagerMutex;
|
||||
AnnotationManager annotationManager;
|
||||
|
||||
std::atomic<MapDebugOptions> debugOptions { MapDebugOptions::NoDebug };
|
||||
MapDebugOptions debugOptions { MapDebugOptions::NoDebug };
|
||||
|
||||
// TODO: make private
|
||||
public:
|
||||
bool paused = false;
|
||||
std::mutex mutexPause;
|
||||
std::condition_variable condPause;
|
||||
};
|
||||
|
||||
} // namespace mbgl
|
||||
|
||||
@@ -15,7 +15,7 @@ enum class ThreadPriority : bool {
|
||||
|
||||
enum class ThreadType : uint8_t {
|
||||
Main,
|
||||
Map,
|
||||
Map = Main,
|
||||
Worker,
|
||||
Unknown,
|
||||
};
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <mbgl/platform/default/headless_view.hpp>
|
||||
#include <mbgl/storage/online_file_source.hpp>
|
||||
#include <mbgl/util/io.hpp>
|
||||
#include <mbgl/util/run_loop.hpp>
|
||||
|
||||
#include <future>
|
||||
#include <vector>
|
||||
@@ -29,6 +30,8 @@ void checkRendering(Map& map, const char * name) {
|
||||
} // end namespace
|
||||
|
||||
TEST(Annotations, PointAnnotation) {
|
||||
util::RunLoop loop;
|
||||
|
||||
auto display = std::make_shared<mbgl::HeadlessDisplay>();
|
||||
HeadlessView view(display, 1);
|
||||
OnlineFileSource fileSource;
|
||||
@@ -42,6 +45,8 @@ TEST(Annotations, PointAnnotation) {
|
||||
}
|
||||
|
||||
TEST(Annotations, LineAnnotation) {
|
||||
util::RunLoop loop;
|
||||
|
||||
auto display = std::make_shared<mbgl::HeadlessDisplay>();
|
||||
HeadlessView view(display, 1);
|
||||
OnlineFileSource fileSource;
|
||||
@@ -61,6 +66,8 @@ TEST(Annotations, LineAnnotation) {
|
||||
}
|
||||
|
||||
TEST(Annotations, FillAnnotation) {
|
||||
util::RunLoop loop;
|
||||
|
||||
auto display = std::make_shared<mbgl::HeadlessDisplay>();
|
||||
HeadlessView view(display, 1);
|
||||
OnlineFileSource fileSource;
|
||||
@@ -79,6 +86,8 @@ TEST(Annotations, FillAnnotation) {
|
||||
}
|
||||
|
||||
TEST(Annotations, StyleSourcedShapeAnnotation) {
|
||||
util::RunLoop loop;
|
||||
|
||||
auto display = std::make_shared<mbgl::HeadlessDisplay>();
|
||||
HeadlessView view(display, 1);
|
||||
OnlineFileSource fileSource;
|
||||
@@ -94,6 +103,8 @@ TEST(Annotations, StyleSourcedShapeAnnotation) {
|
||||
}
|
||||
|
||||
TEST(Annotations, AddMultiple) {
|
||||
util::RunLoop loop;
|
||||
|
||||
auto display = std::make_shared<mbgl::HeadlessDisplay>();
|
||||
HeadlessView view(display, 1);
|
||||
OnlineFileSource fileSource;
|
||||
@@ -111,6 +122,8 @@ TEST(Annotations, AddMultiple) {
|
||||
}
|
||||
|
||||
TEST(Annotations, NonImmediateAdd) {
|
||||
util::RunLoop loop;
|
||||
|
||||
auto display = std::make_shared<mbgl::HeadlessDisplay>();
|
||||
HeadlessView view(display, 1);
|
||||
OnlineFileSource fileSource;
|
||||
@@ -131,6 +144,8 @@ TEST(Annotations, NonImmediateAdd) {
|
||||
}
|
||||
|
||||
TEST(Annotations, UpdateIcon) {
|
||||
util::RunLoop loop;
|
||||
|
||||
auto display = std::make_shared<mbgl::HeadlessDisplay>();
|
||||
HeadlessView view(display, 1);
|
||||
OnlineFileSource fileSource;
|
||||
@@ -150,6 +165,8 @@ TEST(Annotations, UpdateIcon) {
|
||||
}
|
||||
|
||||
TEST(Annotations, UpdatePoint) {
|
||||
util::RunLoop loop;
|
||||
|
||||
auto display = std::make_shared<mbgl::HeadlessDisplay>();
|
||||
HeadlessView view(display, 1);
|
||||
OnlineFileSource fileSource;
|
||||
@@ -168,6 +185,8 @@ TEST(Annotations, UpdatePoint) {
|
||||
}
|
||||
|
||||
TEST(Annotations, RemovePoint) {
|
||||
util::RunLoop loop;
|
||||
|
||||
auto display = std::make_shared<mbgl::HeadlessDisplay>();
|
||||
HeadlessView view(display, 1);
|
||||
OnlineFileSource fileSource;
|
||||
@@ -185,6 +204,8 @@ TEST(Annotations, RemovePoint) {
|
||||
}
|
||||
|
||||
TEST(Annotations, RemoveShape) {
|
||||
util::RunLoop loop;
|
||||
|
||||
auto display = std::make_shared<mbgl::HeadlessDisplay>();
|
||||
HeadlessView view(display, 1);
|
||||
OnlineFileSource fileSource;
|
||||
@@ -207,6 +228,8 @@ TEST(Annotations, RemoveShape) {
|
||||
}
|
||||
|
||||
TEST(Annotations, ImmediateRemoveShape) {
|
||||
util::RunLoop loop;
|
||||
|
||||
auto display = std::make_shared<mbgl::HeadlessDisplay>();
|
||||
HeadlessView view(display, 1);
|
||||
OnlineFileSource fileSource;
|
||||
@@ -219,6 +242,8 @@ TEST(Annotations, ImmediateRemoveShape) {
|
||||
}
|
||||
|
||||
TEST(Annotations, SwitchStyle) {
|
||||
util::RunLoop loop;
|
||||
|
||||
auto display = std::make_shared<mbgl::HeadlessDisplay>();
|
||||
HeadlessView view(display, 1);
|
||||
OnlineFileSource fileSource;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <mbgl/platform/default/headless_view.hpp>
|
||||
#include <mbgl/storage/online_file_source.hpp>
|
||||
#include <mbgl/util/exception.hpp>
|
||||
#include <mbgl/util/run_loop.hpp>
|
||||
|
||||
#include <future>
|
||||
|
||||
@@ -15,6 +16,8 @@ TEST(API, RenderWithoutCallback) {
|
||||
FixtureLogObserver* log = new FixtureLogObserver();
|
||||
Log::setObserver(std::unique_ptr<Log::Observer>(log));
|
||||
|
||||
util::RunLoop loop;
|
||||
|
||||
auto display = std::make_shared<mbgl::HeadlessDisplay>();
|
||||
HeadlessView view(display, 1);
|
||||
view.resize(128, 512);
|
||||
@@ -37,6 +40,8 @@ TEST(API, RenderWithoutCallback) {
|
||||
}
|
||||
|
||||
TEST(API, RenderWithoutStyle) {
|
||||
util::RunLoop loop;
|
||||
|
||||
auto display = std::make_shared<mbgl::HeadlessDisplay>();
|
||||
HeadlessView view(display, 1);
|
||||
view.resize(128, 512);
|
||||
@@ -44,13 +49,16 @@ TEST(API, RenderWithoutStyle) {
|
||||
|
||||
Map map(view, fileSource, MapMode::Still);
|
||||
|
||||
std::promise<std::exception_ptr> promise;
|
||||
map.renderStill([&promise](std::exception_ptr error, PremultipliedImage&&) {
|
||||
promise.set_value(error);
|
||||
std::exception_ptr error;
|
||||
map.renderStill([&](std::exception_ptr error_, PremultipliedImage&&) {
|
||||
error = error_;
|
||||
loop.stop();
|
||||
});
|
||||
|
||||
loop.run();
|
||||
|
||||
try {
|
||||
std::rethrow_exception(promise.get_future().get());
|
||||
std::rethrow_exception(error);
|
||||
} catch (const util::MisuseException& ex) {
|
||||
EXPECT_EQ(std::string(ex.what()), "Map doesn't have a style");
|
||||
} catch (const std::exception&) {
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <mbgl/layer/custom_layer.hpp>
|
||||
#include <mbgl/util/io.hpp>
|
||||
#include <mbgl/util/mat4.hpp>
|
||||
#include <mbgl/util/run_loop.hpp>
|
||||
|
||||
using namespace mbgl;
|
||||
|
||||
@@ -68,6 +69,8 @@ public:
|
||||
};
|
||||
|
||||
TEST(CustomLayer, Basic) {
|
||||
util::RunLoop loop;
|
||||
|
||||
auto display = std::make_shared<mbgl::HeadlessDisplay>();
|
||||
HeadlessView view(display, 1);
|
||||
OnlineFileSource fileSource;
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <mbgl/storage/default_file_source.hpp>
|
||||
#include <mbgl/util/image.hpp>
|
||||
#include <mbgl/util/io.hpp>
|
||||
#include <mbgl/util/run_loop.hpp>
|
||||
|
||||
#include <future>
|
||||
|
||||
@@ -19,6 +20,8 @@
|
||||
TEST(API, TEST_REQUIRES_SERVER(RenderMissingTile)) {
|
||||
using namespace mbgl;
|
||||
|
||||
util::RunLoop loop;
|
||||
|
||||
const auto style = util::read_file("test/fixtures/api/water_missing_tiles.json");
|
||||
|
||||
auto display = std::make_shared<mbgl::HeadlessDisplay>();
|
||||
@@ -38,8 +41,7 @@ TEST(API, TEST_REQUIRES_SERVER(RenderMissingTile)) {
|
||||
|
||||
// This host does not respond (== connection error).
|
||||
map.setStyleJSON(style, "");
|
||||
std::promise<void> promise;
|
||||
map.renderStill([&promise, &message](std::exception_ptr err, PremultipliedImage&&) {
|
||||
map.renderStill([&](std::exception_ptr err, PremultipliedImage&&) {
|
||||
ASSERT_TRUE(err.operator bool());
|
||||
try {
|
||||
std::rethrow_exception(err);
|
||||
@@ -47,9 +49,10 @@ TEST(API, TEST_REQUIRES_SERVER(RenderMissingTile)) {
|
||||
message = ex.what();
|
||||
EXPECT_TRUE(message.find("connect") != std::string::npos);
|
||||
}
|
||||
promise.set_value();
|
||||
loop.stop();
|
||||
});
|
||||
promise.get_future().get();
|
||||
|
||||
loop.run();
|
||||
|
||||
auto observer = Log::removeObserver();
|
||||
auto flo = dynamic_cast<FixtureLogObserver*>(observer.get());
|
||||
|
||||
@@ -7,12 +7,15 @@
|
||||
#include <mbgl/storage/default_file_source.hpp>
|
||||
#include <mbgl/util/image.hpp>
|
||||
#include <mbgl/util/io.hpp>
|
||||
#include <mbgl/util/run_loop.hpp>
|
||||
|
||||
#include <future>
|
||||
|
||||
TEST(API, RepeatedRender) {
|
||||
using namespace mbgl;
|
||||
|
||||
util::RunLoop loop;
|
||||
|
||||
const auto style = util::read_file("test/fixtures/api/water.json");
|
||||
|
||||
auto display = std::make_shared<mbgl::HeadlessDisplay>();
|
||||
@@ -30,11 +33,15 @@ TEST(API, RepeatedRender) {
|
||||
|
||||
{
|
||||
map.setStyleJSON(style, "");
|
||||
std::promise<PremultipliedImage> promise;
|
||||
map.renderStill([&promise](std::exception_ptr, PremultipliedImage&& image) {
|
||||
promise.set_value(std::move(image));
|
||||
PremultipliedImage result;
|
||||
map.renderStill([&result](std::exception_ptr, PremultipliedImage&& image) {
|
||||
result = std::move(image);
|
||||
});
|
||||
auto result = promise.get_future().get();
|
||||
|
||||
while (!result.size()) {
|
||||
loop.runOnce();
|
||||
}
|
||||
|
||||
ASSERT_EQ(256, result.width);
|
||||
ASSERT_EQ(512, result.height);
|
||||
#if !TEST_READ_ONLY
|
||||
@@ -44,11 +51,15 @@ TEST(API, RepeatedRender) {
|
||||
|
||||
{
|
||||
map.setStyleJSON(style, "");
|
||||
std::promise<PremultipliedImage> promise;
|
||||
map.renderStill([&promise](std::exception_ptr, PremultipliedImage&& image) {
|
||||
promise.set_value(std::move(image));
|
||||
PremultipliedImage result;
|
||||
map.renderStill([&result](std::exception_ptr, PremultipliedImage&& image) {
|
||||
result = std::move(image);
|
||||
});
|
||||
auto result = promise.get_future().get();
|
||||
|
||||
while (!result.size()) {
|
||||
loop.runOnce();
|
||||
}
|
||||
|
||||
ASSERT_EQ(256, result.width);
|
||||
ASSERT_EQ(512, result.height);
|
||||
#if !TEST_READ_ONLY
|
||||
|
||||
@@ -5,11 +5,14 @@
|
||||
#include <mbgl/platform/default/headless_view.hpp>
|
||||
#include <mbgl/platform/default/headless_display.hpp>
|
||||
#include <mbgl/storage/online_file_source.hpp>
|
||||
#include <mbgl/util/run_loop.hpp>
|
||||
|
||||
|
||||
TEST(API, SetStyle) {
|
||||
using namespace mbgl;
|
||||
|
||||
util::RunLoop loop;
|
||||
|
||||
auto display = std::make_shared<mbgl::HeadlessDisplay>();
|
||||
HeadlessView view(display, 1);
|
||||
OnlineFileSource fileSource;
|
||||
|
||||
@@ -3,59 +3,17 @@
|
||||
#include <mbgl/map/map.hpp>
|
||||
#include <mbgl/platform/default/headless_view.hpp>
|
||||
#include <mbgl/platform/default/headless_display.hpp>
|
||||
#include <mbgl/storage/online_file_source.hpp>
|
||||
#include <mbgl/storage/network_status.hpp>
|
||||
#include <mbgl/storage/offline_database.hpp>
|
||||
#include <mbgl/storage/default_file_source.hpp>
|
||||
#include <mbgl/util/io.hpp>
|
||||
#include <mbgl/util/run_loop.hpp>
|
||||
|
||||
using namespace mbgl;
|
||||
using namespace std::literals::string_literals;
|
||||
|
||||
TEST(Map, PauseResume) {
|
||||
auto display = std::make_shared<mbgl::HeadlessDisplay>();
|
||||
HeadlessView view(display, 1);
|
||||
OnlineFileSource fileSource;
|
||||
|
||||
Map map(view, fileSource, MapMode::Continuous);
|
||||
|
||||
map.pause();
|
||||
map.resume();
|
||||
}
|
||||
|
||||
TEST(Map, DoublePause) {
|
||||
auto display = std::make_shared<mbgl::HeadlessDisplay>();
|
||||
HeadlessView view(display, 1);
|
||||
OnlineFileSource fileSource;
|
||||
|
||||
Map map(view, fileSource, MapMode::Continuous);
|
||||
|
||||
map.pause();
|
||||
map.pause();
|
||||
map.resume();
|
||||
}
|
||||
|
||||
TEST(Map, ResumeWithoutPause) {
|
||||
auto display = std::make_shared<mbgl::HeadlessDisplay>();
|
||||
HeadlessView view(display, 1);
|
||||
OnlineFileSource fileSource;
|
||||
|
||||
Map map(view, fileSource, MapMode::Continuous);
|
||||
|
||||
map.resume();
|
||||
}
|
||||
|
||||
TEST(Map, DestroyPaused) {
|
||||
auto display = std::make_shared<mbgl::HeadlessDisplay>();
|
||||
HeadlessView view(display, 1);
|
||||
OnlineFileSource fileSource;
|
||||
|
||||
Map map(view, fileSource, MapMode::Continuous);
|
||||
|
||||
map.pause();
|
||||
}
|
||||
|
||||
TEST(Map, Offline) {
|
||||
util::RunLoop runLoop;
|
||||
|
||||
auto display = std::make_shared<mbgl::HeadlessDisplay>();
|
||||
HeadlessView view(display, 1);
|
||||
DefaultFileSource fileSource(":memory:", ".");
|
||||
|
||||
@@ -18,10 +18,7 @@ public:
|
||||
|
||||
void activate() override {};
|
||||
void deactivate() override {};
|
||||
void notify() override {};
|
||||
void invalidate() override {}
|
||||
void beforeRender() override {}
|
||||
void afterRender() override {}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <mbgl/util/image.hpp>
|
||||
#include <mbgl/util/io.hpp>
|
||||
#include <mbgl/util/chrono.hpp>
|
||||
#include <mbgl/util/run_loop.hpp>
|
||||
|
||||
#include <mapbox/pixelmatch.hpp>
|
||||
|
||||
@@ -86,11 +87,16 @@ Server::~Server() {
|
||||
}
|
||||
|
||||
PremultipliedImage render(Map& map) {
|
||||
std::promise<PremultipliedImage> promise;
|
||||
map.renderStill([&](std::exception_ptr, PremultipliedImage&& image) {
|
||||
promise.set_value(std::move(image));
|
||||
PremultipliedImage result;
|
||||
map.renderStill([&result](std::exception_ptr, PremultipliedImage&& image) {
|
||||
result = std::move(image);
|
||||
});
|
||||
return promise.get_future().get();
|
||||
|
||||
while (!result.size()) {
|
||||
util::RunLoop::Get()->runOnce();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void checkImage(const std::string& base,
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
|
||||
'geometry/binpack.cpp',
|
||||
|
||||
'map/map.cpp',
|
||||
'map/map_context.cpp',
|
||||
'map/tile.cpp',
|
||||
'map/transform.cpp',
|
||||
|
||||
Reference in New Issue
Block a user