xref: /third_party/skia/tests/CachedDataTest.cpp (revision cb93a386)
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