Flutter Impeller
entity_pass_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 <memory>
6 
7 #include "flutter/testing/testing.h"
8 #include "gtest/gtest.h"
10 #include "impeller/entity/entity.h"
12 
13 namespace impeller {
14 namespace testing {
15 
16 TEST(EntityPassClipStackTest, CanPushAndPopEntities) {
17  EntityPassClipStack recorder =
18  EntityPassClipStack(Rect::MakeLTRB(0, 0, 100, 100));
19 
20  EXPECT_TRUE(recorder.GetReplayEntities().empty());
21 
22  Entity entity;
24  Rect::MakeLTRB(0, 0, 100, 100));
25  EXPECT_EQ(recorder.GetReplayEntities().size(), 1u);
26 
28  Rect::MakeLTRB(0, 0, 50, 50));
29  EXPECT_EQ(recorder.GetReplayEntities().size(), 2u);
30  ASSERT_TRUE(recorder.GetReplayEntities()[0].clip_coverage.has_value());
31  ASSERT_TRUE(recorder.GetReplayEntities()[1].clip_coverage.has_value());
32  // NOLINTBEGIN(bugprone-unchecked-optional-access)
33  EXPECT_EQ(recorder.GetReplayEntities()[0].clip_coverage.value(),
34  Rect::MakeLTRB(0, 0, 100, 100));
35  EXPECT_EQ(recorder.GetReplayEntities()[1].clip_coverage.value(),
36  Rect::MakeLTRB(0, 0, 50, 50));
37  // NOLINTEND(bugprone-unchecked-optional-access)
38 
40  EXPECT_EQ(recorder.GetReplayEntities().size(), 1u);
41 
43  EXPECT_TRUE(recorder.GetReplayEntities().empty());
44 }
45 
46 TEST(EntityPassClipStackTest, CanPopEntitiesSafely) {
47  EntityPassClipStack recorder =
48  EntityPassClipStack(Rect::MakeLTRB(0, 0, 100, 100));
49 
50  EXPECT_TRUE(recorder.GetReplayEntities().empty());
51 
52  Entity entity;
54  EXPECT_TRUE(recorder.GetReplayEntities().empty());
55 }
56 
57 TEST(EntityPassClipStackTest, CanAppendNoChange) {
58  EntityPassClipStack recorder =
59  EntityPassClipStack(Rect::MakeLTRB(0, 0, 100, 100));
60 
61  EXPECT_TRUE(recorder.GetReplayEntities().empty());
62 
63  Entity entity;
65  Rect());
66  EXPECT_TRUE(recorder.GetReplayEntities().empty());
67 }
68 
69 TEST(EntityPassClipStackTest, AppendCoverageNoChange) {
70  EntityPassClipStack recorder =
71  EntityPassClipStack(Rect::MakeLTRB(0, 0, 100, 100));
72 
73  EXPECT_EQ(recorder.GetClipCoverageLayers()[0].coverage,
74  Rect::MakeSize(Size::MakeWH(100, 100)));
75  EXPECT_EQ(recorder.GetClipCoverageLayers()[0].clip_height, 0u);
76 
77  Entity entity;
81  .coverage = std::nullopt,
82  },
83  entity, 0, Point(0, 0));
84  EXPECT_TRUE(result.should_render);
85  EXPECT_FALSE(result.clip_did_change);
86 
87  EXPECT_EQ(recorder.GetClipCoverageLayers()[0].coverage,
88  Rect::MakeSize(Size::MakeWH(100, 100)));
89  EXPECT_EQ(recorder.GetClipCoverageLayers()[0].clip_height, 0u);
90 }
91 
92 TEST(EntityPassClipStackTest, AppendAndRestoreClipCoverage) {
93  EntityPassClipStack recorder =
94  EntityPassClipStack(Rect::MakeLTRB(0, 0, 100, 100));
95 
96  ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 1u);
97 
98  // Push a clip.
99  Entity entity;
103  .coverage = Rect::MakeLTRB(50, 50, 55, 55),
104  },
105  entity, 0, Point(0, 0));
106  EXPECT_TRUE(result.should_render);
107  EXPECT_TRUE(result.clip_did_change);
108 
109  ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 2u);
110  EXPECT_EQ(recorder.GetClipCoverageLayers()[1].coverage,
111  Rect::MakeLTRB(50, 50, 55, 55));
112  EXPECT_EQ(recorder.GetClipCoverageLayers()[1].clip_height, 1u);
113  EXPECT_EQ(recorder.GetReplayEntities().size(), 1u);
114 
115  // Restore the clip.
116  auto restore_clip = std::make_shared<ClipRestoreContents>();
117  restore_clip->SetRestoreHeight(0);
118  entity.SetContents(std::move(restore_clip));
119  recorder.ApplyClipState(
122  .coverage = Rect::MakeLTRB(50, 50, 55, 55),
123  },
124  entity, 0, Point(0, 0));
125 
126  ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 1u);
127  EXPECT_EQ(recorder.GetClipCoverageLayers()[0].coverage,
128  Rect::MakeSize(Size::MakeWH(100, 100)));
129  EXPECT_EQ(recorder.GetClipCoverageLayers()[0].clip_height, 0u);
130  EXPECT_EQ(recorder.GetReplayEntities().size(), 0u);
131 }
132 
133 // Append two clip coverages, the second is larger the first. This
134 // should result in the second clip not requiring any update.
135 TEST(EntityPassClipStackTest, AppendLargerClipCoverage) {
136  EntityPassClipStack recorder =
137  EntityPassClipStack(Rect::MakeLTRB(0, 0, 100, 100));
138 
139  ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 1u);
140 
141  // Push a clip.
142  Entity entity;
146  .coverage = Rect::MakeLTRB(50, 50, 55, 55),
147  },
148  entity, 0, Point(0, 0));
149  EXPECT_TRUE(result.should_render);
150  EXPECT_TRUE(result.clip_did_change);
151 
152  // Push a clip with larger coverage than the previous state.
153  result = recorder.ApplyClipState(
156  .coverage = Rect::MakeLTRB(0, 0, 100, 100),
157  },
158  entity, 0, Point(0, 0));
159 
160  EXPECT_FALSE(result.should_render);
161  EXPECT_FALSE(result.clip_did_change);
162 }
163 
164 // Since clip entities return the outer coverage we can only cull axis aligned
165 // rectangles and intersect clips.
166 TEST(EntityPassClipStackTest,
167  AppendLargerClipCoverageWithDifferenceOrNonSquare) {
168  EntityPassClipStack recorder =
169  EntityPassClipStack(Rect::MakeLTRB(0, 0, 100, 100));
170 
171  ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 1u);
172 
173  // Push a clip.
174  Entity entity;
178  .coverage = Rect::MakeLTRB(50, 50, 55, 55),
179  },
180  entity, 0, Point(0, 0));
181  EXPECT_TRUE(result.should_render);
182  EXPECT_TRUE(result.clip_did_change);
183 
184  // Push a clip with larger coverage than the previous state.
185  result = recorder.ApplyClipState(
188  .is_difference_or_non_square = true,
189  .coverage = Rect::MakeLTRB(0, 0, 100, 100),
190  },
191  entity, 0, Point(0, 0));
192 
193  EXPECT_TRUE(result.should_render);
194  EXPECT_TRUE(result.clip_did_change);
195 }
196 
197 TEST(EntityPassClipStackTest, AppendDecreasingSizeClipCoverage) {
198  EntityPassClipStack recorder =
199  EntityPassClipStack(Rect::MakeLTRB(0, 0, 100, 100));
200 
201  ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 1u);
202 
203  // Push Clips that shrink in size. All should be applied.
204  Entity entity;
205 
206  for (auto i = 1; i < 20; i++) {
210  .coverage = Rect::MakeLTRB(i, i, 100 - i, 100 - i),
211  },
212  entity, 0, Point(0, 0));
213  EXPECT_TRUE(result.should_render);
214  EXPECT_TRUE(result.clip_did_change);
215  EXPECT_EQ(recorder.CurrentClipCoverage(),
216  Rect::MakeLTRB(i, i, 100 - i, 100 - i));
217  }
218 }
219 
220 TEST(EntityPassClipStackTest, AppendIncreasingSizeClipCoverage) {
221  EntityPassClipStack recorder =
222  EntityPassClipStack(Rect::MakeLTRB(0, 0, 100, 100));
223 
224  ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 1u);
225 
226  // Push Clips that grow in size. All should be skipped.
227  Entity entity;
228 
229  for (auto i = 1; i < 20; i++) {
233  .coverage = Rect::MakeLTRB(0 - i, 0 - i, 100 + i, 100 + i),
234  },
235  entity, 0, Point(0, 0));
236  EXPECT_FALSE(result.should_render);
237  EXPECT_FALSE(result.clip_did_change);
238  EXPECT_EQ(recorder.CurrentClipCoverage(), Rect::MakeLTRB(0, 0, 100, 100));
239  }
240 }
241 
242 TEST(EntityPassClipStackTest, UnbalancedRestore) {
243  EntityPassClipStack recorder =
244  EntityPassClipStack(Rect::MakeLTRB(0, 0, 100, 100));
245 
246  ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 1u);
247 
248  // Restore the clip.
249  Entity entity;
250  auto restore_clip = std::make_shared<ClipRestoreContents>();
251  restore_clip->SetRestoreHeight(0);
252  entity.SetContents(std::move(restore_clip));
256  .coverage = Rect::MakeLTRB(50, 50, 55, 55),
257  },
258  entity, 0, Point(0, 0));
259  EXPECT_FALSE(result.should_render);
260  EXPECT_FALSE(result.clip_did_change);
261 
262  ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 1u);
263  EXPECT_EQ(recorder.GetClipCoverageLayers()[0].coverage,
264  Rect::MakeSize(Size::MakeWH(100, 100)));
265  EXPECT_EQ(recorder.GetClipCoverageLayers()[0].clip_height, 0u);
266  EXPECT_EQ(recorder.GetReplayEntities().size(), 0u);
267 }
268 
269 TEST(EntityPassClipStackTest, ClipAndRestoreWithSubpasses) {
270  EntityPassClipStack recorder =
271  EntityPassClipStack(Rect::MakeLTRB(0, 0, 100, 100));
272 
273  ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 1u);
274 
275  // Push a clip.
276  Entity entity;
277  {
281  .coverage = Rect::MakeLTRB(50, 50, 55, 55),
282  },
283  entity, 0, Point(0, 0));
284  EXPECT_TRUE(result.should_render);
285  EXPECT_TRUE(result.clip_did_change);
286  }
287 
288  ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 2u);
289  EXPECT_EQ(recorder.GetClipCoverageLayers()[1].coverage,
290  Rect::MakeLTRB(50, 50, 55, 55));
291  EXPECT_EQ(recorder.GetClipCoverageLayers()[1].clip_height, 1u);
292  EXPECT_EQ(recorder.GetReplayEntities().size(), 1u);
293 
294  // Begin a subpass.
295  recorder.PushSubpass(Rect::MakeLTRB(50, 50, 55, 55), 1);
296  ASSERT_EQ(recorder.GetClipCoverageLayers().size(), 1u);
297  EXPECT_EQ(recorder.GetClipCoverageLayers()[0].coverage,
298  Rect::MakeLTRB(50, 50, 55, 55));
299 
300  {
304  .coverage = Rect::MakeLTRB(54, 54, 55, 55),
305  },
306  entity, 0, Point(0, 0));
307  EXPECT_TRUE(result.should_render);
308  EXPECT_TRUE(result.clip_did_change);
309  }
310 
311  EXPECT_EQ(recorder.GetClipCoverageLayers()[1].coverage,
312  Rect::MakeLTRB(54, 54, 55, 55));
313 
314  // End subpass.
315  recorder.PopSubpass();
316 
317  EXPECT_EQ(recorder.GetClipCoverageLayers()[1].coverage,
318  Rect::MakeLTRB(50, 50, 55, 55));
319 }
320 
321 } // namespace testing
322 } // namespace impeller
impeller::EntityPassClipStack::ClipStateResult::should_render
bool should_render
Definition: entity_pass_clip_stack.h:34
impeller::EntityPassClipStack::PushSubpass
void PushSubpass(std::optional< Rect > subpass_coverage, size_t clip_height)
Definition: entity_pass_clip_stack.cc:33
entity.h
impeller::EntityPassClipStack::GetClipCoverageLayers
const std::vector< ClipCoverageLayer > GetClipCoverageLayers() const
Definition: entity_pass_clip_stack.cc:51
impeller::Contents::ClipCoverage::Type::kRestore
@ kRestore
impeller::Entity::SetContents
void SetContents(std::shared_ptr< Contents > contents)
Definition: entity.cc:83
impeller::Entity
Definition: entity.h:20
impeller::EntityPassClipStack::ApplyClipState
ClipStateResult ApplyClipState(Contents::ClipCoverage global_clip_coverage, Entity &entity, size_t clip_height_floor, Point global_pass_position)
Applies the current clip state to an Entity. If the given Entity is a clip operation,...
Definition: entity_pass_clip_stack.cc:55
impeller::EntityPassClipStack::GetReplayEntities
const std::vector< ReplayResult > & GetReplayEntities() const
Definition: entity_pass_clip_stack.cc:185
impeller::Point
TPoint< Scalar > Point
Definition: point.h:327
impeller::EntityPassClipStack::CurrentClipCoverage
std::optional< Rect > CurrentClipCoverage() const
Definition: entity_pass_clip_stack.cc:25
impeller::Contents::ClipCoverage::type
Type type
Definition: contents.h:40
clip_contents.h
impeller::Rect
TRect< Scalar > Rect
Definition: rect.h:776
impeller::EntityPassClipStack::PopSubpass
void PopSubpass()
Definition: entity_pass_clip_stack.cc:45
entity_pass_clip_stack.h
impeller::EntityPassClipStack::RecordEntity
void RecordEntity(const Entity &entity, Contents::ClipCoverage::Type type, std::optional< Rect > clip_coverage)
Definition: entity_pass_clip_stack.cc:150
impeller::EntityPassClipStack::ClipStateResult::clip_did_change
bool clip_did_change
Definition: entity_pass_clip_stack.h:37
impeller::TRect< Scalar >::MakeSize
constexpr static TRect MakeSize(const TSize< U > &size)
Definition: rect.h:150
impeller::Contents::ClipCoverage
Definition: contents.h:37
impeller::Contents::ClipCoverage::Type::kAppend
@ kAppend
impeller::EntityPassClipStack
A class that tracks all clips that have been recorded in the current entity pass stencil.
Definition: entity_pass_clip_stack.h:24
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:34
impeller::EntityPassClipStack::ClipStateResult
Definition: entity_pass_clip_stack.h:31
impeller
Definition: allocation.cc:12
impeller::testing::TEST
TEST(AllocationSizeTest, CanCreateTypedAllocations)
Definition: allocation_size_unittests.cc:10
impeller::Contents::ClipCoverage::Type::kNoChange
@ kNoChange