blob: ee61bbe6a1113613671f5e6785702c80f35b4210 [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 *
Greg Danielda642612021-02-09 18:04:02 -050024 * PRIOR to the last ref being removed DERIVED::notifyARefCntWillBeZero() will be called
Robert Phillipsbf8bf832019-08-30 13:13:44 -040025 * (static poly morphism using CRTP). It is legal for additional ref's to be added
Greg Danielda642612021-02-09 18:04:02 -050026 * during this time. AFTER the ref count reaches zero DERIVED::notifyARefCntIsZero() will be
Robert Phillipsbf8bf832019-08-30 13:13:44 -040027 * 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
Greg Danielda642612021-02-09 18:04:02 -050040 // 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
44 };
45
bsalomon00b76bd2014-09-03 14:05:49 -070046 void unref() const {
Brian Salomonb810c252019-09-23 12:48:06 -040047 SkASSERT(this->getRefCnt() > 0);
Greg Danielda642612021-02-09 18:04:02 -050048 if (1 == fRefCnt.fetch_add(-1, std::memory_order_acq_rel)) {
49 this->notifyWillBeZero(LastRemovedRef::kMainRef);
Greg Daniel1fd8ac82020-12-11 11:22:01 -050050 }
51 }
52
53 void addCommandBufferUsage() const {
54 // No barrier required.
55 (void)fCommandBufferUsageCnt.fetch_add(+1, std::memory_order_relaxed);
56 }
57
58 void removeCommandBufferUsage() const {
59 SkASSERT(!this->hasNoCommandBufferUsages());
Greg Danielda642612021-02-09 18:04:02 -050060 if (1 == fCommandBufferUsageCnt.fetch_add(-1, std::memory_order_acq_rel)) {
61 this->notifyWillBeZero(LastRemovedRef::kCommandBufferUsage);
bsalomon3f324322015-04-08 11:01:54 -070062 }
bsalomon00b76bd2014-09-03 14:05:49 -070063 }
64
Robert Phillipsb5204762019-06-19 14:12:13 -040065#if GR_TEST_UTILS
Brian Salomonb810c252019-09-23 12:48:06 -040066 int32_t testingOnly_getRefCnt() const { return this->getRefCnt(); }
Robert Phillipsb5204762019-06-19 14:12:13 -040067#endif
68
bsalomon00b76bd2014-09-03 14:05:49 -070069protected:
Greg Daniel1fd8ac82020-12-11 11:22:01 -050070 GrIORef() : fRefCnt(1), fCommandBufferUsageCnt(0) {}
bsalomon8d034a12014-09-22 12:21:08 -070071
Brian Salomonb810c252019-09-23 12:48:06 -040072 bool internalHasRef() const { return SkToBool(this->getRefCnt()); }
Greg Daniel1fd8ac82020-12-11 11:22:01 -050073 bool internalHasNoCommandBufferUsages() const {
74 return SkToBool(this->hasNoCommandBufferUsages());
75 }
Robert Phillipsbf8bf832019-08-30 13:13:44 -040076
Brian Salomon01ceae92019-04-02 11:49:54 -040077 // Privileged method that allows going from ref count = 0 to ref count = 1.
78 void addInitialRef() const {
Robert Phillipsbf8bf832019-08-30 13:13:44 -040079 SkASSERT(fRefCnt >= 0);
Brian Salomonb810c252019-09-23 12:48:06 -040080 // No barrier required.
81 (void)fRefCnt.fetch_add(+1, std::memory_order_relaxed);
Brian Salomon01ceae92019-04-02 11:49:54 -040082 }
83
bsalomon00b76bd2014-09-03 14:05:49 -070084private:
Greg Danielda642612021-02-09 18:04:02 -050085 void notifyWillBeZero(LastRemovedRef removedRef) const {
86 if (0 == this->getRefCnt() && this->hasNoCommandBufferUsages()) {
87 // At this point we better be the only thread accessing this resource.
88 // Trick out the notifyRefCntWillBeZero() call by adding back one more ref.
89 fRefCnt.fetch_add(+1, std::memory_order_relaxed);
90 static_cast<const DERIVED*>(this)->notifyRefCntWillBeZero();
91 // notifyRefCntWillBeZero() could have done anything, including re-refing this and
92 // passing on to another thread. Take away the ref-count we re-added above and see
93 // if we're back to zero.
94 // TODO: Consider making it so that refs can't be added and merge
95 // notifyRefCntWillBeZero()/willRemoveLastRef() with notifyARefCntIsZero().
96 if (1 == fRefCnt.fetch_add(-1, std::memory_order_acq_rel)) {
97 static_cast<const DERIVED*>(this)->notifyARefCntIsZero(removedRef);
98 }
99 } else {
100 static_cast<const DERIVED*>(this)->notifyARefCntIsZero(removedRef);
Greg Daniel1fd8ac82020-12-11 11:22:01 -0500101 }
102 }
103
Brian Salomonb810c252019-09-23 12:48:06 -0400104 int32_t getRefCnt() const { return fRefCnt.load(std::memory_order_relaxed); }
105
Greg Daniel1fd8ac82020-12-11 11:22:01 -0500106 bool hasNoCommandBufferUsages() const {
107 if (0 == fCommandBufferUsageCnt.load(std::memory_order_acquire)) {
108 // The acquire barrier is only really needed if we return true. It
109 // prevents code conditioned on the result of hasNoCommandBufferUsages() from running
110 // until previous owners are all totally done calling removeCommandBufferUsage().
111 return true;
112 }
113 return false;
114 }
115
Brian Salomonb810c252019-09-23 12:48:06 -0400116 mutable std::atomic<int32_t> fRefCnt;
Greg Daniel1fd8ac82020-12-11 11:22:01 -0500117 mutable std::atomic<int32_t> fCommandBufferUsageCnt;
Robert Phillipsaee18c92019-09-06 11:48:27 -0400118
John Stiles7571f9e2020-09-02 22:42:33 -0400119 using INHERITED = SkNoncopyable;
bsalomon00b76bd2014-09-03 14:05:49 -0700120};
121
122/**
bsalomon0ea80f42015-02-11 10:49:59 -0800123 * Base class for objects that can be kept in the GrResourceCache.
bsalomon00b76bd2014-09-03 14:05:49 -0700124 */
Greg Daniel456f9b52020-03-05 19:14:18 +0000125class GrGpuResource : public GrIORef<GrGpuResource> {
bsalomon00b76bd2014-09-03 14:05:49 -0700126public:
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000127 /**
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000128 * Tests whether a object has been abandoned or released. All objects will
129 * be in this state after their creating GrContext is destroyed or has
130 * contextLost called. It's up to the client to test wasDestroyed() before
131 * attempting to use an object if it holds refs on objects across
132 * ~GrContext, freeResources with the force flag, or contextLost.
133 *
134 * @return true if the object has been released or abandoned,
135 * false otherwise.
136 */
Ben Wagnera93a14a2017-08-28 10:34:05 -0400137 bool wasDestroyed() const { return nullptr == fGpu; }
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000138
139 /**
140 * Retrieves the context that owns the object. Note that it is possible for
141 * this to return NULL. When objects have been release()ed or abandon()ed
142 * they no longer have an owning context. Destroying a GrContext
143 * automatically releases all its resources.
144 */
Robert Phillips4e105e22020-07-16 09:18:50 -0400145 const GrDirectContext* getContext() const;
146 GrDirectContext* getContext();
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000147
bsalomonc44be0e2014-07-25 07:32:33 -0700148 /**
149 * Retrieves the amount of GPU memory used by this resource in bytes. It is
150 * approximate since we aren't aware of additional padding or copies made
151 * by the driver.
152 *
153 * @return the amount of GPU memory used in bytes
154 */
bsalomon69ed47f2014-11-12 11:13:39 -0800155 size_t gpuMemorySize() const {
156 if (kInvalidGpuMemorySize == fGpuMemorySize) {
157 fGpuMemorySize = this->onGpuMemorySize();
158 SkASSERT(kInvalidGpuMemorySize != fGpuMemorySize);
159 }
160 return fGpuMemorySize;
161 }
bsalomonc44be0e2014-07-25 07:32:33 -0700162
Robert Phillips294870f2016-11-11 12:38:40 -0500163 class UniqueID {
164 public:
Brian Salomon8c8806f2019-02-07 13:55:57 -0500165 UniqueID() = default;
Robert Phillips294870f2016-11-11 12:38:40 -0500166
167 explicit UniqueID(uint32_t id) : fID(id) {}
168
169 uint32_t asUInt() const { return fID; }
170
Brian Salomon8c8806f2019-02-07 13:55:57 -0500171 bool operator==(const UniqueID& other) const { return fID == other.fID; }
172 bool operator!=(const UniqueID& other) const { return !(*this == other); }
Robert Phillips294870f2016-11-11 12:38:40 -0500173
174 void makeInvalid() { fID = SK_InvalidUniqueID; }
Brian Salomon8c8806f2019-02-07 13:55:57 -0500175 bool isInvalid() const { return fID == SK_InvalidUniqueID; }
Robert Phillips294870f2016-11-11 12:38:40 -0500176
177 protected:
Brian Salomon8c8806f2019-02-07 13:55:57 -0500178 uint32_t fID = SK_InvalidUniqueID;
Robert Phillips294870f2016-11-11 12:38:40 -0500179 };
180
bsalomonc44be0e2014-07-25 07:32:33 -0700181 /**
bsalomon52e9d632014-09-05 12:23:12 -0700182 * Gets an id that is unique for this GrGpuResource object. It is static in that it does
183 * not change when the content of the GrGpuResource object changes. This will never return
bsalomonc44be0e2014-07-25 07:32:33 -0700184 * 0.
185 */
Robert Phillips294870f2016-11-11 12:38:40 -0500186 UniqueID uniqueID() const { return fUniqueID; }
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000187
bsalomon8718aaf2015-02-19 07:24:21 -0800188 /** Returns the current unique key for the resource. It will be invalid if the resource has no
189 associated unique key. */
190 const GrUniqueKey& getUniqueKey() const { return fUniqueKey; }
bsalomon563ff602015-02-02 17:25:26 -0800191
bsalomon453cf402014-11-11 14:15:57 -0800192 /**
bsalomon3582d3e2015-02-13 14:20:05 -0800193 * Internal-only helper class used for manipulations of the resource by the cache.
bsalomon453cf402014-11-11 14:15:57 -0800194 */
195 class CacheAccess;
196 inline CacheAccess cacheAccess();
John Stilesec9b4aa2020-08-07 13:05:14 -0400197 inline const CacheAccess cacheAccess() const; // NOLINT(readability-const-return-type)
bsalomon453cf402014-11-11 14:15:57 -0800198
junov436293a2014-12-11 10:32:32 -0800199 /**
Brian Salomon01ceae92019-04-02 11:49:54 -0400200 * Internal-only helper class used for manipulations of the resource by GrSurfaceProxy.
201 */
202 class ProxyAccess;
203 inline ProxyAccess proxyAccess();
204
205 /**
bsalomon3582d3e2015-02-13 14:20:05 -0800206 * Internal-only helper class used for manipulations of the resource by internal code.
207 */
208 class ResourcePriv;
209 inline ResourcePriv resourcePriv();
John Stilesec9b4aa2020-08-07 13:05:14 -0400210 inline const ResourcePriv resourcePriv() const; // NOLINT(readability-const-return-type)
bsalomon3582d3e2015-02-13 14:20:05 -0800211
212 /**
ericrk0a5fa482015-09-15 14:16:10 -0700213 * Dumps memory usage information for this GrGpuResource to traceMemoryDump.
214 * Typically, subclasses should not need to override this, and should only
215 * need to override setMemoryBacking.
216 **/
217 virtual void dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const;
218
Derek Sollenbergercf6da8c2018-03-29 13:40:02 -0400219 /**
220 * Describes the type of gpu resource that is represented by the implementing
221 * class (e.g. texture, buffer object, stencil). This data is used for diagnostic
222 * purposes by dumpMemoryStatistics().
223 *
224 * The value returned is expected to be long lived and will not be copied by the caller.
225 */
226 virtual const char* getResourceType() const = 0;
227
robertphillips8abb3702016-08-31 14:04:06 -0700228 static uint32_t CreateUniqueID();
229
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000230protected:
kkinnunen2e6055b2016-04-22 01:48:29 -0700231 // This must be called by every non-wrapped GrGpuObject. It should be called once the object is
232 // fully initialized (i.e. only from the constructors of the final class).
233 void registerWithCache(SkBudgeted);
bsalomon16961262014-08-26 14:01:07 -0700234
kkinnunen2e6055b2016-04-22 01:48:29 -0700235 // This must be called by every GrGpuObject that references any wrapped backend objects. It
236 // should be called once the object is fully initialized (i.e. only from the constructors of the
237 // final class).
Brian Salomonaa6ca0a2019-01-24 16:03:07 -0500238 void registerWithCacheWrapped(GrWrapCacheable);
kkinnunen2e6055b2016-04-22 01:48:29 -0700239
240 GrGpuResource(GrGpu*);
bsalomon6d3fe022014-07-25 08:35:45 -0700241 virtual ~GrGpuResource();
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000242
243 GrGpu* getGpu() const { return fGpu; }
244
bsalomon12299ab2014-11-14 13:33:09 -0800245 /** Overridden to free GPU resources in the backend API. */
Brian Salomon9f7d9a22018-12-11 19:01:32 +0000246 virtual void onRelease() { }
bsalomon12299ab2014-11-14 13:33:09 -0800247 /** Overridden to abandon any internal handles, ptrs, etc to backend API resources.
248 This may be called when the underlying 3D context is no longer valid and so no
249 backend API calls should be made. */
Brian Salomon9f7d9a22018-12-11 19:01:32 +0000250 virtual void onAbandon() { }
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000251
bsalomonc44be0e2014-07-25 07:32:33 -0700252 /**
Derek Sollenbergercf6da8c2018-03-29 13:40:02 -0400253 * Allows subclasses to add additional backing information to the SkTraceMemoryDump.
ericrk0a5fa482015-09-15 14:16:10 -0700254 **/
255 virtual void setMemoryBacking(SkTraceMemoryDump*, const SkString&) const {}
256
Derek Sollenbergercf6da8c2018-03-29 13:40:02 -0400257 /**
258 * Returns a string that uniquely identifies this resource.
259 */
260 SkString getResourceName() const;
261
262 /**
263 * A helper for subclasses that override dumpMemoryStatistics(). This method using a format
264 * consistent with the default implementation of dumpMemoryStatistics() but allows the caller
265 * to customize various inputs.
266 */
267 void dumpMemoryStatisticsPriv(SkTraceMemoryDump* traceMemoryDump, const SkString& resourceName,
268 const char* type, size_t size) const;
269
Brian Salomon9f7d9a22018-12-11 19:01:32 +0000270
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000271private:
Brian Salomon9bc76d92019-01-24 12:18:33 -0500272 bool isPurgeable() const;
Brian Salomon2c791fc2019-04-02 11:52:03 -0400273 bool hasRef() const;
Greg Daniel1fd8ac82020-12-11 11:22:01 -0500274 bool hasNoCommandBufferUsages() const;
Brian Salomon614c1a82018-12-19 15:42:06 -0500275
bsalomon12299ab2014-11-14 13:33:09 -0800276 /**
kkinnunen2e6055b2016-04-22 01:48:29 -0700277 * Called by the registerWithCache if the resource is available to be used as scratch.
278 * Resource subclasses should override this if the instances should be recycled as scratch
279 * resources and populate the scratchKey with the key.
280 * By default resources are not recycled as scratch.
281 **/
Brian Salomon9bc76d92019-01-24 12:18:33 -0500282 virtual void computeScratchKey(GrScratchKey*) const {}
kkinnunen2e6055b2016-04-22 01:48:29 -0700283
284 /**
Brian Salomon35ba6142019-01-24 13:08:59 -0500285 * Removes references to objects in the underlying 3D API without freeing them.
286 * Called by CacheAccess.
287 */
288 void abandon();
289
290 /**
bsalomon12299ab2014-11-14 13:33:09 -0800291 * Frees the object in the underlying 3D API. Called by CacheAccess.
292 */
293 void release();
294
bsalomon69ed47f2014-11-12 11:13:39 -0800295 virtual size_t onGpuMemorySize() const = 0;
296
Brian Salomon614c1a82018-12-19 15:42:06 -0500297 /**
Robert Phillipsbf8bf832019-08-30 13:13:44 -0400298 * Called by GrIORef when a resource is about to lose its last ref
Brian Salomon614c1a82018-12-19 15:42:06 -0500299 */
Robert Phillipsbf8bf832019-08-30 13:13:44 -0400300 virtual void willRemoveLastRef() {}
Brian Salomon614c1a82018-12-19 15:42:06 -0500301
bsalomon9f2d1572015-02-17 11:47:40 -0800302 // See comments in CacheAccess and ResourcePriv.
bsalomonf99e9612015-02-19 08:24:16 -0800303 void setUniqueKey(const GrUniqueKey&);
bsalomon8718aaf2015-02-19 07:24:21 -0800304 void removeUniqueKey();
Robert Phillipsbf8bf832019-08-30 13:13:44 -0400305 void notifyRefCntWillBeZero() const;
Greg Danielda642612021-02-09 18:04:02 -0500306 void notifyARefCntIsZero(LastRemovedRef removedRef) const;
bsalomon10e23ca2014-11-25 05:52:06 -0800307 void removeScratchKey();
bsalomonafe30052015-01-16 07:32:33 -0800308 void makeBudgeted();
bsalomonc2f35b72015-01-23 07:19:22 -0800309 void makeUnbudgeted();
bsalomonbcf0a522014-10-08 08:40:09 -0700310
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000311#ifdef SK_DEBUG
Brian Salomon5e150852017-03-22 14:53:13 -0400312 friend class GrGpu; // for assert in GrGpu to access getGpu
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000313#endif
Brian Salomon5e150852017-03-22 14:53:13 -0400314
bsalomonf320e042015-02-17 15:09:34 -0800315 // An index into a heap when this resource is purgeable or an array when not. This is maintained
316 // by the cache.
Brian Salomon5e150852017-03-22 14:53:13 -0400317 int fCacheArrayIndex;
bsalomon9f2d1572015-02-17 11:47:40 -0800318 // This value reflects how recently this resource was accessed in the cache. This is maintained
319 // by the cache.
Brian Salomon5e150852017-03-22 14:53:13 -0400320 uint32_t fTimestamp;
Brian Salomon5e150852017-03-22 14:53:13 -0400321 GrStdSteadyClock::time_point fTimeWhenBecamePurgeable;
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000322
bsalomon69ed47f2014-11-12 11:13:39 -0800323 static const size_t kInvalidGpuMemorySize = ~static_cast<size_t>(0);
Brian Salomon5e150852017-03-22 14:53:13 -0400324 GrScratchKey fScratchKey;
325 GrUniqueKey fUniqueKey;
bsalomon84c8e622014-11-17 09:33:27 -0800326
327 // This is not ref'ed but abandon() or release() will be called before the GrGpu object
328 // is destroyed. Those calls set will this to NULL.
Brian Salomon5e150852017-03-22 14:53:13 -0400329 GrGpu* fGpu;
Brian Salomonfa2ebea2019-01-24 15:58:58 -0500330 mutable size_t fGpuMemorySize = kInvalidGpuMemorySize;
bsalomon84c8e622014-11-17 09:33:27 -0800331
Brian Salomonaa6ca0a2019-01-24 16:03:07 -0500332 GrBudgetedType fBudgetedType = GrBudgetedType::kUnbudgetedUncacheable;
Brian Salomonfa2ebea2019-01-24 15:58:58 -0500333 bool fRefsWrappedObjects = false;
Brian Salomon5e150852017-03-22 14:53:13 -0400334 const UniqueID fUniqueID;
bsalomon744998e2014-08-28 09:54:34 -0700335
John Stiles7571f9e2020-09-02 22:42:33 -0400336 using INHERITED = GrIORef<GrGpuResource>;
Greg Danielda642612021-02-09 18:04:02 -0500337 friend class GrIORef<GrGpuResource>; // to access notifyRefCntWillBeZero and
338 // notifyARefCntIsZero.
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000339};
340
Brian Salomon01ceae92019-04-02 11:49:54 -0400341class GrGpuResource::ProxyAccess {
342private:
343 ProxyAccess(GrGpuResource* resource) : fResource(resource) {}
344
345 /** Proxies are allowed to take a resource from no refs to one ref. */
Brian Salomon2c791fc2019-04-02 11:52:03 -0400346 void ref(GrResourceCache* cache);
Brian Salomon01ceae92019-04-02 11:49:54 -0400347
348 // No taking addresses of this type.
349 const CacheAccess* operator&() const = delete;
350 CacheAccess* operator&() = delete;
351
352 GrGpuResource* fResource;
353
354 friend class GrGpuResource;
355 friend class GrSurfaceProxy;
Brian Salomon01ceae92019-04-02 11:49:54 -0400356};
357
358inline GrGpuResource::ProxyAccess GrGpuResource::proxyAccess() { return ProxyAccess(this); }
359
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000360#endif