1 /*
2 * Copyright 2014 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "include/core/SkCanvas.h"
9 #include "include/core/SkColor.h"
10 #include "include/core/SkImageInfo.h"
11 #include "include/core/SkPaint.h"
12 #include "include/core/SkPicture.h"
13 #include "include/core/SkPictureRecorder.h"
14 #include "include/core/SkRefCnt.h"
15 #include "include/core/SkSamplingOptions.h"
16 #include "include/core/SkSurface.h"
17 #include "include/core/SkTileMode.h"
18 #include "src/core/SkPicturePriv.h"
19 #include "src/core/SkResourceCache.h"
20 #include "tests/Test.h"
21
22 #include <cstdint>
23 #include <initializer_list>
24
25 // Test that the SkPictureShader cache is purged on shader deletion.
DEF_TEST(PictureShader_caching,reporter)26 DEF_TEST(PictureShader_caching, reporter) {
27 auto makePicture = [] () {
28 SkPictureRecorder recorder;
29 recorder.beginRecording(100, 100)->drawColor(SK_ColorGREEN);
30 return recorder.finishRecordingAsPicture();
31 };
32
33 sk_sp<SkPicture> picture = makePicture();
34 REPORTER_ASSERT(reporter, picture->unique());
35
36 sk_sp<SkSurface> surface = SkSurfaces::Raster(SkImageInfo::MakeN32Premul(100, 100));
37
38 {
39 SkPaint paint;
40 paint.setShader(picture->makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat,
41 SkFilterMode::kNearest));
42 surface->getCanvas()->drawPaint(paint);
43
44 // We should have about 3 refs by now: local + shader + shader cache.
45 REPORTER_ASSERT(reporter, !picture->unique());
46 }
47
48 // Draw another picture shader to have a chance to purge.
49 {
50 SkPaint paint;
51 paint.setShader(makePicture()->makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat,
52 SkFilterMode::kNearest));
53 surface->getCanvas()->drawPaint(paint);
54
55 }
56
57 // All but the local ref should be gone now.
58 REPORTER_ASSERT(reporter, picture->unique());
59 }
60
61 /*
62 * Check caching of picture-shaders
63 * - we do cache the underlying image (i.e. there is a cache entry)
64 * - there is only 1 entry, even with differing tile modes
65 * - after deleting the picture, the cache entry is purged
66 */
DEF_TEST(PictureShader_caching2,reporter)67 DEF_TEST(PictureShader_caching2, reporter) {
68 auto picture = []() {
69 SkPictureRecorder recorder;
70 recorder.beginRecording(100, 100)->drawColor(SK_ColorGREEN);
71 return recorder.finishRecordingAsPicture();
72 }();
73 REPORTER_ASSERT(reporter, picture->unique());
74
75 struct Data {
76 uint64_t sharedID;
77 int counter;
78 } data = {
79 SkPicturePriv::MakeSharedID(picture->uniqueID()),
80 0,
81 };
82
83 auto counter = [](const SkResourceCache::Rec& rec, void* dataPtr) {
84 if (rec.getKey().getSharedID() == ((Data*)dataPtr)->sharedID) {
85 ((Data*)dataPtr)->counter += 1;
86 }
87 };
88
89 SkResourceCache::VisitAll(counter, &data);
90 REPORTER_ASSERT(reporter, data.counter == 0);
91
92 // Draw with a view variants of picture-shaders that all use the same picture.
93 // Only expect 1 cache entry for all (since same CTM for all).
94 sk_sp<SkSurface> surface = SkSurfaces::Raster(SkImageInfo::MakeN32Premul(100, 100));
95 for (SkTileMode m : {
96 SkTileMode::kClamp, SkTileMode::kRepeat, SkTileMode::kRepeat, SkTileMode::kDecal
97 }) {
98 SkPaint paint;
99 paint.setShader(picture->makeShader(m, m, SkFilterMode::kNearest));
100 surface->getCanvas()->drawPaint(paint);
101 }
102
103 // Don't expect any additional refs on the picture
104 REPORTER_ASSERT(reporter, picture->unique());
105
106 // Check that we did cache something, but only 1 thing
107 data.counter = 0;
108 SkResourceCache::VisitAll(counter, &data);
109 REPORTER_ASSERT(reporter, data.counter == 1);
110
111 // Now delete the picture, and check the we purge the cache entry
112
113 picture.reset();
114 SkResourceCache::CheckMessages();
115
116 data.counter = 0;
117 SkResourceCache::VisitAll(counter, &data);
118 REPORTER_ASSERT(reporter, data.counter == 0);
119 }
120