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