Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

Commit

Permalink
fixes #1157, #1255: cache parsed tiles in memory
Browse files Browse the repository at this point in the history
  • Loading branch information
incanus committed Apr 16, 2015
1 parent c574acd commit 4f851a4
Show file tree
Hide file tree
Showing 11 changed files with 200 additions and 8 deletions.
3 changes: 3 additions & 0 deletions include/mbgl/ios/MGLMapView.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
7 changes: 7 additions & 0 deletions include/mbgl/map/map.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,11 @@ class Map : private util::noncopyable {
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();
Expand Down Expand Up @@ -196,6 +201,8 @@ class Map : private util::noncopyable {

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
Expand Down
11 changes: 8 additions & 3 deletions ios/app/MBXViewController.mm
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ - (void)showSettings
otherButtonTitles:@"Reset North",
@"Reset Position",
@"Toggle Debug",
@"Empty Memory",
@"Add 100 Points",
@"Add 1,000 Points",
@"Add 10,000 Points",
Expand All @@ -170,17 +171,21 @@ - (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSIn
}
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];
}
Expand Down
25 changes: 24 additions & 1 deletion platform/ios/MGLMapView.mm
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,7 @@ - (BOOL)commonInit
//
[[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
//
Expand Down Expand Up @@ -574,6 +575,17 @@ - (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
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();
}
}
Expand Down Expand Up @@ -1166,6 +1178,11 @@ - (void)toggleDebug
mbglMap->toggleDebug();
}

- (void)emptyMemoryCache
{
mbglMap->onLowMemory();
}

#pragma mark - Geography -

+ (NSSet *)keyPathsForValuesAffectingCenterCoordinate
Expand Down Expand Up @@ -2450,7 +2467,8 @@ void deactivate() override
[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);
}

Expand Down Expand Up @@ -2566,4 +2584,9 @@ - (void)setAllowsRotating:(BOOL)allowsRotating
self.rotateEnabled = allowsRotating;
}

- (void)didReceiveMemoryWarning
{
mbglMap->onLowMemory();
}

@end
6 changes: 5 additions & 1 deletion src/mbgl/map/live_tile_data.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@ LiveTileData::LiveTileData(const TileID& id_,
state = State::loaded;
}

LiveTileData::~LiveTileData() {}
LiveTileData::~LiveTileData() {
// Clear the style (if not already during parse) to
// avoid cyclical shared_ptr references.
style.reset();
}

void LiveTileData::parse() {
if (state != State::loaded) {
Expand Down
23 changes: 23 additions & 0 deletions src/mbgl/map/map.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
});
};
34 changes: 31 additions & 3 deletions src/mbgl/map/source.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -394,28 +398,43 @@ 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;
}

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;
Expand All @@ -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();
}

}
5 changes: 5 additions & 0 deletions src/mbgl/map/source.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -72,6 +73,9 @@ class Source : public std::enable_shared_from_this<Source>, private util::noncop

std::forward_list<Tile *> getLoadedTiles() const;

void setCacheSize(size_t);
void onLowMemory();

SourceInfo info;
bool enabled;

Expand All @@ -96,6 +100,7 @@ class Source : public std::enable_shared_from_this<Source>, private util::noncop

std::map<TileID, std::unique_ptr<Tile>> tiles;
std::map<TileID, std::weak_ptr<TileData>> tile_data;
TileCache cache;
};

}
Expand Down
60 changes: 60 additions & 0 deletions src/mbgl/map/tile_cache.cpp
Original file line number Diff line number Diff line change
@@ -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 changes: 30 additions & 0 deletions src/mbgl/map/tile_cache.hpp
Original file line number Diff line number Diff line change
@@ -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
4 changes: 4 additions & 0 deletions src/mbgl/map/vector_tile_data.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ VectorTileData::VectorTileData(const TileID& id_,

VectorTileData::~VectorTileData() {
glyphAtlas.removeGlyphs(reinterpret_cast<uintptr_t>(this));

// Clear the style (if not already during parse) to
// avoid cyclical shared_ptr references.
style.reset();
}

void VectorTileData::parse() {
Expand Down

0 comments on commit 4f851a4

Please sign in to comment.