Flutter Engine
diff_context.cc
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 #include "flutter/flow/diff_context.h"
6 #include "flutter/flow/layers/layer.h"
7 
8 namespace flutter {
9 
10 DiffContext::DiffContext(SkISize frame_size,
11  double frame_device_pixel_ratio,
12  PaintRegionMap& this_frame_paint_region_map,
13  const PaintRegionMap& last_frame_paint_region_map)
14  : rects_(std::make_shared<std::vector<SkRect>>()),
15  frame_size_(frame_size),
16  frame_device_pixel_ratio_(frame_device_pixel_ratio),
17  this_frame_paint_region_map_(this_frame_paint_region_map),
18  last_frame_paint_region_map_(last_frame_paint_region_map) {}
19 
21  state_stack_.push_back(state_);
22  state_.rect_index_ = rects_->size();
23  state_.has_filter_bounds_adjustment = false;
24  state_.has_texture = false;
25  if (state_.transform_override) {
26  state_.transform = *state_.transform_override;
27  state_.transform_override = std::nullopt;
28  }
29 }
30 
32  FML_DCHECK(!state_stack_.empty());
33  if (state_.has_filter_bounds_adjustment) {
34  filter_bounds_adjustment_stack_.pop_back();
35  }
36  state_ = std::move(state_stack_.back());
37  state_stack_.pop_back();
38 }
39 
41  : dirty(false),
42  cull_rect(kGiantRect),
43  rect_index_(0),
44  has_filter_bounds_adjustment(false),
45  has_texture(false) {}
46 
47 void DiffContext::PushTransform(const SkMatrix& transform) {
48  state_.transform.preConcat(transform);
49 }
50 
51 void DiffContext::SetTransform(const SkMatrix& transform) {
52  state_.transform_override = transform;
53 }
54 
56  FML_DCHECK(state_.has_filter_bounds_adjustment == false);
57  state_.has_filter_bounds_adjustment = true;
58  filter_bounds_adjustment_stack_.push_back(filter);
59 }
60 
61 SkRect DiffContext::ApplyFilterBoundsAdjustment(SkRect rect) const {
62  // Apply filter bounds adjustment in reverse order
63  for (auto i = filter_bounds_adjustment_stack_.rbegin();
64  i != filter_bounds_adjustment_stack_.rend(); ++i) {
65  rect = (*i)(rect);
66  }
67  return rect;
68 }
69 
71  const SkIRect& accumulated_buffer_damage) const {
72  SkRect buffer_damage = SkRect::Make(accumulated_buffer_damage);
73  buffer_damage.join(damage_);
74  SkRect frame_damage(damage_);
75 
76  for (const auto& r : readbacks_) {
77  SkRect rect = SkRect::Make(r.rect);
78  if (rect.intersects(frame_damage)) {
79  frame_damage.join(rect);
80  }
81  if (rect.intersects(buffer_damage)) {
82  buffer_damage.join(rect);
83  }
84  }
85 
86  Damage res;
87  buffer_damage.roundOut(&res.buffer_damage);
88  frame_damage.roundOut(&res.frame_damage);
89 
90  SkIRect frame_clip = SkIRect::MakeSize(frame_size_);
91  res.buffer_damage.intersect(frame_clip);
92  res.frame_damage.intersect(frame_clip);
93  return res;
94 }
95 
96 bool DiffContext::PushCullRect(const SkRect& clip) {
97  SkRect cull_rect = state_.transform.mapRect(clip);
98  return state_.cull_rect.intersect(cull_rect);
99 }
100 
101 SkRect DiffContext::GetCullRect() const {
102  SkMatrix inverse_transform;
103  // Perspective projections don't produce rectangles that are useful for
104  // culling for some reason.
105  if (!state_.transform.hasPerspective() &&
106  state_.transform.invert(&inverse_transform)) {
107  return inverse_transform.mapRect(state_.cull_rect);
108  } else {
109  return kGiantRect;
110  }
111 }
112 
113 void DiffContext::MarkSubtreeDirty(const PaintRegion& previous_paint_region) {
115  if (previous_paint_region.is_valid()) {
116  AddDamage(previous_paint_region);
117  }
118  state_.dirty = true;
119 }
120 
121 void DiffContext::MarkSubtreeDirty(const SkRect& previous_paint_region) {
123  AddDamage(previous_paint_region);
124  state_.dirty = true;
125 }
126 
127 void DiffContext::AddLayerBounds(const SkRect& rect) {
128  // During painting we cull based on non-overriden transform and then
129  // override the transform right before paint. Do the same thing here to get
130  // identical paint rect.
131  auto transformed_rect =
132  ApplyFilterBoundsAdjustment(state_.transform.mapRect(rect));
133  if (transformed_rect.intersects(state_.cull_rect)) {
134  auto paint_rect = state_.transform_override
135  ? ApplyFilterBoundsAdjustment(
136  state_.transform_override->mapRect(rect))
137  : transformed_rect;
138  rects_->push_back(paint_rect);
139  if (IsSubtreeDirty()) {
140  AddDamage(paint_rect);
141  }
142  }
143 }
144 
146  // Set the has_texture flag on current state and all parent states. That
147  // way we'll know that we can't skip diff for retained layers because
148  // they contain a TextureLayer.
149  for (auto& state : state_stack_) {
150  state.has_texture = true;
151  }
152  state_.has_texture = true;
153 }
154 
156  // Adding paint region for retained layer implies that current subtree is not
157  // dirty, so we know, for example, that the inherited transforms must match
159  if (region.is_valid()) {
160  rects_->insert(rects_->end(), region.begin(), region.end());
161  }
162 }
163 
164 void DiffContext::AddReadbackRegion(const SkIRect& rect) {
165  Readback readback;
166  readback.rect = rect;
167  readback.position = rects_->size();
168  // Push empty rect as a placeholder for position in current subtree
169  rects_->push_back(SkRect::MakeEmpty());
170  readbacks_.push_back(std::move(readback));
171 }
172 
174  bool has_readback = std::any_of(
175  readbacks_.begin(), readbacks_.end(),
176  [&](const Readback& r) { return r.position >= state_.rect_index_; });
177  return PaintRegion(rects_, state_.rect_index_, rects_->size(), has_readback,
178  state_.has_texture);
179 }
180 
181 void DiffContext::AddDamage(const PaintRegion& damage) {
182  FML_DCHECK(damage.is_valid());
183  for (const auto& r : damage) {
184  damage_.join(r);
185  }
186 }
187 
188 void DiffContext::AddDamage(const SkRect& rect) {
189  damage_.join(rect);
190 }
191 
193  const PaintRegion& region) {
194  this_frame_paint_region_map_[layer->unique_id()] = region;
195 }
196 
198  auto i = last_frame_paint_region_map_.find(layer->unique_id());
199  if (i != last_frame_paint_region_map_.end()) {
200  return i->second;
201  } else {
202  // This is valid when Layer::PreservePaintRegion is called for retained
203  // layer with zero sized parent clip (these layers are not diffed)
204  return PaintRegion();
205  }
206 }
207 
209 #if !FLUTTER_RELEASE
210  FML_TRACE_COUNTER("flutter", "DiffContext", reinterpret_cast<int64_t>(this),
211  "NewPictures", new_pictures_, "PicturesTooComplexToCompare",
212  pictures_too_complex_to_compare_, "DeepComparePictures",
213  deep_compare_pictures_, "SameInstancePictures",
214  same_instance_pictures_,
215  "DifferentInstanceButEqualPictures",
216  different_instance_but_equal_pictures_);
217 #endif // !FLUTTER_RELEASE
218 }
219 
220 } // namespace flutter
bool PushCullRect(const SkRect &clip)
Definition: diff_context.cc:96
void SetLayerPaintRegion(const Layer *layer, const PaintRegion &region)
#define FML_DCHECK(condition)
Definition: logging.h:86
#define FML_TRACE_COUNTER(category_group, name, counter_id, arg1,...)
Definition: trace_event.h:69
std::map< uint64_t, PaintRegion > PaintRegionMap
Definition: diff_context.h:40
void PushFilterBoundsAdjustment(FilterBoundsAdjustment filter)
Definition: diff_context.cc:55
void AddDamage(const PaintRegion &damage)
Definition: ref_ptr.h:255
void AddLayerBounds(const SkRect &rect)
static constexpr SkRect kGiantRect
Definition: layer.h:37
std::vector< SkRect >::const_iterator begin() const
Definition: paint_region.h:36
PaintRegion GetOldLayerPaintRegion(const Layer *layer) const
void AddExistingPaintRegion(const PaintRegion &region)
Damage ComputeDamage(const SkIRect &additional_damage) const
Definition: diff_context.cc:70
void PushTransform(const SkMatrix &transform)
Definition: diff_context.cc:47
std::function< SkRect(SkRect)> FilterBoundsAdjustment
Definition: diff_context.h:79
SkRect GetCullRect() const
bool IsSubtreeDirty() const
Definition: diff_context.h:105
bool is_valid() const
Definition: paint_region.h:49
void SetTransform(const SkMatrix &transform)
Definition: diff_context.cc:51
uint64_t unique_id() const
Definition: layer.h:330
void AddReadbackRegion(const SkIRect &rect)
SkIRect buffer_damage
Definition: diff_context.h:36
void MarkSubtreeHasTextureLayer()
PaintRegion CurrentSubtreeRegion() const
DiffContext(SkISize frame_size, double device_pixel_aspect_ratio, PaintRegionMap &this_frame_paint_region_map, const PaintRegionMap &last_frame_paint_region_map)
Definition: diff_context.cc:10
std::vector< SkRect >::const_iterator end() const
Definition: paint_region.h:41
void MarkSubtreeDirty(const PaintRegion &previous_paint_region=PaintRegion())
AtkStateType state
SkIRect frame_damage
Definition: diff_context.h:29