| 1 | // Copyright 2013 The Flutter Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #ifndef FLUTTER_FLOW_LAYERS_LAYER_H_ |
| 6 | #define FLUTTER_FLOW_LAYERS_LAYER_H_ |
| 7 | |
| 8 | #include <algorithm> |
| 9 | #include <memory> |
| 10 | #include <unordered_set> |
| 11 | #include <vector> |
| 12 | |
| 13 | #include "flutter/common/graphics/texture.h" |
| 14 | #include "flutter/display_list/dl_canvas.h" |
| 15 | #include "flutter/flow/diff_context.h" |
| 16 | #include "flutter/flow/embedded_views.h" |
| 17 | #include "flutter/flow/instrumentation.h" |
| 18 | #include "flutter/flow/layer_snapshot_store.h" |
| 19 | #include "flutter/flow/layers/layer_state_stack.h" |
| 20 | #include "flutter/flow/raster_cache.h" |
| 21 | #include "flutter/fml/build_config.h" |
| 22 | #include "flutter/fml/compiler_specific.h" |
| 23 | #include "flutter/fml/logging.h" |
| 24 | #include "flutter/fml/macros.h" |
| 25 | #include "flutter/fml/trace_event.h" |
| 26 | #include "third_party/skia/include/core/SkCanvas.h" |
| 27 | #include "third_party/skia/include/core/SkColor.h" |
| 28 | #include "third_party/skia/include/core/SkColorFilter.h" |
| 29 | #include "third_party/skia/include/core/SkMatrix.h" |
| 30 | #include "third_party/skia/include/core/SkPath.h" |
| 31 | #include "third_party/skia/include/core/SkRRect.h" |
| 32 | #include "third_party/skia/include/core/SkRect.h" |
| 33 | #include "third_party/skia/include/utils/SkNWayCanvas.h" |
| 34 | |
| 35 | class GrDirectContext; |
| 36 | |
| 37 | namespace flutter { |
| 38 | |
| 39 | namespace testing { |
| 40 | class MockLayer; |
| 41 | } // namespace testing |
| 42 | |
| 43 | class ContainerLayer; |
| 44 | class DisplayListLayer; |
| 45 | class PerformanceOverlayLayer; |
| 46 | class TextureLayer; |
| 47 | class RasterCacheItem; |
| 48 | |
| 49 | static constexpr SkRect kGiantRect = SkRect::MakeLTRB(l: -1E9F, t: -1E9F, r: 1E9F, b: 1E9F); |
| 50 | |
| 51 | // This should be an exact copy of the Clip enum in painting.dart. |
| 52 | enum Clip { none, hardEdge, antiAlias, antiAliasWithSaveLayer }; |
| 53 | |
| 54 | struct PrerollContext { |
| 55 | RasterCache* raster_cache; |
| 56 | GrDirectContext* gr_context; |
| 57 | ExternalViewEmbedder* view_embedder; |
| 58 | LayerStateStack& state_stack; |
| 59 | SkColorSpace* dst_color_space; |
| 60 | bool surface_needs_readback; |
| 61 | |
| 62 | // These allow us to paint in the end of subtree Preroll. |
| 63 | const Stopwatch& raster_time; |
| 64 | const Stopwatch& ui_time; |
| 65 | std::shared_ptr<TextureRegistry> texture_registry; |
| 66 | |
| 67 | // These allow us to track properties like elevation, opacity, and the |
| 68 | // presence of a platform view during Preroll. |
| 69 | bool has_platform_view = false; |
| 70 | // These allow us to track properties like elevation, opacity, and the |
| 71 | // presence of a texture layer during Preroll. |
| 72 | bool has_texture_layer = false; |
| 73 | |
| 74 | bool impeller_enabled = false; |
| 75 | |
| 76 | // The list of flags that describe which rendering state attributes |
| 77 | // (such as opacity, ColorFilter, ImageFilter) a given layer can |
| 78 | // render itself without requiring the parent to perform a protective |
| 79 | // saveLayer with those attributes. |
| 80 | // For containers, the flags will be set to the intersection (logical |
| 81 | // and) of all of the state bits that all of the children can render |
| 82 | // or to 0 if some of the children overlap and, as such, cannot apply |
| 83 | // those attributes individually and separately. |
| 84 | int renderable_state_flags = 0; |
| 85 | |
| 86 | std::vector<RasterCacheItem*>* raster_cached_entries; |
| 87 | }; |
| 88 | |
| 89 | struct PaintContext { |
| 90 | // When splitting the scene into multiple canvases (e.g when embedding |
| 91 | // a platform view on iOS) during the paint traversal we apply any state |
| 92 | // changes which affect children (i.e. saveLayer attributes) to the |
| 93 | // state_stack and any local rendering state changes for leaf layers to |
| 94 | // the canvas or builder. |
| 95 | // When we switch a canvas or builder (when painting a PlatformViewLayer) |
| 96 | // the new canvas receives all of the stateful changes from the state_stack |
| 97 | // to put it into the exact same state that the outgoing canvas had at the |
| 98 | // time it was swapped out. |
| 99 | // The state stack lazily applies saveLayer calls to its current canvas, |
| 100 | // allowing leaf layers to report that they can handle rendering some of |
| 101 | // its state attributes themselves via the |applyState| method. |
| 102 | LayerStateStack& state_stack; |
| 103 | DlCanvas* canvas; |
| 104 | |
| 105 | // Whether current canvas is an overlay canvas. Used to determine if the |
| 106 | // raster cache is painting to a surface that will be displayed above a |
| 107 | // platform view, in which case it will attempt to preserve the R-Tree. |
| 108 | bool rendering_above_platform_view = false; |
| 109 | |
| 110 | GrDirectContext* gr_context; |
| 111 | SkColorSpace* dst_color_space; |
| 112 | ExternalViewEmbedder* view_embedder; |
| 113 | const Stopwatch& raster_time; |
| 114 | const Stopwatch& ui_time; |
| 115 | std::shared_ptr<TextureRegistry> texture_registry; |
| 116 | const RasterCache* raster_cache; |
| 117 | |
| 118 | // Snapshot store to collect leaf layer snapshots. The store is non-null |
| 119 | // only when leaf layer tracing is enabled. |
| 120 | LayerSnapshotStore* layer_snapshot_store = nullptr; |
| 121 | bool enable_leaf_layer_tracing = false; |
| 122 | bool impeller_enabled = false; |
| 123 | impeller::AiksContext* aiks_context; |
| 124 | }; |
| 125 | |
| 126 | // Represents a single composited layer. Created on the UI thread but then |
| 127 | // subsequently used on the Rasterizer thread. |
| 128 | class Layer { |
| 129 | public: |
| 130 | // The state attribute flags that represent which attributes a |
| 131 | // layer can render if it plans to use a saveLayer call in its |
| 132 | // |Paint| method. |
| 133 | static constexpr int kSaveLayerRenderFlags = |
| 134 | LayerStateStack::kCallerCanApplyOpacity | |
| 135 | LayerStateStack::kCallerCanApplyColorFilter | |
| 136 | LayerStateStack::kCallerCanApplyImageFilter; |
| 137 | |
| 138 | // The state attribute flags that represent which attributes a |
| 139 | // layer can render if it will be rendering its content/children |
| 140 | // from a cached representation. |
| 141 | static constexpr int kRasterCacheRenderFlags = |
| 142 | LayerStateStack::kCallerCanApplyOpacity; |
| 143 | |
| 144 | Layer(); |
| 145 | virtual ~Layer(); |
| 146 | |
| 147 | void AssignOldLayer(Layer* old_layer) { |
| 148 | original_layer_id_ = old_layer->original_layer_id_; |
| 149 | } |
| 150 | |
| 151 | // Used to establish link between old layer and new layer that replaces it. |
| 152 | // If this method returns true, it is assumed that this layer replaces the old |
| 153 | // layer in tree and is able to diff with it. |
| 154 | virtual bool IsReplacing(DiffContext* context, const Layer* old_layer) const { |
| 155 | return original_layer_id_ == old_layer->original_layer_id_; |
| 156 | } |
| 157 | |
| 158 | // Performs diff with given layer |
| 159 | virtual void Diff(DiffContext* context, const Layer* old_layer) {} |
| 160 | |
| 161 | // Used when diffing retained layer; In case the layer is identical, it |
| 162 | // doesn't need to be diffed, but the paint region needs to be stored in diff |
| 163 | // context so that it can be used in next frame |
| 164 | virtual void PreservePaintRegion(DiffContext* context) { |
| 165 | // retained layer means same instance so 'this' is used to index into both |
| 166 | // current and old region |
| 167 | context->SetLayerPaintRegion(layer: this, region: context->GetOldLayerPaintRegion(layer: this)); |
| 168 | } |
| 169 | |
| 170 | virtual void Preroll(PrerollContext* context) = 0; |
| 171 | |
| 172 | // Used during Preroll by layers that employ a saveLayer to manage the |
| 173 | // PrerollContext settings with values affected by the saveLayer mechanism. |
| 174 | // This object must be created before calling Preroll on the children to |
| 175 | // set up the state for the children and then restore the state upon |
| 176 | // destruction. |
| 177 | class AutoPrerollSaveLayerState { |
| 178 | public: |
| 179 | [[nodiscard]] static AutoPrerollSaveLayerState Create( |
| 180 | PrerollContext* preroll_context, |
| 181 | bool save_layer_is_active = true, |
| 182 | bool layer_itself_performs_readback = false); |
| 183 | |
| 184 | ~AutoPrerollSaveLayerState(); |
| 185 | |
| 186 | private: |
| 187 | AutoPrerollSaveLayerState(PrerollContext* preroll_context, |
| 188 | bool save_layer_is_active, |
| 189 | bool layer_itself_performs_readback); |
| 190 | |
| 191 | PrerollContext* preroll_context_; |
| 192 | bool save_layer_is_active_; |
| 193 | bool layer_itself_performs_readback_; |
| 194 | |
| 195 | bool prev_surface_needs_readback_; |
| 196 | }; |
| 197 | |
| 198 | virtual void Paint(PaintContext& context) const = 0; |
| 199 | |
| 200 | virtual void PaintChildren(PaintContext& context) const { FML_DCHECK(false); } |
| 201 | |
| 202 | bool subtree_has_platform_view() const { return subtree_has_platform_view_; } |
| 203 | void set_subtree_has_platform_view(bool value) { |
| 204 | subtree_has_platform_view_ = value; |
| 205 | } |
| 206 | |
| 207 | // Returns the paint bounds in the layer's local coordinate system |
| 208 | // as determined during Preroll(). The bounds should include any |
| 209 | // transform, clip or distortions performed by the layer itself, |
| 210 | // but not any similar modifications inherited from its ancestors. |
| 211 | const SkRect& paint_bounds() const { return paint_bounds_; } |
| 212 | |
| 213 | // This must be set by the time Preroll() returns otherwise the layer will |
| 214 | // be assumed to have empty paint bounds (paints no content). |
| 215 | // The paint bounds should be independent of the context outside of this |
| 216 | // layer as the layer may be painted under different conditions than |
| 217 | // the Preroll context. The most common example of this condition is |
| 218 | // that we might Preroll the layer with a cull_rect established by a |
| 219 | // clip layer above it but then we might be asked to paint anyway if |
| 220 | // another layer above us needs to cache its children. During the |
| 221 | // paint operation that arises due to the caching, the clip will |
| 222 | // be the bounds of the layer needing caching, not the cull_rect |
| 223 | // that we saw in the overall Preroll operation. |
| 224 | void set_paint_bounds(const SkRect& paint_bounds) { |
| 225 | paint_bounds_ = paint_bounds; |
| 226 | } |
| 227 | |
| 228 | // Determines if the layer has any content. |
| 229 | bool is_empty() const { return paint_bounds_.isEmpty(); } |
| 230 | |
| 231 | // Determines if the Paint() method is necessary based on the properties |
| 232 | // of the indicated PaintContext object. |
| 233 | bool needs_painting(PaintContext& context) const { |
| 234 | if (subtree_has_platform_view_) { |
| 235 | // Workaround for the iOS embedder. The iOS embedder expects that |
| 236 | // if we preroll it, then we will later call its Paint() method. |
| 237 | // Now that we preroll all layers without any culling, we may |
| 238 | // call its Preroll() without calling its Paint(). For now, we |
| 239 | // will not perform paint culling on any subtree that has a |
| 240 | // platform view. |
| 241 | // See https://github.com/flutter/flutter/issues/81419 |
| 242 | return true; |
| 243 | } |
| 244 | return !context.state_stack.painting_is_nop() && |
| 245 | !context.state_stack.content_culled(content_bounds: paint_bounds_); |
| 246 | } |
| 247 | |
| 248 | // Propagated unique_id of the first layer in "chain" of replacement layers |
| 249 | // that can be diffed. |
| 250 | uint64_t original_layer_id() const { return original_layer_id_; } |
| 251 | |
| 252 | uint64_t unique_id() const { return unique_id_; } |
| 253 | |
| 254 | virtual RasterCacheKeyID caching_key_id() const { |
| 255 | return RasterCacheKeyID(unique_id_, RasterCacheKeyType::kLayer); |
| 256 | } |
| 257 | virtual const ContainerLayer* as_container_layer() const { return nullptr; } |
| 258 | virtual const DisplayListLayer* as_display_list_layer() const { |
| 259 | return nullptr; |
| 260 | } |
| 261 | virtual const TextureLayer* as_texture_layer() const { return nullptr; } |
| 262 | virtual const PerformanceOverlayLayer* as_performance_overlay_layer() const { |
| 263 | return nullptr; |
| 264 | } |
| 265 | virtual const testing::MockLayer* as_mock_layer() const { return nullptr; } |
| 266 | |
| 267 | private: |
| 268 | SkRect paint_bounds_; |
| 269 | uint64_t unique_id_; |
| 270 | uint64_t original_layer_id_; |
| 271 | bool subtree_has_platform_view_; |
| 272 | |
| 273 | static uint64_t NextUniqueID(); |
| 274 | |
| 275 | FML_DISALLOW_COPY_AND_ASSIGN(Layer); |
| 276 | }; |
| 277 | |
| 278 | } // namespace flutter |
| 279 | |
| 280 | #endif // FLUTTER_FLOW_LAYERS_LAYER_H_ |
| 281 | |