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
24namespace angle
25{
26
27template <typename ContextT, typename ErrorT>
28class RefCountObject : angle::NonCopyable
29{
30 public:
31 using ContextType = ContextT;
32 using ErrorType = ErrorT;
33
34 RefCountObject() : mRefCount(0) {}
35
36 virtual void onDestroy(const ContextType *context) {}
37
38 void addRef() const { ++mRefCount; }
39
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
50 size_t getRefCount() const { return mRefCount; }
51
52 protected:
53 virtual ~RefCountObject() { ASSERT(mRefCount == 0); }
54
55 mutable size_t mRefCount;
56};
57
58template <class ObjectType, typename ContextT, typename ErrorT = angle::Result>
59class RefCountObjectReleaser : angle::NonCopyable
60{
61 public:
62 using ContextType = ContextT;
63 using ErrorType = ErrorT;
64
65 RefCountObjectReleaser() {}
66 RefCountObjectReleaser(const ContextType *context, ObjectType *object)
67 : mContext(context), mObject(object)
68 {}
69
70 RefCountObjectReleaser(RefCountObjectReleaser &&other)
71 : mContext(other.mContext), mObject(other.mObject)
72 {
73 other.mContext = nullptr;
74 other.mObject = nullptr;
75 }
76
77 RefCountObjectReleaser &operator=(RefCountObjectReleaser &&other)
78 {
79 std::swap(mContext, other.mContext);
80 std::swap(mObject, other.mObject);
81 return *this;
82 }
83
84 ~RefCountObjectReleaser()
85 {
86 if (mObject)
87 {
88 reinterpret_cast<RefCountObject<ContextType, ErrorType> *>(mObject)->release(mContext);
89 mObject = nullptr;
90 }
91 }
92
93 private:
94 const ContextType *mContext = nullptr;
95 ObjectType *mObject = nullptr;
96};
97
98template <class ObjectType, typename ContextT, typename ErrorT = angle::Result>
99class BindingPointer
100{
101 public:
102 using ContextType = ContextT;
103 using ErrorType = ErrorT;
104
105 BindingPointer() : mObject(nullptr) {}
106
107 BindingPointer(ObjectType *object) : mObject(object)
108 {
109 if (mObject)
110 {
111 mObject->addRef();
112 }
113 }
114
115 BindingPointer(const BindingPointer &other) : mObject(other.mObject)
116 {
117 if (mObject)
118 {
119 mObject->addRef();
120 }
121 }
122
123 BindingPointer &operator=(BindingPointer &&other)
124 {
125 std::swap(mObject, other.mObject);
126 return *this;
127 }
128
129 virtual ~BindingPointer()
130 {
131 // Objects have to be released before the resource manager is destroyed, so they must be
132 // explicitly cleaned up.
133 ASSERT(mObject == nullptr);
134 }
135
136 RefCountObjectReleaser<ObjectType, ContextType, ErrorT> set(const ContextType *context,
137 ObjectType *newObject)
138 {
139 // addRef first in case newObject == mObject and this is the last reference to it.
140 if (newObject != nullptr)
141 {
142 reinterpret_cast<RefCountObject<ContextType, ErrorType> *>(newObject)->addRef();
143 }
144
145 // Store the old pointer in a temporary so we can set the pointer before calling release.
146 // Otherwise the object could still be referenced when its destructor is called.
147 ObjectType *oldObject = mObject;
148 mObject = newObject;
149 return RefCountObjectReleaser<ObjectType, ContextType, ErrorT>(context, oldObject);
150 }
151
152 void assign(ObjectType *object) { mObject = object; }
153
154 ObjectType *get() const { return mObject; }
155 ObjectType *operator->() const { return mObject; }
156
157 bool operator==(const BindingPointer &other) const { return mObject == other.mObject; }
158
159 bool operator!=(const BindingPointer &other) const { return !(*this == other); }
160
161 protected:
162 ANGLE_INLINE void setImpl(ObjectType *obj) { mObject = obj; }
163
164 private:
165 ObjectType *mObject;
166};
167} // namespace angle
168
169namespace gl
170{
171class Context;
172
173template <class ObjectType>
174class BindingPointer;
175
176using RefCountObjectNoID = angle::RefCountObject<Context, angle::Result>;
177
178template <typename IDType>
179class RefCountObject : public gl::RefCountObjectNoID
180{
181 public:
182 explicit RefCountObject(rx::UniqueSerial serial, IDType id) : mSerial(serial), mId(id) {}
183
184 rx::UniqueSerial serial() const { return mSerial; }
185 IDType id() const { return mId; }
186
187 protected:
188 ~RefCountObject() override {}
189
190 private:
191 // Unique serials are used to identify resources for frame capture.
192 rx::UniqueSerial mSerial;
193 IDType mId;
194};
195
196template <class ObjectType>
197class BindingPointer : public angle::BindingPointer<ObjectType, Context>
198{
199 public:
200 using ContextType = typename angle::BindingPointer<ObjectType, Context>::ContextType;
201 using ErrorType = typename angle::BindingPointer<ObjectType, Context>::ErrorType;
202
203 BindingPointer() {}
204
205 BindingPointer(ObjectType *object) : angle::BindingPointer<ObjectType, Context>(object) {}
206
207 typename ResourceTypeToID<ObjectType>::IDType id() const
208 {
209 ObjectType *obj = this->get();
210 if (obj)
211 return obj->id();
212 return {0};
213 }
214};
215
216template <class ObjectType>
217class OffsetBindingPointer : public BindingPointer<ObjectType>
218{
219 public:
220 using ContextType = typename BindingPointer<ObjectType>::ContextType;
221 using ErrorType = typename BindingPointer<ObjectType>::ErrorType;
222
223 OffsetBindingPointer() : mOffset(0), mSize(0) {}
224
225 void set(const ContextType *context, ObjectType *newObject, GLintptr offset, GLsizeiptr size)
226 {
227 set(context, newObject);
228 updateOffsetAndSize(newObject, offset, size);
229 }
230
231 GLintptr getOffset() const { return mOffset; }
232 GLsizeiptr getSize() const { return mSize; }
233
234 bool operator==(const OffsetBindingPointer<ObjectType> &other) const
235 {
236 return this->get() == other.get() && mOffset == other.mOffset && mSize == other.mSize;
237 }
238
239 bool operator!=(const OffsetBindingPointer<ObjectType> &other) const
240 {
241 return !(*this == other);
242 }
243
244 void assign(ObjectType *newObject, GLintptr offset, GLsizeiptr size)
245 {
246 assign(newObject);
247 updateOffsetAndSize(newObject, offset, size);
248 }
249
250 private:
251 ANGLE_INLINE void updateOffsetAndSize(ObjectType *newObject, GLintptr offset, GLsizeiptr size)
252 {
253 if (newObject)
254 {
255 mOffset = offset;
256 mSize = size;
257 }
258 else
259 {
260 mOffset = 0;
261 mSize = 0;
262 }
263 }
264
265 // Delete the unparameterized functions. This forces an explicit offset and size.
266 using BindingPointer<ObjectType>::set;
267 using BindingPointer<ObjectType>::assign;
268
269 GLintptr mOffset;
270 GLsizeiptr mSize;
271};
272
273template <typename SubjectT>
274class SubjectBindingPointer : protected BindingPointer<SubjectT>, public angle::ObserverBindingBase
275{
276 public:
277 SubjectBindingPointer(angle::ObserverInterface *observer, angle::SubjectIndex index)
278 : ObserverBindingBase(observer, index)
279 {}
280 ~SubjectBindingPointer() override {}
281 SubjectBindingPointer(const SubjectBindingPointer &other) = default;
282 SubjectBindingPointer &operator=(const SubjectBindingPointer &other) = default;
283
284 void bind(const Context *context, SubjectT *subject)
285 {
286 // AddRef first in case subject == get()
287 if (subject)
288 {
289 subject->addObserver(this);
290 subject->addRef();
291 }
292
293 if (get())
294 {
295 get()->removeObserver(this);
296 get()->release(context);
297 }
298
299 this->setImpl(subject);
300 }
301
302 using BindingPointer<SubjectT>::get;
303 using BindingPointer<SubjectT>::operator->;
304
305 friend class State;
306};
307} // namespace gl
308
309namespace egl
310{
311class Display;
312
313using RefCountObject = angle::RefCountObject<Display, Error>;
314
315template <class ObjectType>
316using RefCountObjectReleaser = angle::RefCountObjectReleaser<ObjectType, Display, Error>;
317
318template <class ObjectType>
319using BindingPointer = angle::BindingPointer<ObjectType, Display, Error>;
320
321} // namespace egl
322
323#endif // LIBANGLE_REFCOUNTOBJECT_H_
324

source code of flutter_engine/third_party/angle/src/libANGLE/RefCountObject.h