blob: e4b3d46dd1cd3d9bc0f6e65be31f827304b526e3 [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);
42 if (1 == fRefCnt.fetch_add(-1, std::memory_order_acq_rel)) {
43 // At this point we better be the only thread accessing this resource.
44 // Trick out the notifyRefCntWillBeZero() call by adding back one more ref.
45 fRefCnt.fetch_add(+1, std::memory_order_relaxed);
Robert Phillipsbf8bf832019-08-30 13:13:44 -040046 static_cast<const DERIVED*>(this)->notifyRefCntWillBeZero();
Brian Salomonb810c252019-09-23 12:48:06 -040047 // notifyRefCntWillBeZero() could have done anything, including re-refing this and
48 // passing on to another thread. Take away the ref-count we re-added above and see
49 // if we're back to zero.
50 // TODO: Consider making it so that refs can't be added and merge
51 // notifyRefCntWillBeZero()/willRemoveLastRef() with notifyRefCntIsZero().
52 if (1 == fRefCnt.fetch_add(-1, std::memory_order_acq_rel)) {
53 static_cast<const DERIVED*>(this)->notifyRefCntIsZero();
54 }
bsalomon3f324322015-04-08 11:01:54 -070055 }
bsalomon00b76bd2014-09-03 14:05:49 -070056 }
57
Robert Phillipsb5204762019-06-19 14:12:13 -040058#if GR_TEST_UTILS
Brian Salomonb810c252019-09-23 12:48:06 -040059 int32_t testingOnly_getRefCnt() const { return this->getRefCnt(); }
Robert Phillipsb5204762019-06-19 14:12:13 -040060#endif
61
bsalomon00b76bd2014-09-03 14:05:49 -070062protected:
Robert Phillipsbf8bf832019-08-30 13:13:44 -040063 friend class GrResourceCache; // for internalHasRef
bsalomon00b76bd2014-09-03 14:05:49 -070064
Robert Phillipsbf8bf832019-08-30 13:13:44 -040065 GrIORef() : fRefCnt(1) {}
bsalomon8d034a12014-09-22 12:21:08 -070066
Brian Salomonb810c252019-09-23 12:48:06 -040067 bool internalHasRef() const { return SkToBool(this->getRefCnt()); }
Robert Phillipsbf8bf832019-08-30 13:13:44 -040068
Brian Salomon01ceae92019-04-02 11:49:54 -040069 // Privileged method that allows going from ref count = 0 to ref count = 1.
70 void addInitialRef() const {
Robert Phillipsbf8bf832019-08-30 13:13:44 -040071 SkASSERT(fRefCnt >= 0);
Brian Salomonb810c252019-09-23 12:48:06 -040072 // No barrier required.
73 (void)fRefCnt.fetch_add(+1, std::memory_order_relaxed);
Brian Salomon01ceae92019-04-02 11:49:54 -040074 }
75
bsalomon00b76bd2014-09-03 14:05:49 -070076private:
Brian Salomonb810c252019-09-23 12:48:06 -040077 int32_t getRefCnt() const { return fRefCnt.load(std::memory_order_relaxed); }
78
79 mutable std::atomic<int32_t> fRefCnt;
Robert Phillipsaee18c92019-09-06 11:48:27 -040080
John Stiles7571f9e2020-09-02 22:42:33 -040081 using INHERITED = SkNoncopyable;
bsalomon00b76bd2014-09-03 14:05:49 -070082};
83
84/**
bsalomon0ea80f42015-02-11 10:49:59 -080085 * Base class for objects that can be kept in the GrResourceCache.
bsalomon00b76bd2014-09-03 14:05:49 -070086 */
Greg Daniel456f9b52020-03-05 19:14:18 +000087class GrGpuResource : public GrIORef<GrGpuResource> {
bsalomon00b76bd2014-09-03 14:05:49 -070088public:
commit-bot@chromium.org089a7802014-05-02 21:38:22 +000089 /**
commit-bot@chromium.org089a7802014-05-02 21:38:22 +000090 * Tests whether a object has been abandoned or released. All objects will
91 * be in this state after their creating GrContext is destroyed or has
92 * contextLost called. It's up to the client to test wasDestroyed() before
93 * attempting to use an object if it holds refs on objects across
94 * ~GrContext, freeResources with the force flag, or contextLost.
95 *
96 * @return true if the object has been released or abandoned,
97 * false otherwise.
98 */
Ben Wagnera93a14a2017-08-28 10:34:05 -040099 bool wasDestroyed() const { return nullptr == fGpu; }
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000100
101 /**
102 * Retrieves the context that owns the object. Note that it is possible for
103 * this to return NULL. When objects have been release()ed or abandon()ed
104 * they no longer have an owning context. Destroying a GrContext
105 * automatically releases all its resources.
106 */
Robert Phillips4e105e22020-07-16 09:18:50 -0400107 const GrDirectContext* getContext() const;
108 GrDirectContext* getContext();
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000109
bsalomonc44be0e2014-07-25 07:32:33 -0700110 /**
111 * Retrieves the amount of GPU memory used by this resource in bytes. It is
112 * approximate since we aren't aware of additional padding or copies made
113 * by the driver.
114 *
115 * @return the amount of GPU memory used in bytes
116 */
bsalomon69ed47f2014-11-12 11:13:39 -0800117 size_t gpuMemorySize() const {
118 if (kInvalidGpuMemorySize == fGpuMemorySize) {
119 fGpuMemorySize = this->onGpuMemorySize();
120 SkASSERT(kInvalidGpuMemorySize != fGpuMemorySize);
121 }
122 return fGpuMemorySize;
123 }
bsalomonc44be0e2014-07-25 07:32:33 -0700124
Robert Phillips294870f2016-11-11 12:38:40 -0500125 class UniqueID {
126 public:
Brian Salomon8c8806f2019-02-07 13:55:57 -0500127 UniqueID() = default;
Robert Phillips294870f2016-11-11 12:38:40 -0500128
129 explicit UniqueID(uint32_t id) : fID(id) {}
130
131 uint32_t asUInt() const { return fID; }
132
Brian Salomon8c8806f2019-02-07 13:55:57 -0500133 bool operator==(const UniqueID& other) const { return fID == other.fID; }
134 bool operator!=(const UniqueID& other) const { return !(*this == other); }
Robert Phillips294870f2016-11-11 12:38:40 -0500135
136 void makeInvalid() { fID = SK_InvalidUniqueID; }
Brian Salomon8c8806f2019-02-07 13:55:57 -0500137 bool isInvalid() const { return fID == SK_InvalidUniqueID; }
Robert Phillips294870f2016-11-11 12:38:40 -0500138
139 protected:
Brian Salomon8c8806f2019-02-07 13:55:57 -0500140 uint32_t fID = SK_InvalidUniqueID;
Robert Phillips294870f2016-11-11 12:38:40 -0500141 };
142
bsalomonc44be0e2014-07-25 07:32:33 -0700143 /**
bsalomon52e9d632014-09-05 12:23:12 -0700144 * Gets an id that is unique for this GrGpuResource object. It is static in that it does
145 * not change when the content of the GrGpuResource object changes. This will never return
bsalomonc44be0e2014-07-25 07:32:33 -0700146 * 0.
147 */
Robert Phillips294870f2016-11-11 12:38:40 -0500148 UniqueID uniqueID() const { return fUniqueID; }
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000149
bsalomon8718aaf2015-02-19 07:24:21 -0800150 /** Returns the current unique key for the resource. It will be invalid if the resource has no
151 associated unique key. */
152 const GrUniqueKey& getUniqueKey() const { return fUniqueKey; }
bsalomon563ff602015-02-02 17:25:26 -0800153
bsalomon453cf402014-11-11 14:15:57 -0800154 /**
bsalomon3582d3e2015-02-13 14:20:05 -0800155 * Internal-only helper class used for manipulations of the resource by the cache.
bsalomon453cf402014-11-11 14:15:57 -0800156 */
157 class CacheAccess;
158 inline CacheAccess cacheAccess();
John Stilesec9b4aa2020-08-07 13:05:14 -0400159 inline const CacheAccess cacheAccess() const; // NOLINT(readability-const-return-type)
bsalomon453cf402014-11-11 14:15:57 -0800160
junov436293a2014-12-11 10:32:32 -0800161 /**
Brian Salomon01ceae92019-04-02 11:49:54 -0400162 * Internal-only helper class used for manipulations of the resource by GrSurfaceProxy.
163 */
164 class ProxyAccess;
165 inline ProxyAccess proxyAccess();
166
167 /**
bsalomon3582d3e2015-02-13 14:20:05 -0800168 * Internal-only helper class used for manipulations of the resource by internal code.
169 */
170 class ResourcePriv;
171 inline ResourcePriv resourcePriv();
John Stilesec9b4aa2020-08-07 13:05:14 -0400172 inline const ResourcePriv resourcePriv() const; // NOLINT(readability-const-return-type)
bsalomon3582d3e2015-02-13 14:20:05 -0800173
174 /**
ericrk0a5fa482015-09-15 14:16:10 -0700175 * Dumps memory usage information for this GrGpuResource to traceMemoryDump.
176 * Typically, subclasses should not need to override this, and should only
177 * need to override setMemoryBacking.
178 **/
179 virtual void dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const;
180
Derek Sollenbergercf6da8c2018-03-29 13:40:02 -0400181 /**
182 * Describes the type of gpu resource that is represented by the implementing
183 * class (e.g. texture, buffer object, stencil). This data is used for diagnostic
184 * purposes by dumpMemoryStatistics().
185 *
186 * The value returned is expected to be long lived and will not be copied by the caller.
187 */
188 virtual const char* getResourceType() const = 0;
189
robertphillips8abb3702016-08-31 14:04:06 -0700190 static uint32_t CreateUniqueID();
191
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000192protected:
kkinnunen2e6055b2016-04-22 01:48:29 -0700193 // This must be called by every non-wrapped GrGpuObject. It should be called once the object is
194 // fully initialized (i.e. only from the constructors of the final class).
195 void registerWithCache(SkBudgeted);
bsalomon16961262014-08-26 14:01:07 -0700196
kkinnunen2e6055b2016-04-22 01:48:29 -0700197 // This must be called by every GrGpuObject that references any wrapped backend objects. It
198 // should be called once the object is fully initialized (i.e. only from the constructors of the
199 // final class).
Brian Salomonaa6ca0a2019-01-24 16:03:07 -0500200 void registerWithCacheWrapped(GrWrapCacheable);
kkinnunen2e6055b2016-04-22 01:48:29 -0700201
202 GrGpuResource(GrGpu*);
bsalomon6d3fe022014-07-25 08:35:45 -0700203 virtual ~GrGpuResource();
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000204
205 GrGpu* getGpu() const { return fGpu; }
206
bsalomon12299ab2014-11-14 13:33:09 -0800207 /** Overridden to free GPU resources in the backend API. */
Brian Salomon9f7d9a22018-12-11 19:01:32 +0000208 virtual void onRelease() { }
bsalomon12299ab2014-11-14 13:33:09 -0800209 /** Overridden to abandon any internal handles, ptrs, etc to backend API resources.
210 This may be called when the underlying 3D context is no longer valid and so no
211 backend API calls should be made. */
Brian Salomon9f7d9a22018-12-11 19:01:32 +0000212 virtual void onAbandon() { }
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000213
bsalomonc44be0e2014-07-25 07:32:33 -0700214 /**
Derek Sollenbergercf6da8c2018-03-29 13:40:02 -0400215 * Allows subclasses to add additional backing information to the SkTraceMemoryDump.
ericrk0a5fa482015-09-15 14:16:10 -0700216 **/
217 virtual void setMemoryBacking(SkTraceMemoryDump*, const SkString&) const {}
218
Derek Sollenbergercf6da8c2018-03-29 13:40:02 -0400219 /**
220 * Returns a string that uniquely identifies this resource.
221 */
222 SkString getResourceName() const;
223
224 /**
225 * A helper for subclasses that override dumpMemoryStatistics(). This method using a format
226 * consistent with the default implementation of dumpMemoryStatistics() but allows the caller
227 * to customize various inputs.
228 */
229 void dumpMemoryStatisticsPriv(SkTraceMemoryDump* traceMemoryDump, const SkString& resourceName,
230 const char* type, size_t size) const;
231
Brian Salomon9f7d9a22018-12-11 19:01:32 +0000232
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000233private:
Brian Salomon9bc76d92019-01-24 12:18:33 -0500234 bool isPurgeable() const;
Brian Salomon2c791fc2019-04-02 11:52:03 -0400235 bool hasRef() const;
Brian Salomon614c1a82018-12-19 15:42:06 -0500236
bsalomon12299ab2014-11-14 13:33:09 -0800237 /**
kkinnunen2e6055b2016-04-22 01:48:29 -0700238 * Called by the registerWithCache if the resource is available to be used as scratch.
239 * Resource subclasses should override this if the instances should be recycled as scratch
240 * resources and populate the scratchKey with the key.
241 * By default resources are not recycled as scratch.
242 **/
Brian Salomon9bc76d92019-01-24 12:18:33 -0500243 virtual void computeScratchKey(GrScratchKey*) const {}
kkinnunen2e6055b2016-04-22 01:48:29 -0700244
245 /**
Brian Salomon35ba6142019-01-24 13:08:59 -0500246 * Removes references to objects in the underlying 3D API without freeing them.
247 * Called by CacheAccess.
248 */
249 void abandon();
250
251 /**
bsalomon12299ab2014-11-14 13:33:09 -0800252 * Frees the object in the underlying 3D API. Called by CacheAccess.
253 */
254 void release();
255
bsalomon69ed47f2014-11-12 11:13:39 -0800256 virtual size_t onGpuMemorySize() const = 0;
257
Brian Salomon614c1a82018-12-19 15:42:06 -0500258 /**
Robert Phillipsbf8bf832019-08-30 13:13:44 -0400259 * Called by GrIORef when a resource is about to lose its last ref
Brian Salomon614c1a82018-12-19 15:42:06 -0500260 */
Robert Phillipsbf8bf832019-08-30 13:13:44 -0400261 virtual void willRemoveLastRef() {}
Brian Salomon614c1a82018-12-19 15:42:06 -0500262
bsalomon9f2d1572015-02-17 11:47:40 -0800263 // See comments in CacheAccess and ResourcePriv.
bsalomonf99e9612015-02-19 08:24:16 -0800264 void setUniqueKey(const GrUniqueKey&);
bsalomon8718aaf2015-02-19 07:24:21 -0800265 void removeUniqueKey();
Robert Phillipsbf8bf832019-08-30 13:13:44 -0400266 void notifyRefCntWillBeZero() const;
267 void notifyRefCntIsZero() const;
bsalomon10e23ca2014-11-25 05:52:06 -0800268 void removeScratchKey();
bsalomonafe30052015-01-16 07:32:33 -0800269 void makeBudgeted();
bsalomonc2f35b72015-01-23 07:19:22 -0800270 void makeUnbudgeted();
bsalomonbcf0a522014-10-08 08:40:09 -0700271
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000272#ifdef SK_DEBUG
Brian Salomon5e150852017-03-22 14:53:13 -0400273 friend class GrGpu; // for assert in GrGpu to access getGpu
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000274#endif
Brian Salomon5e150852017-03-22 14:53:13 -0400275
bsalomonf320e042015-02-17 15:09:34 -0800276 // An index into a heap when this resource is purgeable or an array when not. This is maintained
277 // by the cache.
Brian Salomon5e150852017-03-22 14:53:13 -0400278 int fCacheArrayIndex;
bsalomon9f2d1572015-02-17 11:47:40 -0800279 // This value reflects how recently this resource was accessed in the cache. This is maintained
280 // by the cache.
Brian Salomon5e150852017-03-22 14:53:13 -0400281 uint32_t fTimestamp;
Brian Salomon5e150852017-03-22 14:53:13 -0400282 GrStdSteadyClock::time_point fTimeWhenBecamePurgeable;
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000283
bsalomon69ed47f2014-11-12 11:13:39 -0800284 static const size_t kInvalidGpuMemorySize = ~static_cast<size_t>(0);
Brian Salomon5e150852017-03-22 14:53:13 -0400285 GrScratchKey fScratchKey;
286 GrUniqueKey fUniqueKey;
bsalomon84c8e622014-11-17 09:33:27 -0800287
288 // This is not ref'ed but abandon() or release() will be called before the GrGpu object
289 // is destroyed. Those calls set will this to NULL.
Brian Salomon5e150852017-03-22 14:53:13 -0400290 GrGpu* fGpu;
Brian Salomonfa2ebea2019-01-24 15:58:58 -0500291 mutable size_t fGpuMemorySize = kInvalidGpuMemorySize;
bsalomon84c8e622014-11-17 09:33:27 -0800292
Brian Salomonaa6ca0a2019-01-24 16:03:07 -0500293 GrBudgetedType fBudgetedType = GrBudgetedType::kUnbudgetedUncacheable;
Brian Salomonfa2ebea2019-01-24 15:58:58 -0500294 bool fRefsWrappedObjects = false;
Brian Salomon5e150852017-03-22 14:53:13 -0400295 const UniqueID fUniqueID;
bsalomon744998e2014-08-28 09:54:34 -0700296
John Stiles7571f9e2020-09-02 22:42:33 -0400297 using INHERITED = GrIORef<GrGpuResource>;
Robert Phillipsbf8bf832019-08-30 13:13:44 -0400298 friend class GrIORef<GrGpuResource>; // to access notifyRefCntWillBeZero and notifyRefCntIsZero.
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000299};
300
Brian Salomon01ceae92019-04-02 11:49:54 -0400301class GrGpuResource::ProxyAccess {
302private:
303 ProxyAccess(GrGpuResource* resource) : fResource(resource) {}
304
305 /** Proxies are allowed to take a resource from no refs to one ref. */
Brian Salomon2c791fc2019-04-02 11:52:03 -0400306 void ref(GrResourceCache* cache);
Brian Salomon01ceae92019-04-02 11:49:54 -0400307
308 // No taking addresses of this type.
309 const CacheAccess* operator&() const = delete;
310 CacheAccess* operator&() = delete;
311
312 GrGpuResource* fResource;
313
314 friend class GrGpuResource;
315 friend class GrSurfaceProxy;
Brian Salomon01ceae92019-04-02 11:49:54 -0400316};
317
318inline GrGpuResource::ProxyAccess GrGpuResource::proxyAccess() { return ProxyAccess(this); }
319
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000320#endif