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 // Alternative base class to RefCountObject using atomics to track the reference count. 59 // Interchangable with RefCountObject for usage with BindingPointer and other wrappers. 60 template <typename ContextT, typename ErrorT> 61 class ThreadSafeRefCountObject : angle::NonCopyable 62 { 63 public: 64 using ContextType = ContextT; 65 using ErrorType = ErrorT; 66 ThreadSafeRefCountObject()67 ThreadSafeRefCountObject() : mRefCount(0) {} 68 onDestroy(const ContextType * context)69 virtual void onDestroy(const ContextType *context) {} 70 addRef()71 void addRef() const { mRefCount.fetch_add(1, std::memory_order_relaxed); } 72 release(const ContextType * context)73 ANGLE_INLINE void release(const ContextType *context) 74 { 75 ASSERT(mRefCount > 0); 76 if (mRefCount.fetch_sub(1, std::memory_order_acq_rel) == 1) 77 { 78 onDestroy(context); 79 delete this; 80 } 81 } 82 getRefCount()83 size_t getRefCount() const { return mRefCount; } 84 85 protected: ~ThreadSafeRefCountObject()86 virtual ~ThreadSafeRefCountObject() { ASSERT(mRefCount == 0); } 87 88 mutable std::atomic<size_t> mRefCount; 89 }; 90 91 template <class ObjectType, typename ContextT, typename ErrorT = angle::Result> 92 class RefCountObjectReleaser : angle::NonCopyable 93 { 94 public: 95 using ContextType = ContextT; 96 using ErrorType = ErrorT; 97 RefCountObjectReleaser()98 RefCountObjectReleaser() {} RefCountObjectReleaser(const ContextType * context,ObjectType * object)99 RefCountObjectReleaser(const ContextType *context, ObjectType *object) 100 : mContext(context), mObject(object) 101 {} 102 RefCountObjectReleaser(RefCountObjectReleaser && other)103 RefCountObjectReleaser(RefCountObjectReleaser &&other) 104 : mContext(other.mContext), mObject(other.mObject) 105 { 106 other.mContext = nullptr; 107 other.mObject = nullptr; 108 } 109 110 RefCountObjectReleaser &operator=(RefCountObjectReleaser &&other) 111 { 112 std::swap(mContext, other.mContext); 113 std::swap(mObject, other.mObject); 114 return *this; 115 } 116 ~RefCountObjectReleaser()117 ~RefCountObjectReleaser() 118 { 119 if (mObject) 120 { 121 mObject->release(mContext); 122 mObject = nullptr; 123 } 124 } 125 126 private: 127 const ContextType *mContext = nullptr; 128 ObjectType *mObject = nullptr; 129 }; 130 131 template <class ObjectType, typename ContextT, typename ErrorT = angle::Result> 132 class BindingPointer 133 { 134 public: 135 using ContextType = ContextT; 136 using ErrorType = ErrorT; 137 BindingPointer()138 BindingPointer() : mObject(nullptr) {} 139 BindingPointer(ObjectType * object)140 BindingPointer(ObjectType *object) : mObject(object) 141 { 142 if (mObject) 143 { 144 mObject->addRef(); 145 } 146 } 147 BindingPointer(const BindingPointer & other)148 BindingPointer(const BindingPointer &other) : mObject(other.mObject) 149 { 150 if (mObject) 151 { 152 mObject->addRef(); 153 } 154 } 155 156 BindingPointer &operator=(BindingPointer &&other) 157 { 158 std::swap(mObject, other.mObject); 159 return *this; 160 } 161 ~BindingPointer()162 virtual ~BindingPointer() 163 { 164 // Objects have to be released before the resource manager is destroyed, so they must be 165 // explicitly cleaned up. 166 ASSERT(mObject == nullptr); 167 } 168 set(const ContextType * context,ObjectType * newObject)169 RefCountObjectReleaser<ObjectType, ContextType, ErrorT> set(const ContextType *context, 170 ObjectType *newObject) 171 { 172 // addRef first in case newObject == mObject and this is the last reference to it. 173 if (newObject != nullptr) 174 { 175 newObject->addRef(); 176 } 177 178 // Store the old pointer in a temporary so we can set the pointer before calling release. 179 // Otherwise the object could still be referenced when its destructor is called. 180 ObjectType *oldObject = mObject; 181 mObject = newObject; 182 return RefCountObjectReleaser<ObjectType, ContextType, ErrorT>(context, oldObject); 183 } 184 assign(ObjectType * object)185 void assign(ObjectType *object) { mObject = object; } 186 get()187 ObjectType *get() const { return mObject; } 188 ObjectType *operator->() const { return mObject; } 189 190 bool operator==(const BindingPointer &other) const { return mObject == other.mObject; } 191 192 bool operator!=(const BindingPointer &other) const { return !(*this == other); } 193 194 protected: setImpl(ObjectType * obj)195 ANGLE_INLINE void setImpl(ObjectType *obj) { mObject = obj; } 196 197 private: 198 ObjectType *mObject; 199 }; 200 } // namespace angle 201 202 namespace gl 203 { 204 class Context; 205 206 template <class ObjectType> 207 class BindingPointer; 208 209 using RefCountObjectNoID = angle::RefCountObject<Context, angle::Result>; 210 using ThreadSafeRefCountObjectNoID = angle::ThreadSafeRefCountObject<Context, angle::Result>; 211 212 template <typename IDType, typename RC = RefCountObjectNoID> 213 class RefCountObject : public RC 214 { 215 public: RefCountObject(rx::UniqueSerial serial,IDType id)216 explicit RefCountObject(rx::UniqueSerial serial, IDType id) : mSerial(serial), mId(id) {} 217 serial()218 rx::UniqueSerial serial() const { return mSerial; } id()219 IDType id() const { return mId; } 220 221 protected: ~RefCountObject()222 ~RefCountObject() override {} 223 224 private: 225 // Unique serials are used to identify resources for frame capture. 226 rx::UniqueSerial mSerial; 227 IDType mId; 228 }; 229 template <typename IDType> 230 using ThreadSafeRefCountObject = RefCountObject<IDType, ThreadSafeRefCountObjectNoID>; 231 232 template <class ObjectType> 233 class BindingPointer : public angle::BindingPointer<ObjectType, Context> 234 { 235 public: 236 using ContextType = typename angle::BindingPointer<ObjectType, Context>::ContextType; 237 using ErrorType = typename angle::BindingPointer<ObjectType, Context>::ErrorType; 238 BindingPointer()239 BindingPointer() {} 240 BindingPointer(ObjectType * object)241 BindingPointer(ObjectType *object) : angle::BindingPointer<ObjectType, Context>(object) {} 242 id()243 typename ResourceTypeToID<ObjectType>::IDType id() const 244 { 245 ObjectType *obj = this->get(); 246 if (obj) 247 return obj->id(); 248 return {0}; 249 } 250 }; 251 252 template <class ObjectType> 253 class OffsetBindingPointer : public BindingPointer<ObjectType> 254 { 255 public: 256 using ContextType = typename BindingPointer<ObjectType>::ContextType; 257 using ErrorType = typename BindingPointer<ObjectType>::ErrorType; 258 OffsetBindingPointer()259 OffsetBindingPointer() : mOffset(0), mSize(0) {} 260 set(const ContextType * context,ObjectType * newObject,GLintptr offset,GLsizeiptr size)261 void set(const ContextType *context, ObjectType *newObject, GLintptr offset, GLsizeiptr size) 262 { 263 set(context, newObject); 264 updateOffsetAndSize(newObject, offset, size); 265 } 266 getOffset()267 GLintptr getOffset() const { return mOffset; } getSize()268 GLsizeiptr getSize() const { return mSize; } 269 270 bool operator==(const OffsetBindingPointer<ObjectType> &other) const 271 { 272 return this->get() == other.get() && mOffset == other.mOffset && mSize == other.mSize; 273 } 274 275 bool operator!=(const OffsetBindingPointer<ObjectType> &other) const 276 { 277 return !(*this == other); 278 } 279 assign(ObjectType * newObject,GLintptr offset,GLsizeiptr size)280 void assign(ObjectType *newObject, GLintptr offset, GLsizeiptr size) 281 { 282 assign(newObject); 283 updateOffsetAndSize(newObject, offset, size); 284 } 285 286 private: updateOffsetAndSize(ObjectType * newObject,GLintptr offset,GLsizeiptr size)287 ANGLE_INLINE void updateOffsetAndSize(ObjectType *newObject, GLintptr offset, GLsizeiptr size) 288 { 289 if (newObject) 290 { 291 mOffset = offset; 292 mSize = size; 293 } 294 else 295 { 296 mOffset = 0; 297 mSize = 0; 298 } 299 } 300 301 // Delete the unparameterized functions. This forces an explicit offset and size. 302 using BindingPointer<ObjectType>::set; 303 using BindingPointer<ObjectType>::assign; 304 305 GLintptr mOffset; 306 GLsizeiptr mSize; 307 }; 308 309 template <typename SubjectT> 310 class SubjectBindingPointer : protected BindingPointer<SubjectT>, public angle::ObserverBindingBase 311 { 312 public: SubjectBindingPointer(angle::ObserverInterface * observer,angle::SubjectIndex index)313 SubjectBindingPointer(angle::ObserverInterface *observer, angle::SubjectIndex index) 314 : ObserverBindingBase(observer, index) 315 {} ~SubjectBindingPointer()316 ~SubjectBindingPointer() override {} 317 SubjectBindingPointer(const SubjectBindingPointer &other) = default; 318 SubjectBindingPointer &operator=(const SubjectBindingPointer &other) = default; 319 bind(const Context * context,SubjectT * subject)320 void bind(const Context *context, SubjectT *subject) 321 { 322 // AddRef first in case subject == get() 323 if (subject) 324 { 325 subject->addObserver(this); 326 subject->addRef(); 327 } 328 329 if (get()) 330 { 331 get()->removeObserver(this); 332 get()->release(context); 333 } 334 335 this->setImpl(subject); 336 } 337 338 using BindingPointer<SubjectT>::get; 339 using BindingPointer<SubjectT>::operator->; 340 341 friend class State; 342 }; 343 } // namespace gl 344 345 namespace egl 346 { 347 class Display; 348 349 using RefCountObject = angle::RefCountObject<Display, Error>; 350 using ThreadSafeRefCountObject = angle::ThreadSafeRefCountObject<Display, Error>; 351 352 template <class ObjectType> 353 using RefCountObjectReleaser = angle::RefCountObjectReleaser<ObjectType, Display, Error>; 354 355 template <class ObjectType> 356 using BindingPointer = angle::BindingPointer<ObjectType, Display, Error>; 357 358 } // namespace egl 359 360 #endif // LIBANGLE_REFCOUNTOBJECT_H_ 361