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