• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 class SkDiscardableMemory;
18 
19 enum LockedState {
20     kUnlocked,
21     kLocked,
22 };
23 
24 enum CachedState {
25     kNotInCache,
26     kInCache,
27 };
28 
check_data(skiatest::Reporter * reporter,SkCachedData * data,int refcnt,CachedState cacheState,LockedState lockedState)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 
make_data(size_t size,SkDiscardableMemoryPool * pool)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
test_locking(skiatest::Reporter * reporter,size_t size,SkDiscardableMemoryPool * pool)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  */
DEF_TEST(CachedData,reporter)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