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/effects/SkBitmapSource.h"
24 #include "third_party/skia/include/utils/SkPictureUtils.h"
25 #include "ui/gfx/geometry/rect_conversions.h"
26 #include "ui/gfx/skia_util.h"
30 TEST(DisplayItemListTest
, SingleDrawingItem
) {
31 gfx::Rect
layer_rect(100, 100);
32 SkPictureRecorder recorder
;
33 skia::RefPtr
<SkCanvas
> canvas
;
34 skia::RefPtr
<SkPicture
> picture
;
36 blue_paint
.setColor(SK_ColorBLUE
);
38 red_paint
.setColor(SK_ColorRED
);
39 unsigned char pixels
[4 * 100 * 100] = {0};
40 const bool use_cached_picture
= true;
41 scoped_refptr
<DisplayItemList
> list
=
42 DisplayItemList::Create(layer_rect
, use_cached_picture
);
44 gfx::PointF
offset(8.f
, 9.f
);
45 gfx::RectF
recording_rect(offset
, layer_rect
.size());
46 canvas
= skia::SharePtr(
47 recorder
.beginRecording(gfx::RectFToSkRect(recording_rect
)));
48 canvas
->translate(offset
.x(), offset
.y());
49 canvas
->drawRectCoords(0.f
, 0.f
, 60.f
, 60.f
, red_paint
);
50 canvas
->drawRectCoords(50.f
, 50.f
, 75.f
, 75.f
, blue_paint
);
51 picture
= skia::AdoptRef(recorder
.endRecordingAsPicture());
52 auto* item
= list
->CreateAndAppendItem
<DrawingDisplayItem
>();
53 item
->SetNew(picture
);
55 DrawDisplayList(pixels
, layer_rect
, list
);
57 SkBitmap expected_bitmap
;
58 unsigned char expected_pixels
[4 * 100 * 100] = {0};
60 SkImageInfo::MakeN32Premul(layer_rect
.width(), layer_rect
.height());
61 expected_bitmap
.installPixels(info
, expected_pixels
, info
.minRowBytes());
62 SkCanvas
expected_canvas(expected_bitmap
);
63 expected_canvas
.clipRect(gfx::RectToSkRect(layer_rect
));
64 expected_canvas
.drawRectCoords(0.f
+ offset
.x(), 0.f
+ offset
.y(),
65 60.f
+ offset
.x(), 60.f
+ offset
.y(),
67 expected_canvas
.drawRectCoords(50.f
+ offset
.x(), 50.f
+ offset
.y(),
68 75.f
+ offset
.x(), 75.f
+ offset
.y(),
71 EXPECT_EQ(0, memcmp(pixels
, expected_pixels
, 4 * 100 * 100));
74 TEST(DisplayItemListTest
, ClipItem
) {
75 gfx::Rect
layer_rect(100, 100);
76 SkPictureRecorder recorder
;
77 skia::RefPtr
<SkCanvas
> canvas
;
78 skia::RefPtr
<SkPicture
> picture
;
80 blue_paint
.setColor(SK_ColorBLUE
);
82 red_paint
.setColor(SK_ColorRED
);
83 unsigned char pixels
[4 * 100 * 100] = {0};
84 const bool use_cached_picture
= true;
85 scoped_refptr
<DisplayItemList
> list
=
86 DisplayItemList::Create(layer_rect
, use_cached_picture
);
88 gfx::PointF
first_offset(8.f
, 9.f
);
89 gfx::RectF
first_recording_rect(first_offset
, layer_rect
.size());
90 canvas
= skia::SharePtr(
91 recorder
.beginRecording(gfx::RectFToSkRect(first_recording_rect
)));
92 canvas
->translate(first_offset
.x(), first_offset
.y());
93 canvas
->drawRectCoords(0.f
, 0.f
, 60.f
, 60.f
, red_paint
);
94 picture
= skia::AdoptRef(recorder
.endRecordingAsPicture());
95 auto* item1
= list
->CreateAndAppendItem
<DrawingDisplayItem
>();
96 item1
->SetNew(picture
.Pass());
98 gfx::Rect
clip_rect(60, 60, 10, 10);
99 auto* item2
= list
->CreateAndAppendItem
<ClipDisplayItem
>();
100 item2
->SetNew(clip_rect
, std::vector
<SkRRect
>());
102 gfx::PointF
second_offset(2.f
, 3.f
);
103 gfx::RectF
second_recording_rect(second_offset
, layer_rect
.size());
104 canvas
= skia::SharePtr(
105 recorder
.beginRecording(gfx::RectFToSkRect(second_recording_rect
)));
106 canvas
->translate(second_offset
.x(), second_offset
.y());
107 canvas
->drawRectCoords(50.f
, 50.f
, 75.f
, 75.f
, blue_paint
);
108 picture
= skia::AdoptRef(recorder
.endRecordingAsPicture());
109 auto* item3
= list
->CreateAndAppendItem
<DrawingDisplayItem
>();
110 item3
->SetNew(picture
.Pass());
112 list
->CreateAndAppendItem
<EndClipDisplayItem
>();
115 DrawDisplayList(pixels
, layer_rect
, list
);
117 SkBitmap expected_bitmap
;
118 unsigned char expected_pixels
[4 * 100 * 100] = {0};
120 SkImageInfo::MakeN32Premul(layer_rect
.width(), layer_rect
.height());
121 expected_bitmap
.installPixels(info
, expected_pixels
, info
.minRowBytes());
122 SkCanvas
expected_canvas(expected_bitmap
);
123 expected_canvas
.clipRect(gfx::RectToSkRect(layer_rect
));
124 expected_canvas
.drawRectCoords(0.f
+ first_offset
.x(), 0.f
+ first_offset
.y(),
125 60.f
+ first_offset
.x(),
126 60.f
+ first_offset
.y(), red_paint
);
127 expected_canvas
.clipRect(gfx::RectToSkRect(clip_rect
));
128 expected_canvas
.drawRectCoords(
129 50.f
+ second_offset
.x(), 50.f
+ second_offset
.y(),
130 75.f
+ second_offset
.x(), 75.f
+ second_offset
.y(), blue_paint
);
132 EXPECT_EQ(0, memcmp(pixels
, expected_pixels
, 4 * 100 * 100));
135 TEST(DisplayItemListTest
, TransformItem
) {
136 gfx::Rect
layer_rect(100, 100);
137 SkPictureRecorder recorder
;
138 skia::RefPtr
<SkCanvas
> canvas
;
139 skia::RefPtr
<SkPicture
> picture
;
141 blue_paint
.setColor(SK_ColorBLUE
);
143 red_paint
.setColor(SK_ColorRED
);
144 unsigned char pixels
[4 * 100 * 100] = {0};
145 const bool use_cached_picture
= true;
146 scoped_refptr
<DisplayItemList
> list
=
147 DisplayItemList::Create(layer_rect
, use_cached_picture
);
149 gfx::PointF
first_offset(8.f
, 9.f
);
150 gfx::RectF
first_recording_rect(first_offset
, layer_rect
.size());
151 canvas
= skia::SharePtr(
152 recorder
.beginRecording(gfx::RectFToSkRect(first_recording_rect
)));
153 canvas
->translate(first_offset
.x(), first_offset
.y());
154 canvas
->drawRectCoords(0.f
, 0.f
, 60.f
, 60.f
, red_paint
);
155 picture
= skia::AdoptRef(recorder
.endRecordingAsPicture());
156 auto* item1
= list
->CreateAndAppendItem
<DrawingDisplayItem
>();
157 item1
->SetNew(picture
);
159 gfx::Transform transform
;
160 transform
.Rotate(45.0);
161 auto* item2
= list
->CreateAndAppendItem
<TransformDisplayItem
>();
162 item2
->SetNew(transform
);
164 gfx::PointF
second_offset(2.f
, 3.f
);
165 gfx::RectF
second_recording_rect(second_offset
, layer_rect
.size());
166 canvas
= skia::SharePtr(
167 recorder
.beginRecording(gfx::RectFToSkRect(second_recording_rect
)));
168 canvas
->translate(second_offset
.x(), second_offset
.y());
169 canvas
->drawRectCoords(50.f
, 50.f
, 75.f
, 75.f
, blue_paint
);
170 picture
= skia::AdoptRef(recorder
.endRecordingAsPicture());
171 auto* item3
= list
->CreateAndAppendItem
<DrawingDisplayItem
>();
172 item3
->SetNew(picture
);
174 list
->CreateAndAppendItem
<EndTransformDisplayItem
>();
177 DrawDisplayList(pixels
, layer_rect
, list
);
179 SkBitmap expected_bitmap
;
180 unsigned char expected_pixels
[4 * 100 * 100] = {0};
182 SkImageInfo::MakeN32Premul(layer_rect
.width(), layer_rect
.height());
183 expected_bitmap
.installPixels(info
, expected_pixels
, info
.minRowBytes());
184 SkCanvas
expected_canvas(expected_bitmap
);
185 expected_canvas
.clipRect(gfx::RectToSkRect(layer_rect
));
186 expected_canvas
.drawRectCoords(0.f
+ first_offset
.x(), 0.f
+ first_offset
.y(),
187 60.f
+ first_offset
.x(),
188 60.f
+ first_offset
.y(), red_paint
);
189 expected_canvas
.setMatrix(transform
.matrix());
190 expected_canvas
.drawRectCoords(
191 50.f
+ second_offset
.x(), 50.f
+ second_offset
.y(),
192 75.f
+ second_offset
.x(), 75.f
+ second_offset
.y(), blue_paint
);
194 EXPECT_EQ(0, memcmp(pixels
, expected_pixels
, 4 * 100 * 100));
197 TEST(DisplayItemListTest
, FilterItem
) {
198 gfx::Rect
layer_rect(100, 100);
199 FilterOperations filters
;
200 unsigned char pixels
[4 * 100 * 100] = {0};
201 const bool use_cached_picture
= true;
202 scoped_refptr
<DisplayItemList
> list
=
203 DisplayItemList::Create(layer_rect
, use_cached_picture
);
205 SkBitmap source_bitmap
;
206 source_bitmap
.allocN32Pixels(50, 50);
207 SkCanvas
source_canvas(source_bitmap
);
208 source_canvas
.clear(SkColorSetRGB(128, 128, 128));
210 // For most SkImageFilters, the |dst| bounds computed by computeFastBounds are
211 // dependent on the provided |src| bounds. This means, for example, that
212 // translating |src| results in a corresponding translation of |dst|. But this
213 // is not the case for all SkImageFilters; for some of them (e.g.
214 // SkBitmapSource), the computation of |dst| in computeFastBounds doesn't
215 // involve |src| at all. Incorrectly assuming such a relationship (e.g. by
216 // translating |dst| after it is computed by computeFastBounds, rather than
217 // translating |src| before it provided to computedFastBounds) can cause
218 // incorrect clipping of filter output. To test for this, we include an
219 // SkBitmapSource filter in |filters|. Here, |src| is |filter_bounds|, defined
221 skia::RefPtr
<SkImageFilter
> image_filter
=
222 skia::AdoptRef(SkBitmapSource::Create(source_bitmap
));
223 filters
.Append(FilterOperation::CreateReferenceFilter(image_filter
));
224 filters
.Append(FilterOperation::CreateBrightnessFilter(0.5f
));
225 gfx::RectF
filter_bounds(10.f
, 10.f
, 50.f
, 50.f
);
226 auto* item
= list
->CreateAndAppendItem
<FilterDisplayItem
>();
227 item
->SetNew(filters
, filter_bounds
);
228 list
->CreateAndAppendItem
<EndFilterDisplayItem
>();
231 DrawDisplayList(pixels
, layer_rect
, list
);
233 SkBitmap expected_bitmap
;
234 unsigned char expected_pixels
[4 * 100 * 100] = {0};
236 paint
.setColor(SkColorSetRGB(64, 64, 64));
238 SkImageInfo::MakeN32Premul(layer_rect
.width(), layer_rect
.height());
239 expected_bitmap
.installPixels(info
, expected_pixels
, info
.minRowBytes());
240 SkCanvas
expected_canvas(expected_bitmap
);
241 expected_canvas
.drawRect(RectFToSkRect(filter_bounds
), paint
);
243 EXPECT_EQ(0, memcmp(pixels
, expected_pixels
, 4 * 100 * 100));
246 TEST(DisplayItemListTest
, CompactingItems
) {
247 gfx::Rect
layer_rect(100, 100);
248 SkPictureRecorder recorder
;
249 skia::RefPtr
<SkCanvas
> canvas
;
250 skia::RefPtr
<SkPicture
> picture
;
252 blue_paint
.setColor(SK_ColorBLUE
);
254 red_paint
.setColor(SK_ColorRED
);
255 unsigned char pixels
[4 * 100 * 100] = {0};
257 gfx::PointF
offset(8.f
, 9.f
);
258 gfx::RectF
recording_rect(offset
, layer_rect
.size());
260 bool use_cached_picture
= false;
261 scoped_refptr
<DisplayItemList
> list_without_caching
=
262 DisplayItemList::Create(layer_rect
, use_cached_picture
);
264 canvas
= skia::SharePtr(
265 recorder
.beginRecording(gfx::RectFToSkRect(recording_rect
)));
266 canvas
->translate(offset
.x(), offset
.y());
267 canvas
->drawRectCoords(0.f
, 0.f
, 60.f
, 60.f
, red_paint
);
268 canvas
->drawRectCoords(50.f
, 50.f
, 75.f
, 75.f
, blue_paint
);
269 picture
= skia::AdoptRef(recorder
.endRecordingAsPicture());
270 auto* item1
= list_without_caching
->CreateAndAppendItem
<DrawingDisplayItem
>();
271 item1
->SetNew(picture
);
272 list_without_caching
->Finalize();
273 DrawDisplayList(pixels
, layer_rect
, list_without_caching
);
275 unsigned char expected_pixels
[4 * 100 * 100] = {0};
276 use_cached_picture
= true;
277 scoped_refptr
<DisplayItemList
> list_with_caching
=
278 DisplayItemList::Create(layer_rect
, use_cached_picture
);
279 auto* item2
= list_with_caching
->CreateAndAppendItem
<DrawingDisplayItem
>();
280 item2
->SetNew(picture
);
281 list_with_caching
->Finalize();
282 DrawDisplayList(expected_pixels
, layer_rect
, list_with_caching
);
284 EXPECT_EQ(0, memcmp(pixels
, expected_pixels
, 4 * 100 * 100));
287 TEST(DisplayItemListTest
, IsSuitableForGpuRasterizationWithCachedPicture
) {
288 gfx::Rect
layer_rect(1000, 1000);
289 SkPictureRecorder recorder
;
290 skia::RefPtr
<SkCanvas
> canvas
;
291 skia::RefPtr
<SkPicture
> picture
;
293 bool use_cached_picture
= true;
294 scoped_refptr
<DisplayItemList
> list
=
295 DisplayItemList::Create(layer_rect
, use_cached_picture
);
297 skia::SharePtr(recorder
.beginRecording(gfx::RectToSkRect(layer_rect
)));
303 path
.lineTo(100, 100);
308 paint
.setAntiAlias(true);
309 canvas
->drawPath(path
, paint
);
311 picture
= skia::AdoptRef(recorder
.endRecordingAsPicture());
312 DrawingDisplayItem
* item
= list
->CreateAndAppendItem
<DrawingDisplayItem
>();
313 item
->SetNew(picture
);
316 // A single DrawingDisplayItem with a large AA concave path shouldn't trigger
318 EXPECT_TRUE(list
->IsSuitableForGpuRasterization());
320 list
= DisplayItemList::Create(layer_rect
, use_cached_picture
);
322 skia::SharePtr(recorder
.beginRecording(gfx::RectToSkRect(layer_rect
)));
323 for (int i
= 0; i
< 10; ++i
)
324 canvas
->drawPath(path
, paint
);
325 picture
= skia::AdoptRef(recorder
.endRecordingAsPicture());
326 item
= list
->CreateAndAppendItem
<DrawingDisplayItem
>();
327 item
->SetNew(picture
);
330 // A single DrawingDisplayItem with several large AA concave paths should
332 EXPECT_FALSE(list
->IsSuitableForGpuRasterization());
334 list
= DisplayItemList::Create(layer_rect
, use_cached_picture
);
335 for (int i
= 0; i
< 10; ++i
) {
337 skia::SharePtr(recorder
.beginRecording(gfx::RectToSkRect(layer_rect
)));
338 canvas
->drawPath(path
, paint
);
339 picture
= skia::AdoptRef(recorder
.endRecordingAsPicture());
340 item
= list
->CreateAndAppendItem
<DrawingDisplayItem
>();
341 item
->SetNew(picture
);
345 // Having several DrawingDisplayItems that each contain a large AA concave
346 // path should trigger a veto.
347 EXPECT_FALSE(list
->IsSuitableForGpuRasterization());
350 TEST(DisplayItemListTest
, IsSuitableForGpuRasterizationWithoutCachedPicture
) {
351 gfx::Rect
layer_rect(1000, 1000);
352 SkPictureRecorder recorder
;
353 skia::RefPtr
<SkCanvas
> canvas
;
354 skia::RefPtr
<SkPicture
> picture
;
356 bool use_cached_picture
= false;
357 scoped_refptr
<DisplayItemList
> list
=
358 DisplayItemList::Create(layer_rect
, use_cached_picture
);
360 skia::SharePtr(recorder
.beginRecording(gfx::RectToSkRect(layer_rect
)));
366 path
.lineTo(100, 100);
371 paint
.setAntiAlias(true);
372 canvas
->drawPath(path
, paint
);
374 picture
= skia::AdoptRef(recorder
.endRecordingAsPicture());
375 DrawingDisplayItem
* item
= list
->CreateAndAppendItem
<DrawingDisplayItem
>();
376 item
->SetNew(picture
);
379 // A single DrawingDisplayItem with a large AA concave path shouldn't trigger
381 EXPECT_TRUE(list
->IsSuitableForGpuRasterization());
383 list
= DisplayItemList::Create(layer_rect
, use_cached_picture
);
385 skia::SharePtr(recorder
.beginRecording(gfx::RectToSkRect(layer_rect
)));
386 for (int i
= 0; i
< 10; ++i
)
387 canvas
->drawPath(path
, paint
);
388 picture
= skia::AdoptRef(recorder
.endRecordingAsPicture());
389 item
= list
->CreateAndAppendItem
<DrawingDisplayItem
>();
390 item
->SetNew(picture
);
393 // A single DrawingDisplayItem with several large AA concave paths should
395 EXPECT_FALSE(list
->IsSuitableForGpuRasterization());
397 list
= DisplayItemList::Create(layer_rect
, use_cached_picture
);
398 for (int i
= 0; i
< 10; ++i
) {
400 skia::SharePtr(recorder
.beginRecording(gfx::RectToSkRect(layer_rect
)));
401 canvas
->drawPath(path
, paint
);
402 picture
= skia::AdoptRef(recorder
.endRecordingAsPicture());
403 item
= list
->CreateAndAppendItem
<DrawingDisplayItem
>();
404 item
->SetNew(picture
);
408 // Without a cached picture, having several DrawingDisplayItems that each
409 // contain a single large AA concave will not trigger a veto, since each item
410 // is individually suitable for GPU rasterization.
411 EXPECT_TRUE(list
->IsSuitableForGpuRasterization());
414 TEST(DisplayItemListTest
, ApproximateMemoryUsage
) {
415 const int kNumCommandsInTestSkPicture
= 1000;
416 scoped_refptr
<DisplayItemList
> list
;
419 // Make an SkPicture whose size is known.
420 gfx::Rect
layer_rect(100, 100);
421 SkPictureRecorder recorder
;
423 blue_paint
.setColor(SK_ColorBLUE
);
424 SkCanvas
* canvas
= recorder
.beginRecording(gfx::RectToSkRect(layer_rect
));
425 for (int i
= 0; i
< kNumCommandsInTestSkPicture
; i
++)
426 canvas
->drawPaint(blue_paint
);
427 skia::RefPtr
<SkPicture
> picture
=
428 skia::AdoptRef(recorder
.endRecordingAsPicture());
429 size_t picture_size
= SkPictureUtils::ApproximateBytesUsed(picture
.get());
430 ASSERT_GE(picture_size
, kNumCommandsInTestSkPicture
* sizeof(blue_paint
));
432 // Using a cached picture, we should get about the right size.
433 list
= DisplayItemList::Create(layer_rect
, true);
434 auto* item
= list
->CreateAndAppendItem
<DrawingDisplayItem
>();
435 item
->SetNew(picture
);
437 memory_usage
= list
->ApproximateMemoryUsage();
438 EXPECT_GE(memory_usage
, picture_size
);
439 EXPECT_LE(memory_usage
, 2 * picture_size
);
441 // Using no cached picture, we should still get the right size.
442 list
= DisplayItemList::Create(layer_rect
, false);
443 item
= list
->CreateAndAppendItem
<DrawingDisplayItem
>();
444 item
->SetNew(picture
);
446 memory_usage
= list
->ApproximateMemoryUsage();
447 EXPECT_GE(memory_usage
, picture_size
);
448 EXPECT_LE(memory_usage
, 2 * picture_size
);
450 // To avoid double counting, we expect zero size to be computed if both the
451 // picture and items are retained (currently this only happens due to certain
452 // categories being traced).
453 DisplayItemListSettings settings
;
454 settings
.use_cached_picture
= true;
455 list
= new DisplayItemList(layer_rect
, settings
, true);
456 item
= list
->CreateAndAppendItem
<DrawingDisplayItem
>();
457 item
->SetNew(picture
);
459 memory_usage
= list
->ApproximateMemoryUsage();
460 EXPECT_EQ(static_cast<size_t>(0), memory_usage
);