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 "include/core/SkRefCnt.h" 9#include "include/core/SkTypes.h" 10#include "include/private/SkMalloc.h" 11#include "src/core/SkCachedData.h" 12#include "src/lazy/SkDiscardableMemoryPool.h" 13#include "tests/Test.h" 14 15#include <cstring> 16 17class SkDiscardableMemory; 18 19enum LockedState { 20 kUnlocked, 21 kLocked, 22}; 23 24enum CachedState { 25 kNotInCache, 26 kInCache, 27}; 28 29static 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 36static 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 48static 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 */ 81DEF_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