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