Flutter Engine
The Flutter Engine
display_list_layer_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#define FML_USED_ON_EMBEDDER
6
7#include "flutter/flow/layers/display_list_layer.h"
8
9#include "flutter/display_list/dl_builder.h"
10#include "flutter/flow/layers/layer_tree.h"
11#include "flutter/flow/testing/diff_context_test.h"
12#include "flutter/fml/macros.h"
13
14// TODO(zanderso): https://github.com/flutter/flutter/issues/127701
15// NOLINTBEGIN(bugprone-unchecked-optional-access)
16
17namespace flutter {
18namespace testing {
19
21
22#ifndef NDEBUG
23TEST_F(DisplayListLayerTest, PaintBeforePrerollInvalidDisplayListDies) {
24 const SkPoint layer_offset = SkPoint::Make(0.0f, 0.0f);
25 auto layer = std::make_shared<DisplayListLayer>(
26 layer_offset, sk_sp<DisplayList>(), false, false);
27
28 EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()), "display_list_");
29}
30
31TEST_F(DisplayListLayerTest, PaintBeforePrerollDies) {
32 const SkPoint layer_offset = SkPoint::Make(0.0f, 0.0f);
33 const SkRect picture_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 20.5f, 21.5f);
35 builder.DrawRect(picture_bounds, DlPaint());
36 auto display_list = builder.Build();
37 auto layer = std::make_shared<DisplayListLayer>(layer_offset, display_list,
38 false, false);
39
40 EXPECT_EQ(layer->paint_bounds(), SkRect::MakeEmpty());
41 EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()),
42 "needs_painting\\(context\\)");
43}
44
45TEST_F(DisplayListLayerTest, PaintingEmptyLayerDies) {
46 const SkPoint layer_offset = SkPoint::Make(0.0f, 0.0f);
47 const SkRect picture_bounds = SkRect::MakeEmpty();
48 DisplayListBuilder builder;
49 builder.DrawRect(picture_bounds, DlPaint());
50 auto display_list = builder.Build();
51 auto layer = std::make_shared<DisplayListLayer>(layer_offset, display_list,
52 false, false);
53
54 layer->Preroll(preroll_context());
55 EXPECT_EQ(layer->paint_bounds(), SkRect::MakeEmpty());
56 EXPECT_FALSE(layer->needs_painting(paint_context()));
57
58 EXPECT_DEATH_IF_SUPPORTED(layer->Paint(paint_context()),
59 "needs_painting\\(context\\)");
60}
61
62TEST_F(DisplayListLayerTest, InvalidDisplayListDies) {
63 const SkPoint layer_offset = SkPoint::Make(0.0f, 0.0f);
64 auto layer = std::make_shared<DisplayListLayer>(
65 layer_offset, sk_sp<DisplayList>(), false, false);
66
67 // Crashes reading a nullptr.
68 EXPECT_DEATH_IF_SUPPORTED(layer->Preroll(preroll_context()), "");
69}
70#endif
71
72TEST_F(DisplayListLayerTest, SimpleDisplayList) {
73 const SkPoint layer_offset = SkPoint::Make(1.5f, -0.5f);
74 const SkRect picture_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 20.5f, 21.5f);
76 builder.DrawRect(picture_bounds, DlPaint());
77 auto display_list = builder.Build();
78 auto layer = std::make_shared<DisplayListLayer>(layer_offset, display_list,
79 false, false);
80
81 layer->Preroll(preroll_context());
82 EXPECT_EQ(layer->paint_bounds(),
83 picture_bounds.makeOffset(layer_offset.fX, layer_offset.fY));
84 EXPECT_EQ(layer->display_list(), display_list.get());
85 EXPECT_TRUE(layer->needs_painting(paint_context()));
86
87 layer->Paint(display_list_paint_context());
88 DisplayListBuilder expected_builder;
89 /* (DisplayList)layer::Paint */ {
90 expected_builder.Save();
91 {
92 expected_builder.Translate(layer_offset.fX, layer_offset.fY);
93 expected_builder.DrawDisplayList(display_list);
94 }
95 expected_builder.Restore();
96 }
98 DisplayListsEQ_Verbose(this->display_list(), expected_builder.Build()));
99}
100
101TEST_F(DisplayListLayerTest, CachingDoesNotChangeCullRect) {
102 const SkPoint layer_offset = SkPoint::Make(10, 10);
104 builder.DrawRect({10, 10, 20, 20}, DlPaint());
105 auto display_list = builder.Build();
106 auto layer = std::make_shared<DisplayListLayer>(layer_offset, display_list,
107 true, false);
108
109 SkRect original_cull_rect = preroll_context()->state_stack.device_cull_rect();
110 use_mock_raster_cache();
111 layer->Preroll(preroll_context());
112 ASSERT_EQ(preroll_context()->state_stack.device_cull_rect(),
113 original_cull_rect);
114}
115
116TEST_F(DisplayListLayerTest, SimpleDisplayListOpacityInheritance) {
117 const SkPoint layer_offset = SkPoint::Make(1.5f, -0.5f);
118 const SkRect picture_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 20.5f, 21.5f);
120 builder.DrawRect(picture_bounds, DlPaint());
121 auto display_list = builder.Build();
122 auto display_list_layer = std::make_shared<DisplayListLayer>(
123 layer_offset, display_list, false, false);
124 EXPECT_TRUE(display_list->can_apply_group_opacity());
125
126 auto context = preroll_context();
127 display_list_layer->Preroll(preroll_context());
128 EXPECT_EQ(context->renderable_state_flags,
130
131 int opacity_alpha = 0x7F;
132 SkScalar opacity = opacity_alpha / 255.0;
133 SkPoint opacity_offset = SkPoint::Make(10, 10);
134 auto opacity_layer =
135 std::make_shared<OpacityLayer>(opacity_alpha, opacity_offset);
136 opacity_layer->Add(display_list_layer);
137 opacity_layer->Preroll(context);
138 EXPECT_TRUE(opacity_layer->children_can_accept_opacity());
139
140 DisplayListBuilder child_builder;
141 child_builder.DrawRect(picture_bounds, DlPaint());
142 auto child_display_list = child_builder.Build();
143
144 DisplayListBuilder expected_builder;
145 /* opacity_layer::Paint() */ {
146 expected_builder.Save();
147 {
148 expected_builder.Translate(opacity_offset.fX, opacity_offset.fY);
149 /* display_list_layer::Paint() */ {
150 expected_builder.Save();
151 {
152 expected_builder.Translate(layer_offset.fX, layer_offset.fY);
153 expected_builder.DrawDisplayList(child_display_list, opacity);
154 }
155 expected_builder.Restore();
156 }
157 }
158 expected_builder.Restore();
159 }
160
161 opacity_layer->Paint(display_list_paint_context());
163 DisplayListsEQ_Verbose(this->display_list(), expected_builder.Build()));
164}
165
166TEST_F(DisplayListLayerTest, IncompatibleDisplayListOpacityInheritance) {
167 const SkPoint layer_offset = SkPoint::Make(1.5f, -0.5f);
168 const SkRect picture1_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 20.5f, 21.5f);
169 const SkRect picture2_bounds = SkRect::MakeLTRB(10.0f, 15.0f, 30.0f, 35.0f);
171 builder.DrawRect(picture1_bounds, DlPaint());
172 builder.DrawRect(picture2_bounds, DlPaint());
173 auto display_list = builder.Build();
174 auto display_list_layer = std::make_shared<DisplayListLayer>(
175 layer_offset, display_list, false, false);
176 EXPECT_FALSE(display_list->can_apply_group_opacity());
177
178 auto context = preroll_context();
179 display_list_layer->Preroll(preroll_context());
180 EXPECT_EQ(context->renderable_state_flags, 0);
181
182 int opacity_alpha = 0x7F;
183 SkPoint opacity_offset = SkPoint::Make(10, 10);
184 auto opacity_layer =
185 std::make_shared<OpacityLayer>(opacity_alpha, opacity_offset);
186 opacity_layer->Add(display_list_layer);
187 opacity_layer->Preroll(context);
188 EXPECT_FALSE(opacity_layer->children_can_accept_opacity());
189
190 DisplayListBuilder child_builder;
191 child_builder.DrawRect(picture1_bounds, DlPaint());
192 child_builder.DrawRect(picture2_bounds, DlPaint());
193 auto child_display_list = child_builder.Build();
194
195 auto display_list_bounds = picture1_bounds;
196 display_list_bounds.join(picture2_bounds);
197 auto save_layer_bounds =
198 display_list_bounds.makeOffset(layer_offset.fX, layer_offset.fY);
199 DisplayListBuilder expected_builder;
200 /* opacity_layer::Paint() */ {
201 expected_builder.Save();
202 {
203 expected_builder.Translate(opacity_offset.fX, opacity_offset.fY);
204 expected_builder.SaveLayer(&save_layer_bounds,
205 &DlPaint().setAlpha(opacity_alpha));
206 {
207 /* display_list_layer::Paint() */ {
208 expected_builder.Save();
209 {
210 expected_builder.Translate(layer_offset.fX, layer_offset.fY);
211 expected_builder.DrawDisplayList(child_display_list);
212 }
213 expected_builder.Restore();
214 }
215 }
216 expected_builder.Restore();
217 }
218 expected_builder.Restore();
219 }
220
221 opacity_layer->Paint(display_list_paint_context());
223 DisplayListsEQ_Verbose(this->display_list(), expected_builder.Build()));
224}
225
226TEST_F(DisplayListLayerTest, CachedIncompatibleDisplayListOpacityInheritance) {
227 const SkPoint layer_offset = SkPoint::Make(1.5f, -0.5f);
228 const SkRect picture1_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 20.5f, 21.5f);
229 const SkRect picture2_bounds = SkRect::MakeLTRB(10.0f, 15.0f, 30.0f, 35.0f);
231 builder.DrawRect(picture1_bounds, DlPaint());
232 builder.DrawRect(picture2_bounds, DlPaint());
233 auto display_list = builder.Build();
234 auto display_list_layer = std::make_shared<DisplayListLayer>(
235 layer_offset, display_list, true, false);
236 EXPECT_FALSE(display_list->can_apply_group_opacity());
237
238 use_skia_raster_cache();
239
240 auto context = preroll_context();
241 display_list_layer->Preroll(preroll_context());
242 EXPECT_EQ(context->renderable_state_flags, 0);
243
244 // Pump the DisplayListLayer until it is ready to cache its DL
245 display_list_layer->Preroll(preroll_context());
246 display_list_layer->Preroll(preroll_context());
247 display_list_layer->Preroll(preroll_context());
248 LayerTree::TryToRasterCache(*preroll_context()->raster_cached_entries,
249 &paint_context(), false);
250
251 int opacity_alpha = 0x7F;
252 SkPoint opacity_offset = SkPoint::Make(10.2, 10.2);
253 auto opacity_layer =
254 std::make_shared<OpacityLayer>(opacity_alpha, opacity_offset);
255 opacity_layer->Add(display_list_layer);
256 opacity_layer->Preroll(context);
257 EXPECT_TRUE(opacity_layer->children_can_accept_opacity());
258
259 auto display_list_bounds = picture1_bounds;
260 display_list_bounds.join(picture2_bounds);
261 auto save_layer_bounds =
262 display_list_bounds.makeOffset(layer_offset.fX, layer_offset.fY);
263 save_layer_bounds.roundOut(&save_layer_bounds);
264 auto opacity_integral_matrix =
266 SkMatrix layer_offset_matrix = opacity_integral_matrix;
267 layer_offset_matrix.postTranslate(layer_offset.fX, layer_offset.fY);
268 auto layer_offset_integral_matrix =
269 RasterCacheUtil::GetIntegralTransCTM(layer_offset_matrix);
270 DisplayListBuilder expected(SkRect::MakeWH(1000, 1000));
271 /* opacity_layer::Paint() */ {
272 expected.Save();
273 {
274 expected.Translate(opacity_offset.fX, opacity_offset.fY);
275 expected.TransformReset();
276 expected.Transform(opacity_integral_matrix);
277 /* display_list_layer::Paint() */ {
278 expected.Save();
279 {
280 expected.Translate(layer_offset.fX, layer_offset.fY);
281 expected.TransformReset();
282 expected.Transform(layer_offset_integral_matrix);
283 context->raster_cache->Draw(display_list_layer->caching_key_id(),
284 expected,
285 &DlPaint().setAlpha(opacity_alpha));
286 }
287 expected.Restore();
288 }
289 }
290 expected.Restore();
291 }
292
293 opacity_layer->Paint(display_list_paint_context());
294 EXPECT_TRUE(DisplayListsEQ_Verbose(expected.Build(), this->display_list()));
295}
296
297TEST_F(DisplayListLayerTest, RasterCachePreservesRTree) {
298 const SkRect picture1_bounds = SkRect::MakeXYWH(10, 10, 10, 10);
299 const SkRect picture2_bounds = SkRect::MakeXYWH(15, 15, 10, 10);
301 builder.DrawRect(picture1_bounds, DlPaint());
302 builder.DrawRect(picture2_bounds, DlPaint());
303 auto display_list = builder.Build();
304 auto display_list_layer = std::make_shared<DisplayListLayer>(
305 SkPoint::Make(3, 3), display_list, true, false);
306
307 use_skia_raster_cache();
308
309 auto context = preroll_context();
310 {
311 auto mutator = context->state_stack.save();
312 mutator.transform(SkMatrix::Scale(2.0, 2.0));
313 display_list_layer->Preroll(preroll_context());
314 EXPECT_EQ(context->renderable_state_flags, 0);
315
316 // Pump the DisplayListLayer until it is ready to cache its DL
317 display_list_layer->Preroll(preroll_context());
318 display_list_layer->Preroll(preroll_context());
319 display_list_layer->Preroll(preroll_context());
320 LayerTree::TryToRasterCache(*preroll_context()->raster_cached_entries,
321 &paint_context(), false);
322 }
323
324 DisplayListBuilder expected_root_canvas(true);
325 expected_root_canvas.Scale(2.0, 2.0);
326 ASSERT_TRUE(context->raster_cache->Draw(display_list_layer->caching_key_id(),
327 expected_root_canvas, nullptr,
328 false));
329 auto root_canvas_dl = expected_root_canvas.Build();
330 const auto root_canvas_rects =
331 root_canvas_dl->rtree()->searchAndConsolidateRects(kGiantRect, true);
332 std::list<SkRect> root_canvas_rects_expected = {
333 SkRect::MakeLTRB(26, 26, 56, 56),
334 };
335 EXPECT_EQ(root_canvas_rects_expected, root_canvas_rects);
336
337 DisplayListBuilder expected_overlay_canvas(true);
338 expected_overlay_canvas.Scale(2.0, 2.0);
339 ASSERT_TRUE(context->raster_cache->Draw(display_list_layer->caching_key_id(),
340 expected_overlay_canvas, nullptr,
341 true));
342 auto overlay_canvas_dl = expected_overlay_canvas.Build();
343 const auto overlay_canvas_rects =
344 overlay_canvas_dl->rtree()->searchAndConsolidateRects(kGiantRect, true);
345
346 // Same bounds as root canvas, but preserves individual rects.
347 std::list<SkRect> overlay_canvas_rects_expected = {
348 SkRect::MakeLTRB(26, 26, 46, 36),
349 SkRect::MakeLTRB(26, 36, 56, 46),
350 SkRect::MakeLTRB(36, 46, 56, 56),
351 };
352 EXPECT_EQ(overlay_canvas_rects_expected, overlay_canvas_rects);
353};
354
356
357TEST_F(DisplayListLayerDiffTest, SimpleDisplayList) {
358 auto display_list = CreateDisplayList(SkRect::MakeLTRB(10, 10, 60, 60));
359
360 MockLayerTree tree1;
361 tree1.root()->Add(CreateDisplayListLayer(display_list));
362
363 auto damage = DiffLayerTree(tree1, MockLayerTree());
364 EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(10, 10, 60, 60));
365
366 MockLayerTree tree2;
367 tree2.root()->Add(CreateDisplayListLayer(display_list));
368
369 damage = DiffLayerTree(tree2, tree1);
370 EXPECT_TRUE(damage.frame_damage.isEmpty());
371
372 MockLayerTree tree3;
373 damage = DiffLayerTree(tree3, tree2);
374 EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(10, 10, 60, 60));
375}
376
377TEST_F(DisplayListLayerDiffTest, FractionalTranslation) {
378 auto display_list = CreateDisplayList(SkRect::MakeLTRB(10, 10, 60, 60));
379
380 MockLayerTree tree1;
381 tree1.root()->Add(
382 CreateDisplayListLayer(display_list, SkPoint::Make(0.5, 0.5)));
383
384 auto damage =
385 DiffLayerTree(tree1, MockLayerTree(), SkIRect::MakeEmpty(), 0, 0,
386 /*use_raster_cache=*/false);
387 EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(10, 10, 61, 61));
388}
389
390TEST_F(DisplayListLayerDiffTest, FractionalTranslationWithRasterCache) {
391 auto display_list = CreateDisplayList(SkRect::MakeLTRB(10, 10, 60, 60));
392
393 MockLayerTree tree1;
394 tree1.root()->Add(
395 CreateDisplayListLayer(display_list, SkPoint::Make(0.5, 0.5)));
396
397 auto damage =
398 DiffLayerTree(tree1, MockLayerTree(), SkIRect::MakeEmpty(), 0, 0,
399 /*use_raster_cache=*/true);
400 EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(11, 11, 61, 61));
401}
402
404 MockLayerTree tree1;
405 auto display_list1 =
406 CreateDisplayList(SkRect::MakeLTRB(10, 10, 60, 60), DlColor::kGreen());
407 tree1.root()->Add(CreateDisplayListLayer(display_list1));
408
409 auto damage = DiffLayerTree(tree1, MockLayerTree());
410 EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(10, 10, 60, 60));
411
412 MockLayerTree tree2;
413 // same DL, same offset
414 auto display_list2 =
415 CreateDisplayList(SkRect::MakeLTRB(10, 10, 60, 60), DlColor::kGreen());
416 tree2.root()->Add(CreateDisplayListLayer(display_list2));
417
418 damage = DiffLayerTree(tree2, tree1);
419 EXPECT_EQ(damage.frame_damage, SkIRect::MakeEmpty());
420
421 MockLayerTree tree3;
422 auto display_list3 =
423 CreateDisplayList(SkRect::MakeLTRB(10, 10, 60, 60), DlColor::kGreen());
424 // add offset
425 tree3.root()->Add(
426 CreateDisplayListLayer(display_list3, SkPoint::Make(10, 10)));
427
428 damage = DiffLayerTree(tree3, tree2);
429 EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(10, 10, 70, 70));
430
431 MockLayerTree tree4;
432 // different color
433 auto display_list4 =
434 CreateDisplayList(SkRect::MakeLTRB(10, 10, 60, 60), DlColor::kRed());
435 tree4.root()->Add(
436 CreateDisplayListLayer(display_list4, SkPoint::Make(10, 10)));
437
438 damage = DiffLayerTree(tree4, tree3);
439 EXPECT_EQ(damage.frame_damage, SkIRect::MakeLTRB(20, 20, 70, 70));
440}
441
442TEST_F(DisplayListLayerTest, LayerTreeSnapshotsWhenEnabled) {
443 const SkPoint layer_offset = SkPoint::Make(1.5f, -0.5f);
444 const SkRect picture_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 20.5f, 21.5f);
446 builder.DrawRect(picture_bounds, DlPaint());
447 auto display_list = builder.Build();
448 auto layer = std::make_shared<DisplayListLayer>(layer_offset, display_list,
449 false, false);
450
451 layer->Preroll(preroll_context());
452
453 enable_leaf_layer_tracing();
454 layer->Paint(paint_context());
455 disable_leaf_layer_tracing();
456
457 auto& snapshot_store = layer_snapshot_store();
458 EXPECT_EQ(1u, snapshot_store.Size());
459}
460
461TEST_F(DisplayListLayerTest, NoLayerTreeSnapshotsWhenDisabledByDefault) {
462 const SkPoint layer_offset = SkPoint::Make(1.5f, -0.5f);
463 const SkRect picture_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 20.5f, 21.5f);
465 builder.DrawRect(picture_bounds, DlPaint());
466 auto display_list = builder.Build();
467 auto layer = std::make_shared<DisplayListLayer>(layer_offset, display_list,
468 false, false);
469
470 layer->Preroll(preroll_context());
471 layer->Paint(paint_context());
472
473 auto& snapshot_store = layer_snapshot_store();
474 EXPECT_EQ(0u, snapshot_store.Size());
475}
476
477TEST_F(DisplayListLayerTest, DisplayListAccessCountDependsOnVisibility) {
478 const SkPoint layer_offset = SkPoint::Make(1.5f, -0.5f);
479 const SkRect picture_bounds = SkRect::MakeLTRB(5.0f, 6.0f, 20.5f, 21.5f);
480 const SkRect missed_cull_rect = SkRect::MakeLTRB(100, 100, 200, 200);
481 const SkRect hit_cull_rect = SkRect::MakeLTRB(0, 0, 200, 200);
483 builder.DrawRect(picture_bounds, DlPaint());
484 auto display_list = builder.Build();
485 auto layer = std::make_shared<DisplayListLayer>(layer_offset, display_list,
486 true, false);
487
488 auto raster_cache_item = layer->raster_cache_item();
489 use_mock_raster_cache();
490
491 // First Preroll the DisplayListLayer a few times where it does not intersect
492 // the cull rect. No caching progress should occur during this time, the
493 // access_count should remain 0 because the DisplayList was never "visible".
494 ASSERT_TRUE(preroll_context()->state_stack.is_empty());
495 preroll_context()->state_stack.set_preroll_delegate(missed_cull_rect);
496 for (int i = 0; i < 10; i++) {
497 preroll_context()->raster_cached_entries->clear();
498 layer->Preroll(preroll_context());
499 ASSERT_EQ(raster_cache_item->cache_state(), RasterCacheItem::kNone);
500 ASSERT_TRUE(raster_cache_item->GetId().has_value());
501 ASSERT_EQ(preroll_context()->raster_cache->GetAccessCount(
502 raster_cache_item->GetId().value(), SkMatrix::I()),
503 0);
504 ASSERT_EQ(preroll_context()->raster_cached_entries->size(), size_t(1));
505 ASSERT_EQ(preroll_context()->raster_cache->EstimatePictureCacheByteSize(),
506 size_t(0));
507 ASSERT_FALSE(raster_cache_item->TryToPrepareRasterCache(paint_context()));
508 ASSERT_FALSE(raster_cache_item->Draw(paint_context(), nullptr));
509 }
510
511 // Next Preroll the DisplayListLayer once where it does intersect
512 // the cull rect. No caching progress should occur during this time
513 // since this is the first frame in which it was visible, but the
514 // count should start incrementing.
515 ASSERT_TRUE(preroll_context()->state_stack.is_empty());
516 preroll_context()->state_stack.set_preroll_delegate(hit_cull_rect);
517 preroll_context()->raster_cached_entries->clear();
518 layer->Preroll(preroll_context());
519 ASSERT_EQ(raster_cache_item->cache_state(), RasterCacheItem::kNone);
520 ASSERT_TRUE(raster_cache_item->GetId().has_value());
521 ASSERT_EQ(preroll_context()->raster_cache->GetAccessCount(
522 raster_cache_item->GetId().value(), SkMatrix::I()),
523 1);
524 ASSERT_EQ(preroll_context()->raster_cached_entries->size(), size_t(1));
525 ASSERT_EQ(preroll_context()->raster_cache->EstimatePictureCacheByteSize(),
526 size_t(0));
527 ASSERT_FALSE(raster_cache_item->TryToPrepareRasterCache(paint_context()));
528 ASSERT_FALSE(raster_cache_item->Draw(paint_context(), nullptr));
529
530 // Now we can Preroll the DisplayListLayer again with a cull rect that
531 // it does not intersect and it should continue to count these operations
532 // even though it is not visible. No actual caching should occur yet,
533 // even though we will surpass its threshold.
534 ASSERT_TRUE(preroll_context()->state_stack.is_empty());
535 preroll_context()->state_stack.set_preroll_delegate(missed_cull_rect);
536 for (int i = 0; i < 10; i++) {
537 preroll_context()->raster_cached_entries->clear();
538 layer->Preroll(preroll_context());
539 ASSERT_EQ(raster_cache_item->cache_state(), RasterCacheItem::kNone);
540 ASSERT_TRUE(raster_cache_item->GetId().has_value());
541 ASSERT_EQ(preroll_context()->raster_cache->GetAccessCount(
542 raster_cache_item->GetId().value(), SkMatrix::I()),
543 i + 2);
544 ASSERT_EQ(preroll_context()->raster_cached_entries->size(), size_t(1));
545 ASSERT_EQ(preroll_context()->raster_cache->EstimatePictureCacheByteSize(),
546 size_t(0));
547 ASSERT_FALSE(raster_cache_item->TryToPrepareRasterCache(paint_context()));
548 ASSERT_FALSE(raster_cache_item->Draw(paint_context(), nullptr));
549 }
550
551 // Finally Preroll the DisplayListLayer again where it does intersect
552 // the cull rect. Since we should have exhausted our access count
553 // threshold in the loop above, these operations should result in the
554 // DisplayList being cached.
555 ASSERT_TRUE(preroll_context()->state_stack.is_empty());
556 preroll_context()->state_stack.set_preroll_delegate(hit_cull_rect);
557 preroll_context()->raster_cached_entries->clear();
558 layer->Preroll(preroll_context());
559 ASSERT_EQ(raster_cache_item->cache_state(), RasterCacheItem::kCurrent);
560 ASSERT_TRUE(raster_cache_item->GetId().has_value());
561 ASSERT_EQ(preroll_context()->raster_cache->GetAccessCount(
562 raster_cache_item->GetId().value(), SkMatrix::I()),
563 12);
564 ASSERT_EQ(preroll_context()->raster_cached_entries->size(), size_t(1));
565 ASSERT_EQ(preroll_context()->raster_cache->EstimatePictureCacheByteSize(),
566 size_t(0));
567 ASSERT_TRUE(raster_cache_item->TryToPrepareRasterCache(paint_context()));
568 ASSERT_GT(preroll_context()->raster_cache->EstimatePictureCacheByteSize(),
569 size_t(0));
570 ASSERT_TRUE(raster_cache_item->Draw(paint_context(), nullptr));
571}
572
573TEST_F(DisplayListLayerTest, OverflowCachedDisplayListOpacityInheritance) {
574 use_mock_raster_cache();
575 PrerollContext* context = preroll_context();
576 int per_frame =
578 int layer_count = per_frame + 1;
579 SkPoint opacity_offset = {10, 10};
580 auto opacity_layer = std::make_shared<OpacityLayer>(0.5f, opacity_offset);
581 std::vector<std::shared_ptr<DisplayListLayer>> layers;
582 for (int i = 0; i < layer_count; i++) {
584 builder.DrawRect({0, 0, 100, 100}, DlPaint());
585 builder.DrawRect({50, 50, 100, 100}, DlPaint());
586 auto display_list = builder.Build();
587 ASSERT_FALSE(display_list->can_apply_group_opacity());
588 SkPoint offset = {i * 200.0f, 0};
589
590 layers.push_back(
591 std::make_shared<DisplayListLayer>(offset, display_list, true, false));
592 opacity_layer->Add(layers.back());
593 }
594 for (size_t j = 0; j < context->raster_cache->access_threshold(); j++) {
595 context->raster_cache->BeginFrame();
596 for (int i = 0; i < layer_count; i++) {
597 context->renderable_state_flags = 0;
598 layers[i]->Preroll(context);
599 ASSERT_EQ(context->renderable_state_flags, 0) << "pass " << (j + 1);
600 }
601 }
602 opacity_layer->Preroll(context);
603 ASSERT_FALSE(opacity_layer->children_can_accept_opacity());
604 LayerTree::TryToRasterCache(*context->raster_cached_entries, &paint_context(),
605 false);
606 context->raster_cached_entries->clear();
607 context->raster_cache->BeginFrame();
608 for (int i = 0; i < per_frame; i++) {
609 context->renderable_state_flags = 0;
610 layers[i]->Preroll(context);
611 ASSERT_EQ(context->renderable_state_flags,
613 << "layer " << (i + 1);
614 }
615 for (int i = per_frame; i < layer_count; i++) {
616 context->renderable_state_flags = 0;
617 layers[i]->Preroll(context);
618 ASSERT_EQ(context->renderable_state_flags, 0) << "layer " << (i + 1);
619 }
620 opacity_layer->Preroll(context);
621 ASSERT_FALSE(opacity_layer->children_can_accept_opacity());
622 LayerTree::TryToRasterCache(*context->raster_cached_entries, &paint_context(),
623 false);
624 context->raster_cached_entries->clear();
625 context->raster_cache->BeginFrame();
626 for (int i = 0; i < layer_count; i++) {
627 context->renderable_state_flags = 0;
628 layers[i]->Preroll(context);
629 ASSERT_EQ(context->renderable_state_flags,
631 << "layer " << (i + 1);
632 }
633 opacity_layer->Preroll(context);
634 ASSERT_TRUE(opacity_layer->children_can_accept_opacity());
635}
636
637} // namespace testing
638} // namespace flutter
639
640// NOLINTEND(bugprone-unchecked-optional-access)
static SkMatrix Scale(SkScalar sx, SkScalar sy)
Definition: SkMatrix.h:75
SkMatrix & postTranslate(SkScalar dx, SkScalar dy)
Definition: SkMatrix.cpp:281
static SkMatrix Translate(SkScalar dx, SkScalar dy)
Definition: SkMatrix.h:91
static const SkMatrix & I()
Definition: SkMatrix.cpp:1544
virtual void Add(std::shared_ptr< Layer > layer)
void DrawRect(const SkRect &rect, const DlPaint &paint) override
Definition: dl_builder.cc:1116
void Transform(const SkMatrix *matrix) override
Definition: dl_builder.cc:919
void TransformReset() override
Definition: dl_builder.cc:893
void Translate(SkScalar tx, SkScalar ty) override
Definition: dl_builder.cc:799
void Scale(SkScalar sx, SkScalar sy) override
Definition: dl_builder.cc:807
void SaveLayer(const SkRect *bounds, const DlPaint *paint=nullptr, const DlImageFilter *backdrop=nullptr) override
Definition: dl_builder.cc:549
sk_sp< DisplayList > Build()
Definition: dl_builder.cc:67
void DrawDisplayList(const sk_sp< DisplayList > display_list, SkScalar opacity=SK_Scalar1) override
Definition: dl_builder.cc:1535
static constexpr int kCallerCanApplyOpacity
static void TryToRasterCache(const std::vector< RasterCacheItem * > &raster_cached_entries, const PaintContext *paint_context, bool ignore_raster_cache=false)
Definition: layer_tree.cc:68
float SkScalar
Definition: extension.cpp:12
TEST_F(DisplayListTest, Defaults)
LayerTestBase<::testing::Test > LayerTest
Definition: layer_test.h:210
bool DisplayListsEQ_Verbose(const DisplayList *a, const DisplayList *b)
DisplayListCompare
Definition: dl_op_records.h:72
static constexpr SkRect kGiantRect
Definition: layer.h:50
flutter::DlPaint DlPaint
SeparatedVector2 offset
static constexpr SkIRect MakeLTRB(int32_t l, int32_t t, int32_t r, int32_t b)
Definition: SkRect.h:91
static constexpr SkIRect MakeEmpty()
Definition: SkRect.h:45
float fX
x-axis value
Definition: SkPoint_impl.h:164
static constexpr SkPoint Make(float x, float y)
Definition: SkPoint_impl.h:173
float fY
y-axis value
Definition: SkPoint_impl.h:165
static constexpr SkRect MakeEmpty()
Definition: SkRect.h:595
constexpr SkRect makeOffset(float dx, float dy) const
Definition: SkRect.h:965
static constexpr SkRect MakeXYWH(float x, float y, float w, float h)
Definition: SkRect.h:659
void join(const SkRect &r)
Definition: SkRect.cpp:126
static constexpr SkRect MakeWH(float w, float h)
Definition: SkRect.h:609
static constexpr SkRect MakeLTRB(float l, float t, float r, float b)
Definition: SkRect.h:646
static constexpr DlColor kRed()
Definition: dl_color.h:24
static constexpr DlColor kGreen()
Definition: dl_color.h:25
std::vector< RasterCacheItem * > * raster_cached_entries
Definition: layer.h:85
int renderable_state_flags
Definition: layer.h:83
static SkMatrix GetIntegralTransCTM(const SkMatrix &ctm)
Snap the translation components of the matrix to integers.
static constexpr int kDefaultPictureAndDisplayListCacheLimitPerFrame
#define EXPECT_TRUE(handle)
Definition: unit_test.h:678