1 /* 2 * Copyright 2022 Google LLC 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 skgpu_Resource_DEFINED 9 #define skgpu_Resource_DEFINED 10 11 #include "experimental/graphite/src/ResourceTypes.h" 12 #include "include/core/SkTypes.h" 13 14 #include <atomic> 15 16 namespace skgpu { 17 18 class Gpu; 19 20 /** 21 * Base class for objects that can be kept in the ResourceCache. 22 */ 23 class Resource { 24 public: 25 Resource(const Resource&) = delete; 26 Resource(Resource&&) = delete; 27 Resource& operator=(const Resource&) = delete; 28 Resource& operator=(Resource&&) = delete; 29 30 // Adds a usage ref to the resource. Named ref so we can easily manage usage refs with sk_sp. ref()31 void ref() const { 32 // Only the cache should be able to add the first usage ref to a resource. 33 SkASSERT(this->hasUsageRef()); 34 // No barrier required. 35 (void)fUsageRefCnt.fetch_add(+1, std::memory_order_relaxed); 36 } 37 38 // Removes a usage ref from the resource unref()39 void unref() const { 40 SkASSERT(this->hasUsageRef()); 41 // A release here acts in place of all releases we "should" have been doing in ref(). 42 if (1 == fUsageRefCnt.fetch_add(-1, std::memory_order_acq_rel)) { 43 this->notifyARefIsZero(LastRemovedRef::kUsageRef); 44 } 45 } 46 47 // Adds a command buffer ref to the resource refCommandBuffer()48 void refCommandBuffer() const { 49 // No barrier required. 50 (void)fCommandBufferRefCnt.fetch_add(+1, std::memory_order_relaxed); 51 } 52 53 // Removes a command buffer ref from the resource unrefCommandBuffer()54 void unrefCommandBuffer() const { 55 SkASSERT(this->hasCommandBufferRef()); 56 // A release here acts in place of all releases we "should" have been doing in ref(). 57 if (1 == fCommandBufferRefCnt.fetch_add(-1, std::memory_order_acq_rel)) { 58 this->notifyARefIsZero(LastRemovedRef::kCommandBufferRef); 59 } 60 } 61 62 /** 63 * Tests whether a object has been abandoned or released. All objects will be in this state 64 * after their creating Context is destroyed or abandoned. 65 * 66 * @return true if the object has been released or abandoned, 67 * false otherwise. 68 */ wasDestroyed()69 bool wasDestroyed() const { return fGpu == nullptr; } 70 accessCacheIndex()71 int* accessCacheIndex() const { return &fCacheArrayIndex; } 72 timestamp()73 uint32_t timestamp() const { return fTimestamp; } setTimestamp(uint32_t ts)74 void setTimestamp(uint32_t ts) { fTimestamp = ts; } 75 76 protected: 77 Resource(const Gpu*); 78 virtual ~Resource(); 79 80 /** Overridden to free GPU resources in the backend API. */ 81 virtual void onFreeGpuData() = 0; 82 83 private: hasUsageRef()84 bool hasUsageRef() const { 85 if (0 == fUsageRefCnt.load(std::memory_order_acquire)) { 86 // The acquire barrier is only really needed if we return true. It 87 // prevents code conditioned on the result of hasUsageRef() from running until previous 88 // owners are all totally done calling unref(). 89 return false; 90 } 91 return true; 92 } 93 hasCommandBufferRef()94 bool hasCommandBufferRef() const { 95 if (0 == fCommandBufferRefCnt.load(std::memory_order_acquire)) { 96 // The acquire barrier is only really needed if we return true. It 97 // prevents code conditioned on the result of hasCommandBufferRef() from running 98 // until previous owners are all totally done calling unrefCommandBuffer(). 99 return false; 100 } 101 return true; 102 } 103 104 // Privileged method that allows going from ref count = 0 to ref count = 1. addInitialUsageRef()105 void addInitialUsageRef() const { 106 SkASSERT(!this->hasUsageRef()); 107 // No barrier required. 108 (void)fUsageRefCnt.fetch_add(+1, std::memory_order_relaxed); 109 } 110 111 void notifyARefIsZero(LastRemovedRef removedRef) const; 112 113 /** 114 * Frees the object in the underlying 3D API. 115 */ 116 void freeGpuData(); 117 118 // This is not ref'ed but abandon() or release() will be called before the Gpu object is 119 // destroyed. Those calls set will this to nullptr. 120 const Gpu* fGpu; 121 122 mutable std::atomic<int32_t> fUsageRefCnt; 123 mutable std::atomic<int32_t> fCommandBufferRefCnt; 124 125 // An index into a heap when this resource is purgeable or an array when not. This is maintained 126 // by the cache. 127 mutable int fCacheArrayIndex; 128 // This value reflects how recently this resource was accessed in the cache. This is maintained 129 // by the cache. 130 uint32_t fTimestamp; 131 }; 132 133 } // namespace skgpu 134 135 #endif // skgpu_Resource_DEFINED 136 137