/* * Copyright 2022 Google LLC * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef skgpu_Resource_DEFINED #define skgpu_Resource_DEFINED #include "experimental/graphite/src/ResourceTypes.h" #include "include/core/SkTypes.h" #include namespace skgpu { class Gpu; /** * Base class for objects that can be kept in the ResourceCache. */ class Resource { public: Resource(const Resource&) = delete; Resource(Resource&&) = delete; Resource& operator=(const Resource&) = delete; Resource& operator=(Resource&&) = delete; // Adds a usage ref to the resource. Named ref so we can easily manage usage refs with sk_sp. void ref() const { // Only the cache should be able to add the first usage ref to a resource. SkASSERT(this->hasUsageRef()); // No barrier required. (void)fUsageRefCnt.fetch_add(+1, std::memory_order_relaxed); } // Removes a usage ref from the resource void unref() const { SkASSERT(this->hasUsageRef()); // A release here acts in place of all releases we "should" have been doing in ref(). if (1 == fUsageRefCnt.fetch_add(-1, std::memory_order_acq_rel)) { this->notifyARefIsZero(LastRemovedRef::kUsageRef); } } // Adds a command buffer ref to the resource void refCommandBuffer() const { // No barrier required. (void)fCommandBufferRefCnt.fetch_add(+1, std::memory_order_relaxed); } // Removes a command buffer ref from the resource void unrefCommandBuffer() const { SkASSERT(this->hasCommandBufferRef()); // A release here acts in place of all releases we "should" have been doing in ref(). if (1 == fCommandBufferRefCnt.fetch_add(-1, std::memory_order_acq_rel)) { this->notifyARefIsZero(LastRemovedRef::kCommandBufferRef); } } /** * Tests whether a object has been abandoned or released. All objects will be in this state * after their creating Context is destroyed or abandoned. * * @return true if the object has been released or abandoned, * false otherwise. */ bool wasDestroyed() const { return fGpu == nullptr; } int* accessCacheIndex() const { return &fCacheArrayIndex; } uint32_t timestamp() const { return fTimestamp; } void setTimestamp(uint32_t ts) { fTimestamp = ts; } protected: Resource(const Gpu*); virtual ~Resource(); /** Overridden to free GPU resources in the backend API. */ virtual void onFreeGpuData() = 0; private: bool hasUsageRef() const { if (0 == fUsageRefCnt.load(std::memory_order_acquire)) { // The acquire barrier is only really needed if we return true. It // prevents code conditioned on the result of hasUsageRef() from running until previous // owners are all totally done calling unref(). return false; } return true; } bool hasCommandBufferRef() const { if (0 == fCommandBufferRefCnt.load(std::memory_order_acquire)) { // The acquire barrier is only really needed if we return true. It // prevents code conditioned on the result of hasCommandBufferRef() from running // until previous owners are all totally done calling unrefCommandBuffer(). return false; } return true; } // Privileged method that allows going from ref count = 0 to ref count = 1. void addInitialUsageRef() const { SkASSERT(!this->hasUsageRef()); // No barrier required. (void)fUsageRefCnt.fetch_add(+1, std::memory_order_relaxed); } void notifyARefIsZero(LastRemovedRef removedRef) const; /** * Frees the object in the underlying 3D API. */ void freeGpuData(); // This is not ref'ed but abandon() or release() will be called before the Gpu object is // destroyed. Those calls set will this to nullptr. const Gpu* fGpu; mutable std::atomic fUsageRefCnt; mutable std::atomic fCommandBufferRefCnt; // An index into a heap when this resource is purgeable or an array when not. This is maintained // by the cache. mutable int fCacheArrayIndex; // This value reflects how recently this resource was accessed in the cache. This is maintained // by the cache. uint32_t fTimestamp; }; } // namespace skgpu #endif // skgpu_Resource_DEFINED