// 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. #include "flutter/flow/layers/layer_tree.h" #include "flutter/display_list/skia/dl_sk_canvas.h" #include "flutter/flow/embedded_views.h" #include "flutter/flow/frame_timings.h" #include "flutter/flow/layer_snapshot_store.h" #include "flutter/flow/layers/cacheable_layer.h" #include "flutter/flow/layers/layer.h" #include "flutter/flow/paint_utils.h" #include "flutter/flow/raster_cache.h" #include "flutter/fml/time/time_point.h" #include "flutter/fml/trace_event.h" #include "include/core/SkMatrix.h" #include "third_party/skia/include/core/SkPictureRecorder.h" #include "third_party/skia/include/utils/SkNWayCanvas.h" namespace flutter { LayerTree::LayerTree(const Config& config, const SkISize& frame_size) : root_layer_(config.root_layer), frame_size_(frame_size), rasterizer_tracing_threshold_(config.rasterizer_tracing_threshold), checkerboard_raster_cache_images_( config.checkerboard_raster_cache_images), checkerboard_offscreen_layers_(config.checkerboard_offscreen_layers) {} inline SkColorSpace* GetColorSpace(DlCanvas* canvas) { return canvas ? canvas->GetImageInfo().colorSpace() : nullptr; } bool LayerTree::Preroll(CompositorContext::ScopedFrame& frame, bool ignore_raster_cache, SkRect cull_rect) { TRACE_EVENT0("flutter", "LayerTree::Preroll"); if (!root_layer_) { FML_LOG(ERROR) << "The scene did not specify any layers."; return false; } SkColorSpace* color_space = GetColorSpace(frame.canvas()); frame.context().raster_cache().SetCheckboardCacheImages( checkerboard_raster_cache_images_); LayerStateStack state_stack; state_stack.set_preroll_delegate(cull_rect, frame.root_surface_transformation()); RasterCache* cache = ignore_raster_cache ? nullptr : &frame.context().raster_cache(); raster_cache_items_.clear(); PrerollContext context = { // clang-format off .raster_cache = cache, .gr_context = frame.gr_context(), .view_embedder = frame.view_embedder(), .state_stack = state_stack, .dst_color_space = color_space, .surface_needs_readback = false, .raster_time = frame.context().raster_time(), .ui_time = frame.context().ui_time(), .texture_registry = frame.context().texture_registry(), .raster_cached_entries = &raster_cache_items_, .display_list_enabled = frame.display_list_builder() != nullptr, // clang-format on }; root_layer_->Preroll(&context); return context.surface_needs_readback; } void LayerTree::TryToRasterCache( const std::vector& raster_cached_items, const PaintContext* paint_context, bool ignore_raster_cache) { unsigned i = 0; const auto item_size = raster_cached_items.size(); while (i < item_size) { auto* item = raster_cached_items[i]; if (item->need_caching()) { // try to cache current layer // If parent failed to cache, just proceed to the next entry // cache current entry, this entry's parent must not cache if (item->TryToPrepareRasterCache(*paint_context, false)) { // if parent cached, then foreach child layer to touch them. for (unsigned j = 0; j < item->child_items(); j++) { auto* child_item = raster_cached_items[i + j + 1]; if (child_item->need_caching()) { child_item->TryToPrepareRasterCache(*paint_context, true); } } i += item->child_items() + 1; continue; } } i++; } } void LayerTree::Paint(CompositorContext::ScopedFrame& frame, bool ignore_raster_cache) const { TRACE_EVENT0("flutter", "LayerTree::Paint"); if (!root_layer_) { FML_LOG(ERROR) << "The scene did not specify any layers to paint."; return; } LayerStateStack state_stack; // DrawCheckerboard is not supported on Impeller. if (checkerboard_offscreen_layers_ && !frame.aiks_context()) { state_stack.set_checkerboard_func(DrawCheckerboard); } DlCanvas* canvas = frame.canvas(); state_stack.set_delegate(canvas); // clear the previous snapshots. LayerSnapshotStore* snapshot_store = nullptr; if (enable_leaf_layer_tracing_) { frame.context().snapshot_store().Clear(); snapshot_store = &frame.context().snapshot_store(); } SkColorSpace* color_space = GetColorSpace(frame.canvas()); RasterCache* cache = ignore_raster_cache ? nullptr : &frame.context().raster_cache(); PaintContext context = { // clang-format off .state_stack = state_stack, .canvas = canvas, .gr_context = frame.gr_context(), .dst_color_space = color_space, .view_embedder = frame.view_embedder(), .raster_time = frame.context().raster_time(), .ui_time = frame.context().ui_time(), .texture_registry = frame.context().texture_registry(), .raster_cache = cache, .layer_snapshot_store = snapshot_store, .enable_leaf_layer_tracing = enable_leaf_layer_tracing_, .aiks_context = frame.aiks_context(), // clang-format on }; if (cache) { cache->EvictUnusedCacheEntries(); TryToRasterCache(raster_cache_items_, &context, ignore_raster_cache); } if (root_layer_->needs_painting(context)) { root_layer_->Paint(context); } } sk_sp LayerTree::Flatten( const SkRect& bounds, const std::shared_ptr& texture_registry, GrDirectContext* gr_context) { TRACE_EVENT0("flutter", "LayerTree::Flatten"); DisplayListBuilder builder(bounds); const FixedRefreshRateStopwatch unused_stopwatch; LayerStateStack preroll_state_stack; // No root surface transformation. So assume identity. preroll_state_stack.set_preroll_delegate(bounds); PrerollContext preroll_context{ // clang-format off .raster_cache = nullptr, .gr_context = gr_context, .view_embedder = nullptr, .state_stack = preroll_state_stack, .dst_color_space = nullptr, .surface_needs_readback = false, .raster_time = unused_stopwatch, .ui_time = unused_stopwatch, .texture_registry = texture_registry, // clang-format on }; LayerStateStack paint_state_stack; paint_state_stack.set_delegate(&builder); PaintContext paint_context = { // clang-format off .state_stack = paint_state_stack, .canvas = &builder, .gr_context = gr_context, .dst_color_space = nullptr, .view_embedder = nullptr, .raster_time = unused_stopwatch, .ui_time = unused_stopwatch, .texture_registry = texture_registry, .raster_cache = nullptr, .layer_snapshot_store = nullptr, .enable_leaf_layer_tracing = false, // clang-format on }; // Even if we don't have a root layer, we still need to create an empty // picture. if (root_layer_) { root_layer_->Preroll(&preroll_context); // The needs painting flag may be set after the preroll. So check it after. if (root_layer_->needs_painting(paint_context)) { root_layer_->Paint(paint_context); } } return builder.Build(); } } // namespace flutter