Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

Commit

Permalink
[core] Unify update and render into a single step
Browse files Browse the repository at this point in the history
Update only when, and just prior to, rendering, giving no opportunity to interleave unexpected state changes. This means that every time anything about the state is changed, we'll have to attempt a render to reflect that change. In the case of continuous rendering this has happened before this change as well, but it leaves no room for time to pass between an update and a render. In the case of still image rendering, a render call will only actually paint something to the view when all resources have been loaded.
  • Loading branch information
jfirebaugh committed Jan 6, 2017
1 parent 4617d18 commit b6894dd
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 84 deletions.
170 changes: 88 additions & 82 deletions src/mbgl/map/map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ class Map::Impl : public style::Observer {
void onStyleError() override;
void onResourceError(std::exception_ptr) override;

void update();
void render(View&);
void renderStill();

void loadStyleJSON(const std::string&);

Expand All @@ -83,7 +83,6 @@ class Map::Impl : public style::Observer {
MapDebugOptions debugOptions { MapDebugOptions::NoDebug };

Update updateFlags = Update::Nothing;
util::AsyncTask asyncUpdate;

std::unique_ptr<AnnotationManager> annotationManager;
std::unique_ptr<Painter> painter;
Expand All @@ -96,10 +95,11 @@ class Map::Impl : public style::Observer {

std::unique_ptr<AsyncRequest> styleRequest;

std::unique_ptr<StillImageRequest> stillImageRequest;
size_t sourceCacheSize;
TimePoint timePoint;
bool loading = false;

util::AsyncTask asyncInvalidate;
std::unique_ptr<StillImageRequest> stillImageRequest;
};

Map::Map(Backend& backend,
Expand Down Expand Up @@ -142,8 +142,14 @@ Map::Impl::Impl(Map& map_,
mode(mode_),
contextMode(contextMode_),
pixelRatio(pixelRatio_),
asyncUpdate([this] { update(); }),
annotationManager(std::make_unique<AnnotationManager>(pixelRatio)) {
annotationManager(std::make_unique<AnnotationManager>(pixelRatio)),
asyncInvalidate([this] {
if (mode == MapMode::Continuous) {
backend.invalidate();
} else {
renderStill();
}
}) {
}

Map::~Map() {
Expand Down Expand Up @@ -185,64 +191,37 @@ void Map::renderStill(View& view, StillImageCallback callback) {
}

impl->stillImageRequest = std::make_unique<StillImageRequest>(view, std::move(callback));
impl->updateFlags |= Update::RenderStill;
impl->asyncUpdate.send();
impl->onUpdate(Update::Repaint);
}

void Map::render(View& view) {
if (!impl->style) {
void Map::Impl::renderStill() {
if (!stillImageRequest) {
return;
}

if (impl->renderState == RenderState::Never) {
impl->backend.notifyMapChange(MapChangeWillStartRenderingMap);
}

impl->backend.notifyMapChange(MapChangeWillStartRenderingFrame);

const Update flags = impl->transform.updateTransitions(Clock::now());

impl->render(view);

impl->backend.notifyMapChange(isFullyLoaded() ?
MapChangeDidFinishRenderingFrameFullyRendered :
MapChangeDidFinishRenderingFrame);

if (!isFullyLoaded()) {
impl->renderState = RenderState::Partial;
} else if (impl->renderState != RenderState::Fully) {
impl->renderState = RenderState::Fully;
impl->backend.notifyMapChange(MapChangeDidFinishRenderingMapFullyRendered);
if (impl->loading) {
impl->loading = false;
impl->backend.notifyMapChange(MapChangeDidFinishLoadingMap);
}
}

// Triggers an asynchronous update, that eventually triggers a view
// invalidation, causing renderSync to be called again if in transition.
if (flags != Update::Nothing) {
impl->onUpdate(flags);
}
// TODO: determine whether we need activate/deactivate
BackendScope guard(backend);
render(stillImageRequest->view);
}

void Map::triggerRepaint() {
impl->backend.invalidate();
}

void Map::Impl::update() {
if (!style) {
updateFlags = Update::Nothing;
}
void Map::render(View& view) {
impl->render(view);
}

if (updateFlags == Update::Nothing || (mode == MapMode::Still && !stillImageRequest)) {
void Map::Impl::render(View& view) {
if (!style) {
return;
}

// This time point is used to:
// - Calculate style property transitions;
// - Hint style sources to notify when all its tiles are loaded;
timePoint = Clock::now();
TimePoint timePoint = Clock::now();

auto flags = transform.updateTransitions(timePoint);

updateFlags |= flags;

if (style->loaded && updateFlags & Update::AnnotationStyle) {
annotationManager->updateStyle(*style);
Expand Down Expand Up @@ -276,46 +255,74 @@ void Map::Impl::update() {

style->updateTiles(parameters);

if (mode == MapMode::Continuous) {
backend.invalidate();
} else if (stillImageRequest && style->isLoaded()) {
// TODO: determine whether we need activate/deactivate
BackendScope guard(backend);
render(stillImageRequest->view);
}

updateFlags = Update::Nothing;
}

void Map::Impl::render(View& view) {
if (!painter) {
painter = std::make_unique<Painter>(backend.getContext(), transform.getState(), pixelRatio);
}

FrameData frameData { timePoint,
pixelRatio,
mode,
contextMode,
debugOptions };
if (mode == MapMode::Continuous) {
if (renderState == RenderState::Never) {
backend.notifyMapChange(MapChangeWillStartRenderingMap);
}

backend.notifyMapChange(MapChangeWillStartRenderingFrame);

FrameData frameData { timePoint,
pixelRatio,
mode,
contextMode,
debugOptions };

painter->render(*style,
frameData,
view,
annotationManager->getSpriteAtlas());

painter->cleanup();

backend.notifyMapChange(style->isLoaded() ?
MapChangeDidFinishRenderingFrameFullyRendered :
MapChangeDidFinishRenderingFrame);

if (!style->isLoaded()) {
renderState = RenderState::Partial;
} else if (renderState != RenderState::Fully) {
renderState = RenderState::Fully;
backend.notifyMapChange(MapChangeDidFinishRenderingMapFullyRendered);
if (loading) {
loading = false;
backend.notifyMapChange(MapChangeDidFinishLoadingMap);
}
}

painter->render(*style,
frameData,
view,
annotationManager->getSpriteAtlas());
if (style->hasTransitions()) {
flags |= Update::RecalculateStyle;
} else if (painter->needsAnimation()) {
flags |= Update::Repaint;
}

// Only schedule an update if we need to paint another frame due to transitions or
// animations that are still in progress
if (flags != Update::Nothing) {
onUpdate(flags);
}
} else if (stillImageRequest && style->isLoaded()) {
FrameData frameData { timePoint,
pixelRatio,
mode,
contextMode,
debugOptions };

painter->render(*style,
frameData,
view,
annotationManager->getSpriteAtlas());

if (mode == MapMode::Still) {
auto request = std::move(stillImageRequest);
request->callback(nullptr);
}

painter->cleanup();

if (style->hasTransitions()) {
updateFlags |= Update::RecalculateStyle;
asyncUpdate.send();
} else if (painter->needsAnimation()) {
updateFlags |= Update::Repaint;
asyncUpdate.send();
painter->cleanup();
}
}

Expand Down Expand Up @@ -399,8 +406,7 @@ void Map::Impl::loadStyleJSON(const std::string& json) {
map.setPitch(map.getDefaultPitch());
}

updateFlags |= Update::Classes | Update::RecalculateStyle | Update::AnnotationStyle;
asyncUpdate.send();
onUpdate(Update::Classes | Update::RecalculateStyle | Update::AnnotationStyle);
}

std::string Map::getStyleURL() const {
Expand Down Expand Up @@ -1075,9 +1081,9 @@ void Map::Impl::onSourceAttributionChanged(style::Source&, const std::string&) {

void Map::Impl::onUpdate(Update flags) {
updateFlags |= flags;
asyncUpdate.send();
asyncInvalidate.send();
}

void Map::Impl::onStyleLoaded() {
backend.notifyMapChange(MapChangeDidFinishLoadingStyle);
}
Expand Down
3 changes: 1 addition & 2 deletions src/mbgl/map/update.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@ namespace mbgl {

enum class Update {
Nothing = 0,
Repaint = 1 << 0,
Classes = 1 << 2,
RecalculateStyle = 1 << 3,
RenderStill = 1 << 4,
Repaint = 1 << 5,
AnnotationStyle = 1 << 6,
AnnotationData = 1 << 7,
Layout = 1 << 8
Expand Down

0 comments on commit b6894dd

Please sign in to comment.