blob: 83e82fb5b1ac908f7e564c1ff6421946e759eb0e [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"
12#include "SkTDynamicHash.h"
13#include "SkRandom.h"
14
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
34 possibly abandonSubResources().
35*/
36
37class GrVkResource : SkNoncopyable {
38public:
39 // Simple refCount tracing, to ensure that everything ref'ed is unref'ed.
40#ifdef SK_TRACE_VK_RESOURCES
41 static const uint32_t& GetKey(const GrVkResource& r) { return r.fKey; }
42 static uint32_t Hash(const uint32_t& k) { return k; }
jvanverthd5f6e9a2016-07-07 08:21:48 -070043
44 class Trace {
45 public:
46 ~Trace() {
47 if (fHash.count()) {
48 SkTDynamicHash<GrVkResource, uint32_t>::Iter iter(&fHash);
49 for (; !iter.done(); ++iter) {
50 (*iter).dumpInfo();
51 }
52 }
53 SkASSERT(0 == fHash.count());
54 }
55 void add(GrVkResource* r) { fHash.add(r); }
56 void remove(const GrVkResource* r) { fHash.remove(GetKey(*r)); }
57
58 private:
59 SkTDynamicHash<GrVkResource, uint32_t> fHash;
60 };
61 static Trace fTrace;
62
egdaniel50ead532016-07-13 14:23:26 -070063 static uint32_t fKeyCounter;
Greg Daniel164a9f02016-02-22 09:56:40 -050064#endif
65
66 /** Default construct, initializing the reference count to 1.
67 */
68 GrVkResource() : fRefCnt(1) {
69#ifdef SK_TRACE_VK_RESOURCES
egdaniel50ead532016-07-13 14:23:26 -070070 fKey = sk_atomic_fetch_add(&fKeyCounter, 1u, sk_memory_order_relaxed);
Greg Daniel164a9f02016-02-22 09:56:40 -050071 fTrace.add(this);
72#endif
73 }
74
75 /** Destruct, asserting that the reference count is 1.
76 */
77 virtual ~GrVkResource() {
78#ifdef SK_DEBUG
79 SkASSERTF(fRefCnt == 1, "fRefCnt was %d", fRefCnt);
80 fRefCnt = 0; // illegal value, to catch us if we reuse after delete
81#endif
82 }
83
84#ifdef SK_DEBUG
85 /** Return the reference count. Use only for debugging. */
86 int32_t getRefCnt() const { return fRefCnt; }
87#endif
88
89 /** May return true if the caller is the only owner.
90 * Ensures that all previous owner's actions are complete.
91 */
92 bool unique() const {
93 if (1 == sk_atomic_load(&fRefCnt, sk_memory_order_acquire)) {
94 // The acquire barrier is only really needed if we return true. It
95 // prevents code conditioned on the result of unique() from running
96 // until previous owners are all totally done calling unref().
97 return true;
98 }
99 return false;
100 }
101
halcanary9d524f22016-03-29 09:03:52 -0700102 /** Increment the reference count.
Greg Daniel164a9f02016-02-22 09:56:40 -0500103 Must be balanced by a call to unref() or unrefAndFreeResources().
104 */
105 void ref() const {
106 SkASSERT(fRefCnt > 0);
107 (void)sk_atomic_fetch_add(&fRefCnt, +1, sk_memory_order_relaxed); // No barrier required.
108 }
109
110 /** Decrement the reference count. If the reference count is 1 before the
111 decrement, then delete the object. Note that if this is the case, then
112 the object needs to have been allocated via new, and not on the stack.
113 Any GPU data associated with this resource will be freed before it's deleted.
114 */
115 void unref(const GrVkGpu* gpu) const {
116 SkASSERT(fRefCnt > 0);
117 SkASSERT(gpu);
118 // A release here acts in place of all releases we "should" have been doing in ref().
119 if (1 == sk_atomic_fetch_add(&fRefCnt, -1, sk_memory_order_acq_rel)) {
120 // Like unique(), the acquire is only needed on success, to make sure
121 // code in internal_dispose() doesn't happen before the decrement.
122 this->internal_dispose(gpu);
123 }
124 }
125
126 /** Unref without freeing GPU data. Used only when we're abandoning the resource */
127 void unrefAndAbandon() const {
128 SkASSERT(fRefCnt > 0);
129 // A release here acts in place of all releases we "should" have been doing in ref().
130 if (1 == sk_atomic_fetch_add(&fRefCnt, -1, sk_memory_order_acq_rel)) {
131 // Like unique(), the acquire is only needed on success, to make sure
132 // code in internal_dispose() doesn't happen before the decrement.
133 this->internal_dispose();
134 }
135 }
136
137#ifdef SK_DEBUG
138 void validate() const {
139 SkASSERT(fRefCnt > 0);
140 }
141#endif
142
jvanverth7ec92412016-07-06 09:24:57 -0700143#ifdef SK_TRACE_VK_RESOURCES
144 /** Output a human-readable dump of this resource's information
145 */
146 virtual void dumpInfo() const = 0;
147#endif
148
Greg Daniel164a9f02016-02-22 09:56:40 -0500149private:
halcanary9d524f22016-03-29 09:03:52 -0700150 /** Must be implemented by any subclasses.
151 * Deletes any Vk data associated with this resource
Greg Daniel164a9f02016-02-22 09:56:40 -0500152 */
153 virtual void freeGPUData(const GrVkGpu* gpu) const = 0;
154
halcanary9d524f22016-03-29 09:03:52 -0700155 /** Must be overridden by subclasses that themselves store GrVkResources.
156 * Will unrefAndAbandon those resources without deleting the underlying Vk data
Greg Daniel164a9f02016-02-22 09:56:40 -0500157 */
158 virtual void abandonSubResources() const {}
159
160 /**
161 * Called when the ref count goes to 0. Will free Vk resources.
162 */
163 void internal_dispose(const GrVkGpu* gpu) const {
164 this->freeGPUData(gpu);
165#ifdef SK_TRACE_VK_RESOURCES
jvanverthd5f6e9a2016-07-07 08:21:48 -0700166 fTrace.remove(this);
Greg Daniel164a9f02016-02-22 09:56:40 -0500167#endif
168 SkASSERT(0 == fRefCnt);
169 fRefCnt = 1;
170 delete this;
171 }
172
173 /**
174 * Internal_dispose without freeing Vk resources. Used when we've lost context.
175 */
176 void internal_dispose() const {
177 this->abandonSubResources();
178#ifdef SK_TRACE_VK_RESOURCES
jvanverthd5f6e9a2016-07-07 08:21:48 -0700179 fTrace.remove(this);
Greg Daniel164a9f02016-02-22 09:56:40 -0500180#endif
181 SkASSERT(0 == fRefCnt);
182 fRefCnt = 1;
183 delete this;
184 }
185
186 mutable int32_t fRefCnt;
187#ifdef SK_TRACE_VK_RESOURCES
188 uint32_t fKey;
189#endif
190
191 typedef SkNoncopyable INHERITED;
192};
193
194
195#endif