drive map rendering from main thread

This commit is contained in:
Konstantin Käfer
2015-05-22 15:56:05 +02:00
committed by John Firebaugh
parent 740281cc89
commit 84e2ea886d
14 changed files with 71 additions and 35 deletions

View File

@@ -124,12 +124,16 @@ void NativeMapView::deactivate() {
}
}
void NativeMapView::invalidate(std::function<void()> render) {
void NativeMapView::invalidate() {
mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::invalidate");
// TODO: inform the main thread that it must call map->renderSync();
}
void NativeMapView::swap() {
mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::invalidate");
if ((display != EGL_NO_DISPLAY) && (surface != EGL_NO_SURFACE)) {
render();
if (!eglSwapBuffers(display, surface)) {
mbgl::Log::Error(mbgl::Event::OpenGL, "eglSwapBuffers() returned error %d",
eglGetError());

View File

@@ -23,7 +23,8 @@ public:
void activate() override;
void deactivate() override;
void notify() override;
void invalidate(std::function<void()> render) override;
void invalidate() override;
void swap() override;
void notifyMapChange(mbgl::MapChange change, Duration delay = Duration::zero()) override;

View File

@@ -44,9 +44,11 @@ public:
virtual void resize(uint16_t width, uint16_t height, float pixelRatio);
// Called from the render thread. The implementation must trigger a rerender.
// (i.e. either the passed render() function for rendering immediately on the map thread,
// or map->renderSync() from the main thread must be called as a result of this)
virtual void invalidate(std::function<void()> render) = 0;
// (map->renderSync() from the main thread must be called as a result of this)
virtual void invalidate() = 0;
// Called from the render thread after the render is complete.
virtual void swap() = 0;
// Reads the pixel data from the current framebuffer. If your View implementation
// doesn't support reading from the framebuffer, return a null pointer.

View File

@@ -8,6 +8,8 @@
#endif
#include <GLFW/glfw3.h>
#include <atomic>
class GLFWView : public mbgl::View {
public:
GLFWView(bool fullscreen = false);
@@ -17,7 +19,8 @@ public:
void activate() override;
void deactivate() override;
void notify() override;
void invalidate(std::function<void()> render) override;
void invalidate() override;
void swap() override;
static void onKey(GLFWwindow *window, int key, int scancode, int action, int mods);
static void onScroll(GLFWwindow *window, double xoffset, double yoffset);
@@ -62,6 +65,7 @@ private:
std::function<void()> changeStyleCallback;
GLFWwindow *window = nullptr;
std::atomic_flag clean = ATOMIC_FLAG_INIT;
};
#endif

View File

@@ -33,7 +33,8 @@ public:
void deactivate() override;
void notify() override;
void resize(uint16_t width, uint16_t height, float pixelRatio) override;
void invalidate(std::function<void()> render) override;
void invalidate() override;
void swap() override;
std::unique_ptr<StillImage> readStillImage() override;
private:

View File

@@ -282,6 +282,10 @@ void GLFWView::onMouseMove(GLFWwindow *window, double x, double y) {
void GLFWView::run() {
while (!glfwWindowShouldClose(window)) {
glfwWaitEvents();
const bool dirty = !clean.test_and_set();
if (dirty) {
map->renderSync();
}
}
}
@@ -297,8 +301,12 @@ void GLFWView::notify() {
glfwPostEmptyEvent();
}
void GLFWView::invalidate(std::function<void()> render) {
render();
void GLFWView::invalidate() {
clean.clear();
glfwPostEmptyEvent();
}
void GLFWView::swap() {
glfwSwapBuffers(window);
fps();
}

View File

@@ -280,8 +280,12 @@ void HeadlessView::deactivate() {
#endif
}
void HeadlessView::invalidate(std::function<void()> render) {
render();
void HeadlessView::invalidate() {
// no-op
}
void HeadlessView::swap() {
// no-op
}
}

View File

@@ -2755,13 +2755,18 @@ class MBGLView : public mbgl::View
[EAGLContext setCurrentContext:nil];
}
void invalidate(std::function<void()>) override
void invalidate() override
{
[nativeView performSelectorOnMainThread:@selector(invalidate)
withObject:nil
waitUntilDone:NO];
}
void swap() override
{
// no-op
}
private:
__weak MGLMapView *nativeView = nullptr;
};

View File

@@ -43,7 +43,7 @@ void Map::renderStill(StillImageCallback callback) {
}
void Map::renderSync() {
context->invokeSync(&MapContext::render);
context->invokeSync(&MapContext::renderSync);
}
void Map::update(Update update_) {

View File

@@ -269,7 +269,11 @@ void MapContext::update() {
}
}
view.invalidate([this] { render(); });
if (mayRender) {
render();
} else {
view.invalidate();
}
}
updated = static_cast<UpdateType>(Update::Nothing);
@@ -302,9 +306,16 @@ void MapContext::renderStill(StillImageCallback fn) {
}
callback = fn;
mayRender = true;
triggerUpdate(Update::RenderStill);
}
void MapContext::renderSync() {
mayRender = true;
render();
mayRender = false;
}
void MapContext::render() {
assert(util::ThreadContext::currentlyOn(util::ThreadType::Map));
@@ -326,11 +337,15 @@ void MapContext::render() {
painter->setDebug(data.getDebug());
painter->render(*style, transformState, data.getAnimationTime());
mayRender = false;
if (data.mode == MapMode::Still) {
callback(nullptr, view.readStillImage());
callback = nullptr;
}
view.swap();
// Schedule another rerender when we definitely need a next frame.
if (data.transform.needsTransition() || style->hasTransitions()) {
triggerUpdate();
@@ -351,7 +366,7 @@ void MapContext::setSourceTileCacheSize(size_t size) {
for (const auto &source : style->sources) {
source->setCacheSize(sourceCacheSize);
}
view.invalidate([this] { render(); });
view.invalidate();
}
}
@@ -361,7 +376,7 @@ void MapContext::onLowMemory() {
for (const auto &source : style->sources) {
source->onLowMemory();
}
view.invalidate([this] { render(); });
view.invalidate();
}
void MapContext::onTileDataChanged() {

View File

@@ -34,12 +34,12 @@ public:
~MapContext();
void pause();
void render();
void resize(uint16_t width, uint16_t height, float ratio);
using StillImageCallback = std::function<void(std::exception_ptr, std::unique_ptr<const StillImage>)>;
void renderStill(StillImageCallback callback);
void renderSync();
void triggerUpdate(Update = Update::Nothing);
@@ -62,6 +62,7 @@ public:
private:
void updateTiles();
void render();
// Style-related updates.
void cascadeClasses();
@@ -88,6 +89,7 @@ private:
std::string styleURL;
std::string styleJSON;
bool mayRender = false;
StillImageCallback callback;
size_t sourceCacheSize;
TransformState transformState;

View File

@@ -1,5 +1,5 @@
#ifndef TEST_RESOURCES_MOCK_VIEW
#define TEST_RESOURCES_MOCK_VIEW
#ifndef TEST_FIXTURES_MOCK_VIEW
#define TEST_FIXTURES_MOCK_VIEW
#include <mbgl/map/view.hpp>
@@ -13,7 +13,8 @@ public:
void activate() override {};
void deactivate() override {};
void notify() override {};
void invalidate(std::function<void()>) override {};
void invalidate() override {}
void swap() override {}
};
}

View File

@@ -1,4 +1,5 @@
#include "../fixtures/util.hpp"
#include "../fixtures/mock_view.hpp"
#include <mbgl/util/run_loop.hpp>
#include <mbgl/map/map_data.hpp>
@@ -11,18 +12,6 @@
using namespace mbgl;
class MockView : public View {
public:
void activate() override {
}
void deactivate() override {
}
void notify() override {
}
void invalidate(std::function<void()>) override {
}
};
TEST(Transform, InvalidScale) {
MockView view;
Transform transform(view);

View File

@@ -1,7 +1,7 @@
#include "../fixtures/fixture_log_observer.hpp"
#include "../fixtures/util.hpp"
#include "../fixtures/mock_view.hpp"
#include "mock_file_source.hpp"
#include "mock_view.hpp"
#include <mbgl/map/map_data.hpp>
#include <mbgl/map/transform_state.hpp>