Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit a39d13f

Browse files
committed
introduce LSS delegates to simplify some code and reduce overhead
1 parent 2a79b94 commit a39d13f

35 files changed

+1791
-1014
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -699,6 +699,9 @@ FILE: ../../../flutter/display_list/display_list_image_skia.h
699699
FILE: ../../../flutter/display_list/display_list_mask_filter.cc
700700
FILE: ../../../flutter/display_list/display_list_mask_filter.h
701701
FILE: ../../../flutter/display_list/display_list_mask_filter_unittests.cc
702+
FILE: ../../../flutter/display_list/display_list_matrix_clip_tracker.cc
703+
FILE: ../../../flutter/display_list/display_list_matrix_clip_tracker.h
704+
FILE: ../../../flutter/display_list/display_list_matrix_clip_tracker_unittests.cc
702705
FILE: ../../../flutter/display_list/display_list_ops.cc
703706
FILE: ../../../flutter/display_list/display_list_ops.h
704707
FILE: ../../../flutter/display_list/display_list_paint.cc

display_list/BUILD.gn

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ source_set("display_list") {
4545
"display_list_image_skia.h",
4646
"display_list_mask_filter.cc",
4747
"display_list_mask_filter.h",
48+
"display_list_matrix_clip_tracker.cc",
49+
"display_list_matrix_clip_tracker.h",
4850
"display_list_ops.cc",
4951
"display_list_ops.h",
5052
"display_list_paint.cc",
@@ -104,6 +106,7 @@ if (enable_unittests) {
104106
"display_list_enum_unittests.cc",
105107
"display_list_image_filter_unittests.cc",
106108
"display_list_mask_filter_unittests.cc",
109+
"display_list_matrix_clip_tracker_unittests.cc",
107110
"display_list_paint_unittests.cc",
108111
"display_list_path_effect_unittests.cc",
109112
"display_list_unittests.cc",

display_list/display_list_builder.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -706,7 +706,7 @@ SkRect DisplayListBuilder::getLocalClipBounds() {
706706
current_layer_->clip_bounds.roundOut(&dev_bounds);
707707
return inverse.asM33().mapRect(dev_bounds);
708708
}
709-
return kMaxCullRect_;
709+
return kMaxCullRect;
710710
}
711711

712712
bool DisplayListBuilder::quickReject(const SkRect& bounds) const {

display_list/display_list_builder.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,10 @@ class DisplayListBuilder final : public virtual Dispatcher,
2828
public SkRefCnt,
2929
DisplayListOpFlags {
3030
public:
31-
explicit DisplayListBuilder(const SkRect& cull_rect = kMaxCullRect_);
31+
static constexpr SkRect kMaxCullRect =
32+
SkRect::MakeLTRB(-1E9F, -1E9F, 1E9F, 1E9F);
33+
34+
explicit DisplayListBuilder(const SkRect& cull_rect = kMaxCullRect);
3235

3336
~DisplayListBuilder();
3437

@@ -364,8 +367,6 @@ class DisplayListBuilder final : public virtual Dispatcher,
364367
int nested_op_count_ = 0;
365368

366369
SkRect cull_rect_;
367-
static constexpr SkRect kMaxCullRect_ =
368-
SkRect::MakeLTRB(-1E9F, -1E9F, 1E9F, 1E9F);
369370

370371
template <typename T, typename... Args>
371372
void* Push(size_t extra, int op_inc, Args&&... args);
Lines changed: 328 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,328 @@
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/display_list/display_list_matrix_clip_tracker.h"
6+
7+
#include "flutter/display_list/display_list_builder.h"
8+
#include "flutter/fml/logging.h"
9+
#include "third_party/skia/include/core/SkPath.h"
10+
11+
namespace flutter {
12+
13+
class Data4x4 : public DisplayListMatrixClipTracker::Data {
14+
public:
15+
Data4x4(const SkM44& m44, const SkRect& rect) : Data(rect), m44_(m44) {}
16+
explicit Data4x4(const Data* copy)
17+
: Data(copy->device_cull_rect()), m44_(copy->matrix_4x4()) {}
18+
19+
~Data4x4() override = default;
20+
21+
bool is_4x4() const override { return true; }
22+
23+
SkMatrix matrix_3x3() const override { return m44_.asM33(); }
24+
SkM44 matrix_4x4() const override { return m44_; }
25+
SkRect local_cull_rect() const override;
26+
27+
void translate(SkScalar tx, SkScalar ty) override {
28+
m44_.preTranslate(tx, ty);
29+
}
30+
void scale(SkScalar sx, SkScalar sy) override { m44_.preScale(sx, sy); }
31+
void skew(SkScalar skx, SkScalar sky) override {
32+
m44_.preConcat(SkMatrix::Skew(skx, sky));
33+
}
34+
void rotate(SkScalar degrees) override {
35+
m44_.preConcat(SkMatrix::RotateDeg(degrees));
36+
}
37+
void transform(const SkMatrix& matrix) override { m44_.preConcat(matrix); }
38+
void transform(const SkM44& m44) override { m44_.preConcat(m44); }
39+
void setTransform(const SkMatrix& matrix) override { m44_ = SkM44(matrix); }
40+
void setTransform(const SkM44& m44) override { m44_ = m44; }
41+
void setIdentity() override { m44_.setIdentity(); }
42+
43+
protected:
44+
bool has_perspective() const override;
45+
bool map_rect(const SkRect& rect, SkRect* mapped) const override {
46+
return m44_.asM33().mapRect(mapped, rect);
47+
}
48+
49+
private:
50+
SkM44 m44_;
51+
};
52+
53+
class Data3x3 : public DisplayListMatrixClipTracker::Data {
54+
public:
55+
Data3x3(const SkMatrix& matrix, const SkRect& rect)
56+
: Data(rect), matrix_(matrix) {}
57+
explicit Data3x3(const Data* copy)
58+
: Data(copy->device_cull_rect()), matrix_(copy->matrix_3x3()) {}
59+
60+
~Data3x3() override = default;
61+
62+
bool is_4x4() const override { return false; }
63+
64+
SkMatrix matrix_3x3() const override { return matrix_; }
65+
SkM44 matrix_4x4() const override { return SkM44(matrix_); }
66+
SkRect local_cull_rect() const override;
67+
68+
void translate(SkScalar tx, SkScalar ty) override {
69+
matrix_.preTranslate(tx, ty);
70+
}
71+
void scale(SkScalar sx, SkScalar sy) override { matrix_.preScale(sx, sy); }
72+
void skew(SkScalar skx, SkScalar sky) override { matrix_.preSkew(skx, sky); }
73+
void rotate(SkScalar degrees) override { matrix_.preRotate(degrees); }
74+
void transform(const SkMatrix& matrix) override { matrix_.preConcat(matrix); }
75+
void transform(const SkM44& m44) override {
76+
FML_CHECK(false) << "SkM44 was concatenated without upgrading Data";
77+
}
78+
void setTransform(const SkMatrix& matrix) override { matrix_ = matrix; }
79+
void setTransform(const SkM44& m44) override {
80+
FML_CHECK(false) << "SkM44 was set without upgrading Data";
81+
}
82+
void setIdentity() override { matrix_.setIdentity(); }
83+
84+
protected:
85+
bool has_perspective() const override { return matrix_.hasPerspective(); }
86+
bool map_rect(const SkRect& rect, SkRect* mapped) const override {
87+
return matrix_.mapRect(mapped, rect);
88+
}
89+
90+
private:
91+
SkMatrix matrix_;
92+
};
93+
94+
static bool is_3x3(const SkM44& m) {
95+
// clang-format off
96+
return ( m.rc(0, 2) == 0 &&
97+
m.rc(1, 2) == 0 &&
98+
m.rc(2, 0) == 0 && m.rc(2, 1) == 0 && m.rc(2, 2) == 1 && m.rc(2, 3) == 0 &&
99+
m.rc(3, 2) == 0);
100+
// clang-format on
101+
}
102+
103+
DisplayListMatrixClipTracker::DisplayListMatrixClipTracker(
104+
const SkRect& cull_rect,
105+
const SkMatrix& matrix) {
106+
saved_.emplace_back(std::make_unique<Data3x3>(matrix, cull_rect));
107+
current_ = saved_.back().get();
108+
}
109+
110+
DisplayListMatrixClipTracker::DisplayListMatrixClipTracker(
111+
const SkRect& cull_rect,
112+
const SkM44& m44) {
113+
if (is_3x3(m44)) {
114+
saved_.emplace_back(std::make_unique<Data3x3>(m44.asM33(), cull_rect));
115+
} else {
116+
saved_.emplace_back(std::make_unique<Data4x4>(m44, cull_rect));
117+
}
118+
current_ = saved_.back().get();
119+
}
120+
121+
void DisplayListMatrixClipTracker::save() {
122+
if (current_->is_4x4()) {
123+
saved_.emplace_back(std::make_unique<Data4x4>(current_));
124+
} else {
125+
saved_.emplace_back(std::make_unique<Data3x3>(current_));
126+
}
127+
current_ = saved_.back().get();
128+
}
129+
130+
void DisplayListMatrixClipTracker::restore() {
131+
saved_.pop_back();
132+
current_ = saved_.back().get();
133+
}
134+
135+
void DisplayListMatrixClipTracker::restoreToCount(int restore_count) {
136+
FML_DCHECK(restore_count <= getSaveCount());
137+
if (restore_count < 1) {
138+
restore_count = 1;
139+
}
140+
while (restore_count < getSaveCount()) {
141+
restore();
142+
}
143+
}
144+
145+
void DisplayListMatrixClipTracker::transform(const SkM44& m44) {
146+
if (!current_->is_4x4()) {
147+
if (is_3x3(m44)) {
148+
current_->transform(m44.asM33());
149+
return;
150+
}
151+
saved_.back() = std::make_unique<Data4x4>(current_);
152+
current_ = saved_.back().get();
153+
}
154+
current_->transform(m44);
155+
}
156+
157+
void DisplayListMatrixClipTracker::setTransform(const SkM44& m44) {
158+
if (!current_->is_4x4()) {
159+
if (is_3x3(m44)) {
160+
current_->setTransform(m44.asM33());
161+
return;
162+
}
163+
saved_.back() = std::make_unique<Data4x4>(current_);
164+
}
165+
current_->setTransform(m44);
166+
}
167+
168+
void DisplayListMatrixClipTracker::clipRRect(const SkRRect& rrect,
169+
SkClipOp op,
170+
bool is_aa) {
171+
switch (op) {
172+
case SkClipOp::kIntersect:
173+
break;
174+
case SkClipOp::kDifference:
175+
if (!rrect.isRect()) {
176+
return;
177+
}
178+
break;
179+
}
180+
current_->clipBounds(rrect.getBounds(), op, is_aa);
181+
}
182+
void DisplayListMatrixClipTracker::clipPath(const SkPath& path,
183+
SkClipOp op,
184+
bool is_aa) {
185+
SkRect bounds;
186+
switch (op) {
187+
case SkClipOp::kIntersect:
188+
bounds = path.getBounds();
189+
break;
190+
case SkClipOp::kDifference:
191+
if (!path.isRect(&bounds)) {
192+
return;
193+
}
194+
break;
195+
}
196+
current_->clipBounds(bounds, op, is_aa);
197+
}
198+
199+
bool DisplayListMatrixClipTracker::Data::content_culled(
200+
const SkRect& content_bounds) const {
201+
if (cull_rect_.isEmpty() || content_bounds.isEmpty()) {
202+
return true;
203+
}
204+
if (has_perspective()) {
205+
return false;
206+
}
207+
SkRect mapped;
208+
map_rect(content_bounds, &mapped);
209+
return !mapped.intersects(cull_rect_);
210+
}
211+
212+
void DisplayListMatrixClipTracker::Data::clipBounds(const SkRect& clip,
213+
SkClipOp op,
214+
bool is_aa) {
215+
if (cull_rect_.isEmpty()) {
216+
// No point in intersecting further.
217+
return;
218+
}
219+
if (has_perspective()) {
220+
// We can conservatively ignore this clip.
221+
return;
222+
}
223+
switch (op) {
224+
case SkClipOp::kIntersect: {
225+
if (clip.isEmpty()) {
226+
cull_rect_.setEmpty();
227+
break;
228+
}
229+
SkRect rect;
230+
map_rect(clip, &rect);
231+
if (is_aa) {
232+
rect.roundOut(&rect);
233+
}
234+
if (!cull_rect_.intersect(rect)) {
235+
cull_rect_.setEmpty();
236+
}
237+
break;
238+
}
239+
case SkClipOp::kDifference: {
240+
if (clip.isEmpty() || !clip.intersects(cull_rect_)) {
241+
break;
242+
}
243+
SkRect rect;
244+
if (map_rect(clip, &rect)) {
245+
// This technique only works if it is rect -> rect
246+
if (is_aa) {
247+
SkIRect rounded;
248+
rect.round(&rounded);
249+
if (rounded.isEmpty()) {
250+
break;
251+
}
252+
rect.set(rounded);
253+
}
254+
if (rect.fLeft <= cull_rect_.fLeft &&
255+
rect.fRight >= cull_rect_.fRight) {
256+
// bounds spans entire width of cull_rect_
257+
// therefore we can slice off a top or bottom
258+
// edge of the cull_rect_.
259+
SkScalar top = std::max(rect.fBottom, cull_rect_.fTop);
260+
SkScalar btm = std::min(rect.fTop, cull_rect_.fBottom);
261+
if (top < btm) {
262+
cull_rect_.fTop = top;
263+
cull_rect_.fBottom = btm;
264+
} else {
265+
cull_rect_.setEmpty();
266+
}
267+
} else if (rect.fTop <= cull_rect_.fTop &&
268+
rect.fBottom >= cull_rect_.fBottom) {
269+
// bounds spans entire height of cull_rect_
270+
// therefore we can slice off a left or right
271+
// edge of the cull_rect_.
272+
SkScalar lft = std::max(rect.fRight, cull_rect_.fLeft);
273+
SkScalar rgt = std::min(rect.fLeft, cull_rect_.fRight);
274+
if (lft < rgt) {
275+
cull_rect_.fLeft = lft;
276+
cull_rect_.fRight = rgt;
277+
} else {
278+
cull_rect_.setEmpty();
279+
}
280+
}
281+
}
282+
break;
283+
}
284+
}
285+
}
286+
287+
SkRect Data4x4::local_cull_rect() const {
288+
if (cull_rect_.isEmpty()) {
289+
return cull_rect_;
290+
}
291+
SkMatrix inverse;
292+
if (!m44_.asM33().invert(&inverse)) {
293+
return SkRect::MakeEmpty();
294+
}
295+
if (has_perspective()) {
296+
// We could do a 4-point long-form conversion, but since this is
297+
// only used for culling, let's just return a non-constricting
298+
// cull rect.
299+
return DisplayListBuilder::kMaxCullRect;
300+
}
301+
return inverse.mapRect(cull_rect_);
302+
}
303+
304+
bool Data4x4::has_perspective() const {
305+
return (m44_.rc(3, 0) != 0 || //
306+
m44_.rc(3, 1) != 0 || //
307+
m44_.rc(3, 2) != 0 || //
308+
m44_.rc(3, 3) != 1);
309+
}
310+
311+
SkRect Data3x3::local_cull_rect() const {
312+
if (cull_rect_.isEmpty()) {
313+
return cull_rect_;
314+
}
315+
SkMatrix inverse;
316+
if (!matrix_.invert(&inverse)) {
317+
return SkRect::MakeEmpty();
318+
}
319+
if (matrix_.hasPerspective()) {
320+
// We could do a 4-point long-form conversion, but since this is
321+
// only used for culling, let's just return a non-constricting
322+
// cull rect.
323+
return DisplayListBuilder::kMaxCullRect;
324+
}
325+
return inverse.mapRect(cull_rect_);
326+
}
327+
328+
} // namespace flutter

0 commit comments

Comments
 (0)