• 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         std::swap(mContext, other.mContext);
80         std::swap(mObject, other.mObject);
81         return *this;
82     }
83 
~RefCountObjectReleaser()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 
BindingPointer()105     BindingPointer() : mObject(nullptr) {}
106 
BindingPointer(ObjectType * object)107     BindingPointer(ObjectType *object) : mObject(object)
108     {
109         if (mObject)
110         {
111             mObject->addRef();
112         }
113     }
114 
BindingPointer(const BindingPointer & other)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 
~BindingPointer()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 
set(const ContextType * context,ObjectType * newObject)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 
assign(ObjectType * object)152     void assign(ObjectType *object) { mObject = object; }
153 
get()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:
setImpl(ObjectType * obj)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:
RefCountObject(rx::UniqueSerial serial,IDType id)182     explicit RefCountObject(rx::UniqueSerial serial, IDType id) : mSerial(serial), mId(id) {}
183 
serial()184     rx::UniqueSerial serial() const { return mSerial; }
id()185     IDType id() const { return mId; }
186 
187   protected:
~RefCountObject()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 
BindingPointer()203     BindingPointer() {}
204 
BindingPointer(ObjectType * object)205     BindingPointer(ObjectType *object) : angle::BindingPointer<ObjectType, Context>(object) {}
206 
id()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 
OffsetBindingPointer()223     OffsetBindingPointer() : mOffset(0), mSize(0) {}
224 
set(const ContextType * context,ObjectType * newObject,GLintptr offset,GLsizeiptr size)225     void set(const ContextType *context, ObjectType *newObject, GLintptr offset, GLsizeiptr size)
226     {
227         set(context, newObject);
228         updateOffsetAndSize(newObject, offset, size);
229     }
230 
getOffset()231     GLintptr getOffset() const { return mOffset; }
getSize()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 
assign(ObjectType * newObject,GLintptr offset,GLsizeiptr size)244     void assign(ObjectType *newObject, GLintptr offset, GLsizeiptr size)
245     {
246         assign(newObject);
247         updateOffsetAndSize(newObject, offset, size);
248     }
249 
250   private:
updateOffsetAndSize(ObjectType * newObject,GLintptr offset,GLsizeiptr size)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:
SubjectBindingPointer(angle::ObserverInterface * observer,angle::SubjectIndex index)277     SubjectBindingPointer(angle::ObserverInterface *observer, angle::SubjectIndex index)
278         : ObserverBindingBase(observer, index)
279     {}
~SubjectBindingPointer()280     ~SubjectBindingPointer() override {}
281     SubjectBindingPointer(const SubjectBindingPointer &other)            = default;
282     SubjectBindingPointer &operator=(const SubjectBindingPointer &other) = default;
283 
bind(const Context * context,SubjectT * subject)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