blob: a9f2a0b32fd0303ab01c6eff096d37661fc7c56b [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 *
Brian Salomon8cabb322019-02-22 10:44:19 -050036 * PRIOR to the last ref/IO count being removed DERIVED::notifyAllCntsWillBeZero() will be called
37 * (static poly morphism using CRTP). It is legal for additional ref's or pending IOs to be added
38 * during this time. AFTER all the ref/io counts reach zero DERIVED::notifyAllCntsAreZero() will be
39 * called. Similarly when the ref (but not necessarily pending read/write) count reaches 0
40 * DERIVED::notifyRefCountIsZero() will be called. In the case when an unref() causes both
bsalomon3f324322015-04-08 11:01:54 -070041 * the ref cnt to reach zero and the other counts are zero, notifyRefCountIsZero() will be called
Brian Salomon9bc76d92019-01-24 12:18:33 -050042 * before notifyAllCntsAreZero(). Moreover, if notifyRefCountIsZero() returns false then
Brian Salomon8cabb322019-02-22 10:44:19 -050043 * notifyAllCntsAreZero() won't be called at all. notifyRefCountIsZero() must return false if the
bsalomon3f324322015-04-08 11:01:54 -070044 * object may be deleted after notifyRefCntIsZero() returns.
45 *
46 * GrIORef and GrGpuResource are separate classes for organizational reasons and to be
bsalomonbcf0a522014-10-08 08:40:09 -070047 * able to give access via friendship to only the functions related to pending IO operations.
commit-bot@chromium.org089a7802014-05-02 21:38:22 +000048 */
bsalomonbcf0a522014-10-08 08:40:09 -070049template <typename DERIVED> class GrIORef : public SkNoncopyable {
commit-bot@chromium.org089a7802014-05-02 21:38:22 +000050public:
bsalomon00b76bd2014-09-03 14:05:49 -070051 // Some of the signatures are written to mirror SkRefCnt so that GrGpuResource can work with
bungeman6bd52842016-10-27 09:30:08 -070052 // templated helper classes (e.g. sk_sp). However, we have different categories of
bsalomon00b76bd2014-09-03 14:05:49 -070053 // refs (e.g. pending reads). We also don't require thread safety as GrCacheable objects are
54 // not intended to cross thread boundaries.
bsalomon00b76bd2014-09-03 14:05:49 -070055 void ref() const {
Brian Salomon9323b8b2014-10-07 15:07:38 -040056 this->validate();
bsalomonbcf0a522014-10-08 08:40:09 -070057 ++fRefCnt;
bsalomonc44be0e2014-07-25 07:32:33 -070058 }
bsalomon00b76bd2014-09-03 14:05:49 -070059
60 void unref() const {
61 this->validate();
mtklein2766c002015-06-26 11:45:03 -070062
Brian Salomon8cabb322019-02-22 10:44:19 -050063 if (fRefCnt == 1) {
64 if (!this->internalHasPendingIO()) {
65 static_cast<const DERIVED*>(this)->notifyAllCntsWillBeZero();
66 }
67 SkASSERT(fRefCnt > 0);
68 }
69 if (--fRefCnt == 0) {
bsalomon3f324322015-04-08 11:01:54 -070070 if (!static_cast<const DERIVED*>(this)->notifyRefCountIsZero()) {
71 return;
72 }
73 }
74
75 this->didRemoveRefOrPendingIO(kRef_CntType);
bsalomon00b76bd2014-09-03 14:05:49 -070076 }
77
bsalomon00b76bd2014-09-03 14:05:49 -070078 void validate() const {
79#ifdef SK_DEBUG
80 SkASSERT(fRefCnt >= 0);
81 SkASSERT(fPendingReads >= 0);
82 SkASSERT(fPendingWrites >= 0);
bsalomon12299ab2014-11-14 13:33:09 -080083 SkASSERT(fRefCnt + fPendingReads + fPendingWrites >= 0);
bsalomonc44be0e2014-07-25 07:32:33 -070084#endif
bsalomon00b76bd2014-09-03 14:05:49 -070085 }
86
87protected:
Brian Salomon9f7d9a22018-12-11 19:01:32 +000088 GrIORef() : fRefCnt(1), fPendingReads(0), fPendingWrites(0) { }
bsalomon00b76bd2014-09-03 14:05:49 -070089
bsalomon3f324322015-04-08 11:01:54 -070090 enum CntType {
91 kRef_CntType,
92 kPendingRead_CntType,
93 kPendingWrite_CntType,
94 };
95
bsalomon8d034a12014-09-22 12:21:08 -070096 bool internalHasPendingRead() const { return SkToBool(fPendingReads); }
97 bool internalHasPendingWrite() const { return SkToBool(fPendingWrites); }
98 bool internalHasPendingIO() const { return SkToBool(fPendingWrites | fPendingReads); }
99
bsalomon6d4488c2014-11-11 07:27:16 -0800100 bool internalHasRef() const { return SkToBool(fRefCnt); }
Eric Karl914a36b2017-10-12 12:44:50 -0700101 bool internalHasUniqueRef() const { return fRefCnt == 1; }
bsalomon6d4488c2014-11-11 07:27:16 -0800102
bsalomon00b76bd2014-09-03 14:05:49 -0700103private:
Brian Salomonf046e152017-01-11 15:24:47 -0500104 // This is for a unit test.
105 template <typename T>
106 friend void testingOnly_getIORefCnts(const T*, int* refCnt, int* readCnt, int* writeCnt);
robertphillips1125a032016-11-16 11:17:17 -0800107
bsalomon00b76bd2014-09-03 14:05:49 -0700108 void addPendingRead() const {
109 this->validate();
110 ++fPendingReads;
111 }
112
113 void completedRead() const {
114 this->validate();
Brian Salomon8cabb322019-02-22 10:44:19 -0500115 if (fPendingReads == 1 && !fPendingWrites && !fRefCnt) {
116 static_cast<const DERIVED*>(this)->notifyAllCntsWillBeZero();
117 }
bsalomon00b76bd2014-09-03 14:05:49 -0700118 --fPendingReads;
bsalomon3f324322015-04-08 11:01:54 -0700119 this->didRemoveRefOrPendingIO(kPendingRead_CntType);
bsalomon00b76bd2014-09-03 14:05:49 -0700120 }
121
122 void addPendingWrite() const {
123 this->validate();
124 ++fPendingWrites;
125 }
126
127 void completedWrite() const {
128 this->validate();
Brian Salomon8cabb322019-02-22 10:44:19 -0500129 if (fPendingWrites == 1 && !fPendingReads && !fRefCnt) {
130 static_cast<const DERIVED*>(this)->notifyAllCntsWillBeZero();
131 }
bsalomon00b76bd2014-09-03 14:05:49 -0700132 --fPendingWrites;
bsalomon3f324322015-04-08 11:01:54 -0700133 this->didRemoveRefOrPendingIO(kPendingWrite_CntType);
bsalomon00b76bd2014-09-03 14:05:49 -0700134 }
135
bsalomon3f324322015-04-08 11:01:54 -0700136 void didRemoveRefOrPendingIO(CntType cntTypeRemoved) const {
bsalomon12299ab2014-11-14 13:33:09 -0800137 if (0 == fPendingReads && 0 == fPendingWrites && 0 == fRefCnt) {
bsalomon3f324322015-04-08 11:01:54 -0700138 static_cast<const DERIVED*>(this)->notifyAllCntsAreZero(cntTypeRemoved);
bsalomonbcf0a522014-10-08 08:40:09 -0700139 }
140 }
141
bsalomon00b76bd2014-09-03 14:05:49 -0700142 mutable int32_t fRefCnt;
143 mutable int32_t fPendingReads;
144 mutable int32_t fPendingWrites;
145
Brian Salomondbf70722019-02-07 11:31:24 -0500146 friend class GrIORefProxy; // needs to forward on wrapped IO calls
Brian Salomon9f7d9a22018-12-11 19:01:32 +0000147 friend class GrResourceCache; // to check IO ref counts.
bsalomonbcf0a522014-10-08 08:40:09 -0700148
149 template <typename, GrIOType> friend class GrPendingIOResource;
bsalomon00b76bd2014-09-03 14:05:49 -0700150};
151
152/**
bsalomon0ea80f42015-02-11 10:49:59 -0800153 * Base class for objects that can be kept in the GrResourceCache.
bsalomon00b76bd2014-09-03 14:05:49 -0700154 */
bsalomon544fe232014-10-08 10:24:07 -0700155class SK_API GrGpuResource : public GrIORef<GrGpuResource> {
bsalomon00b76bd2014-09-03 14:05:49 -0700156public:
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000157 /**
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000158 * Tests whether a object has been abandoned or released. All objects will
159 * be in this state after their creating GrContext is destroyed or has
160 * contextLost called. It's up to the client to test wasDestroyed() before
161 * attempting to use an object if it holds refs on objects across
162 * ~GrContext, freeResources with the force flag, or contextLost.
163 *
164 * @return true if the object has been released or abandoned,
165 * false otherwise.
166 */
Ben Wagnera93a14a2017-08-28 10:34:05 -0400167 bool wasDestroyed() const { return nullptr == fGpu; }
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000168
169 /**
170 * Retrieves the context that owns the object. Note that it is possible for
171 * this to return NULL. When objects have been release()ed or abandon()ed
172 * they no longer have an owning context. Destroying a GrContext
173 * automatically releases all its resources.
174 */
175 const GrContext* getContext() const;
176 GrContext* getContext();
177
bsalomonc44be0e2014-07-25 07:32:33 -0700178 /**
179 * Retrieves the amount of GPU memory used by this resource in bytes. It is
180 * approximate since we aren't aware of additional padding or copies made
181 * by the driver.
182 *
183 * @return the amount of GPU memory used in bytes
184 */
bsalomon69ed47f2014-11-12 11:13:39 -0800185 size_t gpuMemorySize() const {
186 if (kInvalidGpuMemorySize == fGpuMemorySize) {
187 fGpuMemorySize = this->onGpuMemorySize();
188 SkASSERT(kInvalidGpuMemorySize != fGpuMemorySize);
189 }
190 return fGpuMemorySize;
191 }
bsalomonc44be0e2014-07-25 07:32:33 -0700192
Robert Phillips294870f2016-11-11 12:38:40 -0500193 class UniqueID {
194 public:
Brian Salomon8c8806f2019-02-07 13:55:57 -0500195 UniqueID() = default;
Robert Phillips294870f2016-11-11 12:38:40 -0500196
197 explicit UniqueID(uint32_t id) : fID(id) {}
198
199 uint32_t asUInt() const { return fID; }
200
Brian Salomon8c8806f2019-02-07 13:55:57 -0500201 bool operator==(const UniqueID& other) const { return fID == other.fID; }
202 bool operator!=(const UniqueID& other) const { return !(*this == other); }
Robert Phillips294870f2016-11-11 12:38:40 -0500203
204 void makeInvalid() { fID = SK_InvalidUniqueID; }
Brian Salomon8c8806f2019-02-07 13:55:57 -0500205 bool isInvalid() const { return fID == SK_InvalidUniqueID; }
Robert Phillips294870f2016-11-11 12:38:40 -0500206
207 protected:
Brian Salomon8c8806f2019-02-07 13:55:57 -0500208 uint32_t fID = SK_InvalidUniqueID;
Robert Phillips294870f2016-11-11 12:38:40 -0500209 };
210
bsalomonc44be0e2014-07-25 07:32:33 -0700211 /**
bsalomon52e9d632014-09-05 12:23:12 -0700212 * Gets an id that is unique for this GrGpuResource object. It is static in that it does
213 * not change when the content of the GrGpuResource object changes. This will never return
bsalomonc44be0e2014-07-25 07:32:33 -0700214 * 0.
215 */
Robert Phillips294870f2016-11-11 12:38:40 -0500216 UniqueID uniqueID() const { return fUniqueID; }
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000217
bsalomon8718aaf2015-02-19 07:24:21 -0800218 /** Returns the current unique key for the resource. It will be invalid if the resource has no
219 associated unique key. */
220 const GrUniqueKey& getUniqueKey() const { return fUniqueKey; }
bsalomon563ff602015-02-02 17:25:26 -0800221
bsalomon453cf402014-11-11 14:15:57 -0800222 /**
bsalomon3582d3e2015-02-13 14:20:05 -0800223 * Internal-only helper class used for manipulations of the resource by the cache.
bsalomon453cf402014-11-11 14:15:57 -0800224 */
225 class CacheAccess;
226 inline CacheAccess cacheAccess();
227 inline const CacheAccess cacheAccess() const;
228
junov436293a2014-12-11 10:32:32 -0800229 /**
bsalomon3582d3e2015-02-13 14:20:05 -0800230 * Internal-only helper class used for manipulations of the resource by internal code.
231 */
232 class ResourcePriv;
233 inline ResourcePriv resourcePriv();
234 inline const ResourcePriv resourcePriv() const;
235
236 /**
ericrk0a5fa482015-09-15 14:16:10 -0700237 * Dumps memory usage information for this GrGpuResource to traceMemoryDump.
238 * Typically, subclasses should not need to override this, and should only
239 * need to override setMemoryBacking.
240 **/
241 virtual void dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const;
242
Derek Sollenbergercf6da8c2018-03-29 13:40:02 -0400243 /**
244 * Describes the type of gpu resource that is represented by the implementing
245 * class (e.g. texture, buffer object, stencil). This data is used for diagnostic
246 * purposes by dumpMemoryStatistics().
247 *
248 * The value returned is expected to be long lived and will not be copied by the caller.
249 */
250 virtual const char* getResourceType() const = 0;
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).
Brian Salomonaa6ca0a2019-01-24 16:03:07 -0500262 void registerWithCacheWrapped(GrWrapCacheable);
kkinnunen2e6055b2016-04-22 01:48:29 -0700263
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. */
Brian Salomon9f7d9a22018-12-11 19:01:32 +0000270 virtual void onRelease() { }
bsalomon12299ab2014-11-14 13:33:09 -0800271 /** 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. */
Brian Salomon9f7d9a22018-12-11 19:01:32 +0000274 virtual void onAbandon() { }
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000275
bsalomonc44be0e2014-07-25 07:32:33 -0700276 /**
Derek Sollenbergercf6da8c2018-03-29 13:40:02 -0400277 * Allows subclasses to add additional backing information to the SkTraceMemoryDump.
ericrk0a5fa482015-09-15 14:16:10 -0700278 **/
279 virtual void setMemoryBacking(SkTraceMemoryDump*, const SkString&) const {}
280
Derek Sollenbergercf6da8c2018-03-29 13:40:02 -0400281 /**
282 * Returns a string that uniquely identifies this resource.
283 */
284 SkString getResourceName() const;
285
286 /**
287 * A helper for subclasses that override dumpMemoryStatistics(). This method using a format
288 * consistent with the default implementation of dumpMemoryStatistics() but allows the caller
289 * to customize various inputs.
290 */
291 void dumpMemoryStatisticsPriv(SkTraceMemoryDump* traceMemoryDump, const SkString& resourceName,
292 const char* type, size_t size) const;
293
Brian Salomon9f7d9a22018-12-11 19:01:32 +0000294
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000295private:
Brian Salomon9bc76d92019-01-24 12:18:33 -0500296 bool isPurgeable() const;
297 bool hasRefOrPendingIO() const;
Brian Salomon614c1a82018-12-19 15:42:06 -0500298
bsalomon12299ab2014-11-14 13:33:09 -0800299 /**
kkinnunen2e6055b2016-04-22 01:48:29 -0700300 * Called by the registerWithCache if the resource is available to be used as scratch.
301 * Resource subclasses should override this if the instances should be recycled as scratch
302 * resources and populate the scratchKey with the key.
303 * By default resources are not recycled as scratch.
304 **/
Brian Salomon9bc76d92019-01-24 12:18:33 -0500305 virtual void computeScratchKey(GrScratchKey*) const {}
kkinnunen2e6055b2016-04-22 01:48:29 -0700306
307 /**
Brian Salomon35ba6142019-01-24 13:08:59 -0500308 * Removes references to objects in the underlying 3D API without freeing them.
309 * Called by CacheAccess.
310 */
311 void abandon();
312
313 /**
bsalomon12299ab2014-11-14 13:33:09 -0800314 * Frees the object in the underlying 3D API. Called by CacheAccess.
315 */
316 void release();
317
bsalomon69ed47f2014-11-12 11:13:39 -0800318 virtual size_t onGpuMemorySize() const = 0;
319
Brian Salomon614c1a82018-12-19 15:42:06 -0500320 /**
Brian Salomon9bc76d92019-01-24 12:18:33 -0500321 * Called by GrResourceCache when a resource loses its last ref or pending IO.
Brian Salomon614c1a82018-12-19 15:42:06 -0500322 */
Brian Salomon8cabb322019-02-22 10:44:19 -0500323 virtual void willRemoveLastRefOrPendingIO() {}
Brian Salomon614c1a82018-12-19 15:42:06 -0500324
bsalomon9f2d1572015-02-17 11:47:40 -0800325 // See comments in CacheAccess and ResourcePriv.
bsalomonf99e9612015-02-19 08:24:16 -0800326 void setUniqueKey(const GrUniqueKey&);
bsalomon8718aaf2015-02-19 07:24:21 -0800327 void removeUniqueKey();
Brian Salomon8cabb322019-02-22 10:44:19 -0500328 void notifyAllCntsWillBeZero() const;
bsalomon3f324322015-04-08 11:01:54 -0700329 void notifyAllCntsAreZero(CntType) const;
330 bool notifyRefCountIsZero() const;
bsalomon10e23ca2014-11-25 05:52:06 -0800331 void removeScratchKey();
bsalomonafe30052015-01-16 07:32:33 -0800332 void makeBudgeted();
bsalomonc2f35b72015-01-23 07:19:22 -0800333 void makeUnbudgeted();
bsalomonbcf0a522014-10-08 08:40:09 -0700334
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000335#ifdef SK_DEBUG
Brian Salomon5e150852017-03-22 14:53:13 -0400336 friend class GrGpu; // for assert in GrGpu to access getGpu
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000337#endif
Brian Salomon5e150852017-03-22 14:53:13 -0400338
bsalomonf320e042015-02-17 15:09:34 -0800339 // An index into a heap when this resource is purgeable or an array when not. This is maintained
340 // by the cache.
Brian Salomon5e150852017-03-22 14:53:13 -0400341 int fCacheArrayIndex;
bsalomon9f2d1572015-02-17 11:47:40 -0800342 // This value reflects how recently this resource was accessed in the cache. This is maintained
343 // by the cache.
Brian Salomon5e150852017-03-22 14:53:13 -0400344 uint32_t fTimestamp;
Brian Salomon5e150852017-03-22 14:53:13 -0400345 GrStdSteadyClock::time_point fTimeWhenBecamePurgeable;
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000346
bsalomon69ed47f2014-11-12 11:13:39 -0800347 static const size_t kInvalidGpuMemorySize = ~static_cast<size_t>(0);
Brian Salomon5e150852017-03-22 14:53:13 -0400348 GrScratchKey fScratchKey;
349 GrUniqueKey fUniqueKey;
bsalomon84c8e622014-11-17 09:33:27 -0800350
351 // This is not ref'ed but abandon() or release() will be called before the GrGpu object
352 // is destroyed. Those calls set will this to NULL.
Brian Salomon5e150852017-03-22 14:53:13 -0400353 GrGpu* fGpu;
Brian Salomonfa2ebea2019-01-24 15:58:58 -0500354 mutable size_t fGpuMemorySize = kInvalidGpuMemorySize;
bsalomon84c8e622014-11-17 09:33:27 -0800355
Brian Salomonaa6ca0a2019-01-24 16:03:07 -0500356 GrBudgetedType fBudgetedType = GrBudgetedType::kUnbudgetedUncacheable;
Brian Salomonfa2ebea2019-01-24 15:58:58 -0500357 bool fRefsWrappedObjects = false;
Brian Salomon5e150852017-03-22 14:53:13 -0400358 const UniqueID fUniqueID;
bsalomon744998e2014-08-28 09:54:34 -0700359
bsalomonbcf0a522014-10-08 08:40:09 -0700360 typedef GrIORef<GrGpuResource> INHERITED;
Brian Salomon9f7d9a22018-12-11 19:01:32 +0000361 friend class GrIORef<GrGpuResource>; // to access notifyAllCntsAreZero and notifyRefCntIsZero.
commit-bot@chromium.org089a7802014-05-02 21:38:22 +0000362};
363
364#endif