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"
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.
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.
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.
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.
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++) {
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++) {
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.
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  {
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  {
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  {
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  {
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
A class that tracks all clips that have been recorded in the current entity pass stencil.
std::optional< Rect > CurrentClipCoverage() const
void PushSubpass(std::optional< Rect > subpass_coverage, size_t clip_height)
const std::vector< ReplayResult > & GetReplayEntities() const
ClipStateResult RecordClip(const ClipContents &clip_contents, Matrix transform, Point global_pass_position, uint32_t clip_depth, size_t clip_height_floor, bool is_aa)
ClipStateResult RecordRestore(Point global_pass_position, size_t restore_height)
const std::vector< ClipCoverageLayer > GetClipCoverageLayers() const
TEST(AllocationSizeTest, CanCreateTypedAllocations)
TPoint< Scalar > Point
Definition: point.h:327
A 4x4 matrix using column-major storage.
Definition: matrix.h:37
constexpr static TRect MakeSize(const TSize< U > &size)
Definition: rect.h:150
constexpr static TRect MakeLTRB(Type left, Type top, Type right, Type bottom)
Definition: rect.h:129
static constexpr TSize MakeWH(Type width, Type height)
Definition: size.h:43