xref: /aosp_15_r20/external/skia/src/gpu/graphite/Resource.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2022 Google LLC
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #ifndef skgpu_graphite_Resource_DEFINED
9*c8dee2aaSAndroid Build Coastguard Worker #define skgpu_graphite_Resource_DEFINED
10*c8dee2aaSAndroid Build Coastguard Worker 
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/GpuTypes.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkMutex.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/GpuTypesPriv.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/GraphiteResourceKey.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/ResourceTypes.h"
16*c8dee2aaSAndroid Build Coastguard Worker 
17*c8dee2aaSAndroid Build Coastguard Worker #include <atomic>
18*c8dee2aaSAndroid Build Coastguard Worker #include <functional>
19*c8dee2aaSAndroid Build Coastguard Worker #include <string>
20*c8dee2aaSAndroid Build Coastguard Worker #include <string_view>
21*c8dee2aaSAndroid Build Coastguard Worker 
22*c8dee2aaSAndroid Build Coastguard Worker class SkMutex;
23*c8dee2aaSAndroid Build Coastguard Worker class SkTraceMemoryDump;
24*c8dee2aaSAndroid Build Coastguard Worker 
25*c8dee2aaSAndroid Build Coastguard Worker namespace skgpu::graphite {
26*c8dee2aaSAndroid Build Coastguard Worker 
27*c8dee2aaSAndroid Build Coastguard Worker class ResourceCache;
28*c8dee2aaSAndroid Build Coastguard Worker class SharedContext;
29*c8dee2aaSAndroid Build Coastguard Worker class Texture;
30*c8dee2aaSAndroid Build Coastguard Worker 
31*c8dee2aaSAndroid Build Coastguard Worker /**
32*c8dee2aaSAndroid Build Coastguard Worker  * Base class for objects that can be kept in the ResourceCache.
33*c8dee2aaSAndroid Build Coastguard Worker  */
34*c8dee2aaSAndroid Build Coastguard Worker class Resource {
35*c8dee2aaSAndroid Build Coastguard Worker public:
36*c8dee2aaSAndroid Build Coastguard Worker     Resource(const Resource&) = delete;
37*c8dee2aaSAndroid Build Coastguard Worker     Resource(Resource&&) = delete;
38*c8dee2aaSAndroid Build Coastguard Worker     Resource& operator=(const Resource&) = delete;
39*c8dee2aaSAndroid Build Coastguard Worker     Resource& operator=(Resource&&) = delete;
40*c8dee2aaSAndroid Build Coastguard Worker 
41*c8dee2aaSAndroid Build Coastguard Worker     // Adds a usage ref to the resource. Named ref so we can easily manage usage refs with sk_sp.
ref()42*c8dee2aaSAndroid Build Coastguard Worker     void ref() const {
43*c8dee2aaSAndroid Build Coastguard Worker         // Only the cache should be able to add the first usage ref to a resource.
44*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(this->hasUsageRef());
45*c8dee2aaSAndroid Build Coastguard Worker         // No barrier required.
46*c8dee2aaSAndroid Build Coastguard Worker         (void)fUsageRefCnt.fetch_add(+1, std::memory_order_relaxed);
47*c8dee2aaSAndroid Build Coastguard Worker     }
48*c8dee2aaSAndroid Build Coastguard Worker 
49*c8dee2aaSAndroid Build Coastguard Worker     // Removes a usage ref from the resource
unref()50*c8dee2aaSAndroid Build Coastguard Worker     void unref() const {
51*c8dee2aaSAndroid Build Coastguard Worker         bool shouldFree = false;
52*c8dee2aaSAndroid Build Coastguard Worker         {
53*c8dee2aaSAndroid Build Coastguard Worker             SkAutoMutexExclusive locked(fUnrefMutex);
54*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(this->hasUsageRef());
55*c8dee2aaSAndroid Build Coastguard Worker             // A release here acts in place of all releases we "should" have been doing in ref().
56*c8dee2aaSAndroid Build Coastguard Worker             if (1 == fUsageRefCnt.fetch_add(-1, std::memory_order_acq_rel)) {
57*c8dee2aaSAndroid Build Coastguard Worker                 shouldFree = this->notifyARefIsZero(LastRemovedRef::kUsage);
58*c8dee2aaSAndroid Build Coastguard Worker             }
59*c8dee2aaSAndroid Build Coastguard Worker         }
60*c8dee2aaSAndroid Build Coastguard Worker         if (shouldFree) {
61*c8dee2aaSAndroid Build Coastguard Worker             Resource* mutableThis = const_cast<Resource*>(this);
62*c8dee2aaSAndroid Build Coastguard Worker             mutableThis->internalDispose();
63*c8dee2aaSAndroid Build Coastguard Worker         }
64*c8dee2aaSAndroid Build Coastguard Worker     }
65*c8dee2aaSAndroid Build Coastguard Worker 
66*c8dee2aaSAndroid Build Coastguard Worker     // Adds a command buffer ref to the resource
refCommandBuffer()67*c8dee2aaSAndroid Build Coastguard Worker     void refCommandBuffer() const {
68*c8dee2aaSAndroid Build Coastguard Worker         if (fCommandBufferRefsAsUsageRefs) {
69*c8dee2aaSAndroid Build Coastguard Worker             return this->ref();
70*c8dee2aaSAndroid Build Coastguard Worker         }
71*c8dee2aaSAndroid Build Coastguard Worker         // No barrier required.
72*c8dee2aaSAndroid Build Coastguard Worker         (void)fCommandBufferRefCnt.fetch_add(+1, std::memory_order_relaxed);
73*c8dee2aaSAndroid Build Coastguard Worker     }
74*c8dee2aaSAndroid Build Coastguard Worker 
75*c8dee2aaSAndroid Build Coastguard Worker     // Removes a command buffer ref from the resource
unrefCommandBuffer()76*c8dee2aaSAndroid Build Coastguard Worker     void unrefCommandBuffer() const {
77*c8dee2aaSAndroid Build Coastguard Worker         if (fCommandBufferRefsAsUsageRefs) {
78*c8dee2aaSAndroid Build Coastguard Worker             return this->unref();
79*c8dee2aaSAndroid Build Coastguard Worker         }
80*c8dee2aaSAndroid Build Coastguard Worker         bool shouldFree = false;
81*c8dee2aaSAndroid Build Coastguard Worker         {
82*c8dee2aaSAndroid Build Coastguard Worker             SkAutoMutexExclusive locked(fUnrefMutex);
83*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(this->hasCommandBufferRef());
84*c8dee2aaSAndroid Build Coastguard Worker             // A release here acts in place of all releases we "should" have been doing in ref().
85*c8dee2aaSAndroid Build Coastguard Worker             if (1 == fCommandBufferRefCnt.fetch_add(-1, std::memory_order_acq_rel)) {
86*c8dee2aaSAndroid Build Coastguard Worker                 shouldFree = this->notifyARefIsZero(LastRemovedRef::kCommandBuffer);
87*c8dee2aaSAndroid Build Coastguard Worker             }
88*c8dee2aaSAndroid Build Coastguard Worker         }
89*c8dee2aaSAndroid Build Coastguard Worker         if (shouldFree) {
90*c8dee2aaSAndroid Build Coastguard Worker             Resource* mutableThis = const_cast<Resource*>(this);
91*c8dee2aaSAndroid Build Coastguard Worker             mutableThis->internalDispose();
92*c8dee2aaSAndroid Build Coastguard Worker         }
93*c8dee2aaSAndroid Build Coastguard Worker     }
94*c8dee2aaSAndroid Build Coastguard Worker 
ownership()95*c8dee2aaSAndroid Build Coastguard Worker     Ownership ownership() const { return fOwnership; }
96*c8dee2aaSAndroid Build Coastguard Worker 
budgeted()97*c8dee2aaSAndroid Build Coastguard Worker     skgpu::Budgeted budgeted() const { return fBudgeted; }
98*c8dee2aaSAndroid Build Coastguard Worker 
99*c8dee2aaSAndroid Build Coastguard Worker     // Retrieves the amount of GPU memory used by this resource in bytes. It is approximate since we
100*c8dee2aaSAndroid Build Coastguard Worker     // aren't aware of additional padding or copies made by the driver.
gpuMemorySize()101*c8dee2aaSAndroid Build Coastguard Worker     size_t gpuMemorySize() const { return fGpuMemorySize; }
102*c8dee2aaSAndroid Build Coastguard Worker 
103*c8dee2aaSAndroid Build Coastguard Worker     class UniqueID {
104*c8dee2aaSAndroid Build Coastguard Worker     public:
105*c8dee2aaSAndroid Build Coastguard Worker         UniqueID() = default;
106*c8dee2aaSAndroid Build Coastguard Worker 
UniqueID(uint32_t id)107*c8dee2aaSAndroid Build Coastguard Worker         explicit UniqueID(uint32_t id) : fID(id) {}
108*c8dee2aaSAndroid Build Coastguard Worker 
asUInt()109*c8dee2aaSAndroid Build Coastguard Worker         uint32_t asUInt() const { return fID; }
110*c8dee2aaSAndroid Build Coastguard Worker 
111*c8dee2aaSAndroid Build Coastguard Worker         bool operator==(const UniqueID& other) const { return fID == other.fID; }
112*c8dee2aaSAndroid Build Coastguard Worker         bool operator!=(const UniqueID& other) const { return !(*this == other); }
113*c8dee2aaSAndroid Build Coastguard Worker 
114*c8dee2aaSAndroid Build Coastguard Worker     private:
115*c8dee2aaSAndroid Build Coastguard Worker         uint32_t fID = SK_InvalidUniqueID;
116*c8dee2aaSAndroid Build Coastguard Worker     };
117*c8dee2aaSAndroid Build Coastguard Worker 
118*c8dee2aaSAndroid Build Coastguard Worker     // Gets an id that is unique for this Resource object. It is static in that it does not change
119*c8dee2aaSAndroid Build Coastguard Worker     // when the content of the Resource object changes. This will never return 0.
uniqueID()120*c8dee2aaSAndroid Build Coastguard Worker     UniqueID uniqueID() const { return fUniqueID; }
121*c8dee2aaSAndroid Build Coastguard Worker 
122*c8dee2aaSAndroid Build Coastguard Worker     // Describes the type of gpu resource that is represented by the implementing
123*c8dee2aaSAndroid Build Coastguard Worker     // class (e.g. texture, buffer, etc).  This data is used for diagnostic
124*c8dee2aaSAndroid Build Coastguard Worker     // purposes by dumpMemoryStatistics().
125*c8dee2aaSAndroid Build Coastguard Worker     //
126*c8dee2aaSAndroid Build Coastguard Worker     // The value returned is expected to be long lived and will not be copied by the caller.
127*c8dee2aaSAndroid Build Coastguard Worker     virtual const char* getResourceType() const = 0;
128*c8dee2aaSAndroid Build Coastguard Worker 
getLabel()129*c8dee2aaSAndroid Build Coastguard Worker     std::string getLabel() const { return fLabel; }
130*c8dee2aaSAndroid Build Coastguard Worker 
131*c8dee2aaSAndroid Build Coastguard Worker     // We allow the label on a Resource to change when used for a different function. For example
132*c8dee2aaSAndroid Build Coastguard Worker     // when reusing a scratch Texture we can change the label to match callers current use.
setLabel(std::string_view label)133*c8dee2aaSAndroid Build Coastguard Worker     void setLabel(std::string_view label) {
134*c8dee2aaSAndroid Build Coastguard Worker         fLabel = label;
135*c8dee2aaSAndroid Build Coastguard Worker 
136*c8dee2aaSAndroid Build Coastguard Worker         if (!fLabel.empty()) {
137*c8dee2aaSAndroid Build Coastguard Worker             const std::string fullLabel = "Skia_" + fLabel;
138*c8dee2aaSAndroid Build Coastguard Worker             this->setBackendLabel(fullLabel.c_str());
139*c8dee2aaSAndroid Build Coastguard Worker         }
140*c8dee2aaSAndroid Build Coastguard Worker     }
141*c8dee2aaSAndroid Build Coastguard Worker 
142*c8dee2aaSAndroid Build Coastguard Worker     // Tests whether a object has been abandoned or released. All objects will be in this state
143*c8dee2aaSAndroid Build Coastguard Worker     // after their creating Context is destroyed or abandoned.
144*c8dee2aaSAndroid Build Coastguard Worker     //
145*c8dee2aaSAndroid Build Coastguard Worker     // @return true if the object has been released or abandoned,
146*c8dee2aaSAndroid Build Coastguard Worker     //         false otherwise.
147*c8dee2aaSAndroid Build Coastguard Worker     // TODO: As of now this function isn't really needed because in freeGpuData we are always
148*c8dee2aaSAndroid Build Coastguard Worker     // deleting this object. However, I want to implement all the purging logic first to make sure
149*c8dee2aaSAndroid Build Coastguard Worker     // we don't have a use case for calling internalDispose but not wanting to delete the actual
150*c8dee2aaSAndroid Build Coastguard Worker     // object yet.
wasDestroyed()151*c8dee2aaSAndroid Build Coastguard Worker     bool wasDestroyed() const { return fSharedContext == nullptr; }
152*c8dee2aaSAndroid Build Coastguard Worker 
key()153*c8dee2aaSAndroid Build Coastguard Worker     const GraphiteResourceKey& key() const { return fKey; }
154*c8dee2aaSAndroid Build Coastguard Worker     // This should only ever be called by the ResourceProvider
setKey(const GraphiteResourceKey & key)155*c8dee2aaSAndroid Build Coastguard Worker     void setKey(const GraphiteResourceKey& key) {
156*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(key.shareable() == Shareable::kNo || this->budgeted() == skgpu::Budgeted::kYes);
157*c8dee2aaSAndroid Build Coastguard Worker         fKey = key;
158*c8dee2aaSAndroid Build Coastguard Worker     }
159*c8dee2aaSAndroid Build Coastguard Worker 
160*c8dee2aaSAndroid Build Coastguard Worker     // Dumps memory usage information for this Resource to traceMemoryDump.
161*c8dee2aaSAndroid Build Coastguard Worker     void dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const;
162*c8dee2aaSAndroid Build Coastguard Worker 
163*c8dee2aaSAndroid Build Coastguard Worker     /**
164*c8dee2aaSAndroid Build Coastguard Worker      * If the resource has a non-shareable key then this gives the resource subclass an opportunity
165*c8dee2aaSAndroid Build Coastguard Worker      * to prepare itself to re-enter the cache. The ResourceCache extends its privilege to take the
166*c8dee2aaSAndroid Build Coastguard Worker      * first UsageRef to this function via takeRef. If takeRef is called this resource will not
167*c8dee2aaSAndroid Build Coastguard Worker      * immediately enter the cache but will be re-reprocessed with the Usage Ref count again reaches
168*c8dee2aaSAndroid Build Coastguard Worker      * zero.
169*c8dee2aaSAndroid Build Coastguard Worker      */
prepareForReturnToCache(const std::function<void ()> & takeRef)170*c8dee2aaSAndroid Build Coastguard Worker     virtual void prepareForReturnToCache(const std::function<void()>& takeRef) {}
171*c8dee2aaSAndroid Build Coastguard Worker 
asTexture()172*c8dee2aaSAndroid Build Coastguard Worker     virtual const Texture* asTexture() const { return nullptr; }
173*c8dee2aaSAndroid Build Coastguard Worker 
174*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS)
testingShouldDeleteASAP()175*c8dee2aaSAndroid Build Coastguard Worker     bool testingShouldDeleteASAP() const { return fDeleteASAP == DeleteASAP::kYes; }
176*c8dee2aaSAndroid Build Coastguard Worker #endif
177*c8dee2aaSAndroid Build Coastguard Worker 
178*c8dee2aaSAndroid Build Coastguard Worker protected:
179*c8dee2aaSAndroid Build Coastguard Worker     Resource(const SharedContext*,
180*c8dee2aaSAndroid Build Coastguard Worker              Ownership,
181*c8dee2aaSAndroid Build Coastguard Worker              skgpu::Budgeted,
182*c8dee2aaSAndroid Build Coastguard Worker              size_t gpuMemorySize,
183*c8dee2aaSAndroid Build Coastguard Worker              bool commandBufferRefsAsUsageRefs = false);
184*c8dee2aaSAndroid Build Coastguard Worker     virtual ~Resource();
185*c8dee2aaSAndroid Build Coastguard Worker 
sharedContext()186*c8dee2aaSAndroid Build Coastguard Worker     const SharedContext* sharedContext() const { return fSharedContext; }
187*c8dee2aaSAndroid Build Coastguard Worker 
188*c8dee2aaSAndroid Build Coastguard Worker     // Overridden to add extra information to the memory dump.
onDumpMemoryStatistics(SkTraceMemoryDump * traceMemoryDump,const char * dumpName)189*c8dee2aaSAndroid Build Coastguard Worker     virtual void onDumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump,
190*c8dee2aaSAndroid Build Coastguard Worker                                         const char* dumpName) const {}
191*c8dee2aaSAndroid Build Coastguard Worker 
192*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_DEBUG
debugHasCommandBufferRef()193*c8dee2aaSAndroid Build Coastguard Worker     bool debugHasCommandBufferRef() const {
194*c8dee2aaSAndroid Build Coastguard Worker         return hasCommandBufferRef();
195*c8dee2aaSAndroid Build Coastguard Worker     }
196*c8dee2aaSAndroid Build Coastguard Worker #endif
197*c8dee2aaSAndroid Build Coastguard Worker 
198*c8dee2aaSAndroid Build Coastguard Worker     // Needed to be protected for DawnBuffer emscripten prepareForReturnToCache
setDeleteASAP()199*c8dee2aaSAndroid Build Coastguard Worker     void setDeleteASAP() { fDeleteASAP = DeleteASAP::kYes; }
200*c8dee2aaSAndroid Build Coastguard Worker 
201*c8dee2aaSAndroid Build Coastguard Worker private:
202*c8dee2aaSAndroid Build Coastguard Worker     friend class ProxyCache; // for setDeleteASAP and updateAccessTime
203*c8dee2aaSAndroid Build Coastguard Worker 
204*c8dee2aaSAndroid Build Coastguard Worker     // Overridden to free GPU resources in the backend API.
205*c8dee2aaSAndroid Build Coastguard Worker     virtual void freeGpuData() = 0;
206*c8dee2aaSAndroid Build Coastguard Worker 
207*c8dee2aaSAndroid Build Coastguard Worker     // Overridden to call any release callbacks, if necessary
invokeReleaseProc()208*c8dee2aaSAndroid Build Coastguard Worker     virtual void invokeReleaseProc() {}
209*c8dee2aaSAndroid Build Coastguard Worker 
210*c8dee2aaSAndroid Build Coastguard Worker     enum class DeleteASAP : bool {
211*c8dee2aaSAndroid Build Coastguard Worker         kNo = false,
212*c8dee2aaSAndroid Build Coastguard Worker         kYes = true,
213*c8dee2aaSAndroid Build Coastguard Worker     };
214*c8dee2aaSAndroid Build Coastguard Worker 
shouldDeleteASAP()215*c8dee2aaSAndroid Build Coastguard Worker     DeleteASAP shouldDeleteASAP() const { return fDeleteASAP; }
216*c8dee2aaSAndroid Build Coastguard Worker 
217*c8dee2aaSAndroid Build Coastguard Worker     // In the ResourceCache this is called whenever a Resource is moved into the purgeableQueue. It
218*c8dee2aaSAndroid Build Coastguard Worker     // may also be called by the ProxyCache to track the time on Resources it is holding on to.
updateAccessTime()219*c8dee2aaSAndroid Build Coastguard Worker     void updateAccessTime() {
220*c8dee2aaSAndroid Build Coastguard Worker         fLastAccess = skgpu::StdSteadyClock::now();
221*c8dee2aaSAndroid Build Coastguard Worker     }
lastAccessTime()222*c8dee2aaSAndroid Build Coastguard Worker     skgpu::StdSteadyClock::time_point lastAccessTime() const {
223*c8dee2aaSAndroid Build Coastguard Worker         return fLastAccess;
224*c8dee2aaSAndroid Build Coastguard Worker     }
225*c8dee2aaSAndroid Build Coastguard Worker 
setBackendLabel(char const * label)226*c8dee2aaSAndroid Build Coastguard Worker     virtual void setBackendLabel(char const* label) {}
227*c8dee2aaSAndroid Build Coastguard Worker 
228*c8dee2aaSAndroid Build Coastguard Worker     ////////////////////////////////////////////////////////////////////////////
229*c8dee2aaSAndroid Build Coastguard Worker     // The following set of functions are only meant to be called by the ResourceCache. We don't
230*c8dee2aaSAndroid Build Coastguard Worker     // want them public general users of a Resource, but they also aren't purely internal calls.
231*c8dee2aaSAndroid Build Coastguard Worker     ////////////////////////////////////////////////////////////////////////////
232*c8dee2aaSAndroid Build Coastguard Worker     friend ResourceCache;
233*c8dee2aaSAndroid Build Coastguard Worker 
makeBudgeted()234*c8dee2aaSAndroid Build Coastguard Worker     void makeBudgeted() { fBudgeted = skgpu::Budgeted::kYes; }
makeUnbudgeted()235*c8dee2aaSAndroid Build Coastguard Worker     void makeUnbudgeted() { fBudgeted = skgpu::Budgeted::kNo; }
236*c8dee2aaSAndroid Build Coastguard Worker 
237*c8dee2aaSAndroid Build Coastguard Worker     // This version of ref allows adding a ref when the usage count is 0. This should only be called
238*c8dee2aaSAndroid Build Coastguard Worker     // from the ResourceCache.
initialUsageRef()239*c8dee2aaSAndroid Build Coastguard Worker     void initialUsageRef() const {
240*c8dee2aaSAndroid Build Coastguard Worker         // Only the cache should be able to add the first usage ref to a resource.
241*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(fUsageRefCnt >= 0);
242*c8dee2aaSAndroid Build Coastguard Worker         // No barrier required.
243*c8dee2aaSAndroid Build Coastguard Worker         (void)fUsageRefCnt.fetch_add(+1, std::memory_order_relaxed);
244*c8dee2aaSAndroid Build Coastguard Worker     }
245*c8dee2aaSAndroid Build Coastguard Worker 
246*c8dee2aaSAndroid Build Coastguard Worker     bool isPurgeable() const;
accessReturnIndex()247*c8dee2aaSAndroid Build Coastguard Worker     int* accessReturnIndex()  const { return &fReturnIndex; }
accessCacheIndex()248*c8dee2aaSAndroid Build Coastguard Worker     int* accessCacheIndex()  const { return &fCacheArrayIndex; }
249*c8dee2aaSAndroid Build Coastguard Worker 
timestamp()250*c8dee2aaSAndroid Build Coastguard Worker     uint32_t timestamp() const { return fTimestamp; }
setTimestamp(uint32_t ts)251*c8dee2aaSAndroid Build Coastguard Worker     void setTimestamp(uint32_t ts) { fTimestamp = ts; }
252*c8dee2aaSAndroid Build Coastguard Worker 
253*c8dee2aaSAndroid Build Coastguard Worker     void registerWithCache(sk_sp<ResourceCache>);
254*c8dee2aaSAndroid Build Coastguard Worker 
255*c8dee2aaSAndroid Build Coastguard Worker     // Adds a cache ref to the resource. This is only called by ResourceCache. A Resource will only
256*c8dee2aaSAndroid Build Coastguard Worker     // ever add a ref when the Resource is part of the cache (i.e. when insertResource is called)
257*c8dee2aaSAndroid Build Coastguard Worker     // and while the Resource is in the ResourceCache::ReturnQueue.
refCache()258*c8dee2aaSAndroid Build Coastguard Worker     void refCache() const {
259*c8dee2aaSAndroid Build Coastguard Worker         // No barrier required.
260*c8dee2aaSAndroid Build Coastguard Worker         (void)fCacheRefCnt.fetch_add(+1, std::memory_order_relaxed);
261*c8dee2aaSAndroid Build Coastguard Worker     }
262*c8dee2aaSAndroid Build Coastguard Worker 
263*c8dee2aaSAndroid Build Coastguard Worker     // Removes a cache ref from the resource. The unref here should only ever be called from the
264*c8dee2aaSAndroid Build Coastguard Worker     // ResourceCache and only in the Recorder thread the ResourceCache is part of.
unrefCache()265*c8dee2aaSAndroid Build Coastguard Worker     void unrefCache() const {
266*c8dee2aaSAndroid Build Coastguard Worker         bool shouldFree = false;
267*c8dee2aaSAndroid Build Coastguard Worker         {
268*c8dee2aaSAndroid Build Coastguard Worker             SkAutoMutexExclusive locked(fUnrefMutex);
269*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(this->hasCacheRef());
270*c8dee2aaSAndroid Build Coastguard Worker             // A release here acts in place of all releases we "should" have been doing in ref().
271*c8dee2aaSAndroid Build Coastguard Worker             if (1 == fCacheRefCnt.fetch_add(-1, std::memory_order_acq_rel)) {
272*c8dee2aaSAndroid Build Coastguard Worker                 shouldFree = this->notifyARefIsZero(LastRemovedRef::kCache);
273*c8dee2aaSAndroid Build Coastguard Worker             }
274*c8dee2aaSAndroid Build Coastguard Worker         }
275*c8dee2aaSAndroid Build Coastguard Worker         if (shouldFree) {
276*c8dee2aaSAndroid Build Coastguard Worker             Resource* mutableThis = const_cast<Resource*>(this);
277*c8dee2aaSAndroid Build Coastguard Worker             mutableThis->internalDispose();
278*c8dee2aaSAndroid Build Coastguard Worker         }
279*c8dee2aaSAndroid Build Coastguard Worker     }
280*c8dee2aaSAndroid Build Coastguard Worker 
281*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_DEBUG
isUsableAsScratch()282*c8dee2aaSAndroid Build Coastguard Worker     bool isUsableAsScratch() const {
283*c8dee2aaSAndroid Build Coastguard Worker         return fKey.shareable() == Shareable::kNo && !this->hasUsageRef() && fNonShareableInCache;
284*c8dee2aaSAndroid Build Coastguard Worker     }
285*c8dee2aaSAndroid Build Coastguard Worker #endif
286*c8dee2aaSAndroid Build Coastguard Worker 
287*c8dee2aaSAndroid Build Coastguard Worker     ////////////////////////////////////////////////////////////////////////////
288*c8dee2aaSAndroid Build Coastguard Worker     // The remaining calls are meant to be truely private
289*c8dee2aaSAndroid Build Coastguard Worker     ////////////////////////////////////////////////////////////////////////////
hasUsageRef()290*c8dee2aaSAndroid Build Coastguard Worker     bool hasUsageRef() const {
291*c8dee2aaSAndroid Build Coastguard Worker         if (0 == fUsageRefCnt.load(std::memory_order_acquire)) {
292*c8dee2aaSAndroid Build Coastguard Worker             // The acquire barrier is only really needed if we return true.  It
293*c8dee2aaSAndroid Build Coastguard Worker             // prevents code conditioned on the result of hasUsageRef() from running until previous
294*c8dee2aaSAndroid Build Coastguard Worker             // owners are all totally done calling unref().
295*c8dee2aaSAndroid Build Coastguard Worker             return false;
296*c8dee2aaSAndroid Build Coastguard Worker         }
297*c8dee2aaSAndroid Build Coastguard Worker         return true;
298*c8dee2aaSAndroid Build Coastguard Worker     }
299*c8dee2aaSAndroid Build Coastguard Worker 
hasCommandBufferRef()300*c8dee2aaSAndroid Build Coastguard Worker     bool hasCommandBufferRef() const {
301*c8dee2aaSAndroid Build Coastguard Worker         // Note that we don't check here for fCommandBufferRefsAsUsageRefs. This should always
302*c8dee2aaSAndroid Build Coastguard Worker         // report zero if that value is true.
303*c8dee2aaSAndroid Build Coastguard Worker         if (0 == fCommandBufferRefCnt.load(std::memory_order_acquire)) {
304*c8dee2aaSAndroid Build Coastguard Worker             // The acquire barrier is only really needed if we return true.  It
305*c8dee2aaSAndroid Build Coastguard Worker             // prevents code conditioned on the result of hasCommandBufferRef() from running
306*c8dee2aaSAndroid Build Coastguard Worker             // until previous owners are all totally done calling unrefCommandBuffer().
307*c8dee2aaSAndroid Build Coastguard Worker             return false;
308*c8dee2aaSAndroid Build Coastguard Worker         }
309*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(!fCommandBufferRefsAsUsageRefs);
310*c8dee2aaSAndroid Build Coastguard Worker         return true;
311*c8dee2aaSAndroid Build Coastguard Worker     }
312*c8dee2aaSAndroid Build Coastguard Worker 
hasCacheRef()313*c8dee2aaSAndroid Build Coastguard Worker     bool hasCacheRef() const {
314*c8dee2aaSAndroid Build Coastguard Worker         if (0 == fCacheRefCnt.load(std::memory_order_acquire)) {
315*c8dee2aaSAndroid Build Coastguard Worker             // The acquire barrier is only really needed if we return true. It
316*c8dee2aaSAndroid Build Coastguard Worker             // prevents code conditioned on the result of hasUsageRef() from running until previous
317*c8dee2aaSAndroid Build Coastguard Worker             // owners are all totally done calling unref().
318*c8dee2aaSAndroid Build Coastguard Worker             return false;
319*c8dee2aaSAndroid Build Coastguard Worker         }
320*c8dee2aaSAndroid Build Coastguard Worker         return true;
321*c8dee2aaSAndroid Build Coastguard Worker     }
322*c8dee2aaSAndroid Build Coastguard Worker 
hasAnyRefs()323*c8dee2aaSAndroid Build Coastguard Worker     bool hasAnyRefs() const {
324*c8dee2aaSAndroid Build Coastguard Worker         return this->hasUsageRef() || this->hasCommandBufferRef() || this->hasCacheRef();
325*c8dee2aaSAndroid Build Coastguard Worker     }
326*c8dee2aaSAndroid Build Coastguard Worker 
327*c8dee2aaSAndroid Build Coastguard Worker     bool notifyARefIsZero(LastRemovedRef removedRef) const;
328*c8dee2aaSAndroid Build Coastguard Worker 
329*c8dee2aaSAndroid Build Coastguard Worker     // Frees the object in the underlying 3D API.
330*c8dee2aaSAndroid Build Coastguard Worker     void internalDispose();
331*c8dee2aaSAndroid Build Coastguard Worker 
332*c8dee2aaSAndroid Build Coastguard Worker     // We need to guard calling unref on the usage and command buffer refs since they each could be
333*c8dee2aaSAndroid Build Coastguard Worker     // unreffed on different threads. This can lead to calling notifyARefIsZero twice with each
334*c8dee2aaSAndroid Build Coastguard Worker     // instance thinking there are no more refs left and both trying to delete the object.
335*c8dee2aaSAndroid Build Coastguard Worker     mutable SkMutex fUnrefMutex;
336*c8dee2aaSAndroid Build Coastguard Worker 
337*c8dee2aaSAndroid Build Coastguard Worker     SkDEBUGCODE(mutable bool fCalledRemovedFromCache = false;)
338*c8dee2aaSAndroid Build Coastguard Worker 
339*c8dee2aaSAndroid Build Coastguard Worker     // This is not ref'ed but internalDispose() will be called before the Gpu object is destroyed.
340*c8dee2aaSAndroid Build Coastguard Worker     // That call will set this to nullptr.
341*c8dee2aaSAndroid Build Coastguard Worker     const SharedContext* fSharedContext;
342*c8dee2aaSAndroid Build Coastguard Worker 
343*c8dee2aaSAndroid Build Coastguard Worker     mutable std::atomic<int32_t> fUsageRefCnt;
344*c8dee2aaSAndroid Build Coastguard Worker     mutable std::atomic<int32_t> fCommandBufferRefCnt;
345*c8dee2aaSAndroid Build Coastguard Worker     mutable std::atomic<int32_t> fCacheRefCnt;
346*c8dee2aaSAndroid Build Coastguard Worker     // Indicates that CommandBufferRefs should be rerouted to UsageRefs.
347*c8dee2aaSAndroid Build Coastguard Worker     const bool fCommandBufferRefsAsUsageRefs = false;
348*c8dee2aaSAndroid Build Coastguard Worker 
349*c8dee2aaSAndroid Build Coastguard Worker     GraphiteResourceKey fKey;
350*c8dee2aaSAndroid Build Coastguard Worker 
351*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<ResourceCache> fReturnCache;
352*c8dee2aaSAndroid Build Coastguard Worker     // An index into the return cache so we know whether or not the resource is already waiting to
353*c8dee2aaSAndroid Build Coastguard Worker     // be returned or not.
354*c8dee2aaSAndroid Build Coastguard Worker     mutable int fReturnIndex = -1;
355*c8dee2aaSAndroid Build Coastguard Worker 
356*c8dee2aaSAndroid Build Coastguard Worker     Ownership fOwnership;
357*c8dee2aaSAndroid Build Coastguard Worker 
358*c8dee2aaSAndroid Build Coastguard Worker     static const size_t kInvalidGpuMemorySize = ~static_cast<size_t>(0);
359*c8dee2aaSAndroid Build Coastguard Worker     mutable size_t fGpuMemorySize = kInvalidGpuMemorySize;
360*c8dee2aaSAndroid Build Coastguard Worker 
361*c8dee2aaSAndroid Build Coastguard Worker     // All resource created internally by Graphite and held in the ResourceCache as a shared
362*c8dee2aaSAndroid Build Coastguard Worker     // resource or available scratch resource are considered budgeted. Resources that back client
363*c8dee2aaSAndroid Build Coastguard Worker     // owned objects (e.g. SkSurface or SkImage) are not budgeted and do not count against cache
364*c8dee2aaSAndroid Build Coastguard Worker     // limits.
365*c8dee2aaSAndroid Build Coastguard Worker     skgpu::Budgeted fBudgeted;
366*c8dee2aaSAndroid Build Coastguard Worker 
367*c8dee2aaSAndroid Build Coastguard Worker     // This is only used by ProxyCache::purgeProxiesNotUsedSince which is called from
368*c8dee2aaSAndroid Build Coastguard Worker     // ResourceCache::purgeResourcesNotUsedSince. When kYes, this signals that the Resource
369*c8dee2aaSAndroid Build Coastguard Worker     // should've been purged based on its timestamp at some point regardless of what its
370*c8dee2aaSAndroid Build Coastguard Worker     // current timestamp may indicate (since the timestamp will be updated when the Resource
371*c8dee2aaSAndroid Build Coastguard Worker     // is returned to the ResourceCache).
372*c8dee2aaSAndroid Build Coastguard Worker     DeleteASAP fDeleteASAP = DeleteASAP::kNo;
373*c8dee2aaSAndroid Build Coastguard Worker 
374*c8dee2aaSAndroid Build Coastguard Worker     // An index into a heap when this resource is purgeable or an array when not. This is maintained
375*c8dee2aaSAndroid Build Coastguard Worker     // by the cache.
376*c8dee2aaSAndroid Build Coastguard Worker     mutable int fCacheArrayIndex = -1;
377*c8dee2aaSAndroid Build Coastguard Worker     // This value reflects how recently this resource was accessed in the cache. This is maintained
378*c8dee2aaSAndroid Build Coastguard Worker     // by the cache.
379*c8dee2aaSAndroid Build Coastguard Worker     uint32_t fTimestamp;
380*c8dee2aaSAndroid Build Coastguard Worker     skgpu::StdSteadyClock::time_point fLastAccess;
381*c8dee2aaSAndroid Build Coastguard Worker 
382*c8dee2aaSAndroid Build Coastguard Worker     const UniqueID fUniqueID;
383*c8dee2aaSAndroid Build Coastguard Worker 
384*c8dee2aaSAndroid Build Coastguard Worker     // String used to describe the current use of this Resource.
385*c8dee2aaSAndroid Build Coastguard Worker     std::string fLabel;
386*c8dee2aaSAndroid Build Coastguard Worker 
387*c8dee2aaSAndroid Build Coastguard Worker     // This is only used during validation checking. Lots of the validation code depends on a
388*c8dee2aaSAndroid Build Coastguard Worker     // resource being purgeable or not. However, purgeable itself just means having no refs. The
389*c8dee2aaSAndroid Build Coastguard Worker     // refs can be removed before a Resource is returned to the cache (or even added to the
390*c8dee2aaSAndroid Build Coastguard Worker     // ReturnQueue).
391*c8dee2aaSAndroid Build Coastguard Worker     SkDEBUGCODE(mutable bool fNonShareableInCache = false;)
392*c8dee2aaSAndroid Build Coastguard Worker };
393*c8dee2aaSAndroid Build Coastguard Worker 
394*c8dee2aaSAndroid Build Coastguard Worker } // namespace skgpu::graphite
395*c8dee2aaSAndroid Build Coastguard Worker 
396*c8dee2aaSAndroid Build Coastguard Worker #endif // skgpu_graphite_Resource_DEFINED
397