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