Home | History | Annotate | Download | only in gpu
      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:
     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 
     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 
     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:
     82     GrIORef() : fRefCnt(1), fPendingReads(0), fPendingWrites(0) { }
     83 
     84     enum CntType {
     85         kRef_CntType,
     86         kPendingRead_CntType,
     87         kPendingWrite_CntType,
     88     };
     89 
     90     bool isPurgeable() const { return !this->internalHasRef() && !this->internalHasPendingIO(); }
     91 
     92     bool internalHasPendingRead() const { return SkToBool(fPendingReads); }
     93     bool internalHasPendingWrite() const { return SkToBool(fPendingWrites); }
     94     bool internalHasPendingIO() const { return SkToBool(fPendingWrites | fPendingReads); }
     95 
     96     bool internalHasRef() const { return SkToBool(fRefCnt); }
     97 
     98 private:
     99     void addPendingRead() const {
    100         this->validate();
    101         ++fPendingReads;
    102     }
    103 
    104     void completedRead() const {
    105         this->validate();
    106         --fPendingReads;
    107         this->didRemoveRefOrPendingIO(kPendingRead_CntType);
    108     }
    109 
    110     void addPendingWrite() const {
    111         this->validate();
    112         ++fPendingWrites;
    113     }
    114 
    115     void completedWrite() const {
    116         this->validate();
    117         --fPendingWrites;
    118         this->didRemoveRefOrPendingIO(kPendingWrite_CntType);
    119     }
    120 
    121 private:
    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      */
    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      */
    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      */
    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. */
    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      */
    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 
    259     GrGpu* getGpu() const { return fGpu; }
    260 
    261     /** Overridden to free GPU resources in the backend API. */
    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. */
    266     virtual void onAbandon() { }
    267 
    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