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/GrResourceKey.h" 12 #include "../private/GrTypesPriv.h" 13 #include "../private/SkNoncopyable.h" 14 15 class GrContext; 16 class GrGpu; 17 class GrResourceCache; 18 class SkTraceMemoryDump; 19 20 /** 21 * 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. 24 * 25 * 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 GrOpList and by any object that must own a 28 * GrGpuResource and is itself owned (directly or indirectly) by Skia-client code. 29 * 2) Pending read (+ by addPendingRead(), - by completedRead()): GrContext has scheduled a read 30 * of the resource by the GPU as a result of a skia API call but hasn't executed it yet. 31 * 3) Pending write (+ by addPendingWrite(), - by completedWrite()): GrContext has scheduled a 32 * 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. 35 * 36 * 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 notifyAllCntsAreZero(). 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 45 * able to give access via friendship to only the functions related to pending IO operations. 46 */ 47 template <typename DERIVED> class GrIORef : public SkNoncopyable { 48 public: 49 // Some of the signatures are written to mirror SkRefCnt so that GrGpuResource can work with 50 // templated helper classes (e.g. sk_sp). 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. ref()53 void ref() const { 54 this->validate(); 55 ++fRefCnt; 56 } 57 unref()58 void unref() const { 59 this->validate(); 60 61 if (!(--fRefCnt)) { 62 if (!static_cast<const DERIVED*>(this)->notifyRefCountIsZero()) { 63 return; 64 } 65 } 66 67 this->didRemoveRefOrPendingIO(kRef_CntType); 68 } 69 validate()70 void validate() const { 71 #ifdef SK_DEBUG 72 SkASSERT(fRefCnt >= 0); 73 SkASSERT(fPendingReads >= 0); 74 SkASSERT(fPendingWrites >= 0); 75 SkASSERT(fRefCnt + fPendingReads + fPendingWrites >= 0); 76 #endif 77 } 78 79 protected: GrIORef()80 GrIORef() : fRefCnt(1), fPendingReads(0), fPendingWrites(0) { } 81 82 enum CntType { 83 kRef_CntType, 84 kPendingRead_CntType, 85 kPendingWrite_CntType, 86 }; 87 internalHasPendingRead()88 bool internalHasPendingRead() const { return SkToBool(fPendingReads); } internalHasPendingWrite()89 bool internalHasPendingWrite() const { return SkToBool(fPendingWrites); } internalHasPendingIO()90 bool internalHasPendingIO() const { return SkToBool(fPendingWrites | fPendingReads); } 91 internalHasRef()92 bool internalHasRef() const { return SkToBool(fRefCnt); } internalHasUniqueRef()93 bool internalHasUniqueRef() const { return fRefCnt == 1; } 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 friend class GrResourceCache; // to check IO ref counts. 135 136 template <typename, GrIOType> friend class GrPendingIOResource; 137 }; 138 139 /** 140 * Base class for objects that can be kept in the GrResourceCache. 141 */ 142 class SK_API GrGpuResource : public GrIORef<GrGpuResource> { 143 public: 144 /** 145 * Tests whether a object has been abandoned or released. All objects will 146 * be in this state after their creating GrContext is destroyed or has 147 * contextLost called. It's up to the client to test wasDestroyed() before 148 * attempting to use an object if it holds refs on objects across 149 * ~GrContext, freeResources with the force flag, or contextLost. 150 * 151 * @return true if the object has been released or abandoned, 152 * false otherwise. 153 */ wasDestroyed()154 bool wasDestroyed() const { return nullptr == fGpu; } 155 156 /** 157 * Retrieves the context that owns the object. Note that it is possible for 158 * this to return NULL. When objects have been release()ed or abandon()ed 159 * they no longer have an owning context. Destroying a GrContext 160 * automatically releases all its resources. 161 */ 162 const GrContext* getContext() const; 163 GrContext* getContext(); 164 165 /** 166 * Retrieves the amount of GPU memory used by this resource in bytes. It is 167 * approximate since we aren't aware of additional padding or copies made 168 * by the driver. 169 * 170 * @return the amount of GPU memory used in bytes 171 */ gpuMemorySize()172 size_t gpuMemorySize() const { 173 if (kInvalidGpuMemorySize == fGpuMemorySize) { 174 fGpuMemorySize = this->onGpuMemorySize(); 175 SkASSERT(kInvalidGpuMemorySize != fGpuMemorySize); 176 } 177 return fGpuMemorySize; 178 } 179 180 class UniqueID { 181 public: InvalidID()182 static UniqueID InvalidID() { 183 return UniqueID(uint32_t(SK_InvalidUniqueID)); 184 } 185 UniqueID()186 UniqueID() {} 187 UniqueID(uint32_t id)188 explicit UniqueID(uint32_t id) : fID(id) {} 189 asUInt()190 uint32_t asUInt() const { return fID; } 191 192 bool operator==(const UniqueID& other) const { 193 return fID == other.fID; 194 } 195 bool operator!=(const UniqueID& other) const { 196 return !(*this == other); 197 } 198 makeInvalid()199 void makeInvalid() { fID = SK_InvalidUniqueID; } isInvalid()200 bool isInvalid() const { return SK_InvalidUniqueID == fID; } 201 202 protected: 203 uint32_t fID; 204 }; 205 206 /** 207 * Gets an id that is unique for this GrGpuResource object. It is static in that it does 208 * not change when the content of the GrGpuResource object changes. This will never return 209 * 0. 210 */ uniqueID()211 UniqueID uniqueID() const { return fUniqueID; } 212 213 /** Returns the current unique key for the resource. It will be invalid if the resource has no 214 associated unique key. */ getUniqueKey()215 const GrUniqueKey& getUniqueKey() const { return fUniqueKey; } 216 217 /** 218 * Internal-only helper class used for manipulations of the resource by the cache. 219 */ 220 class CacheAccess; 221 inline CacheAccess cacheAccess(); 222 inline const CacheAccess cacheAccess() const; 223 224 /** 225 * Internal-only helper class used for manipulations of the resource by internal code. 226 */ 227 class ResourcePriv; 228 inline ResourcePriv resourcePriv(); 229 inline const ResourcePriv resourcePriv() const; 230 231 /** 232 * Dumps memory usage information for this GrGpuResource to traceMemoryDump. 233 * Typically, subclasses should not need to override this, and should only 234 * need to override setMemoryBacking. 235 **/ 236 virtual void dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const; 237 238 /** 239 * Describes the type of gpu resource that is represented by the implementing 240 * class (e.g. texture, buffer object, stencil). This data is used for diagnostic 241 * purposes by dumpMemoryStatistics(). 242 * 243 * The value returned is expected to be long lived and will not be copied by the caller. 244 */ 245 virtual const char* getResourceType() const = 0; 246 247 static uint32_t CreateUniqueID(); 248 249 protected: 250 // This must be called by every non-wrapped GrGpuObject. It should be called once the object is 251 // fully initialized (i.e. only from the constructors of the final class). 252 void registerWithCache(SkBudgeted); 253 254 // This must be called by every GrGpuObject that references any wrapped backend objects. It 255 // should be called once the object is fully initialized (i.e. only from the constructors of the 256 // final class). 257 void registerWithCacheWrapped(GrWrapCacheable); 258 259 GrGpuResource(GrGpu*); 260 virtual ~GrGpuResource(); 261 getGpu()262 GrGpu* getGpu() const { return fGpu; } 263 264 /** Overridden to free GPU resources in the backend API. */ onRelease()265 virtual void onRelease() { } 266 /** Overridden to abandon any internal handles, ptrs, etc to backend API resources. 267 This may be called when the underlying 3D context is no longer valid and so no 268 backend API calls should be made. */ onAbandon()269 virtual void onAbandon() { } 270 271 /** 272 * Allows subclasses to add additional backing information to the SkTraceMemoryDump. 273 **/ setMemoryBacking(SkTraceMemoryDump *,const SkString &)274 virtual void setMemoryBacking(SkTraceMemoryDump*, const SkString&) const {} 275 276 /** 277 * Returns a string that uniquely identifies this resource. 278 */ 279 SkString getResourceName() const; 280 281 /** 282 * A helper for subclasses that override dumpMemoryStatistics(). This method using a format 283 * consistent with the default implementation of dumpMemoryStatistics() but allows the caller 284 * to customize various inputs. 285 */ 286 void dumpMemoryStatisticsPriv(SkTraceMemoryDump* traceMemoryDump, const SkString& resourceName, 287 const char* type, size_t size) const; 288 289 290 private: 291 bool isPurgeable() const; 292 bool hasRefOrPendingIO() const; 293 294 /** 295 * Called by the registerWithCache if the resource is available to be used as scratch. 296 * Resource subclasses should override this if the instances should be recycled as scratch 297 * resources and populate the scratchKey with the key. 298 * By default resources are not recycled as scratch. 299 **/ computeScratchKey(GrScratchKey *)300 virtual void computeScratchKey(GrScratchKey*) const {} 301 302 /** 303 * Removes references to objects in the underlying 3D API without freeing them. 304 * Called by CacheAccess. 305 */ 306 void abandon(); 307 308 /** 309 * Frees the object in the underlying 3D API. Called by CacheAccess. 310 */ 311 void release(); 312 313 virtual size_t onGpuMemorySize() const = 0; 314 315 /** 316 * Called by GrResourceCache when a resource loses its last ref or pending IO. 317 */ removedLastRefOrPendingIO()318 virtual void removedLastRefOrPendingIO() {} 319 320 // See comments in CacheAccess and ResourcePriv. 321 void setUniqueKey(const GrUniqueKey&); 322 void removeUniqueKey(); 323 void notifyAllCntsAreZero(CntType) const; 324 bool notifyRefCountIsZero() const; 325 void removeScratchKey(); 326 void makeBudgeted(); 327 void makeUnbudgeted(); 328 329 #ifdef SK_DEBUG 330 friend class GrGpu; // for assert in GrGpu to access getGpu 331 #endif 332 333 // An index into a heap when this resource is purgeable or an array when not. This is maintained 334 // by the cache. 335 int fCacheArrayIndex; 336 // This value reflects how recently this resource was accessed in the cache. This is maintained 337 // by the cache. 338 uint32_t fTimestamp; 339 GrStdSteadyClock::time_point fTimeWhenBecamePurgeable; 340 341 static const size_t kInvalidGpuMemorySize = ~static_cast<size_t>(0); 342 GrScratchKey fScratchKey; 343 GrUniqueKey fUniqueKey; 344 345 // This is not ref'ed but abandon() or release() will be called before the GrGpu object 346 // is destroyed. Those calls set will this to NULL. 347 GrGpu* fGpu; 348 mutable size_t fGpuMemorySize = kInvalidGpuMemorySize; 349 350 GrBudgetedType fBudgetedType = GrBudgetedType::kUnbudgetedUncacheable; 351 bool fRefsWrappedObjects = false; 352 const UniqueID fUniqueID; 353 354 typedef GrIORef<GrGpuResource> INHERITED; 355 friend class GrIORef<GrGpuResource>; // to access notifyAllCntsAreZero and notifyRefCntIsZero. 356 }; 357 358 #endif 359