Flutter Engine
The Flutter Engine
raster_cache_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/display_list/benchmarking/dl_complexity.h"
6#include "flutter/display_list/display_list.h"
7#include "flutter/display_list/dl_builder.h"
8#include "flutter/display_list/testing/dl_test_snippets.h"
9#include "flutter/flow/layers/container_layer.h"
10#include "flutter/flow/layers/display_list_layer.h"
11#include "flutter/flow/layers/image_filter_layer.h"
12#include "flutter/flow/layers/layer_tree.h"
13#include "flutter/flow/layers/transform_layer.h"
14#include "flutter/flow/raster_cache.h"
15#include "flutter/flow/raster_cache_item.h"
16#include "flutter/flow/testing/layer_test.h"
17#include "flutter/flow/testing/mock_raster_cache.h"
18#include "flutter/testing/assertions_skia.h"
19#include "gtest/gtest.h"
22
23// TODO(zanderso): https://github.com/flutter/flutter/issues/127701
24// NOLINTBEGIN(bugprone-unchecked-optional-access)
25
26namespace flutter {
27namespace testing {
28
29TEST(RasterCache, SimpleInitialization) {
31 ASSERT_TRUE(true);
32}
33
34TEST(RasterCache, MetricsOmitUnpopulatedEntries) {
35 size_t threshold = 2;
36 flutter::RasterCache cache(threshold);
37
39
40 auto display_list = GetSampleDisplayList();
41
42 MockCanvas dummy_canvas(1000, 1000);
44
45 LayerStateStack preroll_state_stack;
46 preroll_state_stack.set_preroll_delegate(kGiantRect, matrix);
47 LayerStateStack paint_state_stack;
48 preroll_state_stack.set_delegate(&dummy_canvas);
49
50 FixedRefreshRateStopwatch raster_time;
53 preroll_state_stack, &cache, &raster_time, &ui_time);
55 paint_state_stack, &cache, &raster_time, &ui_time);
56 auto& preroll_context = preroll_context_holder.preroll_context;
57 auto& paint_context = paint_context_holder.paint_context;
58
59 cache.BeginFrame();
60 DisplayListRasterCacheItem display_list_item(display_list, SkPoint(), true,
61 false);
62
63 // 1st access.
65 display_list_item, preroll_context, paint_context, matrix));
66 ASSERT_FALSE(display_list_item.Draw(paint_context, &dummy_canvas, &paint));
67
68 cache.EndFrame();
69 ASSERT_EQ(cache.picture_metrics().total_count(), 0u);
70 ASSERT_EQ(cache.picture_metrics().total_bytes(), 0u);
71 cache.BeginFrame();
72
73 // 2nd access.
75 display_list_item, preroll_context, paint_context, matrix));
76 ASSERT_FALSE(display_list_item.Draw(paint_context, &dummy_canvas, &paint));
77
78 cache.EndFrame();
79 ASSERT_EQ(cache.picture_metrics().total_count(), 0u);
80 ASSERT_EQ(cache.picture_metrics().total_bytes(), 0u);
81 cache.BeginFrame();
82
83 // Now Prepare should cache it.
85 display_list_item, preroll_context, paint_context, matrix));
86 ASSERT_TRUE(display_list_item.Draw(paint_context, &dummy_canvas, &paint));
87
88 cache.EndFrame();
89 ASSERT_EQ(cache.picture_metrics().total_count(), 1u);
90 // 80w * 80h * 4bpp + image object overhead
91 ASSERT_EQ(cache.picture_metrics().total_bytes(), 25624u);
92}
93
94TEST(RasterCache, ThresholdIsRespectedForDisplayList) {
95 size_t threshold = 2;
96 flutter::RasterCache cache(threshold);
97
99
100 auto display_list = GetSampleDisplayList();
101
102 MockCanvas dummy_canvas(1000, 1000);
104
105 LayerStateStack preroll_state_stack;
106 preroll_state_stack.set_preroll_delegate(kGiantRect, matrix);
107 LayerStateStack paint_state_stack;
108 preroll_state_stack.set_delegate(&dummy_canvas);
109
110 FixedRefreshRateStopwatch raster_time;
113 preroll_state_stack, &cache, &raster_time, &ui_time);
114 PaintContextHolder paint_context_holder = GetSamplePaintContextHolder(
115 paint_state_stack, &cache, &raster_time, &ui_time);
116 auto& preroll_context = preroll_context_holder.preroll_context;
117 auto& paint_context = paint_context_holder.paint_context;
118
119 cache.BeginFrame();
120
121 DisplayListRasterCacheItem display_list_item(display_list, SkPoint(), true,
122 false);
123
124 // 1st access.
126 display_list_item, preroll_context, paint_context, matrix));
127 ASSERT_FALSE(display_list_item.Draw(paint_context, &dummy_canvas, &paint));
128
129 cache.EndFrame();
130 cache.BeginFrame();
131
132 // 2nd access.
134 display_list_item, preroll_context, paint_context, matrix));
135 ASSERT_FALSE(display_list_item.Draw(paint_context, &dummy_canvas, &paint));
136
137 cache.EndFrame();
138 cache.BeginFrame();
139
140 // Now Prepare should cache it.
142 display_list_item, preroll_context, paint_context, matrix));
143 ASSERT_TRUE(display_list_item.Draw(paint_context, &dummy_canvas, &paint));
144}
145
146TEST(RasterCache, AccessThresholdOfZeroDisablesCachingForDisplayList) {
147 size_t threshold = 0;
148 flutter::RasterCache cache(threshold);
149
151
152 auto display_list = GetSampleDisplayList();
153
154 MockCanvas dummy_canvas(1000, 1000);
156
157 LayerStateStack preroll_state_stack;
158 preroll_state_stack.set_preroll_delegate(kGiantRect, matrix);
159 LayerStateStack paint_state_stack;
160 preroll_state_stack.set_delegate(&dummy_canvas);
161
162 FixedRefreshRateStopwatch raster_time;
165 preroll_state_stack, &cache, &raster_time, &ui_time);
166 PaintContextHolder paint_context_holder = GetSamplePaintContextHolder(
167 paint_state_stack, &cache, &raster_time, &ui_time);
168 auto& preroll_context = preroll_context_holder.preroll_context;
169 auto& paint_context = paint_context_holder.paint_context;
170
171 cache.BeginFrame();
172
173 DisplayListRasterCacheItem display_list_item(display_list, SkPoint(), true,
174 false);
176 display_list_item, preroll_context, paint_context, matrix));
177 ASSERT_FALSE(display_list_item.Draw(paint_context, &dummy_canvas, &paint));
178}
179
180TEST(RasterCache, PictureCacheLimitPerFrameIsRespectedWhenZeroForDisplayList) {
181 size_t picture_cache_limit_per_frame = 0;
182 flutter::RasterCache cache(3, picture_cache_limit_per_frame);
183
185
186 auto display_list = GetSampleDisplayList();
187
188 MockCanvas dummy_canvas(1000, 1000);
190
191 LayerStateStack preroll_state_stack;
192 preroll_state_stack.set_preroll_delegate(kGiantRect, matrix);
193 LayerStateStack paint_state_stack;
194 preroll_state_stack.set_delegate(&dummy_canvas);
195
196 FixedRefreshRateStopwatch raster_time;
199 preroll_state_stack, &cache, &raster_time, &ui_time);
200 PaintContextHolder paint_context_holder = GetSamplePaintContextHolder(
201 paint_state_stack, &cache, &raster_time, &ui_time);
202 auto& preroll_context = preroll_context_holder.preroll_context;
203 auto& paint_context = paint_context_holder.paint_context;
204
205 cache.BeginFrame();
206
207 DisplayListRasterCacheItem display_list_item(display_list, SkPoint(), true,
208 false);
209 // 1st access.
211 display_list_item, preroll_context, paint_context, matrix));
212 ASSERT_FALSE(display_list_item.Draw(paint_context, &dummy_canvas, &paint));
213 // 2nd access.
215 display_list_item, preroll_context, paint_context, matrix));
216 ASSERT_FALSE(display_list_item.Draw(paint_context, &dummy_canvas, &paint));
217 // the picture_cache_limit_per_frame = 0, so don't cache it
219 display_list_item, preroll_context, paint_context, matrix));
220 ASSERT_FALSE(display_list_item.Draw(paint_context, &dummy_canvas, &paint));
221}
222
223TEST(RasterCache, EvictUnusedCacheEntries) {
224 size_t threshold = 1;
225 flutter::RasterCache cache(threshold);
226
228
229 auto display_list_1 = GetSampleDisplayList();
230 auto display_list_2 = GetSampleDisplayList();
231
232 MockCanvas dummy_canvas(1000, 1000);
234
235 LayerStateStack preroll_state_stack;
236 preroll_state_stack.set_preroll_delegate(kGiantRect, matrix);
237 LayerStateStack paint_state_stack;
238 preroll_state_stack.set_delegate(&dummy_canvas);
239
240 FixedRefreshRateStopwatch raster_time;
243 preroll_state_stack, &cache, &raster_time, &ui_time);
244 PaintContextHolder paint_context_holder = GetSamplePaintContextHolder(
245 paint_state_stack, &cache, &raster_time, &ui_time);
246 auto& preroll_context = preroll_context_holder.preroll_context;
247 auto& paint_context = paint_context_holder.paint_context;
248
249 DisplayListRasterCacheItem display_list_item_1(display_list_1, SkPoint(),
250 true, false);
251 DisplayListRasterCacheItem display_list_item_2(display_list_2, SkPoint(),
252 true, false);
253
254 cache.BeginFrame();
255 RasterCacheItemPreroll(display_list_item_1, preroll_context, matrix);
256 RasterCacheItemPreroll(display_list_item_2, preroll_context, matrix);
257 cache.EvictUnusedCacheEntries();
258 ASSERT_EQ(cache.EstimatePictureCacheByteSize(), 0u);
259 ASSERT_FALSE(
260 RasterCacheItemTryToRasterCache(display_list_item_1, paint_context));
261 ASSERT_FALSE(
262 RasterCacheItemTryToRasterCache(display_list_item_2, paint_context));
263 ASSERT_EQ(cache.EstimatePictureCacheByteSize(), 0u);
264 ASSERT_FALSE(display_list_item_1.Draw(paint_context, &dummy_canvas, &paint));
265 ASSERT_FALSE(display_list_item_2.Draw(paint_context, &dummy_canvas, &paint));
266 cache.EndFrame();
267
268 ASSERT_EQ(cache.EstimatePictureCacheByteSize(), 0u);
269 ASSERT_EQ(cache.picture_metrics().total_count(), 0u);
270 ASSERT_EQ(cache.picture_metrics().total_bytes(), 0u);
271
272 cache.BeginFrame();
273 RasterCacheItemPreroll(display_list_item_1, preroll_context, matrix);
274 RasterCacheItemPreroll(display_list_item_2, preroll_context, matrix);
275 cache.EvictUnusedCacheEntries();
276 ASSERT_EQ(cache.EstimatePictureCacheByteSize(), 0u);
277 ASSERT_TRUE(
278 RasterCacheItemTryToRasterCache(display_list_item_1, paint_context));
279 ASSERT_TRUE(
280 RasterCacheItemTryToRasterCache(display_list_item_2, paint_context));
281 ASSERT_EQ(cache.EstimatePictureCacheByteSize(), 51248u);
282 ASSERT_TRUE(display_list_item_1.Draw(paint_context, &dummy_canvas, &paint));
283 ASSERT_TRUE(display_list_item_2.Draw(paint_context, &dummy_canvas, &paint));
284 cache.EndFrame();
285
286 ASSERT_EQ(cache.EstimatePictureCacheByteSize(), 51248u);
287 ASSERT_EQ(cache.picture_metrics().total_count(), 2u);
288 ASSERT_EQ(cache.picture_metrics().total_bytes(), 51248u);
289
290 cache.BeginFrame();
291 RasterCacheItemPreroll(display_list_item_1, preroll_context, matrix);
292 cache.EvictUnusedCacheEntries();
293 ASSERT_EQ(cache.EstimatePictureCacheByteSize(), 25624u);
294 ASSERT_TRUE(
295 RasterCacheItemTryToRasterCache(display_list_item_1, paint_context));
296 ASSERT_EQ(cache.EstimatePictureCacheByteSize(), 25624u);
297 ASSERT_TRUE(display_list_item_1.Draw(paint_context, &dummy_canvas, &paint));
298 cache.EndFrame();
299
300 ASSERT_EQ(cache.EstimatePictureCacheByteSize(), 25624u);
301 ASSERT_EQ(cache.picture_metrics().total_count(), 1u);
302 ASSERT_EQ(cache.picture_metrics().total_bytes(), 25624u);
303
304 cache.BeginFrame();
305 cache.EvictUnusedCacheEntries();
306 ASSERT_EQ(cache.EstimatePictureCacheByteSize(), 0u);
307 cache.EndFrame();
308
309 ASSERT_EQ(cache.EstimatePictureCacheByteSize(), 0u);
310 ASSERT_EQ(cache.picture_metrics().total_count(), 0u);
311 ASSERT_EQ(cache.picture_metrics().total_bytes(), 0u);
312
313 cache.BeginFrame();
314 ASSERT_FALSE(
315 cache.Draw(display_list_item_1.GetId().value(), dummy_canvas, &paint));
316 ASSERT_FALSE(display_list_item_1.Draw(paint_context, &dummy_canvas, &paint));
317 ASSERT_FALSE(
318 cache.Draw(display_list_item_2.GetId().value(), dummy_canvas, &paint));
319 ASSERT_FALSE(display_list_item_2.Draw(paint_context, &dummy_canvas, &paint));
320 cache.EndFrame();
321}
322
323TEST(RasterCache, ComputeDeviceRectBasedOnFractionalTranslation) {
324 SkRect logical_rect = SkRect::MakeLTRB(0, 0, 300.2, 300.3);
325 SkMatrix ctm = SkMatrix::MakeAll(2.0, 0, 0, 0, 2.0, 0, 0, 0, 1);
326 auto result = RasterCacheUtil::GetDeviceBounds(logical_rect, ctm);
327 ASSERT_EQ(result, SkRect::MakeLTRB(0.0, 0.0, 600.4, 600.6));
328}
329
330// Construct a cache result whose device target rectangle rounds out to be one
331// pixel wider than the cached image. Verify that it can be drawn without
332// triggering any assertions.
333TEST(RasterCache, DeviceRectRoundOutForDisplayList) {
334 size_t threshold = 1;
335 flutter::RasterCache cache(threshold);
336
337 SkRect logical_rect = SkRect::MakeLTRB(28, 0, 354.56731, 310.288);
338 DisplayListBuilder builder(logical_rect);
339 builder.DrawRect(logical_rect, DlPaint(DlColor::kRed()));
340 sk_sp<DisplayList> display_list = builder.Build();
341
342 SkMatrix ctm = SkMatrix::MakeAll(1.3312, 0, 233, 0, 1.3312, 206, 0, 0, 1);
344
345 MockCanvas canvas(1000, 1000);
346 canvas.SetTransform(ctm);
347
348 LayerStateStack preroll_state_stack;
349 preroll_state_stack.set_preroll_delegate(kGiantRect, ctm);
350 LayerStateStack paint_state_stack;
351 preroll_state_stack.set_delegate(&canvas);
352
353 FixedRefreshRateStopwatch raster_time;
356 preroll_state_stack, &cache, &raster_time, &ui_time);
357 PaintContextHolder paint_context_holder = GetSamplePaintContextHolder(
358 paint_state_stack, &cache, &raster_time, &ui_time);
359 auto& preroll_context = preroll_context_holder.preroll_context;
360 auto& paint_context = paint_context_holder.paint_context;
361
362 cache.BeginFrame();
363 DisplayListRasterCacheItem display_list_item(display_list, SkPoint(), true,
364 false);
365
367 display_list_item, preroll_context, paint_context, ctm));
368 ASSERT_FALSE(display_list_item.Draw(paint_context, &canvas, &paint));
369
370 cache.EndFrame();
371 cache.BeginFrame();
372
374 display_list_item, preroll_context, paint_context, ctm));
375 ASSERT_TRUE(display_list_item.Draw(paint_context, &canvas, &paint));
376
377 canvas.Translate(248, 0);
378 ASSERT_TRUE(cache.Draw(display_list_item.GetId().value(), canvas, &paint));
379 ASSERT_TRUE(display_list_item.Draw(paint_context, &canvas, &paint));
380}
381
382TEST(RasterCache, NestedOpCountMetricUsedForDisplayList) {
383 size_t threshold = 1;
384 flutter::RasterCache cache(threshold);
385
387
388 auto display_list = GetSampleNestedDisplayList();
389 ASSERT_EQ(display_list->op_count(), 1u);
390 ASSERT_EQ(display_list->op_count(true), 36u);
391
392 MockCanvas dummy_canvas(1000, 1000);
394
395 LayerStateStack preroll_state_stack;
396 preroll_state_stack.set_preroll_delegate(kGiantRect, matrix);
397 LayerStateStack paint_state_stack;
398 preroll_state_stack.set_delegate(&dummy_canvas);
399
400 FixedRefreshRateStopwatch raster_time;
403 preroll_state_stack, &cache, &raster_time, &ui_time);
404 PaintContextHolder paint_context_holder = GetSamplePaintContextHolder(
405 paint_state_stack, &cache, &raster_time, &ui_time);
406 auto& preroll_context = preroll_context_holder.preroll_context;
407 auto& paint_context = paint_context_holder.paint_context;
408
409 cache.BeginFrame();
410
411 DisplayListRasterCacheItem display_list_item(display_list, SkPoint(), false,
412 false);
413
415 display_list_item, preroll_context, paint_context, matrix));
416 ASSERT_FALSE(display_list_item.Draw(paint_context, &dummy_canvas, &paint));
417
418 cache.EndFrame();
419 cache.BeginFrame();
420
422 display_list_item, preroll_context, paint_context, matrix));
423 ASSERT_TRUE(display_list_item.Draw(paint_context, &dummy_canvas, &paint));
424}
425
426TEST(RasterCache, NaiveComplexityScoringDisplayList) {
429
430 size_t threshold = 1;
431 flutter::RasterCache cache(threshold);
432
434
435 // Five raster ops will not be cached
436 auto display_list = GetSampleDisplayList(5);
437 unsigned int complexity_score = calculator->Compute(display_list.get());
438
439 ASSERT_EQ(complexity_score, 5u);
440 ASSERT_EQ(display_list->op_count(), 5u);
441 ASSERT_FALSE(calculator->ShouldBeCached(complexity_score));
442
443 MockCanvas dummy_canvas(1000, 1000);
445
446 LayerStateStack preroll_state_stack;
447 preroll_state_stack.set_preroll_delegate(kGiantRect, matrix);
448 LayerStateStack paint_state_stack;
449 preroll_state_stack.set_delegate(&dummy_canvas);
450
451 FixedRefreshRateStopwatch raster_time;
454 preroll_state_stack, &cache, &raster_time, &ui_time);
455 PaintContextHolder paint_context_holder = GetSamplePaintContextHolder(
456 paint_state_stack, &cache, &raster_time, &ui_time);
457 auto& preroll_context = preroll_context_holder.preroll_context;
458 auto& paint_context = paint_context_holder.paint_context;
459
460 cache.BeginFrame();
461
462 DisplayListRasterCacheItem display_list_item(display_list, SkPoint(), false,
463 false);
464
466 display_list_item, preroll_context, paint_context, matrix));
467 ASSERT_FALSE(display_list_item.Draw(paint_context, &dummy_canvas, &paint));
468
469 cache.EndFrame();
470 cache.BeginFrame();
471
473 display_list_item, preroll_context, paint_context, matrix));
474 ASSERT_FALSE(display_list_item.Draw(paint_context, &dummy_canvas, &paint));
475
476 // Six raster ops should be cached
477 display_list = GetSampleDisplayList(6);
478 complexity_score = calculator->Compute(display_list.get());
479
480 ASSERT_EQ(complexity_score, 6u);
481 ASSERT_EQ(display_list->op_count(), 6u);
482 ASSERT_TRUE(calculator->ShouldBeCached(complexity_score));
483
484 DisplayListRasterCacheItem display_list_item_2 =
485 DisplayListRasterCacheItem(display_list, SkPoint(), false, false);
486 cache.BeginFrame();
487
489 display_list_item_2, preroll_context, paint_context, matrix));
490 ASSERT_FALSE(display_list_item_2.Draw(paint_context, &dummy_canvas, &paint));
491
492 cache.EndFrame();
493 cache.BeginFrame();
494
496 display_list_item_2, preroll_context, paint_context, matrix));
497 ASSERT_TRUE(display_list_item_2.Draw(paint_context, &dummy_canvas, &paint));
498}
499
500TEST(RasterCache, DisplayListWithSingularMatrixIsNotCached) {
501 size_t threshold = 2;
502 flutter::RasterCache cache(threshold);
503
504 SkMatrix matrices[] = {
505 SkMatrix::Scale(0, 1),
506 SkMatrix::Scale(1, 0),
507 SkMatrix::Skew(1, 1),
508 };
509 int matrix_count = sizeof(matrices) / sizeof(matrices[0]);
510
511 auto display_list = GetSampleDisplayList();
512
513 MockCanvas dummy_canvas(1000, 1000);
515
516 LayerStateStack preroll_state_stack;
517 preroll_state_stack.set_preroll_delegate(kGiantRect, SkMatrix::I());
518 LayerStateStack paint_state_stack;
519 preroll_state_stack.set_delegate(&dummy_canvas);
520
521 FixedRefreshRateStopwatch raster_time;
524 preroll_state_stack, &cache, &raster_time, &ui_time);
525 PaintContextHolder paint_context_holder = GetSamplePaintContextHolder(
526 paint_state_stack, &cache, &raster_time, &ui_time);
527 auto& preroll_context = preroll_context_holder.preroll_context;
528 auto& paint_context = paint_context_holder.paint_context;
529
530 DisplayListRasterCacheItem display_list_item(display_list, SkPoint(), true,
531 false);
532
533 for (int i = 0; i < 10; i++) {
534 cache.BeginFrame();
535
536 for (int j = 0; j < matrix_count; j++) {
537 display_list_item.set_matrix(matrices[j]);
539 display_list_item, preroll_context, paint_context, matrices[j]));
540 }
541
542 for (int j = 0; j < matrix_count; j++) {
543 dummy_canvas.SetTransform(matrices[j]);
544 ASSERT_FALSE(
545 display_list_item.Draw(paint_context, &dummy_canvas, &paint));
546 }
547
548 cache.EndFrame();
549 }
550}
551
552TEST(RasterCache, PrepareLayerTransform) {
553 SkRect child_bounds = SkRect::MakeLTRB(10, 10, 50, 50);
554 SkPath child_path = SkPath().addOval(child_bounds);
555 auto child_layer = MockLayer::Make(child_path);
556 auto blur_filter =
557 std::make_shared<DlBlurImageFilter>(5, 5, DlTileMode::kClamp);
558 auto blur_layer = std::make_shared<ImageFilterLayer>(blur_filter);
560 auto transform_layer = std::make_shared<TransformLayer>(matrix);
561 SkMatrix cache_matrix = SkMatrix::Translate(-20, -20);
562 cache_matrix.preConcat(matrix);
563 child_layer->set_expected_paint_matrix(cache_matrix);
564
565 blur_layer->Add(child_layer);
566 transform_layer->Add(blur_layer);
567
568 size_t threshold = 2;
569 MockRasterCache cache(threshold);
570 MockCanvas dummy_canvas(1000, 1000);
571
572 LayerStateStack preroll_state_stack;
573 preroll_state_stack.set_preroll_delegate(kGiantRect, matrix);
574 LayerStateStack paint_state_stack;
575 preroll_state_stack.set_delegate(&dummy_canvas);
576
577 FixedRefreshRateStopwatch raster_time;
579 std::vector<RasterCacheItem*> cache_items;
580
581 cache.BeginFrame();
582
583 auto preroll_holder = GetSamplePrerollContextHolder(
584 preroll_state_stack, &cache, &raster_time, &ui_time);
585 preroll_holder.preroll_context.raster_cached_entries = &cache_items;
586 transform_layer->Preroll(&preroll_holder.preroll_context);
587
588 auto paint_holder = GetSamplePaintContextHolder(paint_state_stack, &cache,
589 &raster_time, &ui_time);
590
591 cache.EvictUnusedCacheEntries();
593 *preroll_holder.preroll_context.raster_cached_entries,
594 &paint_holder.paint_context);
595
596 // Condition tested inside MockLayer::Paint against expected paint matrix.
597}
598
599TEST(RasterCache, RasterCacheKeyHashFunction) {
601 auto hash_function = map.hash_function();
603 uint64_t id = 5;
607 matrix);
608
609 auto layer_cache_key_id = RasterCacheKeyID(id, RasterCacheKeyType::kLayer);
610 auto layer_hash_code = hash_function(layer_key);
611 ASSERT_EQ(layer_hash_code, layer_cache_key_id.GetHash());
612
613 auto display_list_cache_key_id =
615 auto display_list_hash_code = hash_function(display_list_key);
616 ASSERT_EQ(display_list_hash_code, display_list_cache_key_id.GetHash());
617
618 auto layer_children_cache_key_id =
620 auto layer_children_hash_code = hash_function(layer_children_key);
621 ASSERT_EQ(layer_children_hash_code, layer_children_cache_key_id.GetHash());
622}
623
624TEST(RasterCache, RasterCacheKeySameID) {
627 uint64_t id = 5;
631 matrix);
632 map[layer_key] = 100;
633 map[display_list_key] = 300;
634 map[layer_children_key] = 400;
635
636 ASSERT_EQ(map[layer_key], 100);
637 ASSERT_EQ(map[display_list_key], 300);
638 ASSERT_EQ(map[layer_children_key], 400);
639}
640
641TEST(RasterCache, RasterCacheKeySameType) {
644
646 RasterCacheKey layer_first_key(5, type, matrix);
647 RasterCacheKey layer_second_key(10, type, matrix);
648 RasterCacheKey layer_third_key(15, type, matrix);
649 map[layer_first_key] = 50;
650 map[layer_second_key] = 100;
651 map[layer_third_key] = 150;
652 ASSERT_EQ(map[layer_first_key], 50);
653 ASSERT_EQ(map[layer_second_key], 100);
654 ASSERT_EQ(map[layer_third_key], 150);
655
657 RasterCacheKey picture_first_key(20, type, matrix);
658 RasterCacheKey picture_second_key(25, type, matrix);
659 RasterCacheKey picture_third_key(30, type, matrix);
660 map[picture_first_key] = 200;
661 map[picture_second_key] = 250;
662 map[picture_third_key] = 300;
663 ASSERT_EQ(map[picture_first_key], 200);
664 ASSERT_EQ(map[picture_second_key], 250);
665 ASSERT_EQ(map[picture_third_key], 300);
666
668 RasterCacheKey display_list_first_key(35, type, matrix);
669 RasterCacheKey display_list_second_key(40, type, matrix);
670 RasterCacheKey display_list_third_key(45, type, matrix);
671 map[display_list_first_key] = 350;
672 map[display_list_second_key] = 400;
673 map[display_list_third_key] = 450;
674 ASSERT_EQ(map[display_list_first_key], 350);
675 ASSERT_EQ(map[display_list_second_key], 400);
676 ASSERT_EQ(map[display_list_third_key], 450);
677
682 RasterCacheKey layer_children_first_key(
683 RasterCacheKeyID({foo, bar, baz}, type), matrix);
684 RasterCacheKey layer_children_second_key(
685 RasterCacheKeyID({foo, baz, bar}, type), matrix);
686 RasterCacheKey layer_children_third_key(
687 RasterCacheKeyID({baz, bar, foo}, type), matrix);
688 map[layer_children_first_key] = 100;
689 map[layer_children_second_key] = 200;
690 map[layer_children_third_key] = 300;
691 ASSERT_EQ(map[layer_children_first_key], 100);
692 ASSERT_EQ(map[layer_children_second_key], 200);
693 ASSERT_EQ(map[layer_children_third_key], 300);
694}
695
696TEST(RasterCache, RasterCacheKeyIDEqual) {
699 RasterCacheKeyID third =
701
702 ASSERT_NE(first, second);
703 ASSERT_NE(first, third);
704 ASSERT_NE(second, third);
705
706 RasterCacheKeyID fourth =
708 RasterCacheKeyID fifth =
710 RasterCacheKeyID sixth =
712 ASSERT_NE(fourth, fifth);
713 ASSERT_NE(fifth, sixth);
714}
715
716TEST(RasterCache, RasterCacheKeyIDHashCode) {
717 uint64_t foo = 1;
718 uint64_t bar = 2;
721 std::size_t first_hash = first.GetHash();
722 std::size_t second_hash = second.GetHash();
723
724 ASSERT_EQ(first_hash, fml::HashCombine(foo, RasterCacheKeyType::kLayer));
725 ASSERT_EQ(second_hash, fml::HashCombine(bar, RasterCacheKeyType::kLayer));
726
727 RasterCacheKeyID third =
729 RasterCacheKeyID fourth =
731 std::size_t third_hash = third.GetHash();
732 std::size_t fourth_hash = fourth.GetHash();
733
736 first.GetHash(), second.GetHash()));
739 second.GetHash(), first.GetHash()));
740
741 // Verify that the cached hash code is correct.
742 ASSERT_EQ(first_hash, first.GetHash());
743 ASSERT_EQ(second_hash, second.GetHash());
744 ASSERT_EQ(third_hash, third.GetHash());
745 ASSERT_EQ(fourth_hash, fourth.GetHash());
746}
747
749
750TEST_F(RasterCacheTest, RasterCacheKeyIDLayerChildrenIds) {
751 auto layer = std::make_shared<ContainerLayer>();
752
753 const SkPath child_path = SkPath().addRect(SkRect::MakeWH(5.0f, 5.0f));
754 auto mock_layer = std::make_shared<MockLayer>(child_path);
755 layer->Add(mock_layer);
756
757 auto display_list = GetSampleDisplayList();
758 auto display_list_layer = std::make_shared<DisplayListLayer>(
759 SkPoint::Make(0.0f, 0.0f), display_list, false, false);
760 layer->Add(display_list_layer);
761
762 auto ids = RasterCacheKeyID::LayerChildrenIds(layer.get()).value();
763 std::vector<RasterCacheKeyID> expected_ids;
764 expected_ids.emplace_back(
765 RasterCacheKeyID(mock_layer->unique_id(), RasterCacheKeyType::kLayer));
766 expected_ids.emplace_back(RasterCacheKeyID(display_list->unique_id(),
768 ASSERT_EQ(expected_ids[0], mock_layer->caching_key_id());
769 ASSERT_EQ(expected_ids[1], display_list_layer->caching_key_id());
770 ASSERT_EQ(ids, expected_ids);
771}
772
773TEST(RasterCacheUtilsTest, SkMatrixIntegralTransCTM) {
774#define EXPECT_EQ_WITH_TRANSLATE(test, expected, expected_tx, expected_ty) \
775 do { \
776 EXPECT_EQ(test[SkMatrix::kMScaleX], expected[SkMatrix::kMScaleX]); \
777 EXPECT_EQ(test[SkMatrix::kMSkewX], expected[SkMatrix::kMSkewX]); \
778 EXPECT_EQ(test[SkMatrix::kMScaleY], expected[SkMatrix::kMScaleY]); \
779 EXPECT_EQ(test[SkMatrix::kMSkewY], expected[SkMatrix::kMSkewY]); \
780 EXPECT_EQ(test[SkMatrix::kMSkewX], expected[SkMatrix::kMSkewX]); \
781 EXPECT_EQ(test[SkMatrix::kMPersp0], expected[SkMatrix::kMPersp0]); \
782 EXPECT_EQ(test[SkMatrix::kMPersp1], expected[SkMatrix::kMPersp1]); \
783 EXPECT_EQ(test[SkMatrix::kMPersp2], expected[SkMatrix::kMPersp2]); \
784 EXPECT_EQ(test[SkMatrix::kMTransX], expected_tx); \
785 EXPECT_EQ(test[SkMatrix::kMTransY], expected_ty); \
786 } while (0)
787
788#define EXPECT_NON_INTEGER_TRANSLATION(matrix) \
789 EXPECT_TRUE(SkScalarFraction(matrix[SkMatrix::kMTransX]) != 0.0f || \
790 SkScalarFraction(matrix[SkMatrix::kMTransY]) != 0.0f)
791
792 {
793 // Identity
796 SkMatrix compute;
797 EXPECT_FALSE(RasterCacheUtil::ComputeIntegralTransCTM(matrix, &compute));
798 EXPECT_EQ(get, matrix);
799 }
800 {
801 // Integer translate
802 SkMatrix matrix = SkMatrix::Translate(10.0f, 12.0f);
804 SkMatrix compute;
805 EXPECT_FALSE(RasterCacheUtil::ComputeIntegralTransCTM(matrix, &compute));
806 EXPECT_EQ(get, matrix);
807 }
808 {
809 // Fractional x translate
810 SkMatrix matrix = SkMatrix::Translate(10.2f, 12.0f);
813 SkMatrix compute;
815 EXPECT_EQ_WITH_TRANSLATE(get, matrix, 10.0f, 12.0f);
816 EXPECT_EQ(get, compute);
817 }
818 {
819 // Fractional y translate
820 SkMatrix matrix = SkMatrix::Translate(10.0f, 12.3f);
823 SkMatrix compute;
825 EXPECT_EQ_WITH_TRANSLATE(get, matrix, 10.0f, 12.0f);
826 EXPECT_EQ(get, compute);
827 }
828 {
829 // Fractional x & y translate
830 SkMatrix matrix = SkMatrix::Translate(10.7f, 12.3f);
833 SkMatrix compute;
835 EXPECT_EQ_WITH_TRANSLATE(get, matrix, 11.0f, 12.0f);
836 EXPECT_EQ(get, compute);
837 }
838 {
839 // Scale
840 SkMatrix matrix = SkMatrix::Scale(2.0f, 3.0f);
842 SkMatrix compute;
843 EXPECT_FALSE(RasterCacheUtil::ComputeIntegralTransCTM(matrix, &compute));
844 EXPECT_EQ(get, matrix);
845 }
846 {
847 // Scale, Integer translate
848 SkMatrix matrix = SkMatrix::Scale(2.0f, 3.0f);
849 matrix.preTranslate(10.0f, 12.0f);
851 SkMatrix compute;
852 EXPECT_FALSE(RasterCacheUtil::ComputeIntegralTransCTM(matrix, &compute));
853 EXPECT_EQ(get, matrix);
854 }
855 {
856 // Scale, Fractional translate
857 SkMatrix matrix = SkMatrix::Scale(2.0f, 3.0f);
858 matrix.preTranslate(10.7f, 12.1f);
861 SkMatrix compute;
863 EXPECT_EQ_WITH_TRANSLATE(get, matrix, 21.0f, 36.0f);
864 EXPECT_EQ(get, compute);
865 }
866 {
867 // Skew
868 SkMatrix matrix = SkMatrix::Skew(0.5f, 0.1f);
870 SkMatrix compute;
871 EXPECT_FALSE(RasterCacheUtil::ComputeIntegralTransCTM(matrix, &compute));
872 EXPECT_EQ(get, matrix);
873 }
874 {
875 // Skew, Fractional translate - should be NOP
876 SkMatrix matrix = SkMatrix::Skew(0.5f, 0.1f);
877 matrix.preTranslate(10.7f, 12.1f);
880 SkMatrix compute;
881 EXPECT_FALSE(RasterCacheUtil::ComputeIntegralTransCTM(matrix, &compute));
882 EXPECT_EQ(get, matrix);
883 }
884 {
885 // Rotate
888 SkMatrix compute;
889 EXPECT_FALSE(RasterCacheUtil::ComputeIntegralTransCTM(matrix, &compute));
890 EXPECT_EQ(get, matrix);
891 }
892 {
893 // Rotate, Fractional Translate - should be NOP
895 matrix.preTranslate(10.7f, 12.1f);
898 SkMatrix compute;
899 EXPECT_FALSE(RasterCacheUtil::ComputeIntegralTransCTM(matrix, &compute));
900 EXPECT_EQ(get, matrix);
901 }
902 {
903 // Perspective x
905 matrix.setPerspX(0.1);
907 SkMatrix compute;
908 EXPECT_FALSE(RasterCacheUtil::ComputeIntegralTransCTM(matrix, &compute));
909 EXPECT_EQ(get, matrix);
910 }
911 {
912 // Perspective x, Fractional Translate - should be NOP
914 matrix.setPerspX(0.1);
915 matrix.preTranslate(10.7f, 12.1f);
918 SkMatrix compute;
919 EXPECT_FALSE(RasterCacheUtil::ComputeIntegralTransCTM(matrix, &compute));
920 EXPECT_EQ(get, matrix);
921 }
922 {
923 // Perspective y
925 matrix.setPerspY(0.1);
927 SkMatrix compute;
928 EXPECT_FALSE(RasterCacheUtil::ComputeIntegralTransCTM(matrix, &compute));
929 EXPECT_EQ(get, matrix);
930 }
931 {
932 // Perspective y, Fractional Translate - should be NOP
934 matrix.setPerspY(0.1);
935 matrix.preTranslate(10.7f, 12.1f);
938 SkMatrix compute;
939 EXPECT_FALSE(RasterCacheUtil::ComputeIntegralTransCTM(matrix, &compute));
940 EXPECT_EQ(get, matrix);
941 }
942 {
943 // Perspective weight
944 // clang-format off
946 1.0f, 0.0f, 0.0f,
947 0.0f, 1.0f, 0.0f,
948 0.0f, 0.0f, 0.9f);
949 // clang-format on
951 SkMatrix compute;
952 EXPECT_FALSE(RasterCacheUtil::ComputeIntegralTransCTM(matrix, &compute));
953 EXPECT_EQ(get, matrix);
954 }
955 {
956 // Perspective weight, Fractional Translate - should be NOP
957 // clang-format off
959 1.0f, 0.0f, 0.0f,
960 0.0f, 1.0f, 0.0f,
961 0.0f, 0.0f, 0.9f);
962 // clang-format on
963 matrix.preTranslate(10.7f, 12.1f);
966 SkMatrix compute;
967 EXPECT_FALSE(RasterCacheUtil::ComputeIntegralTransCTM(matrix, &compute));
968 EXPECT_EQ(get, matrix);
969 }
970#undef EXPECT_NON_INTEGER_TRANSLATION
971#undef EXPECT_EQ_WITH_TRANSLATE
972}
973
974TEST(RasterCacheUtilsTest, SkM44IntegralTransCTM) {
975#define EXPECT_EQ_WITH_TRANSLATE(test, expected, tx, ty, label) \
976 do { \
977 EXPECT_EQ(test.rc(0, 0), expected.rc(0, 0)) << label; \
978 EXPECT_EQ(test.rc(0, 1), expected.rc(0, 1)) << label; \
979 EXPECT_EQ(test.rc(0, 2), expected.rc(0, 2)) << label; \
980 EXPECT_EQ(test.rc(0, 3), tx) << label; \
981 EXPECT_EQ(test.rc(1, 0), expected.rc(1, 0)) << label; \
982 EXPECT_EQ(test.rc(1, 1), expected.rc(1, 1)) << label; \
983 EXPECT_EQ(test.rc(1, 2), expected.rc(1, 2)) << label; \
984 EXPECT_EQ(test.rc(1, 3), ty) << label; \
985 EXPECT_EQ(test.rc(2, 0), expected.rc(2, 0)) << label; \
986 EXPECT_EQ(test.rc(2, 1), expected.rc(2, 1)) << label; \
987 EXPECT_EQ(test.rc(2, 2), expected.rc(2, 2)) << label; \
988 EXPECT_EQ(test.rc(2, 3), expected.rc(2, 3)) << label; \
989 EXPECT_EQ(test.rc(3, 0), expected.rc(3, 0)) << label; \
990 EXPECT_EQ(test.rc(3, 1), expected.rc(3, 1)) << label; \
991 EXPECT_EQ(test.rc(3, 2), expected.rc(3, 2)) << label; \
992 EXPECT_EQ(test.rc(3, 3), expected.rc(3, 3)) << label; \
993 } while (0)
994
995#define EXPECT_NON_INTEGER_TRANSLATION(matrix) \
996 EXPECT_TRUE(SkScalarFraction(matrix.rc(0, 3)) != 0.0f || \
997 SkScalarFraction(matrix.rc(1, 3)) != 0.0f)
998
999 for (int r = 0; r < 4; r++) {
1000 for (int c = 0; c < 4; c++) {
1001 bool snaps;
1002 switch (r) {
1003 case 0: // X equation
1004 if (c == 3) {
1005 continue; // TranslateX, the value we are testing, skip
1006 }
1007 snaps = (c == 0); // X Scale value yes, Skew by Y or Z no
1008 break;
1009 case 1: // Y equation
1010 if (c == 3) {
1011 continue; // TranslateY, the value we are testing, skip
1012 }
1013 snaps = (c == 1); // Y Scale value yes, Skew by X or Z no
1014 break;
1015 case 2: // Z equation, ignored, will snap
1016 snaps = true;
1017 break;
1018 case 3: // W equation, modifications prevent snapping
1019 snaps = false;
1020 break;
1021 default:
1023 }
1024 auto label = std::to_string(r) + ", " + std::to_string(c);
1025 SkM44 matrix = SkM44::Translate(10.7f, 12.1f);
1027 matrix.setRC(r, c, 0.5f);
1028 if (snaps) {
1029 SkM44 compute;
1032 << label;
1033 EXPECT_EQ_WITH_TRANSLATE(get, matrix, 11.0f, 12.0f, label);
1034 EXPECT_EQ(get, compute) << label;
1035 } else {
1036 SkM44 compute;
1038 EXPECT_FALSE(RasterCacheUtil::ComputeIntegralTransCTM(matrix, &compute))
1039 << label;
1040 EXPECT_EQ(get, matrix) << label;
1041 }
1042 }
1043 }
1044#undef EXPECT_NON_INTEGER_TRANSLATION
1045#undef EXPECT_EQ_WITH_TRANSLATE
1046}
1047
1048} // namespace testing
1049} // namespace flutter
1050
1051// NOLINTEND(bugprone-unchecked-optional-access)
GLenum type
Definition: SkM44.h:150
static SkM44 Translate(SkScalar x, SkScalar y, SkScalar z=0)
Definition: SkM44.h:225
static SkMatrix Scale(SkScalar sx, SkScalar sy)
Definition: SkMatrix.h:75
static SkMatrix RotateDeg(SkScalar deg)
Definition: SkMatrix.h:104
static SkMatrix Translate(SkScalar dx, SkScalar dy)
Definition: SkMatrix.h:91
static SkMatrix MakeAll(SkScalar scaleX, SkScalar skewX, SkScalar transX, SkScalar skewY, SkScalar scaleY, SkScalar transY, SkScalar pers0, SkScalar pers1, SkScalar pers2)
Definition: SkMatrix.h:179
static const SkMatrix & I()
Definition: SkMatrix.cpp:1544
SkMatrix & preConcat(const SkMatrix &other)
Definition: SkMatrix.cpp:674
static SkMatrix Skew(SkScalar kx, SkScalar ky)
Definition: SkMatrix.h:124
Definition: SkPath.h:59
SkPath & addOval(const SkRect &oval, SkPathDirection dir=SkPathDirection::kCW)
Definition: SkPath.cpp:1106
SkPath & addRect(const SkRect &rect, SkPathDirection dir, unsigned start)
Definition: SkPath.cpp:864
virtual bool ShouldBeCached(unsigned int complexity_score)=0
virtual unsigned int Compute(const DisplayList *display_list)=0
static DisplayListComplexityCalculator * GetInstance()
bool Draw(const PaintContext &context, const DlPaint *paint) const override
Used for fixed refresh rate cases.
Definition: stopwatch.h:77
void set_preroll_delegate(const SkRect &cull_rect, const SkMatrix &matrix)
void set_delegate(DlCanvas *canvas)
static void TryToRasterCache(const std::vector< RasterCacheItem * > &raster_cached_entries, const PaintContext *paint_context, bool ignore_raster_cache=false)
Definition: layer_tree.cc:68
void set_matrix(const SkMatrix &matrix)
virtual std::optional< RasterCacheKeyID > GetId() const
static constexpr uint64_t kDefaultUniqueID
std::size_t GetHash() const
static std::optional< std::vector< RasterCacheKeyID > > LayerChildrenIds(const Layer *layer)
std::unordered_map< RasterCacheKey, Value, Hash, Equal > Map
void Translate(SkScalar tx, SkScalar ty) override
Definition: mock_canvas.cc:118
void SetTransform(const SkMatrix *matrix) override
Definition: mock_canvas.cc:102
static std::shared_ptr< MockLayer > Make(const SkPath &path, DlPaint paint=DlPaint())
Definition: mock_layer.h:30
A RasterCache implementation that simulates the act of rendering a Layer or DisplayList without the o...
const Paint & paint
Definition: color_source.cc:38
GAsyncResult * result
#define FML_UNREACHABLE()
Definition: logging.h:109
unsigned useCenter Optional< SkMatrix > matrix
Definition: SkRecords.h:258
TEST_F(DisplayListTest, Defaults)
bool RasterCacheItemTryToRasterCache(DisplayListRasterCacheItem &display_list_item, PaintContext &paint_context)
LayerTestBase<::testing::Test > LayerTest
Definition: layer_test.h:210
PrerollContextHolder GetSamplePrerollContextHolder(LayerStateStack &state_stack, RasterCache *raster_cache, FixedRefreshRateStopwatch *raster_time, FixedRefreshRateStopwatch *ui_time)
void RasterCacheItemPreroll(DisplayListRasterCacheItem &display_list_item, PrerollContext &context, const SkMatrix &matrix)
sk_sp< DisplayList > GetSampleDisplayList()
bool RasterCacheItemPrerollAndTryToRasterCache(DisplayListRasterCacheItem &display_list_item, PrerollContext &context, PaintContext &paint_context, const SkMatrix &matrix)
sk_sp< DisplayList > GetSampleNestedDisplayList()
PaintContextHolder GetSamplePaintContextHolder(LayerStateStack &state_stack, RasterCache *raster_cache, FixedRefreshRateStopwatch *raster_time, FixedRefreshRateStopwatch *ui_time)
TEST(DisplayListComplexity, EmptyDisplayList)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace Enable an endless trace buffer The default is a ring buffer This is useful when very old events need to viewed For during application launch Memory usage will continue to grow indefinitely however Start app with an specific route defined on the framework flutter assets Path to the Flutter assets directory enable service port Allow the VM service to fallback to automatic port selection if binding to a specified port fails trace Trace early application lifecycle Automatically switches to an endless trace buffer trace skia Filters out all Skia trace event categories except those that are specified in this comma separated list dump skp on shader Automatically dump the skp that triggers new shader compilations This is useful for writing custom ShaderWarmUp to reduce jank By this is not enabled to reduce the overhead purge persistent cache
Definition: switches.h:191
static constexpr SkRect kGiantRect
Definition: layer.h:50
constexpr std::size_t HashCombine()
Definition: hash_combine.h:25
const myers::Point & get(const myers::Segment &)
SI auto map(std::index_sequence< I... >, Fn &&fn, const Args &... args) -> skvx::Vec< sizeof...(I), decltype(fn(args[0]...))>
Definition: SkVx.h:680
flutter::DlPaint DlPaint
static SkString to_string(int n)
Definition: nanobench.cpp:119
#define EXPECT_NON_INTEGER_TRANSLATION(matrix)
#define EXPECT_EQ_WITH_TRANSLATE(test, expected, expected_tx, expected_ty)
static constexpr SkPoint Make(float x, float y)
Definition: SkPoint_impl.h:173
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 bool ComputeIntegralTransCTM(const SkMatrix &in, SkMatrix *out)
Snap the translation components of the |in| matrix to integers and store the snapped matrix in |out|.
static SkMatrix GetIntegralTransCTM(const SkMatrix &ctm)
Snap the translation components of the matrix to integers.
static SkRect GetDeviceBounds(const SkRect &rect, const SkMatrix &ctm)
#define EXPECT_TRUE(handle)
Definition: unit_test.h:678