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 #include "SkData.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 GrDrawTarget 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 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 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. 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. 53 void ref() const { 54 this->validate(); 55 ++fRefCnt; 56 } 57 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 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: 80 GrIORef() : fRefCnt(1), fPendingReads(0), fPendingWrites(0) { } 81 82 enum CntType { 83 kRef_CntType, 84 kPendingRead_CntType, 85 kPendingWrite_CntType, 86 }; 87 88 bool isPurgeable() const { return !this->internalHasRef() && !this->internalHasPendingIO(); } 89 90 bool internalHasPendingRead() const { return SkToBool(fPendingReads); } 91 bool internalHasPendingWrite() const { return SkToBool(fPendingWrites); } 92 bool internalHasPendingIO() const { return SkToBool(fPendingWrites | fPendingReads); } 93 94 bool internalHasRef() const { return SkToBool(fRefCnt); } 95 96 private: 97 void addPendingRead() const { 98 this->validate(); 99 ++fPendingReads; 100 } 101 102 void completedRead() const { 103 this->validate(); 104 --fPendingReads; 105 this->didRemoveRefOrPendingIO(kPendingRead_CntType); 106 } 107 108 void addPendingWrite() const { 109 this->validate(); 110 ++fPendingWrites; 111 } 112 113 void completedWrite() const { 114 this->validate(); 115 --fPendingWrites; 116 this->didRemoveRefOrPendingIO(kPendingWrite_CntType); 117 } 118 119 private: 120 void didRemoveRefOrPendingIO(CntType cntTypeRemoved) const { 121 if (0 == fPendingReads && 0 == fPendingWrites && 0 == fRefCnt) { 122 static_cast<const DERIVED*>(this)->notifyAllCntsAreZero(cntTypeRemoved); 123 } 124 } 125 126 mutable int32_t fRefCnt; 127 mutable int32_t fPendingReads; 128 mutable int32_t fPendingWrites; 129 130 // This class is used to manage conversion of refs to pending reads/writes. 131 friend class GrGpuResourceRef; 132 friend class GrResourceCache; // to check IO ref counts. 133 134 template <typename, GrIOType> friend class GrPendingIOResource; 135 }; 136 137 /** 138 * Base class for objects that can be kept in the GrResourceCache. 139 */ 140 class SK_API GrGpuResource : public GrIORef<GrGpuResource> { 141 public: 142 143 144 enum LifeCycle { 145 /** 146 * The resource is cached and owned by Skia. Resources with this status may be kept alive 147 * by the cache as either scratch or unique resources even when there are no refs to them. 148 * The cache may release them whenever there are no refs. 149 */ 150 kCached_LifeCycle, 151 152 /** 153 * The resource is uncached. As soon as there are no more refs to it, it is released. Under 154 * the hood the cache may opaquely recycle it as a cached resource. 155 */ 156 kUncached_LifeCycle, 157 158 /** 159 * Similar to uncached, but Skia does not manage the lifetime of the underlying backend 160 * 3D API object(s). The client is responsible for freeing those. Used to inject client- 161 * created GPU resources into Skia (e.g. to render to a client-created texture). 162 */ 163 kBorrowed_LifeCycle, 164 165 /** 166 * An external resource with ownership transfered into Skia. Skia will free the resource. 167 */ 168 kAdopted_LifeCycle, 169 }; 170 171 /** 172 * Tests whether a object has been abandoned or released. All objects will 173 * be in this state after their creating GrContext is destroyed or has 174 * contextLost called. It's up to the client to test wasDestroyed() before 175 * attempting to use an object if it holds refs on objects across 176 * ~GrContext, freeResources with the force flag, or contextLost. 177 * 178 * @return true if the object has been released or abandoned, 179 * false otherwise. 180 */ 181 bool wasDestroyed() const { return NULL == fGpu; } 182 183 /** 184 * Retrieves the context that owns the object. Note that it is possible for 185 * this to return NULL. When objects have been release()ed or abandon()ed 186 * they no longer have an owning context. Destroying a GrContext 187 * automatically releases all its resources. 188 */ 189 const GrContext* getContext() const; 190 GrContext* getContext(); 191 192 /** 193 * Retrieves the amount of GPU memory used by this resource in bytes. It is 194 * approximate since we aren't aware of additional padding or copies made 195 * by the driver. 196 * 197 * @return the amount of GPU memory used in bytes 198 */ 199 size_t gpuMemorySize() const { 200 if (kInvalidGpuMemorySize == fGpuMemorySize) { 201 fGpuMemorySize = this->onGpuMemorySize(); 202 SkASSERT(kInvalidGpuMemorySize != fGpuMemorySize); 203 } 204 return fGpuMemorySize; 205 } 206 207 /** 208 * Gets an id that is unique for this GrGpuResource object. It is static in that it does 209 * not change when the content of the GrGpuResource object changes. This will never return 210 * 0. 211 */ 212 uint32_t getUniqueID() const { return fUniqueID; } 213 214 /** Returns the current unique key for the resource. It will be invalid if the resource has no 215 associated unique key. */ 216 const GrUniqueKey& getUniqueKey() const { return fUniqueKey; } 217 218 /** 219 * Attach a custom data object to this resource. The data will remain attached 220 * for the lifetime of this resource (until it is abandoned or released). 221 * Takes a ref on data. Previously attached data, if any, is unrefed. 222 * Returns the data argument, for convenience. 223 */ 224 const SkData* setCustomData(const SkData* data); 225 226 /** 227 * Returns the custom data object that was attached to this resource by 228 * calling setCustomData. 229 */ 230 const SkData* getCustomData() const { return fData.get(); } 231 232 /** 233 * Internal-only helper class used for manipulations of the resource by the cache. 234 */ 235 class CacheAccess; 236 inline CacheAccess cacheAccess(); 237 inline const CacheAccess cacheAccess() const; 238 239 /** 240 * Internal-only helper class used for manipulations of the resource by internal code. 241 */ 242 class ResourcePriv; 243 inline ResourcePriv resourcePriv(); 244 inline const ResourcePriv resourcePriv() const; 245 246 /** 247 * Removes references to objects in the underlying 3D API without freeing them. 248 * Called by CacheAccess. 249 * In general this method should not be called outside of skia. It was 250 * made by public for a special case where it needs to be called in Blink 251 * when a texture becomes unsafe to use after having been shared through 252 * a texture mailbox. 253 */ 254 void abandon(); 255 256 /** 257 * Dumps memory usage information for this GrGpuResource to traceMemoryDump. 258 * Typically, subclasses should not need to override this, and should only 259 * need to override setMemoryBacking. 260 **/ 261 virtual void dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const; 262 263 protected: 264 // This must be called by every GrGpuObject. It should be called once the object is fully 265 // initialized (i.e. not in a base class constructor). 266 void registerWithCache(); 267 268 GrGpuResource(GrGpu*, LifeCycle); 269 virtual ~GrGpuResource(); 270 271 GrGpu* getGpu() const { return fGpu; } 272 273 /** Overridden to free GPU resources in the backend API. */ 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. */ 278 virtual void onAbandon() { } 279 280 bool shouldFreeResources() const { return fLifeCycle != kBorrowed_LifeCycle; } 281 282 bool isExternal() const { 283 return GrGpuResource::kAdopted_LifeCycle == fLifeCycle || 284 GrGpuResource::kBorrowed_LifeCycle == fLifeCycle; 285 } 286 287 /** 288 * This entry point should be called whenever gpuMemorySize() should report a different size. 289 * The cache will call gpuMemorySize() to update the current size of the resource. 290 */ 291 void didChangeGpuMemorySize() const; 292 293 /** 294 * Optionally called by the GrGpuResource subclass if the resource can be used as scratch. 295 * By default resources are not usable as scratch. This should only be called once. 296 **/ 297 void setScratchKey(const GrScratchKey& scratchKey); 298 299 /** 300 * Allows subclasses to add additional backing information to the SkTraceMemoryDump. Called by 301 * onMemoryDump. The default implementation adds no backing information. 302 **/ 303 virtual void setMemoryBacking(SkTraceMemoryDump*, const SkString&) const {} 304 305 private: 306 /** 307 * Frees the object in the underlying 3D API. Called by CacheAccess. 308 */ 309 void release(); 310 311 virtual size_t onGpuMemorySize() const = 0; 312 313 // See comments in CacheAccess and ResourcePriv. 314 void setUniqueKey(const GrUniqueKey&); 315 void removeUniqueKey(); 316 void notifyAllCntsAreZero(CntType) const; 317 bool notifyRefCountIsZero() const; 318 void removeScratchKey(); 319 void makeBudgeted(); 320 void makeUnbudgeted(); 321 322 #ifdef SK_DEBUG 323 friend class GrGpu; // for assert in GrGpu to access getGpu 324 #endif 325 326 static uint32_t CreateUniqueID(); 327 328 // An index into a heap when this resource is purgeable or an array when not. This is maintained 329 // by the cache. 330 int fCacheArrayIndex; 331 // This value reflects how recently this resource was accessed in the cache. This is maintained 332 // by the cache. 333 uint32_t fTimestamp; 334 335 static const size_t kInvalidGpuMemorySize = ~static_cast<size_t>(0); 336 GrScratchKey fScratchKey; 337 GrUniqueKey fUniqueKey; 338 339 // This is not ref'ed but abandon() or release() will be called before the GrGpu object 340 // is destroyed. Those calls set will this to NULL. 341 GrGpu* fGpu; 342 mutable size_t fGpuMemorySize; 343 344 LifeCycle fLifeCycle; 345 const uint32_t fUniqueID; 346 347 SkAutoTUnref<const SkData> fData; 348 349 typedef GrIORef<GrGpuResource> INHERITED; 350 friend class GrIORef<GrGpuResource>; // to access notifyAllCntsAreZero and notifyRefCntIsZero. 351 }; 352 353 #endif 354