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 "../private/GrTypesPriv.h" 12 #include "GrResourceKey.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 GrGpuResource(GrGpu*); 264 virtual ~GrGpuResource(); 265 getGpu()266 GrGpu* getGpu() const { return fGpu; } 267 268 /** Overridden to free GPU resources in the backend API. */ onRelease()269 virtual void onRelease() { } 270 /** Overridden to abandon any internal handles, ptrs, etc to backend API resources. 271 This may be called when the underlying 3D context is no longer valid and so no 272 backend API calls should be made. */ onAbandon()273 virtual void onAbandon() { } 274 275 /** 276 * This entry point should be called whenever gpuMemorySize() should report a different size. 277 * The cache will call gpuMemorySize() to update the current size of the resource. 278 */ 279 void didChangeGpuMemorySize() const; 280 281 /** 282 * Allows subclasses to add additional backing information to the SkTraceMemoryDump. Called by 283 * onMemoryDump. The default implementation adds no backing information. 284 **/ setMemoryBacking(SkTraceMemoryDump *,const SkString &)285 virtual void setMemoryBacking(SkTraceMemoryDump*, const SkString&) const {} 286 287 private: 288 /** 289 * Called by the registerWithCache if the resource is available to be used as scratch. 290 * Resource subclasses should override this if the instances should be recycled as scratch 291 * resources and populate the scratchKey with the key. 292 * By default resources are not recycled as scratch. 293 **/ computeScratchKey(GrScratchKey *)294 virtual void computeScratchKey(GrScratchKey*) const { } 295 296 /** 297 * Frees the object in the underlying 3D API. Called by CacheAccess. 298 */ 299 void release(); 300 301 virtual size_t onGpuMemorySize() const = 0; 302 303 // See comments in CacheAccess and ResourcePriv. 304 void setUniqueKey(const GrUniqueKey&); 305 void removeUniqueKey(); 306 void notifyAllCntsAreZero(CntType) const; 307 bool notifyRefCountIsZero() const; 308 void removeScratchKey(); 309 void makeBudgeted(); 310 void makeUnbudgeted(); 311 312 #ifdef SK_DEBUG 313 friend class GrGpu; // for assert in GrGpu to access getGpu 314 #endif 315 316 // An index into a heap when this resource is purgeable or an array when not. This is maintained 317 // by the cache. 318 int fCacheArrayIndex; 319 // This value reflects how recently this resource was accessed in the cache. This is maintained 320 // by the cache. 321 uint32_t fTimestamp; 322 uint32_t fExternalFlushCntWhenBecamePurgeable; 323 GrStdSteadyClock::time_point fTimeWhenBecamePurgeable; 324 325 static const size_t kInvalidGpuMemorySize = ~static_cast<size_t>(0); 326 GrScratchKey fScratchKey; 327 GrUniqueKey fUniqueKey; 328 329 // This is not ref'ed but abandon() or release() will be called before the GrGpu object 330 // is destroyed. Those calls set will this to NULL. 331 GrGpu* fGpu; 332 mutable size_t fGpuMemorySize; 333 334 SkBudgeted fBudgeted; 335 bool fRefsWrappedObjects; 336 const UniqueID fUniqueID; 337 338 typedef GrIORef<GrGpuResource> INHERITED; 339 friend class GrIORef<GrGpuResource>; // to access notifyAllCntsAreZero and notifyRefCntIsZero. 340 }; 341 342 #endif 343