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