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 #include "SkCachedData.h" 9 #include "SkDiscardableMemoryPool.h" 10 #include "SkMalloc.h" 11 #include "SkRefCnt.h" 12 #include "SkTypes.h" 13 #include "Test.h" 14 15 #include <cstring> 16 17 class SkDiscardableMemory; 18 19 enum LockedState { 20 kUnlocked, 21 kLocked, 22 }; 23 24 enum CachedState { 25 kNotInCache, 26 kInCache, 27 }; 28 29 static void check_data(skiatest::Reporter* reporter, SkCachedData* data, 30 int refcnt, CachedState cacheState, LockedState lockedState) { 31 REPORTER_ASSERT(reporter, data->testing_only_getRefCnt() == refcnt); 32 REPORTER_ASSERT(reporter, data->testing_only_isInCache() == (kInCache == cacheState)); 33 REPORTER_ASSERT(reporter, data->testing_only_isLocked() == (lockedState == kLocked)); 34 } 35 36 static SkCachedData* make_data(size_t size, SkDiscardableMemoryPool* pool) { 37 if (pool) { 38 SkDiscardableMemory* dm = pool->create(size); 39 // the pool "can" return null, but it shouldn't in these controlled conditions 40 SkASSERT_RELEASE(dm); 41 return new SkCachedData(size, dm); 42 } else { 43 return new SkCachedData(sk_malloc_throw(size), size); 44 } 45 } 46 47 // returns with the data locked by client and cache 48 static SkCachedData* test_locking(skiatest::Reporter* reporter, 49 size_t size, SkDiscardableMemoryPool* pool) { 50 SkCachedData* data = make_data(size, pool); 51 52 memset(data->writable_data(), 0x80, size); // just to use writable_data() 53 54 check_data(reporter, data, 1, kNotInCache, kLocked); 55 56 data->ref(); 57 check_data(reporter, data, 2, kNotInCache, kLocked); 58 data->unref(); 59 check_data(reporter, data, 1, kNotInCache, kLocked); 60 61 data->attachToCacheAndRef(); 62 check_data(reporter, data, 2, kInCache, kLocked); 63 64 data->unref(); 65 check_data(reporter, data, 1, kInCache, kUnlocked); 66 67 data->ref(); 68 check_data(reporter, data, 2, kInCache, kLocked); 69 70 return data; 71 } 72 73 /* 74 * SkCachedData behaves differently (regarding its locked/unlocked state) depending on 75 * when it is in the cache or not. Being in the cache is signaled by calling attachToCacheAndRef() 76 * instead of ref(). (and balanced by detachFromCacheAndUnref). 77 * 78 * Thus, among other things, we test the end-of-life behavior when the client is the last owner 79 * and when the cache is. 80 */ 81 DEF_TEST(CachedData, reporter) { 82 sk_sp<SkDiscardableMemoryPool> pool(SkDiscardableMemoryPool::Make(1000)); 83 84 for (int useDiscardable = 0; useDiscardable <= 1; ++useDiscardable) { 85 const size_t size = 100; 86 87 // test with client as last owner 88 SkCachedData* data = test_locking(reporter, size, useDiscardable ? pool.get() : nullptr); 89 check_data(reporter, data, 2, kInCache, kLocked); 90 data->detachFromCacheAndUnref(); 91 check_data(reporter, data, 1, kNotInCache, kLocked); 92 data->unref(); 93 94 // test with cache as last owner 95 data = test_locking(reporter, size, useDiscardable ? pool.get() : nullptr); 96 check_data(reporter, data, 2, kInCache, kLocked); 97 data->unref(); 98 check_data(reporter, data, 1, kInCache, kUnlocked); 99 data->detachFromCacheAndUnref(); 100 } 101 } 102