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