blob: 331f57349f11c39f48f0505aba31149f53acaacc [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_FLOW_RASTER_CACHE_H_
#define FLUTTER_FLOW_RASTER_CACHE_H_
#include <memory>
#include <unordered_map>
#include "flutter/display_list/display_list.h"
#include "flutter/display_list/display_list_complexity.h"
#include "flutter/flow/raster_cache_key.h"
#include "flutter/flow/raster_cache_util.h"
#include "flutter/fml/macros.h"
#include "flutter/fml/memory/weak_ptr.h"
#include "flutter/fml/trace_event.h"
#include "include/core/SkCanvas.h"
#include "include/core/SkMatrix.h"
#include "include/core/SkRect.h"
#include "third_party/skia/include/core/SkImage.h"
#include "third_party/skia/include/core/SkSize.h"
class SkColorSpace;
namespace flutter {
enum class RasterCacheLayerStrategy { kLayer, kLayerChildren };
class RasterCacheResult {
public:
RasterCacheResult(sk_sp<SkImage> image,
const SkRect& logical_rect,
const char* type);
virtual ~RasterCacheResult() = default;
virtual void draw(SkCanvas& canvas, const SkPaint* paint) const;
virtual SkISize image_dimensions() const {
return image_ ? image_->dimensions() : SkISize::Make(0, 0);
};
virtual int64_t image_bytes() const {
return image_ ? image_->imageInfo().computeMinByteSize() : 0;
};
private:
sk_sp<SkImage> image_;
SkRect logical_rect_;
fml::tracing::TraceFlow flow_;
};
class Layer;
class RasterCacheItem;
struct PrerollContext;
struct PaintContext;
struct RasterCacheMetrics {
/**
* The number of cache entries with images evicted in this frame.
*/
size_t eviction_count = 0;
/**
* The size of all of the images evicted in this frame.
*/
size_t eviction_bytes = 0;
/**
* The number of cache entries with images used in this frame.
*/
size_t in_use_count = 0;
/**
* The size of all of the images used in this frame.
*/
size_t in_use_bytes = 0;
/**
* The total cache entries that had images during this frame.
*/
size_t total_count() const { return in_use_count; }
/**
* The size of all of the cached images during this frame.
*/
size_t total_bytes() const { return in_use_bytes; }
};
/**
* RasterCache is used to cache rasterized layers or display lists to improve
* performance.
*
* Life cycle of RasterCache methods:
* - Preroll stage
* - LayerTree::Preroll - for each Layer in the tree:
* - RasterCacheItem::PrerollSetup
* At the start of each layer's preroll, add cache items to
* `PrerollContext::raster_cached_entries`.
* - RasterCacheItem::PrerollFinalize
* At the end of each layer's preroll, may mark cache entries as
* encountered by the current frame.
* - Paint stage
* - RasterCache::EvictUnusedCacheEntries
* Evict cached images that are no longer used.
* - LayerTree::TryToPrepareRasterCache
* Create cache image for each cache entry if it does not exist.
* - LayerTree::Paint - for each layer in the tree:
* If layers or display lists are cached as cached images, the method
* `RasterCache::Draw` will be used to draw those cache images.
* - RasterCache::EndFrame:
* Computes used counts and memory then reports cache metrics.
*/
class RasterCache {
public:
struct Context {
GrDirectContext* gr_context;
const SkColorSpace* dst_color_space;
const SkMatrix& matrix;
const SkRect& logical_rect;
const char* flow_type;
};
std::unique_ptr<RasterCacheResult> Rasterize(
const RasterCache::Context& context,
const std::function<void(SkCanvas*)>& draw_function,
const std::function<void(SkCanvas*, const SkRect& rect)>&
draw_checkerboard) const;
explicit RasterCache(
size_t access_threshold = 3,
size_t picture_and_display_list_cache_limit_per_frame =
RasterCacheUtil::kDefaultPictureAndDispLayListCacheLimitPerFrame);
virtual ~RasterCache() = default;
// Draws this item if it should be rendered from the cache and returns
// true iff it was successfully drawn. Typically this should only fail
// if the item was disabled due to conditions discovered during |Preroll|
// or if the attempt to populate the entry failed due to bounds overflow
// conditions.
bool Draw(const RasterCacheKeyID& id,
SkCanvas& canvas,
const SkPaint* paint) const;
bool HasEntry(const RasterCacheKeyID& id, const SkMatrix&) const;
void BeginFrame();
void EvictUnusedCacheEntries();
void EndFrame();
void Clear();
void SetCheckboardCacheImages(bool checkerboard);
const RasterCacheMetrics& picture_metrics() const { return picture_metrics_; }
const RasterCacheMetrics& layer_metrics() const { return layer_metrics_; }
size_t GetCachedEntriesCount() const;
/**
* Return the number of map entries in the layer cache regardless of whether
* the entries have been populated with an image.
*/
size_t GetLayerCachedEntriesCount() const;
/**
* Return the number of map entries in the picture caches (SkPicture and
* DisplayList) regardless of whether the entries have been populated with
* an image.
*/
size_t GetPictureCachedEntriesCount() const;
/**
* @brief Estimate how much memory is used by picture raster cache entries in
* bytes, including cache entries in the SkPicture cache and the DisplayList
* cache.
*
* Only SkImage's memory usage is counted as other objects are often much
* smaller compared to SkImage. SkImageInfo::computeMinByteSize is used to
* estimate the SkImage memory usage.
*/
size_t EstimatePictureCacheByteSize() const;
/**
* @brief Estimate how much memory is used by layer raster cache entries in
* bytes.
*
* Only SkImage's memory usage is counted as other objects are often much
* smaller compared to SkImage. SkImageInfo::computeMinByteSize is used to
* estimate the SkImage memory usage.
*/
size_t EstimateLayerCacheByteSize() const;
/**
* @brief Return the number of frames that a picture must be prepared
* before it will be cached. If the number is 0, then no picture will
* ever be cached.
*
* If the number is one, then it must be prepared and drawn on 1 frame
* and it will then be cached on the next frame if it is prepared.
*/
int access_threshold() const { return access_threshold_; }
bool GenerateNewCacheInThisFrame() const {
// Disabling caching when access_threshold is zero is historic behavior.
return access_threshold_ != 0 && display_list_cached_this_frame_ <
display_list_cache_limit_per_frame_;
}
/**
* @brief The entry whose RasterCacheKey is generated by RasterCacheKeyID
* and matrix is marked as encountered by the current frame. The entry
* will be created if it does not exist. Optionally the entry will be marked
* as visible in the current frame if the caller determines that it
* intersects the cull rect. The access_count of the entry will be
* increased if it is visible, or if it was ever visible.
* @return the number of times the entry has been hit since it was created.
* For a new entry that will be 1 if it is visible, or zero if non-visible.
*/
int MarkSeen(const RasterCacheKeyID& id,
const SkMatrix& matrix,
bool visible) const;
/**
* Returns the access count (i.e. accesses_since_visible) for the given
* entry in the cache, or -1 if no such entry exists.
*/
int GetAccessCount(const RasterCacheKeyID& id, const SkMatrix& matrix) const;
bool UpdateCacheEntry(
const RasterCacheKeyID& id,
const Context& raster_cache_context,
const std::function<void(SkCanvas*)>& render_function) const;
private:
struct Entry {
bool encountered_this_frame = false;
bool visible_this_frame = false;
size_t accesses_since_visible = 0;
std::unique_ptr<RasterCacheResult> image;
};
void UpdateMetrics();
RasterCacheMetrics& GetMetricsForKind(RasterCacheKeyKind kind);
const size_t access_threshold_;
const size_t display_list_cache_limit_per_frame_;
mutable size_t display_list_cached_this_frame_ = 0;
RasterCacheMetrics layer_metrics_;
RasterCacheMetrics picture_metrics_;
mutable RasterCacheKey::Map<Entry> cache_;
bool checkerboard_images_;
void TraceStatsToTimeline() const;
friend class RasterCacheItem;
friend class LayerRasterCacheItem;
FML_DISALLOW_COPY_AND_ASSIGN(RasterCache);
};
} // namespace flutter
#endif // FLUTTER_FLOW_RASTER_CACHE_H_