blob: 9ddde474c1548f3e63c1bc892155c0eeac8bc680 [file] [log] [blame]
Greg Daniel164a9f02016-02-22 09:56:40 -05001/*
2 * Copyright 2015 Google Inc.
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 GrVkResource_DEFINED
9#define GrVkResource_DEFINED
10
11#include "SkAtomics.h"
Greg Daniel164a9f02016-02-22 09:56:40 -050012#include "SkRandom.h"
egdaniel00db3fd2016-07-29 08:55:53 -070013#include "SkTHash.h"
Greg Daniel164a9f02016-02-22 09:56:40 -050014
15class GrVkGpu;
16
17// uncomment to enable tracing of resource refs
jvanverth7ec92412016-07-06 09:24:57 -070018#ifdef SK_DEBUG
19#define SK_TRACE_VK_RESOURCES
20#endif
Greg Daniel164a9f02016-02-22 09:56:40 -050021
22/** \class GrVkResource
23
24 GrVkResource is the base class for Vulkan resources that may be shared by multiple
25 objects. When an existing owner wants to share a reference, it calls ref().
26 When an owner wants to release its reference, it calls unref(). When the
27 shared object's reference count goes to zero as the result of an unref()
28 call, its (virtual) destructor is called. It is an error for the
29 destructor to be called explicitly (or via the object going out of scope on
30 the stack or calling delete) if getRefCnt() > 1.
31
32 This is nearly identical to SkRefCntBase. The exceptions are that unref()
33 takes a GrVkGpu, and any derived classes must implement freeGPUData() and
Greg Danielcef213c2017-04-21 11:52:27 -040034 possibly abandonGPUData().
Greg Daniel164a9f02016-02-22 09:56:40 -050035*/
36
37class GrVkResource : SkNoncopyable {
38public:
39 // Simple refCount tracing, to ensure that everything ref'ed is unref'ed.
40#ifdef SK_TRACE_VK_RESOURCES
egdaniel00db3fd2016-07-29 08:55:53 -070041 struct Hash {
42 uint32_t operator()(const GrVkResource* const& r) const {
43 SkASSERT(r);
44 return r->fKey;
45 }
46 };
jvanverthd5f6e9a2016-07-07 08:21:48 -070047
48 class Trace {
49 public:
50 ~Trace() {
egdaniel00db3fd2016-07-29 08:55:53 -070051 fHashSet.foreach([](const GrVkResource* r) {
52 r->dumpInfo();
53 });
54 SkASSERT(0 == fHashSet.count());
jvanverthd5f6e9a2016-07-07 08:21:48 -070055 }
egdaniel00db3fd2016-07-29 08:55:53 -070056 void add(const GrVkResource* r) { fHashSet.add(r); }
57 void remove(const GrVkResource* r) { fHashSet.remove(r); }
jvanverthd5f6e9a2016-07-07 08:21:48 -070058
59 private:
egdaniel00db3fd2016-07-29 08:55:53 -070060 SkTHashSet<const GrVkResource*, GrVkResource::Hash> fHashSet;
jvanverthd5f6e9a2016-07-07 08:21:48 -070061 };
62 static Trace fTrace;
63
egdaniel50ead532016-07-13 14:23:26 -070064 static uint32_t fKeyCounter;
Greg Daniel164a9f02016-02-22 09:56:40 -050065#endif
66
67 /** Default construct, initializing the reference count to 1.
68 */
69 GrVkResource() : fRefCnt(1) {
70#ifdef SK_TRACE_VK_RESOURCES
egdaniel50ead532016-07-13 14:23:26 -070071 fKey = sk_atomic_fetch_add(&fKeyCounter, 1u, sk_memory_order_relaxed);
Greg Daniel164a9f02016-02-22 09:56:40 -050072 fTrace.add(this);
73#endif
74 }
75
76 /** Destruct, asserting that the reference count is 1.
77 */
78 virtual ~GrVkResource() {
79#ifdef SK_DEBUG
80 SkASSERTF(fRefCnt == 1, "fRefCnt was %d", fRefCnt);
81 fRefCnt = 0; // illegal value, to catch us if we reuse after delete
82#endif
83 }
84
85#ifdef SK_DEBUG
86 /** Return the reference count. Use only for debugging. */
87 int32_t getRefCnt() const { return fRefCnt; }
88#endif
89
90 /** May return true if the caller is the only owner.
91 * Ensures that all previous owner's actions are complete.
92 */
93 bool unique() const {
94 if (1 == sk_atomic_load(&fRefCnt, sk_memory_order_acquire)) {
95 // The acquire barrier is only really needed if we return true. It
96 // prevents code conditioned on the result of unique() from running
97 // until previous owners are all totally done calling unref().
98 return true;
99 }
100 return false;
101 }
102
halcanary9d524f22016-03-29 09:03:52 -0700103 /** Increment the reference count.
Greg Daniel164a9f02016-02-22 09:56:40 -0500104 Must be balanced by a call to unref() or unrefAndFreeResources().
105 */
106 void ref() const {
107 SkASSERT(fRefCnt > 0);
108 (void)sk_atomic_fetch_add(&fRefCnt, +1, sk_memory_order_relaxed); // No barrier required.
109 }
110
111 /** Decrement the reference count. If the reference count is 1 before the
112 decrement, then delete the object. Note that if this is the case, then
113 the object needs to have been allocated via new, and not on the stack.
114 Any GPU data associated with this resource will be freed before it's deleted.
115 */
116 void unref(const GrVkGpu* gpu) const {
117 SkASSERT(fRefCnt > 0);
118 SkASSERT(gpu);
119 // A release here acts in place of all releases we "should" have been doing in ref().
120 if (1 == sk_atomic_fetch_add(&fRefCnt, -1, sk_memory_order_acq_rel)) {
121 // Like unique(), the acquire is only needed on success, to make sure
122 // code in internal_dispose() doesn't happen before the decrement.
123 this->internal_dispose(gpu);
124 }
125 }
126
127 /** Unref without freeing GPU data. Used only when we're abandoning the resource */
128 void unrefAndAbandon() const {
129 SkASSERT(fRefCnt > 0);
130 // A release here acts in place of all releases we "should" have been doing in ref().
131 if (1 == sk_atomic_fetch_add(&fRefCnt, -1, sk_memory_order_acq_rel)) {
132 // Like unique(), the acquire is only needed on success, to make sure
133 // code in internal_dispose() doesn't happen before the decrement.
134 this->internal_dispose();
135 }
136 }
137
138#ifdef SK_DEBUG
139 void validate() const {
140 SkASSERT(fRefCnt > 0);
141 }
142#endif
143
jvanverth7ec92412016-07-06 09:24:57 -0700144#ifdef SK_TRACE_VK_RESOURCES
145 /** Output a human-readable dump of this resource's information
146 */
147 virtual void dumpInfo() const = 0;
148#endif
149
Greg Daniel164a9f02016-02-22 09:56:40 -0500150private:
halcanary9d524f22016-03-29 09:03:52 -0700151 /** Must be implemented by any subclasses.
152 * Deletes any Vk data associated with this resource
Greg Daniel164a9f02016-02-22 09:56:40 -0500153 */
154 virtual void freeGPUData(const GrVkGpu* gpu) const = 0;
155
Greg Danielcef213c2017-04-21 11:52:27 -0400156 /**
157 * Called from unrefAndAbandon. Resources should do any necessary cleanup without freeing
158 * underlying Vk objects. This must be overridden by subclasses that themselves store
159 * GrVkResources since those resource will need to be unrefed.
Greg Daniel164a9f02016-02-22 09:56:40 -0500160 */
Greg Danielcef213c2017-04-21 11:52:27 -0400161 virtual void abandonGPUData() const {}
Greg Daniel164a9f02016-02-22 09:56:40 -0500162
163 /**
164 * Called when the ref count goes to 0. Will free Vk resources.
165 */
166 void internal_dispose(const GrVkGpu* gpu) const {
167 this->freeGPUData(gpu);
168#ifdef SK_TRACE_VK_RESOURCES
jvanverthd5f6e9a2016-07-07 08:21:48 -0700169 fTrace.remove(this);
Greg Daniel164a9f02016-02-22 09:56:40 -0500170#endif
171 SkASSERT(0 == fRefCnt);
172 fRefCnt = 1;
173 delete this;
174 }
175
176 /**
177 * Internal_dispose without freeing Vk resources. Used when we've lost context.
178 */
179 void internal_dispose() const {
Greg Danielcef213c2017-04-21 11:52:27 -0400180 this->abandonGPUData();
Greg Daniel164a9f02016-02-22 09:56:40 -0500181#ifdef SK_TRACE_VK_RESOURCES
jvanverthd5f6e9a2016-07-07 08:21:48 -0700182 fTrace.remove(this);
Greg Daniel164a9f02016-02-22 09:56:40 -0500183#endif
184 SkASSERT(0 == fRefCnt);
185 fRefCnt = 1;
186 delete this;
187 }
188
189 mutable int32_t fRefCnt;
190#ifdef SK_TRACE_VK_RESOURCES
191 uint32_t fKey;
192#endif
193
194 typedef SkNoncopyable INHERITED;
195};
196
egdanielc1be9bc2016-07-20 08:33:00 -0700197// This subclass allows for recycling
198class GrVkRecycledResource : public GrVkResource {
199public:
200 // When recycle is called and there is only one ref left on the resource, we will signal that
egdaniela95220d2016-07-21 11:50:37 -0700201 // the resource can be recycled for reuse. If the sublass (or whoever is managing this resource)
202 // decides not to recycle the objects, it is their responsibility to call unref on the object.
egdanielc1be9bc2016-07-20 08:33:00 -0700203 void recycle(GrVkGpu* gpu) const {
204 if (this->unique()) {
205 this->onRecycle(gpu);
egdaniela95220d2016-07-21 11:50:37 -0700206 } else {
207 this->unref(gpu);
egdanielc1be9bc2016-07-20 08:33:00 -0700208 }
egdanielc1be9bc2016-07-20 08:33:00 -0700209 }
210
211private:
212 virtual void onRecycle(GrVkGpu* gpu) const = 0;
213};
Greg Daniel164a9f02016-02-22 09:56:40 -0500214
215#endif