Home | History | Annotate | Download | only in tests
      1 /*
      2 * Copyright 2014 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 #if SK_SUPPORT_GPU
      9 
     10 #include "GrContext.h"
     11 #include "GrLayerCache.h"
     12 #include "GrResourceCache.h"
     13 #include "SkPictureRecorder.h"
     14 #include "Test.h"
     15 
     16 class TestingAccess {
     17 public:
     18     static int NumPlots() {
     19         return GrLayerCache::kNumPlotsX * GrLayerCache::kNumPlotsY;
     20     }
     21     static SkISize PlotSize() {
     22         return SkISize::Make(GrLayerCache::kAtlasTextureWidth / GrLayerCache::kNumPlotsX,
     23                              GrLayerCache::kAtlasTextureHeight / GrLayerCache::kNumPlotsY);
     24     }
     25 
     26     static GrTexture* GetBackingTexture(GrLayerCache* cache) {
     27         return cache->fAtlas->getTextureOrNull();
     28     }
     29 
     30     static int NumLayers(GrLayerCache* cache) {
     31         return cache->numLayers();
     32     }
     33     static void Purge(GrLayerCache* cache, uint32_t pictureID) {
     34         cache->purge(pictureID);
     35     }
     36     static int Uses(GrCachedLayer* layer) {
     37         return layer->uses();
     38     }
     39     static GrCachedLayer* Find(GrLayerCache* cache, uint32_t pictureID,
     40                                const SkMatrix& initialMat,
     41                                const int* key, int keySize) {
     42         return cache->findLayer(pictureID, initialMat, key, keySize);
     43     }
     44 };
     45 
     46 // Add several layers to the cache
     47 static void create_layers(skiatest::Reporter* reporter,
     48                           GrLayerCache* cache,
     49                           const SkPicture& picture,
     50                           int numToAdd,
     51                           int idOffset) {
     52 
     53     for (int i = 0; i < numToAdd; ++i) {
     54         int key[1] = { idOffset+i+1 };
     55         GrCachedLayer* layer = cache->findLayerOrCreate(picture.uniqueID(),
     56                                                         idOffset+i+1, idOffset+i+2,
     57                                                         SkIRect::MakeEmpty(),
     58                                                         SkIRect::MakeEmpty(),
     59                                                         SkMatrix::I(),
     60                                                         key, 1,
     61                                                         nullptr);
     62         REPORTER_ASSERT(reporter, layer);
     63         GrCachedLayer* temp = TestingAccess::Find(cache, picture.uniqueID(), SkMatrix::I(),
     64                                                   key, 1);
     65         REPORTER_ASSERT(reporter, temp == layer);
     66 
     67         REPORTER_ASSERT(reporter, TestingAccess::NumLayers(cache) == idOffset + i + 1);
     68 
     69         REPORTER_ASSERT(reporter, picture.uniqueID() == layer->pictureID());
     70         REPORTER_ASSERT(reporter, layer->start() == idOffset + i + 1);
     71         REPORTER_ASSERT(reporter, layer->stop() == idOffset + i + 2);
     72         REPORTER_ASSERT(reporter, nullptr == layer->texture());
     73         REPORTER_ASSERT(reporter, nullptr == layer->paint());
     74         REPORTER_ASSERT(reporter, !layer->isAtlased());
     75     }
     76 }
     77 
     78 static void lock_layer(skiatest::Reporter* reporter,
     79                        GrLayerCache* cache,
     80                        GrCachedLayer* layer) {
     81     // Make each layer big enough to consume one whole plot in the atlas
     82     GrSurfaceDesc desc;
     83     desc.fFlags = kRenderTarget_GrSurfaceFlag;
     84     desc.fWidth = TestingAccess::PlotSize().fWidth;
     85     desc.fHeight = TestingAccess::PlotSize().fHeight;
     86     desc.fConfig = kSkia8888_GrPixelConfig;
     87 
     88     bool needsRerendering;
     89     bool inAtlas = cache->tryToAtlas(layer, desc, &needsRerendering);
     90     if (!inAtlas) {
     91         cache->lock(layer, desc, &needsRerendering);
     92     }
     93     REPORTER_ASSERT(reporter, needsRerendering);
     94 
     95     cache->lock(layer, desc, &needsRerendering);
     96     REPORTER_ASSERT(reporter, !needsRerendering);
     97 
     98     REPORTER_ASSERT(reporter, layer->texture());
     99     REPORTER_ASSERT(reporter, layer->locked());
    100 
    101     cache->addUse(layer);
    102 
    103     REPORTER_ASSERT(reporter, 1 == TestingAccess::Uses(layer));
    104 }
    105 
    106 // This test case exercises the public API of the GrLayerCache class.
    107 // In particular it checks its interaction with the resource cache (w.r.t.
    108 // locking & unlocking textures).
    109 // TODO: need to add checks on VRAM usage!
    110 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(GpuLayerCache, reporter, context) {
    111     // Add one more layer than can fit in the atlas
    112     static const int kInitialNumLayers = TestingAccess::NumPlots() + 1;
    113 
    114 #if GR_CACHE_STATS
    115     GrResourceCache::Stats stats;
    116 #endif
    117 
    118     SkAutoTUnref<const SkPicture> picture;
    119 
    120     {
    121         SkPictureRecorder recorder;
    122         SkCanvas* c = recorder.beginRecording(1, 1);
    123         // Draw something, anything, to prevent an empty-picture optimization,
    124         // which is a singleton and never purged.
    125         c->drawRect(SkRect::MakeWH(1,1), SkPaint());
    126         picture.reset(recorder.endRecording());
    127     }
    128 
    129     GrResourceCache* resourceCache = context->getResourceCache();
    130 
    131     GrLayerCache cache(context);
    132 
    133     create_layers(reporter, &cache, *picture, kInitialNumLayers, 0);
    134 
    135     for (int i = 0; i < kInitialNumLayers; ++i) {
    136         int key[1] = { i + 1 };
    137         GrCachedLayer* layer = TestingAccess::Find(&cache, picture->uniqueID(), SkMatrix::I(),
    138                                                    key, 1);
    139         REPORTER_ASSERT(reporter, layer);
    140 
    141         lock_layer(reporter, &cache, layer);
    142 
    143 #if GR_CACHE_STATS
    144         resourceCache->getStats(&stats);
    145 #endif
    146 
    147         // The first 4 layers should be in the atlas (and thus have non-empty rects)
    148         if (i < TestingAccess::NumPlots()) {
    149             REPORTER_ASSERT(reporter, layer->isAtlased());
    150 #if GR_CACHE_STATS
    151             REPORTER_ASSERT(reporter, 1 == stats.fTotal);
    152 #endif
    153         } else {
    154             // The 5th layer couldn't fit in the atlas
    155             REPORTER_ASSERT(reporter, !layer->isAtlased());
    156 #if GR_CACHE_STATS
    157             REPORTER_ASSERT(reporter, 2 == stats.fTotal);
    158 #endif
    159         }
    160     }
    161 
    162     // Unlock the textures
    163     for (int i = 0; i < kInitialNumLayers; ++i) {
    164         int key[1] = { i+1 };
    165 
    166         GrCachedLayer* layer = TestingAccess::Find(&cache, picture->uniqueID(), SkMatrix::I(),
    167                                                    key, 1);
    168         REPORTER_ASSERT(reporter, layer);
    169         cache.removeUse(layer);
    170     }
    171 
    172 #if GR_CACHE_STATS
    173     resourceCache->getStats(&stats);
    174     REPORTER_ASSERT(reporter, 2 == stats.fTotal);
    175     // The floating layer is purgeable the cache is not
    176     REPORTER_ASSERT(reporter, 1 == stats.fNumPurgeable);
    177     REPORTER_ASSERT(reporter, 1 == stats.fNumNonPurgeable);
    178 #endif
    179 
    180     for (int i = 0; i < kInitialNumLayers; ++i) {
    181         int key[1] = { i+1 };
    182 
    183         GrCachedLayer* layer = TestingAccess::Find(&cache, picture->uniqueID(), SkMatrix::I(),
    184                                                    key, 1);
    185         REPORTER_ASSERT(reporter, layer);
    186 
    187         // All the layers should be unlocked
    188         REPORTER_ASSERT(reporter, !layer->locked());
    189 
    190         // When hoisted layers aren't cached they are aggressively removed
    191         // from the atlas
    192 #if GR_CACHE_HOISTED_LAYERS
    193         // The first 4 layers should still be in the atlas.
    194         if (i < 4) {
    195             REPORTER_ASSERT(reporter, layer->texture());
    196             REPORTER_ASSERT(reporter, layer->isAtlased());
    197         } else {
    198 #endif
    199             // The final layer should not be atlased.
    200             REPORTER_ASSERT(reporter, nullptr == layer->texture());
    201             REPORTER_ASSERT(reporter, !layer->isAtlased());
    202 #if GR_CACHE_HOISTED_LAYERS
    203         }
    204 #endif
    205     }
    206 
    207     // Let go of the backing texture
    208     cache.end();
    209     REPORTER_ASSERT(reporter, nullptr == TestingAccess::GetBackingTexture(&cache));
    210 
    211 #if GR_CACHE_STATS
    212     resourceCache->getStats(&stats);
    213     REPORTER_ASSERT(reporter, 2 == stats.fTotal);
    214     // Now both the floater and the atlas are purgeable
    215     REPORTER_ASSERT(reporter, 2 == stats.fNumPurgeable);
    216 #endif
    217 
    218     // re-attach to the backing texture
    219     cache.begin();
    220     REPORTER_ASSERT(reporter, TestingAccess::GetBackingTexture(&cache));
    221 
    222 #if GR_CACHE_STATS
    223     resourceCache->getStats(&stats);
    224     REPORTER_ASSERT(reporter, 2 == stats.fTotal);
    225     // The atlas is restored to being non-purgeable
    226     REPORTER_ASSERT(reporter, 1 == stats.fNumPurgeable);
    227     REPORTER_ASSERT(reporter, 1 == stats.fNumNonPurgeable);
    228 #endif
    229 
    230     {
    231         int key[1] = { kInitialNumLayers+1 };
    232 
    233         // Add an additional layer. Since all the layers are unlocked this
    234         // will force out the first atlased layer
    235         create_layers(reporter, &cache, *picture, 1, kInitialNumLayers);
    236         GrCachedLayer* layer = TestingAccess::Find(&cache, picture->uniqueID(), SkMatrix::I(),
    237                                                    key, 1);
    238         REPORTER_ASSERT(reporter, layer);
    239 
    240         lock_layer(reporter, &cache, layer);
    241         cache.removeUse(layer);
    242     }
    243 
    244     for (int i = 0; i < kInitialNumLayers+1; ++i) {
    245         int key[1] = { i+1 };
    246 
    247         GrCachedLayer* layer = TestingAccess::Find(&cache, picture->uniqueID(), SkMatrix::I(),
    248                                                    key, 1);
    249 #if GR_CACHE_HOISTED_LAYERS
    250         // 3 old layers plus the new one should be in the atlas.
    251         if (1 == i || 2 == i || 3 == i || 5 == i) {
    252             REPORTER_ASSERT(reporter, layer);
    253             REPORTER_ASSERT(reporter, !layer->locked());
    254             REPORTER_ASSERT(reporter, layer->texture());
    255             REPORTER_ASSERT(reporter, layer->isAtlased());
    256         } else if (4 == i) {
    257 #endif
    258             // The one that was never atlased should still be around
    259             REPORTER_ASSERT(reporter, layer);
    260 
    261             REPORTER_ASSERT(reporter, nullptr == layer->texture());
    262             REPORTER_ASSERT(reporter, !layer->isAtlased());
    263 #if GR_CACHE_HOISTED_LAYERS
    264         } else {
    265             // The one bumped out of the atlas (i.e., 0) should be gone
    266             REPORTER_ASSERT(reporter, nullptr == layer);
    267         }
    268 #endif
    269     }
    270 
    271     //--------------------------------------------------------------------
    272     // Free them all SkGpuDevice-style. This will not free up the
    273     // atlas' texture but will eliminate all the layers.
    274     TestingAccess::Purge(&cache, picture->uniqueID());
    275 
    276     REPORTER_ASSERT(reporter, TestingAccess::NumLayers(&cache) == 0);
    277 
    278 #if GR_CACHE_STATS
    279     resourceCache->getStats(&stats);
    280     REPORTER_ASSERT(reporter, 2 == stats.fTotal);
    281     // Atlas isn't purgeable
    282     REPORTER_ASSERT(reporter, 1 == stats.fNumPurgeable);
    283     REPORTER_ASSERT(reporter, 1 == stats.fNumNonPurgeable);
    284 #endif
    285 
    286     //--------------------------------------------------------------------
    287     // Test out the GrContext-style purge. This should remove all the layers
    288     // and the atlas.
    289     // Re-create the layers
    290     create_layers(reporter, &cache, *picture, kInitialNumLayers, 0);
    291 
    292     // Free them again GrContext-style. This should free up everything.
    293     cache.freeAll();
    294 
    295     REPORTER_ASSERT(reporter, TestingAccess::NumLayers(&cache) == 0);
    296 
    297     REPORTER_ASSERT(reporter, nullptr == TestingAccess::GetBackingTexture(&cache));
    298 
    299 #if GR_CACHE_STATS
    300     resourceCache->getStats(&stats);
    301     REPORTER_ASSERT(reporter, 2 == stats.fTotal);
    302     REPORTER_ASSERT(reporter, 2 == stats.fNumPurgeable);
    303 #endif
    304 
    305     // Purge the resource cache ...
    306     resourceCache->purgeAllUnlocked();
    307 
    308 #if GR_CACHE_STATS
    309     resourceCache->getStats(&stats);
    310     REPORTER_ASSERT(reporter, 0 == stats.fTotal);
    311 #endif
    312 
    313     // and try to re-attach to the backing texture. This should fail
    314     cache.begin();
    315     REPORTER_ASSERT(reporter, nullptr == TestingAccess::GetBackingTexture(&cache));
    316 
    317     //--------------------------------------------------------------------
    318     // Test out the MessageBus-style purge. This will not free the atlas
    319     // but should eliminate the free-floating layers.
    320     create_layers(reporter, &cache, *picture, kInitialNumLayers, 0);
    321 
    322     // Allocate/use the layers
    323     for (int i = 0; i < kInitialNumLayers; ++i) {
    324         int key[1] = { i + 1 };
    325         GrCachedLayer* layer = TestingAccess::Find(&cache, picture->uniqueID(), SkMatrix::I(),
    326                                                    key, 1);
    327         REPORTER_ASSERT(reporter, layer);
    328 
    329         lock_layer(reporter, &cache, layer);
    330     }
    331 
    332 #if GR_CACHE_STATS
    333     resourceCache->getStats(&stats);
    334     REPORTER_ASSERT(reporter, 2 == stats.fTotal);
    335     REPORTER_ASSERT(reporter, 2 == stats.fNumNonPurgeable);
    336 #endif
    337 
    338     // Unlock the textures
    339     for (int i = 0; i < kInitialNumLayers; ++i) {
    340         int key[1] = { i+1 };
    341 
    342         GrCachedLayer* layer = TestingAccess::Find(&cache, picture->uniqueID(), SkMatrix::I(),
    343                                                    key, 1);
    344         REPORTER_ASSERT(reporter, layer);
    345         cache.removeUse(layer);
    346     }
    347 
    348     picture.reset(nullptr);
    349     cache.processDeletedPictures();
    350 
    351     REPORTER_ASSERT(reporter, TestingAccess::NumLayers(&cache) == 0);
    352 
    353 #if GR_CACHE_STATS
    354     resourceCache->getStats(&stats);
    355     REPORTER_ASSERT(reporter, 2 == stats.fTotal);
    356     REPORTER_ASSERT(reporter, 1 == stats.fNumPurgeable);
    357     REPORTER_ASSERT(reporter, 1 == stats.fNumNonPurgeable);
    358 #endif
    359 
    360     cache.end();
    361 
    362 #if GR_CACHE_STATS
    363     resourceCache->getStats(&stats);
    364     REPORTER_ASSERT(reporter, 2 == stats.fTotal);
    365     REPORTER_ASSERT(reporter, 2 == stats.fNumPurgeable);
    366 #endif
    367 }
    368 
    369 #endif
    370