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