• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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