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