1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2014 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 "include/core/SkRefCnt.h"
9cb93a386Sopenharmony_ci#include "include/core/SkTypes.h"
10cb93a386Sopenharmony_ci#include "include/private/SkMalloc.h"
11cb93a386Sopenharmony_ci#include "src/core/SkCachedData.h"
12cb93a386Sopenharmony_ci#include "src/lazy/SkDiscardableMemoryPool.h"
13cb93a386Sopenharmony_ci#include "tests/Test.h"
14cb93a386Sopenharmony_ci
15cb93a386Sopenharmony_ci#include <cstring>
16cb93a386Sopenharmony_ci
17cb93a386Sopenharmony_ciclass SkDiscardableMemory;
18cb93a386Sopenharmony_ci
19cb93a386Sopenharmony_cienum LockedState {
20cb93a386Sopenharmony_ci    kUnlocked,
21cb93a386Sopenharmony_ci    kLocked,
22cb93a386Sopenharmony_ci};
23cb93a386Sopenharmony_ci
24cb93a386Sopenharmony_cienum CachedState {
25cb93a386Sopenharmony_ci    kNotInCache,
26cb93a386Sopenharmony_ci    kInCache,
27cb93a386Sopenharmony_ci};
28cb93a386Sopenharmony_ci
29cb93a386Sopenharmony_cistatic void check_data(skiatest::Reporter* reporter, SkCachedData* data,
30cb93a386Sopenharmony_ci                       int refcnt, CachedState cacheState, LockedState lockedState) {
31cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, data->testing_only_getRefCnt() == refcnt);
32cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, data->testing_only_isInCache() == (kInCache == cacheState));
33cb93a386Sopenharmony_ci    REPORTER_ASSERT(reporter, data->testing_only_isLocked() == (lockedState == kLocked));
34cb93a386Sopenharmony_ci}
35cb93a386Sopenharmony_ci
36cb93a386Sopenharmony_cistatic SkCachedData* make_data(size_t size, SkDiscardableMemoryPool* pool) {
37cb93a386Sopenharmony_ci    if (pool) {
38cb93a386Sopenharmony_ci        SkDiscardableMemory* dm = pool->create(size);
39cb93a386Sopenharmony_ci        // the pool "can" return null, but it shouldn't in these controlled conditions
40cb93a386Sopenharmony_ci        SkASSERT_RELEASE(dm);
41cb93a386Sopenharmony_ci        return new SkCachedData(size, dm);
42cb93a386Sopenharmony_ci    } else {
43cb93a386Sopenharmony_ci        return new SkCachedData(sk_malloc_throw(size), size);
44cb93a386Sopenharmony_ci    }
45cb93a386Sopenharmony_ci}
46cb93a386Sopenharmony_ci
47cb93a386Sopenharmony_ci// returns with the data locked by client and cache
48cb93a386Sopenharmony_cistatic SkCachedData* test_locking(skiatest::Reporter* reporter,
49cb93a386Sopenharmony_ci                                  size_t size, SkDiscardableMemoryPool* pool) {
50cb93a386Sopenharmony_ci    SkCachedData* data = make_data(size, pool);
51cb93a386Sopenharmony_ci
52cb93a386Sopenharmony_ci    memset(data->writable_data(), 0x80, size);  // just to use writable_data()
53cb93a386Sopenharmony_ci
54cb93a386Sopenharmony_ci    check_data(reporter, data, 1, kNotInCache, kLocked);
55cb93a386Sopenharmony_ci
56cb93a386Sopenharmony_ci    data->ref();
57cb93a386Sopenharmony_ci    check_data(reporter, data, 2, kNotInCache, kLocked);
58cb93a386Sopenharmony_ci    data->unref();
59cb93a386Sopenharmony_ci    check_data(reporter, data, 1, kNotInCache, kLocked);
60cb93a386Sopenharmony_ci
61cb93a386Sopenharmony_ci    data->attachToCacheAndRef();
62cb93a386Sopenharmony_ci    check_data(reporter, data, 2, kInCache, kLocked);
63cb93a386Sopenharmony_ci
64cb93a386Sopenharmony_ci    data->unref();
65cb93a386Sopenharmony_ci    check_data(reporter, data, 1, kInCache, kUnlocked);
66cb93a386Sopenharmony_ci
67cb93a386Sopenharmony_ci    data->ref();
68cb93a386Sopenharmony_ci    check_data(reporter, data, 2, kInCache, kLocked);
69cb93a386Sopenharmony_ci
70cb93a386Sopenharmony_ci    return data;
71cb93a386Sopenharmony_ci}
72cb93a386Sopenharmony_ci
73cb93a386Sopenharmony_ci/*
74cb93a386Sopenharmony_ci *  SkCachedData behaves differently (regarding its locked/unlocked state) depending on
75cb93a386Sopenharmony_ci *  when it is in the cache or not. Being in the cache is signaled by calling attachToCacheAndRef()
76cb93a386Sopenharmony_ci *  instead of ref(). (and balanced by detachFromCacheAndUnref).
77cb93a386Sopenharmony_ci *
78cb93a386Sopenharmony_ci *  Thus, among other things, we test the end-of-life behavior when the client is the last owner
79cb93a386Sopenharmony_ci *  and when the cache is.
80cb93a386Sopenharmony_ci */
81cb93a386Sopenharmony_ciDEF_TEST(CachedData, reporter) {
82cb93a386Sopenharmony_ci    sk_sp<SkDiscardableMemoryPool> pool(SkDiscardableMemoryPool::Make(1000));
83cb93a386Sopenharmony_ci
84cb93a386Sopenharmony_ci    for (int useDiscardable = 0; useDiscardable <= 1; ++useDiscardable) {
85cb93a386Sopenharmony_ci        const size_t size = 100;
86cb93a386Sopenharmony_ci
87cb93a386Sopenharmony_ci        // test with client as last owner
88cb93a386Sopenharmony_ci        SkCachedData* data = test_locking(reporter, size, useDiscardable ? pool.get() : nullptr);
89cb93a386Sopenharmony_ci        check_data(reporter, data, 2, kInCache, kLocked);
90cb93a386Sopenharmony_ci        data->detachFromCacheAndUnref();
91cb93a386Sopenharmony_ci        check_data(reporter, data, 1, kNotInCache, kLocked);
92cb93a386Sopenharmony_ci        data->unref();
93cb93a386Sopenharmony_ci
94cb93a386Sopenharmony_ci        // test with cache as last owner
95cb93a386Sopenharmony_ci        data = test_locking(reporter, size, useDiscardable ? pool.get() : nullptr);
96cb93a386Sopenharmony_ci        check_data(reporter, data, 2, kInCache, kLocked);
97cb93a386Sopenharmony_ci        data->unref();
98cb93a386Sopenharmony_ci        check_data(reporter, data, 1, kInCache, kUnlocked);
99cb93a386Sopenharmony_ci        data->detachFromCacheAndUnref();
100cb93a386Sopenharmony_ci    }
101cb93a386Sopenharmony_ci}
102