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