1 //
2 // Copyright (c) 2002-2010 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
19 #include <cstddef>
20
21 namespace gl
22 {
23 class Context;
24
25 class RefCountObjectNoID : angle::NonCopyable
26 {
27 public:
RefCountObjectNoID()28 RefCountObjectNoID() : mRefCount(0) {}
29 virtual Error onDestroy(const Context *context);
30
addRef()31 void addRef() const { ++mRefCount; }
32
release()33 void release() const
34 {
35 ASSERT(mRefCount > 0);
36
37 if (--mRefCount == 0)
38 {
39 delete this;
40 }
41 }
42
getRefCount()43 size_t getRefCount() const { return mRefCount; }
44
45 protected:
46 virtual ~RefCountObjectNoID();
47
48 // A specialized release method for objects which need a destroy context.
release(const gl::Context * context)49 void release(const gl::Context *context)
50 {
51 ASSERT(mRefCount > 0);
52 if (--mRefCount == 0)
53 {
54 ANGLE_SWALLOW_ERR(onDestroy(context));
55 delete this;
56 }
57 }
58
59 template <class ObjectType>
60 friend class BindingPointer;
61 mutable std::size_t mRefCount;
62 };
63
~RefCountObjectNoID()64 inline RefCountObjectNoID::~RefCountObjectNoID()
65 {
66 ASSERT(mRefCount == 0);
67 }
68
onDestroy(const Context * context)69 inline Error RefCountObjectNoID::onDestroy(const Context *context)
70 {
71 return NoError();
72 }
73
74 template <class ObjectType>
75 class BindingPointer;
76
77 class RefCountObject : RefCountObjectNoID
78 {
79 public:
RefCountObject(GLuint id)80 explicit RefCountObject(GLuint id) : mId(id) {}
81
id()82 GLuint id() const { return mId; }
83
84 using RefCountObjectNoID::release;
85 using RefCountObjectNoID::addRef;
86 using RefCountObjectNoID::getRefCount;
87
88 protected:
~RefCountObject()89 ~RefCountObject() override {}
90
91 private:
92 GLuint mId;
93 };
94
95 template <class ObjectType>
96 class BindingPointer
97 {
98 public:
BindingPointer()99 BindingPointer()
100 : mObject(nullptr)
101 {
102 }
103
BindingPointer(ObjectType * object)104 BindingPointer(ObjectType *object) : mObject(object) { mObject->addRef(); }
105
BindingPointer(const BindingPointer<ObjectType> & other)106 BindingPointer(const BindingPointer<ObjectType> &other) : mObject(other.mObject)
107 {
108 mObject->addRef();
109 }
110
111 BindingPointer &operator=(BindingPointer<ObjectType> &&other)
112 {
113 std::swap(mObject, other.mObject);
114 return *this;
115 }
116
~BindingPointer()117 virtual ~BindingPointer()
118 {
119 // Objects have to be released before the resource manager is destroyed, so they must be explicitly cleaned up.
120 ASSERT(mObject == nullptr);
121 }
122
set(const Context * context,ObjectType * newObject)123 virtual void set(const Context *context, ObjectType *newObject)
124 {
125 // addRef first in case newObject == mObject and this is the last reference to it.
126 if (newObject != nullptr) reinterpret_cast<const RefCountObjectNoID*>(newObject)->addRef();
127 if (mObject != nullptr)
128 reinterpret_cast<RefCountObjectNoID *>(mObject)->release(context);
129 mObject = newObject;
130 }
131
get()132 ObjectType *get() const { return mObject; }
133 ObjectType *operator->() const { return mObject; }
134
id()135 GLuint id() const { return (mObject != nullptr) ? mObject->id() : 0; }
136
137 bool operator==(const BindingPointer<ObjectType> &other) const
138 {
139 return mObject == other.mObject;
140 }
141
142 bool operator!=(const BindingPointer<ObjectType> &other) const { return !(*this == other); }
143
144 private:
145 ObjectType *mObject;
146 };
147
148 template <class ObjectType>
149 class OffsetBindingPointer : public BindingPointer<ObjectType>
150 {
151 public:
OffsetBindingPointer()152 OffsetBindingPointer() : mOffset(0), mSize(0) { }
153
set(const Context * context,ObjectType * newObject)154 void set(const Context *context, ObjectType *newObject) override
155 {
156 BindingPointer<ObjectType>::set(context, newObject);
157 mOffset = 0;
158 mSize = 0;
159 }
160
set(const Context * context,ObjectType * newObject,GLintptr offset,GLsizeiptr size)161 void set(const Context *context, ObjectType *newObject, GLintptr offset, GLsizeiptr size)
162 {
163 BindingPointer<ObjectType>::set(context, newObject);
164 mOffset = offset;
165 mSize = size;
166 }
167
getOffset()168 GLintptr getOffset() const { return mOffset; }
getSize()169 GLsizeiptr getSize() const { return mSize; }
170
171 bool operator==(const OffsetBindingPointer<ObjectType> &other) const
172 {
173 return this->get() == other.get() && mOffset == other.mOffset && mSize == other.mSize;
174 }
175
176 bool operator!=(const OffsetBindingPointer<ObjectType> &other) const
177 {
178 return !(*this == other);
179 }
180
181 private:
182 GLintptr mOffset;
183 GLsizeiptr mSize;
184 };
185 } // namespace gl
186
187 #endif // LIBANGLE_REFCOUNTOBJECT_H_
188