• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /*
2   * Copyright 2016 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 "Test.h"
9 
10 #include "SkBitmap.h"
11 #include "SkColorFilter.h"
12 #include "SkColorFilterImageFilter.h"
13 #include "SkImage.h"
14 #include "SkImageFilter.h"
15 #include "SkImageFilterCache.h"
16 #include "SkMatrix.h"
17 #include "SkSpecialImage.h"
18 
19 static const int kSmallerSize = 10;
20 static const int kPad = 3;
21 static const int kFullSize = kSmallerSize + 2 * kPad;
22 
create_bm()23 static SkBitmap create_bm() {
24     SkBitmap bm;
25     bm.allocN32Pixels(kFullSize, kFullSize, true);
26     bm.eraseColor(SK_ColorTRANSPARENT);
27     return bm;
28 }
29 
make_filter()30 static sk_sp<SkImageFilter> make_filter() {
31     sk_sp<SkColorFilter> filter(SkColorFilter::MakeModeFilter(SK_ColorBLUE,
32                                                               SkBlendMode::kSrcIn));
33     return SkColorFilterImageFilter::Make(std::move(filter), nullptr, nullptr);
34 }
35 
36 // Ensure the cache can return a cached image
test_find_existing(skiatest::Reporter * reporter,const sk_sp<SkSpecialImage> & image,const sk_sp<SkSpecialImage> & subset)37 static void test_find_existing(skiatest::Reporter* reporter,
38                                const sk_sp<SkSpecialImage>& image,
39                                const sk_sp<SkSpecialImage>& subset) {
40     static const size_t kCacheSize = 1000000;
41     sk_sp<SkImageFilterCache> cache(SkImageFilterCache::Create(kCacheSize));
42 
43     SkIRect clip = SkIRect::MakeWH(100, 100);
44     SkImageFilterCacheKey key1(0, SkMatrix::I(), clip, image->uniqueID(), image->subset());
45     SkImageFilterCacheKey key2(0, SkMatrix::I(), clip, subset->uniqueID(), subset->subset());
46 
47     SkIPoint offset = SkIPoint::Make(3, 4);
48     auto filter = make_filter();
49     cache->set(key1, image.get(), offset, filter.get());
50 
51     SkIPoint foundOffset;
52 
53     sk_sp<SkSpecialImage> foundImage = cache->get(key1, &foundOffset);
54     REPORTER_ASSERT(reporter, foundImage);
55     REPORTER_ASSERT(reporter, offset == foundOffset);
56 
57     REPORTER_ASSERT(reporter, !cache->get(key2, &foundOffset));
58 }
59 
60 // If either id is different or the clip or the matrix are different the
61 // cached image won't be found. Even if it is caching the same bitmap.
test_dont_find_if_diff_key(skiatest::Reporter * reporter,const sk_sp<SkSpecialImage> & image,const sk_sp<SkSpecialImage> & subset)62 static void test_dont_find_if_diff_key(skiatest::Reporter* reporter,
63                                        const sk_sp<SkSpecialImage>& image,
64                                        const sk_sp<SkSpecialImage>& subset) {
65     static const size_t kCacheSize = 1000000;
66     sk_sp<SkImageFilterCache> cache(SkImageFilterCache::Create(kCacheSize));
67 
68     SkIRect clip1 = SkIRect::MakeWH(100, 100);
69     SkIRect clip2 = SkIRect::MakeWH(200, 200);
70     SkImageFilterCacheKey key0(0, SkMatrix::I(), clip1, image->uniqueID(), image->subset());
71     SkImageFilterCacheKey key1(1, SkMatrix::I(), clip1, image->uniqueID(), image->subset());
72     SkImageFilterCacheKey key2(0, SkMatrix::MakeTrans(5, 5), clip1,
73                                    image->uniqueID(), image->subset());
74     SkImageFilterCacheKey key3(0, SkMatrix::I(), clip2, image->uniqueID(), image->subset());
75     SkImageFilterCacheKey key4(0, SkMatrix::I(), clip1, subset->uniqueID(), subset->subset());
76 
77     SkIPoint offset = SkIPoint::Make(3, 4);
78     auto filter = make_filter();
79     cache->set(key0, image.get(), offset, filter.get());
80 
81     SkIPoint foundOffset;
82     REPORTER_ASSERT(reporter, !cache->get(key1, &foundOffset));
83     REPORTER_ASSERT(reporter, !cache->get(key2, &foundOffset));
84     REPORTER_ASSERT(reporter, !cache->get(key3, &foundOffset));
85     REPORTER_ASSERT(reporter, !cache->get(key4, &foundOffset));
86 }
87 
88 // Test purging when the max cache size is exceeded
test_internal_purge(skiatest::Reporter * reporter,const sk_sp<SkSpecialImage> & image)89 static void test_internal_purge(skiatest::Reporter* reporter, const sk_sp<SkSpecialImage>& image) {
90     SkASSERT(image->getSize());
91     const size_t kCacheSize = image->getSize() + 10;
92     sk_sp<SkImageFilterCache> cache(SkImageFilterCache::Create(kCacheSize));
93 
94     SkIRect clip = SkIRect::MakeWH(100, 100);
95     SkImageFilterCacheKey key1(0, SkMatrix::I(), clip, image->uniqueID(), image->subset());
96     SkImageFilterCacheKey key2(1, SkMatrix::I(), clip, image->uniqueID(), image->subset());
97 
98     SkIPoint offset = SkIPoint::Make(3, 4);
99     auto filter1 = make_filter();
100     cache->set(key1, image.get(), offset, filter1.get());
101 
102     SkIPoint foundOffset;
103 
104     REPORTER_ASSERT(reporter, cache->get(key1, &foundOffset));
105 
106     // This should knock the first one out of the cache
107     auto filter2 = make_filter();
108     cache->set(key2, image.get(), offset, filter2.get());
109 
110     REPORTER_ASSERT(reporter, cache->get(key2, &foundOffset));
111     REPORTER_ASSERT(reporter, !cache->get(key1, &foundOffset));
112 }
113 
114 // Exercise the purgeByKey and purge methods
test_explicit_purging(skiatest::Reporter * reporter,const sk_sp<SkSpecialImage> & image,const sk_sp<SkSpecialImage> & subset)115 static void test_explicit_purging(skiatest::Reporter* reporter,
116                                   const sk_sp<SkSpecialImage>& image,
117                                   const sk_sp<SkSpecialImage>& subset) {
118     static const size_t kCacheSize = 1000000;
119     sk_sp<SkImageFilterCache> cache(SkImageFilterCache::Create(kCacheSize));
120 
121     SkIRect clip = SkIRect::MakeWH(100, 100);
122     SkImageFilterCacheKey key1(0, SkMatrix::I(), clip, image->uniqueID(), image->subset());
123     SkImageFilterCacheKey key2(1, SkMatrix::I(), clip, subset->uniqueID(), image->subset());
124 
125     SkIPoint offset = SkIPoint::Make(3, 4);
126     auto filter1 = make_filter();
127     auto filter2 = make_filter();
128     cache->set(key1, image.get(), offset, filter1.get());
129     cache->set(key2, image.get(), offset, filter2.get());
130     SkDEBUGCODE(REPORTER_ASSERT(reporter, 2 == cache->count());)
131 
132     SkIPoint foundOffset;
133 
134     REPORTER_ASSERT(reporter, cache->get(key1, &foundOffset));
135     REPORTER_ASSERT(reporter, cache->get(key2, &foundOffset));
136 
137     cache->purgeByImageFilter(filter1.get());
138     SkDEBUGCODE(REPORTER_ASSERT(reporter, 1 == cache->count());)
139 
140     REPORTER_ASSERT(reporter, !cache->get(key1, &foundOffset));
141     REPORTER_ASSERT(reporter, cache->get(key2, &foundOffset));
142 
143     cache->purge();
144     SkDEBUGCODE(REPORTER_ASSERT(reporter, 0 == cache->count());)
145 
146     REPORTER_ASSERT(reporter, !cache->get(key1, &foundOffset));
147     REPORTER_ASSERT(reporter, !cache->get(key2, &foundOffset));
148 }
149 
DEF_TEST(ImageFilterCache_RasterBacked,reporter)150 DEF_TEST(ImageFilterCache_RasterBacked, reporter) {
151     SkBitmap srcBM = create_bm();
152 
153     const SkIRect& full = SkIRect::MakeWH(kFullSize, kFullSize);
154 
155     sk_sp<SkSpecialImage> fullImg(SkSpecialImage::MakeFromRaster(full, srcBM));
156 
157     const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize);
158 
159     sk_sp<SkSpecialImage> subsetImg(SkSpecialImage::MakeFromRaster(subset, srcBM));
160 
161     test_find_existing(reporter, fullImg, subsetImg);
162     test_dont_find_if_diff_key(reporter, fullImg, subsetImg);
163     test_internal_purge(reporter, fullImg);
164     test_explicit_purging(reporter, fullImg, subsetImg);
165 }
166 
167 
168 // Shared test code for both the raster and gpu-backed image cases
test_image_backed(skiatest::Reporter * reporter,GrContext * context,const sk_sp<SkImage> & srcImage)169 static void test_image_backed(skiatest::Reporter* reporter,
170                               GrContext* context,
171                               const sk_sp<SkImage>& srcImage) {
172     const SkIRect& full = SkIRect::MakeWH(kFullSize, kFullSize);
173 
174     sk_sp<SkSpecialImage> fullImg(SkSpecialImage::MakeFromImage(context, full, srcImage));
175 
176     const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize);
177 
178     sk_sp<SkSpecialImage> subsetImg(SkSpecialImage::MakeFromImage(context, subset, srcImage));
179 
180     test_find_existing(reporter, fullImg, subsetImg);
181     test_dont_find_if_diff_key(reporter, fullImg, subsetImg);
182     test_internal_purge(reporter, fullImg);
183     test_explicit_purging(reporter, fullImg, subsetImg);
184 }
185 
DEF_TEST(ImageFilterCache_ImageBackedRaster,reporter)186 DEF_TEST(ImageFilterCache_ImageBackedRaster, reporter) {
187     SkBitmap srcBM = create_bm();
188 
189     sk_sp<SkImage> srcImage(SkImage::MakeFromBitmap(srcBM));
190 
191     test_image_backed(reporter, nullptr, srcImage);
192 }
193 
194 #include "GrContext.h"
195 #include "GrContextPriv.h"
196 #include "GrProxyProvider.h"
197 #include "GrResourceProvider.h"
198 #include "GrSurfaceProxyPriv.h"
199 #include "GrTexture.h"
200 #include "GrTextureProxy.h"
201 
create_proxy(GrProxyProvider * proxyProvider)202 static sk_sp<GrTextureProxy> create_proxy(GrProxyProvider* proxyProvider) {
203     SkBitmap srcBM = create_bm();
204     sk_sp<SkImage> srcImage(SkImage::MakeFromBitmap(srcBM));
205     return proxyProvider->createTextureProxy(srcImage, kNone_GrSurfaceFlags, 1,
206                                              SkBudgeted::kYes, SkBackingFit::kExact);
207 }
208 
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterCache_ImageBackedGPU,reporter,ctxInfo)209 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterCache_ImageBackedGPU, reporter, ctxInfo) {
210     GrContext* context = ctxInfo.grContext();
211 
212     sk_sp<GrTextureProxy> srcProxy(create_proxy(context->contextPriv().proxyProvider()));
213     if (!srcProxy) {
214         return;
215     }
216 
217     if (!srcProxy->instantiate(context->contextPriv().resourceProvider())) {
218         return;
219     }
220     GrTexture* tex = srcProxy->peekTexture();
221 
222     GrBackendTexture backendTex = tex->getBackendTexture();
223 
224     GrSurfaceOrigin texOrigin = kTopLeft_GrSurfaceOrigin;
225     sk_sp<SkImage> srcImage(SkImage::MakeFromTexture(context,
226                                                      backendTex,
227                                                      texOrigin,
228                                                      kRGBA_8888_SkColorType,
229                                                      kPremul_SkAlphaType, nullptr,
230                                                      nullptr, nullptr));
231     if (!srcImage) {
232         return;
233     }
234 
235     GrSurfaceOrigin readBackOrigin;
236     GrBackendTexture readBackBackendTex = srcImage->getBackendTexture(false, &readBackOrigin);
237     if (!GrBackendTexture::TestingOnly_Equals(readBackBackendTex, backendTex)) {
238         ERRORF(reporter, "backend mismatch\n");
239     }
240     REPORTER_ASSERT(reporter, GrBackendTexture::TestingOnly_Equals(readBackBackendTex, backendTex));
241 
242     if (readBackOrigin != texOrigin) {
243         ERRORF(reporter, "origin mismatch %d %d\n", readBackOrigin, texOrigin);
244     }
245     REPORTER_ASSERT(reporter, readBackOrigin == texOrigin);
246 
247     test_image_backed(reporter, context, srcImage);
248 }
249 
DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterCache_GPUBacked,reporter,ctxInfo)250 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterCache_GPUBacked, reporter, ctxInfo) {
251     GrContext* context = ctxInfo.grContext();
252 
253     sk_sp<GrTextureProxy> srcProxy(create_proxy(context->contextPriv().proxyProvider()));
254     if (!srcProxy) {
255         return;
256     }
257 
258     const SkIRect& full = SkIRect::MakeWH(kFullSize, kFullSize);
259 
260     sk_sp<SkSpecialImage> fullImg(SkSpecialImage::MakeDeferredFromGpu(
261                                                               context, full,
262                                                               kNeedNewImageUniqueID_SpecialImage,
263                                                               srcProxy, nullptr));
264 
265     const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize);
266 
267     sk_sp<SkSpecialImage> subsetImg(SkSpecialImage::MakeDeferredFromGpu(
268                                                                 context, subset,
269                                                                 kNeedNewImageUniqueID_SpecialImage,
270                                                                 srcProxy, nullptr));
271 
272     test_find_existing(reporter, fullImg, subsetImg);
273     test_dont_find_if_diff_key(reporter, fullImg, subsetImg);
274     test_internal_purge(reporter, fullImg);
275     test_explicit_purging(reporter, fullImg, subsetImg);
276 }
277