aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAsheem Mamoowala <asheem.mamoowala@mapbox.com>2018-11-12 14:58:13 -0800
committerAsheem Mamoowala <asheem.mamoowala@mapbox.com>2018-11-12 14:58:13 -0800
commitf2bc00267cd6430f85763beeb03b98109ff7b023 (patch)
treec589e1f6cc0759d5806af3b01a5c4d3773232deb
parent9f3cc7b7075b29595dec394733b10fbd26f274e4 (diff)
Prototype ChangeSets based approach to feature state.upstream/feature-state-changesets
- A change set keeps track of all feature state changes for a source between two render. - The change set is applied to the TilePyramid to update the full feature state map, and generate the map of update features for the single frame. The Front end renderer may throttle updates. This results in some changesets not making it to the renderer, and data in that set being dropped entirely. To workaround this the front end renderers would need to accumulate the changes, or some other way to collect all change sets between throttled frames.
-rw-r--r--include/mbgl/style/sources/geojson_source.hpp5
-rw-r--r--include/mbgl/util/feature_state.hpp19
-rw-r--r--platform/glfw/glfw_view.cpp31
-rw-r--r--platform/glfw/glfw_view.hpp1
-rw-r--r--platform/glfw/main.cpp2
-rw-r--r--src/mbgl/map/map.cpp1
-rw-r--r--src/mbgl/renderer/render_source.hpp2
-rw-r--r--src/mbgl/renderer/renderer_impl.cpp22
-rw-r--r--src/mbgl/renderer/sources/render_geojson_source.cpp46
-rw-r--r--src/mbgl/renderer/sources/render_geojson_source.hpp7
-rw-r--r--src/mbgl/renderer/tile_pyramid.cpp22
-rw-r--r--src/mbgl/renderer/tile_pyramid.hpp2
-rw-r--r--src/mbgl/renderer/update_parameters.hpp3
-rw-r--r--src/mbgl/style/sources/geojson_source.cpp17
-rw-r--r--src/mbgl/style/style_impl.cpp16
-rw-r--r--src/mbgl/style/style_impl.hpp4
16 files changed, 175 insertions, 25 deletions
diff --git a/include/mbgl/style/sources/geojson_source.hpp b/include/mbgl/style/sources/geojson_source.hpp
index a03b91027..803588ac7 100644
--- a/include/mbgl/style/sources/geojson_source.hpp
+++ b/include/mbgl/style/sources/geojson_source.hpp
@@ -2,8 +2,10 @@
#include <mbgl/style/source.hpp>
#include <mbgl/util/geojson.hpp>
+#include <mbgl/util/feature_state.hpp>
#include <mbgl/util/optional.hpp>
#include <mbgl/util/constants.hpp>
+#include <mbgl/util/immutable.hpp>
namespace mbgl {
@@ -33,6 +35,7 @@ public:
void setURL(const std::string& url);
void setGeoJSON(const GeoJSON&);
+ void setFeatureState(const FeatureIdentifier&, const std::string&, const mbgl::Value&);
optional<std::string> getURL() const;
@@ -41,9 +44,11 @@ public:
void loadDescription(FileSource&) final;
+ Immutable<std::vector<FeatureStateChange>> collectFeatureStates();
private:
optional<std::string> url;
std::unique_ptr<AsyncRequest> req;
+ Mutable<std::vector<FeatureStateChange>> stateChanges;
};
template <>
diff --git a/include/mbgl/util/feature_state.hpp b/include/mbgl/util/feature_state.hpp
index e97926c6e..f63f3dcbf 100644
--- a/include/mbgl/util/feature_state.hpp
+++ b/include/mbgl/util/feature_state.hpp
@@ -15,17 +15,32 @@ struct FeatureStateChange {
};
ChangeType type;
+ std::string sourceLayer;
FeatureIdentifier id;
std::string key;
optional<Value> value;
FeatureStateChange(ChangeType type_,
- FeatureIdentifier&& id_,
- std::string&& key_,
+ const std::string& sourceLayer_,
+ const FeatureIdentifier& id_,
+ const std::string& key_,
optional<Value> value_) :
type(type_),
+ sourceLayer(sourceLayer_),
id(std::move(id_)),
key(std::move(key_)),
value(std::move(value_)) {}
+
+ FeatureStateChange(ChangeType type_,
+ const FeatureIdentifier& id_,
+ const std::string& key_,
+ optional<Value> value_) :
+ type(type_),
+ id(std::move(id_)),
+ key(std::move(key_)),
+ value(std::move(value_)) {}
+
};
+using FeatureStateChangeSet = std::vector<FeatureStateChange>;
+
} // namespace mbgl
diff --git a/platform/glfw/glfw_view.cpp b/platform/glfw/glfw_view.cpp
index 917911313..522a0c6f6 100644
--- a/platform/glfw/glfw_view.cpp
+++ b/platform/glfw/glfw_view.cpp
@@ -15,6 +15,7 @@
#include <mbgl/renderer/renderer.hpp>
#include <mbgl/renderer/backend_scope.hpp>
#include <mbgl/map/camera.hpp>
+#include <mbgl/style/sources/geojson_source.hpp>
#include <mapbox/cheap_ruler.hpp>
#include <mapbox/geometry.hpp>
@@ -518,6 +519,35 @@ void GLFWView::onMouseMove(GLFWwindow *window, double x, double y) {
}
view->lastX = x;
view->lastY = y;
+
+ if (view->tracking || view->rotating || view->pitching) return;
+
+ mbgl::ScreenCoordinate screenCoordinate = { x, y };
+
+ std::vector<mbgl::Feature> features = view->rendererFrontend->getRenderer()->queryRenderedFeatures(screenCoordinate,{ });
+
+ if (features.empty() && !view->hoveredId) return;
+ auto pointsSource = view->map->getStyle().getSource("points");
+ if (pointsSource && pointsSource->is<mbgl::style::GeoJSONSource>()) {
+ auto gj = pointsSource->as<mbgl::style::GeoJSONSource>();
+
+ if (features.size() >= 1 && features[0].id) {
+ const auto& fId = features[0].id;
+
+ if (view->hoveredId != fId) {
+ if (view->hoveredId) {
+ gj->setFeatureState(*(view->hoveredId), "hover", false);
+ }
+ gj->setFeatureState(*(features[0].id), "hover", true);
+ view->hoveredId = features[0].id;
+ view->invalidate();
+ }
+ } else if (view->hoveredId) {
+ gj->setFeatureState(*(view->hoveredId), "hover", false);
+ view->hoveredId = mbgl::nullopt;
+ view->invalidate();
+ }
+ }
}
void GLFWView::run() {
@@ -539,7 +569,6 @@ void GLFWView::run() {
updateAnimatedAnnotations();
activate();
-
rendererFrontend->render();
glfwSwapBuffers(window);
diff --git a/platform/glfw/glfw_view.hpp b/platform/glfw/glfw_view.hpp
index d5acf697f..9a784660e 100644
--- a/platform/glfw/glfw_view.hpp
+++ b/platform/glfw/glfw_view.hpp
@@ -125,6 +125,7 @@ private:
mbgl::util::RunLoop runLoop;
mbgl::util::Timer frameTick;
+ mbgl::optional<mbgl::FeatureIdentifier> hoveredId;
GLFWwindow *window = nullptr;
bool dirty = false;
diff --git a/platform/glfw/main.cpp b/platform/glfw/main.cpp
index 1bb2e1361..a0320d405 100644
--- a/platform/glfw/main.cpp
+++ b/platform/glfw/main.cpp
@@ -107,7 +107,7 @@ int main(int argc, char *argv[]) {
fileSource.setAccessToken(std::string(token));
}
- mbgl::ThreadPool threadPool(4);
+ mbgl::ThreadPool threadPool(1);
GLFWRendererFrontend rendererFrontend { std::make_unique<mbgl::Renderer>(backend, view->getPixelRatio(), fileSource, threadPool), backend };
mbgl::Map map(rendererFrontend, backend, view->getSize(), view->getPixelRatio(), fileSource, threadPool);
diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp
index 9d886cb74..273ed1bd7 100644
--- a/src/mbgl/map/map.cpp
+++ b/src/mbgl/map/map.cpp
@@ -787,6 +787,7 @@ void Map::Impl::onUpdate() {
style->impl->getImageImpls(),
style->impl->getSourceImpls(),
style->impl->getLayerImpls(),
+ style->impl->getFeatureStateChangeSets(),
annotationManager,
prefetchZoomDelta,
bool(stillImageRequest),
diff --git a/src/mbgl/renderer/render_source.hpp b/src/mbgl/renderer/render_source.hpp
index cffb48214..0445f88a1 100644
--- a/src/mbgl/renderer/render_source.hpp
+++ b/src/mbgl/renderer/render_source.hpp
@@ -50,7 +50,7 @@ public:
virtual void update(Immutable<style::Source::Impl>,
const std::vector<Immutable<style::Layer::Impl>>&,
- const FeatureStatesMap&,
+ Immutable<FeatureStateChangeSet>,
bool,
bool,
const TileParameters&) {}
diff --git a/src/mbgl/renderer/renderer_impl.cpp b/src/mbgl/renderer/renderer_impl.cpp
index dc53f2011..4f9b6b248 100644
--- a/src/mbgl/renderer/renderer_impl.cpp
+++ b/src/mbgl/renderer/renderer_impl.cpp
@@ -243,12 +243,22 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) {
filteredLayers.push_back(layer);
}
- //TODO: AHM: Send feature states
- renderSources.at(source->id)->update(source,
- filteredLayers,
- needsRendering,
- needsRelayout,
- tileParameters);
+ const auto changeSet = updateParameters.stateChanges->find(source->id);
+ if (changeSet != updateParameters.stateChanges->end()) {
+ renderSources.at(source->id)->update(source,
+ filteredLayers,
+ changeSet->second,
+ needsRendering,
+ needsRelayout,
+ tileParameters);
+ }
+ else {
+ renderSources.at(source->id)->update(source,
+ filteredLayers,
+ needsRendering,
+ needsRelayout,
+ tileParameters);
+ }
}
transformState = updateParameters.transformState;
diff --git a/src/mbgl/renderer/sources/render_geojson_source.cpp b/src/mbgl/renderer/sources/render_geojson_source.cpp
index 0e265efff..bfbfe8d76 100644
--- a/src/mbgl/renderer/sources/render_geojson_source.cpp
+++ b/src/mbgl/renderer/sources/render_geojson_source.cpp
@@ -26,6 +26,7 @@ bool RenderGeoJSONSource::isLoaded() const {
void RenderGeoJSONSource::update(Immutable<style::Source::Impl> baseImpl_,
const std::vector<Immutable<Layer::Impl>>& layers,
+ Immutable<FeatureStateChangeSet> statesChangeSet,
const bool needsRendering,
const bool needsRelayout,
const TileParameters& parameters) {
@@ -56,6 +57,7 @@ void RenderGeoJSONSource::update(Immutable<style::Source::Impl> baseImpl_,
}
tilePyramid.update(layers,
+ *statesChangeSet,
needsRendering,
needsRelayout,
parameters,
@@ -68,6 +70,50 @@ void RenderGeoJSONSource::update(Immutable<style::Source::Impl> baseImpl_,
});
}
+void RenderGeoJSONSource::update(Immutable<style::Source::Impl> baseImpl_,
+ const std::vector<Immutable<Layer::Impl>>& layers,
+ const bool needsRendering,
+ const bool needsRelayout,
+ const TileParameters& parameters) {
+ std::swap(baseImpl, baseImpl_);
+
+ enabled = needsRendering;
+
+ GeoJSONData* data_ = impl().getData();
+
+ if (data_ != data) {
+ data = data_;
+ tilePyramid.cache.clear();
+
+ if (data) {
+ const uint8_t maxZ = impl().getZoomRange().max;
+ for (const auto& pair : tilePyramid.tiles) {
+ if (pair.first.canonical.z <= maxZ) {
+ static_cast<GeoJSONTile*>(pair.second.get())->updateData(data->getTile(pair.first.canonical));
+ }
+ }
+ }
+ }
+
+ if (!data) {
+ tilePyramid.tiles.clear();
+ tilePyramid.renderTiles.clear();
+ return;
+ }
+
+ tilePyramid.update(layers,
+ {},
+ needsRendering,
+ needsRelayout,
+ parameters,
+ SourceType::GeoJSON,
+ util::tileSize,
+ impl().getZoomRange(),
+ optional<LatLngBounds>{},
+ [&] (const OverscaledTileID& tileID) {
+ return std::make_unique<GeoJSONTile>(tileID, impl().id, parameters, data->getTile(tileID.canonical));
+ });
+}
void RenderGeoJSONSource::startRender(PaintParameters& parameters) {
parameters.clipIDGenerator.update(tilePyramid.getRenderTiles());
tilePyramid.startRender(parameters);
diff --git a/src/mbgl/renderer/sources/render_geojson_source.hpp b/src/mbgl/renderer/sources/render_geojson_source.hpp
index 297fa09a2..ecba7298c 100644
--- a/src/mbgl/renderer/sources/render_geojson_source.hpp
+++ b/src/mbgl/renderer/sources/render_geojson_source.hpp
@@ -18,6 +18,13 @@ public:
void update(Immutable<style::Source::Impl>,
const std::vector<Immutable<style::Layer::Impl>>&,
+ Immutable<FeatureStateChangeSet>,
+ bool needsRendering,
+ bool needsRelayout,
+ const TileParameters&) final;
+
+ void update(Immutable<style::Source::Impl>,
+ const std::vector<Immutable<style::Layer::Impl>>&,
bool needsRendering,
bool needsRelayout,
const TileParameters&) final;
diff --git a/src/mbgl/renderer/tile_pyramid.cpp b/src/mbgl/renderer/tile_pyramid.cpp
index b23adbec6..a00617b32 100644
--- a/src/mbgl/renderer/tile_pyramid.cpp
+++ b/src/mbgl/renderer/tile_pyramid.cpp
@@ -71,7 +71,7 @@ void TilePyramid::update(const std::vector<Immutable<style::Layer::Impl>>& layer
const Range<uint8_t> zoomRange,
optional<LatLngBounds> bounds,
std::function<std::unique_ptr<Tile> (const OverscaledTileID&)> createTile) {
- FeatureStatesMap fsm;
+ FeatureStateChangeSet fsm;
update(layers,fsm, needsRendering, needsRelayout, parameters, type, tileSize, zoomRange, bounds, createTile);
}
@@ -87,7 +87,7 @@ void extend(PropertyMap& a, const PropertyMap& b) {
}
void TilePyramid::update(const std::vector<Immutable<style::Layer::Impl>>& layers,
- const FeatureStatesMap& newStates,
+ const FeatureStateChangeSet& statesChangeSet,
const bool needsRendering,
const bool needsRelayout,
const TileParameters& parameters,
@@ -151,19 +151,17 @@ void TilePyramid::update(const std::vector<Immutable<style::Layer::Impl>>& layer
idealTiles = util::tileCover(parameters.transformState, idealZoom);
}
+ FeatureStatesMap newStates = {};
//Coalesce changes to the feature state before applying to tiles.
std::shared_ptr<FeatureStatesMap> changedStates = std::make_shared<FeatureStatesMap>();
- for( const auto& sourceLayer: newStates) {
- auto& existing = (*featureStates)[sourceLayer.first];
- auto& changed = sourceLayer.second;
- FeatureStates newChanges;
- //for each feature id in this sourceLayer, get and merge the PropertyMap from newStates
- for (const auto& id: changed) {
- auto& e = existing[id.first];
- extend(e, id.second);
- newChanges[id.first] = e;
+// printf("TPU: %lu statechanges\n", statesChangeSet.size());
+ for( const auto& stateChange: statesChangeSet) {
+ auto& existing = (*featureStates)[stateChange.sourceLayer];
+ if (stateChange.type == FeatureStateChange::ChangeType::Insert) {
+
+ (existing[stateChange.id])[stateChange.key] = *(stateChange.value);
}
- changedStates->emplace(sourceLayer.first, newChanges);
+ (*changedStates)[stateChange.sourceLayer][stateChange.id] = existing[stateChange.id];
}
// Stores a list of all the tiles that we're definitely going to retain. There are two
diff --git a/src/mbgl/renderer/tile_pyramid.hpp b/src/mbgl/renderer/tile_pyramid.hpp
index c238e9f1b..9f676b9ee 100644
--- a/src/mbgl/renderer/tile_pyramid.hpp
+++ b/src/mbgl/renderer/tile_pyramid.hpp
@@ -44,7 +44,7 @@ public:
std::function<std::unique_ptr<Tile> (const OverscaledTileID&)> createTile);
void update(const std::vector<Immutable<style::Layer::Impl>>&,
- const FeatureStatesMap& newStates,
+ const FeatureStateChangeSet&,
bool needsRendering,
bool needsRelayout,
const TileParameters&,
diff --git a/src/mbgl/renderer/update_parameters.hpp b/src/mbgl/renderer/update_parameters.hpp
index a668c64f4..78dafd48e 100644
--- a/src/mbgl/renderer/update_parameters.hpp
+++ b/src/mbgl/renderer/update_parameters.hpp
@@ -8,8 +8,10 @@
#include <mbgl/style/layer.hpp>
#include <mbgl/util/chrono.hpp>
#include <mbgl/util/immutable.hpp>
+#include <mbgl/util/feature_state.hpp>
#include <vector>
+#include <map>
namespace mbgl {
@@ -31,6 +33,7 @@ public:
const Immutable<std::vector<Immutable<style::Image::Impl>>> images;
const Immutable<std::vector<Immutable<style::Source::Impl>>> sources;
const Immutable<std::vector<Immutable<style::Layer::Impl>>> layers;
+ const Immutable<std::unordered_map<std::string, Immutable<std::vector<FeatureStateChange>>>> stateChanges;
AnnotationManager& annotationManager;
diff --git a/src/mbgl/style/sources/geojson_source.cpp b/src/mbgl/style/sources/geojson_source.cpp
index 4e3478322..b626855d5 100644
--- a/src/mbgl/style/sources/geojson_source.cpp
+++ b/src/mbgl/style/sources/geojson_source.cpp
@@ -10,7 +10,8 @@ namespace mbgl {
namespace style {
GeoJSONSource::GeoJSONSource(const std::string& id, const GeoJSONOptions& options)
- : Source(makeMutable<Impl>(std::move(id), options)) {
+ : Source(makeMutable<Impl>(std::move(id), options)),
+ stateChanges(makeMutable<std::vector<FeatureStateChange>>()) {
}
GeoJSONSource::~GeoJSONSource() = default;
@@ -36,6 +37,20 @@ void GeoJSONSource::setGeoJSON(const mapbox::geojson::geojson& geoJSON) {
observer->onSourceChanged(*this);
}
+void GeoJSONSource::setFeatureState(const FeatureIdentifier& featureId, const std::string& key, const mbgl::Value& value) {
+ if ( featureId.valid() && !key.empty()) {
+ stateChanges->emplace_back(FeatureStateChange::ChangeType::Insert, featureId, key, value);
+// observer->onSourceChanged(*this);
+ }
+}
+
+Immutable<std::vector<FeatureStateChange>> GeoJSONSource::collectFeatureStates() {
+ Immutable<std::vector<FeatureStateChange>> immutable(std::move(stateChanges));
+ stateChanges = makeMutable<std::vector<FeatureStateChange>>();
+ printf("!)!)! Collecting feature state!@$!@$\n");
+ return immutable;
+}
+
optional<std::string> GeoJSONSource::getURL() const {
return url;
}
diff --git a/src/mbgl/style/style_impl.cpp b/src/mbgl/style/style_impl.cpp
index 5c9edc789..236aa4d3a 100644
--- a/src/mbgl/style/style_impl.cpp
+++ b/src/mbgl/style/style_impl.cpp
@@ -21,6 +21,8 @@
#include <mbgl/storage/file_source.hpp>
#include <mbgl/storage/resource.hpp>
#include <mbgl/storage/response.hpp>
+#include <mbgl/util/feature_state.hpp>
+#include <mbgl/style/sources/geojson_source.hpp>
namespace mbgl {
namespace style {
@@ -357,5 +359,19 @@ Immutable<std::vector<Immutable<Layer::Impl>>> Style::Impl::getLayerImpls() cons
return layers.getImpls();
}
+Immutable<std::unordered_map<std::string, Immutable<std::vector<FeatureStateChange>>>> Style::Impl::getFeatureStateChangeSets() {
+ auto sources_ = getSources();
+ Mutable<std::unordered_map<std::string, Immutable<std::vector<FeatureStateChange>>>>
+ collectedStates(makeMutable<std::unordered_map<std::string, Immutable<std::vector<FeatureStateChange>>>>());
+
+ for (auto src: sources_) {
+ if (src->is<GeoJSONSource>()) {
+ GeoJSONSource * gjSrc = src->as<GeoJSONSource>();
+ collectedStates->insert({gjSrc->getID(), gjSrc->collectFeatureStates()});
+ }
+ }
+ return std::move(collectedStates);
+}
+
} // namespace style
} // namespace mbgl
diff --git a/src/mbgl/style/style_impl.hpp b/src/mbgl/style/style_impl.hpp
index 3dc222bfa..d34a69ea9 100644
--- a/src/mbgl/style/style_impl.hpp
+++ b/src/mbgl/style/style_impl.hpp
@@ -17,6 +17,7 @@
#include <mbgl/util/noncopyable.hpp>
#include <mbgl/util/optional.hpp>
#include <mbgl/util/geo.hpp>
+#include <mbgl/util/feature_state.hpp>
#include <memory>
#include <string>
@@ -88,6 +89,9 @@ public:
Immutable<std::vector<Immutable<Image::Impl>>> getImageImpls() const;
Immutable<std::vector<Immutable<Source::Impl>>> getSourceImpls() const;
Immutable<std::vector<Immutable<Layer::Impl>>> getLayerImpls() const;
+ Immutable<std::unordered_map<std::string,
+ Immutable<std::vector<FeatureStateChange>>>>
+ getFeatureStateChangeSets();
void dumpDebugLogs() const;