diff options
author | Justin R. Miller <incanus@codesorcery.net> | 2015-04-16 01:15:41 -0700 |
---|---|---|
committer | Justin R. Miller <incanus@codesorcery.net> | 2015-04-16 01:15:41 -0700 |
commit | 190709c6b1fd9326d0eef5ffc8eb36070e5ad5c7 (patch) | |
tree | dbff7b348f78d0481bf76d3c3313f3e5514cb7b6 | |
parent | c574acd64da34ea8bbd58ef5440c6add8f365e24 (diff) | |
download | qtlocation-mapboxgl-190709c6b1fd9326d0eef5ffc8eb36070e5ad5c7.tar.gz |
fixes #1157, #1255: cache parsed tiles in memory
-rw-r--r-- | include/mbgl/ios/MGLMapView.h | 3 | ||||
-rw-r--r-- | include/mbgl/map/map.hpp | 7 | ||||
-rw-r--r-- | ios/app/MBXViewController.mm | 11 | ||||
-rw-r--r-- | platform/ios/MGLMapView.mm | 25 | ||||
-rw-r--r-- | src/mbgl/map/map.cpp | 23 | ||||
-rw-r--r-- | src/mbgl/map/source.cpp | 34 | ||||
-rw-r--r-- | src/mbgl/map/source.hpp | 5 | ||||
-rw-r--r-- | src/mbgl/map/tile_cache.cpp | 60 | ||||
-rw-r--r-- | src/mbgl/map/tile_cache.hpp | 30 |
9 files changed, 191 insertions, 7 deletions
diff --git a/include/mbgl/ios/MGLMapView.h b/include/mbgl/ios/MGLMapView.h index f2aef61830..8717b5e8a1 100644 --- a/include/mbgl/ios/MGLMapView.h +++ b/include/mbgl/ios/MGLMapView.h @@ -279,6 +279,9 @@ IB_DESIGNABLE /** Toggle the current value of debugActive. */ - (void)toggleDebug; +/** Empties the in-memory tile cache. */ +- (void)emptyMemoryCache; + /** Resets the map to the minimum zoom level, a center coordinate of (0, 0), and a northern heading. */ - (void)resetPosition; diff --git a/include/mbgl/map/map.hpp b/include/mbgl/map/map.hpp index 38a37a8057..8c7f5f3961 100644 --- a/include/mbgl/map/map.hpp +++ b/include/mbgl/map/map.hpp @@ -152,6 +152,11 @@ public: std::vector<uint32_t> getAnnotationsInBounds(const LatLngBounds&); LatLngBounds getBoundsForAnnotations(const std::vector<uint32_t>&); + // Memory + void setSourceTileCacheSize(size_t); + size_t getSourceTileCacheSize() const { return sourceCacheSize; } + void onLowMemory(); + // Debug void setDebug(bool value); void toggleDebug(); @@ -196,6 +201,8 @@ private: void updateAnnotationTiles(const std::vector<TileID>&); + size_t sourceCacheSize; + enum class Mode : uint8_t { None, // we're not doing any processing Continuous, // continually updating map diff --git a/ios/app/MBXViewController.mm b/ios/app/MBXViewController.mm index 078d67d398..13235beb07 100644 --- a/ios/app/MBXViewController.mm +++ b/ios/app/MBXViewController.mm @@ -145,6 +145,7 @@ mbgl::Settings_NSUserDefaults *settings = nullptr; otherButtonTitles:@"Reset North", @"Reset Position", @"Toggle Debug", + @"Empty Memory", @"Add 100 Points", @"Add 1,000 Points", @"Add 10,000 Points", @@ -170,18 +171,22 @@ mbgl::Settings_NSUserDefaults *settings = nullptr; } else if (buttonIndex == actionSheet.firstOtherButtonIndex + 3) { - [self parseFeaturesAddingCount:100]; + [self.mapView emptyMemoryCache]; } else if (buttonIndex == actionSheet.firstOtherButtonIndex + 4) { - [self parseFeaturesAddingCount:1000]; + [self parseFeaturesAddingCount:100]; } else if (buttonIndex == actionSheet.firstOtherButtonIndex + 5) { - [self parseFeaturesAddingCount:10000]; + [self parseFeaturesAddingCount:1000]; } else if (buttonIndex == actionSheet.firstOtherButtonIndex + 6) { + [self parseFeaturesAddingCount:10000]; + } + else if (buttonIndex == actionSheet.firstOtherButtonIndex + 7) + { [self.mapView removeAnnotations:self.mapView.annotations]; } } diff --git a/platform/ios/MGLMapView.mm b/platform/ios/MGLMapView.mm index 0395114825..8721b2a4d6 100644 --- a/platform/ios/MGLMapView.mm +++ b/platform/ios/MGLMapView.mm @@ -367,6 +367,7 @@ mbgl::DefaultFileSource *mbglFileSource = nullptr; // [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appDidBackground:) name:UIApplicationDidEnterBackgroundNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appWillForeground:) name:UIApplicationWillEnterForegroundNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveMemoryWarning) name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; // set initial position // @@ -574,6 +575,17 @@ mbgl::DefaultFileSource *mbglFileSource = nullptr; else { mbglView->resize(rect.size.width, rect.size.height, view.contentScaleFactor, view.drawableWidth, view.drawableHeight); + + CGFloat zoomFactor = mbglMap->getMaxZoom() - mbglMap->getMinZoom() + 1; + CGFloat cpuFactor = (CGFloat)[[NSProcessInfo processInfo] processorCount]; + CGFloat memoryFactor = (CGFloat)[[NSProcessInfo processInfo] physicalMemory] / 1000 / 1000 / 1000; + CGFloat sizeFactor = ((CGFloat)mbglMap->getState().getWidth() / mbgl::util::tileSize) * + ((CGFloat)mbglMap->getState().getHeight() / mbgl::util::tileSize); + + NSUInteger cacheSize = zoomFactor * cpuFactor * memoryFactor * sizeFactor * 0.5; + + mbglMap->setSourceTileCacheSize(cacheSize); + mbglMap->renderSync(); } } @@ -1166,6 +1178,11 @@ mbgl::DefaultFileSource *mbglFileSource = nullptr; mbglMap->toggleDebug(); } +- (void)emptyMemoryCache +{ + mbglMap->onLowMemory(); +} + #pragma mark - Geography - + (NSSet *)keyPathsForValuesAffectingCenterCoordinate @@ -2450,7 +2467,8 @@ class MBGLView : public mbgl::View [EAGLContext setCurrentContext:nil]; } - void resize(uint16_t width, uint16_t height, float ratio, uint16_t fbWidth, uint16_t fbHeight) { + void resize(uint16_t width, uint16_t height, float ratio, uint16_t fbWidth, uint16_t fbHeight) + { View::resize(width, height, ratio, fbWidth, fbHeight); } @@ -2566,4 +2584,9 @@ class MBGLView : public mbgl::View self.rotateEnabled = allowsRotating; } +- (void)didReceiveMemoryWarning +{ + mbglMap->onLowMemory(); +} + @end diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp index f76845e3a7..adaf22d60f 100644 --- a/src/mbgl/map/map.cpp +++ b/src/mbgl/map/map.cpp @@ -818,3 +818,26 @@ void Map::render() { triggerUpdate(); } } + +void Map::setSourceTileCacheSize(size_t size) { + if (size != getSourceTileCacheSize()) { + invokeTask([=] { + sourceCacheSize = size; + if (!style) return; + for (const auto &source : style->sources) { + source->setCacheSize(sourceCacheSize); + } + env->performCleanup(); + }); + } +} + +void Map::onLowMemory() { + invokeTask([=] { + if (!style) return; + for (const auto &source : style->sources) { + source->onLowMemory(); + } + env->performCleanup(); + }); +}; diff --git a/src/mbgl/map/source.cpp b/src/mbgl/map/source.cpp index 29f84171d1..3245bab2e3 100644 --- a/src/mbgl/map/source.cpp +++ b/src/mbgl/map/source.cpp @@ -245,6 +245,10 @@ TileData::State Source::addTile(Map &map, Worker &worker, } if (!new_tile.data) { + new_tile.data = cache.get(id.to_uint64()); + } + + if (!new_tile.data) { // If we don't find working tile data, we're just going to load it. if (info.type == SourceType::Vector) { new_tile.data = @@ -394,20 +398,33 @@ void Source::update(Map &map, } } + if (info.type != SourceType::Raster && cache.getSize() == 0) { + size_t conservativeCacheSize = ((float)map.getState().getWidth() / util::tileSize) * + ((float)map.getState().getHeight() / util::tileSize) * + (map.getMaxZoom() - map.getMinZoom() + 1) * + 0.5; + cache.setSize(conservativeCacheSize); + } + + auto& tileCache = cache; + auto& type = info.type; + // Remove tiles that we definitely don't need, i.e. tiles that are not on // the required list. std::set<TileID> retain_data; - util::erase_if(tiles, [&retain, &retain_data](std::pair<const TileID, std::unique_ptr<Tile>> &pair) { + util::erase_if(tiles, [&retain, &retain_data, &tileCache, &type](std::pair<const TileID, std::unique_ptr<Tile>> &pair) { Tile &tile = *pair.second; bool obsolete = std::find(retain.begin(), retain.end(), tile.id) == retain.end(); if (!obsolete) { retain_data.insert(tile.data->id); + } else if (type != SourceType::Raster && tile.data->ready()) { + tileCache.add(tile.id.to_uint64(), tile.data); } return obsolete; }); // Remove all the expired pointers from the set. - util::erase_if(tile_data, [&retain_data](std::pair<const TileID, std::weak_ptr<TileData>> &pair) { + util::erase_if(tile_data, [&retain_data, &tileCache](std::pair<const TileID, std::weak_ptr<TileData>> &pair) { const util::ptr<TileData> tile = pair.second.lock(); if (!tile) { return true; @@ -415,7 +432,9 @@ void Source::update(Map &map, bool obsolete = retain_data.find(tile->id) == retain_data.end(); if (obsolete) { - tile->cancel(); + if (!tileCache.has(tile->id.to_uint64())) { + tile->cancel(); + } return true; } else { return false; @@ -426,10 +445,19 @@ void Source::update(Map &map, } void Source::invalidateTiles(const std::vector<TileID>& ids) { + cache.clear(); for (auto& id : ids) { tiles.erase(id); tile_data.erase(id); } } +void Source::setCacheSize(size_t size) { + cache.setSize(size); +} + +void Source::onLowMemory() { + cache.clear(); +} + } diff --git a/src/mbgl/map/source.hpp b/src/mbgl/map/source.hpp index 625647ac5e..035e862284 100644 --- a/src/mbgl/map/source.hpp +++ b/src/mbgl/map/source.hpp @@ -3,6 +3,7 @@ #include <mbgl/map/tile_id.hpp> #include <mbgl/map/tile_data.hpp> +#include <mbgl/map/tile_cache.hpp> #include <mbgl/style/types.hpp> #include <mbgl/util/noncopyable.hpp> @@ -72,6 +73,9 @@ public: std::forward_list<Tile *> getLoadedTiles() const; + void setCacheSize(size_t); + void onLowMemory(); + SourceInfo info; bool enabled; @@ -96,6 +100,7 @@ private: std::map<TileID, std::unique_ptr<Tile>> tiles; std::map<TileID, std::weak_ptr<TileData>> tile_data; + TileCache cache; }; } diff --git a/src/mbgl/map/tile_cache.cpp b/src/mbgl/map/tile_cache.cpp new file mode 100644 index 0000000000..71eb500be6 --- /dev/null +++ b/src/mbgl/map/tile_cache.cpp @@ -0,0 +1,60 @@ +#include <mbgl/map/tile_cache.hpp> + +#include <cassert> + +namespace mbgl { + +void TileCache::setSize(size_t size_) { + size = size_; + + while (orderedKeys.size() > size) { + auto key = orderedKeys.front(); + orderedKeys.pop_front(); + tiles.erase(key); + } + + assert(orderedKeys.size() <= size); + + tiles.reserve(size); + orderedKeys.resize(size); +} + +void TileCache::add(uint64_t key, std::shared_ptr<TileData> data) { + + assert(tiles.find(key) == tiles.end()); + + tiles.emplace(key, data); + orderedKeys.push_back(key); + + if (orderedKeys.size() > size) { + get(orderedKeys.front()); + } + + assert(orderedKeys.size() <= size); +}; + +std::shared_ptr<TileData> TileCache::get(uint64_t key) { + + std::shared_ptr<TileData> data; + + auto it = tiles.find(key); + if (it != tiles.end()) { + data = it->second; + tiles.erase(it); + orderedKeys.remove(key); + assert(data->ready()); + } + + return data; +}; + +bool TileCache::has(uint64_t key) { + return tiles.find(key) != tiles.end(); +} + +void TileCache::clear() { + orderedKeys.clear(); + tiles.clear(); +} + +}; diff --git a/src/mbgl/map/tile_cache.hpp b/src/mbgl/map/tile_cache.hpp new file mode 100644 index 0000000000..26d830c123 --- /dev/null +++ b/src/mbgl/map/tile_cache.hpp @@ -0,0 +1,30 @@ +#ifndef MBGL_MAP_TILE_CACHE +#define MBGL_MAP_TILE_CACHE + +#include <mbgl/map/tile_data.hpp> + +#include <list> +#include <unordered_map> + +namespace mbgl { + +class TileCache { +public: + TileCache(size_t size_ = 0) : size(size_) {} + + void setSize(size_t); + size_t getSize() const { return size; }; + void add(uint64_t key, std::shared_ptr<TileData> data); + std::shared_ptr<TileData> get(uint64_t key); + bool has(uint64_t key); + void clear(); +private: + std::unordered_map<uint64_t, std::shared_ptr<TileData>> tiles; + std::list<uint64_t> orderedKeys; + + size_t size; +}; + +}; + +#endif |