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