blob: 70c94c0e55d72532e8ecae5f0a7940ced961ad47 [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 Salomonc5886032017-07-19 11:48:05 -040011#include "../private/GrTypesPriv.h"
bsalomonbcf0a522014-10-08 08:40:09 -070012#include "GrResourceKey.h"
commit-bot@chromium.org089a7802014-05-02 21:38:22 +000013
commit-bot@chromium.org089a7802014-05-02 21:38:22 +000014class GrContext;
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/**
bsalomon00b76bd2014-09-03 14:05:49 -070020 * Base class for GrGpuResource. Handles the various types of refs we need. Separated out as a base
21 * class to isolate the ref-cnting behavior and provide friendship without exposing all of
22 * GrGpuResource.
mtklein6f076652015-01-13 08:22:43 -080023 *
bsalomon00b76bd2014-09-03 14:05:49 -070024 * Gpu resources can have three types of refs:
25 * 1) Normal ref (+ by ref(), - by unref()): These are used by code that is issuing draw calls
Robert Phillipsf2361d22016-10-25 14:20:06 -040026 * that read and write the resource via GrOpList and by any object that must own a
bsalomon00b76bd2014-09-03 14:05:49 -070027 * GrGpuResource and is itself owned (directly or indirectly) by Skia-client code.
bsalomonbcf0a522014-10-08 08:40:09 -070028 * 2) Pending read (+ by addPendingRead(), - by completedRead()): GrContext has scheduled a read
bsalomon00b76bd2014-09-03 14:05:49 -070029 * 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 -070030 * 3) Pending write (+ by addPendingWrite(), - by completedWrite()): GrContext has scheduled a
bsalomon00b76bd2014-09-03 14:05:49 -070031 * write to the resource by the GPU as a result of a skia API call but hasn't executed it yet.
32 *
33 * The latter two ref types are private and intended only for Gr core code.
bsalomonbcf0a522014-10-08 08:40:09 -070034 *
bsalomon3f324322015-04-08 11:01:54 -070035 * When all the ref/io counts reach zero DERIVED::notifyAllCntsAreZero() will be called (static poly
36 * morphism using CRTP). Similarly when the ref (but not necessarily pending read/write) count
37 * reaches 0 DERIVED::notifyRefCountIsZero() will be called. In the case when an unref() causes both
38 * the ref cnt to reach zero and the other counts are zero, notifyRefCountIsZero() will be called
39 * before notifyIsPurgeable(). Moreover, if notifyRefCountIsZero() returns false then
40 * notifyAllRefCntsAreZero() won't be called at all. notifyRefCountIsZero() must return false if the
41 * object may be deleted after notifyRefCntIsZero() returns.
42 *
43 * GrIORef and GrGpuResource are separate classes for organizational reasons and to be
bsalomonbcf0a522014-10-08 08:40:09 -070044 * able to give access via friendship to only the functions related to pending IO operations.
commit-bot@chromium.org089a7802014-05-02 21:38:22 +000045 */
bsalomonbcf0a522014-10-08 08:40:09 -070046template <typename DERIVED> class GrIORef : public SkNoncopyable {
commit-bot@chromium.org089a7802014-05-02 21:38:22 +000047public:
bsalomon00b76bd2014-09-03 14:05:49 -070048 // Some of the signatures are written to mirror SkRefCnt so that GrGpuResource can work with
bungeman6bd52842016-10-27 09:30:08 -070049 // templated helper classes (e.g. sk_sp). However, we have different categories of
bsalomon00b76bd2014-09-03 14:05:49 -070050 // refs (e.g. pending reads). We also don't require thread safety as GrCacheable objects are
51 // not intended to cross thread boundaries.
bsalomon00b76bd2014-09-03 14:05:49 -070052 void ref() const {
Brian Salomon9323b8b2014-10-07 15:07:38 -040053 this->validate();
bsalomonbcf0a522014-10-08 08:40:09 -070054 ++fRefCnt;
bsalomonc44be0e2014-07-25 07:32:33 -070055 }
bsalomon00b76bd2014-09-03 14:05:49 -070056
57 void unref() const {
58 this->validate();
mtklein2766c002015-06-26 11:45:03 -070059
bsalomon3f324322015-04-08 11:01:54 -070060 if (!(--fRefCnt)) {
61 if (!static_cast<const DERIVED*>(this)->notifyRefCountIsZero()) {
62 return;
63 }
64 }
65
66 this->didRemoveRefOrPendingIO(kRef_CntType);
bsalomon00b76bd2014-09-03 14:05:49 -070067 }
68
bsalomon00b76bd2014-09-03 14:05:49 -070069 void validate() const {
70#ifdef SK_DEBUG
71 SkASSERT(fRefCnt >= 0);
72 SkASSERT(fPendingReads >= 0);
73 SkASSERT(fPendingWrites >= 0);
bsalomon12299ab2014-11-14 13:33:09 -080074 SkASSERT(fRefCnt + fPendingReads + fPendingWrites >= 0);
bsalomonc44be0e2014-07-25 07:32:33 -070075#endif
bsalomon00b76bd2014-09-03 14:05:49 -070076 }
77
78protected:
bsalomon1e2530b2014-10-09 09:57:18 -070079 GrIORef() : fRefCnt(1), fPendingReads(0), fPendingWrites(0) { }
bsalomon00b76bd2014-09-03 14:05:49 -070080
bsalomon3f324322015-04-08 11:01:54 -070081 enum CntType {
82 kRef_CntType,
83 kPendingRead_CntType,
84 kPendingWrite_CntType,
85 };
86
bsalomon63c992f2015-01-23 12:47:59 -080087 bool isPurgeable() const { return !this->internalHasRef() && !this->internalHasPendingIO(); }
bsalomon12299ab2014-11-14 13:33:09 -080088
bsalomon8d034a12014-09-22 12:21:08 -070089 bool internalHasPendingRead() const { return SkToBool(fPendingReads); }
90 bool internalHasPendingWrite() const { return SkToBool(fPendingWrites); }
91 bool internalHasPendingIO() const { return SkToBool(fPendingWrites | fPendingReads); }
92
bsalomon6d4488c2014-11-11 07:27:16 -080093 bool internalHasRef() const { return SkToBool(fRefCnt); }
Eric Karl914a36b2017-10-12 12:44:50 -070094 bool internalHasUniqueRef() const { return fRefCnt == 1; }
bsalomon6d4488c2014-11-11 07:27:16 -080095
bsalomon00b76bd2014-09-03 14:05:49 -070096private:
robertphillips1125a032016-11-16 11:17:17 -080097 friend class GrIORefProxy; // needs to forward on wrapped IO calls
Brian Salomonf046e152017-01-11 15:24:47 -050098 // This is for a unit test.
99 template <typename T>
100 friend void testingOnly_getIORefCnts(const T*, int* refCnt, int* readCnt, int* writeCnt);
robertphillips1125a032016-11-16 11:17:17 -0800101
bsalomon00b76bd2014-09-03 14:05:49 -0700102 void addPendingRead() const {
103 this->validate();
104 ++fPendingReads;
105 }
106
107 void completedRead() const {
108 this->validate();
109 --fPendingReads;
bsalomon3f324322015-04-08 11:01:54 -0700110 this->didRemoveRefOrPendingIO(kPendingRead_CntType);
bsalomon00b76bd2014-09-03 14:05:49 -0700111 }
112
113 void addPendingWrite() const {
114 this->validate();
115 ++fPendingWrites;
116 }
117
118 void completedWrite() const {
119 this->validate();
120 --fPendingWrites;
bsalomon3f324322015-04-08 11:01:54 -0700121 this->didRemoveRefOrPendingIO(kPendingWrite_CntType);
bsalomon00b76bd2014-09-03 14:05:49 -0700122 }
123
124private:
bsalomon3f324322015-04-08 11:01:54 -0700125 void didRemoveRefOrPendingIO(CntType cntTypeRemoved) const {
bsalomon12299ab2014-11-14 13:33:09 -0800126 if (0 == fPendingReads && 0 == fPendingWrites && 0 == fRefCnt) {
bsalomon3f324322015-04-08 11:01:54 -0700127 static_cast<const DERIVED*>(this)->notifyAllCntsAreZero(cntTypeRemoved);
bsalomonbcf0a522014-10-08 08:40:09 -0700128 }
129 }
130
bsalomon00b76bd2014-09-03 14:05:49 -0700131 mutable int32_t fRefCnt;
132 mutable int32_t fPendingReads;
133 mutable int32_t fPendingWrites;
134
bsalomonac8d6192014-09-04 14:13:44 -0700135 // This class is used to manage conversion of refs to pending reads/writes.
bsalomonf96ba022014-09-17 08:05:40 -0700136 friend class GrGpuResourceRef;
bsalomon0ea80f42015-02-11 10:49:59 -0800137 friend class GrResourceCache; // to check IO ref counts.
bsalomonbcf0a522014-10-08 08:40:09 -0700138
139 template <typename, GrIOType> friend class GrPendingIOResource;
bsalomon00b76bd2014-09-03 14:05:49 -0700140};
141
142/**
bsalomon0ea80f42015-02-11 10:49:59 -0800143 * Base class for objects that can be kept in the GrResourceCache.
bsalomon00b76bd2014-09-03 14:05:49 -0700144 */
bsalomon544fe232014-10-08 10:24:07 -0700145class SK_API GrGpuResource : public GrIORef<GrGpuResource> {
bsalomon00b76bd2014-09-03 14:05:49 -0700146public:
ericrk0a5fa482015-09-15 14:16:10 -0700147
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000148 /**
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000149 * Tests whether a object has been abandoned or released. All objects will
150 * be in this state after their creating GrContext is destroyed or has
151 * contextLost called. It's up to the client to test wasDestroyed() before
152 * attempting to use an object if it holds refs on objects across
153 * ~GrContext, freeResources with the force flag, or contextLost.
154 *
155 * @return true if the object has been released or abandoned,
156 * false otherwise.
157 */
Ben Wagnera93a14a2017-08-28 10:34:05 -0400158 bool wasDestroyed() const { return nullptr == fGpu; }
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000159
160 /**
161 * Retrieves the context that owns the object. Note that it is possible for
162 * this to return NULL. When objects have been release()ed or abandon()ed
163 * they no longer have an owning context. Destroying a GrContext
164 * automatically releases all its resources.
165 */
166 const GrContext* getContext() const;
167 GrContext* getContext();
168
bsalomonc44be0e2014-07-25 07:32:33 -0700169 /**
170 * Retrieves the amount of GPU memory used by this resource in bytes. It is
171 * approximate since we aren't aware of additional padding or copies made
172 * by the driver.
173 *
174 * @return the amount of GPU memory used in bytes
175 */
bsalomon69ed47f2014-11-12 11:13:39 -0800176 size_t gpuMemorySize() const {
177 if (kInvalidGpuMemorySize == fGpuMemorySize) {
178 fGpuMemorySize = this->onGpuMemorySize();
179 SkASSERT(kInvalidGpuMemorySize != fGpuMemorySize);
180 }
181 return fGpuMemorySize;
182 }
bsalomonc44be0e2014-07-25 07:32:33 -0700183
Robert Phillips294870f2016-11-11 12:38:40 -0500184 class UniqueID {
185 public:
186 static UniqueID InvalidID() {
187 return UniqueID(uint32_t(SK_InvalidUniqueID));
188 }
189
190 UniqueID() {}
191
192 explicit UniqueID(uint32_t id) : fID(id) {}
193
194 uint32_t asUInt() const { return fID; }
195
196 bool operator==(const UniqueID& other) const {
197 return fID == other.fID;
198 }
199 bool operator!=(const UniqueID& other) const {
200 return !(*this == other);
201 }
202
203 void makeInvalid() { fID = SK_InvalidUniqueID; }
204 bool isInvalid() const { return SK_InvalidUniqueID == fID; }
205
206 protected:
207 uint32_t fID;
208 };
209
bsalomonc44be0e2014-07-25 07:32:33 -0700210 /**
bsalomon52e9d632014-09-05 12:23:12 -0700211 * Gets an id that is unique for this GrGpuResource object. It is static in that it does
212 * not change when the content of the GrGpuResource object changes. This will never return
bsalomonc44be0e2014-07-25 07:32:33 -0700213 * 0.
214 */
Robert Phillips294870f2016-11-11 12:38:40 -0500215 UniqueID uniqueID() const { return fUniqueID; }
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000216
bsalomon8718aaf2015-02-19 07:24:21 -0800217 /** Returns the current unique key for the resource. It will be invalid if the resource has no
218 associated unique key. */
219 const GrUniqueKey& getUniqueKey() const { return fUniqueKey; }
bsalomon563ff602015-02-02 17:25:26 -0800220
bsalomon453cf402014-11-11 14:15:57 -0800221 /**
bsalomon3582d3e2015-02-13 14:20:05 -0800222 * Internal-only helper class used for manipulations of the resource by the cache.
bsalomon453cf402014-11-11 14:15:57 -0800223 */
224 class CacheAccess;
225 inline CacheAccess cacheAccess();
226 inline const CacheAccess cacheAccess() const;
227
junov436293a2014-12-11 10:32:32 -0800228 /**
bsalomon3582d3e2015-02-13 14:20:05 -0800229 * Internal-only helper class used for manipulations of the resource by internal code.
230 */
231 class ResourcePriv;
232 inline ResourcePriv resourcePriv();
233 inline const ResourcePriv resourcePriv() const;
234
235 /**
junov436293a2014-12-11 10:32:32 -0800236 * Removes references to objects in the underlying 3D API without freeing them.
237 * Called by CacheAccess.
238 * In general this method should not be called outside of skia. It was
239 * made by public for a special case where it needs to be called in Blink
240 * when a texture becomes unsafe to use after having been shared through
241 * a texture mailbox.
242 */
243 void abandon();
244
ericrk0a5fa482015-09-15 14:16:10 -0700245 /**
246 * Dumps memory usage information for this GrGpuResource to traceMemoryDump.
247 * Typically, subclasses should not need to override this, and should only
248 * need to override setMemoryBacking.
249 **/
250 virtual void dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const;
251
robertphillips8abb3702016-08-31 14:04:06 -0700252 static uint32_t CreateUniqueID();
253
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000254protected:
kkinnunen2e6055b2016-04-22 01:48:29 -0700255 // This must be called by every non-wrapped GrGpuObject. It should be called once the object is
256 // fully initialized (i.e. only from the constructors of the final class).
257 void registerWithCache(SkBudgeted);
bsalomon16961262014-08-26 14:01:07 -0700258
kkinnunen2e6055b2016-04-22 01:48:29 -0700259 // This must be called by every GrGpuObject that references any wrapped backend objects. It
260 // should be called once the object is fully initialized (i.e. only from the constructors of the
261 // final class).
262 void registerWithCacheWrapped();
263
264 GrGpuResource(GrGpu*);
bsalomon6d3fe022014-07-25 08:35:45 -0700265 virtual ~GrGpuResource();
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000266
267 GrGpu* getGpu() const { return fGpu; }
268
bsalomon12299ab2014-11-14 13:33:09 -0800269 /** Overridden to free GPU resources in the backend API. */
270 virtual void onRelease() { }
271 /** Overridden to abandon any internal handles, ptrs, etc to backend API resources.
272 This may be called when the underlying 3D context is no longer valid and so no
273 backend API calls should be made. */
274 virtual void onAbandon() { }
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000275
bsalomonc44be0e2014-07-25 07:32:33 -0700276 /**
bsalomon69ed47f2014-11-12 11:13:39 -0800277 * This entry point should be called whenever gpuMemorySize() should report a different size.
278 * The cache will call gpuMemorySize() to update the current size of the resource.
bsalomonc44be0e2014-07-25 07:32:33 -0700279 */
280 void didChangeGpuMemorySize() const;
281
bsalomon744998e2014-08-28 09:54:34 -0700282 /**
ericrk0a5fa482015-09-15 14:16:10 -0700283 * Allows subclasses to add additional backing information to the SkTraceMemoryDump. Called by
284 * onMemoryDump. The default implementation adds no backing information.
285 **/
286 virtual void setMemoryBacking(SkTraceMemoryDump*, const SkString&) const {}
287
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000288private:
bsalomon12299ab2014-11-14 13:33:09 -0800289 /**
kkinnunen2e6055b2016-04-22 01:48:29 -0700290 * Called by the registerWithCache if the resource is available to be used as scratch.
291 * Resource subclasses should override this if the instances should be recycled as scratch
292 * resources and populate the scratchKey with the key.
293 * By default resources are not recycled as scratch.
294 **/
Mike Kleinfc6c37b2016-09-27 09:34:10 -0400295 virtual void computeScratchKey(GrScratchKey*) const { }
kkinnunen2e6055b2016-04-22 01:48:29 -0700296
297 /**
bsalomon12299ab2014-11-14 13:33:09 -0800298 * Frees the object in the underlying 3D API. Called by CacheAccess.
299 */
300 void release();
301
bsalomon69ed47f2014-11-12 11:13:39 -0800302 virtual size_t onGpuMemorySize() const = 0;
303
bsalomon9f2d1572015-02-17 11:47:40 -0800304 // See comments in CacheAccess and ResourcePriv.
bsalomonf99e9612015-02-19 08:24:16 -0800305 void setUniqueKey(const GrUniqueKey&);
bsalomon8718aaf2015-02-19 07:24:21 -0800306 void removeUniqueKey();
bsalomon3f324322015-04-08 11:01:54 -0700307 void notifyAllCntsAreZero(CntType) const;
308 bool notifyRefCountIsZero() const;
bsalomon10e23ca2014-11-25 05:52:06 -0800309 void removeScratchKey();
bsalomonafe30052015-01-16 07:32:33 -0800310 void makeBudgeted();
bsalomonc2f35b72015-01-23 07:19:22 -0800311 void makeUnbudgeted();
bsalomonbcf0a522014-10-08 08:40:09 -0700312
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000313#ifdef SK_DEBUG
Brian Salomon5e150852017-03-22 14:53:13 -0400314 friend class GrGpu; // for assert in GrGpu to access getGpu
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000315#endif
Brian Salomon5e150852017-03-22 14:53:13 -0400316
bsalomonf320e042015-02-17 15:09:34 -0800317 // An index into a heap when this resource is purgeable or an array when not. This is maintained
318 // by the cache.
Brian Salomon5e150852017-03-22 14:53:13 -0400319 int fCacheArrayIndex;
bsalomon9f2d1572015-02-17 11:47:40 -0800320 // This value reflects how recently this resource was accessed in the cache. This is maintained
321 // by the cache.
Brian Salomon5e150852017-03-22 14:53:13 -0400322 uint32_t fTimestamp;
323 uint32_t fExternalFlushCntWhenBecamePurgeable;
324 GrStdSteadyClock::time_point fTimeWhenBecamePurgeable;
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000325
bsalomon69ed47f2014-11-12 11:13:39 -0800326 static const size_t kInvalidGpuMemorySize = ~static_cast<size_t>(0);
Brian Salomon5e150852017-03-22 14:53:13 -0400327 GrScratchKey fScratchKey;
328 GrUniqueKey fUniqueKey;
bsalomon84c8e622014-11-17 09:33:27 -0800329
330 // This is not ref'ed but abandon() or release() will be called before the GrGpu object
331 // is destroyed. Those calls set will this to NULL.
Brian Salomon5e150852017-03-22 14:53:13 -0400332 GrGpu* fGpu;
333 mutable size_t fGpuMemorySize;
bsalomon84c8e622014-11-17 09:33:27 -0800334
Brian Salomon5e150852017-03-22 14:53:13 -0400335 SkBudgeted fBudgeted;
336 bool fRefsWrappedObjects;
337 const UniqueID fUniqueID;
bsalomon744998e2014-08-28 09:54:34 -0700338
bsalomonbcf0a522014-10-08 08:40:09 -0700339 typedef GrIORef<GrGpuResource> INHERITED;
bsalomon3f324322015-04-08 11:01:54 -0700340 friend class GrIORef<GrGpuResource>; // to access notifyAllCntsAreZero and notifyRefCntIsZero.
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000341};
342
343#endif