1*c8dee2aaSAndroid Build Coastguard Worker /* 2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2015 Google Inc. 3*c8dee2aaSAndroid Build Coastguard Worker * 4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be 5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file. 6*c8dee2aaSAndroid Build Coastguard Worker */ 7*c8dee2aaSAndroid Build Coastguard Worker 8*c8dee2aaSAndroid Build Coastguard Worker #ifndef GrManagedResource_DEFINED 9*c8dee2aaSAndroid Build Coastguard Worker #define GrManagedResource_DEFINED 10*c8dee2aaSAndroid Build Coastguard Worker 11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h" 12*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkAssert.h" 13*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkDebug.h" 14*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkMutex.h" 15*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkNoncopyable.h" 16*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkThreadAnnotations.h" 17*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkTHash.h" 18*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrSurface.h" 19*c8dee2aaSAndroid Build Coastguard Worker 20*c8dee2aaSAndroid Build Coastguard Worker #include <atomic> 21*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint> 22*c8dee2aaSAndroid Build Coastguard Worker #include <utility> 23*c8dee2aaSAndroid Build Coastguard Worker 24*c8dee2aaSAndroid Build Coastguard Worker // uncomment to enable tracing of resource refs 25*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_DEBUG 26*c8dee2aaSAndroid Build Coastguard Worker #define SK_TRACE_MANAGED_RESOURCES 27*c8dee2aaSAndroid Build Coastguard Worker #endif 28*c8dee2aaSAndroid Build Coastguard Worker 29*c8dee2aaSAndroid Build Coastguard Worker /** \class GrManagedResource 30*c8dee2aaSAndroid Build Coastguard Worker 31*c8dee2aaSAndroid Build Coastguard Worker GrManagedResource is the base class for GPU resources that may be shared by 32*c8dee2aaSAndroid Build Coastguard Worker multiple objects, in particular objects that are tracked by a command buffer. 33*c8dee2aaSAndroid Build Coastguard Worker When an existing owner wants to share a reference, it calls ref(). 34*c8dee2aaSAndroid Build Coastguard Worker When an owner wants to release its reference, it calls unref(). When the 35*c8dee2aaSAndroid Build Coastguard Worker shared object's reference count goes to zero as the result of an unref() 36*c8dee2aaSAndroid Build Coastguard Worker call, its (virtual) destructor is called. It is an error for the 37*c8dee2aaSAndroid Build Coastguard Worker destructor to be called explicitly (or via the object going out of scope on 38*c8dee2aaSAndroid Build Coastguard Worker the stack or calling delete) if getRefCnt() > 1. 39*c8dee2aaSAndroid Build Coastguard Worker 40*c8dee2aaSAndroid Build Coastguard Worker This is nearly identical to SkRefCntBase. The exceptions are that unref() 41*c8dee2aaSAndroid Build Coastguard Worker takes a GrGpu, and any derived classes must implement freeGPUData(). 42*c8dee2aaSAndroid Build Coastguard Worker */ 43*c8dee2aaSAndroid Build Coastguard Worker 44*c8dee2aaSAndroid Build Coastguard Worker class GrManagedResource : SkNoncopyable { 45*c8dee2aaSAndroid Build Coastguard Worker public: 46*c8dee2aaSAndroid Build Coastguard Worker // Simple refCount tracing, to ensure that everything ref'ed is unref'ed. 47*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_TRACE_MANAGED_RESOURCES 48*c8dee2aaSAndroid Build Coastguard Worker struct Hash { operatorHash49*c8dee2aaSAndroid Build Coastguard Worker uint32_t operator()(const GrManagedResource* const& r) const { 50*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(r); 51*c8dee2aaSAndroid Build Coastguard Worker return r->fKey; 52*c8dee2aaSAndroid Build Coastguard Worker } 53*c8dee2aaSAndroid Build Coastguard Worker }; 54*c8dee2aaSAndroid Build Coastguard Worker 55*c8dee2aaSAndroid Build Coastguard Worker class Trace { 56*c8dee2aaSAndroid Build Coastguard Worker public: ~Trace()57*c8dee2aaSAndroid Build Coastguard Worker ~Trace() { 58*c8dee2aaSAndroid Build Coastguard Worker fHashSet.foreach([](const GrManagedResource* r) { 59*c8dee2aaSAndroid Build Coastguard Worker r->dumpInfo(); 60*c8dee2aaSAndroid Build Coastguard Worker }); 61*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(0 == fHashSet.count()); 62*c8dee2aaSAndroid Build Coastguard Worker } 63*c8dee2aaSAndroid Build Coastguard Worker add(const GrManagedResource * r)64*c8dee2aaSAndroid Build Coastguard Worker void add(const GrManagedResource* r) { 65*c8dee2aaSAndroid Build Coastguard Worker SkAutoMutexExclusive locked(fLock); 66*c8dee2aaSAndroid Build Coastguard Worker fHashSet.add(r); 67*c8dee2aaSAndroid Build Coastguard Worker } 68*c8dee2aaSAndroid Build Coastguard Worker remove(const GrManagedResource * r)69*c8dee2aaSAndroid Build Coastguard Worker void remove(const GrManagedResource* r) { 70*c8dee2aaSAndroid Build Coastguard Worker SkAutoMutexExclusive locked(fLock); 71*c8dee2aaSAndroid Build Coastguard Worker fHashSet.remove(r); 72*c8dee2aaSAndroid Build Coastguard Worker } 73*c8dee2aaSAndroid Build Coastguard Worker 74*c8dee2aaSAndroid Build Coastguard Worker private: 75*c8dee2aaSAndroid Build Coastguard Worker SkMutex fLock; 76*c8dee2aaSAndroid Build Coastguard Worker skia_private::THashSet<const GrManagedResource*, GrManagedResource::Hash> fHashSet 77*c8dee2aaSAndroid Build Coastguard Worker SK_GUARDED_BY(fLock); 78*c8dee2aaSAndroid Build Coastguard Worker }; 79*c8dee2aaSAndroid Build Coastguard Worker 80*c8dee2aaSAndroid Build Coastguard Worker static std::atomic<uint32_t> fKeyCounter; 81*c8dee2aaSAndroid Build Coastguard Worker #endif 82*c8dee2aaSAndroid Build Coastguard Worker 83*c8dee2aaSAndroid Build Coastguard Worker /** Default construct, initializing the reference count to 1. 84*c8dee2aaSAndroid Build Coastguard Worker */ GrManagedResource()85*c8dee2aaSAndroid Build Coastguard Worker GrManagedResource() : fRefCnt(1) { 86*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_TRACE_MANAGED_RESOURCES 87*c8dee2aaSAndroid Build Coastguard Worker fKey = fKeyCounter.fetch_add(+1, std::memory_order_relaxed); 88*c8dee2aaSAndroid Build Coastguard Worker GetTrace()->add(this); 89*c8dee2aaSAndroid Build Coastguard Worker #endif 90*c8dee2aaSAndroid Build Coastguard Worker } 91*c8dee2aaSAndroid Build Coastguard Worker 92*c8dee2aaSAndroid Build Coastguard Worker /** Destruct, asserting that the reference count is 1. 93*c8dee2aaSAndroid Build Coastguard Worker */ ~GrManagedResource()94*c8dee2aaSAndroid Build Coastguard Worker virtual ~GrManagedResource() { 95*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_DEBUG 96*c8dee2aaSAndroid Build Coastguard Worker auto count = this->getRefCnt(); 97*c8dee2aaSAndroid Build Coastguard Worker SkASSERTF(count == 1, "fRefCnt was %d", count); 98*c8dee2aaSAndroid Build Coastguard Worker fRefCnt.store(0); // illegal value, to catch us if we reuse after delete 99*c8dee2aaSAndroid Build Coastguard Worker #endif 100*c8dee2aaSAndroid Build Coastguard Worker } 101*c8dee2aaSAndroid Build Coastguard Worker 102*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_DEBUG 103*c8dee2aaSAndroid Build Coastguard Worker /** Return the reference count. Use only for debugging. */ getRefCnt()104*c8dee2aaSAndroid Build Coastguard Worker int32_t getRefCnt() const { return fRefCnt.load(); } 105*c8dee2aaSAndroid Build Coastguard Worker #endif 106*c8dee2aaSAndroid Build Coastguard Worker 107*c8dee2aaSAndroid Build Coastguard Worker /** May return true if the caller is the only owner. 108*c8dee2aaSAndroid Build Coastguard Worker * Ensures that all previous owner's actions are complete. 109*c8dee2aaSAndroid Build Coastguard Worker */ unique()110*c8dee2aaSAndroid Build Coastguard Worker bool unique() const { 111*c8dee2aaSAndroid Build Coastguard Worker // The acquire barrier is only really needed if we return true. It 112*c8dee2aaSAndroid Build Coastguard Worker // prevents code conditioned on the result of unique() from running 113*c8dee2aaSAndroid Build Coastguard Worker // until previous owners are all totally done calling unref(). 114*c8dee2aaSAndroid Build Coastguard Worker return 1 == fRefCnt.load(std::memory_order_acquire); 115*c8dee2aaSAndroid Build Coastguard Worker } 116*c8dee2aaSAndroid Build Coastguard Worker 117*c8dee2aaSAndroid Build Coastguard Worker /** Increment the reference count. 118*c8dee2aaSAndroid Build Coastguard Worker Must be balanced by a call to unref() or unrefAndFreeResources(). 119*c8dee2aaSAndroid Build Coastguard Worker */ ref()120*c8dee2aaSAndroid Build Coastguard Worker void ref() const { 121*c8dee2aaSAndroid Build Coastguard Worker // No barrier required. 122*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(int newRefCount = )fRefCnt.fetch_add(+1, std::memory_order_relaxed); 123*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(newRefCount >= 1); 124*c8dee2aaSAndroid Build Coastguard Worker } 125*c8dee2aaSAndroid Build Coastguard Worker 126*c8dee2aaSAndroid Build Coastguard Worker /** Decrement the reference count. If the reference count is 1 before the 127*c8dee2aaSAndroid Build Coastguard Worker decrement, then delete the object. Note that if this is the case, then 128*c8dee2aaSAndroid Build Coastguard Worker the object needs to have been allocated via new, and not on the stack. 129*c8dee2aaSAndroid Build Coastguard Worker Any GPU data associated with this resource will be freed before it's deleted. 130*c8dee2aaSAndroid Build Coastguard Worker */ unref()131*c8dee2aaSAndroid Build Coastguard Worker void unref() const { 132*c8dee2aaSAndroid Build Coastguard Worker // A release here acts in place of all releases we "should" have been doing in ref(). 133*c8dee2aaSAndroid Build Coastguard Worker int newRefCount = fRefCnt.fetch_add(-1, std::memory_order_acq_rel); 134*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(newRefCount >= 0); 135*c8dee2aaSAndroid Build Coastguard Worker if (newRefCount == 1) { 136*c8dee2aaSAndroid Build Coastguard Worker // Like unique(), the acquire is only needed on success, to make sure 137*c8dee2aaSAndroid Build Coastguard Worker // code in internal_dispose() doesn't happen before the decrement. 138*c8dee2aaSAndroid Build Coastguard Worker this->internal_dispose(); 139*c8dee2aaSAndroid Build Coastguard Worker } 140*c8dee2aaSAndroid Build Coastguard Worker } 141*c8dee2aaSAndroid Build Coastguard Worker 142*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_DEBUG 143*c8dee2aaSAndroid Build Coastguard Worker // This is used for validating in the vulkan backend when using a main command buffer and temp 144*c8dee2aaSAndroid Build Coastguard Worker // command buffer at the same time. We need to validate that no images in the temp command 145*c8dee2aaSAndroid Build Coastguard Worker // buffer have been used in the main command buffer. asVkImageResource()146*c8dee2aaSAndroid Build Coastguard Worker virtual const GrManagedResource* asVkImageResource() const { return nullptr; } 147*c8dee2aaSAndroid Build Coastguard Worker #endif 148*c8dee2aaSAndroid Build Coastguard Worker 149*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_DEBUG validate()150*c8dee2aaSAndroid Build Coastguard Worker void validate() const { 151*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(this->getRefCnt() > 0); 152*c8dee2aaSAndroid Build Coastguard Worker } 153*c8dee2aaSAndroid Build Coastguard Worker #endif 154*c8dee2aaSAndroid Build Coastguard Worker 155*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_TRACE_MANAGED_RESOURCES 156*c8dee2aaSAndroid Build Coastguard Worker /** Output a human-readable dump of this resource's information 157*c8dee2aaSAndroid Build Coastguard Worker */ 158*c8dee2aaSAndroid Build Coastguard Worker virtual void dumpInfo() const = 0; 159*c8dee2aaSAndroid Build Coastguard Worker #endif 160*c8dee2aaSAndroid Build Coastguard Worker 161*c8dee2aaSAndroid Build Coastguard Worker private: 162*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_TRACE_MANAGED_RESOURCES GetTrace()163*c8dee2aaSAndroid Build Coastguard Worker static Trace* GetTrace() { 164*c8dee2aaSAndroid Build Coastguard Worker static Trace kTrace; 165*c8dee2aaSAndroid Build Coastguard Worker return &kTrace; 166*c8dee2aaSAndroid Build Coastguard Worker } 167*c8dee2aaSAndroid Build Coastguard Worker #endif 168*c8dee2aaSAndroid Build Coastguard Worker 169*c8dee2aaSAndroid Build Coastguard Worker /** Must be implemented by any subclasses. 170*c8dee2aaSAndroid Build Coastguard Worker * Deletes any GPU data associated with this resource 171*c8dee2aaSAndroid Build Coastguard Worker */ 172*c8dee2aaSAndroid Build Coastguard Worker virtual void freeGPUData() const = 0; 173*c8dee2aaSAndroid Build Coastguard Worker 174*c8dee2aaSAndroid Build Coastguard Worker /** 175*c8dee2aaSAndroid Build Coastguard Worker * Called when the ref count goes to 0. Will free GPU resources. 176*c8dee2aaSAndroid Build Coastguard Worker */ internal_dispose()177*c8dee2aaSAndroid Build Coastguard Worker void internal_dispose() const { 178*c8dee2aaSAndroid Build Coastguard Worker this->freeGPUData(); 179*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_TRACE_MANAGED_RESOURCES 180*c8dee2aaSAndroid Build Coastguard Worker GetTrace()->remove(this); 181*c8dee2aaSAndroid Build Coastguard Worker #endif 182*c8dee2aaSAndroid Build Coastguard Worker 183*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_DEBUG 184*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(0 == this->getRefCnt()); 185*c8dee2aaSAndroid Build Coastguard Worker fRefCnt.store(1); 186*c8dee2aaSAndroid Build Coastguard Worker #endif 187*c8dee2aaSAndroid Build Coastguard Worker delete this; 188*c8dee2aaSAndroid Build Coastguard Worker } 189*c8dee2aaSAndroid Build Coastguard Worker 190*c8dee2aaSAndroid Build Coastguard Worker mutable std::atomic<int32_t> fRefCnt; 191*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_TRACE_MANAGED_RESOURCES 192*c8dee2aaSAndroid Build Coastguard Worker uint32_t fKey; 193*c8dee2aaSAndroid Build Coastguard Worker #endif 194*c8dee2aaSAndroid Build Coastguard Worker 195*c8dee2aaSAndroid Build Coastguard Worker using INHERITED = SkNoncopyable; 196*c8dee2aaSAndroid Build Coastguard Worker }; 197*c8dee2aaSAndroid Build Coastguard Worker 198*c8dee2aaSAndroid Build Coastguard Worker // This subclass allows for recycling 199*c8dee2aaSAndroid Build Coastguard Worker class GrRecycledResource : public GrManagedResource { 200*c8dee2aaSAndroid Build Coastguard Worker public: 201*c8dee2aaSAndroid Build Coastguard Worker // When recycle is called and there is only one ref left on the resource, we will signal that 202*c8dee2aaSAndroid Build Coastguard Worker // the resource can be recycled for reuse. If the subclass (or whoever is managing this resource) 203*c8dee2aaSAndroid Build Coastguard Worker // decides not to recycle the objects, it is their responsibility to call unref on the object. recycle()204*c8dee2aaSAndroid Build Coastguard Worker void recycle() const { 205*c8dee2aaSAndroid Build Coastguard Worker if (this->unique()) { 206*c8dee2aaSAndroid Build Coastguard Worker this->onRecycle(); 207*c8dee2aaSAndroid Build Coastguard Worker } else { 208*c8dee2aaSAndroid Build Coastguard Worker this->unref(); 209*c8dee2aaSAndroid Build Coastguard Worker } 210*c8dee2aaSAndroid Build Coastguard Worker } 211*c8dee2aaSAndroid Build Coastguard Worker 212*c8dee2aaSAndroid Build Coastguard Worker private: 213*c8dee2aaSAndroid Build Coastguard Worker virtual void onRecycle() const = 0; 214*c8dee2aaSAndroid Build Coastguard Worker }; 215*c8dee2aaSAndroid Build Coastguard Worker 216*c8dee2aaSAndroid Build Coastguard Worker /** \class GrTextureResource 217*c8dee2aaSAndroid Build Coastguard Worker 218*c8dee2aaSAndroid Build Coastguard Worker GrTextureResource is the base class for managed texture resources, and implements the 219*c8dee2aaSAndroid Build Coastguard Worker basic releaseProc functionality for them. 220*c8dee2aaSAndroid Build Coastguard Worker 221*c8dee2aaSAndroid Build Coastguard Worker */ 222*c8dee2aaSAndroid Build Coastguard Worker class GrTextureResource : public GrManagedResource { 223*c8dee2aaSAndroid Build Coastguard Worker public: GrTextureResource()224*c8dee2aaSAndroid Build Coastguard Worker GrTextureResource() {} 225*c8dee2aaSAndroid Build Coastguard Worker ~GrTextureResource()226*c8dee2aaSAndroid Build Coastguard Worker ~GrTextureResource() override { 227*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!fReleaseHelper); 228*c8dee2aaSAndroid Build Coastguard Worker } 229*c8dee2aaSAndroid Build Coastguard Worker setRelease(sk_sp<GrSurface::RefCntedReleaseProc> releaseHelper)230*c8dee2aaSAndroid Build Coastguard Worker void setRelease(sk_sp<GrSurface::RefCntedReleaseProc> releaseHelper) { 231*c8dee2aaSAndroid Build Coastguard Worker fReleaseHelper = std::move(releaseHelper); 232*c8dee2aaSAndroid Build Coastguard Worker } 233*c8dee2aaSAndroid Build Coastguard Worker 234*c8dee2aaSAndroid Build Coastguard Worker protected: 235*c8dee2aaSAndroid Build Coastguard Worker mutable sk_sp<GrSurface::RefCntedReleaseProc> fReleaseHelper; 236*c8dee2aaSAndroid Build Coastguard Worker invokeReleaseProc()237*c8dee2aaSAndroid Build Coastguard Worker void invokeReleaseProc() const { 238*c8dee2aaSAndroid Build Coastguard Worker if (fReleaseHelper) { 239*c8dee2aaSAndroid Build Coastguard Worker // Depending on the ref count of fReleaseHelper this may or may not actually trigger 240*c8dee2aaSAndroid Build Coastguard Worker // the ReleaseProc to be called. 241*c8dee2aaSAndroid Build Coastguard Worker fReleaseHelper.reset(); 242*c8dee2aaSAndroid Build Coastguard Worker } 243*c8dee2aaSAndroid Build Coastguard Worker } 244*c8dee2aaSAndroid Build Coastguard Worker 245*c8dee2aaSAndroid Build Coastguard Worker private: 246*c8dee2aaSAndroid Build Coastguard Worker using INHERITED = GrManagedResource; 247*c8dee2aaSAndroid Build Coastguard Worker }; 248*c8dee2aaSAndroid Build Coastguard Worker 249*c8dee2aaSAndroid Build Coastguard Worker #endif 250