summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJustin R. Miller <incanus@codesorcery.net>2015-04-16 01:15:41 -0700
committerJustin R. Miller <incanus@codesorcery.net>2015-04-16 01:15:41 -0700
commit190709c6b1fd9326d0eef5ffc8eb36070e5ad5c7 (patch)
treedbff7b348f78d0481bf76d3c3313f3e5514cb7b6
parentc574acd64da34ea8bbd58ef5440c6add8f365e24 (diff)
downloadqtlocation-mapboxgl-190709c6b1fd9326d0eef5ffc8eb36070e5ad5c7.tar.gz
fixes #1157, #1255: cache parsed tiles in memory
-rw-r--r--include/mbgl/ios/MGLMapView.h3
-rw-r--r--include/mbgl/map/map.hpp7
-rw-r--r--ios/app/MBXViewController.mm11
-rw-r--r--platform/ios/MGLMapView.mm25
-rw-r--r--src/mbgl/map/map.cpp23
-rw-r--r--src/mbgl/map/source.cpp34
-rw-r--r--src/mbgl/map/source.hpp5
-rw-r--r--src/mbgl/map/tile_cache.cpp60
-rw-r--r--src/mbgl/map/tile_cache.hpp30
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