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