1 // Copyright 2014 The Chromium 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.
5 #include "cc/playback/display_item_list.h"
9 #include "cc/output/filter_operation.h"
10 #include "cc/output/filter_operations.h"
11 #include "cc/playback/clip_display_item.h"
12 #include "cc/playback/display_item_list_settings.h"
13 #include "cc/playback/drawing_display_item.h"
14 #include "cc/playback/filter_display_item.h"
15 #include "cc/playback/transform_display_item.h"
16 #include "cc/test/skia_common.h"
17 #include "skia/ext/refptr.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19 #include "third_party/skia/include/core/SkBitmap.h"
20 #include "third_party/skia/include/core/SkCanvas.h"
21 #include "third_party/skia/include/core/SkColor.h"
22 #include "third_party/skia/include/core/SkPictureRecorder.h"
23 #include "third_party/skia/include/core/SkSurface.h"
24 #include "third_party/skia/include/effects/SkImageSource.h"
25 #include "third_party/skia/include/utils/SkPictureUtils.h"
26 #include "ui/gfx/geometry/rect_conversions.h"
27 #include "ui/gfx/skia_util.h"
31 TEST(DisplayItemListTest
, SingleDrawingItem
) {
32 gfx::Rect
layer_rect(100, 100);
33 SkPictureRecorder recorder
;
34 skia::RefPtr
<SkCanvas
> canvas
;
35 skia::RefPtr
<SkPicture
> picture
;
37 blue_paint
.setColor(SK_ColorBLUE
);
39 red_paint
.setColor(SK_ColorRED
);
40 unsigned char pixels
[4 * 100 * 100] = {0};
41 DisplayItemListSettings settings
;
42 settings
.use_cached_picture
= true;
43 scoped_refptr
<DisplayItemList
> list
=
44 DisplayItemList::Create(layer_rect
, settings
);
46 gfx::PointF
offset(8.f
, 9.f
);
47 gfx::RectF
recording_rect(offset
, layer_rect
.size());
48 canvas
= skia::SharePtr(
49 recorder
.beginRecording(gfx::RectFToSkRect(recording_rect
)));
50 canvas
->translate(offset
.x(), offset
.y());
51 canvas
->drawRectCoords(0.f
, 0.f
, 60.f
, 60.f
, red_paint
);
52 canvas
->drawRectCoords(50.f
, 50.f
, 75.f
, 75.f
, blue_paint
);
53 picture
= skia::AdoptRef(recorder
.endRecordingAsPicture());
54 auto* item
= list
->CreateAndAppendItem
<DrawingDisplayItem
>();
55 item
->SetNew(picture
);
57 DrawDisplayList(pixels
, layer_rect
, list
);
59 SkBitmap expected_bitmap
;
60 unsigned char expected_pixels
[4 * 100 * 100] = {0};
62 SkImageInfo::MakeN32Premul(layer_rect
.width(), layer_rect
.height());
63 expected_bitmap
.installPixels(info
, expected_pixels
, info
.minRowBytes());
64 SkCanvas
expected_canvas(expected_bitmap
);
65 expected_canvas
.clipRect(gfx::RectToSkRect(layer_rect
));
66 expected_canvas
.drawRectCoords(0.f
+ offset
.x(), 0.f
+ offset
.y(),
67 60.f
+ offset
.x(), 60.f
+ offset
.y(),
69 expected_canvas
.drawRectCoords(50.f
+ offset
.x(), 50.f
+ offset
.y(),
70 75.f
+ offset
.x(), 75.f
+ offset
.y(),
73 EXPECT_EQ(0, memcmp(pixels
, expected_pixels
, 4 * 100 * 100));
76 TEST(DisplayItemListTest
, ClipItem
) {
77 gfx::Rect
layer_rect(100, 100);
78 SkPictureRecorder recorder
;
79 skia::RefPtr
<SkCanvas
> canvas
;
80 skia::RefPtr
<SkPicture
> picture
;
82 blue_paint
.setColor(SK_ColorBLUE
);
84 red_paint
.setColor(SK_ColorRED
);
85 unsigned char pixels
[4 * 100 * 100] = {0};
86 DisplayItemListSettings settings
;
87 settings
.use_cached_picture
= true;
88 scoped_refptr
<DisplayItemList
> list
=
89 DisplayItemList::Create(layer_rect
, settings
);
91 gfx::PointF
first_offset(8.f
, 9.f
);
92 gfx::RectF
first_recording_rect(first_offset
, layer_rect
.size());
93 canvas
= skia::SharePtr(
94 recorder
.beginRecording(gfx::RectFToSkRect(first_recording_rect
)));
95 canvas
->translate(first_offset
.x(), first_offset
.y());
96 canvas
->drawRectCoords(0.f
, 0.f
, 60.f
, 60.f
, red_paint
);
97 picture
= skia::AdoptRef(recorder
.endRecordingAsPicture());
98 auto* item1
= list
->CreateAndAppendItem
<DrawingDisplayItem
>();
99 item1
->SetNew(picture
.Pass());
101 gfx::Rect
clip_rect(60, 60, 10, 10);
102 auto* item2
= list
->CreateAndAppendItem
<ClipDisplayItem
>();
103 item2
->SetNew(clip_rect
, std::vector
<SkRRect
>());
105 gfx::PointF
second_offset(2.f
, 3.f
);
106 gfx::RectF
second_recording_rect(second_offset
, layer_rect
.size());
107 canvas
= skia::SharePtr(
108 recorder
.beginRecording(gfx::RectFToSkRect(second_recording_rect
)));
109 canvas
->translate(second_offset
.x(), second_offset
.y());
110 canvas
->drawRectCoords(50.f
, 50.f
, 75.f
, 75.f
, blue_paint
);
111 picture
= skia::AdoptRef(recorder
.endRecordingAsPicture());
112 auto* item3
= list
->CreateAndAppendItem
<DrawingDisplayItem
>();
113 item3
->SetNew(picture
.Pass());
115 list
->CreateAndAppendItem
<EndClipDisplayItem
>();
118 DrawDisplayList(pixels
, layer_rect
, list
);
120 SkBitmap expected_bitmap
;
121 unsigned char expected_pixels
[4 * 100 * 100] = {0};
123 SkImageInfo::MakeN32Premul(layer_rect
.width(), layer_rect
.height());
124 expected_bitmap
.installPixels(info
, expected_pixels
, info
.minRowBytes());
125 SkCanvas
expected_canvas(expected_bitmap
);
126 expected_canvas
.clipRect(gfx::RectToSkRect(layer_rect
));
127 expected_canvas
.drawRectCoords(0.f
+ first_offset
.x(), 0.f
+ first_offset
.y(),
128 60.f
+ first_offset
.x(),
129 60.f
+ first_offset
.y(), red_paint
);
130 expected_canvas
.clipRect(gfx::RectToSkRect(clip_rect
));
131 expected_canvas
.drawRectCoords(
132 50.f
+ second_offset
.x(), 50.f
+ second_offset
.y(),
133 75.f
+ second_offset
.x(), 75.f
+ second_offset
.y(), blue_paint
);
135 EXPECT_EQ(0, memcmp(pixels
, expected_pixels
, 4 * 100 * 100));
138 TEST(DisplayItemListTest
, TransformItem
) {
139 gfx::Rect
layer_rect(100, 100);
140 SkPictureRecorder recorder
;
141 skia::RefPtr
<SkCanvas
> canvas
;
142 skia::RefPtr
<SkPicture
> picture
;
144 blue_paint
.setColor(SK_ColorBLUE
);
146 red_paint
.setColor(SK_ColorRED
);
147 unsigned char pixels
[4 * 100 * 100] = {0};
148 DisplayItemListSettings settings
;
149 settings
.use_cached_picture
= true;
150 scoped_refptr
<DisplayItemList
> list
=
151 DisplayItemList::Create(layer_rect
, settings
);
153 gfx::PointF
first_offset(8.f
, 9.f
);
154 gfx::RectF
first_recording_rect(first_offset
, layer_rect
.size());
155 canvas
= skia::SharePtr(
156 recorder
.beginRecording(gfx::RectFToSkRect(first_recording_rect
)));
157 canvas
->translate(first_offset
.x(), first_offset
.y());
158 canvas
->drawRectCoords(0.f
, 0.f
, 60.f
, 60.f
, red_paint
);
159 picture
= skia::AdoptRef(recorder
.endRecordingAsPicture());
160 auto* item1
= list
->CreateAndAppendItem
<DrawingDisplayItem
>();
161 item1
->SetNew(picture
);
163 gfx::Transform transform
;
164 transform
.Rotate(45.0);
165 auto* item2
= list
->CreateAndAppendItem
<TransformDisplayItem
>();
166 item2
->SetNew(transform
);
168 gfx::PointF
second_offset(2.f
, 3.f
);
169 gfx::RectF
second_recording_rect(second_offset
, layer_rect
.size());
170 canvas
= skia::SharePtr(
171 recorder
.beginRecording(gfx::RectFToSkRect(second_recording_rect
)));
172 canvas
->translate(second_offset
.x(), second_offset
.y());
173 canvas
->drawRectCoords(50.f
, 50.f
, 75.f
, 75.f
, blue_paint
);
174 picture
= skia::AdoptRef(recorder
.endRecordingAsPicture());
175 auto* item3
= list
->CreateAndAppendItem
<DrawingDisplayItem
>();
176 item3
->SetNew(picture
);
178 list
->CreateAndAppendItem
<EndTransformDisplayItem
>();
181 DrawDisplayList(pixels
, layer_rect
, list
);
183 SkBitmap expected_bitmap
;
184 unsigned char expected_pixels
[4 * 100 * 100] = {0};
186 SkImageInfo::MakeN32Premul(layer_rect
.width(), layer_rect
.height());
187 expected_bitmap
.installPixels(info
, expected_pixels
, info
.minRowBytes());
188 SkCanvas
expected_canvas(expected_bitmap
);
189 expected_canvas
.clipRect(gfx::RectToSkRect(layer_rect
));
190 expected_canvas
.drawRectCoords(0.f
+ first_offset
.x(), 0.f
+ first_offset
.y(),
191 60.f
+ first_offset
.x(),
192 60.f
+ first_offset
.y(), red_paint
);
193 expected_canvas
.setMatrix(transform
.matrix());
194 expected_canvas
.drawRectCoords(
195 50.f
+ second_offset
.x(), 50.f
+ second_offset
.y(),
196 75.f
+ second_offset
.x(), 75.f
+ second_offset
.y(), blue_paint
);
198 EXPECT_EQ(0, memcmp(pixels
, expected_pixels
, 4 * 100 * 100));
201 TEST(DisplayItemListTest
, FilterItem
) {
202 gfx::Rect
layer_rect(100, 100);
203 FilterOperations filters
;
204 unsigned char pixels
[4 * 100 * 100] = {0};
205 DisplayItemListSettings settings
;
206 settings
.use_cached_picture
= true;
207 scoped_refptr
<DisplayItemList
> list
=
208 DisplayItemList::Create(layer_rect
, settings
);
210 skia::RefPtr
<SkSurface
> source_surface
=
211 skia::AdoptRef(SkSurface::NewRasterN32Premul(50, 50));
212 SkCanvas
* source_canvas
= source_surface
->getCanvas();
213 source_canvas
->clear(SkColorSetRGB(128, 128, 128));
214 skia::RefPtr
<SkImage
> source_image
=
215 skia::AdoptRef(source_surface
->newImageSnapshot());
217 // For most SkImageFilters, the |dst| bounds computed by computeFastBounds are
218 // dependent on the provided |src| bounds. This means, for example, that
219 // translating |src| results in a corresponding translation of |dst|. But this
220 // is not the case for all SkImageFilters; for some of them (e.g.
221 // SkImageSource), the computation of |dst| in computeFastBounds doesn't
222 // involve |src| at all. Incorrectly assuming such a relationship (e.g. by
223 // translating |dst| after it is computed by computeFastBounds, rather than
224 // translating |src| before it provided to computedFastBounds) can cause
225 // incorrect clipping of filter output. To test for this, we include an
226 // SkImageSource filter in |filters|. Here, |src| is |filter_bounds|, defined
228 skia::RefPtr
<SkImageFilter
> image_filter
=
229 skia::AdoptRef(SkImageSource::Create(source_image
.get()));
230 filters
.Append(FilterOperation::CreateReferenceFilter(image_filter
));
231 filters
.Append(FilterOperation::CreateBrightnessFilter(0.5f
));
232 gfx::RectF
filter_bounds(10.f
, 10.f
, 50.f
, 50.f
);
233 auto* item
= list
->CreateAndAppendItem
<FilterDisplayItem
>();
234 item
->SetNew(filters
, filter_bounds
);
235 list
->CreateAndAppendItem
<EndFilterDisplayItem
>();
238 DrawDisplayList(pixels
, layer_rect
, list
);
240 SkBitmap expected_bitmap
;
241 unsigned char expected_pixels
[4 * 100 * 100] = {0};
243 paint
.setColor(SkColorSetRGB(64, 64, 64));
245 SkImageInfo::MakeN32Premul(layer_rect
.width(), layer_rect
.height());
246 expected_bitmap
.installPixels(info
, expected_pixels
, info
.minRowBytes());
247 SkCanvas
expected_canvas(expected_bitmap
);
248 expected_canvas
.drawRect(RectFToSkRect(filter_bounds
), paint
);
250 EXPECT_EQ(0, memcmp(pixels
, expected_pixels
, 4 * 100 * 100));
253 TEST(DisplayItemListTest
, CompactingItems
) {
254 gfx::Rect
layer_rect(100, 100);
255 SkPictureRecorder recorder
;
256 skia::RefPtr
<SkCanvas
> canvas
;
257 skia::RefPtr
<SkPicture
> picture
;
259 blue_paint
.setColor(SK_ColorBLUE
);
261 red_paint
.setColor(SK_ColorRED
);
262 unsigned char pixels
[4 * 100 * 100] = {0};
264 gfx::PointF
offset(8.f
, 9.f
);
265 gfx::RectF
recording_rect(offset
, layer_rect
.size());
267 DisplayItemListSettings no_caching_settings
;
268 no_caching_settings
.use_cached_picture
= false;
269 scoped_refptr
<DisplayItemList
> list_without_caching
=
270 DisplayItemList::Create(layer_rect
, no_caching_settings
);
272 canvas
= skia::SharePtr(
273 recorder
.beginRecording(gfx::RectFToSkRect(recording_rect
)));
274 canvas
->translate(offset
.x(), offset
.y());
275 canvas
->drawRectCoords(0.f
, 0.f
, 60.f
, 60.f
, red_paint
);
276 canvas
->drawRectCoords(50.f
, 50.f
, 75.f
, 75.f
, blue_paint
);
277 picture
= skia::AdoptRef(recorder
.endRecordingAsPicture());
278 auto* item1
= list_without_caching
->CreateAndAppendItem
<DrawingDisplayItem
>();
279 item1
->SetNew(picture
);
280 list_without_caching
->Finalize();
281 DrawDisplayList(pixels
, layer_rect
, list_without_caching
);
283 unsigned char expected_pixels
[4 * 100 * 100] = {0};
284 DisplayItemListSettings caching_settings
;
285 caching_settings
.use_cached_picture
= true;
286 scoped_refptr
<DisplayItemList
> list_with_caching
=
287 DisplayItemList::Create(layer_rect
, caching_settings
);
288 auto* item2
= list_with_caching
->CreateAndAppendItem
<DrawingDisplayItem
>();
289 item2
->SetNew(picture
);
290 list_with_caching
->Finalize();
291 DrawDisplayList(expected_pixels
, layer_rect
, list_with_caching
);
293 EXPECT_EQ(0, memcmp(pixels
, expected_pixels
, 4 * 100 * 100));
296 TEST(DisplayItemListTest
, IsSuitableForGpuRasterizationWithCachedPicture
) {
297 gfx::Rect
layer_rect(1000, 1000);
298 SkPictureRecorder recorder
;
299 skia::RefPtr
<SkCanvas
> canvas
;
300 skia::RefPtr
<SkPicture
> picture
;
302 DisplayItemListSettings settings
;
303 settings
.use_cached_picture
= true;
304 scoped_refptr
<DisplayItemList
> list
=
305 DisplayItemList::Create(layer_rect
, settings
);
307 skia::SharePtr(recorder
.beginRecording(gfx::RectToSkRect(layer_rect
)));
313 path
.lineTo(100, 100);
318 paint
.setAntiAlias(true);
319 canvas
->drawPath(path
, paint
);
321 picture
= skia::AdoptRef(recorder
.endRecordingAsPicture());
322 DrawingDisplayItem
* item
= list
->CreateAndAppendItem
<DrawingDisplayItem
>();
323 item
->SetNew(picture
);
326 // A single DrawingDisplayItem with a large AA concave path shouldn't trigger
328 EXPECT_TRUE(list
->IsSuitableForGpuRasterization());
330 list
= DisplayItemList::Create(layer_rect
, settings
);
332 skia::SharePtr(recorder
.beginRecording(gfx::RectToSkRect(layer_rect
)));
333 for (int i
= 0; i
< 10; ++i
)
334 canvas
->drawPath(path
, paint
);
335 picture
= skia::AdoptRef(recorder
.endRecordingAsPicture());
336 item
= list
->CreateAndAppendItem
<DrawingDisplayItem
>();
337 item
->SetNew(picture
);
340 // A single DrawingDisplayItem with several large AA concave paths should
342 EXPECT_FALSE(list
->IsSuitableForGpuRasterization());
344 list
= DisplayItemList::Create(layer_rect
, settings
);
345 for (int i
= 0; i
< 10; ++i
) {
347 skia::SharePtr(recorder
.beginRecording(gfx::RectToSkRect(layer_rect
)));
348 canvas
->drawPath(path
, paint
);
349 picture
= skia::AdoptRef(recorder
.endRecordingAsPicture());
350 item
= list
->CreateAndAppendItem
<DrawingDisplayItem
>();
351 item
->SetNew(picture
);
355 // Having several DrawingDisplayItems that each contain a large AA concave
356 // path should trigger a veto.
357 EXPECT_FALSE(list
->IsSuitableForGpuRasterization());
360 TEST(DisplayItemListTest
, IsSuitableForGpuRasterizationWithoutCachedPicture
) {
361 gfx::Rect
layer_rect(1000, 1000);
362 SkPictureRecorder recorder
;
363 skia::RefPtr
<SkCanvas
> canvas
;
364 skia::RefPtr
<SkPicture
> picture
;
366 DisplayItemListSettings settings
;
367 settings
.use_cached_picture
= false;
368 scoped_refptr
<DisplayItemList
> list
=
369 DisplayItemList::Create(layer_rect
, settings
);
371 skia::SharePtr(recorder
.beginRecording(gfx::RectToSkRect(layer_rect
)));
377 path
.lineTo(100, 100);
382 paint
.setAntiAlias(true);
383 canvas
->drawPath(path
, paint
);
385 picture
= skia::AdoptRef(recorder
.endRecordingAsPicture());
386 DrawingDisplayItem
* item
= list
->CreateAndAppendItem
<DrawingDisplayItem
>();
387 item
->SetNew(picture
);
390 // A single DrawingDisplayItem with a large AA concave path shouldn't trigger
392 EXPECT_TRUE(list
->IsSuitableForGpuRasterization());
394 list
= DisplayItemList::Create(layer_rect
, settings
);
396 skia::SharePtr(recorder
.beginRecording(gfx::RectToSkRect(layer_rect
)));
397 for (int i
= 0; i
< 10; ++i
)
398 canvas
->drawPath(path
, paint
);
399 picture
= skia::AdoptRef(recorder
.endRecordingAsPicture());
400 item
= list
->CreateAndAppendItem
<DrawingDisplayItem
>();
401 item
->SetNew(picture
);
404 // A single DrawingDisplayItem with several large AA concave paths should
406 EXPECT_FALSE(list
->IsSuitableForGpuRasterization());
408 list
= DisplayItemList::Create(layer_rect
, settings
);
409 for (int i
= 0; i
< 10; ++i
) {
411 skia::SharePtr(recorder
.beginRecording(gfx::RectToSkRect(layer_rect
)));
412 canvas
->drawPath(path
, paint
);
413 picture
= skia::AdoptRef(recorder
.endRecordingAsPicture());
414 item
= list
->CreateAndAppendItem
<DrawingDisplayItem
>();
415 item
->SetNew(picture
);
419 // Without a cached picture, having several DrawingDisplayItems that each
420 // contain a single large AA concave will not trigger a veto, since each item
421 // is individually suitable for GPU rasterization.
422 EXPECT_TRUE(list
->IsSuitableForGpuRasterization());
425 TEST(DisplayItemListTest
, ApproximateMemoryUsage
) {
426 const int kNumCommandsInTestSkPicture
= 1000;
427 scoped_refptr
<DisplayItemList
> list
;
430 // Make an SkPicture whose size is known.
431 gfx::Rect
layer_rect(100, 100);
432 SkPictureRecorder recorder
;
434 blue_paint
.setColor(SK_ColorBLUE
);
435 SkCanvas
* canvas
= recorder
.beginRecording(gfx::RectToSkRect(layer_rect
));
436 for (int i
= 0; i
< kNumCommandsInTestSkPicture
; i
++)
437 canvas
->drawPaint(blue_paint
);
438 skia::RefPtr
<SkPicture
> picture
=
439 skia::AdoptRef(recorder
.endRecordingAsPicture());
440 size_t picture_size
= SkPictureUtils::ApproximateBytesUsed(picture
.get());
441 ASSERT_GE(picture_size
, kNumCommandsInTestSkPicture
* sizeof(blue_paint
));
443 // Using a cached picture, we should get about the right size.
444 DisplayItemListSettings caching_settings
;
445 caching_settings
.use_cached_picture
= true;
446 list
= DisplayItemList::Create(layer_rect
, caching_settings
);
447 auto* item
= list
->CreateAndAppendItem
<DrawingDisplayItem
>();
448 item
->SetNew(picture
);
450 memory_usage
= list
->ApproximateMemoryUsage();
451 EXPECT_GE(memory_usage
, picture_size
);
452 EXPECT_LE(memory_usage
, 2 * picture_size
);
454 // Using no cached picture, we should still get the right size.
455 DisplayItemListSettings no_caching_settings
;
456 no_caching_settings
.use_cached_picture
= false;
457 list
= DisplayItemList::Create(layer_rect
, no_caching_settings
);
458 item
= list
->CreateAndAppendItem
<DrawingDisplayItem
>();
459 item
->SetNew(picture
);
461 memory_usage
= list
->ApproximateMemoryUsage();
462 EXPECT_GE(memory_usage
, picture_size
);
463 EXPECT_LE(memory_usage
, 2 * picture_size
);
465 // To avoid double counting, we expect zero size to be computed if both the
466 // picture and items are retained (currently this only happens due to certain
467 // categories being traced).
468 list
= new DisplayItemList(layer_rect
, caching_settings
, true);
469 item
= list
->CreateAndAppendItem
<DrawingDisplayItem
>();
470 item
->SetNew(picture
);
472 memory_usage
= list
->ApproximateMemoryUsage();
473 EXPECT_EQ(static_cast<size_t>(0), memory_usage
);