• 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/debug.h"
17 #include "libANGLE/Error.h"
18 #include "libANGLE/Observer.h"
19 
20 #include <cstddef>
21 
22 namespace angle
23 {
24 
25 template <typename ContextT, typename ErrorT>
26 class RefCountObject : angle::NonCopyable
27 {
28   public:
29     using ContextType = ContextT;
30     using ErrorType   = ErrorT;
31 
RefCountObject()32     RefCountObject() : mRefCount(0) {}
33 
onDestroy(const ContextType * context)34     virtual void onDestroy(const ContextType *context) {}
35 
addRef()36     void addRef() const { ++mRefCount; }
37 
release(const ContextType * context)38     ANGLE_INLINE void release(const ContextType *context)
39     {
40         ASSERT(mRefCount > 0);
41         if (--mRefCount == 0)
42         {
43             onDestroy(context);
44             delete this;
45         }
46     }
47 
getRefCount()48     size_t getRefCount() const { return mRefCount; }
49 
50   protected:
~RefCountObject()51     virtual ~RefCountObject() { ASSERT(mRefCount == 0); }
52 
53     mutable size_t mRefCount;
54 };
55 
56 template <class ObjectType, typename ContextT, typename ErrorT = angle::Result>
57 class BindingPointer
58 {
59   public:
60     using ContextType = ContextT;
61     using ErrorType   = ErrorT;
62 
BindingPointer()63     BindingPointer() : mObject(nullptr) {}
64 
BindingPointer(ObjectType * object)65     BindingPointer(ObjectType *object) : mObject(object)
66     {
67         if (mObject)
68         {
69             mObject->addRef();
70         }
71     }
72 
BindingPointer(const BindingPointer & other)73     BindingPointer(const BindingPointer &other) : mObject(other.mObject)
74     {
75         if (mObject)
76         {
77             mObject->addRef();
78         }
79     }
80 
81     BindingPointer &operator=(BindingPointer &&other)
82     {
83         std::swap(mObject, other.mObject);
84         return *this;
85     }
86 
~BindingPointer()87     virtual ~BindingPointer()
88     {
89         // Objects have to be released before the resource manager is destroyed, so they must be
90         // explicitly cleaned up.
91         ASSERT(mObject == nullptr);
92     }
93 
set(const ContextType * context,ObjectType * newObject)94     void set(const ContextType *context, ObjectType *newObject)
95     {
96         // addRef first in case newObject == mObject and this is the last reference to it.
97         if (newObject != nullptr)
98         {
99             reinterpret_cast<RefCountObject<ContextType, ErrorType> *>(newObject)->addRef();
100         }
101 
102         // Store the old pointer in a temporary so we can set the pointer before calling release.
103         // Otherwise the object could still be referenced when its destructor is called.
104         ObjectType *oldObject = mObject;
105         mObject               = newObject;
106         if (oldObject != nullptr)
107         {
108             reinterpret_cast<RefCountObject<ContextType, ErrorType> *>(oldObject)->release(context);
109         }
110     }
111 
assign(ObjectType * object)112     void assign(ObjectType *object) { mObject = object; }
113 
get()114     ObjectType *get() const { return mObject; }
115     ObjectType *operator->() const { return mObject; }
116 
117     bool operator==(const BindingPointer &other) const { return mObject == other.mObject; }
118 
119     bool operator!=(const BindingPointer &other) const { return !(*this == other); }
120 
121   protected:
setImpl(ObjectType * obj)122     ANGLE_INLINE void setImpl(ObjectType *obj) { mObject = obj; }
123 
124   private:
125     ObjectType *mObject;
126 };
127 }  // namespace angle
128 
129 namespace gl
130 {
131 class Context;
132 
133 template <class ObjectType>
134 class BindingPointer;
135 
136 using RefCountObjectNoID = angle::RefCountObject<Context, angle::Result>;
137 
138 class RefCountObject : public gl::RefCountObjectNoID
139 {
140   public:
RefCountObject(GLuint id)141     explicit RefCountObject(GLuint id) : mId(id) {}
142 
id()143     GLuint id() const { return mId; }
144 
145   protected:
~RefCountObject()146     ~RefCountObject() override {}
147 
148   private:
149     GLuint mId;
150 };
151 
152 template <class ObjectType>
153 class BindingPointer : public angle::BindingPointer<ObjectType, Context>
154 {
155   public:
156     using ContextType = typename angle::BindingPointer<ObjectType, Context>::ContextType;
157     using ErrorType   = typename angle::BindingPointer<ObjectType, Context>::ErrorType;
158 
BindingPointer()159     BindingPointer() {}
160 
BindingPointer(ObjectType * object)161     BindingPointer(ObjectType *object) : angle::BindingPointer<ObjectType, Context>(object) {}
162 
id()163     GLuint id() const
164     {
165         ObjectType *obj = this->get();
166         return obj ? obj->id() : 0;
167     }
168 };
169 
170 template <class ObjectType>
171 class OffsetBindingPointer : public BindingPointer<ObjectType>
172 {
173   public:
174     using ContextType = typename BindingPointer<ObjectType>::ContextType;
175     using ErrorType   = typename BindingPointer<ObjectType>::ErrorType;
176 
OffsetBindingPointer()177     OffsetBindingPointer() : mOffset(0), mSize(0) {}
178 
set(const ContextType * context,ObjectType * newObject,GLintptr offset,GLsizeiptr size)179     void set(const ContextType *context, ObjectType *newObject, GLintptr offset, GLsizeiptr size)
180     {
181         set(context, newObject);
182         mOffset = offset;
183         mSize   = size;
184     }
185 
getOffset()186     GLintptr getOffset() const { return mOffset; }
getSize()187     GLsizeiptr getSize() const { return mSize; }
188 
189     bool operator==(const OffsetBindingPointer<ObjectType> &other) const
190     {
191         return this->get() == other.get() && mOffset == other.mOffset && mSize == other.mSize;
192     }
193 
194     bool operator!=(const OffsetBindingPointer<ObjectType> &other) const
195     {
196         return !(*this == other);
197     }
198 
assign(ObjectType * object,GLintptr offset,GLsizeiptr size)199     void assign(ObjectType *object, GLintptr offset, GLsizeiptr size)
200     {
201         assign(object);
202         mOffset = offset;
203         mSize   = size;
204     }
205 
206   private:
207     // Delete the unparameterized functions. This forces an explicit offset and size.
208     using BindingPointer<ObjectType>::set;
209     using BindingPointer<ObjectType>::assign;
210 
211     GLintptr mOffset;
212     GLsizeiptr mSize;
213 };
214 
215 template <typename SubjectT>
216 class SubjectBindingPointer : protected BindingPointer<SubjectT>, public angle::ObserverBindingBase
217 {
218   public:
SubjectBindingPointer(angle::ObserverInterface * observer,angle::SubjectIndex index)219     SubjectBindingPointer(angle::ObserverInterface *observer, angle::SubjectIndex index)
220         : ObserverBindingBase(observer, index)
221     {}
~SubjectBindingPointer()222     ~SubjectBindingPointer() {}
223     SubjectBindingPointer(const SubjectBindingPointer &other) = default;
224     SubjectBindingPointer &operator=(const SubjectBindingPointer &other) = default;
225 
bind(const Context * context,SubjectT * subject)226     void bind(const Context *context, SubjectT *subject)
227     {
228         // AddRef first in case subject == get()
229         if (subject)
230         {
231             subject->addObserver(this);
232             subject->addRef();
233         }
234 
235         if (get())
236         {
237             get()->removeObserver(this);
238             get()->release(context);
239         }
240 
241         this->setImpl(subject);
242     }
243 
244     using BindingPointer<SubjectT>::get;
245     using BindingPointer<SubjectT>::operator->;
246 
247     friend class State;
248 };
249 }  // namespace gl
250 
251 namespace egl
252 {
253 class Display;
254 
255 using RefCountObject = angle::RefCountObject<Display, Error>;
256 
257 template <class ObjectType>
258 using BindingPointer = angle::BindingPointer<ObjectType, Display, Error>;
259 
260 }  // namespace egl
261 
262 #endif  // LIBANGLE_REFCOUNTOBJECT_H_
263