Home | History | Annotate | Download | only in vk
      1 /*
      2  * Copyright 2015 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 GrVkResource_DEFINED
      9 #define GrVkResource_DEFINED
     10 
     11 #include "SkAtomics.h"
     12 #include "SkTDynamicHash.h"
     13 #include "SkRandom.h"
     14 
     15 class GrVkGpu;
     16 
     17 // uncomment to enable tracing of resource refs
     18 //#ifdef SK_DEBUG
     19 //#define SK_TRACE_VK_RESOURCES
     20 //#endif
     21 
     22 /** \class GrVkResource
     23 
     24   GrVkResource is the base class for Vulkan resources that may be shared by multiple
     25   objects. When an existing owner wants to share a reference, it calls ref().
     26   When an owner wants to release its reference, it calls unref(). When the
     27   shared object's reference count goes to zero as the result of an unref()
     28   call, its (virtual) destructor is called. It is an error for the
     29   destructor to be called explicitly (or via the object going out of scope on
     30   the stack or calling delete) if getRefCnt() > 1.
     31 
     32   This is nearly identical to SkRefCntBase. The exceptions are that unref()
     33   takes a GrVkGpu, and any derived classes must implement freeGPUData() and
     34   possibly abandonSubResources().
     35 */
     36 
     37 class GrVkResource : SkNoncopyable {
     38 public:
     39     // Simple refCount tracing, to ensure that everything ref'ed is unref'ed.
     40 #ifdef SK_TRACE_VK_RESOURCES
     41     static const uint32_t& GetKey(const GrVkResource& r) { return r.fKey; }
     42     static uint32_t Hash(const uint32_t& k) { return k; }
     43     static SkTDynamicHash<GrVkResource, uint32_t> fTrace;
     44     static SkRandom fRandom;
     45 #endif
     46 
     47     /** Default construct, initializing the reference count to 1.
     48      */
     49     GrVkResource() : fRefCnt(1) {
     50 #ifdef SK_TRACE_VK_RESOURCES
     51         fKey = fRandom.nextU();
     52         fTrace.add(this);
     53 #endif
     54     }
     55 
     56     /** Destruct, asserting that the reference count is 1.
     57      */
     58     virtual ~GrVkResource() {
     59 #ifdef SK_DEBUG
     60         SkASSERTF(fRefCnt == 1, "fRefCnt was %d", fRefCnt);
     61         fRefCnt = 0;    // illegal value, to catch us if we reuse after delete
     62 #endif
     63     }
     64 
     65 #ifdef SK_DEBUG
     66     /** Return the reference count. Use only for debugging. */
     67     int32_t getRefCnt() const { return fRefCnt; }
     68 #endif
     69 
     70     /** May return true if the caller is the only owner.
     71      *  Ensures that all previous owner's actions are complete.
     72      */
     73     bool unique() const {
     74         if (1 == sk_atomic_load(&fRefCnt, sk_memory_order_acquire)) {
     75             // The acquire barrier is only really needed if we return true.  It
     76             // prevents code conditioned on the result of unique() from running
     77             // until previous owners are all totally done calling unref().
     78             return true;
     79         }
     80         return false;
     81     }
     82 
     83     /** Increment the reference count.
     84         Must be balanced by a call to unref() or unrefAndFreeResources().
     85      */
     86     void ref() const {
     87         SkASSERT(fRefCnt > 0);
     88         (void)sk_atomic_fetch_add(&fRefCnt, +1, sk_memory_order_relaxed);  // No barrier required.
     89     }
     90 
     91     /** Decrement the reference count. If the reference count is 1 before the
     92         decrement, then delete the object. Note that if this is the case, then
     93         the object needs to have been allocated via new, and not on the stack.
     94         Any GPU data associated with this resource will be freed before it's deleted.
     95      */
     96     void unref(const GrVkGpu* gpu) const {
     97         SkASSERT(fRefCnt > 0);
     98         SkASSERT(gpu);
     99         // A release here acts in place of all releases we "should" have been doing in ref().
    100         if (1 == sk_atomic_fetch_add(&fRefCnt, -1, sk_memory_order_acq_rel)) {
    101             // Like unique(), the acquire is only needed on success, to make sure
    102             // code in internal_dispose() doesn't happen before the decrement.
    103             this->internal_dispose(gpu);
    104         }
    105     }
    106 
    107     /** Unref without freeing GPU data. Used only when we're abandoning the resource */
    108     void unrefAndAbandon() const {
    109         SkASSERT(fRefCnt > 0);
    110         // A release here acts in place of all releases we "should" have been doing in ref().
    111         if (1 == sk_atomic_fetch_add(&fRefCnt, -1, sk_memory_order_acq_rel)) {
    112             // Like unique(), the acquire is only needed on success, to make sure
    113             // code in internal_dispose() doesn't happen before the decrement.
    114             this->internal_dispose();
    115         }
    116     }
    117 
    118 #ifdef SK_DEBUG
    119     void validate() const {
    120         SkASSERT(fRefCnt > 0);
    121     }
    122 #endif
    123 
    124 private:
    125     /** Must be implemented by any subclasses.
    126      *  Deletes any Vk data associated with this resource
    127      */
    128     virtual void freeGPUData(const GrVkGpu* gpu) const = 0;
    129 
    130     /** Must be overridden by subclasses that themselves store GrVkResources.
    131      *  Will unrefAndAbandon those resources without deleting the underlying Vk data
    132      */
    133     virtual void abandonSubResources() const {}
    134 
    135     /**
    136      *  Called when the ref count goes to 0. Will free Vk resources.
    137      */
    138     void internal_dispose(const GrVkGpu* gpu) const {
    139         this->freeGPUData(gpu);
    140 #ifdef SK_TRACE_VK_RESOURCES
    141         fTrace.remove(GetKey(*this));
    142 #endif
    143         SkASSERT(0 == fRefCnt);
    144         fRefCnt = 1;
    145         delete this;
    146     }
    147 
    148     /**
    149      *  Internal_dispose without freeing Vk resources. Used when we've lost context.
    150      */
    151     void internal_dispose() const {
    152         this->abandonSubResources();
    153 #ifdef SK_TRACE_VK_RESOURCES
    154         fTrace.remove(GetKey(*this));
    155 #endif
    156         SkASSERT(0 == fRefCnt);
    157         fRefCnt = 1;
    158         delete this;
    159     }
    160 
    161     mutable int32_t fRefCnt;
    162 #ifdef SK_TRACE_VK_RESOURCES
    163     uint32_t fKey;
    164 #endif
    165 
    166     typedef SkNoncopyable INHERITED;
    167 };
    168 
    169 
    170 #endif
    171