2 * Copyright 2016 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
8 #include "tests/Test.h"
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"
19 static const int kSmallerSize = 10;
20 static const int kPad = 3;
21 static const int kFullSize = kSmallerSize + 2 * kPad;
23 static SkBitmap create_bm() {
24 SkImageInfo ii = SkImageInfo::Make(kFullSize, kFullSize, kRGBA_8888_SkColorType,
29 bm.eraseColor(SK_ColorTRANSPARENT);
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);
39 // Ensure the cache can return a cached image
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));
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());
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)));
54 skif::FilterResult foundImage;
55 REPORTER_ASSERT(reporter, cache->get(key1, &foundImage));
56 REPORTER_ASSERT(reporter, offset == SkIPoint(foundImage.layerOrigin()));
58 REPORTER_ASSERT(reporter, !cache->get(key2, &foundImage));
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.
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));
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());
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)));
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));
89 // Test purging when the max cache size is exceeded
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));
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());
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)));
103 skif::FilterResult foundImage;
104 REPORTER_ASSERT(reporter, cache->get(key1, &foundImage));
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)));
111 REPORTER_ASSERT(reporter, cache->get(key2, &foundImage));
112 REPORTER_ASSERT(reporter, !cache->get(key1, &foundImage));
115 // Exercise the purgeByKey and purge methods
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));
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());
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());)
135 skif::FilterResult foundImage;
136 REPORTER_ASSERT(reporter, cache->get(key1, &foundImage));
137 REPORTER_ASSERT(reporter, cache->get(key2, &foundImage));
139 cache->purgeByImageFilter(filter1.get());
140 SkDEBUGCODE(REPORTER_ASSERT(reporter, 1 == cache->count());)
142 REPORTER_ASSERT(reporter, !cache->get(key1, &foundImage));
143 REPORTER_ASSERT(reporter, cache->get(key2, &foundImage));
146 SkDEBUGCODE(REPORTER_ASSERT(reporter, 0 == cache->count());)
148 REPORTER_ASSERT(reporter, !cache->get(key1, &foundImage));
149 REPORTER_ASSERT(reporter, !cache->get(key2, &foundImage));
152 DEF_TEST(ImageFilterCache_RasterBacked, reporter) {
153 SkBitmap srcBM = create_bm();
155 const SkIRect& full = SkIRect::MakeWH(kFullSize, kFullSize);
157 sk_sp<SkSpecialImage> fullImg(SkSpecialImage::MakeFromRaster(full, srcBM, SkSurfaceProps()));
159 const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize);
161 sk_sp<SkSpecialImage> subsetImg(SkSpecialImage::MakeFromRaster(subset, srcBM,
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);
171 // Shared test code for both the raster and gpu-backed image cases
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);
177 sk_sp<SkSpecialImage> fullImg(SkSpecialImage::MakeFromImage(rContext, full, srcImage,
180 const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize);
182 sk_sp<SkSpecialImage> subsetImg(SkSpecialImage::MakeFromImage(rContext, subset, srcImage,
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);
191 DEF_TEST(ImageFilterCache_ImageBackedRaster, reporter) {
192 SkBitmap srcBM = create_bm();
194 sk_sp<SkImage> srcImage(srcBM.asImage());
196 test_image_backed(reporter, nullptr, srcImage);
199 #include "include/gpu/GrDirectContext.h"
200 #include "src/gpu/ganesh/GrDirectContextPriv.h"
201 #include "src/gpu/ganesh/GrProxyProvider.h"
202 #include "src/gpu/ganesh/GrResourceProvider.h"
203 #include "src/gpu/ganesh/GrSurfaceProxyPriv.h"
204 #include "src/gpu/ganesh/GrTexture.h"
205 #include "src/gpu/ganesh/GrTextureProxy.h"
206 #include "src/gpu/ganesh/SkGr.h"
208 static GrSurfaceProxyView create_proxy_view(GrRecordingContext* rContext) {
209 SkBitmap srcBM = create_bm();
210 return std::get<0>(GrMakeUncachedBitmapProxyView(rContext, srcBM));
213 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterCache_ImageBackedGPU, reporter, ctxInfo) {
214 auto dContext = ctxInfo.directContext();
216 GrSurfaceProxyView srcView = create_proxy_view(dContext);
217 if (!srcView.proxy()) {
221 if (!srcView.proxy()->instantiate(dContext->priv().resourceProvider())) {
224 GrTexture* tex = srcView.proxy()->peekTexture();
226 GrBackendTexture backendTex = tex->getBackendTexture();
228 GrSurfaceOrigin texOrigin = kTopLeft_GrSurfaceOrigin;
229 sk_sp<SkImage> srcImage(SkImage::MakeFromTexture(dContext,
232 kRGBA_8888_SkColorType,
233 kPremul_SkAlphaType, nullptr,
239 GrSurfaceOrigin readBackOrigin;
240 GrBackendTexture readBackBackendTex = srcImage->getBackendTexture(false, &readBackOrigin);
241 if (!GrBackendTexture::TestingOnly_Equals(readBackBackendTex, backendTex)) {
242 ERRORF(reporter, "backend mismatch\n");
244 REPORTER_ASSERT(reporter, GrBackendTexture::TestingOnly_Equals(readBackBackendTex, backendTex));
246 if (readBackOrigin != texOrigin) {
247 ERRORF(reporter, "origin mismatch %d %d\n", readBackOrigin, texOrigin);
249 REPORTER_ASSERT(reporter, readBackOrigin == texOrigin);
251 test_image_backed(reporter, dContext, srcImage);
254 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterCache_GPUBacked, reporter, ctxInfo) {
255 auto dContext = ctxInfo.directContext();
257 GrSurfaceProxyView srcView = create_proxy_view(dContext);
258 if (!srcView.proxy()) {
262 const SkIRect& full = SkIRect::MakeWH(kFullSize, kFullSize);
264 sk_sp<SkSpecialImage> fullImg(SkSpecialImage::MakeDeferredFromGpu(
266 kNeedNewImageUniqueID_SpecialImage,
268 GrColorType::kRGBA_8888, nullptr,
271 const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize);
273 sk_sp<SkSpecialImage> subsetImg(SkSpecialImage::MakeDeferredFromGpu(
275 kNeedNewImageUniqueID_SpecialImage,
277 GrColorType::kRGBA_8888, nullptr,
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);