-
Notifications
You must be signed in to change notification settings - Fork 58
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
extract tile data logic and caching from the tile model and painter. this separation of concerns makes it easier to tune behaviour, since it's more explicit, and to improve performance. introduced memory caching for vector tiles since they now consume far less memory improved heuristics used to provide tile data so that there is less delay in rendering tiles
- Loading branch information
1 parent
80faf93
commit bb955ab
Showing
21 changed files
with
543 additions
and
279 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
import 'dart:collection'; | ||
|
||
import 'cache_stats.dart'; | ||
|
||
class Sizer<V> { | ||
int size(V value) => 1; | ||
} | ||
|
||
class Copier<V> { | ||
V? copy(V? value) => value; | ||
void dispose(V? value) {} | ||
} | ||
|
||
class Cache<K, V> with CacheStats { | ||
int maxSize; | ||
int _currentSize = 0; | ||
bool _disposed = false; | ||
final Sizer _sizer; | ||
final Copier _copier; | ||
|
||
final LinkedHashMap<K, V> _cache = LinkedHashMap(); | ||
|
||
Cache({required this.maxSize, required Sizer sizer, required Copier copier}) | ||
: _sizer = sizer, | ||
_copier = copier; | ||
|
||
int get size => _currentSize; | ||
|
||
void remove(String key) { | ||
_copier.dispose(_cache.remove(key)); | ||
} | ||
|
||
V? get(K key) { | ||
var value = _cache.remove(key); | ||
if (value != null) { | ||
_cache[key] = value; | ||
cacheHit(); | ||
} else { | ||
cacheMiss(); | ||
} | ||
return _copier.copy(value); | ||
} | ||
|
||
void put(K key, V newValue) { | ||
if (_disposed) { | ||
return; | ||
} | ||
var previousValue = _cache.remove(key); | ||
if (previousValue != null) { | ||
_copier.dispose(previousValue); | ||
_currentSize -= _sizer.size(previousValue); | ||
} | ||
_cache[key] = _copier.copy(newValue); | ||
_currentSize += _sizer.size(newValue); | ||
_applyConstraints(); | ||
} | ||
|
||
void _applyConstraints() { | ||
_remove(() => _currentSize > maxSize && _cache.isNotEmpty); | ||
} | ||
|
||
void didHaveMemoryPressure() { | ||
maxSize = maxSize ~/ 2; | ||
clear(); | ||
} | ||
|
||
void dispose() { | ||
_disposed = true; | ||
clear(); | ||
} | ||
|
||
void clear() { | ||
_remove(() => _cache.isNotEmpty); | ||
} | ||
|
||
void _remove(bool Function() condition) { | ||
while (condition()) { | ||
final removed = _cache.remove(_cache.keys.first); | ||
if (removed != null) { | ||
_copier.dispose(removed); | ||
_currentSize -= _sizer.size(removed); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,56 +1,13 @@ | ||
import 'dart:collection'; | ||
import 'dart:typed_data'; | ||
|
||
import 'cache_stats.dart'; | ||
import 'cache.dart'; | ||
|
||
class MemoryCache with CacheStats { | ||
int maxSizeBytes; | ||
int _currentSizeBytes = 0; | ||
final LinkedHashMap<String, Uint8List> _cache = LinkedHashMap(); | ||
|
||
MemoryCache({required this.maxSizeBytes}); | ||
|
||
int get sizeInBytes => _currentSizeBytes; | ||
|
||
void removeItem(String key) { | ||
_cache.remove(key); | ||
} | ||
|
||
Uint8List? getItem(String key) { | ||
var value = _cache.remove(key); | ||
if (value != null) { | ||
_cache[key] = value; | ||
cacheHit(); | ||
} else { | ||
cacheMiss(); | ||
} | ||
return value; | ||
} | ||
|
||
void putItem(String key, Uint8List bytes) { | ||
var value = _cache.remove(key); | ||
if (value != null) { | ||
_currentSizeBytes -= value.lengthInBytes; | ||
} | ||
_cache[key] = bytes; | ||
_currentSizeBytes += bytes.lengthInBytes; | ||
_applyConstraints(); | ||
} | ||
|
||
void _applyConstraints() { | ||
while (_currentSizeBytes > maxSizeBytes && _cache.isNotEmpty) { | ||
final removed = _cache.remove(_cache.keys.first); | ||
_currentSizeBytes -= removed!.lengthInBytes; | ||
} | ||
} | ||
|
||
void didHaveMemoryPressure() { | ||
maxSizeBytes = maxSizeBytes ~/ 2; | ||
clear(); | ||
} | ||
class MemoryCache extends Cache<String, Uint8List> { | ||
MemoryCache({required int maxSizeBytes}) | ||
: super(maxSize: maxSizeBytes, sizer: _Sizer(), copier: Copier()); | ||
} | ||
|
||
void clear() { | ||
_cache.clear(); | ||
_currentSizeBytes = 0; | ||
} | ||
class _Sizer extends Sizer<Uint8List> { | ||
@override | ||
int size(Uint8List value) => value.lengthInBytes; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,66 +1,31 @@ | ||
import 'dart:collection'; | ||
|
||
import 'dart:ui'; | ||
|
||
import '../tile_identity.dart'; | ||
import 'cache_stats.dart'; | ||
|
||
class MemoryImageCache with CacheStats { | ||
int _maxSize; | ||
final _cache = LinkedHashMap<String, Image>(); | ||
bool _disposed = false; | ||
|
||
MemoryImageCache(this._maxSize); | ||
import 'cache.dart'; | ||
|
||
void putImage(TileIdentity id, {required double zoom, required Image image}) { | ||
if (_disposed) { | ||
return; | ||
} | ||
final key = _toKey(id, zoom); | ||
_cache.remove(key)?.dispose(); | ||
_cache[key] = image.clone(); | ||
_applyMaxSize(); | ||
} | ||
class ImageKey { | ||
final TileIdentity id; | ||
final int zoom; | ||
ImageKey(this.id, this.zoom); | ||
|
||
Image? getImage(TileIdentity id, {required double zoom}) { | ||
if (_disposed) { | ||
return null; | ||
} | ||
final key = _toKey(id, zoom); | ||
final image = _cache.remove(key); | ||
if (image != null) { | ||
cacheHit(); | ||
_cache[key] = image; | ||
return image.clone(); | ||
} else { | ||
cacheMiss(); | ||
} | ||
} | ||
@override | ||
operator ==(o) => o is ImageKey && o.id == id && o.zoom == zoom; | ||
|
||
void _applyMaxSize() { | ||
while (_cache.length > _maxSize) { | ||
final oldest = _cache.keys.first; | ||
final removed = _cache.remove(oldest)!; | ||
removed.dispose(); | ||
} | ||
} | ||
@override | ||
int get hashCode => hashValues(id, zoom); | ||
|
||
void didHaveMemoryPressure() { | ||
_clear(); | ||
_maxSize = _maxSize ~/ 2; | ||
} | ||
|
||
void dispose() { | ||
_clear(); | ||
} | ||
@override | ||
String toString() => 'ImageKey(id=$id,zoom=$zoom)'; | ||
} | ||
|
||
void _clear() { | ||
_cache.values.forEach((image) { | ||
image.dispose(); | ||
}); | ||
_cache.clear(); | ||
} | ||
class MemoryImageCache extends Cache<ImageKey, Image> { | ||
MemoryImageCache(int maxSize) | ||
: super(maxSize: maxSize, copier: _Copier(), sizer: Sizer()); | ||
} | ||
|
||
String _toKey(TileIdentity id, double zoom) => | ||
'${id.z}.${id.x}.${id.y}.$zoom'; | ||
class _Copier extends Copier<Image> { | ||
@override | ||
Image? copy(Image? value) => value?.clone(); | ||
@override | ||
void dispose(Image? value) => value?.dispose(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.