diff --git a/flow/BUILD.gn b/flow/BUILD.gn index def9e48d62c76..85ffa117a3d9a 100644 --- a/flow/BUILD.gn +++ b/flow/BUILD.gn @@ -20,6 +20,8 @@ source_set("flow") { "instrumentation.h", "layers/backdrop_filter_layer.cc", "layers/backdrop_filter_layer.h", + "layers/cacheable_layer.cc", + "layers/cacheable_layer.h", "layers/clip_path_layer.cc", "layers/clip_path_layer.h", "layers/clip_rect_layer.cc", diff --git a/flow/layers/cacheable_layer.cc b/flow/layers/cacheable_layer.cc new file mode 100644 index 0000000000000..667b83b892d89 --- /dev/null +++ b/flow/layers/cacheable_layer.cc @@ -0,0 +1,5 @@ +// 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. + +namespace flutter {} // namespace flutter diff --git a/flow/layers/cacheable_layer.h b/flow/layers/cacheable_layer.h new file mode 100644 index 0000000000000..720fd918297e9 --- /dev/null +++ b/flow/layers/cacheable_layer.h @@ -0,0 +1,34 @@ +// 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_LAYERS_CACHEABL_LAYER_H_ +#define FLUTTER_FLOW_LAYERS_CACHEABL_LAYER_H_ + +#include +#include "flutter/flow/embedded_views.h" +#include "flutter/flow/layers/layer.h" +#include "flutter/flow/raster_cache.h" +#include "include/core/SkColor.h" +#include "include/core/SkMatrix.h" + +namespace flutter { + +class CacheableLayer : public Layer { + public: + enum class CacheType { kNone, kCurrent, kChildren }; + + bool IsCacheable() { return true; } + + virtual void TryToPrepareRasterCache(PrerollContext* context, + const SkMatrix& matrix) {} + + virtual CacheType NeedCaching(PrerollContext* context, + const SkMatrix& ctm) = 0; + + virtual ~CacheableLayer() = default; +}; + +} // namespace flutter + +#endif // FLUTTER_FLOW_LAYERS_CACHEABL_LAYER_H_ diff --git a/flow/layers/container_layer.cc b/flow/layers/container_layer.cc index 970d1a81615bc..70a75e72bd123 100644 --- a/flow/layers/container_layer.cc +++ b/flow/layers/container_layer.cc @@ -189,27 +189,21 @@ void ContainerLayer::PaintChildren(PaintContext& context) const { } void ContainerLayer::TryToPrepareRasterCache(PrerollContext* context, - const SkMatrix& ctm) { - if (!context->has_platform_view && !context->has_texture_layer && - context->raster_cache && - SkRect::Intersects(context->cull_rect, this->paint_bounds())) { - context->raster_cache->Prepare(context, this, ctm); - } else if (context->raster_cache) { - // Don't evict raster cache entry during partial repaint - context->raster_cache->Touch(this, ctm); - } + const SkMatrix& matrix) { + TryToPrepareRasterCache(context, this, matrix); } +// TODO(JsouLiang): will remove this method void ContainerLayer::TryToPrepareRasterCache(PrerollContext* context, Layer* layer, - const SkMatrix& matrix) { + const SkMatrix& ctm) { if (!context->has_platform_view && !context->has_texture_layer && context->raster_cache && SkRect::Intersects(context->cull_rect, layer->paint_bounds())) { - context->raster_cache->Prepare(context, layer, matrix); + context->raster_cache->Prepare(context, layer, ctm); } else if (context->raster_cache) { // Don't evict raster cache entry during partial repaint - context->raster_cache->Touch(layer, matrix); + context->raster_cache->Touch(layer, ctm); } } @@ -258,10 +252,14 @@ ContainerLayer* MergedContainerLayer::GetChildContainer() const { return static_cast(layers()[0].get()); } -Layer* MergedContainerLayer::GetCacheableChild() const { +CacheableLayer* MergedContainerLayer::GetCacheableChild() const { ContainerLayer* child_container = GetChildContainer(); if (child_container->layers().size() == 1) { - return child_container->layers()[0].get(); + auto* child = child_container->layers()[0].get(); + if (child->IsCacheable()) { + return static_cast(child); + } + return nullptr; } return child_container; diff --git a/flow/layers/container_layer.h b/flow/layers/container_layer.h index 1bae51db159b2..7ea85ee6a617e 100644 --- a/flow/layers/container_layer.h +++ b/flow/layers/container_layer.h @@ -7,11 +7,10 @@ #include -#include "flutter/flow/layers/layer.h" - +#include "flutter/flow/layers/cacheable_layer.h" namespace flutter { -class ContainerLayer : public Layer { +class ContainerLayer : public CacheableLayer { public: ContainerLayer(); @@ -20,9 +19,6 @@ class ContainerLayer : public Layer { virtual void Add(std::shared_ptr layer); - void TryToPrepareRasterCache(PrerollContext* context, - const SkMatrix& ctm) override; - void Preroll(PrerollContext* context, const SkMatrix& matrix) override; void Paint(PaintContext& context) const override; @@ -31,6 +27,14 @@ class ContainerLayer : public Layer { virtual void DiffChildren(DiffContext* context, const ContainerLayer* old_layer); + CacheableLayer::CacheType NeedCaching(PrerollContext* context, + const SkMatrix& ctm) override { + return CacheableLayer::CacheType::kNone; + } + + void TryToPrepareRasterCache(PrerollContext* context, + const SkMatrix& matrix) override; + protected: void PrerollChildren(PrerollContext* context, const SkMatrix& child_matrix, @@ -129,7 +133,7 @@ class MergedContainerLayer : public ContainerLayer { * @see GetChildContainer() * @return the best candidate Layer for caching the children */ - Layer* GetCacheableChild() const; + CacheableLayer* GetCacheableChild() const; private: FML_DISALLOW_COPY_AND_ASSIGN(MergedContainerLayer); diff --git a/flow/layers/display_list_layer.cc b/flow/layers/display_list_layer.cc index 7f45e32265cf5..806726c2d6706 100644 --- a/flow/layers/display_list_layer.cc +++ b/flow/layers/display_list_layer.cc @@ -5,7 +5,6 @@ #include "flutter/flow/layers/display_list_layer.h" #include "flutter/display_list/display_list_builder.h" -#include "flutter/flow/layers/layer.h" namespace flutter { @@ -92,28 +91,31 @@ bool DisplayListLayer::Compare(DiffContext::Statistics& statistics, void DisplayListLayer::Preroll(PrerollContext* context, const SkMatrix& matrix) { TRACE_EVENT0("flutter", "DisplayListLayer::Preroll"); - context->raster_cached_entries.emplace_back(RasterCacheEntry(this)); + context->raster_cached_entries.emplace_back( + RasterCacheEntry(this, *context, matrix)); auto& cache_entry = context->raster_cached_entries.back(); // display layer is a leaf node cache_entry.num_child_entries = 0; - cache_entry.need_caching = IsNeedCached(context, matrix); + auto cached_type = NeedCaching(context, matrix); + cache_entry.need_caching = cached_type == CacheableLayer::CacheType::kCurrent; } -bool DisplayListLayer::IsNeedCached(PrerollContext* context, - const SkMatrix& ctm) { +CacheableLayer::CacheType DisplayListLayer::NeedCaching(PrerollContext* context, + const SkMatrix& ctm) { DisplayList* disp_list = display_list(); SkRect bounds = disp_list->bounds().makeOffset(offset_.x(), offset_.y()); if (auto* cache = context->raster_cache) { TRACE_EVENT0("flutter", "DisplayListLayer::RasterCache (Preroll)"); - if (context->cull_rect.intersects(bounds)) { - return cache->ShouldBeCached(context, disp_list, is_complex_, - will_change_, ctm); + if (context->cull_rect.intersects(bounds) && + cache->ShouldBeCached(context, disp_list, is_complex_, will_change_, + ctm)) { + return CacheableLayer::CacheType::kCurrent; } } - return false; + return CacheableLayer::CacheType::kNone; } void DisplayListLayer::TryToPrepareRasterCache(PrerollContext* context, diff --git a/flow/layers/display_list_layer.h b/flow/layers/display_list_layer.h index 8caeb63e027cf..70b4a9f81688c 100644 --- a/flow/layers/display_list_layer.h +++ b/flow/layers/display_list_layer.h @@ -6,14 +6,14 @@ #define FLUTTER_FLOW_LAYERS_DISPLAY_LIST_LAYER_H_ #include "flutter/display_list/display_list.h" -#include "flutter/flow/layers/layer.h" +#include "flutter/flow/layers/cacheable_layer.h" #include "flutter/flow/raster_cache.h" #include "flutter/flow/skia_gpu_object.h" #include "include/core/SkMatrix.h" namespace flutter { -class DisplayListLayer : public Layer { +class DisplayListLayer : public CacheableLayer { public: static constexpr size_t kMaxBytesToCompare = 10000; @@ -34,7 +34,8 @@ class DisplayListLayer : public Layer { return this; } - bool IsNeedCached(PrerollContext* context, const SkMatrix& ctm) override; + CacheableLayer::CacheType NeedCaching(PrerollContext* context, + const SkMatrix& ctm) override; void TryToPrepareRasterCache(PrerollContext* context, const SkMatrix& ctm) override; diff --git a/flow/layers/image_filter_layer.cc b/flow/layers/image_filter_layer.cc index ad3fea528734f..85f249074ce74 100644 --- a/flow/layers/image_filter_layer.cc +++ b/flow/layers/image_filter_layer.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "flutter/flow/layers/image_filter_layer.h" +#include "flutter/flow/layers/layer.h" namespace flutter { @@ -43,7 +44,8 @@ void ImageFilterLayer::Preroll(PrerollContext* context, Layer::AutoPrerollSaveLayerState save = Layer::AutoPrerollSaveLayerState::Create(context); - context->raster_cached_entries.emplace_back(RasterCacheEntry(this)); + context->raster_cached_entries.emplace_back( + RasterCacheEntry(this, *context, matrix)); auto current_index = context->raster_cached_entries.size(); auto& cache_entry = context->raster_cached_entries.back(); @@ -53,7 +55,15 @@ void ImageFilterLayer::Preroll(PrerollContext* context, cache_entry.num_child_entries = context->raster_cached_entries.size() - current_index; - cache_entry.need_caching = IsNeedCached(context, matrix); + auto cache_type = NeedCaching(context, matrix); + + cache_entry.need_caching = false; + if (cache_type == CacheableLayer::CacheType::kCurrent) { + cache_entry.layer = this; + } else if (cache_type == CacheableLayer::CacheType::kChildren) { + // Replace Cacheable child + cache_entry.UpdateRasterCacheEntry(GetCacheableChild(), *context, matrix); + } if (!filter_) { set_paint_bounds(child_bounds); @@ -68,10 +78,10 @@ void ImageFilterLayer::Preroll(PrerollContext* context, set_paint_bounds(child_bounds); } -bool ImageFilterLayer::IsNeedCached(PrerollContext* context, - const SkMatrix& ctm) { +CacheableLayer::CacheType ImageFilterLayer::NeedCaching(PrerollContext* context, + const SkMatrix& ctm) { if (render_count_ >= kMinimumRendersBeforeCachingFilterLayer) { - return true; + return CacheableLayer::CacheType::kCurrent; } transformed_filter_ = nullptr; // This ImageFilterLayer is not yet considered stable so we @@ -93,9 +103,9 @@ bool ImageFilterLayer::IsNeedCached(PrerollContext* context, // stable between frames and also avoiding a rendering surface // switch during the Paint phase even if they are not stable. // This benefit is seen most during animations. - return true; + return CacheableLayer::CacheType::kChildren; } - return false; + return CacheableLayer::CacheType::kNone; } void ImageFilterLayer::Paint(PaintContext& context) const { diff --git a/flow/layers/image_filter_layer.h b/flow/layers/image_filter_layer.h index 175dbd4db0948..024af6bf5ede4 100644 --- a/flow/layers/image_filter_layer.h +++ b/flow/layers/image_filter_layer.h @@ -5,6 +5,7 @@ #ifndef FLUTTER_FLOW_LAYERS_IMAGE_FILTER_LAYER_H_ #define FLUTTER_FLOW_LAYERS_IMAGE_FILTER_LAYER_H_ +#include "flutter/flow/layers/cacheable_layer.h" #include "flutter/flow/layers/container_layer.h" #include "third_party/skia/include/core/SkImageFilter.h" @@ -20,7 +21,8 @@ class ImageFilterLayer : public MergedContainerLayer { void Paint(PaintContext& context) const override; - bool IsNeedCached(PrerollContext* context, const SkMatrix& ctm) override; + CacheableLayer::CacheType NeedCaching(PrerollContext* context, + const SkMatrix& ctm) override; private: // The ImageFilterLayer might cache the filtered output of this layer diff --git a/flow/layers/layer.cc b/flow/layers/layer.cc index 0dd1e22003976..4df4211d496fa 100644 --- a/flow/layers/layer.cc +++ b/flow/layers/layer.cc @@ -5,6 +5,7 @@ #include "flutter/flow/layers/layer.h" #include +#include "flutter/flow/diff_context.h" #include "flutter/flow/paint_utils.h" #include "flutter/flow/raster_cache.h" #include "include/core/SkMatrix.h" @@ -32,9 +33,6 @@ uint64_t Layer::NextUniqueID() { void Layer::Preroll(PrerollContext* context, const SkMatrix& matrix) {} -void Layer::TryToPrepareRasterCache(PrerollContext* context, - const SkMatrix& ctm) {} - Layer::AutoPrerollSaveLayerState::AutoPrerollSaveLayerState( PrerollContext* preroll_context, bool save_layer_is_active, diff --git a/flow/layers/layer.h b/flow/layers/layer.h index ebd399f99ca71..a5b98eb51e1a9 100644 --- a/flow/layers/layer.h +++ b/flow/layers/layer.h @@ -40,20 +40,14 @@ class PictureLayer; class DisplayListLayer; class PerformanceOverlayLayer; class TextureLayer; +class CacheableLayer; +struct RasterCacheEntry; static constexpr SkRect kGiantRect = SkRect::MakeLTRB(-1E9F, -1E9F, 1E9F, 1E9F); // This should be an exact copy of the Clip enum in painting.dart. enum Clip { none, hardEdge, antiAlias, antiAliasWithSaveLayer }; -struct RasterCacheEntry { - explicit RasterCacheEntry(Layer* layer) - : layer(layer), num_child_entries(0), need_caching(false) {} - - Layer* layer; - unsigned num_child_entries; - bool need_caching; -}; struct PrerollContext { RasterCache* raster_cache; GrDirectContext* gr_context; @@ -99,6 +93,51 @@ struct PrerollContext { std::vector raster_cached_entries; }; +struct RasterCacheEntry { + RasterCacheEntry(CacheableLayer* layer, + PrerollContext& context, + const SkMatrix& matrix, + unsigned num_child, + bool need_caching = false) + : layer(layer), + matrix(matrix), + raster_cache(context.raster_cache), + mutators_stack(context.mutators_stack), + cull_rect(context.cull_rect), + color_space(context.dst_color_space), + num_child_entries(num_child), + need_caching(need_caching) {} + + explicit RasterCacheEntry(CacheableLayer* layer, + PrerollContext& context, + const SkMatrix& matrix, + bool need_caching = false) + : RasterCacheEntry(layer, context, matrix, 0, need_caching) {} + + void UpdateRasterCacheEntry(CacheableLayer* layer, + PrerollContext& context, + const SkMatrix& matrix) { + this->raster_cache = context.raster_cache; + this->layer = layer; + this->matrix = matrix; + this->mutators_stack = context.mutators_stack; + this->cull_rect = context.cull_rect; + this->color_space = context.dst_color_space; + this->surface_needs_readback = context.surface_needs_readback; + } + + CacheableLayer* layer; + SkMatrix matrix; + RasterCache* raster_cache; + MutatorsStack mutators_stack; + SkRect cull_rect; + SkColorSpace* color_space; + + bool surface_needs_readback; + unsigned num_child_entries; + bool need_caching; +}; + // Represents a single composited layer. Created on the UI thread but then // subquently used on the Rasterizer thread. class Layer { @@ -117,16 +156,9 @@ class Layer { return original_layer_id_ == old_layer->original_layer_id_; } - virtual bool IsNeedCached(PrerollContext* context, const SkMatrix& ctm) { - return false; - } - // Performs diff with given layer virtual void Diff(DiffContext* context, const Layer* old_layer) {} - virtual void TryToPrepareRasterCache(PrerollContext* context, - const SkMatrix& ctm); - // Used when diffing retained layer; In case the layer is identical, it // doesn't need to be diffed, but the paint region needs to be stored in diff // context so that it can be used in next frame @@ -277,6 +309,8 @@ class Layer { virtual void Paint(PaintContext& context) const = 0; + virtual bool IsCacheable() { return false; } + bool subtree_has_platform_view() const { return subtree_has_platform_view_; } void set_subtree_has_platform_view(bool value) { subtree_has_platform_view_ = value; diff --git a/flow/layers/layer_tree.cc b/flow/layers/layer_tree.cc index 4a7d706a72ce4..528833a12fd84 100644 --- a/flow/layers/layer_tree.cc +++ b/flow/layers/layer_tree.cc @@ -5,6 +5,7 @@ #include "flutter/flow/layers/layer_tree.h" #include "flutter/flow/frame_timings.h" +#include "flutter/flow/layers/cacheable_layer.h" #include "flutter/flow/layers/layer.h" #include "flutter/flow/raster_cache.h" #include "flutter/fml/time/time_point.h" @@ -55,16 +56,29 @@ bool LayerTree::Preroll(CompositorContext::ScopedFrame& frame, root_layer_->Preroll(&context, frame.root_surface_transformation()); - RasterCache(&context, frame.root_surface_transformation()); + RasterCache(frame, &context); return context.surface_needs_readback; } -void LayerTree::RasterCache(PrerollContext* context, const SkMatrix& ctm) { +void LayerTree::RasterCache(CompositorContext::ScopedFrame& frame, + PrerollContext* context) { for (unsigned i = 0; i < context->raster_cached_entries.size(); i++) { auto& entry = context->raster_cached_entries[i]; if (entry.need_caching) { - entry.layer->TryToPrepareRasterCache(context, ctm); + PrerollContext context = {entry.raster_cache, + frame.gr_context(), + frame.view_embedder(), + entry.mutators_stack, + entry.color_space, + entry.cull_rect, + entry.surface_needs_readback, + frame.context().raster_time(), + frame.context().ui_time(), + frame.context().texture_registry(), + checkerboard_offscreen_layers_, + device_pixel_ratio_}; + entry.layer->TryToPrepareRasterCache(&context, entry.matrix); i += entry.num_child_entries; } } diff --git a/flow/layers/layer_tree.h b/flow/layers/layer_tree.h index baa1ebc9b1f7c..6f654cb74be7e 100644 --- a/flow/layers/layer_tree.h +++ b/flow/layers/layer_tree.h @@ -10,6 +10,7 @@ #include "flutter/flow/compositor_context.h" #include "flutter/flow/layers/layer.h" +#include "flutter/flow/raster_cache.h" #include "flutter/fml/macros.h" #include "flutter/fml/time/time_delta.h" #include "third_party/skia/include/core/SkPicture.h" @@ -32,7 +33,8 @@ class LayerTree { bool ignore_raster_cache = false, SkRect cull_rect = kGiantRect); - void RasterCache(PrerollContext* context, const SkMatrix& ctm); + void RasterCache(CompositorContext::ScopedFrame& frame, + PrerollContext* context); void Paint(CompositorContext::ScopedFrame& frame, bool ignore_raster_cache = false) const;