GrGpuResource.h revision f320e04c50a1c8a861bc1d8f50bf732044ff9843
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 16class GrContext; 17class GrGpu; 18class 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 an item is purgeable DERIVED:notifyIsPurgeable() will be called (static poly morphism using 37 * CRTP). GrIORef and GrGpuResource are separate classes for organizational reasons and to be 38 * able to give access via friendship to only the functions related to pending IO operations. 39 */ 40template <typename DERIVED> class GrIORef : public SkNoncopyable { 41public: 42 SK_DECLARE_INST_COUNT(GrIORef) 43 44 // Some of the signatures are written to mirror SkRefCnt so that GrGpuResource can work with 45 // templated helper classes (e.g. SkAutoTUnref). However, we have different categories of 46 // refs (e.g. pending reads). We also don't require thread safety as GrCacheable objects are 47 // not intended to cross thread boundaries. 48 void ref() const { 49 this->validate(); 50 ++fRefCnt; 51 } 52 53 void unref() const { 54 this->validate(); 55 --fRefCnt; 56 this->didUnref(); 57 } 58 59 void validate() const { 60#ifdef SK_DEBUG 61 SkASSERT(fRefCnt >= 0); 62 SkASSERT(fPendingReads >= 0); 63 SkASSERT(fPendingWrites >= 0); 64 SkASSERT(fRefCnt + fPendingReads + fPendingWrites >= 0); 65#endif 66 } 67 68protected: 69 GrIORef() : fRefCnt(1), fPendingReads(0), fPendingWrites(0) { } 70 71 bool isPurgeable() const { return !this->internalHasRef() && !this->internalHasPendingIO(); } 72 73 bool internalHasPendingRead() const { return SkToBool(fPendingReads); } 74 bool internalHasPendingWrite() const { return SkToBool(fPendingWrites); } 75 bool internalHasPendingIO() const { return SkToBool(fPendingWrites | fPendingReads); } 76 77 bool internalHasRef() const { return SkToBool(fRefCnt); } 78 79private: 80 void addPendingRead() const { 81 this->validate(); 82 ++fPendingReads; 83 } 84 85 void completedRead() const { 86 this->validate(); 87 --fPendingReads; 88 this->didUnref(); 89 } 90 91 void addPendingWrite() const { 92 this->validate(); 93 ++fPendingWrites; 94 } 95 96 void completedWrite() const { 97 this->validate(); 98 --fPendingWrites; 99 this->didUnref(); 100 } 101 102private: 103 void didUnref() const { 104 if (0 == fPendingReads && 0 == fPendingWrites && 0 == fRefCnt) { 105 static_cast<const DERIVED*>(this)->notifyIsPurgeable(); 106 } 107 } 108 109 mutable int32_t fRefCnt; 110 mutable int32_t fPendingReads; 111 mutable int32_t fPendingWrites; 112 113 // This class is used to manage conversion of refs to pending reads/writes. 114 friend class GrGpuResourceRef; 115 friend class GrResourceCache; // to check IO ref counts. 116 117 template <typename, GrIOType> friend class GrPendingIOResource; 118}; 119 120/** 121 * Base class for objects that can be kept in the GrResourceCache. 122 */ 123class SK_API GrGpuResource : public GrIORef<GrGpuResource> { 124public: 125 SK_DECLARE_INST_COUNT(GrGpuResource) 126 127 enum LifeCycle { 128 /** 129 * The resource is cached and owned by Skia. Resources with this status may be kept alive 130 * by the cache as either scratch or content resources even when there are no refs to them. 131 * The cache may release them whenever there are no refs. 132 */ 133 kCached_LifeCycle, 134 /** 135 * The resource is uncached. As soon as there are no more refs to it, it is released. Under 136 * the hood the cache may opaquely recycle it as a cached resource. 137 */ 138 kUncached_LifeCycle, 139 /** 140 * Similar to uncached, but Skia does not manage the lifetime of the underlying backend 141 * 3D API object(s). The client is responsible for freeing those. Used to inject client- 142 * created GPU resources into Skia (e.g. to render to a client-created texture). 143 */ 144 kWrapped_LifeCycle, 145 }; 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 */ 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 */ 175 size_t gpuMemorySize() const { 176 if (kInvalidGpuMemorySize == fGpuMemorySize) { 177 fGpuMemorySize = this->onGpuMemorySize(); 178 SkASSERT(kInvalidGpuMemorySize != fGpuMemorySize); 179 } 180 return fGpuMemorySize; 181 } 182 183 /** 184 * Gets an id that is unique for this GrGpuResource object. It is static in that it does 185 * not change when the content of the GrGpuResource object changes. This will never return 186 * 0. 187 */ 188 uint32_t getUniqueID() const { return fUniqueID; } 189 190 /** Returns the current content key for the resource. It will be invalid if the resource has not 191 been cached by its contents. */ 192 const GrContentKey& getContentKey() const { return fContentKey; } 193 194 /** 195 * Attach a custom data object to this resource. The data will remain attached 196 * for the lifetime of this resource (until it is abandoned or released). 197 * Takes a ref on data. Previously attached data, if any, is unrefed. 198 * Returns the data argument, for convenience. 199 */ 200 const SkData* setCustomData(const SkData* data); 201 202 /** 203 * Returns the custom data object that was attached to this resource by 204 * calling setCustomData. 205 */ 206 const SkData* getCustomData() const { return fData.get(); } 207 208 /** 209 * Internal-only helper class used for manipulations of the resource by the cache. 210 */ 211 class CacheAccess; 212 inline CacheAccess cacheAccess(); 213 inline const CacheAccess cacheAccess() const; 214 215 /** 216 * Internal-only helper class used for manipulations of the resource by internal code. 217 */ 218 class ResourcePriv; 219 inline ResourcePriv resourcePriv(); 220 inline const ResourcePriv resourcePriv() const; 221 222 /** 223 * Removes references to objects in the underlying 3D API without freeing them. 224 * Called by CacheAccess. 225 * In general this method should not be called outside of skia. It was 226 * made by public for a special case where it needs to be called in Blink 227 * when a texture becomes unsafe to use after having been shared through 228 * a texture mailbox. 229 */ 230 void abandon(); 231 232protected: 233 // This must be called by every GrGpuObject. It should be called once the object is fully 234 // initialized (i.e. not in a base class constructor). 235 void registerWithCache(); 236 237 GrGpuResource(GrGpu*, LifeCycle); 238 virtual ~GrGpuResource(); 239 240 GrGpu* getGpu() const { return fGpu; } 241 242 /** Overridden to free GPU resources in the backend API. */ 243 virtual void onRelease() { } 244 /** Overridden to abandon any internal handles, ptrs, etc to backend API resources. 245 This may be called when the underlying 3D context is no longer valid and so no 246 backend API calls should be made. */ 247 virtual void onAbandon() { } 248 249 bool isWrapped() const { return kWrapped_LifeCycle == fLifeCycle; } 250 251 /** 252 * This entry point should be called whenever gpuMemorySize() should report a different size. 253 * The cache will call gpuMemorySize() to update the current size of the resource. 254 */ 255 void didChangeGpuMemorySize() const; 256 257 /** 258 * Optionally called by the GrGpuResource subclass if the resource can be used as scratch. 259 * By default resources are not usable as scratch. This should only be called once. 260 **/ 261 void setScratchKey(const GrScratchKey& scratchKey); 262 263private: 264 /** 265 * Frees the object in the underlying 3D API. Called by CacheAccess. 266 */ 267 void release(); 268 269 virtual size_t onGpuMemorySize() const = 0; 270 271 // See comments in CacheAccess and ResourcePriv. 272 bool setContentKey(const GrContentKey& contentKey); 273 void removeContentKey(); 274 void notifyIsPurgeable() const; 275 void removeScratchKey(); 276 void makeBudgeted(); 277 void makeUnbudgeted(); 278 279#ifdef SK_DEBUG 280 friend class GrGpu; // for assert in GrGpu to access getGpu 281#endif 282 283 static uint32_t CreateUniqueID(); 284 285 // An index into a heap when this resource is purgeable or an array when not. This is maintained 286 // by the cache. 287 int fCacheArrayIndex; 288 // This value reflects how recently this resource was accessed in the cache. This is maintained 289 // by the cache. 290 uint32_t fTimestamp; 291 292 static const size_t kInvalidGpuMemorySize = ~static_cast<size_t>(0); 293 GrScratchKey fScratchKey; 294 GrContentKey fContentKey; 295 296 // This is not ref'ed but abandon() or release() will be called before the GrGpu object 297 // is destroyed. Those calls set will this to NULL. 298 GrGpu* fGpu; 299 mutable size_t fGpuMemorySize; 300 301 LifeCycle fLifeCycle; 302 const uint32_t fUniqueID; 303 304 SkAutoTUnref<const SkData> fData; 305 306 typedef GrIORef<GrGpuResource> INHERITED; 307 friend class GrIORef<GrGpuResource>; // to access notifyIsPurgeable. 308}; 309 310#endif 311