blob: 0215e2ba91d81aaa06a6104256230b9ff1867431 [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
Brian Salomonb4ba8262018-12-20 20:37:55 -050011#include "../private/GrResourceKey.h"
Brian Salomonc5886032017-07-19 11:48:05 -040012#include "../private/GrTypesPriv.h"
Ben Wagnerd5148e32018-07-16 17:44:06 -040013#include "../private/SkNoncopyable.h"
commit-bot@chromium.org089a7802014-05-02 21:38:22 +000014
commit-bot@chromium.org089a7802014-05-02 21:38:22 +000015class GrContext;
bsalomon37dd3312014-11-03 08:47:23 -080016class GrGpu;
bsalomon0ea80f42015-02-11 10:49:59 -080017class GrResourceCache;
ericrk0a5fa482015-09-15 14:16:10 -070018class SkTraceMemoryDump;
commit-bot@chromium.org089a7802014-05-02 21:38:22 +000019
20/**
bsalomon00b76bd2014-09-03 14:05:49 -070021 * Base class for GrGpuResource. Handles the various types of refs we need. Separated out as a base
22 * class to isolate the ref-cnting behavior and provide friendship without exposing all of
23 * GrGpuResource.
mtklein6f076652015-01-13 08:22:43 -080024 *
bsalomon00b76bd2014-09-03 14:05:49 -070025 * Gpu resources can have three types of refs:
26 * 1) Normal ref (+ by ref(), - by unref()): These are used by code that is issuing draw calls
Robert Phillipsf2361d22016-10-25 14:20:06 -040027 * that read and write the resource via GrOpList and by any object that must own a
bsalomon00b76bd2014-09-03 14:05:49 -070028 * GrGpuResource and is itself owned (directly or indirectly) by Skia-client code.
bsalomonbcf0a522014-10-08 08:40:09 -070029 * 2) Pending read (+ by addPendingRead(), - by completedRead()): GrContext has scheduled a read
bsalomon00b76bd2014-09-03 14:05:49 -070030 * of the resource by the GPU as a result of a skia API call but hasn't executed it yet.
bsalomonbcf0a522014-10-08 08:40:09 -070031 * 3) Pending write (+ by addPendingWrite(), - by completedWrite()): GrContext has scheduled a
bsalomon00b76bd2014-09-03 14:05:49 -070032 * write to the resource by the GPU as a result of a skia API call but hasn't executed it yet.
33 *
34 * The latter two ref types are private and intended only for Gr core code.
bsalomonbcf0a522014-10-08 08:40:09 -070035 *
bsalomon3f324322015-04-08 11:01:54 -070036 * When all the ref/io counts reach zero DERIVED::notifyAllCntsAreZero() will be called (static poly
37 * morphism using CRTP). Similarly when the ref (but not necessarily pending read/write) count
38 * reaches 0 DERIVED::notifyRefCountIsZero() will be called. In the case when an unref() causes both
39 * the ref cnt to reach zero and the other counts are zero, notifyRefCountIsZero() will be called
Brian Salomon9bc76d92019-01-24 12:18:33 -050040 * before notifyAllCntsAreZero(). Moreover, if notifyRefCountIsZero() returns false then
bsalomon3f324322015-04-08 11:01:54 -070041 * notifyAllRefCntsAreZero() won't be called at all. notifyRefCountIsZero() must return false if the
42 * object may be deleted after notifyRefCntIsZero() returns.
43 *
44 * GrIORef and GrGpuResource are separate classes for organizational reasons and to be
bsalomonbcf0a522014-10-08 08:40:09 -070045 * able to give access via friendship to only the functions related to pending IO operations.
commit-bot@chromium.org089a7802014-05-02 21:38:22 +000046 */
bsalomonbcf0a522014-10-08 08:40:09 -070047template <typename DERIVED> class GrIORef : public SkNoncopyable {
commit-bot@chromium.org089a7802014-05-02 21:38:22 +000048public:
bsalomon00b76bd2014-09-03 14:05:49 -070049 // Some of the signatures are written to mirror SkRefCnt so that GrGpuResource can work with
bungeman6bd52842016-10-27 09:30:08 -070050 // templated helper classes (e.g. sk_sp). However, we have different categories of
bsalomon00b76bd2014-09-03 14:05:49 -070051 // refs (e.g. pending reads). We also don't require thread safety as GrCacheable objects are
52 // not intended to cross thread boundaries.
bsalomon00b76bd2014-09-03 14:05:49 -070053 void ref() const {
Brian Salomon9323b8b2014-10-07 15:07:38 -040054 this->validate();
bsalomonbcf0a522014-10-08 08:40:09 -070055 ++fRefCnt;
bsalomonc44be0e2014-07-25 07:32:33 -070056 }
bsalomon00b76bd2014-09-03 14:05:49 -070057
58 void unref() const {
59 this->validate();
mtklein2766c002015-06-26 11:45:03 -070060
bsalomon3f324322015-04-08 11:01:54 -070061 if (!(--fRefCnt)) {
62 if (!static_cast<const DERIVED*>(this)->notifyRefCountIsZero()) {
63 return;
64 }
65 }
66
67 this->didRemoveRefOrPendingIO(kRef_CntType);
bsalomon00b76bd2014-09-03 14:05:49 -070068 }
69
bsalomon00b76bd2014-09-03 14:05:49 -070070 void validate() const {
71#ifdef SK_DEBUG
72 SkASSERT(fRefCnt >= 0);
73 SkASSERT(fPendingReads >= 0);
74 SkASSERT(fPendingWrites >= 0);
bsalomon12299ab2014-11-14 13:33:09 -080075 SkASSERT(fRefCnt + fPendingReads + fPendingWrites >= 0);
bsalomonc44be0e2014-07-25 07:32:33 -070076#endif
bsalomon00b76bd2014-09-03 14:05:49 -070077 }
78
79protected:
Brian Salomon9f7d9a22018-12-11 19:01:32 +000080 GrIORef() : fRefCnt(1), fPendingReads(0), fPendingWrites(0) { }
bsalomon00b76bd2014-09-03 14:05:49 -070081
bsalomon3f324322015-04-08 11:01:54 -070082 enum CntType {
83 kRef_CntType,
84 kPendingRead_CntType,
85 kPendingWrite_CntType,
86 };
87
bsalomon8d034a12014-09-22 12:21:08 -070088 bool internalHasPendingRead() const { return SkToBool(fPendingReads); }
89 bool internalHasPendingWrite() const { return SkToBool(fPendingWrites); }
90 bool internalHasPendingIO() const { return SkToBool(fPendingWrites | fPendingReads); }
91
bsalomon6d4488c2014-11-11 07:27:16 -080092 bool internalHasRef() const { return SkToBool(fRefCnt); }
Eric Karl914a36b2017-10-12 12:44:50 -070093 bool internalHasUniqueRef() const { return fRefCnt == 1; }
bsalomon6d4488c2014-11-11 07:27:16 -080094
bsalomon00b76bd2014-09-03 14:05:49 -070095private:
Brian Salomon9f7d9a22018-12-11 19:01:32 +000096 friend class GrIORefProxy; // needs to forward on wrapped IO calls
Brian Salomonf046e152017-01-11 15:24:47 -050097 // This is for a unit test.
98 template <typename T>
99 friend void testingOnly_getIORefCnts(const T*, int* refCnt, int* readCnt, int* writeCnt);
robertphillips1125a032016-11-16 11:17:17 -0800100
bsalomon00b76bd2014-09-03 14:05:49 -0700101 void addPendingRead() const {
102 this->validate();
103 ++fPendingReads;
104 }
105
106 void completedRead() const {
107 this->validate();
108 --fPendingReads;
bsalomon3f324322015-04-08 11:01:54 -0700109 this->didRemoveRefOrPendingIO(kPendingRead_CntType);
bsalomon00b76bd2014-09-03 14:05:49 -0700110 }
111
112 void addPendingWrite() const {
113 this->validate();
114 ++fPendingWrites;
115 }
116
117 void completedWrite() const {
118 this->validate();
119 --fPendingWrites;
bsalomon3f324322015-04-08 11:01:54 -0700120 this->didRemoveRefOrPendingIO(kPendingWrite_CntType);
bsalomon00b76bd2014-09-03 14:05:49 -0700121 }
122
123private:
bsalomon3f324322015-04-08 11:01:54 -0700124 void didRemoveRefOrPendingIO(CntType cntTypeRemoved) const {
bsalomon12299ab2014-11-14 13:33:09 -0800125 if (0 == fPendingReads && 0 == fPendingWrites && 0 == fRefCnt) {
bsalomon3f324322015-04-08 11:01:54 -0700126 static_cast<const DERIVED*>(this)->notifyAllCntsAreZero(cntTypeRemoved);
bsalomonbcf0a522014-10-08 08:40:09 -0700127 }
128 }
129
bsalomon00b76bd2014-09-03 14:05:49 -0700130 mutable int32_t fRefCnt;
131 mutable int32_t fPendingReads;
132 mutable int32_t fPendingWrites;
133
Brian Salomon9f7d9a22018-12-11 19:01:32 +0000134 friend class GrResourceCache; // to check IO ref counts.
bsalomonbcf0a522014-10-08 08:40:09 -0700135
136 template <typename, GrIOType> friend class GrPendingIOResource;
bsalomon00b76bd2014-09-03 14:05:49 -0700137};
138
139/**
bsalomon0ea80f42015-02-11 10:49:59 -0800140 * Base class for objects that can be kept in the GrResourceCache.
bsalomon00b76bd2014-09-03 14:05:49 -0700141 */
bsalomon544fe232014-10-08 10:24:07 -0700142class SK_API GrGpuResource : public GrIORef<GrGpuResource> {
bsalomon00b76bd2014-09-03 14:05:49 -0700143public:
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000144 /**
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000145 * Tests whether a object has been abandoned or released. All objects will
146 * be in this state after their creating GrContext is destroyed or has
147 * contextLost called. It's up to the client to test wasDestroyed() before
148 * attempting to use an object if it holds refs on objects across
149 * ~GrContext, freeResources with the force flag, or contextLost.
150 *
151 * @return true if the object has been released or abandoned,
152 * false otherwise.
153 */
Ben Wagnera93a14a2017-08-28 10:34:05 -0400154 bool wasDestroyed() const { return nullptr == fGpu; }
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000155
156 /**
157 * Retrieves the context that owns the object. Note that it is possible for
158 * this to return NULL. When objects have been release()ed or abandon()ed
159 * they no longer have an owning context. Destroying a GrContext
160 * automatically releases all its resources.
161 */
162 const GrContext* getContext() const;
163 GrContext* getContext();
164
bsalomonc44be0e2014-07-25 07:32:33 -0700165 /**
166 * Retrieves the amount of GPU memory used by this resource in bytes. It is
167 * approximate since we aren't aware of additional padding or copies made
168 * by the driver.
169 *
170 * @return the amount of GPU memory used in bytes
171 */
bsalomon69ed47f2014-11-12 11:13:39 -0800172 size_t gpuMemorySize() const {
173 if (kInvalidGpuMemorySize == fGpuMemorySize) {
174 fGpuMemorySize = this->onGpuMemorySize();
175 SkASSERT(kInvalidGpuMemorySize != fGpuMemorySize);
176 }
177 return fGpuMemorySize;
178 }
bsalomonc44be0e2014-07-25 07:32:33 -0700179
Robert Phillips294870f2016-11-11 12:38:40 -0500180 class UniqueID {
181 public:
182 static UniqueID InvalidID() {
183 return UniqueID(uint32_t(SK_InvalidUniqueID));
184 }
185
186 UniqueID() {}
187
188 explicit UniqueID(uint32_t id) : fID(id) {}
189
190 uint32_t asUInt() const { return fID; }
191
192 bool operator==(const UniqueID& other) const {
193 return fID == other.fID;
194 }
195 bool operator!=(const UniqueID& other) const {
196 return !(*this == other);
197 }
198
199 void makeInvalid() { fID = SK_InvalidUniqueID; }
200 bool isInvalid() const { return SK_InvalidUniqueID == fID; }
201
202 protected:
203 uint32_t fID;
204 };
205
bsalomonc44be0e2014-07-25 07:32:33 -0700206 /**
bsalomon52e9d632014-09-05 12:23:12 -0700207 * Gets an id that is unique for this GrGpuResource object. It is static in that it does
208 * not change when the content of the GrGpuResource object changes. This will never return
bsalomonc44be0e2014-07-25 07:32:33 -0700209 * 0.
210 */
Robert Phillips294870f2016-11-11 12:38:40 -0500211 UniqueID uniqueID() const { return fUniqueID; }
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000212
bsalomon8718aaf2015-02-19 07:24:21 -0800213 /** Returns the current unique key for the resource. It will be invalid if the resource has no
214 associated unique key. */
215 const GrUniqueKey& getUniqueKey() const { return fUniqueKey; }
bsalomon563ff602015-02-02 17:25:26 -0800216
bsalomon453cf402014-11-11 14:15:57 -0800217 /**
bsalomon3582d3e2015-02-13 14:20:05 -0800218 * Internal-only helper class used for manipulations of the resource by the cache.
bsalomon453cf402014-11-11 14:15:57 -0800219 */
220 class CacheAccess;
221 inline CacheAccess cacheAccess();
222 inline const CacheAccess cacheAccess() const;
223
junov436293a2014-12-11 10:32:32 -0800224 /**
bsalomon3582d3e2015-02-13 14:20:05 -0800225 * Internal-only helper class used for manipulations of the resource by internal code.
226 */
227 class ResourcePriv;
228 inline ResourcePriv resourcePriv();
229 inline const ResourcePriv resourcePriv() const;
230
231 /**
ericrk0a5fa482015-09-15 14:16:10 -0700232 * Dumps memory usage information for this GrGpuResource to traceMemoryDump.
233 * Typically, subclasses should not need to override this, and should only
234 * need to override setMemoryBacking.
235 **/
236 virtual void dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const;
237
Derek Sollenbergercf6da8c2018-03-29 13:40:02 -0400238 /**
239 * Describes the type of gpu resource that is represented by the implementing
240 * class (e.g. texture, buffer object, stencil). This data is used for diagnostic
241 * purposes by dumpMemoryStatistics().
242 *
243 * The value returned is expected to be long lived and will not be copied by the caller.
244 */
245 virtual const char* getResourceType() const = 0;
246
robertphillips8abb3702016-08-31 14:04:06 -0700247 static uint32_t CreateUniqueID();
248
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000249protected:
kkinnunen2e6055b2016-04-22 01:48:29 -0700250 // This must be called by every non-wrapped GrGpuObject. It should be called once the object is
251 // fully initialized (i.e. only from the constructors of the final class).
252 void registerWithCache(SkBudgeted);
bsalomon16961262014-08-26 14:01:07 -0700253
kkinnunen2e6055b2016-04-22 01:48:29 -0700254 // This must be called by every GrGpuObject that references any wrapped backend objects. It
255 // should be called once the object is fully initialized (i.e. only from the constructors of the
256 // final class).
Brian Salomonaa6ca0a2019-01-24 16:03:07 -0500257 void registerWithCacheWrapped(GrWrapCacheable);
kkinnunen2e6055b2016-04-22 01:48:29 -0700258
259 GrGpuResource(GrGpu*);
bsalomon6d3fe022014-07-25 08:35:45 -0700260 virtual ~GrGpuResource();
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000261
262 GrGpu* getGpu() const { return fGpu; }
263
bsalomon12299ab2014-11-14 13:33:09 -0800264 /** Overridden to free GPU resources in the backend API. */
Brian Salomon9f7d9a22018-12-11 19:01:32 +0000265 virtual void onRelease() { }
bsalomon12299ab2014-11-14 13:33:09 -0800266 /** Overridden to abandon any internal handles, ptrs, etc to backend API resources.
267 This may be called when the underlying 3D context is no longer valid and so no
268 backend API calls should be made. */
Brian Salomon9f7d9a22018-12-11 19:01:32 +0000269 virtual void onAbandon() { }
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000270
bsalomonc44be0e2014-07-25 07:32:33 -0700271 /**
Derek Sollenbergercf6da8c2018-03-29 13:40:02 -0400272 * Allows subclasses to add additional backing information to the SkTraceMemoryDump.
ericrk0a5fa482015-09-15 14:16:10 -0700273 **/
274 virtual void setMemoryBacking(SkTraceMemoryDump*, const SkString&) const {}
275
Derek Sollenbergercf6da8c2018-03-29 13:40:02 -0400276 /**
277 * Returns a string that uniquely identifies this resource.
278 */
279 SkString getResourceName() const;
280
281 /**
282 * A helper for subclasses that override dumpMemoryStatistics(). This method using a format
283 * consistent with the default implementation of dumpMemoryStatistics() but allows the caller
284 * to customize various inputs.
285 */
286 void dumpMemoryStatisticsPriv(SkTraceMemoryDump* traceMemoryDump, const SkString& resourceName,
287 const char* type, size_t size) const;
288
Brian Salomon9f7d9a22018-12-11 19:01:32 +0000289
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000290private:
Brian Salomon9bc76d92019-01-24 12:18:33 -0500291 bool isPurgeable() const;
292 bool hasRefOrPendingIO() const;
Brian Salomon614c1a82018-12-19 15:42:06 -0500293
bsalomon12299ab2014-11-14 13:33:09 -0800294 /**
kkinnunen2e6055b2016-04-22 01:48:29 -0700295 * Called by the registerWithCache if the resource is available to be used as scratch.
296 * Resource subclasses should override this if the instances should be recycled as scratch
297 * resources and populate the scratchKey with the key.
298 * By default resources are not recycled as scratch.
299 **/
Brian Salomon9bc76d92019-01-24 12:18:33 -0500300 virtual void computeScratchKey(GrScratchKey*) const {}
kkinnunen2e6055b2016-04-22 01:48:29 -0700301
302 /**
Brian Salomon35ba6142019-01-24 13:08:59 -0500303 * Removes references to objects in the underlying 3D API without freeing them.
304 * Called by CacheAccess.
305 */
306 void abandon();
307
308 /**
bsalomon12299ab2014-11-14 13:33:09 -0800309 * Frees the object in the underlying 3D API. Called by CacheAccess.
310 */
311 void release();
312
bsalomon69ed47f2014-11-12 11:13:39 -0800313 virtual size_t onGpuMemorySize() const = 0;
314
Brian Salomon614c1a82018-12-19 15:42:06 -0500315 /**
Brian Salomon9bc76d92019-01-24 12:18:33 -0500316 * Called by GrResourceCache when a resource loses its last ref or pending IO.
Brian Salomon614c1a82018-12-19 15:42:06 -0500317 */
Brian Salomon9bc76d92019-01-24 12:18:33 -0500318 virtual void removedLastRefOrPendingIO() {}
Brian Salomon614c1a82018-12-19 15:42:06 -0500319
bsalomon9f2d1572015-02-17 11:47:40 -0800320 // See comments in CacheAccess and ResourcePriv.
bsalomonf99e9612015-02-19 08:24:16 -0800321 void setUniqueKey(const GrUniqueKey&);
bsalomon8718aaf2015-02-19 07:24:21 -0800322 void removeUniqueKey();
bsalomon3f324322015-04-08 11:01:54 -0700323 void notifyAllCntsAreZero(CntType) const;
324 bool notifyRefCountIsZero() const;
bsalomon10e23ca2014-11-25 05:52:06 -0800325 void removeScratchKey();
bsalomonafe30052015-01-16 07:32:33 -0800326 void makeBudgeted();
bsalomonc2f35b72015-01-23 07:19:22 -0800327 void makeUnbudgeted();
bsalomonbcf0a522014-10-08 08:40:09 -0700328
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000329#ifdef SK_DEBUG
Brian Salomon5e150852017-03-22 14:53:13 -0400330 friend class GrGpu; // for assert in GrGpu to access getGpu
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000331#endif
Brian Salomon5e150852017-03-22 14:53:13 -0400332
bsalomonf320e042015-02-17 15:09:34 -0800333 // An index into a heap when this resource is purgeable or an array when not. This is maintained
334 // by the cache.
Brian Salomon5e150852017-03-22 14:53:13 -0400335 int fCacheArrayIndex;
bsalomon9f2d1572015-02-17 11:47:40 -0800336 // This value reflects how recently this resource was accessed in the cache. This is maintained
337 // by the cache.
Brian Salomon5e150852017-03-22 14:53:13 -0400338 uint32_t fTimestamp;
Brian Salomon5e150852017-03-22 14:53:13 -0400339 GrStdSteadyClock::time_point fTimeWhenBecamePurgeable;
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000340
bsalomon69ed47f2014-11-12 11:13:39 -0800341 static const size_t kInvalidGpuMemorySize = ~static_cast<size_t>(0);
Brian Salomon5e150852017-03-22 14:53:13 -0400342 GrScratchKey fScratchKey;
343 GrUniqueKey fUniqueKey;
bsalomon84c8e622014-11-17 09:33:27 -0800344
345 // This is not ref'ed but abandon() or release() will be called before the GrGpu object
346 // is destroyed. Those calls set will this to NULL.
Brian Salomon5e150852017-03-22 14:53:13 -0400347 GrGpu* fGpu;
Brian Salomonfa2ebea2019-01-24 15:58:58 -0500348 mutable size_t fGpuMemorySize = kInvalidGpuMemorySize;
bsalomon84c8e622014-11-17 09:33:27 -0800349
Brian Salomonaa6ca0a2019-01-24 16:03:07 -0500350 GrBudgetedType fBudgetedType = GrBudgetedType::kUnbudgetedUncacheable;
Brian Salomonfa2ebea2019-01-24 15:58:58 -0500351 bool fRefsWrappedObjects = false;
Brian Salomon5e150852017-03-22 14:53:13 -0400352 const UniqueID fUniqueID;
bsalomon744998e2014-08-28 09:54:34 -0700353
bsalomonbcf0a522014-10-08 08:40:09 -0700354 typedef GrIORef<GrGpuResource> INHERITED;
Brian Salomon9f7d9a22018-12-11 19:01:32 +0000355 friend class GrIORef<GrGpuResource>; // to access notifyAllCntsAreZero and notifyRefCntIsZero.
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000356};
357
358#endif