@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,17 +171,21 @@ 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];
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
};
|
||||
|
||||
@@ -244,6 +244,10 @@ TileData::State Source::addTile(Map &map, Worker &worker,
|
||||
new_tile.data.reset();
|
||||
}
|
||||
|
||||
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) {
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
60
src/mbgl/map/tile_cache.cpp
Normal file
60
src/mbgl/map/tile_cache.cpp
Normal file
@@ -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();
|
||||
}
|
||||
|
||||
};
|
||||
30
src/mbgl/map/tile_cache.hpp
Normal file
30
src/mbgl/map/tile_cache.hpp
Normal file
@@ -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
|
||||
Reference in New Issue
Block a user