1 /* 2 * Copyright 2014 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #ifndef GrGpuResource_DEFINED 9 #define GrGpuResource_DEFINED 10 11 #include "GrResourceKey.h" 12 #include "GrTypesPriv.h" 13 14 class GrContext; 15 class GrGpu; 16 class GrResourceCache; 17 class SkTraceMemoryDump; 18 19 /** 20 * 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. 23 * 24 * 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 26 * that read and write the resource via GrOpList and by any object that must own a 27 * GrGpuResource and is itself owned (directly or indirectly) by Skia-client code. 28 * 2) Pending read (+ by addPendingRead(), - by completedRead()): GrContext has scheduled a read 29 * of the resource by the GPU as a result of a skia API call but hasn't executed it yet. 30 * 3) Pending write (+ by addPendingWrite(), - by completedWrite()): GrContext has scheduled a 31 * 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. 34 * 35 * 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 44 * able to give access via friendship to only the functions related to pending IO operations. 45 */ 46 template <typename DERIVED> class GrIORef : public SkNoncopyable { 47 public: 48 // Some of the signatures are written to mirror SkRefCnt so that GrGpuResource can work with 49 // templated helper classes (e.g. sk_sp). However, we have different categories of 50 // refs (e.g. pending reads). We also don't require thread safety as GrCacheable objects are 51 // not intended to cross thread boundaries. ref()52 void ref() const { 53 this->validate(); 54 ++fRefCnt; 55 } 56 unref()57 void unref() const { 58 this->validate(); 59 60 if (!(--fRefCnt)) { 61 if (!static_cast<const DERIVED*>(this)->notifyRefCountIsZero()) { 62 return; 63 } 64 } 65 66 this->didRemoveRefOrPendingIO(kRef_CntType); 67 } 68 validate()69 void validate() const { 70 #ifdef SK_DEBUG 71 SkASSERT(fRefCnt >= 0); 72 SkASSERT(fPendingReads >= 0); 73 SkASSERT(fPendingWrites >= 0); 74 SkASSERT(fRefCnt + fPendingReads + fPendingWrites >= 0); 75 #endif 76 } 77 78 protected: GrIORef()79 GrIORef() : fRefCnt(1), fPendingReads(0), fPendingWrites(0) { } 80 81 enum CntType { 82 kRef_CntType, 83 kPendingRead_CntType, 84 kPendingWrite_CntType, 85 }; 86 isPurgeable()87 bool isPurgeable() const { return !this->internalHasRef() && !this->internalHasPendingIO(); } 88 internalHasPendingRead()89 bool internalHasPendingRead() const { return SkToBool(fPendingReads); } internalHasPendingWrite()90 bool internalHasPendingWrite() const { return SkToBool(fPendingWrites); } internalHasPendingIO()91 bool internalHasPendingIO() const { return SkToBool(fPendingWrites | fPendingReads); } 92 internalHasRef()93 bool internalHasRef() const { return SkToBool(fRefCnt); } 94 95 private: 96 friend class GrIORefProxy; // needs to forward on wrapped IO calls 97 // This is for a unit test. 98 template <typename T> 99 friend void testingOnly_getIORefCnts(const T*, int* refCnt, int* readCnt, int* writeCnt); 100 addPendingRead()101 void addPendingRead() const { 102 this->validate(); 103 ++fPendingReads; 104 } 105 completedRead()106 void completedRead() const { 107 this->validate(); 108 --fPendingReads; 109 this->didRemoveRefOrPendingIO(kPendingRead_CntType); 110 } 111 addPendingWrite()112 void addPendingWrite() const { 113 this->validate(); 114 ++fPendingWrites; 115 } 116 completedWrite()117 void completedWrite() const { 118 this->validate(); 119 --fPendingWrites; 120 this->didRemoveRefOrPendingIO(kPendingWrite_CntType); 121 } 122 123 private: didRemoveRefOrPendingIO(CntType cntTypeRemoved)124 void didRemoveRefOrPendingIO(CntType cntTypeRemoved) const { 125 if (0 == fPendingReads && 0 == fPendingWrites && 0 == fRefCnt) { 126 static_cast<const DERIVED*>(this)->notifyAllCntsAreZero(cntTypeRemoved); 127 } 128 } 129 130 mutable int32_t fRefCnt; 131 mutable int32_t fPendingReads; 132 mutable int32_t fPendingWrites; 133 134 // This class is used to manage conversion of refs to pending reads/writes. 135 friend class GrGpuResourceRef; 136 friend class GrResourceCache; // to check IO ref counts. 137 138 template <typename, GrIOType> friend class GrPendingIOResource; 139 }; 140 141 /** 142 * Base class for objects that can be kept in the GrResourceCache. 143 */ 144 class SK_API GrGpuResource : public GrIORef<GrGpuResource> { 145 public: 146 147 /** 148 * Tests whether a object has been abandoned or released. All objects will 149 * be in this state after their creating GrContext is destroyed or has 150 * contextLost called. It's up to the client to test wasDestroyed() before 151 * attempting to use an object if it holds refs on objects across 152 * ~GrContext, freeResources with the force flag, or contextLost. 153 * 154 * @return true if the object has been released or abandoned, 155 * false otherwise. 156 */ wasDestroyed()157 bool wasDestroyed() const { return NULL == fGpu; } 158 159 /** 160 * Retrieves the context that owns the object. Note that it is possible for 161 * this to return NULL. When objects have been release()ed or abandon()ed 162 * they no longer have an owning context. Destroying a GrContext 163 * automatically releases all its resources. 164 */ 165 const GrContext* getContext() const; 166 GrContext* getContext(); 167 168 /** 169 * Retrieves the amount of GPU memory used by this resource in bytes. It is 170 * approximate since we aren't aware of additional padding or copies made 171 * by the driver. 172 * 173 * @return the amount of GPU memory used in bytes 174 */ gpuMemorySize()175 size_t gpuMemorySize() const { 176 if (kInvalidGpuMemorySize == fGpuMemorySize) { 177 fGpuMemorySize = this->onGpuMemorySize(); 178 SkASSERT(kInvalidGpuMemorySize != fGpuMemorySize); 179 } 180 return fGpuMemorySize; 181 } 182 183 class UniqueID { 184 public: InvalidID()185 static UniqueID InvalidID() { 186 return UniqueID(uint32_t(SK_InvalidUniqueID)); 187 } 188 UniqueID()189 UniqueID() {} 190 UniqueID(uint32_t id)191 explicit UniqueID(uint32_t id) : fID(id) {} 192 asUInt()193 uint32_t asUInt() const { return fID; } 194 195 bool operator==(const UniqueID& other) const { 196 return fID == other.fID; 197 } 198 bool operator!=(const UniqueID& other) const { 199 return !(*this == other); 200 } 201 makeInvalid()202 void makeInvalid() { fID = SK_InvalidUniqueID; } isInvalid()203 bool isInvalid() const { return SK_InvalidUniqueID == fID; } 204 205 protected: 206 uint32_t fID; 207 }; 208 209 /** 210 * Gets an id that is unique for this GrGpuResource object. It is static in that it does 211 * not change when the content of the GrGpuResource object changes. This will never return 212 * 0. 213 */ uniqueID()214 UniqueID uniqueID() const { return fUniqueID; } 215 216 /** Returns the current unique key for the resource. It will be invalid if the resource has no 217 associated unique key. */ getUniqueKey()218 const GrUniqueKey& getUniqueKey() const { return fUniqueKey; } 219 220 /** 221 * Internal-only helper class used for manipulations of the resource by the cache. 222 */ 223 class CacheAccess; 224 inline CacheAccess cacheAccess(); 225 inline const CacheAccess cacheAccess() const; 226 227 /** 228 * Internal-only helper class used for manipulations of the resource by internal code. 229 */ 230 class ResourcePriv; 231 inline ResourcePriv resourcePriv(); 232 inline const ResourcePriv resourcePriv() const; 233 234 /** 235 * Removes references to objects in the underlying 3D API without freeing them. 236 * Called by CacheAccess. 237 * In general this method should not be called outside of skia. It was 238 * made by public for a special case where it needs to be called in Blink 239 * when a texture becomes unsafe to use after having been shared through 240 * a texture mailbox. 241 */ 242 void abandon(); 243 244 /** 245 * Dumps memory usage information for this GrGpuResource to traceMemoryDump. 246 * Typically, subclasses should not need to override this, and should only 247 * need to override setMemoryBacking. 248 **/ 249 virtual void dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const; 250 251 static uint32_t CreateUniqueID(); 252 253 protected: 254 // This must be called by every non-wrapped GrGpuObject. It should be called once the object is 255 // fully initialized (i.e. only from the constructors of the final class). 256 void registerWithCache(SkBudgeted); 257 258 // This must be called by every GrGpuObject that references any wrapped backend objects. It 259 // should be called once the object is fully initialized (i.e. only from the constructors of the 260 // final class). 261 void registerWithCacheWrapped(); 262 263 // This is only called by resources that are being exported from Ganesh to client code. It 264 // ensures that the cache can no longer reach this resource, and that it no longer counts 265 // against the budget. 266 void detachFromCache(); 267 268 GrGpuResource(GrGpu*); 269 virtual ~GrGpuResource(); 270 getGpu()271 GrGpu* getGpu() const { return fGpu; } 272 273 /** Overridden to free GPU resources in the backend API. */ onRelease()274 virtual void onRelease() { } 275 /** Overridden to abandon any internal handles, ptrs, etc to backend API resources. 276 This may be called when the underlying 3D context is no longer valid and so no 277 backend API calls should be made. */ onAbandon()278 virtual void onAbandon() { } 279 280 /** 281 * This entry point should be called whenever gpuMemorySize() should report a different size. 282 * The cache will call gpuMemorySize() to update the current size of the resource. 283 */ 284 void didChangeGpuMemorySize() const; 285 286 /** 287 * Allows subclasses to add additional backing information to the SkTraceMemoryDump. Called by 288 * onMemoryDump. The default implementation adds no backing information. 289 **/ setMemoryBacking(SkTraceMemoryDump *,const SkString &)290 virtual void setMemoryBacking(SkTraceMemoryDump*, const SkString&) const {} 291 292 private: 293 /** 294 * Called by the registerWithCache if the resource is available to be used as scratch. 295 * Resource subclasses should override this if the instances should be recycled as scratch 296 * resources and populate the scratchKey with the key. 297 * By default resources are not recycled as scratch. 298 **/ computeScratchKey(GrScratchKey *)299 virtual void computeScratchKey(GrScratchKey*) const { } 300 301 /** 302 * Frees the object in the underlying 3D API. Called by CacheAccess. 303 */ 304 void release(); 305 306 virtual size_t onGpuMemorySize() const = 0; 307 308 // See comments in CacheAccess and ResourcePriv. 309 void setUniqueKey(const GrUniqueKey&); 310 void removeUniqueKey(); 311 void notifyAllCntsAreZero(CntType) const; 312 bool notifyRefCountIsZero() const; 313 void removeScratchKey(); 314 void makeBudgeted(); 315 void makeUnbudgeted(); 316 317 #ifdef SK_DEBUG 318 friend class GrGpu; // for assert in GrGpu to access getGpu 319 #endif 320 321 // An index into a heap when this resource is purgeable or an array when not. This is maintained 322 // by the cache. 323 int fCacheArrayIndex; 324 // This value reflects how recently this resource was accessed in the cache. This is maintained 325 // by the cache. 326 uint32_t fTimestamp; 327 uint32_t fExternalFlushCntWhenBecamePurgeable; 328 GrStdSteadyClock::time_point fTimeWhenBecamePurgeable; 329 330 static const size_t kInvalidGpuMemorySize = ~static_cast<size_t>(0); 331 GrScratchKey fScratchKey; 332 GrUniqueKey fUniqueKey; 333 334 // This is not ref'ed but abandon() or release() will be called before the GrGpu object 335 // is destroyed. Those calls set will this to NULL. 336 GrGpu* fGpu; 337 mutable size_t fGpuMemorySize; 338 339 SkBudgeted fBudgeted; 340 bool fRefsWrappedObjects; 341 const UniqueID fUniqueID; 342 343 typedef GrIORef<GrGpuResource> INHERITED; 344 friend class GrIORef<GrGpuResource>; // to access notifyAllCntsAreZero and notifyRefCntIsZero. 345 }; 346 347 #endif 348