Flutter Engine
 
Loading...
Searching...
No Matches
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>
14#include "flutter/fml/macros.h"
15
16namespace flutter {
17
18class Layer;
19
20// Represents area that needs to be updated in front buffer (frame_damage) and
21// area that is going to be painted to in back buffer (buffer_damage).
22struct Damage {
23 // This is the damage between current and previous frame;
24 // If embedder supports partial update, this is the region that needs to be
25 // repainted.
26 // Corresponds to "surface damage" from EGL_KHR_partial_update.
28
29 // Reflects actual change to target framebuffer; This is frame_damage +
30 // damage previously acumulated for target framebuffer.
31 // All drawing will be clipped to this region. Knowing the affected area
32 // upfront may be useful for tile based GPUs.
33 // Corresponds to "buffer damage" from EGL_KHR_partial_update.
35};
36
37// Layer Unique Id to PaintRegion
38using PaintRegionMap = std::map<uint64_t, PaintRegion>;
39
40// Tracks state during tree diffing process and computes resulting damage
42 public:
43 explicit DiffContext(DlISize frame_size,
44 PaintRegionMap& this_frame_paint_region_map,
45 const PaintRegionMap& last_frame_paint_region_map,
47 bool impeller_enabled);
48
49 // Starts a new subtree.
50 void BeginSubtree();
51
52 // Ends current subtree; All modifications to state (transform, cullrect,
53 // dirty) will be restored
54 void EndSubtree();
55
56 // Creates subtree in current scope and closes it on scope exit
59
60 public:
61 explicit AutoSubtreeRestore(DiffContext* context) : context_(context) {
62 context->BeginSubtree();
63 }
65
66 private:
67 DiffContext* context_;
68 };
69
70 // Pushes additional transform for current subtree
71 void PushTransform(const DlMatrix& transform);
72
73 // Pushes cull rect for current subtree
74 bool PushCullRect(const DlRect& clip);
75
76 // Function that adjusts layer bounds (in device coordinates) depending
77 // on filter.
78 using FilterBoundsAdjustment = std::function<DlRect(DlRect)>;
79
80 // Pushes filter bounds adjustment to current subtree. Every layer in this
81 // subtree will have bounds adjusted by this function.
83
84 // Instruct DiffContext that current layer will paint with integral transform.
85 void WillPaintWithIntegralTransform() { state_.integral_transform = true; }
86
87 // Returns current transform as DlMatrix.
88 const DlMatrix& GetMatrix() const;
89
90 // Return cull rect for current subtree (in local coordinates).
91 DlRect GetCullRect() const;
92
93 // Sets the dirty flag on current subtree.
94 //
95 // previous_paint_region, which should represent region of previous subtree
96 // at this level will be added to damage area.
97 //
98 // Each paint region added to dirty subtree (through AddPaintRegion) is also
99 // added to damage.
100 void MarkSubtreeDirty(
101 const PaintRegion& previous_paint_region = PaintRegion());
102 void MarkSubtreeDirty(const DlRect& previous_paint_region);
103
104 bool IsSubtreeDirty() const { return state_.dirty; }
105
106 // Marks that current subtree contains a TextureLayer. This is needed to
107 // ensure that we'll Diff the TextureLayer even if inside retained layer.
109
110 // Add layer bounds to current paint region; rect is in "local" (layer)
111 // coordinates.
112 void AddLayerBounds(const DlRect& rect);
113
114 // Add entire paint region of retained layer for current subtree. This can
115 // only be used in subtrees that are not dirty, otherwise ancestor transforms
116 // or clips may result in different paint region.
117 void AddExistingPaintRegion(const PaintRegion& region);
118
119 // The idea of readback region is that if any part of the readback region
120 // needs to be repainted, then the whole readback region must be repainted;
121 //
122 // paint_rect - rectangle where the filter paints contents (in screen
123 // coordinates)
124 // readback_rect - rectangle where the filter samples from (in screen
125 // coordinates)
126 void AddReadbackRegion(const DlIRect& paint_rect,
127 const DlIRect& readback_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.
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 DlIRect& 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
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
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 DlRect MapRect(const DlRect& rect);
202
203 private:
204 struct State {
205 State();
206
207 bool dirty = false;
208
209 size_t rect_index = 0;
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 = false;
221
222 // Current transform and clip for the layer
223 DisplayListMatrixClipState matrix_clip;
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 = false;
228
229 // Whether there is a texture layer in this subtree.
230 bool has_texture = false;
231 };
232
233 void MakeTransformIntegral(DisplayListMatrixClipState& matrix_clip);
234
235 std::shared_ptr<std::vector<DlRect>> rects_;
236 State state_;
237 DlISize frame_size_;
238 std::vector<State> state_stack_;
239 std::vector<FilterBoundsAdjustment> filter_bounds_adjustment_stack_;
240
241 // Applies the filter bounds adjustment stack on provided rect.
242 // Rect must be in device coordinates.
243 DlRect ApplyFilterBoundsAdjustment(DlRect rect) const;
244
245 DlRect damage_;
246
247 PaintRegionMap& this_frame_paint_region_map_;
248 const PaintRegionMap& last_frame_paint_region_map_;
249 bool has_raster_cache_;
250 bool impeller_enabled_;
251
252 void AddDamage(const DlRect& rect);
253
254 void AlignRect(DlIRect& rect,
255 int horizontal_alignment,
256 int vertical_clip_alignment) const;
257
258 struct Readback {
259 // Index of rects_ entry that this readback belongs to. Used to
260 // determine if subtree has any readback
261 size_t position;
262
263 // Paint region of the filter performing readback, in screen coordinates.
264 DlIRect paint_rect;
265
266 // Readback area of the filter, in screen coordinates.
267 DlIRect readback_rect;
268 };
269
270 std::vector<Readback> readbacks_;
271 Statistics statistics_;
272};
273
274} // namespace flutter
275
276#endif // FLUTTER_FLOW_DIFF_CONTEXT_H_
DlRect GetCullRect() const
std::function< DlRect(DlRect)> FilterBoundsAdjustment
void WillPaintWithIntegralTransform()
bool PushCullRect(const DlRect &clip)
bool impeller_enabled() const
DlRect MapRect(const DlRect &rect)
Damage ComputeDamage(const DlIRect &additional_damage, int horizontal_clip_alignment=0, int vertical_clip_alignment=0) const
void SetLayerPaintRegion(const Layer *layer, const PaintRegion &region)
void MarkSubtreeDirty(const PaintRegion &previous_paint_region=PaintRegion())
Statistics & statistics()
void AddReadbackRegion(const DlIRect &paint_rect, const DlIRect &readback_rect)
void AddDamage(const PaintRegion &damage)
PaintRegion CurrentSubtreeRegion() const
void AddExistingPaintRegion(const PaintRegion &region)
void PushFilterBoundsAdjustment(const FilterBoundsAdjustment &filter)
bool has_raster_cache() const
PaintRegion GetOldLayerPaintRegion(const Layer *layer) const
const DlMatrix & GetMatrix() const
bool IsSubtreeDirty() const
void AddLayerBounds(const DlRect &rect)
void PushTransform(const DlMatrix &transform)
#define FML_DISALLOW_COPY_ASSIGN_AND_MOVE(TypeName)
Definition macros.h:31
std::map< uint64_t, PaintRegion > PaintRegionMap
impeller::Rect DlRect
impeller::ISize32 DlISize
impeller::IRect32 DlIRect
DlIRect buffer_damage
DlIRect frame_damage
A 4x4 matrix using column-major storage.
Definition matrix.h:37