#ifndef FLUTTER_FLOW_RASTER_CACHE_H_
#define FLUTTER_FLOW_RASTER_CACHE_H_
#include <memory>
#include <unordered_map>
#include "flutter/flow/instrumentation.h"
#include "flutter/flow/raster_cache_key.h"
#include "flutter/fml/macros.h"
#include "flutter/fml/memory/weak_ptr.h"
#include "include/core/SkImage.h"
#include "include/core/SkSize.h"
namespace flutter {
class RasterCacheResult {
public:
RasterCacheResult();
RasterCacheResult(const RasterCacheResult& other);
~RasterCacheResult();
RasterCacheResult(sk_sp<SkImage> image, const SkRect& logical_rect);
operator bool() const { return static_cast<bool>(image_); }
bool is_valid() const { return static_cast<bool>(image_); };
void draw(SkCanvas& canvas, const SkPaint* paint = nullptr) const;
SkISize image_dimensions() const {
return image_ ? image_->dimensions() : SkISize::Make(0, 0);
};
private:
sk_sp<SkImage> image_;
SkRect logical_rect_;
};
struct PrerollContext;
class RasterCache {
public:
static constexpr int kDefaultPictureCacheLimitPerFrame = 3;
explicit RasterCache(
size_t access_threshold = 3,
size_t picture_cache_limit_per_frame = kDefaultPictureCacheLimitPerFrame);
~RasterCache();
static SkIRect GetDeviceBounds(const SkRect& rect, const SkMatrix& ctm) {
SkRect device_rect;
ctm.mapRect(&device_rect, rect);
SkIRect bounds;
device_rect.roundOut(&bounds);
return bounds;
}
static SkMatrix GetIntegralTransCTM(const SkMatrix& ctm) {
SkMatrix result = ctm;
result[SkMatrix::kMTransX] = SkScalarRoundToScalar(ctm.getTranslateX());
result[SkMatrix::kMTransY] = SkScalarRoundToScalar(ctm.getTranslateY());
return result;
}
bool Prepare(GrContext* context,
SkPicture* picture,
const SkMatrix& transformation_matrix,
SkColorSpace* dst_color_space,
bool is_complex,
bool will_change);
void Prepare(PrerollContext* context, Layer* layer, const SkMatrix& ctm);
RasterCacheResult Get(const SkPicture& picture, const SkMatrix& ctm) const;
RasterCacheResult Get(Layer* layer, const SkMatrix& ctm) const;
void SweepAfterFrame();
void Clear();
void SetCheckboardCacheImages(bool checkerboard);
private:
struct Entry {
bool used_this_frame = false;
size_t access_count = 0;
RasterCacheResult image;
};
template <class Cache, class Iterator>
static void SweepOneCacheAfterFrame(Cache& cache) {
std::vector<Iterator> dead;
for (auto it = cache.begin(); it != cache.end(); ++it) {
Entry& entry = it->second;
if (!entry.used_this_frame) {
dead.push_back(it);
}
entry.used_this_frame = false;
}
for (auto it : dead) {
cache.erase(it);
}
}
const size_t access_threshold_;
const size_t picture_cache_limit_per_frame_;
size_t picture_cached_this_frame_ = 0;
PictureRasterCacheKey::Map<Entry> picture_cache_;
LayerRasterCacheKey::Map<Entry> layer_cache_;
bool checkerboard_images_;
fml::WeakPtrFactory<RasterCache> weak_factory_;
void TraceStatsToTimeline() const;
FML_DISALLOW_COPY_AND_ASSIGN(RasterCache);
};
}
#endif