Flutter Engine
The Flutter Engine
diff_context.h
Go to the documentation of this file.
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>
13#include "flutter/flow/paint_region.h"
14#include "flutter/fml/macros.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.
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.
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
45 public:
46 explicit DiffContext(SkISize frame_size,
47 PaintRegionMap& this_frame_paint_region_map,
48 const PaintRegionMap& last_frame_paint_region_map,
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
61 FML_DISALLOW_COPY_ASSIGN_AND_MOVE(AutoSubtreeRestore);
62
63 public:
64 explicit AutoSubtreeRestore(DiffContext* context) : context_(context) {
65 context->BeginSubtree();
66 }
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.
83
84 // Pushes filter bounds adjustment to current subtree. Every layer in this
85 // subtree will have bounds adjusted by this function.
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.
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.
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.
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 // paint_rect - rectangle where the filter paints contents (in screen
127 // coordinates)
128 // readback_rect - rectangle where the filter samples from (in screen
129 // coordinates)
130 void AddReadbackRegion(const SkIRect& paint_rect,
131 const SkIRect& readback_rect);
132
133 // Returns the paint region for current subtree; Each rect in paint region is
134 // in screen coordinates; Once a layer accumulates the paint regions of its
135 // children, this PaintRegion value can be associated with the current layer
136 // using DiffContext::SetLayerPaintRegion.
138
139 // Computes final damage
140 //
141 // additional_damage is the previously accumulated frame_damage for
142 // current framebuffer
143 //
144 // clip_alignment controls the alignment of resulting frame and surface
145 // damage.
146 Damage ComputeDamage(const SkIRect& additional_damage,
147 int horizontal_clip_alignment = 0,
148 int vertical_clip_alignment = 0) const;
149
150 // Adds the region to current damage. Used for removed layers, where instead
151 // of diffing the layer its paint region is direcly added to damage.
152 void AddDamage(const PaintRegion& damage);
153
154 // Associates the paint region with specified layer and current layer tree.
155 // The paint region can not be stored directly in layer itself, because same
156 // retained layer instance can possibly paint in different locations depending
157 // on ancestor layers.
158 void SetLayerPaintRegion(const Layer* layer, const PaintRegion& region);
159
160 // Retrieves the paint region associated with specified layer and previous
161 // frame layer tree.
162 PaintRegion GetOldLayerPaintRegion(const Layer* layer) const;
163
164 // Whether or not a raster cache is being used. If so, we must snap
165 // all transformations to physical pixels if the layer may be raster
166 // cached.
167 bool has_raster_cache() const { return has_raster_cache_; }
168
169 bool impeller_enabled() const { return impeller_enabled_; }
170
172 public:
173 // Picture replaced by different picture
174 void AddNewPicture() { ++new_pictures_; }
175
176 // Picture that would require deep comparison but was considered too complex
177 // to serialize and thus was treated as new picture
178 void AddPictureTooComplexToCompare() { ++pictures_too_complex_to_compare_; }
179
180 // Picture that has identical instance between frames
181 void AddSameInstancePicture() { ++same_instance_pictures_; };
182
183 // Picture that had to be serialized to compare for equality
184 void AddDeepComparePicture() { ++deep_compare_pictures_; }
185
186 // Picture that had to be serialized to compare (different instances),
187 // but were equal
189 ++different_instance_but_equal_pictures_;
190 };
191
192 // Logs the statistics to trace counter
193 void LogStatistics();
194
195 private:
196 int new_pictures_ = 0;
197 int pictures_too_complex_to_compare_ = 0;
198 int same_instance_pictures_ = 0;
199 int deep_compare_pictures_ = 0;
200 int different_instance_but_equal_pictures_ = 0;
201 };
202
203 Statistics& statistics() { return statistics_; }
204
205 SkRect MapRect(const SkRect& rect);
206
207 private:
208 struct State {
209 State();
210
211 bool dirty = false;
212
213 size_t rect_index = 0;
214
215 // In order to replicate paint process closely, DiffContext needs to take
216 // into account that some layers are painted with transform translation
217 // snapped to integral coordinates.
218 //
219 // It's not possible to simply snap the transform itself, because culling
220 // needs to happen with original (unsnapped) transform, just like it does
221 // during paint. This means the integral coordinates must be applied after
222 // culling before painting the layer content (either the layer itself, or
223 // when starting subtree to paint layer children).
224 bool integral_transform = false;
225
226 // Current transform and clip for the layer
227 DisplayListMatrixClipState matrix_clip;
228
229 // Whether this subtree has filter bounds adjustment function. If so,
230 // it will need to be removed from stack when subtree is closed.
231 bool has_filter_bounds_adjustment = false;
232
233 // Whether there is a texture layer in this subtree.
234 bool has_texture = false;
235 };
236
237 void MakeTransformIntegral(DisplayListMatrixClipState& matrix_clip);
238
239 std::shared_ptr<std::vector<SkRect>> rects_;
240 State state_;
241 SkISize frame_size_;
242 std::vector<State> state_stack_;
243 std::vector<FilterBoundsAdjustment> filter_bounds_adjustment_stack_;
244
245 // Applies the filter bounds adjustment stack on provided rect.
246 // Rect must be in device coordinates.
247 SkRect ApplyFilterBoundsAdjustment(SkRect rect) const;
248
249 SkRect damage_ = SkRect::MakeEmpty();
250
251 PaintRegionMap& this_frame_paint_region_map_;
252 const PaintRegionMap& last_frame_paint_region_map_;
253 bool has_raster_cache_;
254 bool impeller_enabled_;
255
256 void AddDamage(const SkRect& rect);
257
258 void AlignRect(SkIRect& rect,
259 int horizontal_alignment,
260 int vertical_clip_alignment) const;
261
262 struct Readback {
263 // Index of rects_ entry that this readback belongs to. Used to
264 // determine if subtree has any readback
265 size_t position;
266
267 // Paint region of the filter performing readback, in screen coordinates.
268 SkIRect paint_rect;
269
270 // Readback area of the filter, in screen coordinates.
271 SkIRect readback_rect;
272 };
273
274 std::vector<Readback> readbacks_;
275 Statistics statistics_;
276};
277
278} // namespace flutter
279
280#endif // FLUTTER_FLOW_DIFF_CONTEXT_H_
static SkPath clip(const SkPath &path, const SkHalfPlane &plane)
Definition: SkPath.cpp:3892
Definition: SkM44.h:150
AutoSubtreeRestore(DiffContext *context)
Definition: diff_context.h:64
SkMatrix GetTransform3x3() const
void PushTransform(const SkMatrix &transform)
Definition: diff_context.cc:49
void WillPaintWithIntegralTransform()
Definition: diff_context.h:89
bool impeller_enabled() const
Definition: diff_context.h:169
void AddLayerBounds(const SkRect &rect)
void SetLayerPaintRegion(const Layer *layer, const PaintRegion &region)
void MarkSubtreeDirty(const PaintRegion &previous_paint_region=PaintRegion())
Statistics & statistics()
Definition: diff_context.h:203
void AddDamage(const PaintRegion &damage)
PaintRegion CurrentSubtreeRegion() const
void AddExistingPaintRegion(const PaintRegion &region)
void PushFilterBoundsAdjustment(const FilterBoundsAdjustment &filter)
Definition: diff_context.cc:76
bool has_raster_cache() const
Definition: diff_context.h:167
PaintRegion GetOldLayerPaintRegion(const Layer *layer) const
SkRect MapRect(const SkRect &rect)
bool PushCullRect(const SkRect &clip)
Damage ComputeDamage(const SkIRect &additional_damage, int horizontal_clip_alignment=0, int vertical_clip_alignment=0) const
void MarkSubtreeHasTextureLayer()
bool IsSubtreeDirty() const
Definition: diff_context.h:108
void AddReadbackRegion(const SkIRect &paint_rect, const SkIRect &readback_rect)
std::function< SkRect(SkRect)> FilterBoundsAdjustment
Definition: diff_context.h:82
DiffContext(SkISize frame_size, PaintRegionMap &this_frame_paint_region_map, const PaintRegionMap &last_frame_paint_region_map, bool has_raster_cache, bool impeller_enabled)
Definition: diff_context.cc:12
SkRect GetCullRect() const
Dart_NativeFunction function
Definition: fuchsia.cc:51
ClipOpAndAA opAA SkRegion region
Definition: SkRecords.h:238
sk_sp< SkBlender > blender SkRect rect
Definition: SkRecords.h:350
std::map< uint64_t, PaintRegion > PaintRegionMap
Definition: diff_context.h:41
static SkColor4f transform(SkColor4f c, SkColorSpace *src, SkColorSpace *dst)
Definition: p3.cpp:47
Definition: SkRect.h:32
Definition: SkSize.h:16
static constexpr SkRect MakeEmpty()
Definition: SkRect.h:595
SkIRect buffer_damage
Definition: diff_context.h:37
SkIRect frame_damage
Definition: diff_context.h:30