2 * Copyright 2014 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
8 #ifndef GrGpuResource_DEFINED
9 #define GrGpuResource_DEFINED
11 #include "include/private/SkNoncopyable.h"
12 #include "include/private/gpu/ganesh/GrTypesPriv.h"
13 #include "src/gpu/ResourceKey.h"
16 class GrResourceCache;
17 class SkTraceMemoryDump;
20 * Base class for GrGpuResource. Provides the hooks for resources to interact with the cache.
21 * Separated out as a base class to isolate the ref-cnting behavior and provide friendship without
22 * exposing all of GrGpuResource.
24 * PRIOR to the last ref being removed DERIVED::notifyARefCntWillBeZero() will be called
25 * (static poly morphism using CRTP). It is legal for additional ref's to be added
26 * during this time. AFTER the ref count reaches zero DERIVED::notifyARefCntIsZero() will be
29 template <typename DERIVED> class GrIORef : public SkNoncopyable {
31 bool unique() const { return fRefCnt == 1; }
34 // Only the cache should be able to add the first ref to a resource.
35 SkASSERT(this->getRefCnt() > 0);
36 // No barrier required.
37 (void)fRefCnt.fetch_add(+1, std::memory_order_relaxed);
40 // This enum is used to notify the GrResourceCache which type of ref just dropped to zero.
41 enum class LastRemovedRef {
42 kMainRef, // This refers to fRefCnt
43 kCommandBufferUsage, // This refers to fCommandBufferUsageCnt
47 SkASSERT(this->getRefCnt() > 0);
48 if (1 == fRefCnt.fetch_add(-1, std::memory_order_acq_rel)) {
49 this->notifyWillBeZero(LastRemovedRef::kMainRef);
53 void addCommandBufferUsage() const {
54 // No barrier required.
55 (void)fCommandBufferUsageCnt.fetch_add(+1, std::memory_order_relaxed);
58 void removeCommandBufferUsage() const {
59 SkASSERT(!this->hasNoCommandBufferUsages());
60 if (1 == fCommandBufferUsageCnt.fetch_add(-1, std::memory_order_acq_rel)) {
61 this->notifyWillBeZero(LastRemovedRef::kCommandBufferUsage);
66 int32_t testingOnly_getRefCnt() const { return this->getRefCnt(); }
70 GrIORef() : fRefCnt(1), fCommandBufferUsageCnt(0) {}
72 bool internalHasRef() const { return SkToBool(this->getRefCnt()); }
73 bool internalHasNoCommandBufferUsages() const {
74 return SkToBool(this->hasNoCommandBufferUsages());
77 // Privileged method that allows going from ref count = 0 to ref count = 1.
78 void addInitialRef() const {
79 SkASSERT(fRefCnt >= 0);
80 // No barrier required.
81 (void)fRefCnt.fetch_add(+1, std::memory_order_relaxed);
85 void notifyWillBeZero(LastRemovedRef removedRef) const {
86 static_cast<const DERIVED*>(this)->notifyARefCntIsZero(removedRef);
89 int32_t getRefCnt() const { return fRefCnt.load(std::memory_order_relaxed); }
91 bool hasNoCommandBufferUsages() const {
92 if (0 == fCommandBufferUsageCnt.load(std::memory_order_acquire)) {
93 // The acquire barrier is only really needed if we return true. It
94 // prevents code conditioned on the result of hasNoCommandBufferUsages() from running
95 // until previous owners are all totally done calling removeCommandBufferUsage().
101 mutable std::atomic<int32_t> fRefCnt;
102 mutable std::atomic<int32_t> fCommandBufferUsageCnt;
104 using INHERITED = SkNoncopyable;
108 * Base class for objects that can be kept in the GrResourceCache.
110 class GrGpuResource : public GrIORef<GrGpuResource> {
113 * Tests whether a object has been abandoned or released. All objects will
114 * be in this state after their creating GrContext is destroyed or has
115 * contextLost called. It's up to the client to test wasDestroyed() before
116 * attempting to use an object if it holds refs on objects across
117 * ~GrContext, freeResources with the force flag, or contextLost.
119 * @return true if the object has been released or abandoned,
122 bool wasDestroyed() const { return nullptr == fGpu; }
125 * Retrieves the context that owns the object. Note that it is possible for
126 * this to return NULL. When objects have been release()ed or abandon()ed
127 * they no longer have an owning context. Destroying a GrDirectContext
128 * automatically releases all its resources.
130 const GrDirectContext* getContext() const;
131 GrDirectContext* getContext();
134 * Retrieves the amount of GPU memory used by this resource in bytes. It is
135 * approximate since we aren't aware of additional padding or copies made
138 * @return the amount of GPU memory used in bytes
140 size_t gpuMemorySize() const {
141 if (kInvalidGpuMemorySize == fGpuMemorySize) {
142 fGpuMemorySize = this->onGpuMemorySize();
143 SkASSERT(kInvalidGpuMemorySize != fGpuMemorySize);
145 return fGpuMemorySize;
150 UniqueID() = default;
152 explicit UniqueID(uint32_t id) : fID(id) {}
154 uint32_t asUInt() const { return fID; }
156 bool operator==(const UniqueID& other) const { return fID == other.fID; }
157 bool operator!=(const UniqueID& other) const { return !(*this == other); }
159 void makeInvalid() { fID = SK_InvalidUniqueID; }
160 bool isInvalid() const { return fID == SK_InvalidUniqueID; }
163 uint32_t fID = SK_InvalidUniqueID;
167 * Gets an id that is unique for this GrGpuResource object. It is static in that it does
168 * not change when the content of the GrGpuResource object changes. This will never return
171 UniqueID uniqueID() const { return fUniqueID; }
173 /** Returns the current unique key for the resource. It will be invalid if the resource has no
174 associated unique key. */
175 const skgpu::UniqueKey& getUniqueKey() const { return fUniqueKey; }
177 std::string_view getLabel() const { return fLabel; }
179 void setLabel(std::string_view label) { fLabel = label; }
182 * Internal-only helper class used for manipulations of the resource by the cache.
185 inline CacheAccess cacheAccess();
186 inline const CacheAccess cacheAccess() const; // NOLINT(readability-const-return-type)
189 * Internal-only helper class used for manipulations of the resource by GrSurfaceProxy.
192 inline ProxyAccess proxyAccess();
195 * Internal-only helper class used for manipulations of the resource by internal code.
198 inline ResourcePriv resourcePriv();
199 inline const ResourcePriv resourcePriv() const; // NOLINT(readability-const-return-type)
202 * Dumps memory usage information for this GrGpuResource to traceMemoryDump.
203 * Typically, subclasses should not need to override this, and should only
204 * need to override setMemoryBacking.
206 virtual void dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const;
209 * Describes the type of gpu resource that is represented by the implementing
210 * class (e.g. texture, buffer object, stencil). This data is used for diagnostic
211 * purposes by dumpMemoryStatistics().
213 * The value returned is expected to be long lived and will not be copied by the caller.
215 virtual const char* getResourceType() const = 0;
217 static uint32_t CreateUniqueID();
220 // This must be called by every non-wrapped GrGpuObject. It should be called once the object is
221 // fully initialized (i.e. only from the constructors of the final class).
222 void registerWithCache(SkBudgeted);
224 // This must be called by every GrGpuObject that references any wrapped backend objects. It
225 // should be called once the object is fully initialized (i.e. only from the constructors of the
227 void registerWithCacheWrapped(GrWrapCacheable);
229 GrGpuResource(GrGpu*, std::string_view label);
230 virtual ~GrGpuResource();
232 GrGpu* getGpu() const { return fGpu; }
234 /** Overridden to free GPU resources in the backend API. */
235 virtual void onRelease() { }
236 /** Overridden to abandon any internal handles, ptrs, etc to backend API resources.
237 This may be called when the underlying 3D context is no longer valid and so no
238 backend API calls should be made. */
239 virtual void onAbandon() { }
242 * Allows subclasses to add additional backing information to the SkTraceMemoryDump.
244 virtual void setMemoryBacking(SkTraceMemoryDump*, const SkString&) const {}
247 * Returns a string that uniquely identifies this resource.
249 SkString getResourceName() const;
252 * A helper for subclasses that override dumpMemoryStatistics(). This method using a format
253 * consistent with the default implementation of dumpMemoryStatistics() but allows the caller
254 * to customize various inputs.
256 void dumpMemoryStatisticsPriv(SkTraceMemoryDump* traceMemoryDump, const SkString& resourceName,
257 const char* type, size_t size) const;
261 bool isPurgeable() const;
263 bool hasNoCommandBufferUsages() const;
266 * Called by the registerWithCache if the resource is available to be used as scratch.
267 * Resource subclasses should override this if the instances should be recycled as scratch
268 * resources and populate the scratchKey with the key.
269 * By default resources are not recycled as scratch.
271 virtual void computeScratchKey(skgpu::ScratchKey*) const {}
274 * Removes references to objects in the underlying 3D API without freeing them.
275 * Called by CacheAccess.
280 * Frees the object in the underlying 3D API. Called by CacheAccess.
284 virtual size_t onGpuMemorySize() const = 0;
286 // See comments in CacheAccess and ResourcePriv.
287 void setUniqueKey(const skgpu::UniqueKey&);
288 void removeUniqueKey();
289 void notifyARefCntIsZero(LastRemovedRef removedRef) const;
290 void removeScratchKey();
292 void makeUnbudgeted();
295 friend class GrGpu; // for assert in GrGpu to access getGpu
298 // An index into a heap when this resource is purgeable or an array when not. This is maintained
300 int fCacheArrayIndex;
301 // This value reflects how recently this resource was accessed in the cache. This is maintained
304 GrStdSteadyClock::time_point fTimeWhenBecamePurgeable;
306 static const size_t kInvalidGpuMemorySize = ~static_cast<size_t>(0);
307 skgpu::ScratchKey fScratchKey;
308 skgpu::UniqueKey fUniqueKey;
310 // This is not ref'ed but abandon() or release() will be called before the GrGpu object
311 // is destroyed. Those calls will set this to NULL.
313 mutable size_t fGpuMemorySize = kInvalidGpuMemorySize;
315 GrBudgetedType fBudgetedType = GrBudgetedType::kUnbudgetedUncacheable;
316 bool fRefsWrappedObjects = false;
317 const UniqueID fUniqueID;
320 using INHERITED = GrIORef<GrGpuResource>;
321 friend class GrIORef<GrGpuResource>; // to access notifyRefCntWillBeZero and
322 // notifyARefCntIsZero.
325 class GrGpuResource::ProxyAccess {
327 ProxyAccess(GrGpuResource* resource) : fResource(resource) {}
329 /** Proxies are allowed to take a resource from no refs to one ref. */
330 void ref(GrResourceCache* cache);
332 // No taking addresses of this type.
333 const CacheAccess* operator&() const = delete;
334 CacheAccess* operator&() = delete;
336 GrGpuResource* fResource;
338 friend class GrGpuResource;
339 friend class GrSurfaceProxy;
342 inline GrGpuResource::ProxyAccess GrGpuResource::proxyAccess() { return ProxyAccess(this); }