ImageFilterCacheTest.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  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. #include "tests/Test.h"
  8. #include "include/core/SkBitmap.h"
  9. #include "include/core/SkColorFilter.h"
  10. #include "include/core/SkImage.h"
  11. #include "include/core/SkImageFilter.h"
  12. #include "include/core/SkMatrix.h"
  13. #include "include/effects/SkColorFilterImageFilter.h"
  14. #include "src/core/SkImageFilterCache.h"
  15. #include "src/core/SkSpecialImage.h"
  16. static const int kSmallerSize = 10;
  17. static const int kPad = 3;
  18. static const int kFullSize = kSmallerSize + 2 * kPad;
  19. static SkBitmap create_bm() {
  20. SkBitmap bm;
  21. bm.allocN32Pixels(kFullSize, kFullSize, true);
  22. bm.eraseColor(SK_ColorTRANSPARENT);
  23. return bm;
  24. }
  25. static sk_sp<SkImageFilter> make_filter() {
  26. sk_sp<SkColorFilter> filter(SkColorFilters::Blend(SK_ColorBLUE,
  27. SkBlendMode::kSrcIn));
  28. return SkColorFilterImageFilter::Make(std::move(filter), nullptr, nullptr);
  29. }
  30. // Ensure the cache can return a cached image
  31. static void test_find_existing(skiatest::Reporter* reporter,
  32. const sk_sp<SkSpecialImage>& image,
  33. const sk_sp<SkSpecialImage>& subset) {
  34. static const size_t kCacheSize = 1000000;
  35. sk_sp<SkImageFilterCache> cache(SkImageFilterCache::Create(kCacheSize));
  36. SkIRect clip = SkIRect::MakeWH(100, 100);
  37. SkImageFilterCacheKey key1(0, SkMatrix::I(), clip, image->uniqueID(), image->subset());
  38. SkImageFilterCacheKey key2(0, SkMatrix::I(), clip, subset->uniqueID(), subset->subset());
  39. SkIPoint offset = SkIPoint::Make(3, 4);
  40. auto filter = make_filter();
  41. cache->set(key1, image.get(), offset, filter.get());
  42. SkIPoint foundOffset;
  43. sk_sp<SkSpecialImage> foundImage = cache->get(key1, &foundOffset);
  44. REPORTER_ASSERT(reporter, foundImage);
  45. REPORTER_ASSERT(reporter, offset == foundOffset);
  46. REPORTER_ASSERT(reporter, !cache->get(key2, &foundOffset));
  47. }
  48. // If either id is different or the clip or the matrix are different the
  49. // cached image won't be found. Even if it is caching the same bitmap.
  50. static void test_dont_find_if_diff_key(skiatest::Reporter* reporter,
  51. const sk_sp<SkSpecialImage>& image,
  52. const sk_sp<SkSpecialImage>& subset) {
  53. static const size_t kCacheSize = 1000000;
  54. sk_sp<SkImageFilterCache> cache(SkImageFilterCache::Create(kCacheSize));
  55. SkIRect clip1 = SkIRect::MakeWH(100, 100);
  56. SkIRect clip2 = SkIRect::MakeWH(200, 200);
  57. SkImageFilterCacheKey key0(0, SkMatrix::I(), clip1, image->uniqueID(), image->subset());
  58. SkImageFilterCacheKey key1(1, SkMatrix::I(), clip1, image->uniqueID(), image->subset());
  59. SkImageFilterCacheKey key2(0, SkMatrix::MakeTrans(5, 5), clip1,
  60. image->uniqueID(), image->subset());
  61. SkImageFilterCacheKey key3(0, SkMatrix::I(), clip2, image->uniqueID(), image->subset());
  62. SkImageFilterCacheKey key4(0, SkMatrix::I(), clip1, subset->uniqueID(), subset->subset());
  63. SkIPoint offset = SkIPoint::Make(3, 4);
  64. auto filter = make_filter();
  65. cache->set(key0, image.get(), offset, filter.get());
  66. SkIPoint foundOffset;
  67. REPORTER_ASSERT(reporter, !cache->get(key1, &foundOffset));
  68. REPORTER_ASSERT(reporter, !cache->get(key2, &foundOffset));
  69. REPORTER_ASSERT(reporter, !cache->get(key3, &foundOffset));
  70. REPORTER_ASSERT(reporter, !cache->get(key4, &foundOffset));
  71. }
  72. // Test purging when the max cache size is exceeded
  73. static void test_internal_purge(skiatest::Reporter* reporter, const sk_sp<SkSpecialImage>& image) {
  74. SkASSERT(image->getSize());
  75. const size_t kCacheSize = image->getSize() + 10;
  76. sk_sp<SkImageFilterCache> cache(SkImageFilterCache::Create(kCacheSize));
  77. SkIRect clip = SkIRect::MakeWH(100, 100);
  78. SkImageFilterCacheKey key1(0, SkMatrix::I(), clip, image->uniqueID(), image->subset());
  79. SkImageFilterCacheKey key2(1, SkMatrix::I(), clip, image->uniqueID(), image->subset());
  80. SkIPoint offset = SkIPoint::Make(3, 4);
  81. auto filter1 = make_filter();
  82. cache->set(key1, image.get(), offset, filter1.get());
  83. SkIPoint foundOffset;
  84. REPORTER_ASSERT(reporter, cache->get(key1, &foundOffset));
  85. // This should knock the first one out of the cache
  86. auto filter2 = make_filter();
  87. cache->set(key2, image.get(), offset, filter2.get());
  88. REPORTER_ASSERT(reporter, cache->get(key2, &foundOffset));
  89. REPORTER_ASSERT(reporter, !cache->get(key1, &foundOffset));
  90. }
  91. // Exercise the purgeByKey and purge methods
  92. static void test_explicit_purging(skiatest::Reporter* reporter,
  93. const sk_sp<SkSpecialImage>& image,
  94. const sk_sp<SkSpecialImage>& subset) {
  95. static const size_t kCacheSize = 1000000;
  96. sk_sp<SkImageFilterCache> cache(SkImageFilterCache::Create(kCacheSize));
  97. SkIRect clip = SkIRect::MakeWH(100, 100);
  98. SkImageFilterCacheKey key1(0, SkMatrix::I(), clip, image->uniqueID(), image->subset());
  99. SkImageFilterCacheKey key2(1, SkMatrix::I(), clip, subset->uniqueID(), image->subset());
  100. SkIPoint offset = SkIPoint::Make(3, 4);
  101. auto filter1 = make_filter();
  102. auto filter2 = make_filter();
  103. cache->set(key1, image.get(), offset, filter1.get());
  104. cache->set(key2, image.get(), offset, filter2.get());
  105. SkDEBUGCODE(REPORTER_ASSERT(reporter, 2 == cache->count());)
  106. SkIPoint foundOffset;
  107. REPORTER_ASSERT(reporter, cache->get(key1, &foundOffset));
  108. REPORTER_ASSERT(reporter, cache->get(key2, &foundOffset));
  109. cache->purgeByImageFilter(filter1.get());
  110. SkDEBUGCODE(REPORTER_ASSERT(reporter, 1 == cache->count());)
  111. REPORTER_ASSERT(reporter, !cache->get(key1, &foundOffset));
  112. REPORTER_ASSERT(reporter, cache->get(key2, &foundOffset));
  113. cache->purge();
  114. SkDEBUGCODE(REPORTER_ASSERT(reporter, 0 == cache->count());)
  115. REPORTER_ASSERT(reporter, !cache->get(key1, &foundOffset));
  116. REPORTER_ASSERT(reporter, !cache->get(key2, &foundOffset));
  117. }
  118. DEF_TEST(ImageFilterCache_RasterBacked, reporter) {
  119. SkBitmap srcBM = create_bm();
  120. const SkIRect& full = SkIRect::MakeWH(kFullSize, kFullSize);
  121. sk_sp<SkSpecialImage> fullImg(SkSpecialImage::MakeFromRaster(full, srcBM));
  122. const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize);
  123. sk_sp<SkSpecialImage> subsetImg(SkSpecialImage::MakeFromRaster(subset, srcBM));
  124. test_find_existing(reporter, fullImg, subsetImg);
  125. test_dont_find_if_diff_key(reporter, fullImg, subsetImg);
  126. test_internal_purge(reporter, fullImg);
  127. test_explicit_purging(reporter, fullImg, subsetImg);
  128. }
  129. // Shared test code for both the raster and gpu-backed image cases
  130. static void test_image_backed(skiatest::Reporter* reporter,
  131. GrContext* context,
  132. const sk_sp<SkImage>& srcImage) {
  133. const SkIRect& full = SkIRect::MakeWH(kFullSize, kFullSize);
  134. sk_sp<SkSpecialImage> fullImg(SkSpecialImage::MakeFromImage(context, full, srcImage));
  135. const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize);
  136. sk_sp<SkSpecialImage> subsetImg(SkSpecialImage::MakeFromImage(context, subset, srcImage));
  137. test_find_existing(reporter, fullImg, subsetImg);
  138. test_dont_find_if_diff_key(reporter, fullImg, subsetImg);
  139. test_internal_purge(reporter, fullImg);
  140. test_explicit_purging(reporter, fullImg, subsetImg);
  141. }
  142. DEF_TEST(ImageFilterCache_ImageBackedRaster, reporter) {
  143. SkBitmap srcBM = create_bm();
  144. sk_sp<SkImage> srcImage(SkImage::MakeFromBitmap(srcBM));
  145. test_image_backed(reporter, nullptr, srcImage);
  146. }
  147. #include "include/gpu/GrContext.h"
  148. #include "include/gpu/GrTexture.h"
  149. #include "src/gpu/GrContextPriv.h"
  150. #include "src/gpu/GrProxyProvider.h"
  151. #include "src/gpu/GrResourceProvider.h"
  152. #include "src/gpu/GrSurfaceProxyPriv.h"
  153. #include "src/gpu/GrTextureProxy.h"
  154. static sk_sp<GrTextureProxy> create_proxy(GrProxyProvider* proxyProvider) {
  155. SkBitmap srcBM = create_bm();
  156. sk_sp<SkImage> srcImage(SkImage::MakeFromBitmap(srcBM));
  157. return proxyProvider->createTextureProxy(srcImage, GrRenderable::kNo, 1, SkBudgeted::kYes,
  158. SkBackingFit::kExact);
  159. }
  160. DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterCache_ImageBackedGPU, reporter, ctxInfo) {
  161. GrContext* context = ctxInfo.grContext();
  162. sk_sp<GrTextureProxy> srcProxy(create_proxy(context->priv().proxyProvider()));
  163. if (!srcProxy) {
  164. return;
  165. }
  166. if (!srcProxy->instantiate(context->priv().resourceProvider())) {
  167. return;
  168. }
  169. GrTexture* tex = srcProxy->peekTexture();
  170. GrBackendTexture backendTex = tex->getBackendTexture();
  171. GrSurfaceOrigin texOrigin = kTopLeft_GrSurfaceOrigin;
  172. sk_sp<SkImage> srcImage(SkImage::MakeFromTexture(context,
  173. backendTex,
  174. texOrigin,
  175. kRGBA_8888_SkColorType,
  176. kPremul_SkAlphaType, nullptr,
  177. nullptr, nullptr));
  178. if (!srcImage) {
  179. return;
  180. }
  181. GrSurfaceOrigin readBackOrigin;
  182. GrBackendTexture readBackBackendTex = srcImage->getBackendTexture(false, &readBackOrigin);
  183. if (!GrBackendTexture::TestingOnly_Equals(readBackBackendTex, backendTex)) {
  184. ERRORF(reporter, "backend mismatch\n");
  185. }
  186. REPORTER_ASSERT(reporter, GrBackendTexture::TestingOnly_Equals(readBackBackendTex, backendTex));
  187. if (readBackOrigin != texOrigin) {
  188. ERRORF(reporter, "origin mismatch %d %d\n", readBackOrigin, texOrigin);
  189. }
  190. REPORTER_ASSERT(reporter, readBackOrigin == texOrigin);
  191. test_image_backed(reporter, context, srcImage);
  192. }
  193. DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterCache_GPUBacked, reporter, ctxInfo) {
  194. GrContext* context = ctxInfo.grContext();
  195. sk_sp<GrTextureProxy> srcProxy(create_proxy(context->priv().proxyProvider()));
  196. if (!srcProxy) {
  197. return;
  198. }
  199. const SkIRect& full = SkIRect::MakeWH(kFullSize, kFullSize);
  200. sk_sp<SkSpecialImage> fullImg(SkSpecialImage::MakeDeferredFromGpu(
  201. context, full,
  202. kNeedNewImageUniqueID_SpecialImage,
  203. srcProxy, nullptr));
  204. const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize);
  205. sk_sp<SkSpecialImage> subsetImg(SkSpecialImage::MakeDeferredFromGpu(
  206. context, subset,
  207. kNeedNewImageUniqueID_SpecialImage,
  208. srcProxy, nullptr));
  209. test_find_existing(reporter, fullImg, subsetImg);
  210. test_dont_find_if_diff_key(reporter, fullImg, subsetImg);
  211. test_internal_purge(reporter, fullImg);
  212. test_explicit_purging(reporter, fullImg, subsetImg);
  213. }