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 | #ifndef SkCachedData_DEFINED |
9 | #define SkCachedData_DEFINED |
10 | |
11 | #include "include/core/SkTypes.h" |
12 | #include "include/private/SkMutex.h" |
13 | #include "include/private/SkNoncopyable.h" |
14 | |
15 | class SkDiscardableMemory; |
16 | |
17 | class SkCachedData : ::SkNoncopyable { |
18 | public: |
19 | SkCachedData(void* mallocData, size_t size); |
20 | SkCachedData(size_t size, SkDiscardableMemory*); |
21 | virtual ~SkCachedData(); |
22 | |
23 | size_t size() const { return fSize; } |
24 | const void* data() const { return fData; } |
25 | |
26 | void* writable_data() { return fData; } |
27 | |
28 | void ref() const { this->internalRef(false); } |
29 | void unref() const { this->internalUnref(false); } |
30 | |
31 | int testing_only_getRefCnt() const { return fRefCnt; } |
32 | bool testing_only_isLocked() const { return fIsLocked; } |
33 | bool testing_only_isInCache() const { return fInCache; } |
34 | |
35 | SkDiscardableMemory* diagnostic_only_getDiscardable() const { |
36 | return kDiscardableMemory_StorageType == fStorageType ? fStorage.fDM : nullptr; |
37 | } |
38 | |
39 | protected: |
40 | // called when fData changes. could be nullptr. |
41 | virtual void onDataChange(void* oldData, void* newData) {} |
42 | |
43 | private: |
44 | SkMutex fMutex; // could use a pool of these... |
45 | |
46 | enum StorageType { |
47 | kDiscardableMemory_StorageType, |
48 | kMalloc_StorageType |
49 | }; |
50 | |
51 | union { |
52 | SkDiscardableMemory* fDM; |
53 | void* fMalloc; |
54 | } fStorage; |
55 | void* fData; |
56 | size_t fSize; |
57 | int fRefCnt; // low-bit means we're owned by the cache |
58 | StorageType fStorageType; |
59 | bool fInCache; |
60 | bool fIsLocked; |
61 | |
62 | void internalRef(bool fromCache) const; |
63 | void internalUnref(bool fromCache) const; |
64 | |
65 | void inMutexRef(bool fromCache); |
66 | bool inMutexUnref(bool fromCache); // returns true if we should delete "this" |
67 | void inMutexLock(); |
68 | void inMutexUnlock(); |
69 | |
70 | // called whenever our fData might change (lock or unlock) |
71 | void setData(void* newData) { |
72 | if (newData != fData) { |
73 | // notify our subclasses of the change |
74 | this->onDataChange(fData, newData); |
75 | fData = newData; |
76 | } |
77 | } |
78 | |
79 | class AutoMutexWritable; |
80 | |
81 | public: |
82 | #ifdef SK_DEBUG |
83 | void validate() const; |
84 | #else |
85 | void validate() const {} |
86 | #endif |
87 | |
88 | /* |
89 | * Attaching a data to to a SkResourceCache (only one at a time) enables the data to be |
90 | * unlocked when the cache is the only owner, thus freeing it to be purged (assuming the |
91 | * data is backed by a SkDiscardableMemory). |
92 | * |
93 | * When attached, it also automatically attempts to "lock" the data when the first client |
94 | * ref's the data (typically from a find(key, visitor) call). |
95 | * |
96 | * Thus the data will always be "locked" when a non-cache has a ref on it (whether or not |
97 | * the lock succeeded to recover the memory -- check data() to see if it is nullptr). |
98 | */ |
99 | |
100 | /* |
101 | * Call when adding this instance to a SkResourceCache::Rec subclass |
102 | * (typically in the Rec's constructor). |
103 | */ |
104 | void attachToCacheAndRef() const { this->internalRef(true); } |
105 | |
106 | /* |
107 | * Call when removing this instance from a SkResourceCache::Rec subclass |
108 | * (typically in the Rec's destructor). |
109 | */ |
110 | void detachFromCacheAndUnref() const { this->internalUnref(true); } |
111 | }; |
112 | |
113 | #endif |
114 | |