1 /*
2 * Copyright 2020 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 GrRefCnt_DEFINED
9 #define GrRefCnt_DEFINED
10
11 #include "include/core/SkRefCnt.h"
12 #include "src/gpu/GrGpuResource.h"
13 #include "src/gpu/GrManagedResource.h"
14
15 // We have to use auto for the function pointers here because if the actual functions live on the
16 // base class of T we need the function here to be a pointer to a function of the base class and not
17 // a function on T. In C++17 RefBase and UnrefBase can be removed and the Ref and Unref paramenters
18 // can be "auto".
19 template <typename T,
20 typename RefBase = T,
21 typename UnrefBase = RefBase,
22 void (RefBase::*Ref)() const = RefBase::Ref,
23 void (UnrefBase::*Unref)() const = UnrefBase::Unref>
24 class gr_sp {
25 private:
SafeRef(T * obj)26 static inline T* SafeRef(T* obj) {
27 if (obj) {
28 (obj->*Ref)();
29 }
30 return obj;
31 }
32
SafeUnref(T * obj)33 static inline void SafeUnref(T* obj) {
34 if (obj) {
35 (obj->*Unref)();
36 }
37 }
38
39 public:
40 using element_type = T;
41
gr_sp()42 constexpr gr_sp() : fPtr(nullptr) {}
gr_sp(std::nullptr_t)43 constexpr gr_sp(std::nullptr_t) : fPtr(nullptr) {}
44
45 /**
46 * Shares the underlying object by calling Ref(), so that both the argument and the newly
47 * created gr_sp both have a reference to it.
48 */
gr_sp(const gr_sp & that)49 gr_sp(const gr_sp& that) : fPtr(SafeRef(that.get())) {}
50 template <typename U,
51 typename URefBase,
52 typename UUnrefBase,
53 typename = typename std::enable_if<std::is_convertible<U*, T*>::value>::type>
gr_sp(const gr_sp<U,URefBase,UUnrefBase,Ref,Unref> & that)54 gr_sp(const gr_sp<U, URefBase, UUnrefBase, Ref, Unref>& that) : fPtr(SafeRef(that.get())) {}
55
gr_sp(const sk_sp<T> & that)56 gr_sp(const sk_sp<T>& that) : fPtr(SafeRef(that.get())) {}
57
58
59 /**
60 * Move the underlying object from the argument to the newly created gr_sp. Afterwards only the
61 * new gr_sp will have a reference to the object, and the argument will point to null.
62 * No call to Ref() or Unref() will be made.
63 */
gr_sp(gr_sp && that)64 gr_sp(gr_sp&& that) : fPtr(that.release()) {}
65
66 /**
67 * Copies the underlying object pointer from the argument to the gr_sp. It will then call
68 * Ref() on the new object.
69 */
gr_sp(sk_sp<T> && that)70 gr_sp(sk_sp<T>&& that) : fPtr(SafeRef(that.get())) {}
71
72 /**
73 * Adopt the bare pointer into the newly created gr_sp.
74 * No call to Ref() or Unref() will be made.
75 */
gr_sp(T * obj)76 explicit gr_sp(T* obj) : fPtr(obj) {}
77
78 /**
79 * Calls Unref() on the underlying object pointer.
80 */
~gr_sp()81 ~gr_sp() {
82 SafeUnref(fPtr);
83 SkDEBUGCODE(fPtr = nullptr);
84 }
85
86 gr_sp& operator=(std::nullptr_t) {
87 this->reset();
88 return *this;
89 }
90
91 /**
92 * Shares the underlying object referenced by the argument by calling Ref() on it. If this gr_sp
93 * previously had a reference to an object (i.e. not null) it will call Unref() on that object.
94 */
95 gr_sp& operator=(const gr_sp& that) {
96 if (this != &that) {
97 this->reset(SafeRef(that.get()));
98 }
99 return *this;
100 }
101
102 /**
103 * Copies the underlying object pointer from the argument to the gr_sp. If the gr_sp previously
104 * held a reference to another object, Unref() will be called on that object. It will then call
105 * Ref() on the new object.
106 */
107 gr_sp& operator=(const sk_sp<T>& that) {
108 this->reset(SafeRef(that.get()));
109 return *this;
110 }
111
112 /**
113 * Move the underlying object from the argument to the gr_sp. If the gr_sp previously held
114 * a reference to another object, Unref() will be called on that object. No call to Ref() will
115 * be made.
116 */
117 gr_sp& operator=(gr_sp&& that) {
118 this->reset(that.release());
119 return *this;
120 }
121
122 /**
123 * Copies the underlying object pointer from the argument to the gr_sp. If the gr_sp previously
124 * held a reference to another object, Unref() will be called on that object. It will then call
125 * Ref() on the new object.
126 */
127 gr_sp& operator=(sk_sp<T>&& that) {
128 this->reset(SafeRef(that.get()));
129 return *this;
130 }
131
132 T& operator*() const {
133 SkASSERT(this->get() != nullptr);
134 return *this->get();
135 }
136
137 explicit operator bool() const { return this->get() != nullptr; }
138
get()139 T* get() const { return fPtr; }
140 T* operator->() const { return fPtr; }
141
142 /**
143 * Adopt the new bare pointer, and call Unref() on any previously held object (if not null).
144 * No call to Ref() will be made.
145 */
146 void reset(T* ptr = nullptr) {
147 T* oldPtr = fPtr;
148 fPtr = ptr;
149 SafeUnref(oldPtr);
150 }
151
152 private:
153 /**
154 * Return the bare pointer, and set the internal object pointer to nullptr.
155 * The caller must assume ownership of the object, and manage its reference count directly.
156 * No call to Unref() will be made.
157 */
release()158 T* SK_WARN_UNUSED_RESULT release() {
159 T* ptr = fPtr;
160 fPtr = nullptr;
161 return ptr;
162 }
163
164 T* fPtr;
165 };
166
167 ////////////////////////////////////////////////////////////////////////////////////////////////////
168
169 /**
170 * Shared pointer class to wrap classes that support a addCommandBufferUsage() and
171 * removeCommandBufferUsage() interface.
172 *
173 * This class supports copying, moving, and assigning an sk_sp into it. In general these commands do
174 * not modify the sk_sp at all but just call addCommandBufferUsage() on the underlying object.
175 *
176 * This class is designed to be used by GrGpuResources that need to track when they are in use on
177 * gpu (usually via a command buffer) separately from tracking if there are any current logical
178 * usages in Ganesh. This allows for a scratch GrGpuResource to be reused for new draw calls even
179 * if it is in use on the GPU.
180 */
181 template <typename T>
182 using gr_cb = gr_sp<T,
183 GrIORef<GrGpuResource>,
184 GrIORef<GrGpuResource>,
185 &T::addCommandBufferUsage,
186 &T::removeCommandBufferUsage>;
187
188 ////////////////////////////////////////////////////////////////////////////////////////////////////
189
190 /**
191 * This class mimics sk_sp but instead of calling unref it calls recycle instead.
192 */
193 template <typename T>
194 using gr_rp = gr_sp<T, GrManagedResource, GrRecycledResource, &T::ref, &T::recycle>;
195
196 /**
197 * Returns a gr_rp wrapping the provided ptr AND calls ref on it (if not null).
198 *
199 * This is different than the semantics of the constructor for gr_rp, which just wraps the ptr,
200 * effectively "adopting" it.
201 */
gr_ref_rp(T * obj)202 template <typename T> gr_rp<T> gr_ref_rp(T* obj) { return gr_rp<T>(SkSafeRef(obj)); }
203
gr_ref_rp(const T * obj)204 template <typename T> gr_rp<T> gr_ref_rp(const T* obj) {
205 return gr_rp<T>(const_cast<T*>(SkSafeRef(obj)));
206 }
207 #endif
208