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_DIFF_CONTEXT_H_
6#define FLUTTER_FLOW_DIFF_CONTEXT_H_
7
8#include <functional>
9#include <map>
10#include <optional>
11#include <vector>
12#include "display_list/utils/dl_matrix_clip_tracker.h"
13#include "flutter/flow/paint_region.h"
14#include "flutter/fml/macros.h"
15#include "third_party/skia/include/core/SkM44.h"
16#include "third_party/skia/include/core/SkMatrix.h"
17#include "third_party/skia/include/core/SkRect.h"
18
19namespace flutter {
20
21class Layer;
22
23// Represents area that needs to be updated in front buffer (frame_damage) and
24// area that is going to be painted to in back buffer (buffer_damage).
25struct Damage {
26 // This is the damage between current and previous frame;
27 // If embedder supports partial update, this is the region that needs to be
28 // repainted.
29 // Corresponds to "surface damage" from EGL_KHR_partial_update.
30 SkIRect frame_damage;
31
32 // Reflects actual change to target framebuffer; This is frame_damage +
33 // damage previously acumulated for target framebuffer.
34 // All drawing will be clipped to this region. Knowing the affected area
35 // upfront may be useful for tile based GPUs.
36 // Corresponds to "buffer damage" from EGL_KHR_partial_update.
37 SkIRect buffer_damage;
38};
39
40// Layer Unique Id to PaintRegion
41using PaintRegionMap = std::map<uint64_t, PaintRegion>;
42
43// Tracks state during tree diffing process and computes resulting damage
44class DiffContext {
45 public:
46 explicit DiffContext(SkISize frame_size,
47 PaintRegionMap& this_frame_paint_region_map,
48 const PaintRegionMap& last_frame_paint_region_map,
49 bool has_raster_cache,
50 bool impeller_enabled);
51
52 // Starts a new subtree.
53 void BeginSubtree();
54
55 // Ends current subtree; All modifications to state (transform, cullrect,
56 // dirty) will be restored
57 void EndSubtree();
58
59 // Creates subtree in current scope and closes it on scope exit
60 class AutoSubtreeRestore {
61 FML_DISALLOW_COPY_ASSIGN_AND_MOVE(AutoSubtreeRestore);
62
63 public:
64 explicit AutoSubtreeRestore(DiffContext* context) : context_(context) {
65 context->BeginSubtree();
66 }
67 ~AutoSubtreeRestore() { context_->EndSubtree(); }
68
69 private:
70 DiffContext* context_;
71 };
72
73 // Pushes additional transform for current subtree
74 void PushTransform(const SkMatrix& transform);
75 void PushTransform(const SkM44& transform);
76
77 // Pushes cull rect for current subtree
78 bool PushCullRect(const SkRect& clip);
79
80 // Function that adjusts layer bounds (in device coordinates) depending
81 // on filter.
82 using FilterBoundsAdjustment = std::function<SkRect(SkRect)>;
83
84 // Pushes filter bounds adjustment to current subtree. Every layer in this
85 // subtree will have bounds adjusted by this function.
86 void PushFilterBoundsAdjustment(const FilterBoundsAdjustment& filter);
87
88 // Instruct DiffContext that current layer will paint with integral transform.
89 void WillPaintWithIntegralTransform() { state_.integral_transform = true; }
90
91 // Returns current transform as SkMatrix.
92 SkMatrix GetTransform3x3() const;
93
94 // Return cull rect for current subtree (in local coordinates).
95 SkRect GetCullRect() const;
96
97 // Sets the dirty flag on current subtree.
98 //
99 // previous_paint_region, which should represent region of previous subtree
100 // at this level will be added to damage area.
101 //
102 // Each paint region added to dirty subtree (through AddPaintRegion) is also
103 // added to damage.
104 void MarkSubtreeDirty(
105 const PaintRegion& previous_paint_region = PaintRegion());
106 void MarkSubtreeDirty(const SkRect& previous_paint_region);
107
108 bool IsSubtreeDirty() const { return state_.dirty; }
109
110 // Marks that current subtree contains a TextureLayer. This is needed to
111 // ensure that we'll Diff the TextureLayer even if inside retained layer.
112 void MarkSubtreeHasTextureLayer();
113
114 // Add layer bounds to current paint region; rect is in "local" (layer)
115 // coordinates.
116 void AddLayerBounds(const SkRect& rect);
117
118 // Add entire paint region of retained layer for current subtree. This can
119 // only be used in subtrees that are not dirty, otherwise ancestor transforms
120 // or clips may result in different paint region.
121 void AddExistingPaintRegion(const PaintRegion& region);
122
123 // The idea of readback region is that if any part of the readback region
124 // needs to be repainted, then the whole readback region must be repainted;
125 //
126 // Readback rect is in screen coordinates.
127 void AddReadbackRegion(const SkIRect& rect);
128
129 // Returns the paint region for current subtree; Each rect in paint region is
130 // in screen coordinates; Once a layer accumulates the paint regions of its
131 // children, this PaintRegion value can be associated with the current layer
132 // using DiffContext::SetLayerPaintRegion.
133 PaintRegion CurrentSubtreeRegion() const;
134
135 // Computes final damage
136 //
137 // additional_damage is the previously accumulated frame_damage for
138 // current framebuffer
139 //
140 // clip_alignment controls the alignment of resulting frame and surface
141 // damage.
142 Damage ComputeDamage(const SkIRect& additional_damage,
143 int horizontal_clip_alignment = 0,
144 int vertical_clip_alignment = 0) const;
145
146 // Adds the region to current damage. Used for removed layers, where instead
147 // of diffing the layer its paint region is direcly added to damage.
148 void AddDamage(const PaintRegion& damage);
149
150 // Associates the paint region with specified layer and current layer tree.
151 // The paint region can not be stored directly in layer itself, because same
152 // retained layer instance can possibly paint in different locations depending
153 // on ancestor layers.
154 void SetLayerPaintRegion(const Layer* layer, const PaintRegion& region);
155
156 // Retrieves the paint region associated with specified layer and previous
157 // frame layer tree.
158 PaintRegion GetOldLayerPaintRegion(const Layer* layer) const;
159
160 // Whether or not a raster cache is being used. If so, we must snap
161 // all transformations to physical pixels if the layer may be raster
162 // cached.
163 bool has_raster_cache() const { return has_raster_cache_; }
164
165 bool impeller_enabled() const { return impeller_enabled_; }
166
167 class Statistics {
168 public:
169 // Picture replaced by different picture
170 void AddNewPicture() { ++new_pictures_; }
171
172 // Picture that would require deep comparison but was considered too complex
173 // to serialize and thus was treated as new picture
174 void AddPictureTooComplexToCompare() { ++pictures_too_complex_to_compare_; }
175
176 // Picture that has identical instance between frames
177 void AddSameInstancePicture() { ++same_instance_pictures_; };
178
179 // Picture that had to be serialized to compare for equality
180 void AddDeepComparePicture() { ++deep_compare_pictures_; }
181
182 // Picture that had to be serialized to compare (different instances),
183 // but were equal
184 void AddDifferentInstanceButEqualPicture() {
185 ++different_instance_but_equal_pictures_;
186 };
187
188 // Logs the statistics to trace counter
189 void LogStatistics();
190
191 private:
192 int new_pictures_ = 0;
193 int pictures_too_complex_to_compare_ = 0;
194 int same_instance_pictures_ = 0;
195 int deep_compare_pictures_ = 0;
196 int different_instance_but_equal_pictures_ = 0;
197 };
198
199 Statistics& statistics() { return statistics_; }
200
201 SkRect MapRect(const SkRect& rect);
202
203 private:
204 struct State {
205 State();
206
207 bool dirty;
208
209 size_t rect_index;
210
211 // In order to replicate paint process closely, DiffContext needs to take
212 // into account that some layers are painted with transform translation
213 // snapped to integral coordinates.
214 //
215 // It's not possible to simply snap the transform itself, because culling
216 // needs to happen with original (unsnapped) transform, just like it does
217 // during paint. This means the integral coordinates must be applied after
218 // culling before painting the layer content (either the layer itself, or
219 // when starting subtree to paint layer children).
220 bool integral_transform;
221
222 // Used to restoring clip tracker when popping state.
223 int clip_tracker_save_count;
224
225 // Whether this subtree has filter bounds adjustment function. If so,
226 // it will need to be removed from stack when subtree is closed.
227 bool has_filter_bounds_adjustment;
228
229 // Whether there is a texture layer in this subtree.
230 bool has_texture;
231 };
232
233 void MakeCurrentTransformIntegral();
234
235 DisplayListMatrixClipTracker clip_tracker_;
236 std::shared_ptr<std::vector<SkRect>> rects_;
237 State state_;
238 SkISize frame_size_;
239 std::vector<State> state_stack_;
240 std::vector<FilterBoundsAdjustment> filter_bounds_adjustment_stack_;
241
242 // Applies the filter bounds adjustment stack on provided rect.
243 // Rect must be in device coordinates.
244 SkRect ApplyFilterBoundsAdjustment(SkRect rect) const;
245
246 SkRect damage_ = SkRect::MakeEmpty();
247
248 PaintRegionMap& this_frame_paint_region_map_;
249 const PaintRegionMap& last_frame_paint_region_map_;
250 bool has_raster_cache_;
251 bool impeller_enabled_;
252
253 void AddDamage(const SkRect& rect);
254
255 void AlignRect(SkIRect& rect,
256 int horizontal_alignment,
257 int vertical_clip_alignment) const;
258
259 struct Readback {
260 // Index of rects_ entry that this readback belongs to. Used to
261 // determine if subtree has any readback
262 size_t position;
263
264 // readback area, in screen coordinates
265 SkIRect rect;
266 };
267
268 std::vector<Readback> readbacks_;
269 Statistics statistics_;
270};
271
272} // namespace flutter
273
274#endif // FLUTTER_FLOW_DIFF_CONTEXT_H_
275

source code of flutter_engine/flutter/flow/diff_context.h