xref: /aosp_15_r20/external/angle/src/libANGLE/RefCountObject.h (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1 //
2 // Copyright 2002 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 
7 // RefCountObject.h: Defines the gl::RefCountObject base class that provides
8 // lifecycle support for GL objects using the traditional BindObject scheme, but
9 // that need to be reference counted for correct cross-context deletion.
10 // (Concretely, textures, buffers and renderbuffers.)
11 
12 #ifndef LIBANGLE_REFCOUNTOBJECT_H_
13 #define LIBANGLE_REFCOUNTOBJECT_H_
14 
15 #include "angle_gl.h"
16 #include "common/PackedEnums.h"
17 #include "common/debug.h"
18 #include "libANGLE/Error.h"
19 #include "libANGLE/Observer.h"
20 #include "libANGLE/renderer/serial_utils.h"
21 
22 #include <cstddef>
23 
24 namespace angle
25 {
26 
27 template <typename ContextT, typename ErrorT>
28 class RefCountObject : angle::NonCopyable
29 {
30   public:
31     using ContextType = ContextT;
32     using ErrorType   = ErrorT;
33 
RefCountObject()34     RefCountObject() : mRefCount(0) {}
35 
onDestroy(const ContextType * context)36     virtual void onDestroy(const ContextType *context) {}
37 
addRef()38     void addRef() const { ++mRefCount; }
39 
release(const ContextType * context)40     ANGLE_INLINE void release(const ContextType *context)
41     {
42         ASSERT(mRefCount > 0);
43         if (--mRefCount == 0)
44         {
45             onDestroy(context);
46             delete this;
47         }
48     }
49 
getRefCount()50     size_t getRefCount() const { return mRefCount; }
51 
52   protected:
~RefCountObject()53     virtual ~RefCountObject() { ASSERT(mRefCount == 0); }
54 
55     mutable size_t mRefCount;
56 };
57 
58 // Alternative base class to RefCountObject using atomics to track the reference count.
59 // Interchangable with RefCountObject for usage with BindingPointer and other wrappers.
60 template <typename ContextT, typename ErrorT>
61 class ThreadSafeRefCountObject : angle::NonCopyable
62 {
63   public:
64     using ContextType = ContextT;
65     using ErrorType   = ErrorT;
66 
ThreadSafeRefCountObject()67     ThreadSafeRefCountObject() : mRefCount(0) {}
68 
onDestroy(const ContextType * context)69     virtual void onDestroy(const ContextType *context) {}
70 
addRef()71     void addRef() const { mRefCount.fetch_add(1, std::memory_order_relaxed); }
72 
release(const ContextType * context)73     ANGLE_INLINE void release(const ContextType *context)
74     {
75         ASSERT(mRefCount > 0);
76         if (mRefCount.fetch_sub(1, std::memory_order_acq_rel) == 1)
77         {
78             onDestroy(context);
79             delete this;
80         }
81     }
82 
getRefCount()83     size_t getRefCount() const { return mRefCount; }
84 
85   protected:
~ThreadSafeRefCountObject()86     virtual ~ThreadSafeRefCountObject() { ASSERT(mRefCount == 0); }
87 
88     mutable std::atomic<size_t> mRefCount;
89 };
90 
91 template <class ObjectType, typename ContextT, typename ErrorT = angle::Result>
92 class RefCountObjectReleaser : angle::NonCopyable
93 {
94   public:
95     using ContextType = ContextT;
96     using ErrorType   = ErrorT;
97 
RefCountObjectReleaser()98     RefCountObjectReleaser() {}
RefCountObjectReleaser(const ContextType * context,ObjectType * object)99     RefCountObjectReleaser(const ContextType *context, ObjectType *object)
100         : mContext(context), mObject(object)
101     {}
102 
RefCountObjectReleaser(RefCountObjectReleaser && other)103     RefCountObjectReleaser(RefCountObjectReleaser &&other)
104         : mContext(other.mContext), mObject(other.mObject)
105     {
106         other.mContext = nullptr;
107         other.mObject  = nullptr;
108     }
109 
110     RefCountObjectReleaser &operator=(RefCountObjectReleaser &&other)
111     {
112         std::swap(mContext, other.mContext);
113         std::swap(mObject, other.mObject);
114         return *this;
115     }
116 
~RefCountObjectReleaser()117     ~RefCountObjectReleaser()
118     {
119         if (mObject)
120         {
121             mObject->release(mContext);
122             mObject = nullptr;
123         }
124     }
125 
126   private:
127     const ContextType *mContext = nullptr;
128     ObjectType *mObject         = nullptr;
129 };
130 
131 template <class ObjectType, typename ContextT, typename ErrorT = angle::Result>
132 class BindingPointer
133 {
134   public:
135     using ContextType = ContextT;
136     using ErrorType   = ErrorT;
137 
BindingPointer()138     BindingPointer() : mObject(nullptr) {}
139 
BindingPointer(ObjectType * object)140     BindingPointer(ObjectType *object) : mObject(object)
141     {
142         if (mObject)
143         {
144             mObject->addRef();
145         }
146     }
147 
BindingPointer(const BindingPointer & other)148     BindingPointer(const BindingPointer &other) : mObject(other.mObject)
149     {
150         if (mObject)
151         {
152             mObject->addRef();
153         }
154     }
155 
156     BindingPointer &operator=(BindingPointer &&other)
157     {
158         std::swap(mObject, other.mObject);
159         return *this;
160     }
161 
~BindingPointer()162     virtual ~BindingPointer()
163     {
164         // Objects have to be released before the resource manager is destroyed, so they must be
165         // explicitly cleaned up.
166         ASSERT(mObject == nullptr);
167     }
168 
set(const ContextType * context,ObjectType * newObject)169     RefCountObjectReleaser<ObjectType, ContextType, ErrorT> set(const ContextType *context,
170                                                                 ObjectType *newObject)
171     {
172         // addRef first in case newObject == mObject and this is the last reference to it.
173         if (newObject != nullptr)
174         {
175             newObject->addRef();
176         }
177 
178         // Store the old pointer in a temporary so we can set the pointer before calling release.
179         // Otherwise the object could still be referenced when its destructor is called.
180         ObjectType *oldObject = mObject;
181         mObject               = newObject;
182         return RefCountObjectReleaser<ObjectType, ContextType, ErrorT>(context, oldObject);
183     }
184 
assign(ObjectType * object)185     void assign(ObjectType *object) { mObject = object; }
186 
get()187     ObjectType *get() const { return mObject; }
188     ObjectType *operator->() const { return mObject; }
189 
190     bool operator==(const BindingPointer &other) const { return mObject == other.mObject; }
191 
192     bool operator!=(const BindingPointer &other) const { return !(*this == other); }
193 
194   protected:
setImpl(ObjectType * obj)195     ANGLE_INLINE void setImpl(ObjectType *obj) { mObject = obj; }
196 
197   private:
198     ObjectType *mObject;
199 };
200 }  // namespace angle
201 
202 namespace gl
203 {
204 class Context;
205 
206 template <class ObjectType>
207 class BindingPointer;
208 
209 using RefCountObjectNoID           = angle::RefCountObject<Context, angle::Result>;
210 using ThreadSafeRefCountObjectNoID = angle::ThreadSafeRefCountObject<Context, angle::Result>;
211 
212 template <typename IDType, typename RC = RefCountObjectNoID>
213 class RefCountObject : public RC
214 {
215   public:
RefCountObject(rx::UniqueSerial serial,IDType id)216     explicit RefCountObject(rx::UniqueSerial serial, IDType id) : mSerial(serial), mId(id) {}
217 
serial()218     rx::UniqueSerial serial() const { return mSerial; }
id()219     IDType id() const { return mId; }
220 
221   protected:
~RefCountObject()222     ~RefCountObject() override {}
223 
224   private:
225     // Unique serials are used to identify resources for frame capture.
226     rx::UniqueSerial mSerial;
227     IDType mId;
228 };
229 template <typename IDType>
230 using ThreadSafeRefCountObject = RefCountObject<IDType, ThreadSafeRefCountObjectNoID>;
231 
232 template <class ObjectType>
233 class BindingPointer : public angle::BindingPointer<ObjectType, Context>
234 {
235   public:
236     using ContextType = typename angle::BindingPointer<ObjectType, Context>::ContextType;
237     using ErrorType   = typename angle::BindingPointer<ObjectType, Context>::ErrorType;
238 
BindingPointer()239     BindingPointer() {}
240 
BindingPointer(ObjectType * object)241     BindingPointer(ObjectType *object) : angle::BindingPointer<ObjectType, Context>(object) {}
242 
id()243     typename ResourceTypeToID<ObjectType>::IDType id() const
244     {
245         ObjectType *obj = this->get();
246         if (obj)
247             return obj->id();
248         return {0};
249     }
250 };
251 
252 template <class ObjectType>
253 class OffsetBindingPointer : public BindingPointer<ObjectType>
254 {
255   public:
256     using ContextType = typename BindingPointer<ObjectType>::ContextType;
257     using ErrorType   = typename BindingPointer<ObjectType>::ErrorType;
258 
OffsetBindingPointer()259     OffsetBindingPointer() : mOffset(0), mSize(0) {}
260 
set(const ContextType * context,ObjectType * newObject,GLintptr offset,GLsizeiptr size)261     void set(const ContextType *context, ObjectType *newObject, GLintptr offset, GLsizeiptr size)
262     {
263         set(context, newObject);
264         updateOffsetAndSize(newObject, offset, size);
265     }
266 
getOffset()267     GLintptr getOffset() const { return mOffset; }
getSize()268     GLsizeiptr getSize() const { return mSize; }
269 
270     bool operator==(const OffsetBindingPointer<ObjectType> &other) const
271     {
272         return this->get() == other.get() && mOffset == other.mOffset && mSize == other.mSize;
273     }
274 
275     bool operator!=(const OffsetBindingPointer<ObjectType> &other) const
276     {
277         return !(*this == other);
278     }
279 
assign(ObjectType * newObject,GLintptr offset,GLsizeiptr size)280     void assign(ObjectType *newObject, GLintptr offset, GLsizeiptr size)
281     {
282         assign(newObject);
283         updateOffsetAndSize(newObject, offset, size);
284     }
285 
286   private:
updateOffsetAndSize(ObjectType * newObject,GLintptr offset,GLsizeiptr size)287     ANGLE_INLINE void updateOffsetAndSize(ObjectType *newObject, GLintptr offset, GLsizeiptr size)
288     {
289         if (newObject)
290         {
291             mOffset = offset;
292             mSize   = size;
293         }
294         else
295         {
296             mOffset = 0;
297             mSize   = 0;
298         }
299     }
300 
301     // Delete the unparameterized functions. This forces an explicit offset and size.
302     using BindingPointer<ObjectType>::set;
303     using BindingPointer<ObjectType>::assign;
304 
305     GLintptr mOffset;
306     GLsizeiptr mSize;
307 };
308 
309 template <typename SubjectT>
310 class SubjectBindingPointer : protected BindingPointer<SubjectT>, public angle::ObserverBindingBase
311 {
312   public:
SubjectBindingPointer(angle::ObserverInterface * observer,angle::SubjectIndex index)313     SubjectBindingPointer(angle::ObserverInterface *observer, angle::SubjectIndex index)
314         : ObserverBindingBase(observer, index)
315     {}
~SubjectBindingPointer()316     ~SubjectBindingPointer() override {}
317     SubjectBindingPointer(const SubjectBindingPointer &other)            = default;
318     SubjectBindingPointer &operator=(const SubjectBindingPointer &other) = default;
319 
bind(const Context * context,SubjectT * subject)320     void bind(const Context *context, SubjectT *subject)
321     {
322         // AddRef first in case subject == get()
323         if (subject)
324         {
325             subject->addObserver(this);
326             subject->addRef();
327         }
328 
329         if (get())
330         {
331             get()->removeObserver(this);
332             get()->release(context);
333         }
334 
335         this->setImpl(subject);
336     }
337 
338     using BindingPointer<SubjectT>::get;
339     using BindingPointer<SubjectT>::operator->;
340 
341     friend class State;
342 };
343 }  // namespace gl
344 
345 namespace egl
346 {
347 class Display;
348 
349 using RefCountObject           = angle::RefCountObject<Display, Error>;
350 using ThreadSafeRefCountObject = angle::ThreadSafeRefCountObject<Display, Error>;
351 
352 template <class ObjectType>
353 using RefCountObjectReleaser = angle::RefCountObjectReleaser<ObjectType, Display, Error>;
354 
355 template <class ObjectType>
356 using BindingPointer = angle::BindingPointer<ObjectType, Display, Error>;
357 
358 }  // namespace egl
359 
360 #endif  // LIBANGLE_REFCOUNTOBJECT_H_
361