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