1*c8dee2aaSAndroid Build Coastguard Worker /* 2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2022 Google LLC 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 skgpu_graphite_Resource_DEFINED 9*c8dee2aaSAndroid Build Coastguard Worker #define skgpu_graphite_Resource_DEFINED 10*c8dee2aaSAndroid Build Coastguard Worker 11*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/GpuTypes.h" 12*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkMutex.h" 13*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/GpuTypesPriv.h" 14*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/GraphiteResourceKey.h" 15*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/graphite/ResourceTypes.h" 16*c8dee2aaSAndroid Build Coastguard Worker 17*c8dee2aaSAndroid Build Coastguard Worker #include <atomic> 18*c8dee2aaSAndroid Build Coastguard Worker #include <functional> 19*c8dee2aaSAndroid Build Coastguard Worker #include <string> 20*c8dee2aaSAndroid Build Coastguard Worker #include <string_view> 21*c8dee2aaSAndroid Build Coastguard Worker 22*c8dee2aaSAndroid Build Coastguard Worker class SkMutex; 23*c8dee2aaSAndroid Build Coastguard Worker class SkTraceMemoryDump; 24*c8dee2aaSAndroid Build Coastguard Worker 25*c8dee2aaSAndroid Build Coastguard Worker namespace skgpu::graphite { 26*c8dee2aaSAndroid Build Coastguard Worker 27*c8dee2aaSAndroid Build Coastguard Worker class ResourceCache; 28*c8dee2aaSAndroid Build Coastguard Worker class SharedContext; 29*c8dee2aaSAndroid Build Coastguard Worker class Texture; 30*c8dee2aaSAndroid Build Coastguard Worker 31*c8dee2aaSAndroid Build Coastguard Worker /** 32*c8dee2aaSAndroid Build Coastguard Worker * Base class for objects that can be kept in the ResourceCache. 33*c8dee2aaSAndroid Build Coastguard Worker */ 34*c8dee2aaSAndroid Build Coastguard Worker class Resource { 35*c8dee2aaSAndroid Build Coastguard Worker public: 36*c8dee2aaSAndroid Build Coastguard Worker Resource(const Resource&) = delete; 37*c8dee2aaSAndroid Build Coastguard Worker Resource(Resource&&) = delete; 38*c8dee2aaSAndroid Build Coastguard Worker Resource& operator=(const Resource&) = delete; 39*c8dee2aaSAndroid Build Coastguard Worker Resource& operator=(Resource&&) = delete; 40*c8dee2aaSAndroid Build Coastguard Worker 41*c8dee2aaSAndroid Build Coastguard Worker // Adds a usage ref to the resource. Named ref so we can easily manage usage refs with sk_sp. ref()42*c8dee2aaSAndroid Build Coastguard Worker void ref() const { 43*c8dee2aaSAndroid Build Coastguard Worker // Only the cache should be able to add the first usage ref to a resource. 44*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(this->hasUsageRef()); 45*c8dee2aaSAndroid Build Coastguard Worker // No barrier required. 46*c8dee2aaSAndroid Build Coastguard Worker (void)fUsageRefCnt.fetch_add(+1, std::memory_order_relaxed); 47*c8dee2aaSAndroid Build Coastguard Worker } 48*c8dee2aaSAndroid Build Coastguard Worker 49*c8dee2aaSAndroid Build Coastguard Worker // Removes a usage ref from the resource unref()50*c8dee2aaSAndroid Build Coastguard Worker void unref() const { 51*c8dee2aaSAndroid Build Coastguard Worker bool shouldFree = false; 52*c8dee2aaSAndroid Build Coastguard Worker { 53*c8dee2aaSAndroid Build Coastguard Worker SkAutoMutexExclusive locked(fUnrefMutex); 54*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(this->hasUsageRef()); 55*c8dee2aaSAndroid Build Coastguard Worker // A release here acts in place of all releases we "should" have been doing in ref(). 56*c8dee2aaSAndroid Build Coastguard Worker if (1 == fUsageRefCnt.fetch_add(-1, std::memory_order_acq_rel)) { 57*c8dee2aaSAndroid Build Coastguard Worker shouldFree = this->notifyARefIsZero(LastRemovedRef::kUsage); 58*c8dee2aaSAndroid Build Coastguard Worker } 59*c8dee2aaSAndroid Build Coastguard Worker } 60*c8dee2aaSAndroid Build Coastguard Worker if (shouldFree) { 61*c8dee2aaSAndroid Build Coastguard Worker Resource* mutableThis = const_cast<Resource*>(this); 62*c8dee2aaSAndroid Build Coastguard Worker mutableThis->internalDispose(); 63*c8dee2aaSAndroid Build Coastguard Worker } 64*c8dee2aaSAndroid Build Coastguard Worker } 65*c8dee2aaSAndroid Build Coastguard Worker 66*c8dee2aaSAndroid Build Coastguard Worker // Adds a command buffer ref to the resource refCommandBuffer()67*c8dee2aaSAndroid Build Coastguard Worker void refCommandBuffer() const { 68*c8dee2aaSAndroid Build Coastguard Worker if (fCommandBufferRefsAsUsageRefs) { 69*c8dee2aaSAndroid Build Coastguard Worker return this->ref(); 70*c8dee2aaSAndroid Build Coastguard Worker } 71*c8dee2aaSAndroid Build Coastguard Worker // No barrier required. 72*c8dee2aaSAndroid Build Coastguard Worker (void)fCommandBufferRefCnt.fetch_add(+1, std::memory_order_relaxed); 73*c8dee2aaSAndroid Build Coastguard Worker } 74*c8dee2aaSAndroid Build Coastguard Worker 75*c8dee2aaSAndroid Build Coastguard Worker // Removes a command buffer ref from the resource unrefCommandBuffer()76*c8dee2aaSAndroid Build Coastguard Worker void unrefCommandBuffer() const { 77*c8dee2aaSAndroid Build Coastguard Worker if (fCommandBufferRefsAsUsageRefs) { 78*c8dee2aaSAndroid Build Coastguard Worker return this->unref(); 79*c8dee2aaSAndroid Build Coastguard Worker } 80*c8dee2aaSAndroid Build Coastguard Worker bool shouldFree = false; 81*c8dee2aaSAndroid Build Coastguard Worker { 82*c8dee2aaSAndroid Build Coastguard Worker SkAutoMutexExclusive locked(fUnrefMutex); 83*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(this->hasCommandBufferRef()); 84*c8dee2aaSAndroid Build Coastguard Worker // A release here acts in place of all releases we "should" have been doing in ref(). 85*c8dee2aaSAndroid Build Coastguard Worker if (1 == fCommandBufferRefCnt.fetch_add(-1, std::memory_order_acq_rel)) { 86*c8dee2aaSAndroid Build Coastguard Worker shouldFree = this->notifyARefIsZero(LastRemovedRef::kCommandBuffer); 87*c8dee2aaSAndroid Build Coastguard Worker } 88*c8dee2aaSAndroid Build Coastguard Worker } 89*c8dee2aaSAndroid Build Coastguard Worker if (shouldFree) { 90*c8dee2aaSAndroid Build Coastguard Worker Resource* mutableThis = const_cast<Resource*>(this); 91*c8dee2aaSAndroid Build Coastguard Worker mutableThis->internalDispose(); 92*c8dee2aaSAndroid Build Coastguard Worker } 93*c8dee2aaSAndroid Build Coastguard Worker } 94*c8dee2aaSAndroid Build Coastguard Worker ownership()95*c8dee2aaSAndroid Build Coastguard Worker Ownership ownership() const { return fOwnership; } 96*c8dee2aaSAndroid Build Coastguard Worker budgeted()97*c8dee2aaSAndroid Build Coastguard Worker skgpu::Budgeted budgeted() const { return fBudgeted; } 98*c8dee2aaSAndroid Build Coastguard Worker 99*c8dee2aaSAndroid Build Coastguard Worker // Retrieves the amount of GPU memory used by this resource in bytes. It is approximate since we 100*c8dee2aaSAndroid Build Coastguard Worker // aren't aware of additional padding or copies made by the driver. gpuMemorySize()101*c8dee2aaSAndroid Build Coastguard Worker size_t gpuMemorySize() const { return fGpuMemorySize; } 102*c8dee2aaSAndroid Build Coastguard Worker 103*c8dee2aaSAndroid Build Coastguard Worker class UniqueID { 104*c8dee2aaSAndroid Build Coastguard Worker public: 105*c8dee2aaSAndroid Build Coastguard Worker UniqueID() = default; 106*c8dee2aaSAndroid Build Coastguard Worker UniqueID(uint32_t id)107*c8dee2aaSAndroid Build Coastguard Worker explicit UniqueID(uint32_t id) : fID(id) {} 108*c8dee2aaSAndroid Build Coastguard Worker asUInt()109*c8dee2aaSAndroid Build Coastguard Worker uint32_t asUInt() const { return fID; } 110*c8dee2aaSAndroid Build Coastguard Worker 111*c8dee2aaSAndroid Build Coastguard Worker bool operator==(const UniqueID& other) const { return fID == other.fID; } 112*c8dee2aaSAndroid Build Coastguard Worker bool operator!=(const UniqueID& other) const { return !(*this == other); } 113*c8dee2aaSAndroid Build Coastguard Worker 114*c8dee2aaSAndroid Build Coastguard Worker private: 115*c8dee2aaSAndroid Build Coastguard Worker uint32_t fID = SK_InvalidUniqueID; 116*c8dee2aaSAndroid Build Coastguard Worker }; 117*c8dee2aaSAndroid Build Coastguard Worker 118*c8dee2aaSAndroid Build Coastguard Worker // Gets an id that is unique for this Resource object. It is static in that it does not change 119*c8dee2aaSAndroid Build Coastguard Worker // when the content of the Resource object changes. This will never return 0. uniqueID()120*c8dee2aaSAndroid Build Coastguard Worker UniqueID uniqueID() const { return fUniqueID; } 121*c8dee2aaSAndroid Build Coastguard Worker 122*c8dee2aaSAndroid Build Coastguard Worker // Describes the type of gpu resource that is represented by the implementing 123*c8dee2aaSAndroid Build Coastguard Worker // class (e.g. texture, buffer, etc). This data is used for diagnostic 124*c8dee2aaSAndroid Build Coastguard Worker // purposes by dumpMemoryStatistics(). 125*c8dee2aaSAndroid Build Coastguard Worker // 126*c8dee2aaSAndroid Build Coastguard Worker // The value returned is expected to be long lived and will not be copied by the caller. 127*c8dee2aaSAndroid Build Coastguard Worker virtual const char* getResourceType() const = 0; 128*c8dee2aaSAndroid Build Coastguard Worker getLabel()129*c8dee2aaSAndroid Build Coastguard Worker std::string getLabel() const { return fLabel; } 130*c8dee2aaSAndroid Build Coastguard Worker 131*c8dee2aaSAndroid Build Coastguard Worker // We allow the label on a Resource to change when used for a different function. For example 132*c8dee2aaSAndroid Build Coastguard Worker // when reusing a scratch Texture we can change the label to match callers current use. setLabel(std::string_view label)133*c8dee2aaSAndroid Build Coastguard Worker void setLabel(std::string_view label) { 134*c8dee2aaSAndroid Build Coastguard Worker fLabel = label; 135*c8dee2aaSAndroid Build Coastguard Worker 136*c8dee2aaSAndroid Build Coastguard Worker if (!fLabel.empty()) { 137*c8dee2aaSAndroid Build Coastguard Worker const std::string fullLabel = "Skia_" + fLabel; 138*c8dee2aaSAndroid Build Coastguard Worker this->setBackendLabel(fullLabel.c_str()); 139*c8dee2aaSAndroid Build Coastguard Worker } 140*c8dee2aaSAndroid Build Coastguard Worker } 141*c8dee2aaSAndroid Build Coastguard Worker 142*c8dee2aaSAndroid Build Coastguard Worker // Tests whether a object has been abandoned or released. All objects will be in this state 143*c8dee2aaSAndroid Build Coastguard Worker // after their creating Context is destroyed or abandoned. 144*c8dee2aaSAndroid Build Coastguard Worker // 145*c8dee2aaSAndroid Build Coastguard Worker // @return true if the object has been released or abandoned, 146*c8dee2aaSAndroid Build Coastguard Worker // false otherwise. 147*c8dee2aaSAndroid Build Coastguard Worker // TODO: As of now this function isn't really needed because in freeGpuData we are always 148*c8dee2aaSAndroid Build Coastguard Worker // deleting this object. However, I want to implement all the purging logic first to make sure 149*c8dee2aaSAndroid Build Coastguard Worker // we don't have a use case for calling internalDispose but not wanting to delete the actual 150*c8dee2aaSAndroid Build Coastguard Worker // object yet. wasDestroyed()151*c8dee2aaSAndroid Build Coastguard Worker bool wasDestroyed() const { return fSharedContext == nullptr; } 152*c8dee2aaSAndroid Build Coastguard Worker key()153*c8dee2aaSAndroid Build Coastguard Worker const GraphiteResourceKey& key() const { return fKey; } 154*c8dee2aaSAndroid Build Coastguard Worker // This should only ever be called by the ResourceProvider setKey(const GraphiteResourceKey & key)155*c8dee2aaSAndroid Build Coastguard Worker void setKey(const GraphiteResourceKey& key) { 156*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(key.shareable() == Shareable::kNo || this->budgeted() == skgpu::Budgeted::kYes); 157*c8dee2aaSAndroid Build Coastguard Worker fKey = key; 158*c8dee2aaSAndroid Build Coastguard Worker } 159*c8dee2aaSAndroid Build Coastguard Worker 160*c8dee2aaSAndroid Build Coastguard Worker // Dumps memory usage information for this Resource to traceMemoryDump. 161*c8dee2aaSAndroid Build Coastguard Worker void dumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump) const; 162*c8dee2aaSAndroid Build Coastguard Worker 163*c8dee2aaSAndroid Build Coastguard Worker /** 164*c8dee2aaSAndroid Build Coastguard Worker * If the resource has a non-shareable key then this gives the resource subclass an opportunity 165*c8dee2aaSAndroid Build Coastguard Worker * to prepare itself to re-enter the cache. The ResourceCache extends its privilege to take the 166*c8dee2aaSAndroid Build Coastguard Worker * first UsageRef to this function via takeRef. If takeRef is called this resource will not 167*c8dee2aaSAndroid Build Coastguard Worker * immediately enter the cache but will be re-reprocessed with the Usage Ref count again reaches 168*c8dee2aaSAndroid Build Coastguard Worker * zero. 169*c8dee2aaSAndroid Build Coastguard Worker */ prepareForReturnToCache(const std::function<void ()> & takeRef)170*c8dee2aaSAndroid Build Coastguard Worker virtual void prepareForReturnToCache(const std::function<void()>& takeRef) {} 171*c8dee2aaSAndroid Build Coastguard Worker asTexture()172*c8dee2aaSAndroid Build Coastguard Worker virtual const Texture* asTexture() const { return nullptr; } 173*c8dee2aaSAndroid Build Coastguard Worker 174*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS) testingShouldDeleteASAP()175*c8dee2aaSAndroid Build Coastguard Worker bool testingShouldDeleteASAP() const { return fDeleteASAP == DeleteASAP::kYes; } 176*c8dee2aaSAndroid Build Coastguard Worker #endif 177*c8dee2aaSAndroid Build Coastguard Worker 178*c8dee2aaSAndroid Build Coastguard Worker protected: 179*c8dee2aaSAndroid Build Coastguard Worker Resource(const SharedContext*, 180*c8dee2aaSAndroid Build Coastguard Worker Ownership, 181*c8dee2aaSAndroid Build Coastguard Worker skgpu::Budgeted, 182*c8dee2aaSAndroid Build Coastguard Worker size_t gpuMemorySize, 183*c8dee2aaSAndroid Build Coastguard Worker bool commandBufferRefsAsUsageRefs = false); 184*c8dee2aaSAndroid Build Coastguard Worker virtual ~Resource(); 185*c8dee2aaSAndroid Build Coastguard Worker sharedContext()186*c8dee2aaSAndroid Build Coastguard Worker const SharedContext* sharedContext() const { return fSharedContext; } 187*c8dee2aaSAndroid Build Coastguard Worker 188*c8dee2aaSAndroid Build Coastguard Worker // Overridden to add extra information to the memory dump. onDumpMemoryStatistics(SkTraceMemoryDump * traceMemoryDump,const char * dumpName)189*c8dee2aaSAndroid Build Coastguard Worker virtual void onDumpMemoryStatistics(SkTraceMemoryDump* traceMemoryDump, 190*c8dee2aaSAndroid Build Coastguard Worker const char* dumpName) const {} 191*c8dee2aaSAndroid Build Coastguard Worker 192*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_DEBUG debugHasCommandBufferRef()193*c8dee2aaSAndroid Build Coastguard Worker bool debugHasCommandBufferRef() const { 194*c8dee2aaSAndroid Build Coastguard Worker return hasCommandBufferRef(); 195*c8dee2aaSAndroid Build Coastguard Worker } 196*c8dee2aaSAndroid Build Coastguard Worker #endif 197*c8dee2aaSAndroid Build Coastguard Worker 198*c8dee2aaSAndroid Build Coastguard Worker // Needed to be protected for DawnBuffer emscripten prepareForReturnToCache setDeleteASAP()199*c8dee2aaSAndroid Build Coastguard Worker void setDeleteASAP() { fDeleteASAP = DeleteASAP::kYes; } 200*c8dee2aaSAndroid Build Coastguard Worker 201*c8dee2aaSAndroid Build Coastguard Worker private: 202*c8dee2aaSAndroid Build Coastguard Worker friend class ProxyCache; // for setDeleteASAP and updateAccessTime 203*c8dee2aaSAndroid Build Coastguard Worker 204*c8dee2aaSAndroid Build Coastguard Worker // Overridden to free GPU resources in the backend API. 205*c8dee2aaSAndroid Build Coastguard Worker virtual void freeGpuData() = 0; 206*c8dee2aaSAndroid Build Coastguard Worker 207*c8dee2aaSAndroid Build Coastguard Worker // Overridden to call any release callbacks, if necessary invokeReleaseProc()208*c8dee2aaSAndroid Build Coastguard Worker virtual void invokeReleaseProc() {} 209*c8dee2aaSAndroid Build Coastguard Worker 210*c8dee2aaSAndroid Build Coastguard Worker enum class DeleteASAP : bool { 211*c8dee2aaSAndroid Build Coastguard Worker kNo = false, 212*c8dee2aaSAndroid Build Coastguard Worker kYes = true, 213*c8dee2aaSAndroid Build Coastguard Worker }; 214*c8dee2aaSAndroid Build Coastguard Worker shouldDeleteASAP()215*c8dee2aaSAndroid Build Coastguard Worker DeleteASAP shouldDeleteASAP() const { return fDeleteASAP; } 216*c8dee2aaSAndroid Build Coastguard Worker 217*c8dee2aaSAndroid Build Coastguard Worker // In the ResourceCache this is called whenever a Resource is moved into the purgeableQueue. It 218*c8dee2aaSAndroid Build Coastguard Worker // may also be called by the ProxyCache to track the time on Resources it is holding on to. updateAccessTime()219*c8dee2aaSAndroid Build Coastguard Worker void updateAccessTime() { 220*c8dee2aaSAndroid Build Coastguard Worker fLastAccess = skgpu::StdSteadyClock::now(); 221*c8dee2aaSAndroid Build Coastguard Worker } lastAccessTime()222*c8dee2aaSAndroid Build Coastguard Worker skgpu::StdSteadyClock::time_point lastAccessTime() const { 223*c8dee2aaSAndroid Build Coastguard Worker return fLastAccess; 224*c8dee2aaSAndroid Build Coastguard Worker } 225*c8dee2aaSAndroid Build Coastguard Worker setBackendLabel(char const * label)226*c8dee2aaSAndroid Build Coastguard Worker virtual void setBackendLabel(char const* label) {} 227*c8dee2aaSAndroid Build Coastguard Worker 228*c8dee2aaSAndroid Build Coastguard Worker //////////////////////////////////////////////////////////////////////////// 229*c8dee2aaSAndroid Build Coastguard Worker // The following set of functions are only meant to be called by the ResourceCache. We don't 230*c8dee2aaSAndroid Build Coastguard Worker // want them public general users of a Resource, but they also aren't purely internal calls. 231*c8dee2aaSAndroid Build Coastguard Worker //////////////////////////////////////////////////////////////////////////// 232*c8dee2aaSAndroid Build Coastguard Worker friend ResourceCache; 233*c8dee2aaSAndroid Build Coastguard Worker makeBudgeted()234*c8dee2aaSAndroid Build Coastguard Worker void makeBudgeted() { fBudgeted = skgpu::Budgeted::kYes; } makeUnbudgeted()235*c8dee2aaSAndroid Build Coastguard Worker void makeUnbudgeted() { fBudgeted = skgpu::Budgeted::kNo; } 236*c8dee2aaSAndroid Build Coastguard Worker 237*c8dee2aaSAndroid Build Coastguard Worker // This version of ref allows adding a ref when the usage count is 0. This should only be called 238*c8dee2aaSAndroid Build Coastguard Worker // from the ResourceCache. initialUsageRef()239*c8dee2aaSAndroid Build Coastguard Worker void initialUsageRef() const { 240*c8dee2aaSAndroid Build Coastguard Worker // Only the cache should be able to add the first usage ref to a resource. 241*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(fUsageRefCnt >= 0); 242*c8dee2aaSAndroid Build Coastguard Worker // No barrier required. 243*c8dee2aaSAndroid Build Coastguard Worker (void)fUsageRefCnt.fetch_add(+1, std::memory_order_relaxed); 244*c8dee2aaSAndroid Build Coastguard Worker } 245*c8dee2aaSAndroid Build Coastguard Worker 246*c8dee2aaSAndroid Build Coastguard Worker bool isPurgeable() const; accessReturnIndex()247*c8dee2aaSAndroid Build Coastguard Worker int* accessReturnIndex() const { return &fReturnIndex; } accessCacheIndex()248*c8dee2aaSAndroid Build Coastguard Worker int* accessCacheIndex() const { return &fCacheArrayIndex; } 249*c8dee2aaSAndroid Build Coastguard Worker timestamp()250*c8dee2aaSAndroid Build Coastguard Worker uint32_t timestamp() const { return fTimestamp; } setTimestamp(uint32_t ts)251*c8dee2aaSAndroid Build Coastguard Worker void setTimestamp(uint32_t ts) { fTimestamp = ts; } 252*c8dee2aaSAndroid Build Coastguard Worker 253*c8dee2aaSAndroid Build Coastguard Worker void registerWithCache(sk_sp<ResourceCache>); 254*c8dee2aaSAndroid Build Coastguard Worker 255*c8dee2aaSAndroid Build Coastguard Worker // Adds a cache ref to the resource. This is only called by ResourceCache. A Resource will only 256*c8dee2aaSAndroid Build Coastguard Worker // ever add a ref when the Resource is part of the cache (i.e. when insertResource is called) 257*c8dee2aaSAndroid Build Coastguard Worker // and while the Resource is in the ResourceCache::ReturnQueue. refCache()258*c8dee2aaSAndroid Build Coastguard Worker void refCache() const { 259*c8dee2aaSAndroid Build Coastguard Worker // No barrier required. 260*c8dee2aaSAndroid Build Coastguard Worker (void)fCacheRefCnt.fetch_add(+1, std::memory_order_relaxed); 261*c8dee2aaSAndroid Build Coastguard Worker } 262*c8dee2aaSAndroid Build Coastguard Worker 263*c8dee2aaSAndroid Build Coastguard Worker // Removes a cache ref from the resource. The unref here should only ever be called from the 264*c8dee2aaSAndroid Build Coastguard Worker // ResourceCache and only in the Recorder thread the ResourceCache is part of. unrefCache()265*c8dee2aaSAndroid Build Coastguard Worker void unrefCache() const { 266*c8dee2aaSAndroid Build Coastguard Worker bool shouldFree = false; 267*c8dee2aaSAndroid Build Coastguard Worker { 268*c8dee2aaSAndroid Build Coastguard Worker SkAutoMutexExclusive locked(fUnrefMutex); 269*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(this->hasCacheRef()); 270*c8dee2aaSAndroid Build Coastguard Worker // A release here acts in place of all releases we "should" have been doing in ref(). 271*c8dee2aaSAndroid Build Coastguard Worker if (1 == fCacheRefCnt.fetch_add(-1, std::memory_order_acq_rel)) { 272*c8dee2aaSAndroid Build Coastguard Worker shouldFree = this->notifyARefIsZero(LastRemovedRef::kCache); 273*c8dee2aaSAndroid Build Coastguard Worker } 274*c8dee2aaSAndroid Build Coastguard Worker } 275*c8dee2aaSAndroid Build Coastguard Worker if (shouldFree) { 276*c8dee2aaSAndroid Build Coastguard Worker Resource* mutableThis = const_cast<Resource*>(this); 277*c8dee2aaSAndroid Build Coastguard Worker mutableThis->internalDispose(); 278*c8dee2aaSAndroid Build Coastguard Worker } 279*c8dee2aaSAndroid Build Coastguard Worker } 280*c8dee2aaSAndroid Build Coastguard Worker 281*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_DEBUG isUsableAsScratch()282*c8dee2aaSAndroid Build Coastguard Worker bool isUsableAsScratch() const { 283*c8dee2aaSAndroid Build Coastguard Worker return fKey.shareable() == Shareable::kNo && !this->hasUsageRef() && fNonShareableInCache; 284*c8dee2aaSAndroid Build Coastguard Worker } 285*c8dee2aaSAndroid Build Coastguard Worker #endif 286*c8dee2aaSAndroid Build Coastguard Worker 287*c8dee2aaSAndroid Build Coastguard Worker //////////////////////////////////////////////////////////////////////////// 288*c8dee2aaSAndroid Build Coastguard Worker // The remaining calls are meant to be truely private 289*c8dee2aaSAndroid Build Coastguard Worker //////////////////////////////////////////////////////////////////////////// hasUsageRef()290*c8dee2aaSAndroid Build Coastguard Worker bool hasUsageRef() const { 291*c8dee2aaSAndroid Build Coastguard Worker if (0 == fUsageRefCnt.load(std::memory_order_acquire)) { 292*c8dee2aaSAndroid Build Coastguard Worker // The acquire barrier is only really needed if we return true. It 293*c8dee2aaSAndroid Build Coastguard Worker // prevents code conditioned on the result of hasUsageRef() from running until previous 294*c8dee2aaSAndroid Build Coastguard Worker // owners are all totally done calling unref(). 295*c8dee2aaSAndroid Build Coastguard Worker return false; 296*c8dee2aaSAndroid Build Coastguard Worker } 297*c8dee2aaSAndroid Build Coastguard Worker return true; 298*c8dee2aaSAndroid Build Coastguard Worker } 299*c8dee2aaSAndroid Build Coastguard Worker hasCommandBufferRef()300*c8dee2aaSAndroid Build Coastguard Worker bool hasCommandBufferRef() const { 301*c8dee2aaSAndroid Build Coastguard Worker // Note that we don't check here for fCommandBufferRefsAsUsageRefs. This should always 302*c8dee2aaSAndroid Build Coastguard Worker // report zero if that value is true. 303*c8dee2aaSAndroid Build Coastguard Worker if (0 == fCommandBufferRefCnt.load(std::memory_order_acquire)) { 304*c8dee2aaSAndroid Build Coastguard Worker // The acquire barrier is only really needed if we return true. It 305*c8dee2aaSAndroid Build Coastguard Worker // prevents code conditioned on the result of hasCommandBufferRef() from running 306*c8dee2aaSAndroid Build Coastguard Worker // until previous owners are all totally done calling unrefCommandBuffer(). 307*c8dee2aaSAndroid Build Coastguard Worker return false; 308*c8dee2aaSAndroid Build Coastguard Worker } 309*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(!fCommandBufferRefsAsUsageRefs); 310*c8dee2aaSAndroid Build Coastguard Worker return true; 311*c8dee2aaSAndroid Build Coastguard Worker } 312*c8dee2aaSAndroid Build Coastguard Worker hasCacheRef()313*c8dee2aaSAndroid Build Coastguard Worker bool hasCacheRef() const { 314*c8dee2aaSAndroid Build Coastguard Worker if (0 == fCacheRefCnt.load(std::memory_order_acquire)) { 315*c8dee2aaSAndroid Build Coastguard Worker // The acquire barrier is only really needed if we return true. It 316*c8dee2aaSAndroid Build Coastguard Worker // prevents code conditioned on the result of hasUsageRef() from running until previous 317*c8dee2aaSAndroid Build Coastguard Worker // owners are all totally done calling unref(). 318*c8dee2aaSAndroid Build Coastguard Worker return false; 319*c8dee2aaSAndroid Build Coastguard Worker } 320*c8dee2aaSAndroid Build Coastguard Worker return true; 321*c8dee2aaSAndroid Build Coastguard Worker } 322*c8dee2aaSAndroid Build Coastguard Worker hasAnyRefs()323*c8dee2aaSAndroid Build Coastguard Worker bool hasAnyRefs() const { 324*c8dee2aaSAndroid Build Coastguard Worker return this->hasUsageRef() || this->hasCommandBufferRef() || this->hasCacheRef(); 325*c8dee2aaSAndroid Build Coastguard Worker } 326*c8dee2aaSAndroid Build Coastguard Worker 327*c8dee2aaSAndroid Build Coastguard Worker bool notifyARefIsZero(LastRemovedRef removedRef) const; 328*c8dee2aaSAndroid Build Coastguard Worker 329*c8dee2aaSAndroid Build Coastguard Worker // Frees the object in the underlying 3D API. 330*c8dee2aaSAndroid Build Coastguard Worker void internalDispose(); 331*c8dee2aaSAndroid Build Coastguard Worker 332*c8dee2aaSAndroid Build Coastguard Worker // We need to guard calling unref on the usage and command buffer refs since they each could be 333*c8dee2aaSAndroid Build Coastguard Worker // unreffed on different threads. This can lead to calling notifyARefIsZero twice with each 334*c8dee2aaSAndroid Build Coastguard Worker // instance thinking there are no more refs left and both trying to delete the object. 335*c8dee2aaSAndroid Build Coastguard Worker mutable SkMutex fUnrefMutex; 336*c8dee2aaSAndroid Build Coastguard Worker 337*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(mutable bool fCalledRemovedFromCache = false;) 338*c8dee2aaSAndroid Build Coastguard Worker 339*c8dee2aaSAndroid Build Coastguard Worker // This is not ref'ed but internalDispose() will be called before the Gpu object is destroyed. 340*c8dee2aaSAndroid Build Coastguard Worker // That call will set this to nullptr. 341*c8dee2aaSAndroid Build Coastguard Worker const SharedContext* fSharedContext; 342*c8dee2aaSAndroid Build Coastguard Worker 343*c8dee2aaSAndroid Build Coastguard Worker mutable std::atomic<int32_t> fUsageRefCnt; 344*c8dee2aaSAndroid Build Coastguard Worker mutable std::atomic<int32_t> fCommandBufferRefCnt; 345*c8dee2aaSAndroid Build Coastguard Worker mutable std::atomic<int32_t> fCacheRefCnt; 346*c8dee2aaSAndroid Build Coastguard Worker // Indicates that CommandBufferRefs should be rerouted to UsageRefs. 347*c8dee2aaSAndroid Build Coastguard Worker const bool fCommandBufferRefsAsUsageRefs = false; 348*c8dee2aaSAndroid Build Coastguard Worker 349*c8dee2aaSAndroid Build Coastguard Worker GraphiteResourceKey fKey; 350*c8dee2aaSAndroid Build Coastguard Worker 351*c8dee2aaSAndroid Build Coastguard Worker sk_sp<ResourceCache> fReturnCache; 352*c8dee2aaSAndroid Build Coastguard Worker // An index into the return cache so we know whether or not the resource is already waiting to 353*c8dee2aaSAndroid Build Coastguard Worker // be returned or not. 354*c8dee2aaSAndroid Build Coastguard Worker mutable int fReturnIndex = -1; 355*c8dee2aaSAndroid Build Coastguard Worker 356*c8dee2aaSAndroid Build Coastguard Worker Ownership fOwnership; 357*c8dee2aaSAndroid Build Coastguard Worker 358*c8dee2aaSAndroid Build Coastguard Worker static const size_t kInvalidGpuMemorySize = ~static_cast<size_t>(0); 359*c8dee2aaSAndroid Build Coastguard Worker mutable size_t fGpuMemorySize = kInvalidGpuMemorySize; 360*c8dee2aaSAndroid Build Coastguard Worker 361*c8dee2aaSAndroid Build Coastguard Worker // All resource created internally by Graphite and held in the ResourceCache as a shared 362*c8dee2aaSAndroid Build Coastguard Worker // resource or available scratch resource are considered budgeted. Resources that back client 363*c8dee2aaSAndroid Build Coastguard Worker // owned objects (e.g. SkSurface or SkImage) are not budgeted and do not count against cache 364*c8dee2aaSAndroid Build Coastguard Worker // limits. 365*c8dee2aaSAndroid Build Coastguard Worker skgpu::Budgeted fBudgeted; 366*c8dee2aaSAndroid Build Coastguard Worker 367*c8dee2aaSAndroid Build Coastguard Worker // This is only used by ProxyCache::purgeProxiesNotUsedSince which is called from 368*c8dee2aaSAndroid Build Coastguard Worker // ResourceCache::purgeResourcesNotUsedSince. When kYes, this signals that the Resource 369*c8dee2aaSAndroid Build Coastguard Worker // should've been purged based on its timestamp at some point regardless of what its 370*c8dee2aaSAndroid Build Coastguard Worker // current timestamp may indicate (since the timestamp will be updated when the Resource 371*c8dee2aaSAndroid Build Coastguard Worker // is returned to the ResourceCache). 372*c8dee2aaSAndroid Build Coastguard Worker DeleteASAP fDeleteASAP = DeleteASAP::kNo; 373*c8dee2aaSAndroid Build Coastguard Worker 374*c8dee2aaSAndroid Build Coastguard Worker // An index into a heap when this resource is purgeable or an array when not. This is maintained 375*c8dee2aaSAndroid Build Coastguard Worker // by the cache. 376*c8dee2aaSAndroid Build Coastguard Worker mutable int fCacheArrayIndex = -1; 377*c8dee2aaSAndroid Build Coastguard Worker // This value reflects how recently this resource was accessed in the cache. This is maintained 378*c8dee2aaSAndroid Build Coastguard Worker // by the cache. 379*c8dee2aaSAndroid Build Coastguard Worker uint32_t fTimestamp; 380*c8dee2aaSAndroid Build Coastguard Worker skgpu::StdSteadyClock::time_point fLastAccess; 381*c8dee2aaSAndroid Build Coastguard Worker 382*c8dee2aaSAndroid Build Coastguard Worker const UniqueID fUniqueID; 383*c8dee2aaSAndroid Build Coastguard Worker 384*c8dee2aaSAndroid Build Coastguard Worker // String used to describe the current use of this Resource. 385*c8dee2aaSAndroid Build Coastguard Worker std::string fLabel; 386*c8dee2aaSAndroid Build Coastguard Worker 387*c8dee2aaSAndroid Build Coastguard Worker // This is only used during validation checking. Lots of the validation code depends on a 388*c8dee2aaSAndroid Build Coastguard Worker // resource being purgeable or not. However, purgeable itself just means having no refs. The 389*c8dee2aaSAndroid Build Coastguard Worker // refs can be removed before a Resource is returned to the cache (or even added to the 390*c8dee2aaSAndroid Build Coastguard Worker // ReturnQueue). 391*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGCODE(mutable bool fNonShareableInCache = false;) 392*c8dee2aaSAndroid Build Coastguard Worker }; 393*c8dee2aaSAndroid Build Coastguard Worker 394*c8dee2aaSAndroid Build Coastguard Worker } // namespace skgpu::graphite 395*c8dee2aaSAndroid Build Coastguard Worker 396*c8dee2aaSAndroid Build Coastguard Worker #endif // skgpu_graphite_Resource_DEFINED 397