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