Home | History | Annotate | Download | only in tests
      1 /*
      2  * Copyright 2013 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 here to ensure SK_SUPPORT_GPU is set correctly before it is examined.
      9 #include "SkTypes.h"
     10 
     11 #if SK_SUPPORT_GPU
     12 
     13 #include "GrContext.h"
     14 #include "GrContextFactory.h"
     15 #include "GrGpu.h"
     16 #include "GrGpuResourceCacheAccess.h"
     17 #include "GrGpuResourcePriv.h"
     18 #include "GrRenderTarget.h"
     19 #include "GrRenderTargetPriv.h"
     20 #include "GrResourceCache.h"
     21 #include "GrResourceProvider.h"
     22 #include "GrTest.h"
     23 #include "SkCanvas.h"
     24 #include "SkGr.h"
     25 #include "SkMessageBus.h"
     26 #include "SkSurface.h"
     27 #include "Test.h"
     28 
     29 static const int gWidth = 640;
     30 static const int gHeight = 480;
     31 
     32 ////////////////////////////////////////////////////////////////////////////////
     33 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ResourceCacheCache, reporter, context) {
     34     GrSurfaceDesc desc;
     35     desc.fConfig = kSkia8888_GrPixelConfig;
     36     desc.fFlags = kRenderTarget_GrSurfaceFlag;
     37     desc.fWidth = gWidth;
     38     desc.fHeight = gHeight;
     39     SkImageInfo info = SkImageInfo::MakeN32Premul(gWidth, gHeight);
     40     SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTarget(context,
     41                                                                SkBudgeted::kNo, info));
     42     SkCanvas* canvas = surface->getCanvas();
     43 
     44     const SkIRect size = SkIRect::MakeWH(gWidth, gHeight);
     45 
     46     SkBitmap src;
     47     src.allocN32Pixels(size.width(), size.height());
     48     src.eraseColor(SK_ColorBLACK);
     49     size_t srcSize = src.getSize();
     50 
     51     size_t initialCacheSize;
     52     context->getResourceCacheUsage(nullptr, &initialCacheSize);
     53 
     54     int oldMaxNum;
     55     size_t oldMaxBytes;
     56     context->getResourceCacheLimits(&oldMaxNum, &oldMaxBytes);
     57 
     58     // Set the cache limits so we can fit 10 "src" images and the
     59     // max number of textures doesn't matter
     60     size_t maxCacheSize = initialCacheSize + 10*srcSize;
     61     context->setResourceCacheLimits(1000, maxCacheSize);
     62 
     63     SkBitmap readback;
     64     readback.allocN32Pixels(size.width(), size.height());
     65 
     66     for (int i = 0; i < 100; ++i) {
     67         canvas->drawBitmap(src, 0, 0);
     68         canvas->readPixels(size, &readback);
     69 
     70         // "modify" the src texture
     71         src.notifyPixelsChanged();
     72 
     73         size_t curCacheSize;
     74         context->getResourceCacheUsage(nullptr, &curCacheSize);
     75 
     76         // we should never go over the size limit
     77         REPORTER_ASSERT(reporter, curCacheSize <= maxCacheSize);
     78     }
     79 
     80     context->setResourceCacheLimits(oldMaxNum, oldMaxBytes);
     81 }
     82 
     83 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ResourceCacheStencilBuffers, reporter, context) {
     84     GrSurfaceDesc smallDesc;
     85     smallDesc.fFlags = kRenderTarget_GrSurfaceFlag;
     86     smallDesc.fConfig = kSkia8888_GrPixelConfig;
     87     smallDesc.fWidth = 4;
     88     smallDesc.fHeight = 4;
     89     smallDesc.fSampleCnt = 0;
     90 
     91     GrTextureProvider* cache = context->textureProvider();
     92     GrResourceProvider* resourceProvider = context->resourceProvider();
     93     // Test that two budgeted RTs with the same desc share a stencil buffer.
     94     SkAutoTUnref<GrTexture> smallRT0(cache->createTexture(smallDesc, SkBudgeted::kYes));
     95     if (smallRT0 && smallRT0->asRenderTarget()) {
     96         resourceProvider->attachStencilAttachment(smallRT0->asRenderTarget());
     97     }
     98 
     99     SkAutoTUnref<GrTexture> smallRT1(cache->createTexture(smallDesc, SkBudgeted::kYes));
    100     if (smallRT1 && smallRT1->asRenderTarget()) {
    101         resourceProvider->attachStencilAttachment(smallRT1->asRenderTarget());
    102     }
    103 
    104     REPORTER_ASSERT(reporter,
    105                     smallRT0 && smallRT1 &&
    106                     smallRT0->asRenderTarget() && smallRT1->asRenderTarget() &&
    107                     resourceProvider->attachStencilAttachment(smallRT0->asRenderTarget()) ==
    108                     resourceProvider->attachStencilAttachment(smallRT1->asRenderTarget()));
    109 
    110     // An unbudgeted RT with the same desc should also share.
    111     SkAutoTUnref<GrTexture> smallRT2(cache->createTexture(smallDesc, SkBudgeted::kNo));
    112     if (smallRT2 && smallRT2->asRenderTarget()) {
    113         resourceProvider->attachStencilAttachment(smallRT2->asRenderTarget());
    114     }
    115     REPORTER_ASSERT(reporter,
    116                     smallRT0 && smallRT2 &&
    117                     smallRT0->asRenderTarget() && smallRT2->asRenderTarget() &&
    118                     resourceProvider->attachStencilAttachment(smallRT0->asRenderTarget()) ==
    119                     resourceProvider->attachStencilAttachment(smallRT2->asRenderTarget()));
    120 
    121     // An RT with a much larger size should not share.
    122     GrSurfaceDesc bigDesc;
    123     bigDesc.fFlags = kRenderTarget_GrSurfaceFlag;
    124     bigDesc.fConfig = kSkia8888_GrPixelConfig;
    125     bigDesc.fWidth = 400;
    126     bigDesc.fHeight = 200;
    127     bigDesc.fSampleCnt = 0;
    128     SkAutoTUnref<GrTexture> bigRT(cache->createTexture(bigDesc, SkBudgeted::kNo));
    129     if (bigRT && bigRT->asRenderTarget()) {
    130         resourceProvider->attachStencilAttachment(bigRT->asRenderTarget());
    131     }
    132     REPORTER_ASSERT(reporter,
    133                     smallRT0 && bigRT &&
    134                     smallRT0->asRenderTarget() && bigRT->asRenderTarget() &&
    135                     resourceProvider->attachStencilAttachment(smallRT0->asRenderTarget()) !=
    136                     resourceProvider->attachStencilAttachment(bigRT->asRenderTarget()));
    137 
    138     if (context->caps()->maxSampleCount() >= 4) {
    139         // An RT with a different sample count should not share.
    140         GrSurfaceDesc smallMSAADesc = smallDesc;
    141         smallMSAADesc.fSampleCnt = 4;
    142         SkAutoTUnref<GrTexture> smallMSAART0(cache->createTexture(smallMSAADesc, SkBudgeted::kNo));
    143         if (smallMSAART0 && smallMSAART0->asRenderTarget()) {
    144             resourceProvider->attachStencilAttachment(smallMSAART0->asRenderTarget());
    145         }
    146 #ifdef SK_BUILD_FOR_ANDROID
    147         if (!smallMSAART0) {
    148             // The nexus player seems to fail to create MSAA textures.
    149             return;
    150         }
    151 #endif
    152         REPORTER_ASSERT(reporter,
    153                         smallRT0 && smallMSAART0 &&
    154                         smallRT0->asRenderTarget() && smallMSAART0->asRenderTarget() &&
    155                         resourceProvider->attachStencilAttachment(smallRT0->asRenderTarget()) !=
    156                         resourceProvider->attachStencilAttachment(smallMSAART0->asRenderTarget()));
    157         // A second MSAA RT should share with the first MSAA RT.
    158         SkAutoTUnref<GrTexture> smallMSAART1(cache->createTexture(smallMSAADesc, SkBudgeted::kNo));
    159         if (smallMSAART1 && smallMSAART1->asRenderTarget()) {
    160             resourceProvider->attachStencilAttachment(smallMSAART1->asRenderTarget());
    161         }
    162         REPORTER_ASSERT(reporter,
    163                         smallMSAART0 && smallMSAART1 &&
    164                         smallMSAART0->asRenderTarget() &&
    165                         smallMSAART1->asRenderTarget() &&
    166                         resourceProvider->attachStencilAttachment(smallMSAART0->asRenderTarget()) ==
    167                         resourceProvider->attachStencilAttachment(smallMSAART1->asRenderTarget()));
    168         // But not one with a larger sample count should not. (Also check that the request for 4
    169         // samples didn't get rounded up to >= 8 or else they could share.).
    170         if (context->caps()->maxSampleCount() >= 8 &&
    171             smallMSAART0 && smallMSAART0->asRenderTarget() &&
    172             smallMSAART0->asRenderTarget()->numColorSamples() < 8) {
    173             smallMSAADesc.fSampleCnt = 8;
    174             smallMSAART1.reset(cache->createTexture(smallMSAADesc, SkBudgeted::kNo));
    175             SkAutoTUnref<GrTexture> smallMSAART1(
    176                     cache->createTexture(smallMSAADesc, SkBudgeted::kNo));
    177             if (smallMSAART1 && smallMSAART1->asRenderTarget()) {
    178                 resourceProvider->attachStencilAttachment(smallMSAART1->asRenderTarget());
    179             }
    180             REPORTER_ASSERT(reporter,
    181                         smallMSAART0 && smallMSAART1 &&
    182                         smallMSAART0->asRenderTarget() &&
    183                         smallMSAART1->asRenderTarget() &&
    184                         resourceProvider->attachStencilAttachment(smallMSAART0->asRenderTarget()) !=
    185                         resourceProvider->attachStencilAttachment(smallMSAART1->asRenderTarget()));
    186         }
    187     }
    188 }
    189 
    190 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ResourceCacheWrappedResources, reporter, context) {
    191     GrGpu* gpu = context->getGpu();
    192     // this test is only valid for GL
    193     if (!gpu || !gpu->glContextForTesting()) {
    194         return;
    195     }
    196 
    197     GrBackendObject texHandles[2];
    198     static const int kW = 100;
    199     static const int kH = 100;
    200 
    201     texHandles[0] = gpu->createTestingOnlyBackendTexture(nullptr, kW, kH, kRGBA_8888_GrPixelConfig);
    202     texHandles[1] = gpu->createTestingOnlyBackendTexture(nullptr, kW, kH, kRGBA_8888_GrPixelConfig);
    203 
    204     context->resetContext();
    205 
    206     GrBackendTextureDesc desc;
    207     desc.fConfig = kBGRA_8888_GrPixelConfig;
    208     desc.fWidth = kW;
    209     desc.fHeight = kH;
    210 
    211     desc.fTextureHandle = texHandles[0];
    212     SkAutoTUnref<GrTexture> borrowed(context->textureProvider()->wrapBackendTexture(
    213                                      desc, kBorrow_GrWrapOwnership));
    214 
    215     desc.fTextureHandle = texHandles[1];
    216     SkAutoTUnref<GrTexture> adopted(context->textureProvider()->wrapBackendTexture(
    217                                     desc, kAdopt_GrWrapOwnership));
    218 
    219     REPORTER_ASSERT(reporter, SkToBool(borrowed) && SkToBool(adopted));
    220     if (!SkToBool(borrowed) || !SkToBool(adopted)) {
    221         return;
    222     }
    223 
    224     borrowed.reset(nullptr);
    225     adopted.reset(nullptr);
    226 
    227     context->flush();
    228 
    229     bool borrowedIsAlive = gpu->isTestingOnlyBackendTexture(texHandles[0]);
    230     bool adoptedIsAlive = gpu->isTestingOnlyBackendTexture(texHandles[1]);
    231 
    232     REPORTER_ASSERT(reporter, borrowedIsAlive);
    233     REPORTER_ASSERT(reporter, !adoptedIsAlive);
    234 
    235     gpu->deleteTestingOnlyBackendTexture(texHandles[0], !borrowedIsAlive);
    236     gpu->deleteTestingOnlyBackendTexture(texHandles[1], !adoptedIsAlive);
    237 
    238     context->resetContext();
    239 }
    240 
    241 class TestResource : public GrGpuResource {
    242     enum ScratchConstructor { kScratchConstructor };
    243 public:
    244     static const size_t kDefaultSize = 100;
    245 
    246     /** Property that distinctly categorizes the resource.
    247      * For example, textures have width, height, ... */
    248     enum SimulatedProperty { kA_SimulatedProperty, kB_SimulatedProperty };
    249 
    250     TestResource(GrGpu* gpu, size_t size, GrGpuResource::LifeCycle lifeCycle)
    251         : INHERITED(gpu, lifeCycle)
    252         , fToDelete(nullptr)
    253         , fSize(size)
    254         , fProperty(kA_SimulatedProperty) {
    255         ++fNumAlive;
    256         this->registerWithCache();
    257     }
    258 
    259     TestResource(GrGpu* gpu, GrGpuResource::LifeCycle lifeCycle)
    260         : INHERITED(gpu, lifeCycle)
    261         , fToDelete(nullptr)
    262         , fSize(kDefaultSize)
    263         , fProperty(kA_SimulatedProperty) {
    264         ++fNumAlive;
    265         this->registerWithCache();
    266     }
    267 
    268     TestResource(GrGpu* gpu)
    269         : INHERITED(gpu, kCached_LifeCycle)
    270         , fToDelete(nullptr)
    271         , fSize(kDefaultSize)
    272         , fProperty(kA_SimulatedProperty) {
    273         ++fNumAlive;
    274         this->registerWithCache();
    275     }
    276 
    277     static TestResource* CreateScratch(GrGpu* gpu, SimulatedProperty property, bool cached = true) {
    278         return new TestResource(gpu, property, cached, kScratchConstructor);
    279     }
    280 
    281     ~TestResource() {
    282         --fNumAlive;
    283         SkSafeUnref(fToDelete);
    284     }
    285 
    286     void setSize(size_t size) {
    287         fSize = size;
    288         this->didChangeGpuMemorySize();
    289     }
    290 
    291     static int NumAlive() { return fNumAlive; }
    292 
    293     void setUnrefWhenDestroyed(TestResource* resource) {
    294         SkRefCnt_SafeAssign(fToDelete, resource);
    295     }
    296 
    297     static void ComputeScratchKey(SimulatedProperty property, GrScratchKey* key) {
    298         static GrScratchKey::ResourceType t = GrScratchKey::GenerateResourceType();
    299         GrScratchKey::Builder builder(key, t, kScratchKeyFieldCnt);
    300         for (int i = 0; i < kScratchKeyFieldCnt; ++i) {
    301             builder[i] = static_cast<uint32_t>(i + property);
    302         }
    303     }
    304 
    305     static size_t ExpectedScratchKeySize() {
    306         return sizeof(uint32_t) * (kScratchKeyFieldCnt + GrScratchKey::kMetaDataCnt);
    307     }
    308 
    309 private:
    310     static const int kScratchKeyFieldCnt = 6;
    311 
    312     TestResource(GrGpu* gpu, SimulatedProperty property, bool cached, ScratchConstructor)
    313         : INHERITED(gpu, cached ? kCached_LifeCycle : kUncached_LifeCycle)
    314         , fToDelete(nullptr)
    315         , fSize(kDefaultSize)
    316         , fProperty(property) {
    317         GrScratchKey scratchKey;
    318         ComputeScratchKey(fProperty, &scratchKey);
    319         this->setScratchKey(scratchKey);
    320         ++fNumAlive;
    321         this->registerWithCache();
    322     }
    323 
    324     size_t onGpuMemorySize() const override { return fSize; }
    325 
    326     TestResource* fToDelete;
    327     size_t fSize;
    328     static int fNumAlive;
    329     SimulatedProperty fProperty;
    330     typedef GrGpuResource INHERITED;
    331 };
    332 int TestResource::fNumAlive = 0;
    333 
    334 class Mock {
    335 public:
    336     Mock(int maxCnt, size_t maxBytes) {
    337         fContext.reset(GrContext::CreateMockContext());
    338         SkASSERT(fContext);
    339         fContext->setResourceCacheLimits(maxCnt, maxBytes);
    340         GrResourceCache* cache = fContext->getResourceCache();
    341         cache->purgeAllUnlocked();
    342         SkASSERT(0 == cache->getResourceCount() && 0 == cache->getResourceBytes());
    343     }
    344 
    345     GrResourceCache* cache() { return fContext->getResourceCache(); }
    346 
    347     GrContext* context() { return fContext; }
    348 
    349 private:
    350     SkAutoTUnref<GrContext> fContext;
    351 };
    352 
    353 static void test_no_key(skiatest::Reporter* reporter) {
    354     Mock mock(10, 30000);
    355     GrContext* context = mock.context();
    356     GrResourceCache* cache = mock.cache();
    357 
    358     // Create a bunch of resources with no keys
    359     TestResource* a = new TestResource(context->getGpu());
    360     TestResource* b = new TestResource(context->getGpu());
    361     TestResource* c = new TestResource(context->getGpu());
    362     TestResource* d = new TestResource(context->getGpu());
    363     a->setSize(11);
    364     b->setSize(12);
    365     c->setSize(13);
    366     d->setSize(14);
    367 
    368     REPORTER_ASSERT(reporter, 4 == TestResource::NumAlive());
    369     REPORTER_ASSERT(reporter, 4 == cache->getResourceCount());
    370     REPORTER_ASSERT(reporter, a->gpuMemorySize() + b->gpuMemorySize() + c->gpuMemorySize() +
    371                               d->gpuMemorySize() == cache->getResourceBytes());
    372 
    373     // Should be safe to purge without deleting the resources since we still have refs.
    374     cache->purgeAllUnlocked();
    375     REPORTER_ASSERT(reporter, 4 == TestResource::NumAlive());
    376 
    377     // Since the resources have neither unique nor scratch keys, delete immediately upon unref.
    378 
    379     a->unref();
    380     REPORTER_ASSERT(reporter, 3 == TestResource::NumAlive());
    381     REPORTER_ASSERT(reporter, 3 == cache->getResourceCount());
    382     REPORTER_ASSERT(reporter, b->gpuMemorySize() + c->gpuMemorySize() + d->gpuMemorySize() ==
    383                               cache->getResourceBytes());
    384 
    385     c->unref();
    386     REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
    387     REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
    388     REPORTER_ASSERT(reporter, b->gpuMemorySize() + d->gpuMemorySize() ==
    389                               cache->getResourceBytes());
    390 
    391     d->unref();
    392     REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
    393     REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
    394     REPORTER_ASSERT(reporter, b->gpuMemorySize() == cache->getResourceBytes());
    395 
    396     b->unref();
    397     REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
    398     REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
    399     REPORTER_ASSERT(reporter, 0 == cache->getResourceBytes());
    400 }
    401 
    402 // Each integer passed as a template param creates a new domain.
    403 template <int> static void make_unique_key(GrUniqueKey* key, int data) {
    404     static GrUniqueKey::Domain d = GrUniqueKey::GenerateDomain();
    405     GrUniqueKey::Builder builder(key, d, 1);
    406     builder[0] = data;
    407 }
    408 
    409 static void test_budgeting(skiatest::Reporter* reporter) {
    410     Mock mock(10, 300);
    411     GrContext* context = mock.context();
    412     GrResourceCache* cache = mock.cache();
    413 
    414     GrUniqueKey uniqueKey;
    415     make_unique_key<0>(&uniqueKey, 0);
    416 
    417     // Create a scratch, a unique, and a wrapped resource
    418     TestResource* scratch =
    419             TestResource::CreateScratch(context->getGpu(), TestResource::kB_SimulatedProperty);
    420     scratch->setSize(10);
    421     TestResource* unique = new TestResource(context->getGpu());
    422     unique->setSize(11);
    423     unique->resourcePriv().setUniqueKey(uniqueKey);
    424     TestResource* wrapped = new TestResource(context->getGpu(), GrGpuResource::kBorrowed_LifeCycle);
    425     wrapped->setSize(12);
    426     TestResource* unbudgeted =
    427             new TestResource(context->getGpu(), GrGpuResource::kUncached_LifeCycle);
    428     unbudgeted->setSize(13);
    429 
    430     // Make sure we can't add a unique key to the wrapped resource
    431     GrUniqueKey uniqueKey2;
    432     make_unique_key<0>(&uniqueKey2, 1);
    433     wrapped->resourcePriv().setUniqueKey(uniqueKey2);
    434     REPORTER_ASSERT(reporter, nullptr == cache->findAndRefUniqueResource(uniqueKey2));
    435 
    436     // Make sure sizes are as we expect
    437     REPORTER_ASSERT(reporter, 4 == cache->getResourceCount());
    438     REPORTER_ASSERT(reporter, scratch->gpuMemorySize() + unique->gpuMemorySize() +
    439                               wrapped->gpuMemorySize() + unbudgeted->gpuMemorySize() ==
    440                               cache->getResourceBytes());
    441     REPORTER_ASSERT(reporter, 2 == cache->getBudgetedResourceCount());
    442     REPORTER_ASSERT(reporter, scratch->gpuMemorySize() + unique->gpuMemorySize() ==
    443                               cache->getBudgetedResourceBytes());
    444 
    445     // Our refs mean that the resources are non purgeable.
    446     cache->purgeAllUnlocked();
    447     REPORTER_ASSERT(reporter, 4 == cache->getResourceCount());
    448     REPORTER_ASSERT(reporter, scratch->gpuMemorySize() + unique->gpuMemorySize() +
    449                               wrapped->gpuMemorySize() + unbudgeted->gpuMemorySize() ==
    450                               cache->getResourceBytes());
    451     REPORTER_ASSERT(reporter, 2 == cache->getBudgetedResourceCount());
    452     REPORTER_ASSERT(reporter, scratch->gpuMemorySize() + unique->gpuMemorySize() ==
    453                               cache->getBudgetedResourceBytes());
    454 
    455     // Unreffing the wrapped resource should free it right away.
    456     wrapped->unref();
    457     REPORTER_ASSERT(reporter, 3 == cache->getResourceCount());
    458     REPORTER_ASSERT(reporter, scratch->gpuMemorySize() + unique->gpuMemorySize() +
    459                               unbudgeted->gpuMemorySize() == cache->getResourceBytes());
    460 
    461     // Now try freeing the budgeted resources first
    462     wrapped = new TestResource(context->getGpu(), GrGpuResource::kBorrowed_LifeCycle);
    463     scratch->setSize(12);
    464     unique->unref();
    465     cache->purgeAllUnlocked();
    466     REPORTER_ASSERT(reporter, 3 == cache->getResourceCount());
    467     REPORTER_ASSERT(reporter, scratch->gpuMemorySize() + wrapped->gpuMemorySize() +
    468                               unbudgeted->gpuMemorySize() == cache->getResourceBytes());
    469     REPORTER_ASSERT(reporter, 1 == cache->getBudgetedResourceCount());
    470     REPORTER_ASSERT(reporter, scratch->gpuMemorySize() == cache->getBudgetedResourceBytes());
    471 
    472     scratch->unref();
    473     cache->purgeAllUnlocked();
    474     REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
    475     REPORTER_ASSERT(reporter, unbudgeted->gpuMemorySize() + wrapped->gpuMemorySize() ==
    476                               cache->getResourceBytes());
    477     REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount());
    478     REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceBytes());
    479 
    480     wrapped->unref();
    481     REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
    482     REPORTER_ASSERT(reporter, unbudgeted->gpuMemorySize() == cache->getResourceBytes());
    483     REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount());
    484     REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceBytes());
    485 
    486     unbudgeted->unref();
    487     REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
    488     REPORTER_ASSERT(reporter, 0 == cache->getResourceBytes());
    489     REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount());
    490     REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceBytes());
    491 }
    492 
    493 static void test_unbudgeted(skiatest::Reporter* reporter) {
    494     Mock mock(10, 30000);
    495     GrContext* context = mock.context();
    496     GrResourceCache* cache = mock.cache();
    497 
    498     GrUniqueKey uniqueKey;
    499     make_unique_key<0>(&uniqueKey, 0);
    500 
    501     TestResource* scratch;
    502     TestResource* unique;
    503     TestResource* wrapped;
    504     TestResource* unbudgeted;
    505 
    506     // A large uncached or wrapped resource shouldn't evict anything.
    507     scratch = TestResource::CreateScratch(context->getGpu(), TestResource::kB_SimulatedProperty);
    508     scratch->setSize(10);
    509     scratch->unref();
    510     REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
    511     REPORTER_ASSERT(reporter, 10 == cache->getResourceBytes());
    512     REPORTER_ASSERT(reporter, 1 == cache->getBudgetedResourceCount());
    513     REPORTER_ASSERT(reporter, 10 == cache->getBudgetedResourceBytes());
    514 
    515     unique = new TestResource(context->getGpu());
    516     unique->setSize(11);
    517     unique->resourcePriv().setUniqueKey(uniqueKey);
    518     unique->unref();
    519     REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
    520     REPORTER_ASSERT(reporter, 21 == cache->getResourceBytes());
    521     REPORTER_ASSERT(reporter, 2 == cache->getBudgetedResourceCount());
    522     REPORTER_ASSERT(reporter, 21 == cache->getBudgetedResourceBytes());
    523 
    524     size_t large = 2 * cache->getResourceBytes();
    525     unbudgeted = new TestResource(context->getGpu(), large, GrGpuResource::kUncached_LifeCycle);
    526     REPORTER_ASSERT(reporter, 3 == cache->getResourceCount());
    527     REPORTER_ASSERT(reporter, 21 + large == cache->getResourceBytes());
    528     REPORTER_ASSERT(reporter, 2 == cache->getBudgetedResourceCount());
    529     REPORTER_ASSERT(reporter, 21 == cache->getBudgetedResourceBytes());
    530 
    531     unbudgeted->unref();
    532     REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
    533     REPORTER_ASSERT(reporter, 21 == cache->getResourceBytes());
    534     REPORTER_ASSERT(reporter, 2 == cache->getBudgetedResourceCount());
    535     REPORTER_ASSERT(reporter, 21 == cache->getBudgetedResourceBytes());
    536 
    537     wrapped = new TestResource(context->getGpu(), large, GrGpuResource::kBorrowed_LifeCycle);
    538     REPORTER_ASSERT(reporter, 3 == cache->getResourceCount());
    539     REPORTER_ASSERT(reporter, 21 + large == cache->getResourceBytes());
    540     REPORTER_ASSERT(reporter, 2 == cache->getBudgetedResourceCount());
    541     REPORTER_ASSERT(reporter, 21 == cache->getBudgetedResourceBytes());
    542 
    543     wrapped->unref();
    544     REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
    545     REPORTER_ASSERT(reporter, 21 == cache->getResourceBytes());
    546     REPORTER_ASSERT(reporter, 2 == cache->getBudgetedResourceCount());
    547     REPORTER_ASSERT(reporter, 21 == cache->getBudgetedResourceBytes());
    548 
    549     cache->purgeAllUnlocked();
    550     REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
    551     REPORTER_ASSERT(reporter, 0 == cache->getResourceBytes());
    552     REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount());
    553     REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceBytes());
    554 }
    555 
    556 // This method can't be static because it needs to friended in GrGpuResource::CacheAccess.
    557 void test_unbudgeted_to_scratch(skiatest::Reporter* reporter);
    558 /*static*/ void test_unbudgeted_to_scratch(skiatest::Reporter* reporter) {
    559     Mock mock(10, 300);
    560     GrContext* context = mock.context();
    561     GrResourceCache* cache = mock.cache();
    562 
    563     TestResource* resource =
    564         TestResource::CreateScratch(context->getGpu(), TestResource::kA_SimulatedProperty, false);
    565     GrScratchKey key;
    566     TestResource::ComputeScratchKey(TestResource::kA_SimulatedProperty, &key);
    567 
    568     size_t size = resource->gpuMemorySize();
    569     for (int i = 0; i < 2; ++i) {
    570         // Since this resource is unbudgeted, it should not be reachable as scratch.
    571         REPORTER_ASSERT(reporter, resource->resourcePriv().getScratchKey() == key);
    572         REPORTER_ASSERT(reporter, !resource->cacheAccess().isScratch());
    573         REPORTER_ASSERT(reporter, SkBudgeted::kNo == resource->resourcePriv().isBudgeted());
    574         REPORTER_ASSERT(reporter, nullptr == cache->findAndRefScratchResource(key, TestResource::kDefaultSize, 0));
    575         REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
    576         REPORTER_ASSERT(reporter, size == cache->getResourceBytes());
    577         REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount());
    578         REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceBytes());
    579 
    580         // Once it is unrefed, it should become available as scratch.
    581         resource->unref();
    582         REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
    583         REPORTER_ASSERT(reporter, size == cache->getResourceBytes());
    584         REPORTER_ASSERT(reporter, 1 == cache->getBudgetedResourceCount());
    585         REPORTER_ASSERT(reporter, size == cache->getBudgetedResourceBytes());
    586         resource = static_cast<TestResource*>(cache->findAndRefScratchResource(key, TestResource::kDefaultSize, 0));
    587         REPORTER_ASSERT(reporter, resource);
    588         REPORTER_ASSERT(reporter, resource->resourcePriv().getScratchKey() == key);
    589         REPORTER_ASSERT(reporter, resource->cacheAccess().isScratch());
    590         REPORTER_ASSERT(reporter, SkBudgeted::kYes == resource->resourcePriv().isBudgeted());
    591 
    592         if (0 == i) {
    593             // If made unbudgeted, it should return to original state: ref'ed and unbudgeted. Try
    594             // the above tests again.
    595             resource->resourcePriv().makeUnbudgeted();
    596         } else {
    597             // After the second time around, try removing the scratch key
    598             resource->resourcePriv().removeScratchKey();
    599             REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
    600             REPORTER_ASSERT(reporter, size == cache->getResourceBytes());
    601             REPORTER_ASSERT(reporter, 1 == cache->getBudgetedResourceCount());
    602             REPORTER_ASSERT(reporter, size == cache->getBudgetedResourceBytes());
    603             REPORTER_ASSERT(reporter, !resource->resourcePriv().getScratchKey().isValid());
    604             REPORTER_ASSERT(reporter, !resource->cacheAccess().isScratch());
    605             REPORTER_ASSERT(reporter, SkBudgeted::kYes == resource->resourcePriv().isBudgeted());
    606 
    607             // now when it is unrefed it should die since it has no key.
    608             resource->unref();
    609             REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
    610             REPORTER_ASSERT(reporter, 0 == cache->getResourceBytes());
    611             REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount());
    612             REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceBytes());
    613         }
    614     }
    615 }
    616 
    617 static void test_duplicate_scratch_key(skiatest::Reporter* reporter) {
    618     Mock mock(5, 30000);
    619     GrContext* context = mock.context();
    620     GrResourceCache* cache = mock.cache();
    621 
    622     // Create two resources that have the same scratch key.
    623     TestResource* a = TestResource::CreateScratch(context->getGpu(),
    624                                                   TestResource::kB_SimulatedProperty);
    625     TestResource* b = TestResource::CreateScratch(context->getGpu(),
    626                                                   TestResource::kB_SimulatedProperty);
    627     a->setSize(11);
    628     b->setSize(12);
    629     GrScratchKey scratchKey1;
    630     TestResource::ComputeScratchKey(TestResource::kA_SimulatedProperty, &scratchKey1);
    631     // Check for negative case consistency. (leaks upon test failure.)
    632     REPORTER_ASSERT(reporter, nullptr == cache->findAndRefScratchResource(scratchKey1, TestResource::kDefaultSize, 0));
    633 
    634     GrScratchKey scratchKey;
    635     TestResource::ComputeScratchKey(TestResource::kB_SimulatedProperty, &scratchKey);
    636 
    637     // Scratch resources are registered with GrResourceCache just by existing. There are 2.
    638     REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
    639     SkDEBUGCODE(REPORTER_ASSERT(reporter, 2 == cache->countScratchEntriesForKey(scratchKey));)
    640     REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
    641     REPORTER_ASSERT(reporter, a->gpuMemorySize() + b->gpuMemorySize() ==
    642                               cache->getResourceBytes());
    643 
    644     // Our refs mean that the resources are non purgeable.
    645     cache->purgeAllUnlocked();
    646     REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
    647     REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
    648 
    649     // Unref but don't purge
    650     a->unref();
    651     b->unref();
    652     REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
    653     SkDEBUGCODE(REPORTER_ASSERT(reporter, 2 == cache->countScratchEntriesForKey(scratchKey));)
    654 
    655     // Purge again. This time resources should be purgeable.
    656     cache->purgeAllUnlocked();
    657     REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
    658     REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
    659     SkDEBUGCODE(REPORTER_ASSERT(reporter, 0 == cache->countScratchEntriesForKey(scratchKey));)
    660 }
    661 
    662 static void test_remove_scratch_key(skiatest::Reporter* reporter) {
    663     Mock mock(5, 30000);
    664     GrContext* context = mock.context();
    665     GrResourceCache* cache = mock.cache();
    666 
    667     // Create two resources that have the same scratch key.
    668     TestResource* a = TestResource::CreateScratch(context->getGpu(),
    669                                                   TestResource::kB_SimulatedProperty);
    670     TestResource* b = TestResource::CreateScratch(context->getGpu(),
    671                                                   TestResource::kB_SimulatedProperty);
    672     a->unref();
    673     b->unref();
    674 
    675     GrScratchKey scratchKey;
    676     // Ensure that scratch key lookup is correct for negative case.
    677     TestResource::ComputeScratchKey(TestResource::kA_SimulatedProperty, &scratchKey);
    678     // (following leaks upon test failure).
    679     REPORTER_ASSERT(reporter, cache->findAndRefScratchResource(scratchKey, TestResource::kDefaultSize, 0) == nullptr);
    680 
    681     // Scratch resources are registered with GrResourceCache just by existing. There are 2.
    682     TestResource::ComputeScratchKey(TestResource::kB_SimulatedProperty, &scratchKey);
    683     REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
    684     SkDEBUGCODE(REPORTER_ASSERT(reporter, 2 == cache->countScratchEntriesForKey(scratchKey));)
    685     REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
    686 
    687     // Find the first resource and remove its scratch key
    688     GrGpuResource* find;
    689     find = cache->findAndRefScratchResource(scratchKey, TestResource::kDefaultSize, 0);
    690     find->resourcePriv().removeScratchKey();
    691     // It's still alive, but not cached by scratch key anymore
    692     REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
    693     SkDEBUGCODE(REPORTER_ASSERT(reporter, 1 == cache->countScratchEntriesForKey(scratchKey));)
    694     REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
    695 
    696     // The cache should immediately delete it when it's unrefed since it isn't accessible.
    697     find->unref();
    698     REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
    699     SkDEBUGCODE(REPORTER_ASSERT(reporter, 1 == cache->countScratchEntriesForKey(scratchKey));)
    700     REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
    701 
    702     // Repeat for the second resource.
    703     find = cache->findAndRefScratchResource(scratchKey, TestResource::kDefaultSize, 0);
    704     find->resourcePriv().removeScratchKey();
    705     REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
    706     SkDEBUGCODE(REPORTER_ASSERT(reporter, 0 == cache->countScratchEntriesForKey(scratchKey));)
    707     REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
    708 
    709     // Should be able to call this multiple times with no problem.
    710     find->resourcePriv().removeScratchKey();
    711     REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
    712     SkDEBUGCODE(REPORTER_ASSERT(reporter, 0 == cache->countScratchEntriesForKey(scratchKey));)
    713     REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
    714 
    715     find->unref();
    716     REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
    717     SkDEBUGCODE(REPORTER_ASSERT(reporter, 0 == cache->countScratchEntriesForKey(scratchKey));)
    718     REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
    719 }
    720 
    721 static void test_scratch_key_consistency(skiatest::Reporter* reporter) {
    722     Mock mock(5, 30000);
    723     GrContext* context = mock.context();
    724     GrResourceCache* cache = mock.cache();
    725 
    726     // Create two resources that have the same scratch key.
    727     TestResource* a = TestResource::CreateScratch(context->getGpu(),
    728                                                   TestResource::kB_SimulatedProperty);
    729     TestResource* b = TestResource::CreateScratch(context->getGpu(),
    730                                                   TestResource::kB_SimulatedProperty);
    731     a->unref();
    732     b->unref();
    733 
    734     GrScratchKey scratchKey;
    735     // Ensure that scratch key comparison and assignment is consistent.
    736     GrScratchKey scratchKey1;
    737     TestResource::ComputeScratchKey(TestResource::kA_SimulatedProperty, &scratchKey1);
    738     GrScratchKey scratchKey2;
    739     TestResource::ComputeScratchKey(TestResource::kB_SimulatedProperty, &scratchKey2);
    740     REPORTER_ASSERT(reporter, scratchKey1.size() == TestResource::ExpectedScratchKeySize());
    741     REPORTER_ASSERT(reporter, scratchKey1 != scratchKey2);
    742     REPORTER_ASSERT(reporter, scratchKey2 != scratchKey1);
    743     scratchKey = scratchKey1;
    744     REPORTER_ASSERT(reporter, scratchKey.size() == TestResource::ExpectedScratchKeySize());
    745     REPORTER_ASSERT(reporter, scratchKey1 == scratchKey);
    746     REPORTER_ASSERT(reporter, scratchKey == scratchKey1);
    747     REPORTER_ASSERT(reporter, scratchKey2 != scratchKey);
    748     REPORTER_ASSERT(reporter, scratchKey != scratchKey2);
    749     scratchKey = scratchKey2;
    750     REPORTER_ASSERT(reporter, scratchKey.size() == TestResource::ExpectedScratchKeySize());
    751     REPORTER_ASSERT(reporter, scratchKey1 != scratchKey);
    752     REPORTER_ASSERT(reporter, scratchKey != scratchKey1);
    753     REPORTER_ASSERT(reporter, scratchKey2 == scratchKey);
    754     REPORTER_ASSERT(reporter, scratchKey == scratchKey2);
    755 
    756     // Ensure that scratch key lookup is correct for negative case.
    757     TestResource::ComputeScratchKey(TestResource::kA_SimulatedProperty, &scratchKey);
    758     // (following leaks upon test failure).
    759     REPORTER_ASSERT(reporter, cache->findAndRefScratchResource(scratchKey, TestResource::kDefaultSize, 0) == nullptr);
    760 
    761     // Find the first resource with a scratch key and a copy of a scratch key.
    762     TestResource::ComputeScratchKey(TestResource::kB_SimulatedProperty, &scratchKey);
    763     GrGpuResource* find = cache->findAndRefScratchResource(scratchKey, TestResource::kDefaultSize, 0);
    764     REPORTER_ASSERT(reporter, find != nullptr);
    765     find->unref();
    766 
    767     scratchKey2 = scratchKey;
    768     find = cache->findAndRefScratchResource(scratchKey2, TestResource::kDefaultSize, 0);
    769     REPORTER_ASSERT(reporter, find != nullptr);
    770     REPORTER_ASSERT(reporter, find == a || find == b);
    771 
    772     GrGpuResource* find2 = cache->findAndRefScratchResource(scratchKey2, TestResource::kDefaultSize, 0);
    773     REPORTER_ASSERT(reporter, find2 != nullptr);
    774     REPORTER_ASSERT(reporter, find2 == a || find2 == b);
    775     REPORTER_ASSERT(reporter, find2 != find);
    776     find2->unref();
    777     find->unref();
    778 }
    779 
    780 static void test_duplicate_unique_key(skiatest::Reporter* reporter) {
    781     Mock mock(5, 30000);
    782     GrContext* context = mock.context();
    783     GrResourceCache* cache = mock.cache();
    784 
    785     GrUniqueKey key;
    786     make_unique_key<0>(&key, 0);
    787 
    788     // Create two resources that we will attempt to register with the same unique key.
    789     TestResource* a = new TestResource(context->getGpu());
    790     a->setSize(11);
    791 
    792     // Set key on resource a.
    793     a->resourcePriv().setUniqueKey(key);
    794     REPORTER_ASSERT(reporter, a == cache->findAndRefUniqueResource(key));
    795     a->unref();
    796 
    797     // Make sure that redundantly setting a's key works.
    798     a->resourcePriv().setUniqueKey(key);
    799     REPORTER_ASSERT(reporter, a == cache->findAndRefUniqueResource(key));
    800     a->unref();
    801     REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
    802     REPORTER_ASSERT(reporter, a->gpuMemorySize() == cache->getResourceBytes());
    803     REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
    804 
    805     // Create resource b and set the same key. It should replace a's unique key cache entry.
    806     TestResource* b = new TestResource(context->getGpu());
    807     b->setSize(12);
    808     b->resourcePriv().setUniqueKey(key);
    809     REPORTER_ASSERT(reporter, b == cache->findAndRefUniqueResource(key));
    810     b->unref();
    811 
    812     // Still have two resources because a is still reffed.
    813     REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
    814     REPORTER_ASSERT(reporter, a->gpuMemorySize() + b->gpuMemorySize() == cache->getResourceBytes());
    815     REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
    816 
    817     a->unref();
    818     // Now a should be gone.
    819     REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
    820     REPORTER_ASSERT(reporter, b->gpuMemorySize() == cache->getResourceBytes());
    821     REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
    822 
    823     // Now replace b with c, but make sure c can start with one unique key and change it to b's key.
    824     // Also make b be unreffed when replacement occurs.
    825     b->unref();
    826     TestResource* c = new TestResource(context->getGpu());
    827     GrUniqueKey differentKey;
    828     make_unique_key<0>(&differentKey, 1);
    829     c->setSize(13);
    830     c->resourcePriv().setUniqueKey(differentKey);
    831     REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
    832     REPORTER_ASSERT(reporter, b->gpuMemorySize() + c->gpuMemorySize() == cache->getResourceBytes());
    833     REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
    834     // c replaces b and b should be immediately purged.
    835     c->resourcePriv().setUniqueKey(key);
    836     REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
    837     REPORTER_ASSERT(reporter, c->gpuMemorySize() == cache->getResourceBytes());
    838     REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
    839 
    840     // c shouldn't be purged because it is ref'ed.
    841     cache->purgeAllUnlocked();
    842     REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
    843     REPORTER_ASSERT(reporter, c->gpuMemorySize() == cache->getResourceBytes());
    844     REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
    845 
    846     // Drop the ref on c, it should be kept alive because it has a unique key.
    847     c->unref();
    848     REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
    849     REPORTER_ASSERT(reporter, c->gpuMemorySize() == cache->getResourceBytes());
    850     REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
    851 
    852     // Verify that we can find c, then remove its unique key. It should get purged immediately.
    853     REPORTER_ASSERT(reporter, c == cache->findAndRefUniqueResource(key));
    854     c->resourcePriv().removeUniqueKey();
    855     c->unref();
    856     REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
    857     REPORTER_ASSERT(reporter, 0 == cache->getResourceBytes());
    858     REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
    859 
    860     {
    861         GrUniqueKey key2;
    862         make_unique_key<0>(&key2, 0);
    863         SkAutoTUnref<TestResource> d(new TestResource(context->getGpu()));
    864         int foo = 4132;
    865         SkAutoTUnref<SkData> data(SkData::NewWithCopy(&foo, sizeof(foo)));
    866         key2.setCustomData(data.get());
    867         d->resourcePriv().setUniqueKey(key2);
    868     }
    869 
    870     GrUniqueKey key3;
    871     make_unique_key<0>(&key3, 0);
    872     SkAutoTUnref<GrGpuResource> d2(cache->findAndRefUniqueResource(key3));
    873     REPORTER_ASSERT(reporter, *(int*) d2->getUniqueKey().getCustomData()->data() == 4132);
    874 }
    875 
    876 static void test_purge_invalidated(skiatest::Reporter* reporter) {
    877     Mock mock(5, 30000);
    878     GrContext* context = mock.context();
    879     GrResourceCache* cache = mock.cache();
    880 
    881     GrUniqueKey key1, key2, key3;
    882     make_unique_key<0>(&key1, 1);
    883     make_unique_key<0>(&key2, 2);
    884     make_unique_key<0>(&key3, 3);
    885 
    886     // Add three resources to the cache. Only c is usable as scratch.
    887     TestResource* a = new TestResource(context->getGpu());
    888     TestResource* b = new TestResource(context->getGpu());
    889     TestResource* c = TestResource::CreateScratch(context->getGpu(),
    890                                                   TestResource::kA_SimulatedProperty);
    891     a->resourcePriv().setUniqueKey(key1);
    892     b->resourcePriv().setUniqueKey(key2);
    893     c->resourcePriv().setUniqueKey(key3);
    894     a->unref();
    895     // hold b until *after* the message is sent.
    896     c->unref();
    897 
    898     REPORTER_ASSERT(reporter, cache->hasUniqueKey(key1));
    899     REPORTER_ASSERT(reporter, cache->hasUniqueKey(key2));
    900     REPORTER_ASSERT(reporter, cache->hasUniqueKey(key3));
    901     REPORTER_ASSERT(reporter, 3 == TestResource::NumAlive());
    902 
    903     typedef GrUniqueKeyInvalidatedMessage Msg;
    904     typedef SkMessageBus<GrUniqueKeyInvalidatedMessage> Bus;
    905 
    906     // Invalidate two of the three, they should be purged and no longer accessible via their keys.
    907     Bus::Post(Msg(key1));
    908     Bus::Post(Msg(key2));
    909     cache->purgeAsNeeded();
    910     // a should be deleted now, but we still have a ref on b.
    911     REPORTER_ASSERT(reporter, !cache->hasUniqueKey(key1));
    912     REPORTER_ASSERT(reporter, !cache->hasUniqueKey(key2));
    913     REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
    914     REPORTER_ASSERT(reporter, cache->hasUniqueKey(key3));
    915 
    916     // Invalidate the third.
    917     Bus::Post(Msg(key3));
    918     cache->purgeAsNeeded();
    919     // we still have a ref on b, c should be recycled as scratch.
    920     REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
    921     REPORTER_ASSERT(reporter, !cache->hasUniqueKey(key3));
    922 
    923     // make b purgeable. It should be immediately deleted since it has no key.
    924     b->unref();
    925     REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
    926 
    927     // Make sure we actually get to c via it's scratch key, before we say goodbye.
    928     GrScratchKey scratchKey;
    929     TestResource::ComputeScratchKey(TestResource::kA_SimulatedProperty, &scratchKey);
    930     GrGpuResource* scratch = cache->findAndRefScratchResource(scratchKey, TestResource::kDefaultSize, 0);
    931     REPORTER_ASSERT(reporter, scratch == c);
    932     SkSafeUnref(scratch);
    933 
    934     // Get rid of c.
    935     cache->purgeAllUnlocked();
    936     scratch = cache->findAndRefScratchResource(scratchKey, TestResource::kDefaultSize, 0);
    937     REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
    938     REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
    939     REPORTER_ASSERT(reporter, 0 == cache->getResourceBytes());
    940     REPORTER_ASSERT(reporter, !scratch);
    941     SkSafeUnref(scratch);
    942 }
    943 
    944 static void test_cache_chained_purge(skiatest::Reporter* reporter) {
    945     Mock mock(3, 30000);
    946     GrContext* context = mock.context();
    947     GrResourceCache* cache = mock.cache();
    948 
    949     GrUniqueKey key1, key2;
    950     make_unique_key<0>(&key1, 1);
    951     make_unique_key<0>(&key2, 2);
    952 
    953     TestResource* a = new TestResource(context->getGpu());
    954     TestResource* b = new TestResource(context->getGpu());
    955     a->resourcePriv().setUniqueKey(key1);
    956     b->resourcePriv().setUniqueKey(key2);
    957 
    958     // Make a cycle
    959     a->setUnrefWhenDestroyed(b);
    960     b->setUnrefWhenDestroyed(a);
    961 
    962     REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
    963 
    964     a->unref();
    965     b->unref();
    966 
    967     REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
    968 
    969     cache->purgeAllUnlocked();
    970     REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
    971 
    972     // Break the cycle
    973     a->setUnrefWhenDestroyed(nullptr);
    974     REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
    975 
    976     cache->purgeAllUnlocked();
    977     REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
    978 }
    979 
    980 static void test_resource_size_changed(skiatest::Reporter* reporter) {
    981     GrUniqueKey key1, key2;
    982     make_unique_key<0>(&key1, 1);
    983     make_unique_key<0>(&key2, 2);
    984 
    985     // Test changing resources sizes (both increase & decrease).
    986     {
    987         Mock mock(3, 30000);
    988         GrContext* context = mock.context();
    989         GrResourceCache* cache = mock.cache();
    990 
    991         TestResource* a = new TestResource(context->getGpu());
    992         a->resourcePriv().setUniqueKey(key1);
    993         a->unref();
    994 
    995         TestResource* b = new TestResource(context->getGpu());
    996         b->resourcePriv().setUniqueKey(key2);
    997         b->unref();
    998 
    999         REPORTER_ASSERT(reporter, 200 == cache->getResourceBytes());
   1000         REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
   1001         {
   1002             SkAutoTUnref<TestResource> find2(
   1003                 static_cast<TestResource*>(cache->findAndRefUniqueResource(key2)));
   1004             find2->setSize(200);
   1005             SkAutoTUnref<TestResource> find1(
   1006                 static_cast<TestResource*>(cache->findAndRefUniqueResource(key1)));
   1007             find1->setSize(50);
   1008         }
   1009 
   1010         REPORTER_ASSERT(reporter, 250 == cache->getResourceBytes());
   1011         REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
   1012     }
   1013 
   1014     // Test increasing a resources size beyond the cache budget.
   1015     {
   1016         Mock mock(2, 300);
   1017         GrContext* context = mock.context();
   1018         GrResourceCache* cache = mock.cache();
   1019 
   1020         TestResource* a = new TestResource(context->getGpu());
   1021         a->setSize(100);
   1022         a->resourcePriv().setUniqueKey(key1);
   1023         a->unref();
   1024 
   1025         TestResource* b = new TestResource(context->getGpu());
   1026         b->setSize(100);
   1027         b->resourcePriv().setUniqueKey(key2);
   1028         b->unref();
   1029 
   1030         REPORTER_ASSERT(reporter, 200 == cache->getResourceBytes());
   1031         REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
   1032 
   1033         {
   1034             SkAutoTUnref<TestResource> find2(static_cast<TestResource*>(
   1035                 cache->findAndRefUniqueResource(key2)));
   1036             find2->setSize(201);
   1037         }
   1038         REPORTER_ASSERT(reporter, !cache->hasUniqueKey(key1));
   1039 
   1040         REPORTER_ASSERT(reporter, 201 == cache->getResourceBytes());
   1041         REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
   1042     }
   1043 }
   1044 
   1045 static void test_timestamp_wrap(skiatest::Reporter* reporter) {
   1046     static const int kCount = 50;
   1047     static const int kBudgetCnt = kCount / 2;
   1048     static const int kLockedFreq = 8;
   1049     static const int kBudgetSize = 0x80000000;
   1050 
   1051     SkRandom random;
   1052 
   1053     // Run the test 2*kCount times;
   1054     for (int i = 0; i < 2 * kCount; ++i ) {
   1055         Mock mock(kBudgetCnt, kBudgetSize);
   1056         GrContext* context = mock.context();
   1057         GrResourceCache* cache = mock.cache();
   1058 
   1059         // Pick a random number of resources to add before the timestamp will wrap.
   1060         cache->changeTimestamp(SK_MaxU32 - random.nextULessThan(kCount + 1));
   1061 
   1062         static const int kNumToPurge = kCount - kBudgetCnt;
   1063 
   1064         SkTDArray<int> shouldPurgeIdxs;
   1065         int purgeableCnt = 0;
   1066         SkTDArray<GrGpuResource*> resourcesToUnref;
   1067 
   1068         // Add kCount resources, holding onto resources at random so we have a mix of purgeable and
   1069         // unpurgeable resources.
   1070         for (int j = 0; j < kCount; ++j) {
   1071             GrUniqueKey key;
   1072             make_unique_key<0>(&key, j);
   1073 
   1074             TestResource* r = new TestResource(context->getGpu());
   1075             r->resourcePriv().setUniqueKey(key);
   1076             if (random.nextU() % kLockedFreq) {
   1077                 // Make this is purgeable.
   1078                 r->unref();
   1079                 ++purgeableCnt;
   1080                 if (purgeableCnt <= kNumToPurge) {
   1081                     *shouldPurgeIdxs.append() = j;
   1082                 }
   1083             } else {
   1084                 *resourcesToUnref.append() = r;
   1085             }
   1086         }
   1087 
   1088         // Verify that the correct resources were purged.
   1089         int currShouldPurgeIdx = 0;
   1090         for (int j = 0; j < kCount; ++j) {
   1091             GrUniqueKey key;
   1092             make_unique_key<0>(&key, j);
   1093             GrGpuResource* res = cache->findAndRefUniqueResource(key);
   1094             if (currShouldPurgeIdx < shouldPurgeIdxs.count() &&
   1095                 shouldPurgeIdxs[currShouldPurgeIdx] == j) {
   1096                 ++currShouldPurgeIdx;
   1097                 REPORTER_ASSERT(reporter, nullptr == res);
   1098             } else {
   1099                 REPORTER_ASSERT(reporter, nullptr != res);
   1100             }
   1101             SkSafeUnref(res);
   1102         }
   1103 
   1104         for (int j = 0; j < resourcesToUnref.count(); ++j) {
   1105             resourcesToUnref[j]->unref();
   1106         }
   1107     }
   1108 }
   1109 
   1110 static void test_flush(skiatest::Reporter* reporter) {
   1111     Mock mock(1000000, 1000000);
   1112     GrContext* context = mock.context();
   1113     GrResourceCache* cache = mock.cache();
   1114 
   1115     // The current cache impl will round the max flush count to the next power of 2. So we choose a
   1116     // power of two here to keep things simpler.
   1117     static const int kFlushCount = 16;
   1118     cache->setLimits(1000000, 1000000, kFlushCount);
   1119 
   1120     {
   1121         // Insert a resource and send a flush notification kFlushCount times.
   1122         for (int i = 0; i < kFlushCount; ++i) {
   1123             TestResource* r = new TestResource(context->getGpu());
   1124             GrUniqueKey k;
   1125             make_unique_key<1>(&k, i);
   1126             r->resourcePriv().setUniqueKey(k);
   1127             r->unref();
   1128             cache->notifyFlushOccurred();
   1129         }
   1130 
   1131         // Send flush notifications to the cache. Each flush should purge the oldest resource.
   1132         for (int i = 0; i < kFlushCount - 1; ++i) {
   1133             // The first resource was purged after the last flush in the initial loop, hence the -1.
   1134             REPORTER_ASSERT(reporter, kFlushCount - i - 1 == cache->getResourceCount());
   1135             for (int j = 0; j < i; ++j) {
   1136                 GrUniqueKey k;
   1137                 make_unique_key<1>(&k, j);
   1138                 GrGpuResource* r = cache->findAndRefUniqueResource(k);
   1139                 REPORTER_ASSERT(reporter, !SkToBool(r));
   1140                 SkSafeUnref(r);
   1141             }
   1142             cache->notifyFlushOccurred();
   1143         }
   1144 
   1145         REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
   1146         cache->purgeAllUnlocked();
   1147     }
   1148 
   1149     // Do a similar test but where we leave refs on some resources to prevent them from being
   1150     // purged.
   1151     {
   1152         GrGpuResource* refedResources[kFlushCount >> 1];
   1153         for (int i = 0; i < kFlushCount; ++i) {
   1154             TestResource* r = new TestResource(context->getGpu());
   1155             GrUniqueKey k;
   1156             make_unique_key<1>(&k, i);
   1157             r->resourcePriv().setUniqueKey(k);
   1158             // Leave a ref on every other resource, beginning with the first.
   1159             if (SkToBool(i & 0x1)) {
   1160                 refedResources[i/2] = r;
   1161             } else {
   1162                 r->unref();
   1163             }
   1164             cache->notifyFlushOccurred();
   1165         }
   1166 
   1167         for (int i = 0; i < kFlushCount; ++i) {
   1168             // Should get a resource purged every other flush.
   1169             REPORTER_ASSERT(reporter, kFlushCount - i/2 - 1 == cache->getResourceCount());
   1170             cache->notifyFlushOccurred();
   1171         }
   1172 
   1173         // Unref all the resources that we kept refs on in the first loop.
   1174         for (int i = 0; i < kFlushCount >> 1; ++i) {
   1175             refedResources[i]->unref();
   1176         }
   1177 
   1178         // When we unref'ed them their timestamps got updated. So nothing should be purged until we
   1179         // get kFlushCount additional flushes. Then everything should be purged.
   1180         for (int i = 0; i < kFlushCount; ++i) {
   1181             REPORTER_ASSERT(reporter, kFlushCount >> 1 == cache->getResourceCount());
   1182             cache->notifyFlushOccurred();
   1183         }
   1184         REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
   1185 
   1186         cache->purgeAllUnlocked();
   1187     }
   1188 
   1189     REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
   1190 }
   1191 
   1192 static void test_large_resource_count(skiatest::Reporter* reporter) {
   1193     // Set the cache size to double the resource count because we're going to create 2x that number
   1194     // resources, using two different key domains. Add a little slop to the bytes because we resize
   1195     // down to 1 byte after creating the resource.
   1196     static const int kResourceCnt = 2000;
   1197 
   1198     Mock mock(2 * kResourceCnt, 2 * kResourceCnt + 1000);
   1199     GrContext* context = mock.context();
   1200     GrResourceCache* cache = mock.cache();
   1201 
   1202     for (int i = 0; i < kResourceCnt; ++i) {
   1203         GrUniqueKey key1, key2;
   1204         make_unique_key<1>(&key1, i);
   1205         make_unique_key<2>(&key2, i);
   1206 
   1207         TestResource* resource;
   1208 
   1209         resource = new TestResource(context->getGpu());
   1210         resource->resourcePriv().setUniqueKey(key1);
   1211         resource->setSize(1);
   1212         resource->unref();
   1213 
   1214         resource = new TestResource(context->getGpu());
   1215         resource->resourcePriv().setUniqueKey(key2);
   1216         resource->setSize(1);
   1217         resource->unref();
   1218     }
   1219 
   1220     REPORTER_ASSERT(reporter, TestResource::NumAlive() == 2 * kResourceCnt);
   1221     REPORTER_ASSERT(reporter, cache->getBudgetedResourceBytes() == 2 * kResourceCnt);
   1222     REPORTER_ASSERT(reporter, cache->getBudgetedResourceCount() == 2 * kResourceCnt);
   1223     REPORTER_ASSERT(reporter, cache->getResourceBytes() == 2 * kResourceCnt);
   1224     REPORTER_ASSERT(reporter, cache->getResourceCount() == 2 * kResourceCnt);
   1225     for (int i = 0; i < kResourceCnt; ++i) {
   1226         GrUniqueKey key1, key2;
   1227         make_unique_key<1>(&key1, i);
   1228         make_unique_key<2>(&key2, i);
   1229 
   1230         REPORTER_ASSERT(reporter, cache->hasUniqueKey(key1));
   1231         REPORTER_ASSERT(reporter, cache->hasUniqueKey(key2));
   1232     }
   1233 
   1234     cache->purgeAllUnlocked();
   1235     REPORTER_ASSERT(reporter, TestResource::NumAlive() == 0);
   1236     REPORTER_ASSERT(reporter, cache->getBudgetedResourceBytes() == 0);
   1237     REPORTER_ASSERT(reporter, cache->getBudgetedResourceCount() == 0);
   1238     REPORTER_ASSERT(reporter, cache->getResourceBytes() == 0);
   1239     REPORTER_ASSERT(reporter, cache->getResourceCount() == 0);
   1240 
   1241     for (int i = 0; i < kResourceCnt; ++i) {
   1242         GrUniqueKey key1, key2;
   1243         make_unique_key<1>(&key1, i);
   1244         make_unique_key<2>(&key2, i);
   1245 
   1246         REPORTER_ASSERT(reporter, !cache->hasUniqueKey(key1));
   1247         REPORTER_ASSERT(reporter, !cache->hasUniqueKey(key2));
   1248     }
   1249 }
   1250 
   1251 static void test_custom_data(skiatest::Reporter* reporter) {
   1252     GrUniqueKey key1, key2;
   1253     make_unique_key<0>(&key1, 1);
   1254     make_unique_key<0>(&key2, 2);
   1255     int foo = 4132;
   1256     SkAutoTUnref<SkData> data(SkData::NewWithCopy(&foo, sizeof(foo)));
   1257     key1.setCustomData(data.get());
   1258     REPORTER_ASSERT(reporter, *(int*) key1.getCustomData()->data() == 4132);
   1259     REPORTER_ASSERT(reporter, key2.getCustomData() == nullptr);
   1260 
   1261     // Test that copying a key also takes a ref on its custom data.
   1262     GrUniqueKey key3 = key1;
   1263     REPORTER_ASSERT(reporter, *(int*) key3.getCustomData()->data() == 4132);
   1264 }
   1265 
   1266 static void test_abandoned(skiatest::Reporter* reporter) {
   1267     Mock mock(10, 300);
   1268     GrContext* context = mock.context();
   1269     SkAutoTUnref<GrGpuResource> resource(new TestResource(context->getGpu()));
   1270     context->abandonContext();
   1271 
   1272     REPORTER_ASSERT(reporter, resource->wasDestroyed());
   1273 
   1274     // Call all the public methods on resource in the abandoned state. They shouldn't crash.
   1275 
   1276     int foo = 4132;
   1277     SkAutoTUnref<SkData> data(SkData::NewWithCopy(&foo, sizeof(foo)));
   1278     resource->setCustomData(data.get());
   1279     resource->getCustomData();
   1280     resource->getUniqueID();
   1281     resource->getUniqueKey();
   1282     resource->wasDestroyed();
   1283     resource->gpuMemorySize();
   1284     resource->getContext();
   1285 
   1286     resource->abandon();
   1287     resource->resourcePriv().getScratchKey();
   1288     resource->resourcePriv().isBudgeted();
   1289     resource->resourcePriv().makeBudgeted();
   1290     resource->resourcePriv().makeUnbudgeted();
   1291     resource->resourcePriv().removeScratchKey();
   1292     GrUniqueKey key;
   1293     make_unique_key<0>(&key, 1);
   1294     resource->resourcePriv().setUniqueKey(key);
   1295     resource->resourcePriv().removeUniqueKey();
   1296 }
   1297 
   1298 DEF_GPUTEST(ResourceCacheMisc, reporter, factory) {
   1299     // The below tests create their own mock contexts.
   1300     test_no_key(reporter);
   1301     test_budgeting(reporter);
   1302     test_unbudgeted(reporter);
   1303     test_unbudgeted_to_scratch(reporter);
   1304     test_duplicate_unique_key(reporter);
   1305     test_duplicate_scratch_key(reporter);
   1306     test_remove_scratch_key(reporter);
   1307     test_scratch_key_consistency(reporter);
   1308     test_purge_invalidated(reporter);
   1309     test_cache_chained_purge(reporter);
   1310     test_resource_size_changed(reporter);
   1311     test_timestamp_wrap(reporter);
   1312     test_flush(reporter);
   1313     test_large_resource_count(reporter);
   1314     test_custom_data(reporter);
   1315     test_abandoned(reporter);
   1316 }
   1317 
   1318 #endif
   1319