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 "SkImage.h" 12 #include "SkImageFilter.h" 13 #include "SkImageFilterCacheKey.h" 14 #include "SkMatrix.h" 15 #include "SkSpecialImage.h" 16 17 static const int kSmallerSize = 10; 18 static const int kPad = 3; 19 static const int kFullSize = kSmallerSize + 2 * kPad; 20 21 static SkBitmap create_bm() { 22 SkBitmap bm; 23 bm.allocN32Pixels(kFullSize, kFullSize, true); 24 bm.eraseColor(SK_ColorTRANSPARENT); 25 return bm; 26 } 27 28 // Ensure the cache can return a cached image 29 static void test_find_existing(skiatest::Reporter* reporter, 30 SkSpecialImage* image, 31 SkSpecialImage* subset) { 32 static const size_t kCacheSize = 1000000; 33 SkAutoTUnref<SkImageFilter::Cache> cache(SkImageFilter::Cache::Create(kCacheSize)); 34 35 SkIRect clip = SkIRect::MakeWH(100, 100); 36 SkImageFilter::Cache::Key key1(0, SkMatrix::I(), clip, image->uniqueID(), image->subset()); 37 SkImageFilter::Cache::Key key2(0, SkMatrix::I(), clip, subset->uniqueID(), subset->subset()); 38 39 SkIPoint offset = SkIPoint::Make(3, 4); 40 cache->set(key1, image, offset); 41 42 SkIPoint foundOffset; 43 44 SkSpecialImage* foundImage = cache->get(key1, &foundOffset); 45 REPORTER_ASSERT(reporter, foundImage); 46 REPORTER_ASSERT(reporter, offset == foundOffset); 47 48 REPORTER_ASSERT(reporter, !cache->get(key2, &foundOffset)); 49 } 50 51 // If either id is different or the clip or the matrix are different the 52 // cached image won't be found. Even if it is caching the same bitmap. 53 static void test_dont_find_if_diff_key(skiatest::Reporter* reporter, 54 SkSpecialImage* image, 55 SkSpecialImage* subset) { 56 static const size_t kCacheSize = 1000000; 57 SkAutoTUnref<SkImageFilter::Cache> cache(SkImageFilter::Cache::Create(kCacheSize)); 58 59 SkIRect clip1 = SkIRect::MakeWH(100, 100); 60 SkIRect clip2 = SkIRect::MakeWH(200, 200); 61 SkImageFilter::Cache::Key key0(0, SkMatrix::I(), clip1, image->uniqueID(), image->subset()); 62 SkImageFilter::Cache::Key key1(1, SkMatrix::I(), clip1, image->uniqueID(), image->subset()); 63 SkImageFilter::Cache::Key key2(0, SkMatrix::MakeTrans(5, 5), clip1, 64 image->uniqueID(), image->subset()); 65 SkImageFilter::Cache::Key key3(0, SkMatrix::I(), clip2, image->uniqueID(), image->subset()); 66 SkImageFilter::Cache::Key key4(0, SkMatrix::I(), clip1, subset->uniqueID(), subset->subset()); 67 68 SkIPoint offset = SkIPoint::Make(3, 4); 69 cache->set(key0, image, offset); 70 71 SkIPoint foundOffset; 72 REPORTER_ASSERT(reporter, !cache->get(key1, &foundOffset)); 73 REPORTER_ASSERT(reporter, !cache->get(key2, &foundOffset)); 74 REPORTER_ASSERT(reporter, !cache->get(key3, &foundOffset)); 75 REPORTER_ASSERT(reporter, !cache->get(key4, &foundOffset)); 76 } 77 78 // Test purging when the max cache size is exceeded 79 static void test_internal_purge(skiatest::Reporter* reporter, SkSpecialImage* image) { 80 SkASSERT(image->getSize()); 81 const size_t kCacheSize = image->getSize() + 10; 82 SkAutoTUnref<SkImageFilter::Cache> cache(SkImageFilter::Cache::Create(kCacheSize)); 83 84 SkIRect clip = SkIRect::MakeWH(100, 100); 85 SkImageFilter::Cache::Key key1(0, SkMatrix::I(), clip, image->uniqueID(), image->subset()); 86 SkImageFilter::Cache::Key key2(1, SkMatrix::I(), clip, image->uniqueID(), image->subset()); 87 88 SkIPoint offset = SkIPoint::Make(3, 4); 89 cache->set(key1, image, offset); 90 91 SkIPoint foundOffset; 92 93 REPORTER_ASSERT(reporter, cache->get(key1, &foundOffset)); 94 95 // This should knock the first one out of the cache 96 cache->set(key2, image, offset); 97 98 REPORTER_ASSERT(reporter, cache->get(key2, &foundOffset)); 99 REPORTER_ASSERT(reporter, !cache->get(key1, &foundOffset)); 100 } 101 102 // Exercise the purgeByKeys and purge methods 103 static void test_explicit_purging(skiatest::Reporter* reporter, 104 SkSpecialImage* image, 105 SkSpecialImage* subset) { 106 static const size_t kCacheSize = 1000000; 107 SkAutoTUnref<SkImageFilter::Cache> cache(SkImageFilter::Cache::Create(kCacheSize)); 108 109 SkIRect clip = SkIRect::MakeWH(100, 100); 110 SkImageFilter::Cache::Key key1(0, SkMatrix::I(), clip, image->uniqueID(), image->subset()); 111 SkImageFilter::Cache::Key key2(1, SkMatrix::I(), clip, subset->uniqueID(), image->subset()); 112 113 SkIPoint offset = SkIPoint::Make(3, 4); 114 cache->set(key1, image, offset); 115 cache->set(key2, image, offset); 116 117 SkIPoint foundOffset; 118 119 REPORTER_ASSERT(reporter, cache->get(key1, &foundOffset)); 120 REPORTER_ASSERT(reporter, cache->get(key2, &foundOffset)); 121 122 cache->purgeByKeys(&key1, 1); 123 124 REPORTER_ASSERT(reporter, !cache->get(key1, &foundOffset)); 125 REPORTER_ASSERT(reporter, cache->get(key2, &foundOffset)); 126 127 cache->purge(); 128 129 REPORTER_ASSERT(reporter, !cache->get(key1, &foundOffset)); 130 REPORTER_ASSERT(reporter, !cache->get(key2, &foundOffset)); 131 } 132 133 DEF_TEST(ImageFilterCache_RasterBacked, reporter) { 134 SkBitmap srcBM = create_bm(); 135 136 const SkIRect& full = SkIRect::MakeWH(kFullSize, kFullSize); 137 138 SkAutoTUnref<SkSpecialImage> fullImg(SkSpecialImage::NewFromRaster(nullptr, full, srcBM)); 139 140 const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize); 141 142 SkAutoTUnref<SkSpecialImage> subsetImg(SkSpecialImage::NewFromRaster(nullptr, subset, srcBM)); 143 144 test_find_existing(reporter, fullImg, subsetImg); 145 test_dont_find_if_diff_key(reporter, fullImg, subsetImg); 146 test_internal_purge(reporter, fullImg); 147 test_explicit_purging(reporter, fullImg, subsetImg); 148 } 149 150 151 // Shared test code for both the raster and gpu-backed image cases 152 static void test_image_backed(skiatest::Reporter* reporter, SkImage* srcImage) { 153 const SkIRect& full = SkIRect::MakeWH(kFullSize, kFullSize); 154 155 SkAutoTUnref<SkSpecialImage> fullImg(SkSpecialImage::NewFromImage(full, srcImage)); 156 157 const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize); 158 159 SkAutoTUnref<SkSpecialImage> subsetImg(SkSpecialImage::NewFromImage(subset, srcImage)); 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 DEF_TEST(ImageFilterCache_ImageBackedRaster, reporter) { 168 SkBitmap srcBM = create_bm(); 169 170 SkAutoTUnref<SkImage> srcImage(SkImage::NewFromBitmap(srcBM)); 171 172 test_image_backed(reporter, srcImage); 173 } 174 175 #if SK_SUPPORT_GPU 176 #include "GrContext.h" 177 178 static GrTexture* create_texture(GrContext* context) { 179 SkBitmap srcBM = create_bm(); 180 181 GrSurfaceDesc desc; 182 desc.fConfig = kSkia8888_GrPixelConfig; 183 desc.fFlags = kNone_GrSurfaceFlags; 184 desc.fWidth = kFullSize; 185 desc.fHeight = kFullSize; 186 187 return context->textureProvider()->createTexture(desc, SkBudgeted::kNo, srcBM.getPixels(), 0); 188 } 189 190 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterCache_ImageBackedGPU, reporter, context) { 191 SkAutoTUnref<GrTexture> srcTexture(create_texture(context)); 192 if (!srcTexture) { 193 return; 194 } 195 196 GrBackendTextureDesc backendDesc; 197 backendDesc.fConfig = kSkia8888_GrPixelConfig; 198 backendDesc.fFlags = kNone_GrBackendTextureFlag; 199 backendDesc.fWidth = kFullSize; 200 backendDesc.fHeight = kFullSize; 201 backendDesc.fSampleCnt = 0; 202 backendDesc.fTextureHandle = srcTexture->getTextureHandle(); 203 SkAutoTUnref<SkImage> srcImage(SkImage::NewFromTexture(context, backendDesc, 204 kPremul_SkAlphaType)); 205 if (!srcImage) { 206 return; 207 } 208 209 test_image_backed(reporter, srcImage); 210 } 211 212 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterCache_GPUBacked, reporter, context) { 213 214 SkAutoTUnref<GrTexture> srcTexture(create_texture(context)); 215 if (!srcTexture) { 216 return; 217 } 218 219 const SkIRect& full = SkIRect::MakeWH(kFullSize, kFullSize); 220 221 SkAutoTUnref<SkSpecialImage> fullImg(SkSpecialImage::NewFromGpu( 222 nullptr, full, 223 kNeedNewImageUniqueID_SpecialImage, 224 srcTexture)); 225 226 const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize); 227 228 SkAutoTUnref<SkSpecialImage> subsetImg(SkSpecialImage::NewFromGpu( 229 nullptr, subset, 230 kNeedNewImageUniqueID_SpecialImage, 231 srcTexture)); 232 233 test_find_existing(reporter, fullImg, subsetImg); 234 test_dont_find_if_diff_key(reporter, fullImg, subsetImg); 235 test_internal_purge(reporter, fullImg); 236 test_explicit_purging(reporter, fullImg, subsetImg); 237 } 238 #endif 239 240