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 GetKey(const GrVkResource & r)41 static const uint32_t& GetKey(const GrVkResource& r) { return r.fKey; } Hash(const uint32_t & k)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 */ GrVkResource()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 */ ~GrVkResource()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. */ getRefCnt()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 */ unique()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 */ ref()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 */ unref(const GrVkGpu * gpu)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 */ unrefAndAbandon()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 validate()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 */ abandonSubResources()133 virtual void abandonSubResources() const {} 134 135 /** 136 * Called when the ref count goes to 0. Will free Vk resources. 137 */ internal_dispose(const GrVkGpu * gpu)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 */ internal_dispose()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