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 "include/core/SkRefCnt.h"
9 #include "include/core/SkTypes.h"
10 #include "include/private/chromium/SkDiscardableMemory.h"
11 #include "src/core/SkResourceCache.h"
12 #include "src/lazy/SkDiscardableMemoryPool.h"
13 #include "tests/Test.h"
14
15 #include <cstddef>
16 #include <cstdint>
17
18 namespace {
19 static void* gGlobalAddress;
20 struct TestingKey : public SkResourceCache::Key {
21 intptr_t fValue;
22
TestingKey__anonbb93fe480111::TestingKey23 TestingKey(intptr_t value, uint64_t sharedID = 0) : fValue(value) {
24 this->init(&gGlobalAddress, sharedID, sizeof(fValue));
25 }
26 };
27 struct TestingRec : public SkResourceCache::Rec {
TestingRec__anonbb93fe480111::TestingRec28 TestingRec(const TestingKey& key, uint32_t value) : fKey(key), fValue(value) {}
29
30 TestingKey fKey;
31 intptr_t fValue;
32
getKey__anonbb93fe480111::TestingRec33 const Key& getKey() const override { return fKey; }
bytesUsed__anonbb93fe480111::TestingRec34 size_t bytesUsed() const override { return sizeof(fKey) + sizeof(fValue); }
getCategory__anonbb93fe480111::TestingRec35 const char* getCategory() const override { return "test_cache"; }
diagnostic_only_getDiscardable__anonbb93fe480111::TestingRec36 SkDiscardableMemory* diagnostic_only_getDiscardable() const override { return nullptr; }
37
Visitor__anonbb93fe480111::TestingRec38 static bool Visitor(const SkResourceCache::Rec& baseRec, void* context) {
39 const TestingRec& rec = static_cast<const TestingRec&>(baseRec);
40 intptr_t* result = (intptr_t*)context;
41
42 *result = rec.fValue;
43 return true;
44 }
45 };
46 } // namespace
47
48 static const int COUNT = 10;
49 static const int DIM = 256;
50
test_cache(skiatest::Reporter * reporter,SkResourceCache & cache,bool testPurge)51 static void test_cache(skiatest::Reporter* reporter, SkResourceCache& cache, bool testPurge) {
52 for (int i = 0; i < COUNT; ++i) {
53 TestingKey key(i);
54 intptr_t value = -1;
55
56 REPORTER_ASSERT(reporter, !cache.find(key, TestingRec::Visitor, &value));
57 REPORTER_ASSERT(reporter, -1 == value);
58
59 cache.add(new TestingRec(key, i));
60
61 REPORTER_ASSERT(reporter, cache.find(key, TestingRec::Visitor, &value));
62 REPORTER_ASSERT(reporter, i == value);
63 }
64
65 if (testPurge) {
66 // stress test, should trigger purges
67 for (int i = 0; i < COUNT * 100; ++i) {
68 TestingKey key(i);
69 cache.add(new TestingRec(key, i));
70 }
71 }
72
73 // test the originals after all that purging
74 for (int i = 0; i < COUNT; ++i) {
75 intptr_t value;
76 (void)cache.find(TestingKey(i), TestingRec::Visitor, &value);
77 }
78
79 cache.setTotalByteLimit(0);
80 }
81
test_cache_purge_shared_id(skiatest::Reporter * reporter,SkResourceCache & cache)82 static void test_cache_purge_shared_id(skiatest::Reporter* reporter, SkResourceCache& cache) {
83 for (int i = 0; i < COUNT; ++i) {
84 TestingKey key(i, i & 1); // every other key will have a 1 for its sharedID
85 cache.add(new TestingRec(key, i));
86 }
87
88 // Ensure that everyone is present
89 for (int i = 0; i < COUNT; ++i) {
90 TestingKey key(i, i & 1); // every other key will have a 1 for its sharedID
91 intptr_t value = -1;
92
93 REPORTER_ASSERT(reporter, cache.find(key, TestingRec::Visitor, &value));
94 REPORTER_ASSERT(reporter, value == i);
95 }
96
97 // Now purge the ones that had a non-zero sharedID (the odd-indexed ones)
98 cache.purgeSharedID(1);
99
100 // Ensure that only the even ones are still present
101 for (int i = 0; i < COUNT; ++i) {
102 TestingKey key(i, i & 1); // every other key will have a 1 for its sharedID
103 intptr_t value = -1;
104
105 if (i & 1) {
106 REPORTER_ASSERT(reporter, !cache.find(key, TestingRec::Visitor, &value));
107 } else {
108 REPORTER_ASSERT(reporter, cache.find(key, TestingRec::Visitor, &value));
109 REPORTER_ASSERT(reporter, value == i);
110 }
111 }
112 }
113
114 static SkDiscardableMemoryPool* gPool;
pool_factory(size_t bytes)115 static SkDiscardableMemory* pool_factory(size_t bytes) {
116 SkASSERT(gPool);
117 return gPool->create(bytes);
118 }
119
DEF_TEST(ImageCache,reporter)120 DEF_TEST(ImageCache, reporter) {
121 static const size_t defLimit = DIM * DIM * 4 * COUNT + 1024; // 1K slop
122
123 {
124 SkResourceCache cache(defLimit);
125 test_cache(reporter, cache, true);
126 }
127 {
128 sk_sp<SkDiscardableMemoryPool> pool(SkDiscardableMemoryPool::Make(defLimit));
129 gPool = pool.get();
130 SkResourceCache cache(pool_factory);
131 test_cache(reporter, cache, true);
132 }
133 {
134 SkResourceCache cache(SkDiscardableMemory::Create);
135 test_cache(reporter, cache, false);
136 }
137 {
138 SkResourceCache cache(defLimit);
139 test_cache_purge_shared_id(reporter, cache);
140 }
141 }
142
DEF_TEST(ImageCache_doubleAdd,r)143 DEF_TEST(ImageCache_doubleAdd, r) {
144 // Adding the same key twice should be safe.
145 SkResourceCache cache(4096);
146
147 TestingKey key(1);
148
149 cache.add(new TestingRec(key, 2));
150 cache.add(new TestingRec(key, 3));
151
152 // Lookup can return either value.
153 intptr_t value = -1;
154 REPORTER_ASSERT(r, cache.find(key, TestingRec::Visitor, &value));
155 REPORTER_ASSERT(r, 2 == value || 3 == value);
156 }
157