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 | |
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 | |
58 | template <class ObjectType, typename ContextT, typename ErrorT = angle::Result> |
59 | class 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 | |
98 | template <class ObjectType, typename ContextT, typename ErrorT = angle::Result> |
99 | class 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 | |
169 | namespace gl |
170 | { |
171 | class Context; |
172 | |
173 | template <class ObjectType> |
174 | class BindingPointer; |
175 | |
176 | using RefCountObjectNoID = angle::RefCountObject<Context, angle::Result>; |
177 | |
178 | template <typename IDType> |
179 | class 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 | |
196 | template <class ObjectType> |
197 | class 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 | |
216 | template <class ObjectType> |
217 | class 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 | |
273 | template <typename SubjectT> |
274 | class 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 | |
309 | namespace egl |
310 | { |
311 | class Display; |
312 | |
313 | using RefCountObject = angle::RefCountObject<Display, Error>; |
314 | |
315 | template <class ObjectType> |
316 | using RefCountObjectReleaser = angle::RefCountObjectReleaser<ObjectType, Display, Error>; |
317 | |
318 | template <class ObjectType> |
319 | using BindingPointer = angle::BindingPointer<ObjectType, Display, Error>; |
320 | |
321 | } // namespace egl |
322 | |
323 | #endif // LIBANGLE_REFCOUNTOBJECT_H_ |
324 | |