Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
ImageFilterCacheTest.cpp
Go to the documentation of this file.
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
21#include "include/core/SkRect.h"
28#include "include/gpu/GrTypes.h"
35#include "src/gpu/ganesh/GrColorInfo.h" // IWYU pragma: keep
40#include "src/gpu/ganesh/SkGr.h"
43#include "tests/Test.h"
44
45#include <cstddef>
46#include <tuple>
47#include <utility>
48
50struct GrContextOptions;
51
52static const int kSmallerSize = 10;
53static const int kPad = 3;
54static const int kFullSize = kSmallerSize + 2 * kPad;
55
66
71
72// Ensure the cache can return a cached image
75 const sk_sp<SkSpecialImage>& subset) {
76 static const size_t kCacheSize = 1000000;
78
79 SkIRect clip = SkIRect::MakeWH(100, 100);
80 SkImageFilterCacheKey key1(0, SkMatrix::I(), clip, image->uniqueID(), image->subset());
81 SkImageFilterCacheKey key2(0, SkMatrix::I(), clip, subset->uniqueID(), subset->subset());
82
84 auto filter = make_filter();
85 cache->set(key1, filter.get(), skif::FilterResult(image, skif::LayerSpace<SkIPoint>(offset)));
86
87 skif::FilterResult foundImage;
88 REPORTER_ASSERT(reporter, cache->get(key1, &foundImage));
91 SkIRect(foundImage.layerBounds()));
92
93 REPORTER_ASSERT(reporter, !cache->get(key2, &foundImage));
94}
95
96// If either id is different or the clip or the matrix are different the
97// cached image won't be found. Even if it is caching the same bitmap.
100 const sk_sp<SkSpecialImage>& subset) {
101 static const size_t kCacheSize = 1000000;
103
104 SkIRect clip1 = SkIRect::MakeWH(100, 100);
105 SkIRect clip2 = SkIRect::MakeWH(200, 200);
106 SkImageFilterCacheKey key0(0, SkMatrix::I(), clip1, image->uniqueID(), image->subset());
107 SkImageFilterCacheKey key1(1, SkMatrix::I(), clip1, image->uniqueID(), image->subset());
108 SkImageFilterCacheKey key2(0, SkMatrix::Translate(5, 5), clip1,
109 image->uniqueID(), image->subset());
110 SkImageFilterCacheKey key3(0, SkMatrix::I(), clip2, image->uniqueID(), image->subset());
111 SkImageFilterCacheKey key4(0, SkMatrix::I(), clip1, subset->uniqueID(), subset->subset());
112
114 auto filter = make_filter();
115 cache->set(key0, filter.get(), skif::FilterResult(image, skif::LayerSpace<SkIPoint>(offset)));
116
117 skif::FilterResult foundImage;
118 REPORTER_ASSERT(reporter, !cache->get(key1, &foundImage));
119 REPORTER_ASSERT(reporter, !cache->get(key2, &foundImage));
120 REPORTER_ASSERT(reporter, !cache->get(key3, &foundImage));
121 REPORTER_ASSERT(reporter, !cache->get(key4, &foundImage));
122}
123
124// Test purging when the max cache size is exceeded
126 SkASSERT(image->getSize());
127 const size_t kCacheSize = image->getSize() + 10;
129
130 SkIRect clip = SkIRect::MakeWH(100, 100);
131 SkImageFilterCacheKey key1(0, SkMatrix::I(), clip, image->uniqueID(), image->subset());
132 SkImageFilterCacheKey key2(1, SkMatrix::I(), clip, image->uniqueID(), image->subset());
133
135 auto filter1 = make_filter();
136 cache->set(key1, filter1.get(), skif::FilterResult(image, skif::LayerSpace<SkIPoint>(offset)));
137
138 skif::FilterResult foundImage;
139 REPORTER_ASSERT(reporter, cache->get(key1, &foundImage));
140
141 // This should knock the first one out of the cache
142 auto filter2 = make_filter();
143 cache->set(key2, filter2.get(),
145
146 REPORTER_ASSERT(reporter, cache->get(key2, &foundImage));
147 REPORTER_ASSERT(reporter, !cache->get(key1, &foundImage));
148}
149
150// Exercise the purgeByKey and purge methods
153 const sk_sp<SkSpecialImage>& subset) {
154 static const size_t kCacheSize = 1000000;
156
157 SkIRect clip = SkIRect::MakeWH(100, 100);
158 SkImageFilterCacheKey key1(0, SkMatrix::I(), clip, image->uniqueID(), image->subset());
159 SkImageFilterCacheKey key2(1, SkMatrix::I(), clip, subset->uniqueID(), image->subset());
160
162 auto filter1 = make_filter();
163 auto filter2 = make_filter();
164 cache->set(key1, filter1.get(),
166 cache->set(key2, filter2.get(),
168 SkDEBUGCODE(REPORTER_ASSERT(reporter, 2 == cache->count());)
169
170 skif::FilterResult foundImage;
171 REPORTER_ASSERT(reporter, cache->get(key1, &foundImage));
172 REPORTER_ASSERT(reporter, cache->get(key2, &foundImage));
173
174 cache->purgeByImageFilter(filter1.get());
175 SkDEBUGCODE(REPORTER_ASSERT(reporter, 1 == cache->count());)
176
177 REPORTER_ASSERT(reporter, !cache->get(key1, &foundImage));
178 REPORTER_ASSERT(reporter, cache->get(key2, &foundImage));
179
180 cache->purge();
181 SkDEBUGCODE(REPORTER_ASSERT(reporter, 0 == cache->count());)
182
183 REPORTER_ASSERT(reporter, !cache->get(key1, &foundImage));
184 REPORTER_ASSERT(reporter, !cache->get(key2, &foundImage));
185}
186
187DEF_TEST(ImageFilterCache_RasterBacked, reporter) {
188 SkBitmap srcBM = create_bm();
189
191
192 sk_sp<SkSpecialImage> fullImg(SkSpecialImages::MakeFromRaster(full, srcBM, SkSurfaceProps()));
193
195
196 sk_sp<SkSpecialImage> subsetImg(
197 SkSpecialImages::MakeFromRaster(subset, srcBM, SkSurfaceProps()));
198
199 test_find_existing(reporter, fullImg, subsetImg);
200 test_dont_find_if_diff_key(reporter, fullImg, subsetImg);
202 test_explicit_purging(reporter, fullImg, subsetImg);
203}
204
205
206// Shared test code for both the raster and gpu-backed image cases
208 GrRecordingContext* rContext,
209 const sk_sp<SkImage>& srcImage) {
211
212 sk_sp<SkSpecialImage> fullImg;
213 if (rContext) {
214 fullImg = SkSpecialImages::MakeFromTextureImage(rContext, full, srcImage, {});
215 } else {
216 fullImg = SkSpecialImages::MakeFromRaster(full, srcImage, {});
217 }
218
220
221 sk_sp<SkSpecialImage> subsetImg;
222 if (rContext) {
223 subsetImg = SkSpecialImages::MakeFromTextureImage(rContext, subset, srcImage, {});
224 } else {
225 subsetImg = SkSpecialImages::MakeFromRaster(subset, srcImage, {});
226 }
227
228 test_find_existing(reporter, fullImg, subsetImg);
229 test_dont_find_if_diff_key(reporter, fullImg, subsetImg);
231 test_explicit_purging(reporter, fullImg, subsetImg);
232}
233
234DEF_TEST(ImageFilterCache_ImageBackedRaster, reporter) {
235 SkBitmap srcBM = create_bm();
236
237 sk_sp<SkImage> srcImage(srcBM.asImage());
238
239 test_image_backed(reporter, nullptr, srcImage);
240}
241
243 SkBitmap srcBM = create_bm();
244 return std::get<0>(GrMakeUncachedBitmapProxyView(rContext, srcBM));
245}
246
247DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageFilterCache_ImageBackedGPU,
248 reporter,
249 ctxInfo,
251 auto dContext = ctxInfo.directContext();
252
253 GrSurfaceProxyView srcView = create_proxy_view(dContext);
254 if (!srcView.proxy()) {
255 return;
256 }
257
258 if (!srcView.proxy()->instantiate(dContext->priv().resourceProvider())) {
259 return;
260 }
261 GrTexture* tex = srcView.proxy()->peekTexture();
262
263 GrBackendTexture backendTex = tex->getBackendTexture();
264
267 backendTex,
268 texOrigin,
271 nullptr,
272 nullptr,
273 nullptr));
274 if (!srcImage) {
275 return;
276 }
277
278 GrSurfaceOrigin readBackOrigin;
279 GrBackendTexture readBackBackendTex;
281 srcImage, &readBackBackendTex, false, &readBackOrigin);
283 if (!GrBackendTexture::TestingOnly_Equals(readBackBackendTex, backendTex)) {
284 ERRORF(reporter, "backend mismatch\n");
285 }
286 REPORTER_ASSERT(reporter, GrBackendTexture::TestingOnly_Equals(readBackBackendTex, backendTex));
287
288 if (readBackOrigin != texOrigin) {
289 ERRORF(reporter, "origin mismatch %d %d\n", readBackOrigin, texOrigin);
290 }
291 REPORTER_ASSERT(reporter, readBackOrigin == texOrigin);
292
293 test_image_backed(reporter, dContext, srcImage);
294}
295
296DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(ImageFilterCache_GPUBacked,
297 reporter,
298 ctxInfo,
300 auto dContext = ctxInfo.directContext();
301
302 GrSurfaceProxyView srcView = create_proxy_view(dContext);
303 if (!srcView.proxy()) {
304 return;
305 }
306
308
309 sk_sp<SkSpecialImage> fullImg(SkSpecialImages::MakeDeferredFromGpu(
310 dContext,
311 full,
313 srcView,
315 SkSurfaceProps()));
316
318
319 sk_sp<SkSpecialImage> subsetImg(SkSpecialImages::MakeDeferredFromGpu(
320 dContext,
321 subset,
323 std::move(srcView),
325 SkSurfaceProps()));
326
327 test_find_existing(reporter, fullImg, subsetImg);
328 test_dont_find_if_diff_key(reporter, fullImg, subsetImg);
330 test_explicit_purging(reporter, fullImg, subsetImg);
331}
332
333DEF_SERIAL_TEST(PurgeImageFilterCache, r) {
335 if (cache) {
336 // This test verifies that Get(false) does not create the cache, but
337 // another test has already created it, so there is nothing to test.
338 return;
339 }
340
341 // This method calls SkImageFilter_Base::PurgeCache(), which is private.
344
345 // PurgeCache should not have created it.
346 REPORTER_ASSERT(r, !cache);
347
348 {
350 REPORTER_ASSERT(r, cache);
351 }
352}
reporter
GrSurfaceOrigin
Definition GrTypes.h:147
@ kTopLeft_GrSurfaceOrigin
Definition GrTypes.h:148
static const int kFullSize
static const int kSmallerSize
static void test_explicit_purging(skiatest::Reporter *reporter, const sk_sp< SkSpecialImage > &image, const sk_sp< SkSpecialImage > &subset)
static void test_dont_find_if_diff_key(skiatest::Reporter *reporter, const sk_sp< SkSpecialImage > &image, const sk_sp< SkSpecialImage > &subset)
static SkBitmap create_bm()
static const int kPad
static void test_image_backed(skiatest::Reporter *reporter, GrRecordingContext *rContext, const sk_sp< SkImage > &srcImage)
static void test_internal_purge(skiatest::Reporter *reporter, const sk_sp< SkSpecialImage > &image)
static GrSurfaceProxyView create_proxy_view(GrRecordingContext *rContext)
static sk_sp< SkImageFilter > make_filter()
static void test_find_existing(skiatest::Reporter *reporter, const sk_sp< SkSpecialImage > &image, const sk_sp< SkSpecialImage > &subset)
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
Definition SkAlphaType.h:29
#define SkASSERT(cond)
Definition SkAssert.h:116
@ kSrcIn
r = s * da
@ kRGBA_8888_SkColorType
pixel with 8 bits for red, green, blue, alpha; in 32-bit word
Definition SkColorType.h:24
constexpr SkColor SK_ColorTRANSPARENT
Definition SkColor.h:99
constexpr SkColor SK_ColorBLUE
Definition SkColor.h:135
#define SkDEBUGCODE(...)
Definition SkDebug.h:23
std::tuple< GrSurfaceProxyView, GrColorType > GrMakeUncachedBitmapProxyView(GrRecordingContext *rContext, const SkBitmap &bitmap, skgpu::Mipmapped mipmapped, SkBackingFit fit, skgpu::Budgeted budgeted)
Definition SkGr.cpp:253
static bool ok(int result)
static SkPath clip(const SkPath &path, const SkHalfPlane &plane)
Definition SkPath.cpp:3824
@ kNeedNewImageUniqueID_SpecialImage
#define DEF_SERIAL_TEST(name, reporter)
Definition Test.h:322
#define DEF_TEST(name, reporter)
Definition Test.h:312
#define REPORTER_ASSERT(r, cond,...)
Definition Test.h:286
#define ERRORF(r,...)
Definition Test.h:293
#define DEF_GANESH_TEST_FOR_RENDERING_CONTEXTS(name, reporter, context_info, ctsEnforcement)
Definition Test.h:434
GrSurfaceProxy * proxy() const
virtual bool instantiate(GrResourceProvider *)=0
GrTexture * peekTexture() const
virtual GrBackendTexture getBackendTexture() const =0
void allocPixels(const SkImageInfo &info, size_t rowBytes)
Definition SkBitmap.cpp:258
sk_sp< SkImage > asImage() const
Definition SkBitmap.cpp:645
void setImmutable()
Definition SkBitmap.cpp:400
void eraseColor(SkColor4f) const
Definition SkBitmap.cpp:442
static sk_sp< SkColorFilter > Blend(const SkColor4f &c, sk_sp< SkColorSpace >, SkBlendMode mode)
static void PurgeResourceCache()
static sk_sp< SkImageFilterCache > Get(CreateIfNecessary=CreateIfNecessary::kYes)
static sk_sp< SkImageFilterCache > Create(size_t maxBytes)
static sk_sp< SkImageFilter > ColorFilter(sk_sp< SkColorFilter > cf, sk_sp< SkImageFilter > input, const CropRect &cropRect={})
uint32_t uniqueID() const
Definition SkImage.h:311
int width() const
Definition SkImage.h:285
int height() const
Definition SkImage.h:291
static SkMatrix Translate(SkScalar dx, SkScalar dy)
Definition SkMatrix.h:91
static const SkMatrix & I()
LayerSpace< SkIRect > layerBounds() const
sk_sp< SkImage > image
Definition examples.cpp:29
SK_API bool GetBackendTextureFromImage(const SkImage *img, GrBackendTexture *outTexture, bool flushPendingGrContextIO, GrSurfaceOrigin *origin=nullptr)
SK_API sk_sp< SkImage > BorrowTextureFrom(GrRecordingContext *context, const GrBackendTexture &backendTexture, GrSurfaceOrigin origin, SkColorType colorType, SkAlphaType alphaType, sk_sp< SkColorSpace > colorSpace, TextureReleaseProc textureReleaseProc=nullptr, ReleaseContext releaseContext=nullptr)
Definition full.py:1
Point offset
static constexpr SkIPoint Make(int32_t x, int32_t y)
static constexpr SkIRect MakeWH(int32_t w, int32_t h)
Definition SkRect.h:56
static constexpr SkIRect MakeXYWH(int32_t x, int32_t y, int32_t w, int32_t h)
Definition SkRect.h:104
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)