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"
20#include "third_party/skia/include/core/SkMatrix.h"
21#include "third_party/skia/include/core/SkPoint.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) {
30 flutter::RasterCache cache;
31 ASSERT_TRUE(true);
32}
33
34TEST(RasterCache, MetricsOmitUnpopulatedEntries) {
35 size_t threshold = 2;
36 flutter::RasterCache cache(threshold);
37
38 SkMatrix matrix = SkMatrix::I();
39
40 auto display_list = GetSampleDisplayList();
41
42 MockCanvas dummy_canvas(1000, 1000);
43 DlPaint paint;
44
45 LayerStateStack preroll_state_stack;
46 preroll_state_stack.set_preroll_delegate(cull_rect: kGiantRect, matrix);
47 LayerStateStack paint_state_stack;
48 preroll_state_stack.set_delegate(&dummy_canvas);
49
50 FixedRefreshRateStopwatch raster_time;
51 FixedRefreshRateStopwatch ui_time;
52 PrerollContextHolder preroll_context_holder = GetSamplePrerollContextHolder(
53 state_stack&: preroll_state_stack, raster_cache: &cache, raster_time: &raster_time, ui_time: &ui_time);
54 PaintContextHolder paint_context_holder = GetSamplePaintContextHolder(
55 state_stack&: paint_state_stack, raster_cache: &cache, raster_time: &raster_time, ui_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.
64 ASSERT_FALSE(RasterCacheItemPrerollAndTryToRasterCache(
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.
74 ASSERT_FALSE(RasterCacheItemPrerollAndTryToRasterCache(
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.
84 ASSERT_TRUE(RasterCacheItemPrerollAndTryToRasterCache(
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
98 SkMatrix matrix = SkMatrix::I();
99
100 auto display_list = GetSampleDisplayList();
101
102 MockCanvas dummy_canvas(1000, 1000);
103 DlPaint paint;
104
105 LayerStateStack preroll_state_stack;
106 preroll_state_stack.set_preroll_delegate(cull_rect: kGiantRect, matrix);
107 LayerStateStack paint_state_stack;
108 preroll_state_stack.set_delegate(&dummy_canvas);
109
110 FixedRefreshRateStopwatch raster_time;
111 FixedRefreshRateStopwatch ui_time;
112 PrerollContextHolder preroll_context_holder = GetSamplePrerollContextHolder(
113 state_stack&: preroll_state_stack, raster_cache: &cache, raster_time: &raster_time, ui_time: &ui_time);
114 PaintContextHolder paint_context_holder = GetSamplePaintContextHolder(
115 state_stack&: paint_state_stack, raster_cache: &cache, raster_time: &raster_time, ui_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.
125 ASSERT_FALSE(RasterCacheItemPrerollAndTryToRasterCache(
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.
133 ASSERT_FALSE(RasterCacheItemPrerollAndTryToRasterCache(
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.
141 ASSERT_TRUE(RasterCacheItemPrerollAndTryToRasterCache(
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, SetCheckboardCacheImages) {
147 size_t threshold = 1;
148 flutter::RasterCache cache(threshold);
149
150 SkMatrix matrix = SkMatrix::I();
151 auto display_list = GetSampleDisplayList();
152
153 LayerStateStack preroll_state_stack;
154 preroll_state_stack.set_preroll_delegate(cull_rect: kGiantRect, matrix);
155
156 FixedRefreshRateStopwatch raster_time;
157 FixedRefreshRateStopwatch ui_time;
158 PaintContextHolder paint_context_holder = GetSamplePaintContextHolder(
159 state_stack&: preroll_state_stack, raster_cache: &cache, raster_time: &raster_time, ui_time: &ui_time);
160 auto& paint_context = paint_context_holder.paint_context;
161 auto dummy_draw_function = [](DlCanvas* canvas) {};
162 bool did_draw_checkerboard = false;
163 auto draw_checkerboard = [&](DlCanvas* canvas, const SkRect&) {
164 did_draw_checkerboard = true;
165 };
166 RasterCache::Context r_context = {
167 // clang-format off
168 .gr_context = paint_context.gr_context,
169 .dst_color_space = paint_context.dst_color_space,
170 .matrix = matrix,
171 .logical_rect = display_list->bounds(),
172 .flow_type = "RasterCacheFlow::DisplayList",
173 // clang-format on
174 };
175
176 cache.SetCheckboardCacheImages(false);
177 cache.Rasterize(context: r_context, rtree: nullptr, draw_function: dummy_draw_function, draw_checkerboard);
178 ASSERT_FALSE(did_draw_checkerboard);
179
180 cache.SetCheckboardCacheImages(true);
181 cache.Rasterize(context: r_context, rtree: nullptr, draw_function: dummy_draw_function, draw_checkerboard);
182 ASSERT_TRUE(did_draw_checkerboard);
183}
184
185TEST(RasterCache, AccessThresholdOfZeroDisablesCachingForDisplayList) {
186 size_t threshold = 0;
187 flutter::RasterCache cache(threshold);
188
189 SkMatrix matrix = SkMatrix::I();
190
191 auto display_list = GetSampleDisplayList();
192
193 MockCanvas dummy_canvas(1000, 1000);
194 DlPaint paint;
195
196 LayerStateStack preroll_state_stack;
197 preroll_state_stack.set_preroll_delegate(cull_rect: kGiantRect, matrix);
198 LayerStateStack paint_state_stack;
199 preroll_state_stack.set_delegate(&dummy_canvas);
200
201 FixedRefreshRateStopwatch raster_time;
202 FixedRefreshRateStopwatch ui_time;
203 PrerollContextHolder preroll_context_holder = GetSamplePrerollContextHolder(
204 state_stack&: preroll_state_stack, raster_cache: &cache, raster_time: &raster_time, ui_time: &ui_time);
205 PaintContextHolder paint_context_holder = GetSamplePaintContextHolder(
206 state_stack&: paint_state_stack, raster_cache: &cache, raster_time: &raster_time, ui_time: &ui_time);
207 auto& preroll_context = preroll_context_holder.preroll_context;
208 auto& paint_context = paint_context_holder.paint_context;
209
210 cache.BeginFrame();
211
212 DisplayListRasterCacheItem display_list_item(display_list, SkPoint(), true,
213 false);
214 ASSERT_FALSE(RasterCacheItemPrerollAndTryToRasterCache(
215 display_list_item, preroll_context, paint_context, matrix));
216 ASSERT_FALSE(display_list_item.Draw(paint_context, &dummy_canvas, &paint));
217}
218
219TEST(RasterCache, PictureCacheLimitPerFrameIsRespectedWhenZeroForDisplayList) {
220 size_t picture_cache_limit_per_frame = 0;
221 flutter::RasterCache cache(3, picture_cache_limit_per_frame);
222
223 SkMatrix matrix = SkMatrix::I();
224
225 auto display_list = GetSampleDisplayList();
226
227 MockCanvas dummy_canvas(1000, 1000);
228 DlPaint paint;
229
230 LayerStateStack preroll_state_stack;
231 preroll_state_stack.set_preroll_delegate(cull_rect: kGiantRect, matrix);
232 LayerStateStack paint_state_stack;
233 preroll_state_stack.set_delegate(&dummy_canvas);
234
235 FixedRefreshRateStopwatch raster_time;
236 FixedRefreshRateStopwatch ui_time;
237 PrerollContextHolder preroll_context_holder = GetSamplePrerollContextHolder(
238 state_stack&: preroll_state_stack, raster_cache: &cache, raster_time: &raster_time, ui_time: &ui_time);
239 PaintContextHolder paint_context_holder = GetSamplePaintContextHolder(
240 state_stack&: paint_state_stack, raster_cache: &cache, raster_time: &raster_time, ui_time: &ui_time);
241 auto& preroll_context = preroll_context_holder.preroll_context;
242 auto& paint_context = paint_context_holder.paint_context;
243
244 cache.BeginFrame();
245
246 DisplayListRasterCacheItem display_list_item(display_list, SkPoint(), true,
247 false);
248 // 1st access.
249 ASSERT_FALSE(RasterCacheItemPrerollAndTryToRasterCache(
250 display_list_item, preroll_context, paint_context, matrix));
251 ASSERT_FALSE(display_list_item.Draw(paint_context, &dummy_canvas, &paint));
252 // 2nd access.
253 ASSERT_FALSE(RasterCacheItemPrerollAndTryToRasterCache(
254 display_list_item, preroll_context, paint_context, matrix));
255 ASSERT_FALSE(display_list_item.Draw(paint_context, &dummy_canvas, &paint));
256 // the picture_cache_limit_per_frame = 0, so don't cache it
257 ASSERT_FALSE(RasterCacheItemPrerollAndTryToRasterCache(
258 display_list_item, preroll_context, paint_context, matrix));
259 ASSERT_FALSE(display_list_item.Draw(paint_context, &dummy_canvas, &paint));
260}
261
262TEST(RasterCache, EvictUnusedCacheEntries) {
263 size_t threshold = 1;
264 flutter::RasterCache cache(threshold);
265
266 SkMatrix matrix = SkMatrix::I();
267
268 auto display_list_1 = GetSampleDisplayList();
269 auto display_list_2 = GetSampleDisplayList();
270
271 MockCanvas dummy_canvas(1000, 1000);
272 DlPaint paint;
273
274 LayerStateStack preroll_state_stack;
275 preroll_state_stack.set_preroll_delegate(cull_rect: kGiantRect, matrix);
276 LayerStateStack paint_state_stack;
277 preroll_state_stack.set_delegate(&dummy_canvas);
278
279 FixedRefreshRateStopwatch raster_time;
280 FixedRefreshRateStopwatch ui_time;
281 PrerollContextHolder preroll_context_holder = GetSamplePrerollContextHolder(
282 state_stack&: preroll_state_stack, raster_cache: &cache, raster_time: &raster_time, ui_time: &ui_time);
283 PaintContextHolder paint_context_holder = GetSamplePaintContextHolder(
284 state_stack&: paint_state_stack, raster_cache: &cache, raster_time: &raster_time, ui_time: &ui_time);
285 auto& preroll_context = preroll_context_holder.preroll_context;
286 auto& paint_context = paint_context_holder.paint_context;
287
288 DisplayListRasterCacheItem display_list_item_1(display_list_1, SkPoint(),
289 true, false);
290 DisplayListRasterCacheItem display_list_item_2(display_list_2, SkPoint(),
291 true, false);
292
293 cache.BeginFrame();
294 RasterCacheItemPreroll(display_list_item&: display_list_item_1, context&: preroll_context, matrix);
295 RasterCacheItemPreroll(display_list_item&: display_list_item_2, context&: preroll_context, matrix);
296 cache.EvictUnusedCacheEntries();
297 ASSERT_EQ(cache.EstimatePictureCacheByteSize(), 0u);
298 ASSERT_FALSE(
299 RasterCacheItemTryToRasterCache(display_list_item_1, paint_context));
300 ASSERT_FALSE(
301 RasterCacheItemTryToRasterCache(display_list_item_2, paint_context));
302 ASSERT_EQ(cache.EstimatePictureCacheByteSize(), 0u);
303 ASSERT_FALSE(display_list_item_1.Draw(paint_context, &dummy_canvas, &paint));
304 ASSERT_FALSE(display_list_item_2.Draw(paint_context, &dummy_canvas, &paint));
305 cache.EndFrame();
306
307 ASSERT_EQ(cache.EstimatePictureCacheByteSize(), 0u);
308 ASSERT_EQ(cache.picture_metrics().total_count(), 0u);
309 ASSERT_EQ(cache.picture_metrics().total_bytes(), 0u);
310
311 cache.BeginFrame();
312 RasterCacheItemPreroll(display_list_item&: display_list_item_1, context&: preroll_context, matrix);
313 RasterCacheItemPreroll(display_list_item&: display_list_item_2, context&: preroll_context, matrix);
314 cache.EvictUnusedCacheEntries();
315 ASSERT_EQ(cache.EstimatePictureCacheByteSize(), 0u);
316 ASSERT_TRUE(
317 RasterCacheItemTryToRasterCache(display_list_item_1, paint_context));
318 ASSERT_TRUE(
319 RasterCacheItemTryToRasterCache(display_list_item_2, paint_context));
320 ASSERT_EQ(cache.EstimatePictureCacheByteSize(), 51248u);
321 ASSERT_TRUE(display_list_item_1.Draw(paint_context, &dummy_canvas, &paint));
322 ASSERT_TRUE(display_list_item_2.Draw(paint_context, &dummy_canvas, &paint));
323 cache.EndFrame();
324
325 ASSERT_EQ(cache.EstimatePictureCacheByteSize(), 51248u);
326 ASSERT_EQ(cache.picture_metrics().total_count(), 2u);
327 ASSERT_EQ(cache.picture_metrics().total_bytes(), 51248u);
328
329 cache.BeginFrame();
330 RasterCacheItemPreroll(display_list_item&: display_list_item_1, context&: preroll_context, matrix);
331 cache.EvictUnusedCacheEntries();
332 ASSERT_EQ(cache.EstimatePictureCacheByteSize(), 25624u);
333 ASSERT_TRUE(
334 RasterCacheItemTryToRasterCache(display_list_item_1, paint_context));
335 ASSERT_EQ(cache.EstimatePictureCacheByteSize(), 25624u);
336 ASSERT_TRUE(display_list_item_1.Draw(paint_context, &dummy_canvas, &paint));
337 cache.EndFrame();
338
339 ASSERT_EQ(cache.EstimatePictureCacheByteSize(), 25624u);
340 ASSERT_EQ(cache.picture_metrics().total_count(), 1u);
341 ASSERT_EQ(cache.picture_metrics().total_bytes(), 25624u);
342
343 cache.BeginFrame();
344 cache.EvictUnusedCacheEntries();
345 ASSERT_EQ(cache.EstimatePictureCacheByteSize(), 0u);
346 cache.EndFrame();
347
348 ASSERT_EQ(cache.EstimatePictureCacheByteSize(), 0u);
349 ASSERT_EQ(cache.picture_metrics().total_count(), 0u);
350 ASSERT_EQ(cache.picture_metrics().total_bytes(), 0u);
351
352 cache.BeginFrame();
353 ASSERT_FALSE(
354 cache.Draw(display_list_item_1.GetId().value(), dummy_canvas, &paint));
355 ASSERT_FALSE(display_list_item_1.Draw(paint_context, &dummy_canvas, &paint));
356 ASSERT_FALSE(
357 cache.Draw(display_list_item_2.GetId().value(), dummy_canvas, &paint));
358 ASSERT_FALSE(display_list_item_2.Draw(paint_context, &dummy_canvas, &paint));
359 cache.EndFrame();
360}
361
362TEST(RasterCache, ComputeDeviceRectBasedOnFractionalTranslation) {
363 SkRect logical_rect = SkRect::MakeLTRB(l: 0, t: 0, r: 300.2, b: 300.3);
364 SkMatrix ctm = SkMatrix::MakeAll(scaleX: 2.0, skewX: 0, transX: 0, skewY: 0, scaleY: 2.0, transY: 0, pers0: 0, pers1: 0, pers2: 1);
365 auto result = RasterCacheUtil::GetDeviceBounds(rect: logical_rect, ctm);
366 ASSERT_EQ(result, SkRect::MakeLTRB(0.0, 0.0, 600.4, 600.6));
367}
368
369// Construct a cache result whose device target rectangle rounds out to be one
370// pixel wider than the cached image. Verify that it can be drawn without
371// triggering any assertions.
372TEST(RasterCache, DeviceRectRoundOutForDisplayList) {
373 size_t threshold = 1;
374 flutter::RasterCache cache(threshold);
375
376 SkRect logical_rect = SkRect::MakeLTRB(l: 28, t: 0, r: 354.56731, b: 310.288);
377 DisplayListBuilder builder(logical_rect);
378 builder.DrawRect(rect: logical_rect, paint: DlPaint(DlColor::kRed()));
379 sk_sp<DisplayList> display_list = builder.Build();
380
381 SkMatrix ctm = SkMatrix::MakeAll(scaleX: 1.3312, skewX: 0, transX: 233, skewY: 0, scaleY: 1.3312, transY: 206, pers0: 0, pers1: 0, pers2: 1);
382 DlPaint paint;
383
384 MockCanvas canvas(1000, 1000);
385 canvas.SetTransform(ctm);
386
387 LayerStateStack preroll_state_stack;
388 preroll_state_stack.set_preroll_delegate(cull_rect: kGiantRect, matrix: ctm);
389 LayerStateStack paint_state_stack;
390 preroll_state_stack.set_delegate(&canvas);
391
392 FixedRefreshRateStopwatch raster_time;
393 FixedRefreshRateStopwatch ui_time;
394 PrerollContextHolder preroll_context_holder = GetSamplePrerollContextHolder(
395 state_stack&: preroll_state_stack, raster_cache: &cache, raster_time: &raster_time, ui_time: &ui_time);
396 PaintContextHolder paint_context_holder = GetSamplePaintContextHolder(
397 state_stack&: paint_state_stack, raster_cache: &cache, raster_time: &raster_time, ui_time: &ui_time);
398 auto& preroll_context = preroll_context_holder.preroll_context;
399 auto& paint_context = paint_context_holder.paint_context;
400
401 cache.BeginFrame();
402 DisplayListRasterCacheItem display_list_item(display_list, SkPoint(), true,
403 false);
404
405 ASSERT_FALSE(RasterCacheItemPrerollAndTryToRasterCache(
406 display_list_item, preroll_context, paint_context, ctm));
407 ASSERT_FALSE(display_list_item.Draw(paint_context, &canvas, &paint));
408
409 cache.EndFrame();
410 cache.BeginFrame();
411
412 ASSERT_TRUE(RasterCacheItemPrerollAndTryToRasterCache(
413 display_list_item, preroll_context, paint_context, ctm));
414 ASSERT_TRUE(display_list_item.Draw(paint_context, &canvas, &paint));
415
416 canvas.Translate(tx: 248, ty: 0);
417 ASSERT_TRUE(cache.Draw(display_list_item.GetId().value(), canvas, &paint));
418 ASSERT_TRUE(display_list_item.Draw(paint_context, &canvas, &paint));
419}
420
421TEST(RasterCache, NestedOpCountMetricUsedForDisplayList) {
422 size_t threshold = 1;
423 flutter::RasterCache cache(threshold);
424
425 SkMatrix matrix = SkMatrix::I();
426
427 auto display_list = GetSampleNestedDisplayList();
428 ASSERT_EQ(display_list->op_count(), 1u);
429 ASSERT_EQ(display_list->op_count(true), 36u);
430
431 MockCanvas dummy_canvas(1000, 1000);
432 DlPaint paint;
433
434 LayerStateStack preroll_state_stack;
435 preroll_state_stack.set_preroll_delegate(cull_rect: kGiantRect, matrix);
436 LayerStateStack paint_state_stack;
437 preroll_state_stack.set_delegate(&dummy_canvas);
438
439 FixedRefreshRateStopwatch raster_time;
440 FixedRefreshRateStopwatch ui_time;
441 PrerollContextHolder preroll_context_holder = GetSamplePrerollContextHolder(
442 state_stack&: preroll_state_stack, raster_cache: &cache, raster_time: &raster_time, ui_time: &ui_time);
443 PaintContextHolder paint_context_holder = GetSamplePaintContextHolder(
444 state_stack&: paint_state_stack, raster_cache: &cache, raster_time: &raster_time, ui_time: &ui_time);
445 auto& preroll_context = preroll_context_holder.preroll_context;
446 auto& paint_context = paint_context_holder.paint_context;
447
448 cache.BeginFrame();
449
450 DisplayListRasterCacheItem display_list_item(display_list, SkPoint(), false,
451 false);
452
453 ASSERT_FALSE(RasterCacheItemPrerollAndTryToRasterCache(
454 display_list_item, preroll_context, paint_context, matrix));
455 ASSERT_FALSE(display_list_item.Draw(paint_context, &dummy_canvas, &paint));
456
457 cache.EndFrame();
458 cache.BeginFrame();
459
460 ASSERT_TRUE(RasterCacheItemPrerollAndTryToRasterCache(
461 display_list_item, preroll_context, paint_context, matrix));
462 ASSERT_TRUE(display_list_item.Draw(paint_context, &dummy_canvas, &paint));
463}
464
465TEST(RasterCache, NaiveComplexityScoringDisplayList) {
466 DisplayListComplexityCalculator* calculator =
467 DisplayListNaiveComplexityCalculator::GetInstance();
468
469 size_t threshold = 1;
470 flutter::RasterCache cache(threshold);
471
472 SkMatrix matrix = SkMatrix::I();
473
474 // Five raster ops will not be cached
475 auto display_list = GetSampleDisplayList(ops: 5);
476 unsigned int complexity_score = calculator->Compute(display_list: display_list.get());
477
478 ASSERT_EQ(complexity_score, 5u);
479 ASSERT_EQ(display_list->op_count(), 5u);
480 ASSERT_FALSE(calculator->ShouldBeCached(complexity_score));
481
482 MockCanvas dummy_canvas(1000, 1000);
483 DlPaint paint;
484
485 LayerStateStack preroll_state_stack;
486 preroll_state_stack.set_preroll_delegate(cull_rect: kGiantRect, matrix);
487 LayerStateStack paint_state_stack;
488 preroll_state_stack.set_delegate(&dummy_canvas);
489
490 FixedRefreshRateStopwatch raster_time;
491 FixedRefreshRateStopwatch ui_time;
492 PrerollContextHolder preroll_context_holder = GetSamplePrerollContextHolder(
493 state_stack&: preroll_state_stack, raster_cache: &cache, raster_time: &raster_time, ui_time: &ui_time);
494 PaintContextHolder paint_context_holder = GetSamplePaintContextHolder(
495 state_stack&: paint_state_stack, raster_cache: &cache, raster_time: &raster_time, ui_time: &ui_time);
496 auto& preroll_context = preroll_context_holder.preroll_context;
497 auto& paint_context = paint_context_holder.paint_context;
498
499 cache.BeginFrame();
500
501 DisplayListRasterCacheItem display_list_item(display_list, SkPoint(), false,
502 false);
503
504 ASSERT_FALSE(RasterCacheItemPrerollAndTryToRasterCache(
505 display_list_item, preroll_context, paint_context, matrix));
506 ASSERT_FALSE(display_list_item.Draw(paint_context, &dummy_canvas, &paint));
507
508 cache.EndFrame();
509 cache.BeginFrame();
510
511 ASSERT_FALSE(RasterCacheItemPrerollAndTryToRasterCache(
512 display_list_item, preroll_context, paint_context, matrix));
513 ASSERT_FALSE(display_list_item.Draw(paint_context, &dummy_canvas, &paint));
514
515 // Six raster ops should be cached
516 display_list = GetSampleDisplayList(ops: 6);
517 complexity_score = calculator->Compute(display_list: display_list.get());
518
519 ASSERT_EQ(complexity_score, 6u);
520 ASSERT_EQ(display_list->op_count(), 6u);
521 ASSERT_TRUE(calculator->ShouldBeCached(complexity_score));
522
523 DisplayListRasterCacheItem display_list_item_2 =
524 DisplayListRasterCacheItem(display_list, SkPoint(), false, false);
525 cache.BeginFrame();
526
527 ASSERT_FALSE(RasterCacheItemPrerollAndTryToRasterCache(
528 display_list_item_2, preroll_context, paint_context, matrix));
529 ASSERT_FALSE(display_list_item_2.Draw(paint_context, &dummy_canvas, &paint));
530
531 cache.EndFrame();
532 cache.BeginFrame();
533
534 ASSERT_TRUE(RasterCacheItemPrerollAndTryToRasterCache(
535 display_list_item_2, preroll_context, paint_context, matrix));
536 ASSERT_TRUE(display_list_item_2.Draw(paint_context, &dummy_canvas, &paint));
537}
538
539TEST(RasterCache, DisplayListWithSingularMatrixIsNotCached) {
540 size_t threshold = 2;
541 flutter::RasterCache cache(threshold);
542
543 SkMatrix matrices[] = {
544 SkMatrix::Scale(sx: 0, sy: 1),
545 SkMatrix::Scale(sx: 1, sy: 0),
546 SkMatrix::Skew(kx: 1, ky: 1),
547 };
548 int matrix_count = sizeof(matrices) / sizeof(matrices[0]);
549
550 auto display_list = GetSampleDisplayList();
551
552 MockCanvas dummy_canvas(1000, 1000);
553 DlPaint paint;
554
555 LayerStateStack preroll_state_stack;
556 preroll_state_stack.set_preroll_delegate(cull_rect: kGiantRect, matrix: SkMatrix::I());
557 LayerStateStack paint_state_stack;
558 preroll_state_stack.set_delegate(&dummy_canvas);
559
560 FixedRefreshRateStopwatch raster_time;
561 FixedRefreshRateStopwatch ui_time;
562 PrerollContextHolder preroll_context_holder = GetSamplePrerollContextHolder(
563 state_stack&: preroll_state_stack, raster_cache: &cache, raster_time: &raster_time, ui_time: &ui_time);
564 PaintContextHolder paint_context_holder = GetSamplePaintContextHolder(
565 state_stack&: paint_state_stack, raster_cache: &cache, raster_time: &raster_time, ui_time: &ui_time);
566 auto& preroll_context = preroll_context_holder.preroll_context;
567 auto& paint_context = paint_context_holder.paint_context;
568
569 DisplayListRasterCacheItem display_list_item(display_list, SkPoint(), true,
570 false);
571
572 for (int i = 0; i < 10; i++) {
573 cache.BeginFrame();
574
575 for (int j = 0; j < matrix_count; j++) {
576 display_list_item.set_matrix(matrices[j]);
577 ASSERT_FALSE(RasterCacheItemPrerollAndTryToRasterCache(
578 display_list_item, preroll_context, paint_context, matrices[j]));
579 }
580
581 for (int j = 0; j < matrix_count; j++) {
582 dummy_canvas.SetTransform(matrices[j]);
583 ASSERT_FALSE(
584 display_list_item.Draw(paint_context, &dummy_canvas, &paint));
585 }
586
587 cache.EndFrame();
588 }
589}
590
591TEST(RasterCache, PrepareLayerTransform) {
592 SkRect child_bounds = SkRect::MakeLTRB(l: 10, t: 10, r: 50, b: 50);
593 SkPath child_path = SkPath().addOval(oval: child_bounds);
594 auto child_layer = MockLayer::Make(path: child_path);
595 auto blur_filter =
596 std::make_shared<DlBlurImageFilter>(args: 5, args: 5, args: DlTileMode::kClamp);
597 auto blur_layer = std::make_shared<ImageFilterLayer>(args&: blur_filter);
598 SkMatrix matrix = SkMatrix::Scale(sx: 2, sy: 2);
599 auto transform_layer = std::make_shared<TransformLayer>(args&: matrix);
600 SkMatrix cache_matrix = SkMatrix::Translate(dx: -20, dy: -20);
601 cache_matrix.preConcat(other: matrix);
602 child_layer->set_expected_paint_matrix(cache_matrix);
603
604 blur_layer->Add(layer: child_layer);
605 transform_layer->Add(layer: blur_layer);
606
607 size_t threshold = 2;
608 MockRasterCache cache(threshold);
609 MockCanvas dummy_canvas(1000, 1000);
610
611 LayerStateStack preroll_state_stack;
612 preroll_state_stack.set_preroll_delegate(cull_rect: kGiantRect, matrix);
613 LayerStateStack paint_state_stack;
614 preroll_state_stack.set_delegate(&dummy_canvas);
615
616 FixedRefreshRateStopwatch raster_time;
617 FixedRefreshRateStopwatch ui_time;
618 std::vector<RasterCacheItem*> cache_items;
619
620 cache.BeginFrame();
621
622 auto preroll_holder = GetSamplePrerollContextHolder(
623 state_stack&: preroll_state_stack, raster_cache: &cache, raster_time: &raster_time, ui_time: &ui_time);
624 preroll_holder.preroll_context.raster_cached_entries = &cache_items;
625 transform_layer->Preroll(context: &preroll_holder.preroll_context);
626
627 auto paint_holder = GetSamplePaintContextHolder(state_stack&: paint_state_stack, raster_cache: &cache,
628 raster_time: &raster_time, ui_time: &ui_time);
629
630 cache.EvictUnusedCacheEntries();
631 LayerTree::TryToRasterCache(
632 raster_cached_entries: *preroll_holder.preroll_context.raster_cached_entries,
633 paint_context: &paint_holder.paint_context);
634
635 // Condition tested inside MockLayer::Paint against expected paint matrix.
636}
637
638TEST(RasterCache, RasterCacheKeyHashFunction) {
639 RasterCacheKey::Map<int> map;
640 auto hash_function = map.hash_function();
641 SkMatrix matrix = SkMatrix::I();
642 uint64_t id = 5;
643 RasterCacheKey layer_key(id, RasterCacheKeyType::kLayer, matrix);
644 RasterCacheKey display_list_key(id, RasterCacheKeyType::kDisplayList, matrix);
645 RasterCacheKey layer_children_key(id, RasterCacheKeyType::kLayerChildren,
646 matrix);
647
648 auto layer_cache_key_id = RasterCacheKeyID(id, RasterCacheKeyType::kLayer);
649 auto layer_hash_code = hash_function(layer_key);
650 ASSERT_EQ(layer_hash_code, layer_cache_key_id.GetHash());
651
652 auto display_list_cache_key_id =
653 RasterCacheKeyID(id, RasterCacheKeyType::kDisplayList);
654 auto display_list_hash_code = hash_function(display_list_key);
655 ASSERT_EQ(display_list_hash_code, display_list_cache_key_id.GetHash());
656
657 auto layer_children_cache_key_id =
658 RasterCacheKeyID(id, RasterCacheKeyType::kLayerChildren);
659 auto layer_children_hash_code = hash_function(layer_children_key);
660 ASSERT_EQ(layer_children_hash_code, layer_children_cache_key_id.GetHash());
661}
662
663TEST(RasterCache, RasterCacheKeySameID) {
664 RasterCacheKey::Map<int> map;
665 SkMatrix matrix = SkMatrix::I();
666 uint64_t id = 5;
667 RasterCacheKey layer_key(id, RasterCacheKeyType::kLayer, matrix);
668 RasterCacheKey display_list_key(id, RasterCacheKeyType::kDisplayList, matrix);
669 RasterCacheKey layer_children_key(id, RasterCacheKeyType::kLayerChildren,
670 matrix);
671 map[layer_key] = 100;
672 map[display_list_key] = 300;
673 map[layer_children_key] = 400;
674
675 ASSERT_EQ(map[layer_key], 100);
676 ASSERT_EQ(map[display_list_key], 300);
677 ASSERT_EQ(map[layer_children_key], 400);
678}
679
680TEST(RasterCache, RasterCacheKeySameType) {
681 RasterCacheKey::Map<int> map;
682 SkMatrix matrix = SkMatrix::I();
683
684 RasterCacheKeyType type = RasterCacheKeyType::kLayer;
685 RasterCacheKey layer_first_key(5, type, matrix);
686 RasterCacheKey layer_second_key(10, type, matrix);
687 RasterCacheKey layer_third_key(15, type, matrix);
688 map[layer_first_key] = 50;
689 map[layer_second_key] = 100;
690 map[layer_third_key] = 150;
691 ASSERT_EQ(map[layer_first_key], 50);
692 ASSERT_EQ(map[layer_second_key], 100);
693 ASSERT_EQ(map[layer_third_key], 150);
694
695 type = RasterCacheKeyType::kDisplayList;
696 RasterCacheKey picture_first_key(20, type, matrix);
697 RasterCacheKey picture_second_key(25, type, matrix);
698 RasterCacheKey picture_third_key(30, type, matrix);
699 map[picture_first_key] = 200;
700 map[picture_second_key] = 250;
701 map[picture_third_key] = 300;
702 ASSERT_EQ(map[picture_first_key], 200);
703 ASSERT_EQ(map[picture_second_key], 250);
704 ASSERT_EQ(map[picture_third_key], 300);
705
706 type = RasterCacheKeyType::kDisplayList;
707 RasterCacheKey display_list_first_key(35, type, matrix);
708 RasterCacheKey display_list_second_key(40, type, matrix);
709 RasterCacheKey display_list_third_key(45, type, matrix);
710 map[display_list_first_key] = 350;
711 map[display_list_second_key] = 400;
712 map[display_list_third_key] = 450;
713 ASSERT_EQ(map[display_list_first_key], 350);
714 ASSERT_EQ(map[display_list_second_key], 400);
715 ASSERT_EQ(map[display_list_third_key], 450);
716
717 type = RasterCacheKeyType::kLayerChildren;
718 RasterCacheKeyID foo = RasterCacheKeyID(10, RasterCacheKeyType::kLayer);
719 RasterCacheKeyID bar = RasterCacheKeyID(20, RasterCacheKeyType::kLayer);
720 RasterCacheKeyID baz = RasterCacheKeyID(30, RasterCacheKeyType::kLayer);
721 RasterCacheKey layer_children_first_key(
722 RasterCacheKeyID({foo, bar, baz}, type), matrix);
723 RasterCacheKey layer_children_second_key(
724 RasterCacheKeyID({foo, baz, bar}, type), matrix);
725 RasterCacheKey layer_children_third_key(
726 RasterCacheKeyID({baz, bar, foo}, type), matrix);
727 map[layer_children_first_key] = 100;
728 map[layer_children_second_key] = 200;
729 map[layer_children_third_key] = 300;
730 ASSERT_EQ(map[layer_children_first_key], 100);
731 ASSERT_EQ(map[layer_children_second_key], 200);
732 ASSERT_EQ(map[layer_children_third_key], 300);
733}
734
735TEST(RasterCache, RasterCacheKeyIDEqual) {
736 RasterCacheKeyID first = RasterCacheKeyID(1, RasterCacheKeyType::kLayer);
737 RasterCacheKeyID second = RasterCacheKeyID(2, RasterCacheKeyType::kLayer);
738 RasterCacheKeyID third =
739 RasterCacheKeyID(1, RasterCacheKeyType::kLayerChildren);
740
741 ASSERT_NE(first, second);
742 ASSERT_NE(first, third);
743 ASSERT_NE(second, third);
744
745 RasterCacheKeyID fourth =
746 RasterCacheKeyID({first, second}, RasterCacheKeyType::kLayer);
747 RasterCacheKeyID fifth =
748 RasterCacheKeyID({first, second}, RasterCacheKeyType::kLayerChildren);
749 RasterCacheKeyID sixth =
750 RasterCacheKeyID({second, first}, RasterCacheKeyType::kLayerChildren);
751 ASSERT_NE(fourth, fifth);
752 ASSERT_NE(fifth, sixth);
753}
754
755TEST(RasterCache, RasterCacheKeyIDHashCode) {
756 uint64_t foo = 1;
757 uint64_t bar = 2;
758 RasterCacheKeyID first = RasterCacheKeyID(foo, RasterCacheKeyType::kLayer);
759 RasterCacheKeyID second = RasterCacheKeyID(bar, RasterCacheKeyType::kLayer);
760 std::size_t first_hash = first.GetHash();
761 std::size_t second_hash = second.GetHash();
762
763 ASSERT_EQ(first_hash, fml::HashCombine(foo, RasterCacheKeyType::kLayer));
764 ASSERT_EQ(second_hash, fml::HashCombine(bar, RasterCacheKeyType::kLayer));
765
766 RasterCacheKeyID third =
767 RasterCacheKeyID({first, second}, RasterCacheKeyType::kLayerChildren);
768 RasterCacheKeyID fourth =
769 RasterCacheKeyID({second, first}, RasterCacheKeyType::kLayerChildren);
770 std::size_t third_hash = third.GetHash();
771 std::size_t fourth_hash = fourth.GetHash();
772
773 ASSERT_EQ(third_hash, fml::HashCombine(RasterCacheKeyID::kDefaultUniqueID,
774 RasterCacheKeyType::kLayerChildren,
775 first.GetHash(), second.GetHash()));
776 ASSERT_EQ(fourth_hash, fml::HashCombine(RasterCacheKeyID::kDefaultUniqueID,
777 RasterCacheKeyType::kLayerChildren,
778 second.GetHash(), first.GetHash()));
779
780 // Verify that the cached hash code is correct.
781 ASSERT_EQ(first_hash, first.GetHash());
782 ASSERT_EQ(second_hash, second.GetHash());
783 ASSERT_EQ(third_hash, third.GetHash());
784 ASSERT_EQ(fourth_hash, fourth.GetHash());
785}
786
787using RasterCacheTest = LayerTest;
788
789TEST_F(RasterCacheTest, RasterCacheKeyIDLayerChildrenIds) {
790 auto layer = std::make_shared<ContainerLayer>();
791
792 const SkPath child_path = SkPath().addRect(rect: SkRect::MakeWH(w: 5.0f, h: 5.0f));
793 auto mock_layer = std::make_shared<MockLayer>(args: child_path);
794 layer->Add(layer: mock_layer);
795
796 auto display_list = GetSampleDisplayList();
797 auto display_list_layer = std::make_shared<DisplayListLayer>(
798 args: SkPoint::Make(x: 0.0f, y: 0.0f), args&: display_list, args: false, args: false);
799 layer->Add(layer: display_list_layer);
800
801 auto ids = RasterCacheKeyID::LayerChildrenIds(layer: layer.get()).value();
802 std::vector<RasterCacheKeyID> expected_ids;
803 expected_ids.emplace_back(
804 args: RasterCacheKeyID(mock_layer->unique_id(), RasterCacheKeyType::kLayer));
805 expected_ids.emplace_back(args: RasterCacheKeyID(display_list->unique_id(),
806 RasterCacheKeyType::kDisplayList));
807 ASSERT_EQ(expected_ids[0], mock_layer->caching_key_id());
808 ASSERT_EQ(expected_ids[1], display_list_layer->caching_key_id());
809 ASSERT_EQ(ids, expected_ids);
810}
811
812} // namespace testing
813} // namespace flutter
814
815// NOLINTEND(bugprone-unchecked-optional-access)
816

source code of flutter_engine/flutter/flow/raster_cache_unittests.cc