mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Start consolidating the caches in RasterCache (flutter/engine#31492)
This commit is contained in:
parent
58ed84f8cd
commit
d2640b977f
@ -178,8 +178,8 @@ std::unique_ptr<RasterCacheResult> RasterCache::RasterizeDisplayList(
|
||||
void RasterCache::Prepare(PrerollContext* context,
|
||||
Layer* layer,
|
||||
const SkMatrix& ctm) {
|
||||
LayerRasterCacheKey cache_key(layer->unique_id(), ctm);
|
||||
Entry& entry = layer_cache_[cache_key];
|
||||
RasterCacheKey cache_key(layer->unique_id(), RasterCacheKeyType::kLayer, ctm);
|
||||
Entry& entry = cache_[cache_key];
|
||||
entry.access_count++;
|
||||
entry.used_this_frame = true;
|
||||
if (!entry.image) {
|
||||
@ -242,10 +242,11 @@ bool RasterCache::Prepare(PrerollContext* context,
|
||||
return false;
|
||||
}
|
||||
|
||||
PictureRasterCacheKey cache_key(picture->uniqueID(), transformation_matrix);
|
||||
RasterCacheKey cache_key(picture->uniqueID(), RasterCacheKeyType::kPicture,
|
||||
transformation_matrix);
|
||||
|
||||
// Creates an entry, if not present prior.
|
||||
Entry& entry = picture_cache_[cache_key];
|
||||
Entry& entry = cache_[cache_key];
|
||||
if (entry.access_count < access_threshold_) {
|
||||
// Frame threshold has not yet been reached.
|
||||
return false;
|
||||
@ -295,11 +296,12 @@ bool RasterCache::Prepare(PrerollContext* context,
|
||||
return false;
|
||||
}
|
||||
|
||||
DisplayListRasterCacheKey cache_key(display_list->unique_id(),
|
||||
transformation_matrix);
|
||||
RasterCacheKey cache_key(display_list->unique_id(),
|
||||
RasterCacheKeyType::kDisplayList,
|
||||
transformation_matrix);
|
||||
|
||||
// Creates an entry, if not present prior.
|
||||
Entry& entry = display_list_cache_[cache_key];
|
||||
Entry& entry = cache_[cache_key];
|
||||
if (entry.access_count < access_threshold_) {
|
||||
// Frame threshold has not yet been reached.
|
||||
return false;
|
||||
@ -321,30 +323,28 @@ bool RasterCache::Prepare(PrerollContext* context,
|
||||
}
|
||||
|
||||
void RasterCache::Touch(Layer* layer, const SkMatrix& ctm) {
|
||||
LayerRasterCacheKey cache_key(layer->unique_id(), ctm);
|
||||
auto it = layer_cache_.find(cache_key);
|
||||
if (it != layer_cache_.end()) {
|
||||
it->second.used_this_frame = true;
|
||||
it->second.access_count++;
|
||||
}
|
||||
RasterCacheKey cache_key(layer->unique_id(), RasterCacheKeyType::kLayer, ctm);
|
||||
Touch(cache_key);
|
||||
}
|
||||
|
||||
void RasterCache::Touch(SkPicture* picture,
|
||||
const SkMatrix& transformation_matrix) {
|
||||
PictureRasterCacheKey cache_key(picture->uniqueID(), transformation_matrix);
|
||||
auto it = picture_cache_.find(cache_key);
|
||||
if (it != picture_cache_.end()) {
|
||||
it->second.used_this_frame = true;
|
||||
it->second.access_count++;
|
||||
}
|
||||
RasterCacheKey cache_key(picture->uniqueID(), RasterCacheKeyType::kPicture,
|
||||
transformation_matrix);
|
||||
Touch(cache_key);
|
||||
}
|
||||
|
||||
void RasterCache::Touch(DisplayList* display_list,
|
||||
const SkMatrix& transformation_matrix) {
|
||||
DisplayListRasterCacheKey cache_key(display_list->unique_id(),
|
||||
transformation_matrix);
|
||||
auto it = display_list_cache_.find(cache_key);
|
||||
if (it != display_list_cache_.end()) {
|
||||
RasterCacheKey cache_key(display_list->unique_id(),
|
||||
RasterCacheKeyType::kDisplayList,
|
||||
transformation_matrix);
|
||||
Touch(cache_key);
|
||||
}
|
||||
|
||||
void RasterCache::Touch(const RasterCacheKey& cache_key) {
|
||||
auto it = cache_.find(cache_key);
|
||||
if (it != cache_.end()) {
|
||||
it->second.used_this_frame = true;
|
||||
it->second.access_count++;
|
||||
}
|
||||
@ -353,52 +353,33 @@ void RasterCache::Touch(DisplayList* display_list,
|
||||
bool RasterCache::Draw(const SkPicture& picture,
|
||||
SkCanvas& canvas,
|
||||
const SkPaint* paint) const {
|
||||
PictureRasterCacheKey cache_key(picture.uniqueID(), canvas.getTotalMatrix());
|
||||
auto it = picture_cache_.find(cache_key);
|
||||
if (it == picture_cache_.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Entry& entry = it->second;
|
||||
entry.access_count++;
|
||||
entry.used_this_frame = true;
|
||||
|
||||
if (entry.image) {
|
||||
entry.image->draw(canvas, paint);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
RasterCacheKey cache_key(picture.uniqueID(), RasterCacheKeyType::kPicture,
|
||||
canvas.getTotalMatrix());
|
||||
return Draw(cache_key, canvas, paint);
|
||||
}
|
||||
|
||||
bool RasterCache::Draw(const DisplayList& display_list,
|
||||
SkCanvas& canvas,
|
||||
const SkPaint* paint) const {
|
||||
DisplayListRasterCacheKey cache_key(display_list.unique_id(),
|
||||
canvas.getTotalMatrix());
|
||||
auto it = display_list_cache_.find(cache_key);
|
||||
if (it == display_list_cache_.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Entry& entry = it->second;
|
||||
entry.access_count++;
|
||||
entry.used_this_frame = true;
|
||||
|
||||
if (entry.image) {
|
||||
entry.image->draw(canvas, paint);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
RasterCacheKey cache_key(display_list.unique_id(),
|
||||
RasterCacheKeyType::kDisplayList,
|
||||
canvas.getTotalMatrix());
|
||||
return Draw(cache_key, canvas, paint);
|
||||
}
|
||||
|
||||
bool RasterCache::Draw(const Layer* layer,
|
||||
SkCanvas& canvas,
|
||||
const SkPaint* paint) const {
|
||||
LayerRasterCacheKey cache_key(layer->unique_id(), canvas.getTotalMatrix());
|
||||
auto it = layer_cache_.find(cache_key);
|
||||
if (it == layer_cache_.end()) {
|
||||
RasterCacheKey cache_key(layer->unique_id(), RasterCacheKeyType::kLayer,
|
||||
canvas.getTotalMatrix());
|
||||
return Draw(cache_key, canvas, paint);
|
||||
}
|
||||
|
||||
bool RasterCache::Draw(const RasterCacheKey& cache_key,
|
||||
SkCanvas& canvas,
|
||||
const SkPaint* paint) const {
|
||||
auto it = cache_.find(cache_key);
|
||||
if (it == cache_.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -419,37 +400,88 @@ void RasterCache::PrepareNewFrame() {
|
||||
display_list_cached_this_frame_ = 0;
|
||||
}
|
||||
|
||||
void RasterCache::SweepOneCacheAfterFrame(RasterCacheKey::Map<Entry>& cache,
|
||||
RasterCacheMetrics& picture_metrics,
|
||||
RasterCacheMetrics& layer_metrics) {
|
||||
std::vector<RasterCacheKey::Map<Entry>::iterator> dead;
|
||||
|
||||
for (auto it = cache.begin(); it != cache.end(); ++it) {
|
||||
Entry& entry = it->second;
|
||||
|
||||
if (!entry.used_this_frame) {
|
||||
dead.push_back(it);
|
||||
} else if (entry.image) {
|
||||
RasterCacheKeyKind kind = it->first.kind();
|
||||
switch (kind) {
|
||||
case RasterCacheKeyKind::kPictureMetrics:
|
||||
picture_metrics.in_use_count++;
|
||||
picture_metrics.in_use_bytes += entry.image->image_bytes();
|
||||
break;
|
||||
case RasterCacheKeyKind::kLayerMetrics:
|
||||
layer_metrics.in_use_count++;
|
||||
layer_metrics.in_use_bytes += entry.image->image_bytes();
|
||||
break;
|
||||
}
|
||||
}
|
||||
entry.used_this_frame = false;
|
||||
}
|
||||
|
||||
for (auto it : dead) {
|
||||
if (it->second.image) {
|
||||
RasterCacheKeyKind kind = it->first.kind();
|
||||
switch (kind) {
|
||||
case RasterCacheKeyKind::kPictureMetrics:
|
||||
picture_metrics.eviction_count++;
|
||||
picture_metrics.eviction_bytes += it->second.image->image_bytes();
|
||||
break;
|
||||
case RasterCacheKeyKind::kLayerMetrics:
|
||||
layer_metrics.eviction_count++;
|
||||
layer_metrics.eviction_bytes += it->second.image->image_bytes();
|
||||
break;
|
||||
}
|
||||
}
|
||||
cache.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
void RasterCache::CleanupAfterFrame() {
|
||||
picture_metrics_ = {};
|
||||
layer_metrics_ = {};
|
||||
{
|
||||
TRACE_EVENT0("flutter", "RasterCache::SweepCaches");
|
||||
SweepOneCacheAfterFrame(picture_cache_, picture_metrics_);
|
||||
SweepOneCacheAfterFrame(display_list_cache_, picture_metrics_);
|
||||
SweepOneCacheAfterFrame(layer_cache_, layer_metrics_);
|
||||
SweepOneCacheAfterFrame(cache_, picture_metrics_, layer_metrics_);
|
||||
}
|
||||
TraceStatsToTimeline();
|
||||
}
|
||||
|
||||
void RasterCache::Clear() {
|
||||
picture_cache_.clear();
|
||||
display_list_cache_.clear();
|
||||
layer_cache_.clear();
|
||||
cache_.clear();
|
||||
picture_metrics_ = {};
|
||||
layer_metrics_ = {};
|
||||
}
|
||||
|
||||
size_t RasterCache::GetCachedEntriesCount() const {
|
||||
return layer_cache_.size() + picture_cache_.size() +
|
||||
display_list_cache_.size();
|
||||
return cache_.size();
|
||||
}
|
||||
|
||||
size_t RasterCache::GetLayerCachedEntriesCount() const {
|
||||
return layer_cache_.size();
|
||||
size_t layer_cached_entries_count = 0;
|
||||
for (const auto& item : cache_) {
|
||||
if (item.first.kind() == RasterCacheKeyKind::kLayerMetrics) {
|
||||
layer_cached_entries_count++;
|
||||
}
|
||||
}
|
||||
return layer_cached_entries_count;
|
||||
}
|
||||
|
||||
size_t RasterCache::GetPictureCachedEntriesCount() const {
|
||||
return picture_cache_.size() + display_list_cache_.size();
|
||||
size_t picture_cached_entries_count = 0;
|
||||
for (const auto& item : cache_) {
|
||||
if (item.first.kind() == RasterCacheKeyKind::kPictureMetrics) {
|
||||
picture_cached_entries_count++;
|
||||
}
|
||||
}
|
||||
return picture_cached_entries_count;
|
||||
}
|
||||
|
||||
void RasterCache::SetCheckboardCacheImages(bool checkerboard) {
|
||||
@ -479,8 +511,9 @@ void RasterCache::TraceStatsToTimeline() const {
|
||||
|
||||
size_t RasterCache::EstimateLayerCacheByteSize() const {
|
||||
size_t layer_cache_bytes = 0;
|
||||
for (const auto& item : layer_cache_) {
|
||||
if (item.second.image) {
|
||||
for (const auto& item : cache_) {
|
||||
if (item.first.kind() == RasterCacheKeyKind::kLayerMetrics &&
|
||||
item.second.image) {
|
||||
layer_cache_bytes += item.second.image->image_bytes();
|
||||
}
|
||||
}
|
||||
@ -489,13 +522,9 @@ size_t RasterCache::EstimateLayerCacheByteSize() const {
|
||||
|
||||
size_t RasterCache::EstimatePictureCacheByteSize() const {
|
||||
size_t picture_cache_bytes = 0;
|
||||
for (const auto& item : picture_cache_) {
|
||||
if (item.second.image) {
|
||||
picture_cache_bytes += item.second.image->image_bytes();
|
||||
}
|
||||
}
|
||||
for (const auto& item : display_list_cache_) {
|
||||
if (item.second.image) {
|
||||
for (const auto& item : cache_) {
|
||||
if (item.first.kind() == RasterCacheKeyKind::kPictureMetrics &&
|
||||
item.second.image) {
|
||||
picture_cache_bytes += item.second.image->image_bytes();
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,6 +43,7 @@ class RasterCacheResult {
|
||||
fml::tracing::TraceFlow flow_;
|
||||
};
|
||||
|
||||
class Layer;
|
||||
struct PrerollContext;
|
||||
|
||||
struct RasterCacheMetrics {
|
||||
@ -290,30 +291,15 @@ class RasterCache {
|
||||
std::unique_ptr<RasterCacheResult> image;
|
||||
};
|
||||
|
||||
template <class Cache>
|
||||
static void SweepOneCacheAfterFrame(Cache& cache,
|
||||
RasterCacheMetrics& metrics) {
|
||||
std::vector<typename Cache::iterator> dead;
|
||||
void Touch(const RasterCacheKey& cache_key);
|
||||
|
||||
for (auto it = cache.begin(); it != cache.end(); ++it) {
|
||||
Entry& entry = it->second;
|
||||
if (!entry.used_this_frame) {
|
||||
dead.push_back(it);
|
||||
} else if (entry.image) {
|
||||
metrics.in_use_count++;
|
||||
metrics.in_use_bytes += entry.image->image_bytes();
|
||||
}
|
||||
entry.used_this_frame = false;
|
||||
}
|
||||
bool Draw(const RasterCacheKey& cache_key,
|
||||
SkCanvas& canvas,
|
||||
const SkPaint* paint) const;
|
||||
|
||||
for (auto it : dead) {
|
||||
if (it->second.image) {
|
||||
metrics.eviction_count++;
|
||||
metrics.eviction_bytes += it->second.image->image_bytes();
|
||||
}
|
||||
cache.erase(it);
|
||||
}
|
||||
}
|
||||
void SweepOneCacheAfterFrame(RasterCacheKey::Map<Entry>& cache,
|
||||
RasterCacheMetrics& picture_metrics,
|
||||
RasterCacheMetrics& layer_metrics);
|
||||
|
||||
bool GenerateNewCacheInThisFrame() const {
|
||||
// Disabling caching when access_threshold is zero is historic behavior.
|
||||
@ -328,9 +314,7 @@ class RasterCache {
|
||||
size_t display_list_cached_this_frame_ = 0;
|
||||
RasterCacheMetrics layer_metrics_;
|
||||
RasterCacheMetrics picture_metrics_;
|
||||
mutable PictureRasterCacheKey::Map<Entry> picture_cache_;
|
||||
mutable DisplayListRasterCacheKey::Map<Entry> display_list_cache_;
|
||||
mutable LayerRasterCacheKey::Map<Entry> layer_cache_;
|
||||
mutable RasterCacheKey::Map<Entry> cache_;
|
||||
bool checkerboard_images_;
|
||||
|
||||
void TraceStatsToTimeline() const;
|
||||
|
||||
@ -7,32 +7,49 @@
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include "flutter/fml/hash_combine.h"
|
||||
#include "flutter/fml/logging.h"
|
||||
#include "third_party/skia/include/core/SkMatrix.h"
|
||||
|
||||
namespace flutter {
|
||||
|
||||
template <typename ID>
|
||||
enum class RasterCacheKeyType { kLayer, kPicture, kDisplayList };
|
||||
|
||||
enum class RasterCacheKeyKind { kLayerMetrics, kPictureMetrics };
|
||||
|
||||
class RasterCacheKey {
|
||||
public:
|
||||
RasterCacheKey(ID id, const SkMatrix& ctm) : id_(id), matrix_(ctm) {
|
||||
RasterCacheKey(uint64_t id, RasterCacheKeyType type, const SkMatrix& ctm)
|
||||
: id_(id), type_(type), matrix_(ctm) {
|
||||
matrix_[SkMatrix::kMTransX] = 0;
|
||||
matrix_[SkMatrix::kMTransY] = 0;
|
||||
}
|
||||
|
||||
ID id() const { return id_; }
|
||||
uint64_t id() const { return id_; }
|
||||
RasterCacheKeyType type() const { return type_; }
|
||||
const SkMatrix& matrix() const { return matrix_; }
|
||||
|
||||
RasterCacheKeyKind kind() const {
|
||||
switch (type_) {
|
||||
case RasterCacheKeyType::kPicture:
|
||||
case RasterCacheKeyType::kDisplayList:
|
||||
return RasterCacheKeyKind::kPictureMetrics;
|
||||
case RasterCacheKeyType::kLayer:
|
||||
return RasterCacheKeyKind::kLayerMetrics;
|
||||
}
|
||||
}
|
||||
|
||||
struct Hash {
|
||||
uint32_t operator()(RasterCacheKey const& key) const {
|
||||
return std::hash<ID>()(key.id_);
|
||||
std::size_t operator()(RasterCacheKey const& key) const {
|
||||
return fml::HashCombine(key.id_, key.type_);
|
||||
}
|
||||
};
|
||||
|
||||
struct Equal {
|
||||
constexpr bool operator()(const RasterCacheKey& lhs,
|
||||
const RasterCacheKey& rhs) const {
|
||||
return lhs.id_ == rhs.id_ && lhs.matrix_ == rhs.matrix_;
|
||||
return lhs.id_ == rhs.id_ && lhs.type_ == rhs.type_ &&
|
||||
lhs.matrix_ == rhs.matrix_;
|
||||
}
|
||||
};
|
||||
|
||||
@ -40,7 +57,9 @@ class RasterCacheKey {
|
||||
using Map = std::unordered_map<RasterCacheKey, Value, Hash, Equal>;
|
||||
|
||||
private:
|
||||
ID id_;
|
||||
uint64_t id_;
|
||||
|
||||
RasterCacheKeyType type_;
|
||||
|
||||
// ctm where only fractional (0-1) translations are preserved:
|
||||
// matrix_ = ctm;
|
||||
@ -49,17 +68,6 @@ class RasterCacheKey {
|
||||
SkMatrix matrix_;
|
||||
};
|
||||
|
||||
// The ID is the uint32_t picture uniqueID
|
||||
using PictureRasterCacheKey = RasterCacheKey<uint32_t>;
|
||||
|
||||
// The ID is the uint32_t DisplayList uniqueID
|
||||
using DisplayListRasterCacheKey = RasterCacheKey<uint32_t>;
|
||||
|
||||
class Layer;
|
||||
|
||||
// The ID is the uint64_t layer unique_id
|
||||
using LayerRasterCacheKey = RasterCacheKey<uint64_t>;
|
||||
|
||||
} // namespace flutter
|
||||
|
||||
#endif // FLUTTER_FLOW_RASTER_CACHE_KEY_H_
|
||||
|
||||
@ -605,6 +605,81 @@ TEST(RasterCache, DisplayListWithSingularMatrixIsNotCached) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(RasterCache, RasterCacheKeyHashFunction) {
|
||||
RasterCacheKey::Map<int> map;
|
||||
auto hash_function = map.hash_function();
|
||||
SkMatrix matrix = SkMatrix::I();
|
||||
uint64_t id = 5;
|
||||
RasterCacheKey layer_key(id, RasterCacheKeyType::kLayer, matrix);
|
||||
RasterCacheKey picture_key(id, RasterCacheKeyType::kPicture, matrix);
|
||||
RasterCacheKey display_list_key(id, RasterCacheKeyType::kDisplayList, matrix);
|
||||
|
||||
auto layer_hash_code = hash_function(layer_key);
|
||||
ASSERT_EQ(layer_hash_code, fml::HashCombine(id, RasterCacheKeyType::kLayer));
|
||||
|
||||
auto picture_hash_code = hash_function(picture_key);
|
||||
ASSERT_EQ(picture_hash_code,
|
||||
fml::HashCombine(id, RasterCacheKeyType::kPicture));
|
||||
|
||||
auto display_list_hash_code = hash_function(display_list_key);
|
||||
ASSERT_EQ(display_list_hash_code,
|
||||
fml::HashCombine(id, RasterCacheKeyType::kDisplayList));
|
||||
}
|
||||
|
||||
TEST(RasterCache, RasterCacheKeySameID) {
|
||||
RasterCacheKey::Map<int> map;
|
||||
SkMatrix matrix = SkMatrix::I();
|
||||
uint64_t id = 5;
|
||||
RasterCacheKey layer_key(id, RasterCacheKeyType::kLayer, matrix);
|
||||
RasterCacheKey picture_key(id, RasterCacheKeyType::kPicture, matrix);
|
||||
RasterCacheKey display_list_key(id, RasterCacheKeyType::kDisplayList, matrix);
|
||||
map[layer_key] = 100;
|
||||
map[picture_key] = 200;
|
||||
map[display_list_key] = 300;
|
||||
|
||||
ASSERT_EQ(map[layer_key], 100);
|
||||
ASSERT_EQ(map[picture_key], 200);
|
||||
ASSERT_EQ(map[display_list_key], 300);
|
||||
}
|
||||
|
||||
TEST(RasterCache, RasterCacheKeySameType) {
|
||||
RasterCacheKey::Map<int> map;
|
||||
SkMatrix matrix = SkMatrix::I();
|
||||
|
||||
RasterCacheKeyType type = RasterCacheKeyType::kLayer;
|
||||
RasterCacheKey layer_first_key(5, type, matrix);
|
||||
RasterCacheKey layer_second_key(10, type, matrix);
|
||||
RasterCacheKey layer_third_key(15, type, matrix);
|
||||
map[layer_first_key] = 50;
|
||||
map[layer_second_key] = 100;
|
||||
map[layer_third_key] = 150;
|
||||
ASSERT_EQ(map[layer_first_key], 50);
|
||||
ASSERT_EQ(map[layer_second_key], 100);
|
||||
ASSERT_EQ(map[layer_third_key], 150);
|
||||
|
||||
type = RasterCacheKeyType::kPicture;
|
||||
RasterCacheKey picture_first_key(20, type, matrix);
|
||||
RasterCacheKey picture_second_key(25, type, matrix);
|
||||
RasterCacheKey picture_third_key(30, type, matrix);
|
||||
map[picture_first_key] = 200;
|
||||
map[picture_second_key] = 250;
|
||||
map[picture_third_key] = 300;
|
||||
ASSERT_EQ(map[picture_first_key], 200);
|
||||
ASSERT_EQ(map[picture_second_key], 250);
|
||||
ASSERT_EQ(map[picture_third_key], 300);
|
||||
|
||||
type = RasterCacheKeyType::kDisplayList;
|
||||
RasterCacheKey display_list_first_key(35, type, matrix);
|
||||
RasterCacheKey display_list_second_key(40, type, matrix);
|
||||
RasterCacheKey display_list_third_key(45, type, matrix);
|
||||
map[display_list_first_key] = 350;
|
||||
map[display_list_second_key] = 400;
|
||||
map[display_list_third_key] = 450;
|
||||
ASSERT_EQ(map[display_list_first_key], 350);
|
||||
ASSERT_EQ(map[display_list_second_key], 400);
|
||||
ASSERT_EQ(map[display_list_third_key], 450);
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
|
||||
} // namespace flutter
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user