blob: 79876d393f4b676370f841f09bb62bddb7d21219 [file] [log] [blame]
commit-bot@chromium.org089a7802014-05-02 21:38:22 +00001/*
bsalomonc44be0e2014-07-25 07:32:33 -07002 * Copyright 2014 Google Inc.
commit-bot@chromium.org089a7802014-05-02 21:38:22 +00003 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
bsalomon6d3fe022014-07-25 08:35:45 -07008#ifndef GrGpuResource_DEFINED
9#define GrGpuResource_DEFINED
commit-bot@chromium.org089a7802014-05-02 21:38:22 +000010
Mike Kleinc0bd9f92019-04-23 12:05:21 -050011#include "include/private/GrResourceKey.h"
12#include "include/private/GrTypesPriv.h"
13#include "include/private/SkNoncopyable.h"
commit-bot@chromium.org089a7802014-05-02 21:38:22 +000014
bsalomon37dd3312014-11-03 08:47:23 -080015class GrGpu;
bsalomon0ea80f42015-02-11 10:49:59 -080016class GrResourceCache;
ericrk0a5fa482015-09-15 14:16:10 -070017class SkTraceMemoryDump;
commit-bot@chromium.org089a7802014-05-02 21:38:22 +000018
19/**
Robert Phillipsbf8bf832019-08-30 13:13:44 -040020 * 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.
mtklein6f076652015-01-13 08:22:43 -080023 *
Robert Phillipsbf8bf832019-08-30 13:13:44 -040024 * PRIOR to the last ref being removed DERIVED::notifyRefCntWillBeZero() 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::notifyRefCntIsZero() will be
27 * called.
commit-bot@chromium.org089a7802014-05-02 21:38:22 +000028 */
bsalomonbcf0a522014-10-08 08:40:09 -070029template <typename DERIVED> class GrIORef : public SkNoncopyable {
commit-bot@chromium.org089a7802014-05-02 21:38:22 +000030public:
Robert Phillipsaee18c92019-09-06 11:48:27 -040031 bool unique() const { return fRefCnt == 1; }
32
bsalomon00b76bd2014-09-03 14:05:49 -070033 void ref() const {
Brian Salomon01ceae92019-04-02 11:49:54 -040034 // Only the cache should be able to add the first ref to a resource.
Brian Salomonb810c252019-09-23 12:48:06 -040035 SkASSERT(this->getRefCnt() > 0);
36 // No barrier required.
37 (void)fRefCnt.fetch_add(+1, std::memory_order_relaxed);
bsalomonc44be0e2014-07-25 07:32:33 -070038 }
bsalomon00b76bd2014-09-03 14:05:49 -070039
40 void unref() const {
Brian Salomonb810c252019-09-23 12:48:06 -040041 SkASSERT(this->getRefCnt() > 0);
Greg Daniel1fd8ac82020-12-11 11:22:01 -050042 if (1 == fRefCnt.fetch_add(-1, std::memory_order_acq_rel) &&
43 this->hasNoCommandBufferUsages()) {
44 this->notifyWillBeZero();
45 }
46 }
47
48 void addCommandBufferUsage() const {
49 // No barrier required.
50 (void)fCommandBufferUsageCnt.fetch_add(+1, std::memory_order_relaxed);
51 }
52
53 void removeCommandBufferUsage() const {
54 SkASSERT(!this->hasNoCommandBufferUsages());
55 if (1 == fCommandBufferUsageCnt.fetch_add(-1, std::memory_order_acq_rel) &&
56 0 == this->getRefCnt()) {
57 this->notifyWillBeZero();
bsalomon3f324322015-04-08 11:01:54 -070058 }
bsalomon00b76bd2014-09-03 14:05:49 -070059 }
60
Robert Phillipsb5204762019-06-19 14:12:13 -040061#if GR_TEST_UTILS
Brian Salomonb810c252019-09-23 12:48:06 -040062 int32_t testingOnly_getRefCnt() const { return this->getRefCnt(); }
Robert Phillipsb5204762019-06-19 14:12:13 -040063#endif
64
bsalomon00b76bd2014-09-03 14:05:49 -070065protected:
Robert Phillipsbf8bf832019-08-30 13:13:44 -040066 friend class GrResourceCache; // for internalHasRef
bsalomon00b76bd2014-09-03 14:05:49 -070067
Greg Daniel1fd8ac82020-12-11 11:22:01 -050068 GrIORef() : fRefCnt(1), fCommandBufferUsageCnt(0) {}
bsalomon8d034a12014-09-22 12:21:08 -070069
Brian Salomonb810c252019-09-23 12:48:06 -040070 bool internalHasRef() const { return SkToBool(this->getRefCnt()); }
Greg Daniel1fd8ac82020-12-11 11:22:01 -050071 bool internalHasNoCommandBufferUsages() const {
72 return SkToBool(this->hasNoCommandBufferUsages());
73 }
Robert Phillipsbf8bf832019-08-30 13:13:44 -040074
Brian Salomon01ceae92019-04-02 11:49:54 -040075 // Privileged method that allows going from ref count = 0 to ref count = 1.
76 void addInitialRef() const {
Robert Phillipsbf8bf832019-08-30 13:13:44 -040077 SkASSERT(fRefCnt >= 0);
Brian Salomonb810c252019-09-23 12:48:06 -040078 // No barrier required.
79 (void)fRefCnt.fetch_add(+1, std::memory_order_relaxed);
Brian Salomon01ceae92019-04-02 11:49:54 -040080 }
81
bsalomon00b76bd2014-09-03 14:05:49 -070082private:
Greg Daniel1fd8ac82020-12-11 11:22:01 -050083 void notifyWillBeZero() const {
84 // At this point we better be the only thread accessing this resource.
85 // Trick out the notifyRefCntWillBeZero() call by adding back one more ref.
86 fRefCnt.fetch_add(+1, std::memory_order_relaxed);
87 static_cast<const DERIVED*>(this)->notifyRefCntWillBeZero();
88 // notifyRefCntWillBeZero() could have done anything, including re-refing this and
89 // passing on to another thread. Take away the ref-count we re-added above and see
90 // if we're back to zero.
91 // TODO: Consider making it so that refs can't be added and merge
92 // notifyRefCntWillBeZero()/willRemoveLastRef() with notifyRefCntIsZero().
93 if (1 == fRefCnt.fetch_add(-1, std::memory_order_acq_rel)) {
94 static_cast<const DERIVED*>(this)->notifyRefCntIsZero();
95 }
96 }
97
Brian Salomonb810c252019-09-23 12:48:06 -040098 int32_t getRefCnt() const { return fRefCnt.load(std::memory_order_relaxed); }
99
Greg Daniel1fd8ac82020-12-11 11:22:01 -0500100 bool hasNoCommandBufferUsages() const {
101 if (0 == fCommandBufferUsageCnt.load(std::memory_order_acquire)) {
102 // The acquire barrier is only really needed if we return true. It
103 // prevents code conditioned on the result of hasNoCommandBufferUsages() from running
104 // until previous owners are all totally done calling removeCommandBufferUsage().
105 return true;
106 }
107 return false;
108 }
109
Brian Salomonb810c252019-09-23 12:48:06 -0400110 mutable std::atomic<int32_t> fRefCnt;
Greg Daniel1fd8ac82020-12-11 11:22:01 -0500111 mutable std::atomic<int32_t> fCommandBufferUsageCnt;
Robert Phillipsaee18c92019-09-06 11:48:27 -0400112
John Stiles7571f9e2020-09-02 22:42:33 -0400113 using INHERITED = SkNoncopyable;
bsalomon00b76bd2014-09-03 14:05:49 -0700114};
115
116/**
bsalomon0ea80f42015-02-11 10:49:59 -0800117 * Base class for objects that can be kept in the GrResourceCache.
bsalomon00b76bd2014-09-03 14:05:49 -0700118 */
Greg Daniel456f9b52020-03-05 19:14:18 +0000119class GrGpuResource : public GrIORef<GrGpuResource> {
bsalomon00b76bd2014-09-03 14:05:49 -0700120public:
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000121 /**
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000122 * Tests whether a object has been abandoned or released. All objects will
123 * be in this state after their creating GrContext is destroyed or has
124 * contextLost called. It's up to the client to test wasDestroyed() before
125 * attempting to use an object if it holds refs on objects across
126 * ~GrContext, freeResources with the force flag, or contextLost.
127 *
128 * @return true if the object has been released or abandoned,
129 * false otherwise.
130 */
Ben Wagnera93a14a2017-08-28 10:34:05 -0400131 bool wasDestroyed() const { return nullptr == fGpu; }
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000132
133 /**
134 * Retrieves the context that owns the object. Note that it is possible for
135 * this to return NULL. When objects have been release()ed or abandon()ed
136 * they no longer have an owning context. Destroying a GrContext
137 * automatically releases all its resources.
138 */
Robert Phillips4e105e22020-07-16 09:18:50 -0400139 const GrDirectContext* getContext() const;
140 GrDirectContext* getContext();
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000141
bsalomonc44be0e2014-07-25 07:32:33 -0700142 /**
143 * Retrieves the amount of GPU memory used by this resource in bytes. It is
144 * approximate since we aren't aware of additional padding or copies made
145 * by the driver.
146 *
147 * @return the amount of GPU memory used in bytes
148 */
bsalomon69ed47f2014-11-12 11:13:39 -0800149 size_t gpuMemorySize() const {
150 if (kInvalidGpuMemorySize == fGpuMemorySize) {
151 fGpuMemorySize = this->onGpuMemorySize();
152 SkASSERT(kInvalidGpuMemorySize != fGpuMemorySize);
153 }
154 return fGpuMemorySize;
155 }
bsalomonc44be0e2014-07-25 07:32:33 -0700156
Robert Phillips294870f2016-11-11 12:38:40 -0500157 class UniqueID {
158 public:
Brian Salomon8c8806f2019-02-07 13:55:57 -0500159 UniqueID() = default;
Robert Phillips294870f2016-11-11 12:38:40 -0500160
161 explicit UniqueID(uint32_t id) : fID(id) {}
162
163 uint32_t asUInt() const { return fID; }
164
Brian Salomon8c8806f2019-02-07 13:55:57 -0500165 bool operator==(const UniqueID& other) const { return fID == other.fID; }
166 bool operator!=(const UniqueID& other) const { return !(*this == other); }
Robert Phillips294870f2016-11-11 12:38:40 -0500167
168 void makeInvalid() { fID = SK_InvalidUniqueID; }
Brian Salomon8c8806f2019-02-07 13:55:57 -0500169 bool isInvalid() const { return fID == SK_InvalidUniqueID; }
Robert Phillips294870f2016-11-11 12:38:40 -0500170
171 protected:
Brian Salomon8c8806f2019-02-07 13:55:57 -0500172 uint32_t fID = SK_InvalidUniqueID;
Robert Phillips294870f2016-11-11 12:38:40 -0500173 };
174
bsalomonc44be0e2014-07-25 07:32:33 -0700175 /**
bsalomon52e9d632014-09-05 12:23:12 -0700176 * Gets an id that is unique for this GrGpuResource object. It is static in that it does
177 * not change when the content of the GrGpuResource object changes. This will never return
bsalomonc44be0e2014-07-25 07:32:33 -0700178 * 0.
179 */
Robert Phillips294870f2016-11-11 12:38:40 -0500180 UniqueID uniqueID() const { return fUniqueID; }
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000181
bsalomon8718aaf2015-02-19 07:24:21 -0800182 /** Returns the current unique key for the resource. It will be invalid if the resource has no
183 associated unique key. */
184 const GrUniqueKey& getUniqueKey() const { return fUniqueKey; }
bsalomon563ff602015-02-02 17:25:26 -0800185
bsalomon453cf402014-11-11 14:15:57 -0800186 /**
bsalomon3582d3e2015-02-13 14:20:05 -0800187 * Internal-only helper class used for manipulations of the resource by the cache.
bsalomon453cf402014-11-11 14:15:57 -0800188 */
189 class CacheAccess;
190 inline CacheAccess cacheAccess();
John Stilesec9b4aa2020-08-07 13:05:14 -0400191 inline const CacheAccess cacheAccess() const; // NOLINT(readability-const-return-type)
bsalomon453cf402014-11-11 14:15:57 -0800192
junov436293a2014-12-11 10:32:32 -0800193 /**
Brian Salomon01ceae92019-04-02 11:49:54 -0400194 * Internal-only helper class used for manipulations of the resource by GrSurfaceProxy.
195 */
196 class ProxyAccess;
197 inline ProxyAccess proxyAccess();
198
199 /**
bsalomon3582d3e2015-02-13 14:20:05 -0800200 * Internal-only helper class used for manipulations of the resource by internal code.
201 */
202 class ResourcePriv;
203 inline ResourcePriv resourcePriv();
John Stilesec9b4aa2020-08-07 13:05:14 -0400204 inline const ResourcePriv resourcePriv() const; // NOLINT(readability-const-return-type)
bsalomon3582d3e2015-02-13 14:20:05 -0800205
206 /**
ericrk0a5fa482015-09-15 14:16:10 -0700207 * Dumps memory usage information for this GrGpuResource to traceMemoryDump.
208 * Typically, subclasses should not need to override this, and should only
209 * need to override setMemoryBacking.
210 **/
211 virtual void dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const;
212
Derek Sollenbergercf6da8c2018-03-29 13:40:02 -0400213 /**
214 * Describes the type of gpu resource that is represented by the implementing
215 * class (e.g. texture, buffer object, stencil). This data is used for diagnostic
216 * purposes by dumpMemoryStatistics().
217 *
218 * The value returned is expected to be long lived and will not be copied by the caller.
219 */
220 virtual const char* getResourceType() const = 0;
221
robertphillips8abb3702016-08-31 14:04:06 -0700222 static uint32_t CreateUniqueID();
223
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000224protected:
kkinnunen2e6055b2016-04-22 01:48:29 -0700225 // This must be called by every non-wrapped GrGpuObject. It should be called once the object is
226 // fully initialized (i.e. only from the constructors of the final class).
227 void registerWithCache(SkBudgeted);
bsalomon16961262014-08-26 14:01:07 -0700228
kkinnunen2e6055b2016-04-22 01:48:29 -0700229 // This must be called by every GrGpuObject that references any wrapped backend objects. It
230 // should be called once the object is fully initialized (i.e. only from the constructors of the
231 // final class).
Brian Salomonaa6ca0a2019-01-24 16:03:07 -0500232 void registerWithCacheWrapped(GrWrapCacheable);
kkinnunen2e6055b2016-04-22 01:48:29 -0700233
234 GrGpuResource(GrGpu*);
bsalomon6d3fe022014-07-25 08:35:45 -0700235 virtual ~GrGpuResource();
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000236
237 GrGpu* getGpu() const { return fGpu; }
238
bsalomon12299ab2014-11-14 13:33:09 -0800239 /** Overridden to free GPU resources in the backend API. */
Brian Salomon9f7d9a22018-12-11 19:01:32 +0000240 virtual void onRelease() { }
bsalomon12299ab2014-11-14 13:33:09 -0800241 /** Overridden to abandon any internal handles, ptrs, etc to backend API resources.
242 This may be called when the underlying 3D context is no longer valid and so no
243 backend API calls should be made. */
Brian Salomon9f7d9a22018-12-11 19:01:32 +0000244 virtual void onAbandon() { }
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000245
bsalomonc44be0e2014-07-25 07:32:33 -0700246 /**
Derek Sollenbergercf6da8c2018-03-29 13:40:02 -0400247 * Allows subclasses to add additional backing information to the SkTraceMemoryDump.
ericrk0a5fa482015-09-15 14:16:10 -0700248 **/
249 virtual void setMemoryBacking(SkTraceMemoryDump*, const SkString&) const {}
250
Derek Sollenbergercf6da8c2018-03-29 13:40:02 -0400251 /**
252 * Returns a string that uniquely identifies this resource.
253 */
254 SkString getResourceName() const;
255
256 /**
257 * A helper for subclasses that override dumpMemoryStatistics(). This method using a format
258 * consistent with the default implementation of dumpMemoryStatistics() but allows the caller
259 * to customize various inputs.
260 */
261 void dumpMemoryStatisticsPriv(SkTraceMemoryDump* traceMemoryDump, const SkString& resourceName,
262 const char* type, size_t size) const;
263
Brian Salomon9f7d9a22018-12-11 19:01:32 +0000264
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000265private:
Brian Salomon9bc76d92019-01-24 12:18:33 -0500266 bool isPurgeable() const;
Brian Salomon2c791fc2019-04-02 11:52:03 -0400267 bool hasRef() const;
Greg Daniel1fd8ac82020-12-11 11:22:01 -0500268 bool hasNoCommandBufferUsages() const;
Brian Salomon614c1a82018-12-19 15:42:06 -0500269
bsalomon12299ab2014-11-14 13:33:09 -0800270 /**
kkinnunen2e6055b2016-04-22 01:48:29 -0700271 * Called by the registerWithCache if the resource is available to be used as scratch.
272 * Resource subclasses should override this if the instances should be recycled as scratch
273 * resources and populate the scratchKey with the key.
274 * By default resources are not recycled as scratch.
275 **/
Brian Salomon9bc76d92019-01-24 12:18:33 -0500276 virtual void computeScratchKey(GrScratchKey*) const {}
kkinnunen2e6055b2016-04-22 01:48:29 -0700277
278 /**
Brian Salomon35ba6142019-01-24 13:08:59 -0500279 * Removes references to objects in the underlying 3D API without freeing them.
280 * Called by CacheAccess.
281 */
282 void abandon();
283
284 /**
bsalomon12299ab2014-11-14 13:33:09 -0800285 * Frees the object in the underlying 3D API. Called by CacheAccess.
286 */
287 void release();
288
bsalomon69ed47f2014-11-12 11:13:39 -0800289 virtual size_t onGpuMemorySize() const = 0;
290
Brian Salomon614c1a82018-12-19 15:42:06 -0500291 /**
Robert Phillipsbf8bf832019-08-30 13:13:44 -0400292 * Called by GrIORef when a resource is about to lose its last ref
Brian Salomon614c1a82018-12-19 15:42:06 -0500293 */
Robert Phillipsbf8bf832019-08-30 13:13:44 -0400294 virtual void willRemoveLastRef() {}
Brian Salomon614c1a82018-12-19 15:42:06 -0500295
bsalomon9f2d1572015-02-17 11:47:40 -0800296 // See comments in CacheAccess and ResourcePriv.
bsalomonf99e9612015-02-19 08:24:16 -0800297 void setUniqueKey(const GrUniqueKey&);
bsalomon8718aaf2015-02-19 07:24:21 -0800298 void removeUniqueKey();
Robert Phillipsbf8bf832019-08-30 13:13:44 -0400299 void notifyRefCntWillBeZero() const;
300 void notifyRefCntIsZero() const;
bsalomon10e23ca2014-11-25 05:52:06 -0800301 void removeScratchKey();
bsalomonafe30052015-01-16 07:32:33 -0800302 void makeBudgeted();
bsalomonc2f35b72015-01-23 07:19:22 -0800303 void makeUnbudgeted();
bsalomonbcf0a522014-10-08 08:40:09 -0700304
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000305#ifdef SK_DEBUG
Brian Salomon5e150852017-03-22 14:53:13 -0400306 friend class GrGpu; // for assert in GrGpu to access getGpu
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000307#endif
Brian Salomon5e150852017-03-22 14:53:13 -0400308
bsalomonf320e042015-02-17 15:09:34 -0800309 // An index into a heap when this resource is purgeable or an array when not. This is maintained
310 // by the cache.
Brian Salomon5e150852017-03-22 14:53:13 -0400311 int fCacheArrayIndex;
bsalomon9f2d1572015-02-17 11:47:40 -0800312 // This value reflects how recently this resource was accessed in the cache. This is maintained
313 // by the cache.
Brian Salomon5e150852017-03-22 14:53:13 -0400314 uint32_t fTimestamp;
Brian Salomon5e150852017-03-22 14:53:13 -0400315 GrStdSteadyClock::time_point fTimeWhenBecamePurgeable;
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000316
bsalomon69ed47f2014-11-12 11:13:39 -0800317 static const size_t kInvalidGpuMemorySize = ~static_cast<size_t>(0);
Brian Salomon5e150852017-03-22 14:53:13 -0400318 GrScratchKey fScratchKey;
319 GrUniqueKey fUniqueKey;
bsalomon84c8e622014-11-17 09:33:27 -0800320
321 // This is not ref'ed but abandon() or release() will be called before the GrGpu object
322 // is destroyed. Those calls set will this to NULL.
Brian Salomon5e150852017-03-22 14:53:13 -0400323 GrGpu* fGpu;
Brian Salomonfa2ebea2019-01-24 15:58:58 -0500324 mutable size_t fGpuMemorySize = kInvalidGpuMemorySize;
bsalomon84c8e622014-11-17 09:33:27 -0800325
Brian Salomonaa6ca0a2019-01-24 16:03:07 -0500326 GrBudgetedType fBudgetedType = GrBudgetedType::kUnbudgetedUncacheable;
Brian Salomonfa2ebea2019-01-24 15:58:58 -0500327 bool fRefsWrappedObjects = false;
Brian Salomon5e150852017-03-22 14:53:13 -0400328 const UniqueID fUniqueID;
bsalomon744998e2014-08-28 09:54:34 -0700329
John Stiles7571f9e2020-09-02 22:42:33 -0400330 using INHERITED = GrIORef<GrGpuResource>;
Robert Phillipsbf8bf832019-08-30 13:13:44 -0400331 friend class GrIORef<GrGpuResource>; // to access notifyRefCntWillBeZero and notifyRefCntIsZero.
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000332};
333
Brian Salomon01ceae92019-04-02 11:49:54 -0400334class GrGpuResource::ProxyAccess {
335private:
336 ProxyAccess(GrGpuResource* resource) : fResource(resource) {}
337
338 /** Proxies are allowed to take a resource from no refs to one ref. */
Brian Salomon2c791fc2019-04-02 11:52:03 -0400339 void ref(GrResourceCache* cache);
Brian Salomon01ceae92019-04-02 11:49:54 -0400340
341 // No taking addresses of this type.
342 const CacheAccess* operator&() const = delete;
343 CacheAccess* operator&() = delete;
344
345 GrGpuResource* fResource;
346
347 friend class GrGpuResource;
348 friend class GrSurfaceProxy;
Brian Salomon01ceae92019-04-02 11:49:54 -0400349};
350
351inline GrGpuResource::ProxyAccess GrGpuResource::proxyAccess() { return ProxyAccess(this); }
352
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000353#endif