Flutter Engine
The 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
7#include "flutter/flow/layers/layer.h"
8#include "flutter/flow/raster_cache_util.h"
9
10namespace flutter {
11
13 PaintRegionMap& this_frame_paint_region_map,
14 const PaintRegionMap& last_frame_paint_region_map,
15 bool has_raster_cache,
16 bool impeller_enabled)
17 : rects_(std::make_shared<std::vector<SkRect>>()),
18 frame_size_(frame_size),
19 this_frame_paint_region_map_(this_frame_paint_region_map),
20 last_frame_paint_region_map_(last_frame_paint_region_map),
21 has_raster_cache_(has_raster_cache),
22 impeller_enabled_(impeller_enabled) {}
23
25 state_stack_.push_back(state_);
26
27 bool had_integral_transform = state_.integral_transform;
28 state_.rect_index = rects_->size();
29 state_.has_filter_bounds_adjustment = false;
30 state_.has_texture = false;
31 state_.integral_transform = false;
32
33 if (had_integral_transform) {
34 MakeTransformIntegral(state_.matrix_clip);
35 }
36}
37
39 FML_DCHECK(!state_stack_.empty());
40 if (state_.has_filter_bounds_adjustment) {
41 filter_bounds_adjustment_stack_.pop_back();
42 }
43 state_ = state_stack_.back();
44 state_stack_.pop_back();
45}
46
47DiffContext::State::State() : matrix_clip(kGiantRect, SkMatrix::I()) {}
48
50 state_.matrix_clip.transform(transform);
51}
52
54 state_.matrix_clip.transform(transform);
55}
56
57void DiffContext::MakeTransformIntegral(
58 DisplayListMatrixClipState& matrix_clip) {
59 // TODO(knopp): This is duplicated from LayerStack. Maybe should be part of
60 // clip tracker?
61 if (matrix_clip.using_4x4_matrix()) {
62 SkM44 integral;
64 &integral)) {
65 matrix_clip.setTransform(integral);
66 }
67 } else {
68 SkMatrix integral;
70 &integral)) {
71 matrix_clip.setTransform(integral);
72 }
73 }
74}
75
77 const FilterBoundsAdjustment& filter) {
78 FML_DCHECK(state_.has_filter_bounds_adjustment == false);
79 state_.has_filter_bounds_adjustment = true;
80 filter_bounds_adjustment_stack_.push_back(filter);
81}
82
83SkRect DiffContext::ApplyFilterBoundsAdjustment(SkRect rect) const {
84 // Apply filter bounds adjustment in reverse order
85 for (auto i = filter_bounds_adjustment_stack_.rbegin();
86 i != filter_bounds_adjustment_stack_.rend(); ++i) {
87 rect = (*i)(rect);
88 }
89 return rect;
90}
91
92void DiffContext::AlignRect(SkIRect& rect,
93 int horizontal_alignment,
94 int vertical_alignment) const {
95 auto top = rect.top();
96 auto left = rect.left();
97 auto right = rect.right();
98 auto bottom = rect.bottom();
99 if (top % vertical_alignment != 0) {
100 top -= top % vertical_alignment;
101 }
102 if (left % horizontal_alignment != 0) {
103 left -= left % horizontal_alignment;
104 }
105 if (right % horizontal_alignment != 0) {
106 right += horizontal_alignment - right % horizontal_alignment;
107 }
108 if (bottom % vertical_alignment != 0) {
109 bottom += vertical_alignment - bottom % vertical_alignment;
110 }
111 right = std::min(right, frame_size_.width());
112 bottom = std::min(bottom, frame_size_.height());
113 rect = SkIRect::MakeLTRB(left, top, right, bottom);
114}
115
116Damage DiffContext::ComputeDamage(const SkIRect& accumulated_buffer_damage,
117 int horizontal_clip_alignment,
118 int vertical_clip_alignment) const {
119 SkRect buffer_damage = SkRect::Make(accumulated_buffer_damage);
120 buffer_damage.join(damage_);
121 SkRect frame_damage(damage_);
122
123 for (const auto& r : readbacks_) {
124 SkRect paint_rect = SkRect::Make(r.paint_rect);
125 SkRect readback_rect = SkRect::Make(r.readback_rect);
126 // Changes either in readback or paint rect require repainting both readback
127 // and paint rect.
128 if (paint_rect.intersects(frame_damage) ||
129 readback_rect.intersects(frame_damage)) {
130 frame_damage.join(readback_rect);
131 frame_damage.join(paint_rect);
132 buffer_damage.join(readback_rect);
133 buffer_damage.join(paint_rect);
134 }
135 }
136
137 Damage res;
138 buffer_damage.roundOut(&res.buffer_damage);
139 frame_damage.roundOut(&res.frame_damage);
140
141 SkIRect frame_clip = SkIRect::MakeSize(frame_size_);
142 res.buffer_damage.intersect(frame_clip);
143 res.frame_damage.intersect(frame_clip);
144
145 if (horizontal_clip_alignment > 1 || vertical_clip_alignment > 1) {
146 AlignRect(res.buffer_damage, horizontal_clip_alignment,
147 vertical_clip_alignment);
148 AlignRect(res.frame_damage, horizontal_clip_alignment,
149 vertical_clip_alignment);
150 }
151 return res;
152}
153
155 SkRect mapped_rect(rect);
156 state_.matrix_clip.mapRect(&mapped_rect);
157 return mapped_rect;
158}
159
161 state_.matrix_clip.clipRect(clip, DlCanvas::ClipOp::kIntersect, false);
162 return !state_.matrix_clip.device_cull_rect().isEmpty();
163}
164
166 return state_.matrix_clip.matrix_3x3();
167}
168
170 return state_.matrix_clip.local_cull_rect();
171}
172
173void DiffContext::MarkSubtreeDirty(const PaintRegion& previous_paint_region) {
175 if (previous_paint_region.is_valid()) {
176 AddDamage(previous_paint_region);
177 }
178 state_.dirty = true;
179}
180
181void DiffContext::MarkSubtreeDirty(const SkRect& previous_paint_region) {
183 AddDamage(previous_paint_region);
184 state_.dirty = true;
185}
186
188 // During painting we cull based on non-overriden transform and then
189 // override the transform right before paint. Do the same thing here to get
190 // identical paint rect.
191 auto transformed_rect = ApplyFilterBoundsAdjustment(MapRect(rect));
192 if (transformed_rect.intersects(state_.matrix_clip.device_cull_rect())) {
193 if (state_.integral_transform) {
194 DisplayListMatrixClipState temp_state = state_.matrix_clip;
195 MakeTransformIntegral(temp_state);
196 temp_state.mapRect(rect, &transformed_rect);
197 transformed_rect = ApplyFilterBoundsAdjustment(transformed_rect);
198 }
199 rects_->push_back(transformed_rect);
200 if (IsSubtreeDirty()) {
201 AddDamage(transformed_rect);
202 }
203 }
204}
205
207 // Set the has_texture flag on current state and all parent states. That
208 // way we'll know that we can't skip diff for retained layers because
209 // they contain a TextureLayer.
210 for (auto& state : state_stack_) {
211 state.has_texture = true;
212 }
213 state_.has_texture = true;
214}
215
217 // Adding paint region for retained layer implies that current subtree is not
218 // dirty, so we know, for example, that the inherited transforms must match
220 if (region.is_valid()) {
221 rects_->insert(rects_->end(), region.begin(), region.end());
222 }
223}
224
226 const SkIRect& readback_rect) {
227 Readback readback;
228 readback.paint_rect = paint_rect;
229 readback.readback_rect = readback_rect;
230 readback.position = rects_->size();
231 // Push empty rect as a placeholder for position in current subtree
232 rects_->push_back(SkRect::MakeEmpty());
233 readbacks_.push_back(readback);
234}
235
237 bool has_readback = std::any_of(
238 readbacks_.begin(), readbacks_.end(),
239 [&](const Readback& r) { return r.position >= state_.rect_index; });
240 return PaintRegion(rects_, state_.rect_index, rects_->size(), has_readback,
241 state_.has_texture);
242}
243
245 FML_DCHECK(damage.is_valid());
246 for (const auto& r : damage) {
247 damage_.join(r);
248 }
249}
250
252 damage_.join(rect);
253}
254
256 const PaintRegion& region) {
257 this_frame_paint_region_map_[layer->unique_id()] = region;
258}
259
261 auto i = last_frame_paint_region_map_.find(layer->unique_id());
262 if (i != last_frame_paint_region_map_.end()) {
263 return i->second;
264 } else {
265 // This is valid when Layer::PreservePaintRegion is called for retained
266 // layer with zero sized parent clip (these layers are not diffed)
267 return PaintRegion();
268 }
269}
270
272#if !FLUTTER_RELEASE
273 FML_TRACE_COUNTER("flutter", "DiffContext", reinterpret_cast<int64_t>(this),
274 "NewPictures", new_pictures_, "PicturesTooComplexToCompare",
275 pictures_too_complex_to_compare_, "DeepComparePictures",
276 deep_compare_pictures_, "SameInstancePictures",
277 same_instance_pictures_,
278 "DifferentInstanceButEqualPictures",
279 different_instance_but_equal_pictures_);
280#endif // !FLUTTER_RELEASE
281}
282
283} // namespace flutter
static void readback(const SkBitmap &src, int *result, int resultCount)
Definition: BlurTest.cpp:264
static SkPath clip(const SkPath &path, const SkHalfPlane &plane)
Definition: SkPath.cpp:3892
Definition: SkM44.h:150
SkMatrix GetTransform3x3() const
void PushTransform(const SkMatrix &transform)
Definition: diff_context.cc:49
void AddLayerBounds(const SkRect &rect)
void SetLayerPaintRegion(const Layer *layer, const PaintRegion &region)
void MarkSubtreeDirty(const PaintRegion &previous_paint_region=PaintRegion())
void AddDamage(const PaintRegion &damage)
PaintRegion CurrentSubtreeRegion() const
void AddExistingPaintRegion(const PaintRegion &region)
void PushFilterBoundsAdjustment(const FilterBoundsAdjustment &filter)
Definition: diff_context.cc:76
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
void setTransform(const DlMatrix &matrix)
uint64_t unique_id() const
Definition: layer.h:251
bool is_valid() const
Definition: paint_region.h:53
AtkStateType state
#define FML_DCHECK(condition)
Definition: logging.h:103
static float min(float r, float g, float b)
Definition: hsl.cpp:48
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 constexpr SkRect kGiantRect
Definition: layer.h:50
Definition: ref_ptr.h:256
static SkColor4f transform(SkColor4f c, SkColorSpace *src, SkColorSpace *dst)
Definition: p3.cpp:47
Definition: SkMD5.cpp:134
Definition: SkRect.h:32
bool intersect(const SkIRect &r)
Definition: SkRect.h:513
static constexpr SkIRect MakeLTRB(int32_t l, int32_t t, int32_t r, int32_t b)
Definition: SkRect.h:91
static constexpr SkIRect MakeSize(const SkISize &size)
Definition: SkRect.h:66
Definition: SkSize.h:16
constexpr int32_t width() const
Definition: SkSize.h:36
constexpr int32_t height() const
Definition: SkSize.h:37
static SkRect Make(const SkISize &size)
Definition: SkRect.h:669
static constexpr SkRect MakeEmpty()
Definition: SkRect.h:595
bool intersects(const SkRect &r) const
Definition: SkRect.h:1121
void roundOut(SkIRect *dst) const
Definition: SkRect.h:1241
void join(const SkRect &r)
Definition: SkRect.cpp:126
SkIRect buffer_damage
Definition: diff_context.h:37
SkIRect frame_damage
Definition: diff_context.h:30
static bool ComputeIntegralTransCTM(const SkMatrix &in, SkMatrix *out)
Snap the translation components of the |in| matrix to integers and store the snapped matrix in |out|.
#define FML_TRACE_COUNTER(category_group, name, counter_id, arg1,...)
Definition: trace_event.h:85