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 "SkDiscardableMemory.h"
9#include "SkResourceCache.h"
10#include "Test.h"
11
12namespace {
13static void* gGlobalAddress;
14struct TestingKey : public SkResourceCache::Key {
15    void*       fPtr;
16    intptr_t    fValue;
17
18    TestingKey(intptr_t value) : fPtr(&gGlobalAddress), fValue(value) {
19        this->init(sizeof(fPtr) + sizeof(fValue));
20    }
21};
22struct TestingRec : public SkResourceCache::Rec {
23    TestingRec(const TestingKey& key, uint32_t value) : fKey(key), fValue(value) {}
24
25    TestingKey  fKey;
26    intptr_t    fValue;
27
28    virtual const Key& getKey() const SK_OVERRIDE { return fKey; }
29    virtual size_t bytesUsed() const SK_OVERRIDE { return sizeof(fKey) + sizeof(fValue); }
30
31    static bool Visitor(const SkResourceCache::Rec& baseRec, void* context) {
32        const TestingRec& rec = static_cast<const TestingRec&>(baseRec);
33        intptr_t* result = (intptr_t*)context;
34
35        *result = rec.fValue;
36        return true;
37    }
38};
39}
40
41static const int COUNT = 10;
42static const int DIM = 256;
43
44static void test_cache(skiatest::Reporter* reporter, SkResourceCache& cache, bool testPurge) {
45    for (int i = 0; i < COUNT; ++i) {
46        TestingKey key(i);
47        intptr_t value = -1;
48
49        REPORTER_ASSERT(reporter, !cache.find(key, TestingRec::Visitor, &value));
50        REPORTER_ASSERT(reporter, -1 == value);
51
52        cache.add(SkNEW_ARGS(TestingRec, (key, i)));
53
54        REPORTER_ASSERT(reporter, cache.find(key, TestingRec::Visitor, &value));
55        REPORTER_ASSERT(reporter, i == value);
56    }
57
58    if (testPurge) {
59        // stress test, should trigger purges
60        for (size_t i = 0; i < COUNT * 100; ++i) {
61            TestingKey key(i);
62            cache.add(SkNEW_ARGS(TestingRec, (key, i)));
63        }
64    }
65
66    // test the originals after all that purging
67    for (int i = 0; i < COUNT; ++i) {
68        intptr_t value;
69        (void)cache.find(TestingKey(i), TestingRec::Visitor, &value);
70    }
71
72    cache.setTotalByteLimit(0);
73}
74
75#include "SkDiscardableMemoryPool.h"
76
77static SkDiscardableMemoryPool* gPool;
78static SkDiscardableMemory* pool_factory(size_t bytes) {
79    SkASSERT(gPool);
80    return gPool->create(bytes);
81}
82
83DEF_TEST(ImageCache, reporter) {
84    static const size_t defLimit = DIM * DIM * 4 * COUNT + 1024;    // 1K slop
85
86    {
87        SkResourceCache cache(defLimit);
88        test_cache(reporter, cache, true);
89    }
90    {
91        SkAutoTUnref<SkDiscardableMemoryPool> pool(
92                SkDiscardableMemoryPool::Create(defLimit, NULL));
93        gPool = pool.get();
94        SkResourceCache cache(pool_factory);
95        test_cache(reporter, cache, true);
96    }
97    {
98        SkResourceCache cache(SkDiscardableMemory::Create);
99        test_cache(reporter, cache, false);
100    }
101}
102
103DEF_TEST(ImageCache_doubleAdd, r) {
104    // Adding the same key twice should be safe.
105    SkResourceCache cache(4096);
106
107    TestingKey key(1);
108
109    cache.add(SkNEW_ARGS(TestingRec, (key, 2)));
110    cache.add(SkNEW_ARGS(TestingRec, (key, 3)));
111
112    // Lookup can return either value.
113    intptr_t value = -1;
114    REPORTER_ASSERT(r, cache.find(key, TestingRec::Visitor, &value));
115    REPORTER_ASSERT(r, 2 == value || 3 == value);
116}
117