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