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