From f2bc00267cd6430f85763beeb03b98109ff7b023 Mon Sep 17 00:00:00 2001 From: Asheem Mamoowala Date: Mon, 12 Nov 2018 14:58:13 -0800 Subject: Prototype ChangeSets based approach to feature state. - 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. --- include/mbgl/style/sources/geojson_source.hpp | 5 +++ include/mbgl/util/feature_state.hpp | 19 ++++++++- platform/glfw/glfw_view.cpp | 31 ++++++++++++++- platform/glfw/glfw_view.hpp | 1 + platform/glfw/main.cpp | 2 +- src/mbgl/map/map.cpp | 1 + src/mbgl/renderer/render_source.hpp | 2 +- src/mbgl/renderer/renderer_impl.cpp | 22 ++++++++--- .../renderer/sources/render_geojson_source.cpp | 46 ++++++++++++++++++++++ .../renderer/sources/render_geojson_source.hpp | 7 ++++ src/mbgl/renderer/tile_pyramid.cpp | 22 +++++------ src/mbgl/renderer/tile_pyramid.hpp | 2 +- src/mbgl/renderer/update_parameters.hpp | 3 ++ src/mbgl/style/sources/geojson_source.cpp | 17 +++++++- src/mbgl/style/style_impl.cpp | 16 ++++++++ src/mbgl/style/style_impl.hpp | 4 ++ 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 a03b910279..803588ac7e 100644 --- a/include/mbgl/style/sources/geojson_source.hpp +++ b/include/mbgl/style/sources/geojson_source.hpp @@ -2,8 +2,10 @@ #include #include +#include #include #include +#include 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 getURL() const; @@ -41,9 +44,11 @@ public: void loadDescription(FileSource&) final; + Immutable> collectFeatureStates(); private: optional url; std::unique_ptr req; + Mutable> stateChanges; }; template <> diff --git a/include/mbgl/util/feature_state.hpp b/include/mbgl/util/feature_state.hpp index e97926c6e1..f63f3dcbff 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; FeatureStateChange(ChangeType type_, - FeatureIdentifier&& id_, - std::string&& key_, + const std::string& sourceLayer_, + const FeatureIdentifier& id_, + const std::string& key_, optional 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_) : + type(type_), + id(std::move(id_)), + key(std::move(key_)), + value(std::move(value_)) {} + }; +using FeatureStateChangeSet = std::vector; + } // namespace mbgl diff --git a/platform/glfw/glfw_view.cpp b/platform/glfw/glfw_view.cpp index 9179113139..522a0c6f61 100644 --- a/platform/glfw/glfw_view.cpp +++ b/platform/glfw/glfw_view.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -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 features = view->rendererFrontend->getRenderer()->queryRenderedFeatures(screenCoordinate,{ }); + + if (features.empty() && !view->hoveredId) return; + auto pointsSource = view->map->getStyle().getSource("points"); + if (pointsSource && pointsSource->is()) { + auto gj = pointsSource->as(); + + 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 d5acf697f7..9a784660e3 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 hoveredId; GLFWwindow *window = nullptr; bool dirty = false; diff --git a/platform/glfw/main.cpp b/platform/glfw/main.cpp index 1bb2e13614..a0320d4052 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(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 9d886cb74c..273ed1bd75 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 cffb482147..0445f88a17 100644 --- a/src/mbgl/renderer/render_source.hpp +++ b/src/mbgl/renderer/render_source.hpp @@ -50,7 +50,7 @@ public: virtual void update(Immutable, const std::vector>&, - const FeatureStatesMap&, + Immutable, bool, bool, const TileParameters&) {} diff --git a/src/mbgl/renderer/renderer_impl.cpp b/src/mbgl/renderer/renderer_impl.cpp index dc53f20110..4f9b6b248b 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 0e265efff4..bfbfe8d76d 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 baseImpl_, const std::vector>& layers, + Immutable statesChangeSet, const bool needsRendering, const bool needsRelayout, const TileParameters& parameters) { @@ -56,6 +57,7 @@ void RenderGeoJSONSource::update(Immutable baseImpl_, } tilePyramid.update(layers, + *statesChangeSet, needsRendering, needsRelayout, parameters, @@ -68,6 +70,50 @@ void RenderGeoJSONSource::update(Immutable baseImpl_, }); } +void RenderGeoJSONSource::update(Immutable baseImpl_, + const std::vector>& 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(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{}, + [&] (const OverscaledTileID& tileID) { + return std::make_unique(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 297fa09a29..ecba7298c1 100644 --- a/src/mbgl/renderer/sources/render_geojson_source.hpp +++ b/src/mbgl/renderer/sources/render_geojson_source.hpp @@ -16,6 +16,13 @@ public: bool isLoaded() const final; + void update(Immutable, + const std::vector>&, + Immutable, + bool needsRendering, + bool needsRelayout, + const TileParameters&) final; + void update(Immutable, const std::vector>&, bool needsRendering, diff --git a/src/mbgl/renderer/tile_pyramid.cpp b/src/mbgl/renderer/tile_pyramid.cpp index b23adbec6e..a00617b321 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>& layer const Range zoomRange, optional bounds, std::function (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>& 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>& layer idealTiles = util::tileCover(parameters.transformState, idealZoom); } + FeatureStatesMap newStates = {}; //Coalesce changes to the feature state before applying to tiles. std::shared_ptr changedStates = std::make_shared(); - 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 c238e9f1bc..9f676b9ee8 100644 --- a/src/mbgl/renderer/tile_pyramid.hpp +++ b/src/mbgl/renderer/tile_pyramid.hpp @@ -44,7 +44,7 @@ public: std::function (const OverscaledTileID&)> createTile); void update(const std::vector>&, - 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 a668c64f48..78dafd48e4 100644 --- a/src/mbgl/renderer/update_parameters.hpp +++ b/src/mbgl/renderer/update_parameters.hpp @@ -8,8 +8,10 @@ #include #include #include +#include #include +#include namespace mbgl { @@ -31,6 +33,7 @@ public: const Immutable>> images; const Immutable>> sources; const Immutable>> layers; + const Immutable>>> stateChanges; AnnotationManager& annotationManager; diff --git a/src/mbgl/style/sources/geojson_source.cpp b/src/mbgl/style/sources/geojson_source.cpp index 4e3478322d..b626855d57 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(std::move(id), options)) { + : Source(makeMutable(std::move(id), options)), + stateChanges(makeMutable>()) { } 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> GeoJSONSource::collectFeatureStates() { + Immutable> immutable(std::move(stateChanges)); + stateChanges = makeMutable>(); + printf("!)!)! Collecting feature state!@$!@$\n"); + return immutable; +} + optional GeoJSONSource::getURL() const { return url; } diff --git a/src/mbgl/style/style_impl.cpp b/src/mbgl/style/style_impl.cpp index 5c9edc789f..236aa4d3aa 100644 --- a/src/mbgl/style/style_impl.cpp +++ b/src/mbgl/style/style_impl.cpp @@ -21,6 +21,8 @@ #include #include #include +#include +#include namespace mbgl { namespace style { @@ -357,5 +359,19 @@ Immutable>> Style::Impl::getLayerImpls() cons return layers.getImpls(); } +Immutable>>> Style::Impl::getFeatureStateChangeSets() { + auto sources_ = getSources(); + Mutable>>> + collectedStates(makeMutable>>>()); + + for (auto src: sources_) { + if (src->is()) { + GeoJSONSource * gjSrc = src->as(); + 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 3dc222bfad..d34a69ea92 100644 --- a/src/mbgl/style/style_impl.hpp +++ b/src/mbgl/style/style_impl.hpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -88,6 +89,9 @@ public: Immutable>> getImageImpls() const; Immutable>> getSourceImpls() const; Immutable>> getLayerImpls() const; + Immutable>>> + getFeatureStateChangeSets(); void dumpDebugLogs() const; -- cgit v1.2.1