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