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 #include <thread>
     13 #include "GrContext.h"
     14 #include "GrContextPriv.h"
     15 #include "GrContextFactory.h"
     16 #include "GrGpu.h"
     17 #include "GrGpuResourceCacheAccess.h"
     18 #include "GrGpuResourcePriv.h"
     19 #include "GrProxyProvider.h"
     20 #include "GrRenderTargetPriv.h"
     21 #include "GrResourceCache.h"
     22 #include "GrResourceProvider.h"
     23 #include "GrTest.h"
     24 #include "GrTexture.h"
     25 
     26 #include "SkCanvas.h"
     27 #include "SkGr.h"
     28 #include "SkMessageBus.h"
     29 #include "SkMipMap.h"
     30 #include "SkSurface.h"
     31 #include "Test.h"
     32 
     33 static const int gWidth = 640;
     34 static const int gHeight = 480;
     35 
     36 ////////////////////////////////////////////////////////////////////////////////
     37 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ResourceCacheCache, reporter, ctxInfo) {
     38     GrContext* context = ctxInfo.grContext();
     39     GrSurfaceDesc desc;
     40     desc.fConfig = kRGBA_8888_GrPixelConfig;
     41     desc.fFlags = kRenderTarget_GrSurfaceFlag;
     42     desc.fWidth = gWidth;
     43     desc.fHeight = gHeight;
     44     SkImageInfo info = SkImageInfo::MakeN32Premul(gWidth, gHeight);
     45     auto surface(SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, info));
     46     SkCanvas* canvas = surface->getCanvas();
     47 
     48     const SkIRect size = SkIRect::MakeWH(gWidth, gHeight);
     49 
     50     SkBitmap src;
     51     src.allocN32Pixels(size.width(), size.height());
     52     src.eraseColor(SK_ColorBLACK);
     53     size_t srcSize = src.computeByteSize();
     54 
     55     size_t initialCacheSize;
     56     context->getResourceCacheUsage(nullptr, &initialCacheSize);
     57 
     58     int oldMaxNum;
     59     size_t oldMaxBytes;
     60     context->getResourceCacheLimits(&oldMaxNum, &oldMaxBytes);
     61 
     62     // Set the cache limits so we can fit 10 "src" images and the
     63     // max number of textures doesn't matter
     64     size_t maxCacheSize = initialCacheSize + 10*srcSize;
     65     context->setResourceCacheLimits(1000, maxCacheSize);
     66 
     67     SkBitmap readback;
     68     readback.allocN32Pixels(size.width(), size.height());
     69 
     70     for (int i = 0; i < 100; ++i) {
     71         canvas->drawBitmap(src, 0, 0);
     72         surface->readPixels(readback, 0, 0);
     73 
     74         // "modify" the src texture
     75         src.notifyPixelsChanged();
     76 
     77         size_t curCacheSize;
     78         context->getResourceCacheUsage(nullptr, &curCacheSize);
     79 
     80         // we should never go over the size limit
     81         REPORTER_ASSERT(reporter, curCacheSize <= maxCacheSize);
     82     }
     83 
     84     context->setResourceCacheLimits(oldMaxNum, oldMaxBytes);
     85 }
     86 
     87 static bool is_rendering_and_not_angle_es3(sk_gpu_test::GrContextFactory::ContextType type) {
     88     if (type == sk_gpu_test::GrContextFactory::kANGLE_D3D11_ES3_ContextType ||
     89         type == sk_gpu_test::GrContextFactory::kANGLE_GL_ES3_ContextType) {
     90         return false;
     91     }
     92     return sk_gpu_test::GrContextFactory::IsRenderingContext(type);
     93 }
     94 
     95 static GrStencilAttachment* get_SB(GrRenderTarget* rt) {
     96     return rt->renderTargetPriv().getStencilAttachment();
     97 }
     98 
     99 static sk_sp<GrRenderTarget> create_RT_with_SB(GrResourceProvider* provider,
    100                                                int size, int sampleCount, SkBudgeted budgeted) {
    101     GrSurfaceDesc desc;
    102     desc.fFlags = kRenderTarget_GrSurfaceFlag;
    103     desc.fOrigin = kBottomLeft_GrSurfaceOrigin;
    104     desc.fWidth = size;
    105     desc.fHeight = size;
    106     desc.fConfig = kRGBA_8888_GrPixelConfig;
    107     desc.fSampleCnt = sampleCount;
    108 
    109     sk_sp<GrTexture> tex(provider->createTexture(desc, budgeted));
    110     if (!tex || !tex->asRenderTarget()) {
    111         return nullptr;
    112     }
    113 
    114     if (!provider->attachStencilAttachment(tex->asRenderTarget())) {
    115         return nullptr;
    116     }
    117     SkASSERT(get_SB(tex->asRenderTarget()));
    118 
    119     return sk_ref_sp(tex->asRenderTarget());
    120 }
    121 
    122 // This currently fails on ES3 ANGLE contexts
    123 DEF_GPUTEST_FOR_CONTEXTS(ResourceCacheStencilBuffers, &is_rendering_and_not_angle_es3, reporter,
    124                          ctxInfo, nullptr) {
    125     GrContext* context = ctxInfo.grContext();
    126     if (context->caps()->avoidStencilBuffers()) {
    127         return;
    128     }
    129 
    130     GrResourceProvider* resourceProvider = context->contextPriv().resourceProvider();
    131 
    132     sk_sp<GrRenderTarget> smallRT0 = create_RT_with_SB(resourceProvider, 4, 1, SkBudgeted::kYes);
    133     REPORTER_ASSERT(reporter, smallRT0);
    134 
    135     {
    136        // Two budgeted RTs with the same desc should share a stencil buffer.
    137        sk_sp<GrRenderTarget> smallRT1 = create_RT_with_SB(resourceProvider, 4, 1, SkBudgeted::kYes);
    138        REPORTER_ASSERT(reporter, smallRT1);
    139 
    140        REPORTER_ASSERT(reporter, get_SB(smallRT0.get()) == get_SB(smallRT1.get()));
    141     }
    142 
    143     {
    144         // An unbudgeted RT with the same desc should also share.
    145         sk_sp<GrRenderTarget> smallRT2 = create_RT_with_SB(resourceProvider, 4, 1, SkBudgeted::kNo);
    146         REPORTER_ASSERT(reporter, smallRT2);
    147 
    148         REPORTER_ASSERT(reporter, get_SB(smallRT0.get()) == get_SB(smallRT2.get()));
    149     }
    150 
    151     {
    152         // An RT with a much larger size should not share.
    153         sk_sp<GrRenderTarget> bigRT = create_RT_with_SB(resourceProvider, 400, 1, SkBudgeted::kNo);
    154         REPORTER_ASSERT(reporter, bigRT);
    155 
    156         REPORTER_ASSERT(reporter, get_SB(smallRT0.get()) != get_SB(bigRT.get()));
    157     }
    158 
    159     int smallSampleCount = context->caps()->getRenderTargetSampleCount(2, kRGBA_8888_GrPixelConfig);
    160     if (smallSampleCount > 1) {
    161         // An RT with a different sample count should not share.
    162         sk_sp<GrRenderTarget> smallMSAART0 = create_RT_with_SB(resourceProvider, 4,
    163                                                                smallSampleCount, SkBudgeted::kNo);
    164 #ifdef SK_BUILD_FOR_ANDROID
    165         if (!smallMSAART0) {
    166             // The nexus player seems to fail to create MSAA textures.
    167             return;
    168         }
    169 #else
    170         REPORTER_ASSERT(reporter, smallMSAART0);
    171 #endif
    172 
    173         REPORTER_ASSERT(reporter, get_SB(smallRT0.get()) != get_SB(smallMSAART0.get()));
    174 
    175         {
    176             // A second MSAA RT should share with the first MSAA RT.
    177             sk_sp<GrRenderTarget> smallMSAART1 = create_RT_with_SB(resourceProvider, 4,
    178                                                                    smallSampleCount,
    179                                                                    SkBudgeted::kNo);
    180             REPORTER_ASSERT(reporter, smallMSAART1);
    181 
    182             REPORTER_ASSERT(reporter, get_SB(smallMSAART0.get()) == get_SB(smallMSAART1.get()));
    183         }
    184 
    185         // But one with a larger sample count should not. (Also check that the two requests didn't
    186         // rounded up to the same actual sample count or else they could share.).
    187         int bigSampleCount =
    188                 context->caps()->getRenderTargetSampleCount(5, kRGBA_8888_GrPixelConfig);
    189         if (bigSampleCount > 0 && bigSampleCount != smallSampleCount) {
    190             sk_sp<GrRenderTarget> smallMSAART2 = create_RT_with_SB(resourceProvider, 4,
    191                                                                    bigSampleCount,
    192                                                                    SkBudgeted::kNo);
    193             REPORTER_ASSERT(reporter, smallMSAART2);
    194 
    195             REPORTER_ASSERT(reporter, get_SB(smallMSAART0.get()) != get_SB(smallMSAART2.get()));
    196         }
    197     }
    198 }
    199 
    200 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ResourceCacheWrappedResources, reporter, ctxInfo) {
    201     GrContext* context = ctxInfo.grContext();
    202     GrResourceProvider* resourceProvider = context->contextPriv().resourceProvider();
    203     GrGpu* gpu = context->contextPriv().getGpu();
    204     // this test is only valid for GL
    205     if (!gpu || !gpu->glContextForTesting()) {
    206         return;
    207     }
    208 
    209     GrBackendTexture backendTextures[2];
    210     static const int kW = 100;
    211     static const int kH = 100;
    212 
    213     backendTextures[0] = gpu->createTestingOnlyBackendTexture(nullptr, kW, kH,
    214                                                               kRGBA_8888_GrPixelConfig,
    215                                                               false, GrMipMapped::kNo);
    216     backendTextures[1] = gpu->createTestingOnlyBackendTexture(nullptr, kW, kH,
    217                                                               kRGBA_8888_GrPixelConfig,
    218                                                               false, GrMipMapped::kNo);
    219     REPORTER_ASSERT(reporter, backendTextures[0].isValid());
    220     REPORTER_ASSERT(reporter, backendTextures[1].isValid());
    221     if (!backendTextures[0].isValid() || !backendTextures[1].isValid()) {
    222         return;
    223     }
    224 
    225     context->resetContext();
    226 
    227     sk_sp<GrTexture> borrowed(resourceProvider->wrapBackendTexture(
    228             backendTextures[0], kBorrow_GrWrapOwnership));
    229 
    230     sk_sp<GrTexture> adopted(resourceProvider->wrapBackendTexture(
    231             backendTextures[1], kAdopt_GrWrapOwnership));
    232 
    233     REPORTER_ASSERT(reporter, borrowed != nullptr && adopted != nullptr);
    234     if (!borrowed || !adopted) {
    235         return;
    236     }
    237 
    238     borrowed.reset(nullptr);
    239     adopted.reset(nullptr);
    240 
    241     context->flush();
    242 
    243     bool borrowedIsAlive = gpu->isTestingOnlyBackendTexture(backendTextures[0]);
    244     bool adoptedIsAlive = gpu->isTestingOnlyBackendTexture(backendTextures[1]);
    245 
    246     REPORTER_ASSERT(reporter, borrowedIsAlive);
    247     REPORTER_ASSERT(reporter, !adoptedIsAlive);
    248 
    249     gpu->deleteTestingOnlyBackendTexture(&(backendTextures[0]), !borrowedIsAlive);
    250     gpu->deleteTestingOnlyBackendTexture(&(backendTextures[1]), !adoptedIsAlive);
    251 
    252     context->resetContext();
    253 }
    254 
    255 class TestResource : public GrGpuResource {
    256     enum ScratchConstructor { kScratchConstructor };
    257 public:
    258     static const size_t kDefaultSize = 100;
    259 
    260     /** Property that distinctly categorizes the resource.
    261      * For example, textures have width, height, ... */
    262     enum SimulatedProperty { kA_SimulatedProperty, kB_SimulatedProperty };
    263 
    264     TestResource(GrGpu* gpu, SkBudgeted budgeted = SkBudgeted::kYes, size_t size = kDefaultSize)
    265         : INHERITED(gpu)
    266         , fToDelete(nullptr)
    267         , fSize(size)
    268         , fProperty(kA_SimulatedProperty)
    269         , fIsScratch(false) {
    270         ++fNumAlive;
    271         this->registerWithCache(budgeted);
    272     }
    273 
    274     static TestResource* CreateScratch(GrGpu* gpu, SkBudgeted budgeted,
    275                                        SimulatedProperty property) {
    276         return new TestResource(gpu, budgeted, property, kScratchConstructor);
    277     }
    278     static TestResource* CreateWrapped(GrGpu* gpu, size_t size = kDefaultSize) {
    279         return new TestResource(gpu, size);
    280     }
    281 
    282     ~TestResource() override {
    283         --fNumAlive;
    284         SkSafeUnref(fToDelete);
    285     }
    286 
    287     void setSize(size_t size) {
    288         fSize = size;
    289         this->didChangeGpuMemorySize();
    290     }
    291 
    292     static int NumAlive() { return fNumAlive; }
    293 
    294     void setUnrefWhenDestroyed(TestResource* resource) {
    295         SkRefCnt_SafeAssign(fToDelete, resource);
    296     }
    297 
    298     static void ComputeScratchKey(SimulatedProperty property, GrScratchKey* key) {
    299         static GrScratchKey::ResourceType t = GrScratchKey::GenerateResourceType();
    300         GrScratchKey::Builder builder(key, t, kScratchKeyFieldCnt);
    301         for (int i = 0; i < kScratchKeyFieldCnt; ++i) {
    302             builder[i] = static_cast<uint32_t>(i + property);
    303         }
    304     }
    305 
    306     static size_t ExpectedScratchKeySize() {
    307         return sizeof(uint32_t) * (kScratchKeyFieldCnt + GrScratchKey::kMetaDataCnt);
    308     }
    309 private:
    310     static const int kScratchKeyFieldCnt = 6;
    311 
    312     TestResource(GrGpu* gpu, SkBudgeted budgeted, SimulatedProperty property, ScratchConstructor)
    313         : INHERITED(gpu)
    314         , fToDelete(nullptr)
    315         , fSize(kDefaultSize)
    316         , fProperty(property)
    317         , fIsScratch(true) {
    318         ++fNumAlive;
    319         this->registerWithCache(budgeted);
    320     }
    321 
    322     // Constructor for simulating resources that wrap backend objects.
    323     TestResource(GrGpu* gpu, size_t size)
    324         : INHERITED(gpu)
    325         , fToDelete(nullptr)
    326         , fSize(size)
    327         , fProperty(kA_SimulatedProperty)
    328         , fIsScratch(false) {
    329         ++fNumAlive;
    330         this->registerWithCacheWrapped();
    331     }
    332 
    333     void computeScratchKey(GrScratchKey* key) const override {
    334         if (fIsScratch) {
    335             ComputeScratchKey(fProperty, key);
    336         }
    337     }
    338 
    339     size_t onGpuMemorySize() const override { return fSize; }
    340     const char* getResourceType() const override { return "Test"; }
    341 
    342     TestResource* fToDelete;
    343     size_t fSize;
    344     static int fNumAlive;
    345     SimulatedProperty fProperty;
    346     bool fIsScratch;
    347     typedef GrGpuResource INHERITED;
    348 };
    349 int TestResource::fNumAlive = 0;
    350 
    351 class Mock {
    352 public:
    353     Mock(int maxCnt, size_t maxBytes) {
    354         fContext = GrContext::MakeMock(nullptr);
    355         SkASSERT(fContext);
    356         fContext->setResourceCacheLimits(maxCnt, maxBytes);
    357         GrResourceCache* cache = fContext->contextPriv().getResourceCache();
    358         cache->purgeAllUnlocked();
    359         SkASSERT(0 == cache->getResourceCount() && 0 == cache->getResourceBytes());
    360     }
    361 
    362     GrResourceCache* cache() { return fContext->contextPriv().getResourceCache(); }
    363 
    364     GrContext* context() { return fContext.get(); }
    365 
    366 private:
    367     sk_sp<GrContext> fContext;
    368 };
    369 
    370 static void test_no_key(skiatest::Reporter* reporter) {
    371     Mock mock(10, 30000);
    372     GrContext* context = mock.context();
    373     GrResourceCache* cache = mock.cache();
    374     GrGpu* gpu = context->contextPriv().getGpu();
    375 
    376     // Create a bunch of resources with no keys
    377     TestResource* a = new TestResource(gpu);
    378     TestResource* b = new TestResource(gpu);
    379     TestResource* c = new TestResource(gpu);
    380     TestResource* d = new TestResource(gpu);
    381     a->setSize(11);
    382     b->setSize(12);
    383     c->setSize(13);
    384     d->setSize(14);
    385 
    386     REPORTER_ASSERT(reporter, 4 == TestResource::NumAlive());
    387     REPORTER_ASSERT(reporter, 4 == cache->getResourceCount());
    388     REPORTER_ASSERT(reporter, a->gpuMemorySize() + b->gpuMemorySize() + c->gpuMemorySize() +
    389                               d->gpuMemorySize() == cache->getResourceBytes());
    390 
    391     // Should be safe to purge without deleting the resources since we still have refs.
    392     cache->purgeAllUnlocked();
    393     REPORTER_ASSERT(reporter, 4 == TestResource::NumAlive());
    394 
    395     // Since the resources have neither unique nor scratch keys, delete immediately upon unref.
    396 
    397     a->unref();
    398     REPORTER_ASSERT(reporter, 3 == TestResource::NumAlive());
    399     REPORTER_ASSERT(reporter, 3 == cache->getResourceCount());
    400     REPORTER_ASSERT(reporter, b->gpuMemorySize() + c->gpuMemorySize() + d->gpuMemorySize() ==
    401                               cache->getResourceBytes());
    402 
    403     c->unref();
    404     REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
    405     REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
    406     REPORTER_ASSERT(reporter, b->gpuMemorySize() + d->gpuMemorySize() ==
    407                               cache->getResourceBytes());
    408 
    409     d->unref();
    410     REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
    411     REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
    412     REPORTER_ASSERT(reporter, b->gpuMemorySize() == cache->getResourceBytes());
    413 
    414     b->unref();
    415     REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
    416     REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
    417     REPORTER_ASSERT(reporter, 0 == cache->getResourceBytes());
    418 }
    419 
    420 // Each integer passed as a template param creates a new domain.
    421 template <int>
    422 static void make_unique_key(GrUniqueKey* key, int data, const char* tag = nullptr) {
    423     static GrUniqueKey::Domain d = GrUniqueKey::GenerateDomain();
    424     GrUniqueKey::Builder builder(key, d, 1, tag);
    425     builder[0] = data;
    426 }
    427 
    428 static void test_purge_unlocked(skiatest::Reporter* reporter) {
    429     Mock mock(10, 30000);
    430     GrContext* context = mock.context();
    431     GrResourceCache* cache = mock.cache();
    432     GrGpu* gpu = context->contextPriv().getGpu();
    433 
    434     // Create two resource w/ a unique key and two w/o but all of which have scratch keys.
    435     TestResource* a = TestResource::CreateScratch(gpu, SkBudgeted::kYes,
    436                                                   TestResource::kA_SimulatedProperty);
    437     a->setSize(11);
    438 
    439     GrUniqueKey uniqueKey;
    440     make_unique_key<0>(&uniqueKey, 0);
    441 
    442     TestResource* b = TestResource::CreateScratch(gpu, SkBudgeted::kYes,
    443                                                   TestResource::kA_SimulatedProperty);
    444     b->setSize(12);
    445     b->resourcePriv().setUniqueKey(uniqueKey);
    446 
    447     TestResource* c = TestResource::CreateScratch(gpu, SkBudgeted::kYes,
    448                                                   TestResource::kA_SimulatedProperty);
    449     c->setSize(13);
    450 
    451     GrUniqueKey uniqueKey2;
    452     make_unique_key<0>(&uniqueKey2, 1);
    453 
    454     TestResource* d = TestResource::CreateScratch(gpu, SkBudgeted::kYes,
    455                                                   TestResource::kA_SimulatedProperty);
    456     d->setSize(14);
    457     d->resourcePriv().setUniqueKey(uniqueKey2);
    458 
    459 
    460     REPORTER_ASSERT(reporter, 4 == TestResource::NumAlive());
    461     REPORTER_ASSERT(reporter, 4 == cache->getResourceCount());
    462     REPORTER_ASSERT(reporter, a->gpuMemorySize() + b->gpuMemorySize() + c->gpuMemorySize() +
    463                               d->gpuMemorySize() == cache->getResourceBytes());
    464 
    465     // Should be safe to purge without deleting the resources since we still have refs.
    466     cache->purgeUnlockedResources(false);
    467     REPORTER_ASSERT(reporter, 4 == TestResource::NumAlive());
    468 
    469     // Unref them all. Since they all have keys they should remain in the cache.
    470 
    471     a->unref();
    472     b->unref();
    473     c->unref();
    474     d->unref();
    475     REPORTER_ASSERT(reporter, 4 == TestResource::NumAlive());
    476     REPORTER_ASSERT(reporter, 4 == cache->getResourceCount());
    477     REPORTER_ASSERT(reporter, a->gpuMemorySize() + b->gpuMemorySize() + c->gpuMemorySize() +
    478                               d->gpuMemorySize() == cache->getResourceBytes());
    479 
    480     // Purge only the two scratch resources
    481     cache->purgeUnlockedResources(true);
    482 
    483     REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
    484     REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
    485     REPORTER_ASSERT(reporter, b->gpuMemorySize() + d->gpuMemorySize() ==
    486                               cache->getResourceBytes());
    487 
    488     // Purge the uniquely keyed resources
    489     cache->purgeUnlockedResources(false);
    490 
    491     REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
    492     REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
    493     REPORTER_ASSERT(reporter, 0 == cache->getResourceBytes());
    494 }
    495 
    496 static void test_budgeting(skiatest::Reporter* reporter) {
    497     Mock mock(10, 300);
    498     GrContext* context = mock.context();
    499     GrResourceCache* cache = mock.cache();
    500     GrGpu* gpu = context->contextPriv().getGpu();
    501 
    502     GrUniqueKey uniqueKey;
    503     make_unique_key<0>(&uniqueKey, 0);
    504 
    505     // Create a scratch, a unique, and a wrapped resource
    506     TestResource* scratch =
    507             TestResource::CreateScratch(gpu, SkBudgeted::kYes, TestResource::kB_SimulatedProperty);
    508     scratch->setSize(10);
    509     TestResource* unique = new TestResource(gpu);
    510     unique->setSize(11);
    511     unique->resourcePriv().setUniqueKey(uniqueKey);
    512     TestResource* wrapped = TestResource::CreateWrapped(gpu);
    513     wrapped->setSize(12);
    514     TestResource* unbudgeted = new TestResource(gpu, SkBudgeted::kNo);
    515     unbudgeted->setSize(13);
    516 
    517     // Make sure we can add a unique key to the wrapped resource
    518     GrUniqueKey uniqueKey2;
    519     make_unique_key<0>(&uniqueKey2, 1);
    520     wrapped->resourcePriv().setUniqueKey(uniqueKey2);
    521     GrGpuResource* wrappedViaKey = cache->findAndRefUniqueResource(uniqueKey2);
    522     REPORTER_ASSERT(reporter, wrappedViaKey != nullptr);
    523 
    524     // Remove the extra ref we just added.
    525     wrappedViaKey->unref();
    526 
    527     // Make sure sizes are as we expect
    528     REPORTER_ASSERT(reporter, 4 == cache->getResourceCount());
    529     REPORTER_ASSERT(reporter, scratch->gpuMemorySize() + unique->gpuMemorySize() +
    530                               wrapped->gpuMemorySize() + unbudgeted->gpuMemorySize() ==
    531                               cache->getResourceBytes());
    532     REPORTER_ASSERT(reporter, 2 == cache->getBudgetedResourceCount());
    533     REPORTER_ASSERT(reporter, scratch->gpuMemorySize() + unique->gpuMemorySize() ==
    534                               cache->getBudgetedResourceBytes());
    535     REPORTER_ASSERT(reporter, 0 == cache->getPurgeableBytes());
    536 
    537     // Our refs mean that the resources are non purgeable.
    538     cache->purgeAllUnlocked();
    539     REPORTER_ASSERT(reporter, 4 == cache->getResourceCount());
    540     REPORTER_ASSERT(reporter, scratch->gpuMemorySize() + unique->gpuMemorySize() +
    541                               wrapped->gpuMemorySize() + unbudgeted->gpuMemorySize() ==
    542                               cache->getResourceBytes());
    543     REPORTER_ASSERT(reporter, 2 == cache->getBudgetedResourceCount());
    544     REPORTER_ASSERT(reporter, scratch->gpuMemorySize() + unique->gpuMemorySize() ==
    545                               cache->getBudgetedResourceBytes());
    546     REPORTER_ASSERT(reporter, 0 == cache->getPurgeableBytes());
    547 
    548     // Unreffing the wrapped resource should free it right away.
    549     wrapped->unref();
    550     REPORTER_ASSERT(reporter, 3 == cache->getResourceCount());
    551     REPORTER_ASSERT(reporter, scratch->gpuMemorySize() + unique->gpuMemorySize() +
    552                               unbudgeted->gpuMemorySize() == cache->getResourceBytes());
    553     REPORTER_ASSERT(reporter, 0 == cache->getPurgeableBytes());
    554 
    555     // Now try freeing the budgeted resources first
    556     wrapped = TestResource::CreateWrapped(gpu);
    557     scratch->setSize(12);
    558     unique->unref();
    559     REPORTER_ASSERT(reporter, 11 == cache->getPurgeableBytes());
    560     cache->purgeAllUnlocked();
    561     REPORTER_ASSERT(reporter, 3 == cache->getResourceCount());
    562     REPORTER_ASSERT(reporter, scratch->gpuMemorySize() + wrapped->gpuMemorySize() +
    563                               unbudgeted->gpuMemorySize() == cache->getResourceBytes());
    564     REPORTER_ASSERT(reporter, 1 == cache->getBudgetedResourceCount());
    565     REPORTER_ASSERT(reporter, scratch->gpuMemorySize() == cache->getBudgetedResourceBytes());
    566     REPORTER_ASSERT(reporter, 0 == cache->getPurgeableBytes());
    567 
    568     scratch->unref();
    569     REPORTER_ASSERT(reporter, 12 == cache->getPurgeableBytes());
    570     cache->purgeAllUnlocked();
    571     REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
    572     REPORTER_ASSERT(reporter, unbudgeted->gpuMemorySize() + wrapped->gpuMemorySize() ==
    573                               cache->getResourceBytes());
    574     REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount());
    575     REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceBytes());
    576     REPORTER_ASSERT(reporter, 0 == cache->getPurgeableBytes());
    577 
    578     wrapped->unref();
    579     REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
    580     REPORTER_ASSERT(reporter, unbudgeted->gpuMemorySize() == cache->getResourceBytes());
    581     REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount());
    582     REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceBytes());
    583     REPORTER_ASSERT(reporter, 0 == cache->getPurgeableBytes());
    584 
    585     unbudgeted->unref();
    586     REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
    587     REPORTER_ASSERT(reporter, 0 == cache->getResourceBytes());
    588     REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount());
    589     REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceBytes());
    590     REPORTER_ASSERT(reporter, 0 == cache->getPurgeableBytes());
    591 }
    592 
    593 static void test_unbudgeted(skiatest::Reporter* reporter) {
    594     Mock mock(10, 30000);
    595     GrContext* context = mock.context();
    596     GrResourceCache* cache = mock.cache();
    597     GrGpu* gpu = context->contextPriv().getGpu();
    598 
    599     GrUniqueKey uniqueKey;
    600     make_unique_key<0>(&uniqueKey, 0);
    601 
    602     TestResource* scratch;
    603     TestResource* unique;
    604     TestResource* wrapped;
    605     TestResource* unbudgeted;
    606 
    607     // A large uncached or wrapped resource shouldn't evict anything.
    608     scratch = TestResource::CreateScratch(gpu, SkBudgeted::kYes,
    609                                           TestResource::kB_SimulatedProperty);
    610 
    611     scratch->setSize(10);
    612     scratch->unref();
    613     REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
    614     REPORTER_ASSERT(reporter, 10 == cache->getResourceBytes());
    615     REPORTER_ASSERT(reporter, 1 == cache->getBudgetedResourceCount());
    616     REPORTER_ASSERT(reporter, 10 == cache->getBudgetedResourceBytes());
    617     REPORTER_ASSERT(reporter, 10 == cache->getPurgeableBytes());
    618 
    619     unique = new TestResource(gpu);
    620     unique->setSize(11);
    621     unique->resourcePriv().setUniqueKey(uniqueKey);
    622     unique->unref();
    623     REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
    624     REPORTER_ASSERT(reporter, 21 == cache->getResourceBytes());
    625     REPORTER_ASSERT(reporter, 2 == cache->getBudgetedResourceCount());
    626     REPORTER_ASSERT(reporter, 21 == cache->getBudgetedResourceBytes());
    627     REPORTER_ASSERT(reporter, 21 == cache->getPurgeableBytes());
    628 
    629     size_t large = 2 * cache->getResourceBytes();
    630     unbudgeted = new TestResource(gpu, SkBudgeted::kNo, large);
    631     REPORTER_ASSERT(reporter, 3 == cache->getResourceCount());
    632     REPORTER_ASSERT(reporter, 21 + large == cache->getResourceBytes());
    633     REPORTER_ASSERT(reporter, 2 == cache->getBudgetedResourceCount());
    634     REPORTER_ASSERT(reporter, 21 == cache->getBudgetedResourceBytes());
    635     REPORTER_ASSERT(reporter, 21 == cache->getPurgeableBytes());
    636 
    637     unbudgeted->unref();
    638     REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
    639     REPORTER_ASSERT(reporter, 21 == cache->getResourceBytes());
    640     REPORTER_ASSERT(reporter, 2 == cache->getBudgetedResourceCount());
    641     REPORTER_ASSERT(reporter, 21 == cache->getBudgetedResourceBytes());
    642     REPORTER_ASSERT(reporter, 21 == cache->getPurgeableBytes());
    643 
    644     wrapped = TestResource::CreateWrapped(gpu, large);
    645     REPORTER_ASSERT(reporter, 3 == cache->getResourceCount());
    646     REPORTER_ASSERT(reporter, 21 + large == cache->getResourceBytes());
    647     REPORTER_ASSERT(reporter, 2 == cache->getBudgetedResourceCount());
    648     REPORTER_ASSERT(reporter, 21 == cache->getBudgetedResourceBytes());
    649     REPORTER_ASSERT(reporter, 21 == cache->getPurgeableBytes());
    650 
    651     wrapped->unref();
    652     REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
    653     REPORTER_ASSERT(reporter, 21 == cache->getResourceBytes());
    654     REPORTER_ASSERT(reporter, 2 == cache->getBudgetedResourceCount());
    655     REPORTER_ASSERT(reporter, 21 == cache->getBudgetedResourceBytes());
    656     REPORTER_ASSERT(reporter, 21 == cache->getPurgeableBytes());
    657 
    658     cache->purgeAllUnlocked();
    659     REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
    660     REPORTER_ASSERT(reporter, 0 == cache->getResourceBytes());
    661     REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount());
    662     REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceBytes());
    663     REPORTER_ASSERT(reporter, 0 == cache->getPurgeableBytes());
    664 }
    665 
    666 // This method can't be static because it needs to friended in GrGpuResource::CacheAccess.
    667 void test_unbudgeted_to_scratch(skiatest::Reporter* reporter);
    668 /*static*/ void test_unbudgeted_to_scratch(skiatest::Reporter* reporter) {
    669     Mock mock(10, 300);
    670     GrContext* context = mock.context();
    671     GrResourceCache* cache = mock.cache();
    672     GrGpu* gpu = context->contextPriv().getGpu();
    673 
    674     TestResource* resource =
    675         TestResource::CreateScratch(gpu, SkBudgeted::kNo, TestResource::kA_SimulatedProperty);
    676     GrScratchKey key;
    677     TestResource::ComputeScratchKey(TestResource::kA_SimulatedProperty, &key);
    678 
    679     size_t size = resource->gpuMemorySize();
    680     for (int i = 0; i < 2; ++i) {
    681         // Since this resource is unbudgeted, it should not be reachable as scratch.
    682         REPORTER_ASSERT(reporter, resource->resourcePriv().getScratchKey() == key);
    683         REPORTER_ASSERT(reporter, !resource->cacheAccess().isScratch());
    684         REPORTER_ASSERT(reporter, SkBudgeted::kNo == resource->resourcePriv().isBudgeted());
    685         REPORTER_ASSERT(reporter, nullptr == cache->findAndRefScratchResource(key, TestResource::kDefaultSize, 0));
    686         REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
    687         REPORTER_ASSERT(reporter, size == cache->getResourceBytes());
    688         REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount());
    689         REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceBytes());
    690         REPORTER_ASSERT(reporter, 0 == cache->getPurgeableBytes());
    691 
    692         // Once it is unrefed, it should become available as scratch.
    693         resource->unref();
    694         REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
    695         REPORTER_ASSERT(reporter, size == cache->getResourceBytes());
    696         REPORTER_ASSERT(reporter, 1 == cache->getBudgetedResourceCount());
    697         REPORTER_ASSERT(reporter, size == cache->getBudgetedResourceBytes());
    698         REPORTER_ASSERT(reporter, size == cache->getPurgeableBytes());
    699         resource = static_cast<TestResource*>(cache->findAndRefScratchResource(key, TestResource::kDefaultSize, 0));
    700         REPORTER_ASSERT(reporter, resource);
    701         REPORTER_ASSERT(reporter, resource->resourcePriv().getScratchKey() == key);
    702         REPORTER_ASSERT(reporter, resource->cacheAccess().isScratch());
    703         REPORTER_ASSERT(reporter, SkBudgeted::kYes == resource->resourcePriv().isBudgeted());
    704 
    705         if (0 == i) {
    706             // If made unbudgeted, it should return to original state: ref'ed and unbudgeted. Try
    707             // the above tests again.
    708             resource->resourcePriv().makeUnbudgeted();
    709         } else {
    710             // After the second time around, try removing the scratch key
    711             resource->resourcePriv().removeScratchKey();
    712             REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
    713             REPORTER_ASSERT(reporter, size == cache->getResourceBytes());
    714             REPORTER_ASSERT(reporter, 1 == cache->getBudgetedResourceCount());
    715             REPORTER_ASSERT(reporter, size == cache->getBudgetedResourceBytes());
    716             REPORTER_ASSERT(reporter, 0 == cache->getPurgeableBytes());
    717             REPORTER_ASSERT(reporter, !resource->resourcePriv().getScratchKey().isValid());
    718             REPORTER_ASSERT(reporter, !resource->cacheAccess().isScratch());
    719             REPORTER_ASSERT(reporter, SkBudgeted::kYes == resource->resourcePriv().isBudgeted());
    720 
    721             // now when it is unrefed it should die since it has no key.
    722             resource->unref();
    723             REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
    724             REPORTER_ASSERT(reporter, 0 == cache->getResourceBytes());
    725             REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount());
    726             REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceBytes());
    727             REPORTER_ASSERT(reporter, 0 == cache->getPurgeableBytes());
    728         }
    729     }
    730 }
    731 
    732 static void test_duplicate_scratch_key(skiatest::Reporter* reporter) {
    733     Mock mock(5, 30000);
    734     GrContext* context = mock.context();
    735     GrResourceCache* cache = mock.cache();
    736     GrGpu* gpu = context->contextPriv().getGpu();
    737 
    738     // Create two resources that have the same scratch key.
    739     TestResource* a = TestResource::CreateScratch(gpu,
    740                                                   SkBudgeted::kYes,
    741                                                   TestResource::kB_SimulatedProperty);
    742     TestResource* b = TestResource::CreateScratch(gpu,
    743                                                   SkBudgeted::kYes,
    744                                                   TestResource::kB_SimulatedProperty);
    745     a->setSize(11);
    746     b->setSize(12);
    747     GrScratchKey scratchKey1;
    748     TestResource::ComputeScratchKey(TestResource::kA_SimulatedProperty, &scratchKey1);
    749     // Check for negative case consistency. (leaks upon test failure.)
    750     REPORTER_ASSERT(reporter, nullptr == cache->findAndRefScratchResource(scratchKey1, TestResource::kDefaultSize, 0));
    751 
    752     GrScratchKey scratchKey;
    753     TestResource::ComputeScratchKey(TestResource::kB_SimulatedProperty, &scratchKey);
    754 
    755     // Scratch resources are registered with GrResourceCache just by existing. There are 2.
    756     REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
    757     SkDEBUGCODE(REPORTER_ASSERT(reporter, 2 == cache->countScratchEntriesForKey(scratchKey));)
    758     REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
    759     REPORTER_ASSERT(reporter, a->gpuMemorySize() + b->gpuMemorySize() ==
    760                               cache->getResourceBytes());
    761 
    762     // Our refs mean that the resources are non purgeable.
    763     cache->purgeAllUnlocked();
    764     REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
    765     REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
    766 
    767     // Unref but don't purge
    768     a->unref();
    769     b->unref();
    770     REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
    771     SkDEBUGCODE(REPORTER_ASSERT(reporter, 2 == cache->countScratchEntriesForKey(scratchKey));)
    772 
    773     // Purge again. This time resources should be purgeable.
    774     cache->purgeAllUnlocked();
    775     REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
    776     REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
    777     SkDEBUGCODE(REPORTER_ASSERT(reporter, 0 == cache->countScratchEntriesForKey(scratchKey));)
    778 }
    779 
    780 static void test_remove_scratch_key(skiatest::Reporter* reporter) {
    781     Mock mock(5, 30000);
    782     GrContext* context = mock.context();
    783     GrResourceCache* cache = mock.cache();
    784     GrGpu* gpu = context->contextPriv().getGpu();
    785 
    786     // Create two resources that have the same scratch key.
    787     TestResource* a = TestResource::CreateScratch(gpu, SkBudgeted::kYes,
    788                                                   TestResource::kB_SimulatedProperty);
    789     TestResource* b = TestResource::CreateScratch(gpu, SkBudgeted::kYes,
    790                                                   TestResource::kB_SimulatedProperty);
    791     a->unref();
    792     b->unref();
    793 
    794     GrScratchKey scratchKey;
    795     // Ensure that scratch key lookup is correct for negative case.
    796     TestResource::ComputeScratchKey(TestResource::kA_SimulatedProperty, &scratchKey);
    797     // (following leaks upon test failure).
    798     REPORTER_ASSERT(reporter, cache->findAndRefScratchResource(scratchKey, TestResource::kDefaultSize, 0) == nullptr);
    799 
    800     // Scratch resources are registered with GrResourceCache just by existing. There are 2.
    801     TestResource::ComputeScratchKey(TestResource::kB_SimulatedProperty, &scratchKey);
    802     REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
    803     SkDEBUGCODE(REPORTER_ASSERT(reporter, 2 == cache->countScratchEntriesForKey(scratchKey));)
    804     REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
    805 
    806     // Find the first resource and remove its scratch key
    807     GrGpuResource* find;
    808     find = cache->findAndRefScratchResource(scratchKey, TestResource::kDefaultSize, 0);
    809     find->resourcePriv().removeScratchKey();
    810     // It's still alive, but not cached by scratch key anymore
    811     REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
    812     SkDEBUGCODE(REPORTER_ASSERT(reporter, 1 == cache->countScratchEntriesForKey(scratchKey));)
    813     REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
    814 
    815     // The cache should immediately delete it when it's unrefed since it isn't accessible.
    816     find->unref();
    817     REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
    818     SkDEBUGCODE(REPORTER_ASSERT(reporter, 1 == cache->countScratchEntriesForKey(scratchKey));)
    819     REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
    820 
    821     // Repeat for the second resource.
    822     find = cache->findAndRefScratchResource(scratchKey, TestResource::kDefaultSize, 0);
    823     find->resourcePriv().removeScratchKey();
    824     REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
    825     SkDEBUGCODE(REPORTER_ASSERT(reporter, 0 == cache->countScratchEntriesForKey(scratchKey));)
    826     REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
    827 
    828     // Should be able to call this multiple times with no problem.
    829     find->resourcePriv().removeScratchKey();
    830     REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
    831     SkDEBUGCODE(REPORTER_ASSERT(reporter, 0 == cache->countScratchEntriesForKey(scratchKey));)
    832     REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
    833 
    834     find->unref();
    835     REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
    836     SkDEBUGCODE(REPORTER_ASSERT(reporter, 0 == cache->countScratchEntriesForKey(scratchKey));)
    837     REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
    838 }
    839 
    840 static void test_scratch_key_consistency(skiatest::Reporter* reporter) {
    841     Mock mock(5, 30000);
    842     GrContext* context = mock.context();
    843     GrResourceCache* cache = mock.cache();
    844     GrGpu* gpu = context->contextPriv().getGpu();
    845 
    846     // Create two resources that have the same scratch key.
    847     TestResource* a = TestResource::CreateScratch(gpu, SkBudgeted::kYes,
    848                                                   TestResource::kB_SimulatedProperty);
    849     TestResource* b = TestResource::CreateScratch(gpu, SkBudgeted::kYes,
    850                                                   TestResource::kB_SimulatedProperty);
    851     a->unref();
    852     b->unref();
    853 
    854     GrScratchKey scratchKey;
    855     // Ensure that scratch key comparison and assignment is consistent.
    856     GrScratchKey scratchKey1;
    857     TestResource::ComputeScratchKey(TestResource::kA_SimulatedProperty, &scratchKey1);
    858     GrScratchKey scratchKey2;
    859     TestResource::ComputeScratchKey(TestResource::kB_SimulatedProperty, &scratchKey2);
    860     REPORTER_ASSERT(reporter, scratchKey1.size() == TestResource::ExpectedScratchKeySize());
    861     REPORTER_ASSERT(reporter, scratchKey1 != scratchKey2);
    862     REPORTER_ASSERT(reporter, scratchKey2 != scratchKey1);
    863     scratchKey = scratchKey1;
    864     REPORTER_ASSERT(reporter, scratchKey.size() == TestResource::ExpectedScratchKeySize());
    865     REPORTER_ASSERT(reporter, scratchKey1 == scratchKey);
    866     REPORTER_ASSERT(reporter, scratchKey == scratchKey1);
    867     REPORTER_ASSERT(reporter, scratchKey2 != scratchKey);
    868     REPORTER_ASSERT(reporter, scratchKey != scratchKey2);
    869     scratchKey = scratchKey2;
    870     REPORTER_ASSERT(reporter, scratchKey.size() == TestResource::ExpectedScratchKeySize());
    871     REPORTER_ASSERT(reporter, scratchKey1 != scratchKey);
    872     REPORTER_ASSERT(reporter, scratchKey != scratchKey1);
    873     REPORTER_ASSERT(reporter, scratchKey2 == scratchKey);
    874     REPORTER_ASSERT(reporter, scratchKey == scratchKey2);
    875 
    876     // Ensure that scratch key lookup is correct for negative case.
    877     TestResource::ComputeScratchKey(TestResource::kA_SimulatedProperty, &scratchKey);
    878     // (following leaks upon test failure).
    879     REPORTER_ASSERT(reporter, cache->findAndRefScratchResource(scratchKey, TestResource::kDefaultSize, 0) == nullptr);
    880 
    881     // Find the first resource with a scratch key and a copy of a scratch key.
    882     TestResource::ComputeScratchKey(TestResource::kB_SimulatedProperty, &scratchKey);
    883     GrGpuResource* find = cache->findAndRefScratchResource(scratchKey, TestResource::kDefaultSize, 0);
    884     REPORTER_ASSERT(reporter, find != nullptr);
    885     find->unref();
    886 
    887     scratchKey2 = scratchKey;
    888     find = cache->findAndRefScratchResource(scratchKey2, TestResource::kDefaultSize, 0);
    889     REPORTER_ASSERT(reporter, find != nullptr);
    890     REPORTER_ASSERT(reporter, find == a || find == b);
    891 
    892     GrGpuResource* find2 = cache->findAndRefScratchResource(scratchKey2, TestResource::kDefaultSize, 0);
    893     REPORTER_ASSERT(reporter, find2 != nullptr);
    894     REPORTER_ASSERT(reporter, find2 == a || find2 == b);
    895     REPORTER_ASSERT(reporter, find2 != find);
    896     find2->unref();
    897     find->unref();
    898 }
    899 
    900 static void test_duplicate_unique_key(skiatest::Reporter* reporter) {
    901     Mock mock(5, 30000);
    902     GrContext* context = mock.context();
    903     GrResourceCache* cache = mock.cache();
    904     GrGpu* gpu = context->contextPriv().getGpu();
    905 
    906     GrUniqueKey key;
    907     make_unique_key<0>(&key, 0);
    908 
    909     // Create two resources that we will attempt to register with the same unique key.
    910     TestResource* a = new TestResource(gpu);
    911     a->setSize(11);
    912 
    913     // Set key on resource a.
    914     a->resourcePriv().setUniqueKey(key);
    915     REPORTER_ASSERT(reporter, a == cache->findAndRefUniqueResource(key));
    916     a->unref();
    917 
    918     // Make sure that redundantly setting a's key works.
    919     a->resourcePriv().setUniqueKey(key);
    920     REPORTER_ASSERT(reporter, a == cache->findAndRefUniqueResource(key));
    921     a->unref();
    922     REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
    923     REPORTER_ASSERT(reporter, a->gpuMemorySize() == cache->getResourceBytes());
    924     REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
    925 
    926     // Create resource b and set the same key. It should replace a's unique key cache entry.
    927     TestResource* b = new TestResource(gpu);
    928     b->setSize(12);
    929     b->resourcePriv().setUniqueKey(key);
    930     REPORTER_ASSERT(reporter, b == cache->findAndRefUniqueResource(key));
    931     b->unref();
    932 
    933     // Still have two resources because a is still reffed.
    934     REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
    935     REPORTER_ASSERT(reporter, a->gpuMemorySize() + b->gpuMemorySize() == cache->getResourceBytes());
    936     REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
    937 
    938     a->unref();
    939     // Now a should be gone.
    940     REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
    941     REPORTER_ASSERT(reporter, b->gpuMemorySize() == cache->getResourceBytes());
    942     REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
    943 
    944     // Now replace b with c, but make sure c can start with one unique key and change it to b's key.
    945     // Also make b be unreffed when replacement occurs.
    946     b->unref();
    947     TestResource* c = new TestResource(gpu);
    948     GrUniqueKey differentKey;
    949     make_unique_key<0>(&differentKey, 1);
    950     c->setSize(13);
    951     c->resourcePriv().setUniqueKey(differentKey);
    952     REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
    953     REPORTER_ASSERT(reporter, b->gpuMemorySize() + c->gpuMemorySize() == cache->getResourceBytes());
    954     REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
    955     // c replaces b and b should be immediately purged.
    956     c->resourcePriv().setUniqueKey(key);
    957     REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
    958     REPORTER_ASSERT(reporter, c->gpuMemorySize() == cache->getResourceBytes());
    959     REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
    960 
    961     // c shouldn't be purged because it is ref'ed.
    962     cache->purgeAllUnlocked();
    963     REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
    964     REPORTER_ASSERT(reporter, c->gpuMemorySize() == cache->getResourceBytes());
    965     REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
    966 
    967     // Drop the ref on c, it should be kept alive because it has a unique key.
    968     c->unref();
    969     REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
    970     REPORTER_ASSERT(reporter, c->gpuMemorySize() == cache->getResourceBytes());
    971     REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
    972 
    973     // Verify that we can find c, then remove its unique key. It should get purged immediately.
    974     REPORTER_ASSERT(reporter, c == cache->findAndRefUniqueResource(key));
    975     c->resourcePriv().removeUniqueKey();
    976     c->unref();
    977     REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
    978     REPORTER_ASSERT(reporter, 0 == cache->getResourceBytes());
    979     REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
    980 
    981     {
    982         GrUniqueKey key2;
    983         make_unique_key<0>(&key2, 0);
    984         sk_sp<TestResource> d(new TestResource(gpu));
    985         int foo = 4132;
    986         key2.setCustomData(SkData::MakeWithCopy(&foo, sizeof(foo)));
    987         d->resourcePriv().setUniqueKey(key2);
    988     }
    989 
    990     GrUniqueKey key3;
    991     make_unique_key<0>(&key3, 0);
    992     sk_sp<GrGpuResource> d2(cache->findAndRefUniqueResource(key3));
    993     REPORTER_ASSERT(reporter, *(int*) d2->getUniqueKey().getCustomData()->data() == 4132);
    994 }
    995 
    996 static void test_purge_invalidated(skiatest::Reporter* reporter) {
    997     Mock mock(5, 30000);
    998     GrContext* context = mock.context();
    999     GrResourceCache* cache = mock.cache();
   1000     GrGpu* gpu = context->contextPriv().getGpu();
   1001 
   1002     GrUniqueKey key1, key2, key3;
   1003     make_unique_key<0>(&key1, 1);
   1004     make_unique_key<0>(&key2, 2);
   1005     make_unique_key<0>(&key3, 3);
   1006 
   1007     // Add three resources to the cache. Only c is usable as scratch.
   1008     TestResource* a = new TestResource(gpu);
   1009     TestResource* b = new TestResource(gpu);
   1010     TestResource* c = TestResource::CreateScratch(gpu, SkBudgeted::kYes,
   1011                                                   TestResource::kA_SimulatedProperty);
   1012     a->resourcePriv().setUniqueKey(key1);
   1013     b->resourcePriv().setUniqueKey(key2);
   1014     c->resourcePriv().setUniqueKey(key3);
   1015     a->unref();
   1016     // hold b until *after* the message is sent.
   1017     c->unref();
   1018 
   1019     REPORTER_ASSERT(reporter, cache->hasUniqueKey(key1));
   1020     REPORTER_ASSERT(reporter, cache->hasUniqueKey(key2));
   1021     REPORTER_ASSERT(reporter, cache->hasUniqueKey(key3));
   1022     REPORTER_ASSERT(reporter, 3 == TestResource::NumAlive());
   1023 
   1024     typedef GrUniqueKeyInvalidatedMessage Msg;
   1025     typedef SkMessageBus<GrUniqueKeyInvalidatedMessage> Bus;
   1026 
   1027     // Invalidate two of the three, they should be purged and no longer accessible via their keys.
   1028     Bus::Post(Msg(key1));
   1029     Bus::Post(Msg(key2));
   1030     cache->purgeAsNeeded();
   1031     // a should be deleted now, but we still have a ref on b.
   1032     REPORTER_ASSERT(reporter, !cache->hasUniqueKey(key1));
   1033     REPORTER_ASSERT(reporter, !cache->hasUniqueKey(key2));
   1034     REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
   1035     REPORTER_ASSERT(reporter, cache->hasUniqueKey(key3));
   1036 
   1037     // Invalidate the third.
   1038     Bus::Post(Msg(key3));
   1039     cache->purgeAsNeeded();
   1040     // we still have a ref on b, c should be recycled as scratch.
   1041     REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
   1042     REPORTER_ASSERT(reporter, !cache->hasUniqueKey(key3));
   1043 
   1044     // make b purgeable. It should be immediately deleted since it has no key.
   1045     b->unref();
   1046     REPORTER_ASSERT(reporter, 1 == TestResource::NumAlive());
   1047 
   1048     // Make sure we actually get to c via it's scratch key, before we say goodbye.
   1049     GrScratchKey scratchKey;
   1050     TestResource::ComputeScratchKey(TestResource::kA_SimulatedProperty, &scratchKey);
   1051     GrGpuResource* scratch = cache->findAndRefScratchResource(scratchKey, TestResource::kDefaultSize, 0);
   1052     REPORTER_ASSERT(reporter, scratch == c);
   1053     SkSafeUnref(scratch);
   1054 
   1055     // Get rid of c.
   1056     cache->purgeAllUnlocked();
   1057     scratch = cache->findAndRefScratchResource(scratchKey, TestResource::kDefaultSize, 0);
   1058     REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
   1059     REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
   1060     REPORTER_ASSERT(reporter, 0 == cache->getResourceBytes());
   1061     REPORTER_ASSERT(reporter, !scratch);
   1062     SkSafeUnref(scratch);
   1063 }
   1064 
   1065 static void test_cache_chained_purge(skiatest::Reporter* reporter) {
   1066     Mock mock(3, 30000);
   1067     GrContext* context = mock.context();
   1068     GrResourceCache* cache = mock.cache();
   1069     GrGpu* gpu = context->contextPriv().getGpu();
   1070 
   1071     GrUniqueKey key1, key2;
   1072     make_unique_key<0>(&key1, 1);
   1073     make_unique_key<0>(&key2, 2);
   1074 
   1075     TestResource* a = new TestResource(gpu);
   1076     TestResource* b = new TestResource(gpu);
   1077     a->resourcePriv().setUniqueKey(key1);
   1078     b->resourcePriv().setUniqueKey(key2);
   1079 
   1080     // Make a cycle
   1081     a->setUnrefWhenDestroyed(b);
   1082     b->setUnrefWhenDestroyed(a);
   1083 
   1084     REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
   1085 
   1086     a->unref();
   1087     b->unref();
   1088 
   1089     REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
   1090 
   1091     cache->purgeAllUnlocked();
   1092     REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
   1093 
   1094     // Break the cycle
   1095     a->setUnrefWhenDestroyed(nullptr);
   1096     REPORTER_ASSERT(reporter, 2 == TestResource::NumAlive());
   1097 
   1098     cache->purgeAllUnlocked();
   1099     REPORTER_ASSERT(reporter, 0 == TestResource::NumAlive());
   1100 }
   1101 
   1102 static void test_resource_size_changed(skiatest::Reporter* reporter) {
   1103     GrUniqueKey key1, key2;
   1104     make_unique_key<0>(&key1, 1);
   1105     make_unique_key<0>(&key2, 2);
   1106 
   1107     // Test changing resources sizes (both increase & decrease).
   1108     {
   1109         Mock mock(3, 30000);
   1110         GrContext* context = mock.context();
   1111         GrResourceCache* cache = mock.cache();
   1112         GrGpu* gpu = context->contextPriv().getGpu();
   1113 
   1114         TestResource* a = new TestResource(gpu);
   1115         a->resourcePriv().setUniqueKey(key1);
   1116         a->unref();
   1117 
   1118         TestResource* b = new TestResource(gpu);
   1119         b->resourcePriv().setUniqueKey(key2);
   1120         b->unref();
   1121 
   1122         REPORTER_ASSERT(reporter, 200 == cache->getResourceBytes());
   1123         REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
   1124         {
   1125             sk_sp<TestResource> find2(
   1126                 static_cast<TestResource*>(cache->findAndRefUniqueResource(key2)));
   1127             find2->setSize(200);
   1128             sk_sp<TestResource> find1(
   1129                 static_cast<TestResource*>(cache->findAndRefUniqueResource(key1)));
   1130             find1->setSize(50);
   1131         }
   1132 
   1133         REPORTER_ASSERT(reporter, 250 == cache->getResourceBytes());
   1134         REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
   1135     }
   1136 
   1137     // Test increasing a resources size beyond the cache budget.
   1138     {
   1139         Mock mock(2, 300);
   1140         GrContext* context = mock.context();
   1141         GrResourceCache* cache = mock.cache();
   1142         GrGpu* gpu = context->contextPriv().getGpu();
   1143 
   1144         TestResource* a = new TestResource(gpu);
   1145         a->setSize(100);
   1146         a->resourcePriv().setUniqueKey(key1);
   1147         a->unref();
   1148 
   1149         TestResource* b = new TestResource(gpu);
   1150         b->setSize(100);
   1151         b->resourcePriv().setUniqueKey(key2);
   1152         b->unref();
   1153 
   1154         REPORTER_ASSERT(reporter, 200 == cache->getResourceBytes());
   1155         REPORTER_ASSERT(reporter, 2 == cache->getResourceCount());
   1156 
   1157         {
   1158             sk_sp<TestResource> find2(static_cast<TestResource*>(
   1159                 cache->findAndRefUniqueResource(key2)));
   1160             find2->setSize(201);
   1161         }
   1162         REPORTER_ASSERT(reporter, !cache->hasUniqueKey(key1));
   1163 
   1164         REPORTER_ASSERT(reporter, 201 == cache->getResourceBytes());
   1165         REPORTER_ASSERT(reporter, 1 == cache->getResourceCount());
   1166     }
   1167 }
   1168 
   1169 static void test_timestamp_wrap(skiatest::Reporter* reporter) {
   1170     static const int kCount = 50;
   1171     static const int kBudgetCnt = kCount / 2;
   1172     static const int kLockedFreq = 8;
   1173     static const int kBudgetSize = 0x80000000;
   1174 
   1175     SkRandom random;
   1176 
   1177     // Run the test 2*kCount times;
   1178     for (int i = 0; i < 2 * kCount; ++i ) {
   1179         Mock mock(kBudgetCnt, kBudgetSize);
   1180         GrContext* context = mock.context();
   1181         GrResourceCache* cache = mock.cache();
   1182         GrGpu* gpu = context->contextPriv().getGpu();
   1183 
   1184         // Pick a random number of resources to add before the timestamp will wrap.
   1185         cache->changeTimestamp(SK_MaxU32 - random.nextULessThan(kCount + 1));
   1186 
   1187         static const int kNumToPurge = kCount - kBudgetCnt;
   1188 
   1189         SkTDArray<int> shouldPurgeIdxs;
   1190         int purgeableCnt = 0;
   1191         SkTDArray<GrGpuResource*> resourcesToUnref;
   1192 
   1193         // Add kCount resources, holding onto resources at random so we have a mix of purgeable and
   1194         // unpurgeable resources.
   1195         for (int j = 0; j < kCount; ++j) {
   1196             GrUniqueKey key;
   1197             make_unique_key<0>(&key, j);
   1198 
   1199             TestResource* r = new TestResource(gpu);
   1200             r->resourcePriv().setUniqueKey(key);
   1201             if (random.nextU() % kLockedFreq) {
   1202                 // Make this is purgeable.
   1203                 r->unref();
   1204                 ++purgeableCnt;
   1205                 if (purgeableCnt <= kNumToPurge) {
   1206                     *shouldPurgeIdxs.append() = j;
   1207                 }
   1208             } else {
   1209                 *resourcesToUnref.append() = r;
   1210             }
   1211         }
   1212 
   1213         // Verify that the correct resources were purged.
   1214         int currShouldPurgeIdx = 0;
   1215         for (int j = 0; j < kCount; ++j) {
   1216             GrUniqueKey key;
   1217             make_unique_key<0>(&key, j);
   1218             GrGpuResource* res = cache->findAndRefUniqueResource(key);
   1219             if (currShouldPurgeIdx < shouldPurgeIdxs.count() &&
   1220                 shouldPurgeIdxs[currShouldPurgeIdx] == j) {
   1221                 ++currShouldPurgeIdx;
   1222                 REPORTER_ASSERT(reporter, nullptr == res);
   1223             } else {
   1224                 REPORTER_ASSERT(reporter, nullptr != res);
   1225             }
   1226             SkSafeUnref(res);
   1227         }
   1228 
   1229         for (int j = 0; j < resourcesToUnref.count(); ++j) {
   1230             resourcesToUnref[j]->unref();
   1231         }
   1232     }
   1233 }
   1234 
   1235 static void test_flush(skiatest::Reporter* reporter) {
   1236     Mock mock(1000000, 1000000);
   1237     GrContext* context = mock.context();
   1238     GrResourceCache* cache = mock.cache();
   1239     GrGpu* gpu = context->contextPriv().getGpu();
   1240 
   1241     // The current cache impl will round the max flush count to the next power of 2. So we choose a
   1242     // power of two here to keep things simpler.
   1243     static const int kFlushCount = 16;
   1244     cache->setLimits(1000000, 1000000, kFlushCount);
   1245 
   1246     {
   1247         // Insert a resource and send a flush notification kFlushCount times.
   1248         for (int i = 0; i < kFlushCount; ++i) {
   1249             TestResource* r = new TestResource(gpu);
   1250             GrUniqueKey k;
   1251             make_unique_key<1>(&k, i);
   1252             r->resourcePriv().setUniqueKey(k);
   1253             r->unref();
   1254             cache->notifyFlushOccurred(GrResourceCache::kExternal);
   1255         }
   1256 
   1257         // Send flush notifications to the cache. Each flush should purge the oldest resource.
   1258         for (int i = 0; i < kFlushCount; ++i) {
   1259             cache->notifyFlushOccurred(GrResourceCache::kExternal);
   1260             REPORTER_ASSERT(reporter, kFlushCount - i - 1 == cache->getResourceCount());
   1261             for (int j = 0; j < i; ++j) {
   1262                 GrUniqueKey k;
   1263                 make_unique_key<1>(&k, j);
   1264                 GrGpuResource* r = cache->findAndRefUniqueResource(k);
   1265                 REPORTER_ASSERT(reporter, !SkToBool(r));
   1266                 SkSafeUnref(r);
   1267             }
   1268         }
   1269 
   1270         REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
   1271         cache->purgeAllUnlocked();
   1272     }
   1273 
   1274     // Do a similar test but where we leave refs on some resources to prevent them from being
   1275     // purged.
   1276     {
   1277         GrGpuResource* refedResources[kFlushCount >> 1];
   1278         for (int i = 0; i < kFlushCount; ++i) {
   1279             TestResource* r = new TestResource(gpu);
   1280             GrUniqueKey k;
   1281             make_unique_key<1>(&k, i);
   1282             r->resourcePriv().setUniqueKey(k);
   1283             // Leave a ref on every other resource, beginning with the first.
   1284             if (SkToBool(i & 0x1)) {
   1285                 refedResources[i/2] = r;
   1286             } else {
   1287                 r->unref();
   1288             }
   1289             cache->notifyFlushOccurred(GrResourceCache::kExternal);
   1290         }
   1291 
   1292         for (int i = 0; i < kFlushCount; ++i) {
   1293             // Should get a resource purged every other flush.
   1294             cache->notifyFlushOccurred(GrResourceCache::kExternal);
   1295             REPORTER_ASSERT(reporter, kFlushCount - i/2 - 1 == cache->getResourceCount());
   1296         }
   1297 
   1298         // Unref all the resources that we kept refs on in the first loop.
   1299         for (int i = 0; i < kFlushCount >> 1; ++i) {
   1300             refedResources[i]->unref();
   1301         }
   1302 
   1303         // After kFlushCount + 1 flushes they all will have sat in the purgeable queue for
   1304         // kFlushCount full flushes.
   1305         for (int i = 0; i < kFlushCount + 1; ++i) {
   1306             REPORTER_ASSERT(reporter, kFlushCount >> 1 == cache->getResourceCount());
   1307             cache->notifyFlushOccurred(GrResourceCache::kExternal);
   1308         }
   1309         REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
   1310 
   1311         cache->purgeAllUnlocked();
   1312     }
   1313 
   1314     REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
   1315 
   1316     // Verify that calling flush() on a GrContext with nothing to do will not trigger resource
   1317     // eviction.
   1318     context->flush();
   1319     for (int i = 0; i < 10; ++i) {
   1320         TestResource* r = new TestResource(gpu);
   1321         GrUniqueKey k;
   1322         make_unique_key<1>(&k, i);
   1323         r->resourcePriv().setUniqueKey(k);
   1324         r->unref();
   1325     }
   1326     REPORTER_ASSERT(reporter, 10 == cache->getResourceCount());
   1327     for (int i = 0; i < 10 * kFlushCount; ++i) {
   1328         context->flush();
   1329     }
   1330     REPORTER_ASSERT(reporter, 10 == cache->getResourceCount());
   1331 }
   1332 
   1333 static void test_time_purge(skiatest::Reporter* reporter) {
   1334     Mock mock(1000000, 1000000);
   1335     GrContext* context = mock.context();
   1336     GrResourceCache* cache = mock.cache();
   1337     GrGpu* gpu = context->contextPriv().getGpu();
   1338 
   1339     static constexpr int kCnts[] = {1, 10, 1024};
   1340     auto nowish = []() {
   1341         // We sleep so that we ensure we get a value that is greater than the last call to
   1342         // GrStdSteadyClock::now().
   1343         std::this_thread::sleep_for(GrStdSteadyClock::duration(5));
   1344         auto result = GrStdSteadyClock::now();
   1345         // Also sleep afterwards so we don't get this value again.
   1346         std::this_thread::sleep_for(GrStdSteadyClock::duration(5));
   1347         return result;
   1348     };
   1349 
   1350     for (int cnt : kCnts) {
   1351         std::unique_ptr<GrStdSteadyClock::time_point[]> timeStamps(
   1352                 new GrStdSteadyClock::time_point[cnt]);
   1353         {
   1354             // Insert resources and get time points between each addition.
   1355             for (int i = 0; i < cnt; ++i) {
   1356                 TestResource* r = new TestResource(gpu);
   1357                 GrUniqueKey k;
   1358                 make_unique_key<1>(&k, i);
   1359                 r->resourcePriv().setUniqueKey(k);
   1360                 r->unref();
   1361                 timeStamps.get()[i] = nowish();
   1362             }
   1363 
   1364             // Purge based on the time points between resource additions. Each purge should remove
   1365             // the oldest resource.
   1366             for (int i = 0; i < cnt; ++i) {
   1367                 cache->purgeResourcesNotUsedSince(timeStamps[i]);
   1368                 REPORTER_ASSERT(reporter, cnt - i - 1 == cache->getResourceCount());
   1369                 for (int j = 0; j < i; ++j) {
   1370                     GrUniqueKey k;
   1371                     make_unique_key<1>(&k, j);
   1372                     GrGpuResource* r = cache->findAndRefUniqueResource(k);
   1373                     REPORTER_ASSERT(reporter, !SkToBool(r));
   1374                     SkSafeUnref(r);
   1375                 }
   1376             }
   1377 
   1378             REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
   1379             cache->purgeAllUnlocked();
   1380         }
   1381 
   1382         // Do a similar test but where we leave refs on some resources to prevent them from being
   1383         // purged.
   1384         {
   1385             std::unique_ptr<GrGpuResource* []> refedResources(new GrGpuResource*[cnt / 2]);
   1386             for (int i = 0; i < cnt; ++i) {
   1387                 TestResource* r = new TestResource(gpu);
   1388                 GrUniqueKey k;
   1389                 make_unique_key<1>(&k, i);
   1390                 r->resourcePriv().setUniqueKey(k);
   1391                 // Leave a ref on every other resource, beginning with the first.
   1392                 if (SkToBool(i & 0x1)) {
   1393                     refedResources.get()[i / 2] = r;
   1394                 } else {
   1395                     r->unref();
   1396                 }
   1397                 timeStamps.get()[i] = nowish();
   1398             }
   1399 
   1400             for (int i = 0; i < cnt; ++i) {
   1401                 // Should get a resource purged every other frame.
   1402                 cache->purgeResourcesNotUsedSince(timeStamps[i]);
   1403                 REPORTER_ASSERT(reporter, cnt - i / 2 - 1 == cache->getResourceCount());
   1404             }
   1405 
   1406             // Unref all the resources that we kept refs on in the first loop.
   1407             for (int i = 0; i < (cnt / 2); ++i) {
   1408                 refedResources.get()[i]->unref();
   1409                 cache->purgeResourcesNotUsedSince(nowish());
   1410                 REPORTER_ASSERT(reporter, cnt / 2 - i - 1 == cache->getResourceCount());
   1411             }
   1412 
   1413             cache->purgeAllUnlocked();
   1414         }
   1415 
   1416         REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
   1417 
   1418         // Verify that calling flush() on a GrContext with nothing to do will not trigger resource
   1419         // eviction
   1420         context->flush();
   1421         for (int i = 0; i < 10; ++i) {
   1422             TestResource* r = new TestResource(gpu);
   1423             GrUniqueKey k;
   1424             make_unique_key<1>(&k, i);
   1425             r->resourcePriv().setUniqueKey(k);
   1426             r->unref();
   1427         }
   1428         REPORTER_ASSERT(reporter, 10 == cache->getResourceCount());
   1429         context->flush();
   1430         REPORTER_ASSERT(reporter, 10 == cache->getResourceCount());
   1431         cache->purgeResourcesNotUsedSince(nowish());
   1432         REPORTER_ASSERT(reporter, 0 == cache->getResourceCount());
   1433     }
   1434 }
   1435 
   1436 static void test_partial_purge(skiatest::Reporter* reporter) {
   1437     Mock mock(6, 100);
   1438     GrContext* context = mock.context();
   1439     GrResourceCache* cache = mock.cache();
   1440     GrGpu* gpu = context->contextPriv().getGpu();
   1441 
   1442     enum TestsCase {
   1443         kOnlyScratch_TestCase = 0,
   1444         kPartialScratch_TestCase = 1,
   1445         kAllScratch_TestCase = 2,
   1446         kPartial_TestCase = 3,
   1447         kAll_TestCase = 4,
   1448         kNone_TestCase = 5,
   1449         kEndTests_TestCase = kNone_TestCase + 1
   1450     };
   1451 
   1452     for (int testCase = 0; testCase < kEndTests_TestCase; testCase++) {
   1453 
   1454         GrUniqueKey key1, key2, key3;
   1455         make_unique_key<0>(&key1, 1);
   1456         make_unique_key<0>(&key2, 2);
   1457         make_unique_key<0>(&key3, 3);
   1458 
   1459         // Add three unique resources to the cache.
   1460         TestResource *unique1 = new TestResource(gpu);
   1461         TestResource *unique2 = new TestResource(gpu);
   1462         TestResource *unique3 = new TestResource(gpu);
   1463 
   1464         unique1->resourcePriv().setUniqueKey(key1);
   1465         unique2->resourcePriv().setUniqueKey(key2);
   1466         unique3->resourcePriv().setUniqueKey(key3);
   1467 
   1468         unique1->setSize(10);
   1469         unique2->setSize(11);
   1470         unique3->setSize(12);
   1471 
   1472         // Add two scratch resources to the cache.
   1473         TestResource *scratch1 = TestResource::CreateScratch(gpu, SkBudgeted::kYes,
   1474                                                              TestResource::kA_SimulatedProperty);
   1475         TestResource *scratch2 = TestResource::CreateScratch(gpu, SkBudgeted::kYes,
   1476                                                              TestResource::kB_SimulatedProperty);
   1477         scratch1->setSize(13);
   1478         scratch2->setSize(14);
   1479 
   1480 
   1481         REPORTER_ASSERT(reporter, 5 == cache->getBudgetedResourceCount());
   1482         REPORTER_ASSERT(reporter, 60 == cache->getBudgetedResourceBytes());
   1483         REPORTER_ASSERT(reporter, 0 == cache->getPurgeableBytes());
   1484 
   1485         // Add resources to the purgeable queue
   1486         unique1->unref();
   1487         scratch1->unref();
   1488         unique2->unref();
   1489         scratch2->unref();
   1490         unique3->unref();
   1491 
   1492         REPORTER_ASSERT(reporter, 5 == cache->getBudgetedResourceCount());
   1493         REPORTER_ASSERT(reporter, 60 == cache->getBudgetedResourceBytes());
   1494         REPORTER_ASSERT(reporter, 60 == cache->getPurgeableBytes());
   1495 
   1496         switch(testCase) {
   1497             case kOnlyScratch_TestCase: {
   1498                 context->purgeUnlockedResources(14, true);
   1499                 REPORTER_ASSERT(reporter, 3 == cache->getBudgetedResourceCount());
   1500                 REPORTER_ASSERT(reporter, 33 == cache->getBudgetedResourceBytes());
   1501                 break;
   1502             }
   1503             case kPartialScratch_TestCase: {
   1504                 context->purgeUnlockedResources(3, true);
   1505                 REPORTER_ASSERT(reporter, 4 == cache->getBudgetedResourceCount());
   1506                 REPORTER_ASSERT(reporter, 47 == cache->getBudgetedResourceBytes());
   1507                 break;
   1508             }
   1509             case kAllScratch_TestCase: {
   1510                 context->purgeUnlockedResources(50, true);
   1511                 REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount());
   1512                 REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceBytes());
   1513                 break;
   1514             }
   1515             case kPartial_TestCase: {
   1516                 context->purgeUnlockedResources(13, false);
   1517                 REPORTER_ASSERT(reporter, 3 == cache->getBudgetedResourceCount());
   1518                 REPORTER_ASSERT(reporter, 37 == cache->getBudgetedResourceBytes());
   1519                 break;
   1520             }
   1521             case kAll_TestCase: {
   1522                 context->purgeUnlockedResources(50, false);
   1523                 REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount());
   1524                 REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceBytes());
   1525                 break;
   1526             }
   1527             case kNone_TestCase: {
   1528                 context->purgeUnlockedResources(0, true);
   1529                 context->purgeUnlockedResources(0, false);
   1530                 REPORTER_ASSERT(reporter, 5 == cache->getBudgetedResourceCount());
   1531                 REPORTER_ASSERT(reporter, 60 == cache->getBudgetedResourceBytes());
   1532                 REPORTER_ASSERT(reporter, 60 == cache->getPurgeableBytes());
   1533                 break;
   1534             }
   1535         };
   1536 
   1537         // ensure all are purged before the next
   1538         context->purgeAllUnlockedResources();
   1539         REPORTER_ASSERT(reporter, 0 == cache->getBudgetedResourceCount());
   1540         REPORTER_ASSERT(reporter, 0 == cache->getPurgeableBytes());
   1541 
   1542     }
   1543 }
   1544 
   1545 static void test_large_resource_count(skiatest::Reporter* reporter) {
   1546     // Set the cache size to double the resource count because we're going to create 2x that number
   1547     // resources, using two different key domains. Add a little slop to the bytes because we resize
   1548     // down to 1 byte after creating the resource.
   1549     static const int kResourceCnt = 2000;
   1550 
   1551     Mock mock(2 * kResourceCnt, 2 * kResourceCnt + 1000);
   1552     GrContext* context = mock.context();
   1553     GrResourceCache* cache = mock.cache();
   1554     GrGpu* gpu = context->contextPriv().getGpu();
   1555 
   1556     for (int i = 0; i < kResourceCnt; ++i) {
   1557         GrUniqueKey key1, key2;
   1558         make_unique_key<1>(&key1, i);
   1559         make_unique_key<2>(&key2, i);
   1560 
   1561         TestResource* resource;
   1562 
   1563         resource = new TestResource(gpu);
   1564         resource->resourcePriv().setUniqueKey(key1);
   1565         resource->setSize(1);
   1566         resource->unref();
   1567 
   1568         resource = new TestResource(gpu);
   1569         resource->resourcePriv().setUniqueKey(key2);
   1570         resource->setSize(1);
   1571         resource->unref();
   1572     }
   1573 
   1574     REPORTER_ASSERT(reporter, TestResource::NumAlive() == 2 * kResourceCnt);
   1575     REPORTER_ASSERT(reporter, cache->getPurgeableBytes() == 2 * kResourceCnt);
   1576     REPORTER_ASSERT(reporter, cache->getBudgetedResourceBytes() == 2 * kResourceCnt);
   1577     REPORTER_ASSERT(reporter, cache->getBudgetedResourceCount() == 2 * kResourceCnt);
   1578     REPORTER_ASSERT(reporter, cache->getResourceBytes() == 2 * kResourceCnt);
   1579     REPORTER_ASSERT(reporter, cache->getResourceCount() == 2 * kResourceCnt);
   1580     for (int i = 0; i < kResourceCnt; ++i) {
   1581         GrUniqueKey key1, key2;
   1582         make_unique_key<1>(&key1, i);
   1583         make_unique_key<2>(&key2, i);
   1584 
   1585         REPORTER_ASSERT(reporter, cache->hasUniqueKey(key1));
   1586         REPORTER_ASSERT(reporter, cache->hasUniqueKey(key2));
   1587     }
   1588 
   1589     cache->purgeAllUnlocked();
   1590     REPORTER_ASSERT(reporter, TestResource::NumAlive() == 0);
   1591     REPORTER_ASSERT(reporter, cache->getPurgeableBytes() == 0);
   1592     REPORTER_ASSERT(reporter, cache->getBudgetedResourceBytes() == 0);
   1593     REPORTER_ASSERT(reporter, cache->getBudgetedResourceCount() == 0);
   1594     REPORTER_ASSERT(reporter, cache->getResourceBytes() == 0);
   1595     REPORTER_ASSERT(reporter, cache->getResourceCount() == 0);
   1596 
   1597     for (int i = 0; i < kResourceCnt; ++i) {
   1598         GrUniqueKey key1, key2;
   1599         make_unique_key<1>(&key1, i);
   1600         make_unique_key<2>(&key2, i);
   1601 
   1602         REPORTER_ASSERT(reporter, !cache->hasUniqueKey(key1));
   1603         REPORTER_ASSERT(reporter, !cache->hasUniqueKey(key2));
   1604     }
   1605 }
   1606 
   1607 static void test_custom_data(skiatest::Reporter* reporter) {
   1608     GrUniqueKey key1, key2;
   1609     make_unique_key<0>(&key1, 1);
   1610     make_unique_key<0>(&key2, 2);
   1611     int foo = 4132;
   1612     key1.setCustomData(SkData::MakeWithCopy(&foo, sizeof(foo)));
   1613     REPORTER_ASSERT(reporter, *(int*) key1.getCustomData()->data() == 4132);
   1614     REPORTER_ASSERT(reporter, key2.getCustomData() == nullptr);
   1615 
   1616     // Test that copying a key also takes a ref on its custom data.
   1617     GrUniqueKey key3 = key1;
   1618     REPORTER_ASSERT(reporter, *(int*) key3.getCustomData()->data() == 4132);
   1619 }
   1620 
   1621 static void test_abandoned(skiatest::Reporter* reporter) {
   1622     Mock mock(10, 300);
   1623     GrContext* context = mock.context();
   1624     GrGpu* gpu = context->contextPriv().getGpu();
   1625 
   1626     sk_sp<GrGpuResource> resource(new TestResource(gpu));
   1627     context->abandonContext();
   1628 
   1629     REPORTER_ASSERT(reporter, resource->wasDestroyed());
   1630 
   1631     // Call all the public methods on resource in the abandoned state. They shouldn't crash.
   1632 
   1633     resource->uniqueID();
   1634     resource->getUniqueKey();
   1635     resource->wasDestroyed();
   1636     resource->gpuMemorySize();
   1637     resource->getContext();
   1638 
   1639     resource->abandon();
   1640     resource->resourcePriv().getScratchKey();
   1641     resource->resourcePriv().isBudgeted();
   1642     resource->resourcePriv().makeBudgeted();
   1643     resource->resourcePriv().makeUnbudgeted();
   1644     resource->resourcePriv().removeScratchKey();
   1645     GrUniqueKey key;
   1646     make_unique_key<0>(&key, 1);
   1647     resource->resourcePriv().setUniqueKey(key);
   1648     resource->resourcePriv().removeUniqueKey();
   1649 }
   1650 
   1651 static void test_tags(skiatest::Reporter* reporter) {
   1652 #ifdef SK_DEBUG
   1653     // We will insert 1 resource with tag "tag1", 2 with "tag2", and so on, up through kLastTagIdx.
   1654     static constexpr int kLastTagIdx = 10;
   1655     static constexpr int kNumResources = kLastTagIdx * (kLastTagIdx + 1) / 2;
   1656 
   1657     Mock mock(kNumResources, kNumResources * TestResource::kDefaultSize);
   1658     GrContext* context = mock.context();
   1659     GrResourceCache* cache = mock.cache();
   1660     GrGpu* gpu = context->contextPriv().getGpu();
   1661 
   1662     // tag strings are expected to be long lived
   1663     std::vector<SkString> tagStrings;
   1664 
   1665     SkString tagStr;
   1666     int tagIdx = 0;
   1667     int currTagCnt = 0;
   1668 
   1669     for (int i = 0; i < kNumResources; ++i, ++currTagCnt) {
   1670 
   1671         sk_sp<GrGpuResource> resource(new TestResource(gpu));
   1672         GrUniqueKey key;
   1673         if (currTagCnt == tagIdx) {
   1674             tagIdx += 1;
   1675             currTagCnt = 0;
   1676             tagStr.printf("tag%d", tagIdx);
   1677             tagStrings.emplace_back(tagStr);
   1678         }
   1679         make_unique_key<1>(&key, i, tagStrings.back().c_str());
   1680         resource->resourcePriv().setUniqueKey(key);
   1681     }
   1682     SkASSERT(kLastTagIdx == tagIdx);
   1683     SkASSERT(currTagCnt == kLastTagIdx);
   1684 
   1685     // Test i = 0 to exercise unused tag string.
   1686     for (int i = 0; i <= kLastTagIdx; ++i) {
   1687         tagStr.printf("tag%d", i);
   1688         REPORTER_ASSERT(reporter, cache->countUniqueKeysWithTag(tagStr.c_str()) == i);
   1689     }
   1690 #endif
   1691 }
   1692 
   1693 DEF_GPUTEST(ResourceCacheMisc, reporter, /* options */) {
   1694     // The below tests create their own mock contexts.
   1695     test_no_key(reporter);
   1696     test_purge_unlocked(reporter);
   1697     test_budgeting(reporter);
   1698     test_unbudgeted(reporter);
   1699     test_unbudgeted_to_scratch(reporter);
   1700     test_duplicate_unique_key(reporter);
   1701     test_duplicate_scratch_key(reporter);
   1702     test_remove_scratch_key(reporter);
   1703     test_scratch_key_consistency(reporter);
   1704     test_purge_invalidated(reporter);
   1705     test_cache_chained_purge(reporter);
   1706     test_resource_size_changed(reporter);
   1707     test_timestamp_wrap(reporter);
   1708     test_flush(reporter);
   1709     test_time_purge(reporter);
   1710     test_partial_purge(reporter);
   1711     test_large_resource_count(reporter);
   1712     test_custom_data(reporter);
   1713     test_abandoned(reporter);
   1714     test_tags(reporter);
   1715 }
   1716 
   1717 ////////////////////////////////////////////////////////////////////////////////
   1718 static sk_sp<GrTexture> make_normal_texture(GrResourceProvider* provider,
   1719                                             GrSurfaceFlags flags,
   1720                                             int width, int height,
   1721                                             int sampleCnt) {
   1722     GrSurfaceDesc desc;
   1723     desc.fFlags = flags;
   1724     desc.fOrigin = kTopLeft_GrSurfaceOrigin;
   1725     desc.fWidth = width;
   1726     desc.fHeight = height;
   1727     desc.fConfig = kRGBA_8888_GrPixelConfig;
   1728     desc.fSampleCnt = sampleCnt;
   1729 
   1730     return provider->createTexture(desc, SkBudgeted::kYes);
   1731 }
   1732 
   1733 static sk_sp<GrTextureProxy> make_mipmap_proxy(GrProxyProvider* proxyProvider,
   1734                                                GrSurfaceFlags flags,
   1735                                                int width, int height,
   1736                                                int sampleCnt) {
   1737     GrSurfaceDesc desc;
   1738     desc.fFlags = flags;
   1739     desc.fOrigin = (flags & kRenderTarget_GrSurfaceFlag) ? kBottomLeft_GrSurfaceOrigin
   1740                                                          : kTopLeft_GrSurfaceOrigin;
   1741     desc.fWidth = width;
   1742     desc.fHeight = height;
   1743     desc.fConfig = kRGBA_8888_GrPixelConfig;
   1744     desc.fSampleCnt = sampleCnt;
   1745 
   1746     return proxyProvider->createMipMapProxy(desc, SkBudgeted::kYes);
   1747 }
   1748 
   1749 // Exercise GrSurface::gpuMemorySize for different combos of MSAA, RT-only,
   1750 // Texture-only, both-RT-and-Texture and MIPmapped
   1751 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GPUMemorySize, reporter, ctxInfo) {
   1752     GrContext* context = ctxInfo.grContext();
   1753     GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();
   1754     GrResourceProvider* resourceProvider = context->contextPriv().resourceProvider();
   1755 
   1756     static const int kSize = 64;
   1757 
   1758     // Normal versions
   1759     {
   1760         sk_sp<GrTexture> tex;
   1761 
   1762         tex = make_normal_texture(resourceProvider, kRenderTarget_GrSurfaceFlag, kSize, kSize, 1);
   1763         size_t size = tex->gpuMemorySize();
   1764         REPORTER_ASSERT(reporter, kSize*kSize*4 == size);
   1765 
   1766         size_t sampleCount =
   1767                 (size_t)context->caps()->getRenderTargetSampleCount(4, kRGBA_8888_GrPixelConfig);
   1768         if (sampleCount >= 4) {
   1769             tex = make_normal_texture(resourceProvider, kRenderTarget_GrSurfaceFlag, kSize, kSize,
   1770                                       sampleCount);
   1771             size = tex->gpuMemorySize();
   1772             REPORTER_ASSERT(reporter,
   1773                             kSize*kSize*4 == size ||                  // msaa4 failed
   1774                             kSize*kSize*4*sampleCount == size ||      // auto-resolving
   1775                             kSize*kSize*4*(sampleCount+1) == size);   // explicit resolve buffer
   1776         }
   1777 
   1778         tex = make_normal_texture(resourceProvider, kNone_GrSurfaceFlags, kSize, kSize, 1);
   1779         size = tex->gpuMemorySize();
   1780         REPORTER_ASSERT(reporter, kSize*kSize*4 == size);
   1781     }
   1782 
   1783 
   1784     // Mipmapped versions
   1785     if (context->caps()->mipMapSupport()) {
   1786         sk_sp<GrTextureProxy> proxy;
   1787 
   1788         proxy = make_mipmap_proxy(proxyProvider, kRenderTarget_GrSurfaceFlag, kSize, kSize, 1);
   1789         size_t size = proxy->gpuMemorySize();
   1790         REPORTER_ASSERT(reporter, kSize*kSize*4+(kSize*kSize*4)/3 == size);
   1791 
   1792         size_t sampleCount =
   1793                 (size_t)context->caps()->getRenderTargetSampleCount(4, kRGBA_8888_GrPixelConfig);
   1794         if (sampleCount >= 4) {
   1795             proxy = make_mipmap_proxy(proxyProvider, kRenderTarget_GrSurfaceFlag, kSize, kSize,
   1796                                       sampleCount);
   1797             size = proxy->gpuMemorySize();
   1798             REPORTER_ASSERT(reporter,
   1799                kSize*kSize*4+(kSize*kSize*4)/3 == size ||                 // msaa4 failed
   1800                kSize*kSize*4*sampleCount+(kSize*kSize*4)/3 == size ||     // auto-resolving
   1801                kSize*kSize*4*(sampleCount+1)+(kSize*kSize*4)/3 == size);  // explicit resolve buffer
   1802         }
   1803 
   1804         proxy = make_mipmap_proxy(proxyProvider, kNone_GrSurfaceFlags, kSize, kSize, 1);
   1805         size = proxy->gpuMemorySize();
   1806         REPORTER_ASSERT(reporter, kSize*kSize*4+(kSize*kSize*4)/3 == size);
   1807     }
   1808 }
   1809 
   1810 #endif
   1811