Home | History | Annotate | Download | only in tests
      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 "SkImageFilterCache.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                                const sk_sp<SkSpecialImage>& image,
     31                                const sk_sp<SkSpecialImage>& subset) {
     32     static const size_t kCacheSize = 1000000;
     33     sk_sp<SkImageFilterCache> cache(SkImageFilterCache::Create(kCacheSize));
     34 
     35     SkIRect clip = SkIRect::MakeWH(100, 100);
     36     SkImageFilterCacheKey key1(0, SkMatrix::I(), clip, image->uniqueID(), image->subset());
     37     SkImageFilterCacheKey key2(0, SkMatrix::I(), clip, subset->uniqueID(), subset->subset());
     38 
     39     SkIPoint offset = SkIPoint::Make(3, 4);
     40     cache->set(key1, image.get(), offset, nullptr);
     41 
     42     SkIPoint foundOffset;
     43 
     44     sk_sp<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                                        const sk_sp<SkSpecialImage>& image,
     55                                        const sk_sp<SkSpecialImage>& subset) {
     56     static const size_t kCacheSize = 1000000;
     57     sk_sp<SkImageFilterCache> cache(SkImageFilterCache::Create(kCacheSize));
     58 
     59     SkIRect clip1 = SkIRect::MakeWH(100, 100);
     60     SkIRect clip2 = SkIRect::MakeWH(200, 200);
     61     SkImageFilterCacheKey key0(0, SkMatrix::I(), clip1, image->uniqueID(), image->subset());
     62     SkImageFilterCacheKey key1(1, SkMatrix::I(), clip1, image->uniqueID(), image->subset());
     63     SkImageFilterCacheKey key2(0, SkMatrix::MakeTrans(5, 5), clip1,
     64                                    image->uniqueID(), image->subset());
     65     SkImageFilterCacheKey key3(0, SkMatrix::I(), clip2, image->uniqueID(), image->subset());
     66     SkImageFilterCacheKey key4(0, SkMatrix::I(), clip1, subset->uniqueID(), subset->subset());
     67 
     68     SkIPoint offset = SkIPoint::Make(3, 4);
     69     cache->set(key0, image.get(), offset, nullptr);
     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, const sk_sp<SkSpecialImage>& image) {
     80     SkASSERT(image->getSize());
     81     const size_t kCacheSize = image->getSize() + 10;
     82     sk_sp<SkImageFilterCache> cache(SkImageFilterCache::Create(kCacheSize));
     83 
     84     SkIRect clip = SkIRect::MakeWH(100, 100);
     85     SkImageFilterCacheKey key1(0, SkMatrix::I(), clip, image->uniqueID(), image->subset());
     86     SkImageFilterCacheKey key2(1, SkMatrix::I(), clip, image->uniqueID(), image->subset());
     87 
     88     SkIPoint offset = SkIPoint::Make(3, 4);
     89     cache->set(key1, image.get(), offset, nullptr);
     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.get(), offset, nullptr);
     97 
     98     REPORTER_ASSERT(reporter, cache->get(key2, &foundOffset));
     99     REPORTER_ASSERT(reporter, !cache->get(key1, &foundOffset));
    100 }
    101 
    102 // Exercise the purgeByKey and purge methods
    103 static void test_explicit_purging(skiatest::Reporter* reporter,
    104                                   const sk_sp<SkSpecialImage>& image,
    105                                   const sk_sp<SkSpecialImage>& subset) {
    106     static const size_t kCacheSize = 1000000;
    107     sk_sp<SkImageFilterCache> cache(SkImageFilterCache::Create(kCacheSize));
    108 
    109     SkIRect clip = SkIRect::MakeWH(100, 100);
    110     SkImageFilterCacheKey key1(0, SkMatrix::I(), clip, image->uniqueID(), image->subset());
    111     SkImageFilterCacheKey key2(1, SkMatrix::I(), clip, subset->uniqueID(), image->subset());
    112 
    113     SkIPoint offset = SkIPoint::Make(3, 4);
    114     cache->set(key1, image.get(), offset, nullptr);
    115     cache->set(key2, image.get(), offset, nullptr);
    116     SkDEBUGCODE(REPORTER_ASSERT(reporter, 2 == cache->count());)
    117 
    118     SkIPoint foundOffset;
    119 
    120     REPORTER_ASSERT(reporter, cache->get(key1, &foundOffset));
    121     REPORTER_ASSERT(reporter, cache->get(key2, &foundOffset));
    122 
    123     cache->purgeByKeys(&key1, 1);
    124     SkDEBUGCODE(REPORTER_ASSERT(reporter, 1 == cache->count());)
    125 
    126     REPORTER_ASSERT(reporter, !cache->get(key1, &foundOffset));
    127     REPORTER_ASSERT(reporter, cache->get(key2, &foundOffset));
    128 
    129     cache->purge();
    130     SkDEBUGCODE(REPORTER_ASSERT(reporter, 0 == cache->count());)
    131 
    132     REPORTER_ASSERT(reporter, !cache->get(key1, &foundOffset));
    133     REPORTER_ASSERT(reporter, !cache->get(key2, &foundOffset));
    134 }
    135 
    136 DEF_TEST(ImageFilterCache_RasterBacked, reporter) {
    137     SkBitmap srcBM = create_bm();
    138 
    139     const SkIRect& full = SkIRect::MakeWH(kFullSize, kFullSize);
    140 
    141     sk_sp<SkSpecialImage> fullImg(SkSpecialImage::MakeFromRaster(full, srcBM));
    142 
    143     const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize);
    144 
    145     sk_sp<SkSpecialImage> subsetImg(SkSpecialImage::MakeFromRaster(subset, srcBM));
    146 
    147     test_find_existing(reporter, fullImg, subsetImg);
    148     test_dont_find_if_diff_key(reporter, fullImg, subsetImg);
    149     test_internal_purge(reporter, fullImg);
    150     test_explicit_purging(reporter, fullImg, subsetImg);
    151 }
    152 
    153 
    154 // Shared test code for both the raster and gpu-backed image cases
    155 static void test_image_backed(skiatest::Reporter* reporter, const sk_sp<SkImage>& srcImage) {
    156     const SkIRect& full = SkIRect::MakeWH(kFullSize, kFullSize);
    157     SkColorSpace* legacyColorSpace = nullptr;
    158 
    159     sk_sp<SkSpecialImage> fullImg(SkSpecialImage::MakeFromImage(full, srcImage, legacyColorSpace));
    160 
    161     const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize);
    162 
    163     sk_sp<SkSpecialImage> subsetImg(SkSpecialImage::MakeFromImage(subset, srcImage,
    164                                                                   legacyColorSpace));
    165 
    166     test_find_existing(reporter, fullImg, subsetImg);
    167     test_dont_find_if_diff_key(reporter, fullImg, subsetImg);
    168     test_internal_purge(reporter, fullImg);
    169     test_explicit_purging(reporter, fullImg, subsetImg);
    170 }
    171 
    172 DEF_TEST(ImageFilterCache_ImageBackedRaster, reporter) {
    173     SkBitmap srcBM = create_bm();
    174 
    175     sk_sp<SkImage> srcImage(SkImage::MakeFromBitmap(srcBM));
    176 
    177     test_image_backed(reporter, srcImage);
    178 }
    179 
    180 #if SK_SUPPORT_GPU
    181 #include "GrContext.h"
    182 #include "GrContextPriv.h"
    183 #include "GrResourceProvider.h"
    184 #include "GrSurfaceProxyPriv.h"
    185 #include "GrTest.h"
    186 #include "GrTexture.h"
    187 #include "GrTextureProxy.h"
    188 
    189 static sk_sp<GrTextureProxy> create_proxy(GrResourceProvider* resourceProvider) {
    190     SkBitmap srcBM = create_bm();
    191 
    192     GrSurfaceDesc desc;
    193     desc.fConfig = kRGBA_8888_GrPixelConfig;
    194     desc.fFlags  = kNone_GrSurfaceFlags;
    195     desc.fWidth  = kFullSize;
    196     desc.fHeight = kFullSize;
    197 
    198     return GrSurfaceProxy::MakeDeferred(resourceProvider,
    199                                         desc, SkBudgeted::kYes,
    200                                         srcBM.getPixels(),
    201                                         srcBM.rowBytes());
    202 }
    203 
    204 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterCache_ImageBackedGPU, reporter, ctxInfo) {
    205     GrContext* context = ctxInfo.grContext();
    206 
    207     sk_sp<GrTextureProxy> srcProxy(create_proxy(context->resourceProvider()));
    208     if (!srcProxy) {
    209         return;
    210     }
    211 
    212     if (!srcProxy->instantiate(context->resourceProvider())) {
    213         return;
    214     }
    215     GrTexture* tex = srcProxy->priv().peekTexture();
    216 
    217     GrBackendTexture backendTex = GrTest::CreateBackendTexture(context->contextPriv().getBackend(),
    218                                                                kFullSize,
    219                                                                kFullSize,
    220                                                                kRGBA_8888_GrPixelConfig,
    221                                                                tex->getTextureHandle());
    222     GrSurfaceOrigin texOrigin = kTopLeft_GrSurfaceOrigin;
    223     sk_sp<SkImage> srcImage(SkImage::MakeFromTexture(context,
    224                                                      backendTex,
    225                                                      texOrigin,
    226                                                      kPremul_SkAlphaType, nullptr));
    227     if (!srcImage) {
    228         return;
    229     }
    230 
    231     GrSurfaceOrigin readBackOrigin;
    232     GrBackendObject readBackHandle = srcImage->getTextureHandle(false, &readBackOrigin);
    233     // TODO: Make it so we can check this (see skbug.com/5019)
    234 #if 0
    235     if (readBackHandle != tex->getTextureHandle()) {
    236         ERRORF(reporter, "backend mismatch %d %d\n",
    237                        (int)readBackHandle, (int)tex->getTextureHandle());
    238     }
    239     REPORTER_ASSERT(reporter, readBackHandle == tex->getTextureHandle());
    240 #else
    241     REPORTER_ASSERT(reporter, SkToBool(readBackHandle));
    242 #endif
    243     if (readBackOrigin != texOrigin) {
    244         ERRORF(reporter, "origin mismatch %d %d\n", readBackOrigin, texOrigin);
    245     }
    246     REPORTER_ASSERT(reporter, readBackOrigin == texOrigin);
    247 
    248     test_image_backed(reporter, srcImage);
    249 }
    250 
    251 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ImageFilterCache_GPUBacked, reporter, ctxInfo) {
    252     GrContext* context = ctxInfo.grContext();
    253 
    254     sk_sp<GrTextureProxy> srcProxy(create_proxy(context->resourceProvider()));
    255     if (!srcProxy) {
    256         return;
    257     }
    258 
    259     const SkIRect& full = SkIRect::MakeWH(kFullSize, kFullSize);
    260 
    261     sk_sp<SkSpecialImage> fullImg(SkSpecialImage::MakeDeferredFromGpu(
    262                                                               context, full,
    263                                                               kNeedNewImageUniqueID_SpecialImage,
    264                                                               srcProxy, nullptr));
    265 
    266     const SkIRect& subset = SkIRect::MakeXYWH(kPad, kPad, kSmallerSize, kSmallerSize);
    267 
    268     sk_sp<SkSpecialImage> subsetImg(SkSpecialImage::MakeDeferredFromGpu(
    269                                                                 context, subset,
    270                                                                 kNeedNewImageUniqueID_SpecialImage,
    271                                                                 srcProxy, nullptr));
    272 
    273     test_find_existing(reporter, fullImg, subsetImg);
    274     test_dont_find_if_diff_key(reporter, fullImg, subsetImg);
    275     test_internal_purge(reporter, fullImg);
    276     test_explicit_purging(reporter, fullImg, subsetImg);
    277 }
    278 #endif
    279