blob: 37a87d364da857d84c2a9502286811881736df43 [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
bsalomonbcf0a522014-10-08 08:40:09 -070011#include "GrResourceKey.h"
12#include "GrTypesPriv.h"
junov5756aff2014-12-11 14:59:31 -080013#include "SkData.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
27 * that read and write the resource via GrDrawTarget and by any object that must own a
28 * 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
40 * before notifyIsPurgeable(). Moreover, if notifyRefCountIsZero() returns false then
41 * 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
50 // templated helper classes (e.g. SkAutoTUnref). However, we have different categories of
51 // 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:
bsalomon1e2530b2014-10-09 09:57:18 -070080 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
bsalomon63c992f2015-01-23 12:47:59 -080088 bool isPurgeable() const { return !this->internalHasRef() && !this->internalHasPendingIO(); }
bsalomon12299ab2014-11-14 13:33:09 -080089
bsalomon8d034a12014-09-22 12:21:08 -070090 bool internalHasPendingRead() const { return SkToBool(fPendingReads); }
91 bool internalHasPendingWrite() const { return SkToBool(fPendingWrites); }
92 bool internalHasPendingIO() const { return SkToBool(fPendingWrites | fPendingReads); }
93
bsalomon6d4488c2014-11-11 07:27:16 -080094 bool internalHasRef() const { return SkToBool(fRefCnt); }
95
bsalomon00b76bd2014-09-03 14:05:49 -070096private:
97 void addPendingRead() const {
98 this->validate();
99 ++fPendingReads;
100 }
101
102 void completedRead() const {
103 this->validate();
104 --fPendingReads;
bsalomon3f324322015-04-08 11:01:54 -0700105 this->didRemoveRefOrPendingIO(kPendingRead_CntType);
bsalomon00b76bd2014-09-03 14:05:49 -0700106 }
107
108 void addPendingWrite() const {
109 this->validate();
110 ++fPendingWrites;
111 }
112
113 void completedWrite() const {
114 this->validate();
115 --fPendingWrites;
bsalomon3f324322015-04-08 11:01:54 -0700116 this->didRemoveRefOrPendingIO(kPendingWrite_CntType);
bsalomon00b76bd2014-09-03 14:05:49 -0700117 }
118
119private:
bsalomon3f324322015-04-08 11:01:54 -0700120 void didRemoveRefOrPendingIO(CntType cntTypeRemoved) const {
bsalomon12299ab2014-11-14 13:33:09 -0800121 if (0 == fPendingReads && 0 == fPendingWrites && 0 == fRefCnt) {
bsalomon3f324322015-04-08 11:01:54 -0700122 static_cast<const DERIVED*>(this)->notifyAllCntsAreZero(cntTypeRemoved);
bsalomonbcf0a522014-10-08 08:40:09 -0700123 }
124 }
125
bsalomon00b76bd2014-09-03 14:05:49 -0700126 mutable int32_t fRefCnt;
127 mutable int32_t fPendingReads;
128 mutable int32_t fPendingWrites;
129
bsalomonac8d6192014-09-04 14:13:44 -0700130 // This class is used to manage conversion of refs to pending reads/writes.
bsalomonf96ba022014-09-17 08:05:40 -0700131 friend class GrGpuResourceRef;
bsalomon0ea80f42015-02-11 10:49:59 -0800132 friend class GrResourceCache; // to check IO ref counts.
bsalomonbcf0a522014-10-08 08:40:09 -0700133
134 template <typename, GrIOType> friend class GrPendingIOResource;
bsalomon00b76bd2014-09-03 14:05:49 -0700135};
136
137/**
bsalomon0ea80f42015-02-11 10:49:59 -0800138 * Base class for objects that can be kept in the GrResourceCache.
bsalomon00b76bd2014-09-03 14:05:49 -0700139 */
bsalomon544fe232014-10-08 10:24:07 -0700140class SK_API GrGpuResource : public GrIORef<GrGpuResource> {
bsalomon00b76bd2014-09-03 14:05:49 -0700141public:
ericrk0a5fa482015-09-15 14:16:10 -0700142
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000143 /**
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000144 * Tests whether a object has been abandoned or released. All objects will
145 * be in this state after their creating GrContext is destroyed or has
146 * contextLost called. It's up to the client to test wasDestroyed() before
147 * attempting to use an object if it holds refs on objects across
148 * ~GrContext, freeResources with the force flag, or contextLost.
149 *
150 * @return true if the object has been released or abandoned,
151 * false otherwise.
152 */
153 bool wasDestroyed() const { return NULL == fGpu; }
154
155 /**
156 * Retrieves the context that owns the object. Note that it is possible for
157 * this to return NULL. When objects have been release()ed or abandon()ed
158 * they no longer have an owning context. Destroying a GrContext
159 * automatically releases all its resources.
160 */
161 const GrContext* getContext() const;
162 GrContext* getContext();
163
bsalomonc44be0e2014-07-25 07:32:33 -0700164 /**
165 * Retrieves the amount of GPU memory used by this resource in bytes. It is
166 * approximate since we aren't aware of additional padding or copies made
167 * by the driver.
168 *
169 * @return the amount of GPU memory used in bytes
170 */
bsalomon69ed47f2014-11-12 11:13:39 -0800171 size_t gpuMemorySize() const {
172 if (kInvalidGpuMemorySize == fGpuMemorySize) {
173 fGpuMemorySize = this->onGpuMemorySize();
174 SkASSERT(kInvalidGpuMemorySize != fGpuMemorySize);
175 }
176 return fGpuMemorySize;
177 }
bsalomonc44be0e2014-07-25 07:32:33 -0700178
bsalomonc44be0e2014-07-25 07:32:33 -0700179 /**
bsalomon52e9d632014-09-05 12:23:12 -0700180 * Gets an id that is unique for this GrGpuResource object. It is static in that it does
181 * not change when the content of the GrGpuResource object changes. This will never return
bsalomonc44be0e2014-07-25 07:32:33 -0700182 * 0.
183 */
184 uint32_t getUniqueID() const { return fUniqueID; }
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000185
bsalomon8718aaf2015-02-19 07:24:21 -0800186 /** Returns the current unique key for the resource. It will be invalid if the resource has no
187 associated unique key. */
188 const GrUniqueKey& getUniqueKey() const { return fUniqueKey; }
bsalomon563ff602015-02-02 17:25:26 -0800189
bsalomon453cf402014-11-11 14:15:57 -0800190 /**
junov5756aff2014-12-11 14:59:31 -0800191 * Attach a custom data object to this resource. The data will remain attached
192 * for the lifetime of this resource (until it is abandoned or released).
193 * Takes a ref on data. Previously attached data, if any, is unrefed.
194 * Returns the data argument, for convenience.
195 */
196 const SkData* setCustomData(const SkData* data);
197
198 /**
199 * Returns the custom data object that was attached to this resource by
200 * calling setCustomData.
201 */
202 const SkData* getCustomData() const { return fData.get(); }
203
204 /**
bsalomon3582d3e2015-02-13 14:20:05 -0800205 * Internal-only helper class used for manipulations of the resource by the cache.
bsalomon453cf402014-11-11 14:15:57 -0800206 */
207 class CacheAccess;
208 inline CacheAccess cacheAccess();
209 inline const CacheAccess cacheAccess() const;
210
junov436293a2014-12-11 10:32:32 -0800211 /**
bsalomon3582d3e2015-02-13 14:20:05 -0800212 * Internal-only helper class used for manipulations of the resource by internal code.
213 */
214 class ResourcePriv;
215 inline ResourcePriv resourcePriv();
216 inline const ResourcePriv resourcePriv() const;
217
218 /**
junov436293a2014-12-11 10:32:32 -0800219 * Removes references to objects in the underlying 3D API without freeing them.
220 * Called by CacheAccess.
221 * In general this method should not be called outside of skia. It was
222 * made by public for a special case where it needs to be called in Blink
223 * when a texture becomes unsafe to use after having been shared through
224 * a texture mailbox.
225 */
226 void abandon();
227
ericrk0a5fa482015-09-15 14:16:10 -0700228 /**
229 * Dumps memory usage information for this GrGpuResource to traceMemoryDump.
230 * Typically, subclasses should not need to override this, and should only
231 * need to override setMemoryBacking.
232 **/
233 virtual void dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const;
234
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000235protected:
kkinnunen2e6055b2016-04-22 01:48:29 -0700236 // This must be called by every non-wrapped GrGpuObject. It should be called once the object is
237 // fully initialized (i.e. only from the constructors of the final class).
238 void registerWithCache(SkBudgeted);
bsalomon16961262014-08-26 14:01:07 -0700239
kkinnunen2e6055b2016-04-22 01:48:29 -0700240 // This must be called by every GrGpuObject that references any wrapped backend objects. It
241 // should be called once the object is fully initialized (i.e. only from the constructors of the
242 // final class).
243 void registerWithCacheWrapped();
244
245 GrGpuResource(GrGpu*);
bsalomon6d3fe022014-07-25 08:35:45 -0700246 virtual ~GrGpuResource();
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000247
248 GrGpu* getGpu() const { return fGpu; }
249
bsalomon12299ab2014-11-14 13:33:09 -0800250 /** Overridden to free GPU resources in the backend API. */
251 virtual void onRelease() { }
252 /** Overridden to abandon any internal handles, ptrs, etc to backend API resources.
253 This may be called when the underlying 3D context is no longer valid and so no
254 backend API calls should be made. */
255 virtual void onAbandon() { }
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000256
bsalomonc44be0e2014-07-25 07:32:33 -0700257 /**
bsalomon69ed47f2014-11-12 11:13:39 -0800258 * This entry point should be called whenever gpuMemorySize() should report a different size.
259 * The cache will call gpuMemorySize() to update the current size of the resource.
bsalomonc44be0e2014-07-25 07:32:33 -0700260 */
261 void didChangeGpuMemorySize() const;
262
bsalomon744998e2014-08-28 09:54:34 -0700263 /**
ericrk0a5fa482015-09-15 14:16:10 -0700264 * Allows subclasses to add additional backing information to the SkTraceMemoryDump. Called by
265 * onMemoryDump. The default implementation adds no backing information.
266 **/
267 virtual void setMemoryBacking(SkTraceMemoryDump*, const SkString&) const {}
268
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000269private:
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 **/
276 virtual void computeScratchKey(GrScratchKey*) const { };
277
278 /**
bsalomon12299ab2014-11-14 13:33:09 -0800279 * Frees the object in the underlying 3D API. Called by CacheAccess.
280 */
281 void release();
282
bsalomon69ed47f2014-11-12 11:13:39 -0800283 virtual size_t onGpuMemorySize() const = 0;
284
bsalomon9f2d1572015-02-17 11:47:40 -0800285 // See comments in CacheAccess and ResourcePriv.
bsalomonf99e9612015-02-19 08:24:16 -0800286 void setUniqueKey(const GrUniqueKey&);
bsalomon8718aaf2015-02-19 07:24:21 -0800287 void removeUniqueKey();
bsalomon3f324322015-04-08 11:01:54 -0700288 void notifyAllCntsAreZero(CntType) const;
289 bool notifyRefCountIsZero() const;
bsalomon10e23ca2014-11-25 05:52:06 -0800290 void removeScratchKey();
bsalomonafe30052015-01-16 07:32:33 -0800291 void makeBudgeted();
bsalomonc2f35b72015-01-23 07:19:22 -0800292 void makeUnbudgeted();
bsalomonbcf0a522014-10-08 08:40:09 -0700293
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000294#ifdef SK_DEBUG
295 friend class GrGpu; // for assert in GrGpu to access getGpu
296#endif
297
bsalomonc44be0e2014-07-25 07:32:33 -0700298 static uint32_t CreateUniqueID();
299
bsalomonf320e042015-02-17 15:09:34 -0800300 // An index into a heap when this resource is purgeable or an array when not. This is maintained
301 // by the cache.
bsalomon9f2d1572015-02-17 11:47:40 -0800302 int fCacheArrayIndex;
303 // This value reflects how recently this resource was accessed in the cache. This is maintained
304 // by the cache.
305 uint32_t fTimestamp;
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000306
bsalomon69ed47f2014-11-12 11:13:39 -0800307 static const size_t kInvalidGpuMemorySize = ~static_cast<size_t>(0);
bsalomon24db3b12015-01-23 04:24:04 -0800308 GrScratchKey fScratchKey;
bsalomon8718aaf2015-02-19 07:24:21 -0800309 GrUniqueKey fUniqueKey;
bsalomon84c8e622014-11-17 09:33:27 -0800310
311 // This is not ref'ed but abandon() or release() will be called before the GrGpu object
312 // is destroyed. Those calls set will this to NULL.
bsalomon24db3b12015-01-23 04:24:04 -0800313 GrGpu* fGpu;
314 mutable size_t fGpuMemorySize;
bsalomon84c8e622014-11-17 09:33:27 -0800315
kkinnunen2e6055b2016-04-22 01:48:29 -0700316 SkBudgeted fBudgeted;
317 bool fRefsWrappedObjects;
bsalomon24db3b12015-01-23 04:24:04 -0800318 const uint32_t fUniqueID;
bsalomon744998e2014-08-28 09:54:34 -0700319
bsalomon24db3b12015-01-23 04:24:04 -0800320 SkAutoTUnref<const SkData> fData;
junov5756aff2014-12-11 14:59:31 -0800321
bsalomonbcf0a522014-10-08 08:40:09 -0700322 typedef GrIORef<GrGpuResource> INHERITED;
bsalomon3f324322015-04-08 11:01:54 -0700323 friend class GrIORef<GrGpuResource>; // to access notifyAllCntsAreZero and notifyRefCntIsZero.
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000324};
325
326#endif