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