| Flutter Impeller |

clip_stack_unittests.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/testing/testing.h"
6 #include "gtest/gtest.h"
7 #include "impeller/entity/contents/clip_contents.h"
8 #include "impeller/entity/entity.h"
9 #include "impeller/entity/entity_pass_clip_stack.h"
10
11 namespace impeller {
12 namespace testing {
13
14 TEST(EntityPassClipStackTest, CanPushAndPopEntities) {
15 EntityPassClipStack recorder =
16 EntityPassClipStack(Rect::MakeLTRB(0, 0, 100, 100));
17
18 EXPECT_TRUE(recorder.GetReplayEntities().empty());
19
20 recorder.RecordClip(ClipContents(Rect::MakeLTRB(0, 0, 100, 100),
21 /*is_axis_aligned_rect=*/false),
22 Matrix(), {0, 0}, 0, 100, /*is_aa=*/true);
23
24 EXPECT_EQ(recorder.GetReplayEntities().size(), 1u);
25
26 recorder.RecordClip(ClipContents(Rect::MakeLTRB(0, 0, 50.5, 50.5),
27 /*is_axis_aligned_rect=*/true),
28 Matrix(), {0, 0}, 2, 100, /*is_aa=*/true);
29
30 EXPECT_EQ(recorder.GetReplayEntities().size(), 2u);
31 ASSERT_TRUE(recorder.GetReplayEntities()[0].clip_coverage.has_value());
32 ASSERT_TRUE(recorder.GetReplayEntities()[1].clip_coverage.has_value());
33
34 // NOLINTBEGIN(bugprone-unchecked-optional-access)
35 EXPECT_EQ(recorder.GetReplayEntities()[0].clip_coverage.value(),
36 Rect::MakeLTRB(0, 0, 100, 100));
37 EXPECT_EQ(recorder.GetReplayEntities()[1].clip_coverage.value(),
38 Rect::MakeLTRB(0, 0, 50.5, 50.5));
39 // NOLINTEND(bugprone-unchecked-optional-access)
40
41 recorder.RecordRestore({0, 0}, 1);
42 EXPECT_EQ(recorder.GetReplayEntities().size(), 1u);
43
44 recorder.RecordRestore({0, 0}, 0);
45 EXPECT_TRUE(recorder.GetReplayEntities().empty());
46 }
47
48 TEST(EntityPassClipStackTest, CanPopEntitiesSafely) {
49 EntityPassClipStack recorder =
50 EntityPassClipStack(Rect::MakeLTRB(0, 0, 100, 100));
51
52 EXPECT_TRUE(recorder.GetReplayEntities().empty());
53
54 recorder.RecordRestore({0, 0}, 0);
55 EXPECT_TRUE(recorder.GetReplayEntities().empty());
56 }
57
58 TEST(EntityPassClipStackTest, AppendAndRestoreClipCoverage) {
59 EntityPassClipStack recorder =
60 EntityPassClipStack(Rect::MakeLTRB(0, 0, 100, 100));
61
62 ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 1u);
63
64 // Push a clip.
65 EntityPassClipStack::ClipStateResult result =
66 recorder.RecordClip(ClipContents(Rect::MakeLTRB(50, 50, 55.5, 55.5),
67 /*is_axis_aligned_rect=*/true),
68 Matrix(), {0, 0}, 0, 100, /*is_aa=*/true);
69 EXPECT_TRUE(result.should_render);
70 EXPECT_TRUE(result.clip_did_change);
71
72 ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 2u);
73 EXPECT_EQ(recorder.GetClipCoverageLayers()[1].coverage,
74 Rect::MakeLTRB(50, 50, 55.5, 55.5));
75 EXPECT_EQ(recorder.GetClipCoverageLayers()[1].clip_height, 1u);
76 EXPECT_EQ(recorder.GetReplayEntities().size(), 1u);
77
78 // Restore the clip.
79 recorder.RecordRestore({0, 0}, 0);
80
81 ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 1u);
82 EXPECT_EQ(recorder.GetClipCoverageLayers()[0].coverage,
83 Rect::MakeSize(Size::MakeWH(100, 100)));
84 EXPECT_EQ(recorder.GetClipCoverageLayers()[0].clip_height, 0u);
85 EXPECT_EQ(recorder.GetReplayEntities().size(), 0u);
86 }
87
88 TEST(EntityPassClipStackTest, AppendAndRestoreClipCoverageNonAA) {
89 EntityPassClipStack recorder =
90 EntityPassClipStack(Rect::MakeLTRB(0, 0, 100, 100));
91
92 ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 1u);
93
94 // Push a clip.
95 EntityPassClipStack::ClipStateResult result =
96 recorder.RecordClip(ClipContents(Rect::MakeLTRB(50, 50, 55.4, 55.4),
97 /*is_axis_aligned_rect=*/true),
98 Matrix(), {0, 0}, 0, 100, /*is_aa=*/false);
99 EXPECT_FALSE(result.should_render);
100 EXPECT_TRUE(result.clip_did_change);
101
102 ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 2u);
103 EXPECT_EQ(recorder.GetClipCoverageLayers()[1].coverage,
104 Rect::MakeLTRB(50, 50, 55, 55));
105 EXPECT_EQ(recorder.GetClipCoverageLayers()[1].clip_height, 1u);
106 EXPECT_EQ(recorder.GetReplayEntities().size(), 1u);
107
108 // Restore the clip.
109 recorder.RecordRestore({0, 0}, 0);
110
111 ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 1u);
112 EXPECT_EQ(recorder.GetClipCoverageLayers()[0].coverage,
113 Rect::MakeSize(Size::MakeWH(100, 100)));
114 EXPECT_EQ(recorder.GetClipCoverageLayers()[0].clip_height, 0u);
115 EXPECT_EQ(recorder.GetReplayEntities().size(), 0u);
116 }
117
118 // Append two clip coverages, the second is larger the first. This
119 // should result in the second clip not requiring any update.
120 TEST(EntityPassClipStackTest, AppendLargerClipCoverage) {
121 EntityPassClipStack recorder =
122 EntityPassClipStack(Rect::MakeLTRB(0, 0, 100, 100));
123
124 ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 1u);
125
126 // Push a clip.
127 EntityPassClipStack::ClipStateResult result =
128 recorder.RecordClip(ClipContents(Rect::MakeLTRB(50, 50, 55.5, 55.5),
129 /*is_axis_aligned_rect=*/true),
130 Matrix(), {0, 0}, 0, 100, /*is_aa=*/true);
131
132 EXPECT_TRUE(result.should_render);
133 EXPECT_TRUE(result.clip_did_change);
134
135 // Push a clip with larger coverage than the previous state.
136 result = recorder.RecordClip(ClipContents(Rect::MakeLTRB(0, 0, 100.5, 100.5),
137 /*is_axis_aligned_rect=*/true),
138 Matrix(), {0, 0}, 1, 100, /*is_aa=*/true);
139
140 EXPECT_FALSE(result.should_render);
141 EXPECT_FALSE(result.clip_did_change);
142 }
143
144 // Since clip entities return the outer coverage we can only cull axis aligned
145 // rectangles and intersect clips.
146 TEST(EntityPassClipStackTest,
147 AppendLargerClipCoverageWithDifferenceOrNonSquare) {
148 EntityPassClipStack recorder =
149 EntityPassClipStack(Rect::MakeLTRB(0, 0, 100, 100));
150
151 ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 1u);
152
153 // Push a clip.
154 EntityPassClipStack::ClipStateResult result =
155 recorder.RecordClip(ClipContents(Rect::MakeLTRB(50, 50, 55, 55),
156 /*is_axis_aligned_rect=*/true),
157 Matrix(), {0, 0}, 0, 100, /*is_aa=*/true);
158
159 EXPECT_FALSE(result.should_render);
160 EXPECT_TRUE(result.clip_did_change);
161
162 // Push a clip with larger coverage than the previous state.
163 result = recorder.RecordClip(ClipContents(Rect::MakeLTRB(0, 0, 100, 100),
164 /*is_axis_aligned_rect=*/false),
165 Matrix(), {0, 0}, 0, 100, /*is_aa=*/true);
166
167 EXPECT_TRUE(result.should_render);
168 EXPECT_TRUE(result.clip_did_change);
169 }
170
171 TEST(EntityPassClipStackTest, AppendDecreasingSizeClipCoverage) {
172 EntityPassClipStack recorder =
173 EntityPassClipStack(Rect::MakeLTRB(0, 0, 100, 100));
174
175 ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 1u);
176
177 // Push Clips that shrink in size. All should be applied.
178 Entity entity;
179
180 for (auto i = 1; i < 20; i++) {
181 EntityPassClipStack::ClipStateResult result = recorder.RecordClip(
182 ClipContents(Rect::MakeLTRB(i, i, 99.6 - i, 99.6 - i),
183 /*is_axis_aligned_rect=*/true),
184 Matrix(), {0, 0}, 0, 100, /*is_aa=*/true);
185
186 EXPECT_TRUE(result.should_render);
187 EXPECT_TRUE(result.clip_did_change);
188 EXPECT_EQ(recorder.CurrentClipCoverage(),
189 Rect::MakeLTRB(i, i, 99.6 - i, 99.6 - i));
190 }
191 }
192
193 TEST(EntityPassClipStackTest, AppendIncreasingSizeClipCoverage) {
194 EntityPassClipStack recorder =
195 EntityPassClipStack(Rect::MakeLTRB(0, 0, 100, 100));
196
197 ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 1u);
198
199 // Push Clips that grow in size. All should be skipped.
200
201 for (auto i = 1; i < 20; i++) {
202 EntityPassClipStack::ClipStateResult result = recorder.RecordClip(
203 ClipContents(Rect::MakeLTRB(0 - i, 0 - i, 100 + i, 100 + i),
204 /*is_axis_aligned_rect=*/true),
205 Matrix(), {0, 0}, 0, 100, /*is_aa=*/true);
206
207 EXPECT_FALSE(result.should_render);
208 EXPECT_FALSE(result.clip_did_change);
209 EXPECT_EQ(recorder.CurrentClipCoverage(), Rect::MakeLTRB(0, 0, 100, 100));
210 }
211 }
212
213 TEST(EntityPassClipStackTest, UnbalancedRestore) {
214 EntityPassClipStack recorder =
215 EntityPassClipStack(Rect::MakeLTRB(0, 0, 100, 100));
216
217 ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 1u);
218
219 // Restore the clip.
220 EntityPassClipStack::ClipStateResult result =
221 recorder.RecordRestore(Point(0, 0), 0);
222 EXPECT_FALSE(result.should_render);
223 EXPECT_FALSE(result.clip_did_change);
224
225 ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 1u);
226 EXPECT_EQ(recorder.GetClipCoverageLayers()[0].coverage,
227 Rect::MakeSize(Size::MakeWH(100, 100)));
228 EXPECT_EQ(recorder.GetClipCoverageLayers()[0].clip_height, 0u);
229 EXPECT_EQ(recorder.GetReplayEntities().size(), 0u);
230 }
231
232 TEST(EntityPassClipStackTest, ClipAndRestoreWithSubpasses) {
233 EntityPassClipStack recorder =
234 EntityPassClipStack(Rect::MakeLTRB(0, 0, 100, 100));
235
236 ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 1u);
237
238 // Push a clip.
239 {
240 EntityPassClipStack::ClipStateResult result =
241 recorder.RecordClip(ClipContents(Rect::MakeLTRB(50, 50, 55.5, 55.5),
242 /*is_axis_aligned_rect=*/true),
243 Matrix(), {0, 0}, 0, 100, /*is_aa=*/true);
244
245 EXPECT_TRUE(result.should_render);
246 EXPECT_TRUE(result.clip_did_change);
247 }
248
249 ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 2u);
250 EXPECT_EQ(recorder.GetClipCoverageLayers()[1].coverage,
251 Rect::MakeLTRB(50, 50, 55.5, 55.5));
252 EXPECT_EQ(recorder.GetClipCoverageLayers()[1].clip_height, 1u);
253 EXPECT_EQ(recorder.GetReplayEntities().size(), 1u);
254
255 // Begin a subpass.
256 recorder.PushSubpass(Rect::MakeLTRB(50, 50, 55, 55), 1);
257 ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 1u);
258 EXPECT_EQ(recorder.GetClipCoverageLayers()[0].coverage,
259 Rect::MakeLTRB(50, 50, 55, 55));
260
261 {
262 EntityPassClipStack::ClipStateResult result =
263 recorder.RecordClip(ClipContents(Rect::MakeLTRB(54, 54, 54.5, 54.5),
264 /*is_axis_aligned_rect=*/true),
265 Matrix(), {0, 0}, 0, 100, /*is_aa=*/true);
266
267 EXPECT_TRUE(result.should_render);
268 EXPECT_TRUE(result.clip_did_change);
269 }
270
271 EXPECT_EQ(recorder.GetClipCoverageLayers()[1].coverage,
272 Rect::MakeLTRB(54, 54, 54.5, 54.5));
273
274 // End subpass.
275 recorder.PopSubpass();
276
277 EXPECT_EQ(recorder.GetClipCoverageLayers()[1].coverage,
278 Rect::MakeLTRB(50, 50, 55.5, 55.5));
279 }
280
281 TEST(EntityPassClipStackTest, ClipAndRestoreWithSubpassesNonAA) {
282 EntityPassClipStack recorder =
283 EntityPassClipStack(Rect::MakeLTRB(0, 0, 100, 100));
284
285 ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 1u);
286
287 // Push a clip.
288 {
289 EntityPassClipStack::ClipStateResult result =
290 recorder.RecordClip(ClipContents(Rect::MakeLTRB(50, 50, 55.4, 55.4),
291 /*is_axis_aligned_rect=*/true),
292 Matrix(), {0, 0}, 0, 100, /*is_aa=*/false);
293
294 EXPECT_FALSE(result.should_render);
295 EXPECT_TRUE(result.clip_did_change);
296 }
297
298 ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 2u);
299 EXPECT_EQ(recorder.GetClipCoverageLayers()[1].coverage,
300 Rect::MakeLTRB(50, 50, 55.0, 55.0));
301 EXPECT_EQ(recorder.GetClipCoverageLayers()[1].clip_height, 1u);
302 EXPECT_EQ(recorder.GetReplayEntities().size(), 1u);
303
304 // Begin a subpass.
305 recorder.PushSubpass(Rect::MakeLTRB(50, 50, 55, 55), 1);
306 ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 1u);
307 EXPECT_EQ(recorder.GetClipCoverageLayers()[0].coverage,
308 Rect::MakeLTRB(50, 50, 55, 55));
309
310 {
311 EntityPassClipStack::ClipStateResult result =
312 recorder.RecordClip(ClipContents(Rect::MakeLTRB(54, 54, 55.4, 55.4),
313 /*is_axis_aligned_rect=*/true),
314 Matrix(), {0, 0}, 0, 100, /*is_aa=*/false);
315
316 EXPECT_FALSE(result.should_render);
317 EXPECT_TRUE(result.clip_did_change);
318 }
319
320 EXPECT_EQ(recorder.GetClipCoverageLayers()[1].coverage,
321 Rect::MakeLTRB(54, 54, 55.0, 55.0));
322
323 // End subpass.
324 recorder.PopSubpass();
325
326 EXPECT_EQ(recorder.GetClipCoverageLayers()[1].coverage,
327 Rect::MakeLTRB(50, 50, 55, 55));
328 }
329
330 } // namespace testing
331 } // namespace impeller
impeller::ClipContents
Definition: clip_contents.h:29
impeller::Entity
Definition: entity.h:20
impeller::EntityPassClipStack
A class that tracks all clips that have been recorded in the current entity pass stencil.
Definition: entity_pass_clip_stack.h:23
impeller::EntityPassClipStack::CurrentClipCoverage
std::optional< Rect > CurrentClipCoverage() const
Definition: entity_pass_clip_stack.cc:24
impeller::EntityPassClipStack::PushSubpass
void PushSubpass(std::optional< Rect > subpass_coverage, size_t clip_height)
Definition: entity_pass_clip_stack.cc:32
impeller::EntityPassClipStack::GetReplayEntities
const std::vector< ReplayResult > & GetReplayEntities() const
Definition: entity_pass_clip_stack.cc:209
impeller::EntityPassClipStack::RecordClip
ClipStateResult RecordClip(const ClipContents &clip_contents, Matrix transform, Point global_pass_position, uint32_t clip_depth, size_t clip_height_floor, bool is_aa)
Definition: entity_pass_clip_stack.cc:100
impeller::EntityPassClipStack::RecordRestore
ClipStateResult RecordRestore(Point global_pass_position, size_t restore_height)
Definition: entity_pass_clip_stack.cc:54
impeller::EntityPassClipStack::PopSubpass
void PopSubpass()
Definition: entity_pass_clip_stack.cc:44
impeller::EntityPassClipStack::GetClipCoverageLayers
const std::vector< ClipCoverageLayer > GetClipCoverageLayers() const
Definition: entity_pass_clip_stack.cc:50
clip_contents.h
entity.h
entity_pass_clip_stack.h
impeller::testing::TEST
TEST(AllocationSizeTest, CanCreateTypedAllocations)
Definition: allocation_size_unittests.cc:10
impeller
Definition: allocation.cc:12
impeller::Point
TPoint< Scalar > Point
Definition: point.h:327
impeller::EntityPassClipStack::ClipStateResult
Definition: entity_pass_clip_stack.h:32
impeller::EntityPassClipStack::ClipStateResult::clip_did_change
bool clip_did_change
Definition: entity_pass_clip_stack.h:38
impeller::EntityPassClipStack::ClipStateResult::should_render
bool should_render
Definition: entity_pass_clip_stack.h:35
impeller::Matrix
A 4x4 matrix using column-major storage.
Definition: matrix.h:37
impeller::TRect< Scalar >::MakeSize
constexpr static TRect MakeSize(const TSize< U > &size)
Definition: rect.h:150
impeller::TRect< Scalar >::MakeLTRB
constexpr static TRect MakeLTRB(Type left, Type top, Type right, Type bottom)
Definition: rect.h:129
impeller::TSize< Scalar >::MakeWH
static constexpr TSize MakeWH(Type width, Type height)
Definition: size.h:43