// // Copyright 2002 The ANGLE Project Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // // RefCountObject.h: Defines the gl::RefCountObject base class that provides // lifecycle support for GL objects using the traditional BindObject scheme, but // that need to be reference counted for correct cross-context deletion. // (Concretely, textures, buffers and renderbuffers.) #ifndef LIBANGLE_REFCOUNTOBJECT_H_ #define LIBANGLE_REFCOUNTOBJECT_H_ #include "angle_gl.h" #include "common/PackedEnums.h" #include "common/debug.h" #include "libANGLE/Error.h" #include "libANGLE/Observer.h" #include "libANGLE/renderer/serial_utils.h" #include namespace angle { template class RefCountObject : angle::NonCopyable { public: using ContextType = ContextT; using ErrorType = ErrorT; RefCountObject() : mRefCount(0) {} virtual void onDestroy(const ContextType *context) {} void addRef() const { ++mRefCount; } ANGLE_INLINE void release(const ContextType *context) { ASSERT(mRefCount > 0); if (--mRefCount == 0) { onDestroy(context); delete this; } } size_t getRefCount() const { return mRefCount; } protected: virtual ~RefCountObject() { ASSERT(mRefCount == 0); } mutable size_t mRefCount; }; template class RefCountObjectReleaser : angle::NonCopyable { public: using ContextType = ContextT; using ErrorType = ErrorT; RefCountObjectReleaser() {} RefCountObjectReleaser(const ContextType *context, ObjectType *object) : mContext(context), mObject(object) {} RefCountObjectReleaser(RefCountObjectReleaser &&other) : mContext(other.mContext), mObject(other.mObject) { other.mContext = nullptr; other.mObject = nullptr; } RefCountObjectReleaser &operator=(RefCountObjectReleaser &&other) { mContext = other.mContext; mObject = other.mObject; other.mContext = nullptr; other.mObject = nullptr; return *this; } ~RefCountObjectReleaser() { if (mObject) { reinterpret_cast *>(mObject)->release(mContext); mObject = nullptr; } } private: const ContextType *mContext = nullptr; ObjectType *mObject = nullptr; }; template class BindingPointer { public: using ContextType = ContextT; using ErrorType = ErrorT; BindingPointer() : mObject(nullptr) {} BindingPointer(ObjectType *object) : mObject(object) { if (mObject) { mObject->addRef(); } } BindingPointer(const BindingPointer &other) : mObject(other.mObject) { if (mObject) { mObject->addRef(); } } BindingPointer &operator=(BindingPointer &&other) { std::swap(mObject, other.mObject); return *this; } virtual ~BindingPointer() { // Objects have to be released before the resource manager is destroyed, so they must be // explicitly cleaned up. ASSERT(mObject == nullptr); } RefCountObjectReleaser set(const ContextType *context, ObjectType *newObject) { // addRef first in case newObject == mObject and this is the last reference to it. if (newObject != nullptr) { reinterpret_cast *>(newObject)->addRef(); } // Store the old pointer in a temporary so we can set the pointer before calling release. // Otherwise the object could still be referenced when its destructor is called. ObjectType *oldObject = mObject; mObject = newObject; return RefCountObjectReleaser(context, oldObject); } void assign(ObjectType *object) { mObject = object; } ObjectType *get() const { return mObject; } ObjectType *operator->() const { return mObject; } bool operator==(const BindingPointer &other) const { return mObject == other.mObject; } bool operator!=(const BindingPointer &other) const { return !(*this == other); } protected: ANGLE_INLINE void setImpl(ObjectType *obj) { mObject = obj; } private: ObjectType *mObject; }; } // namespace angle namespace gl { class Context; template class BindingPointer; using RefCountObjectNoID = angle::RefCountObject; template class RefCountObject : public gl::RefCountObjectNoID { public: explicit RefCountObject(rx::Serial serial, IDType id) : mSerial(serial), mId(id) {} rx::Serial serial() const { return mSerial; } IDType id() const { return mId; } protected: ~RefCountObject() override {} private: // Unique serials are used to identify resources for frame capture. rx::Serial mSerial; IDType mId; }; template class BindingPointer : public angle::BindingPointer { public: using ContextType = typename angle::BindingPointer::ContextType; using ErrorType = typename angle::BindingPointer::ErrorType; BindingPointer() {} BindingPointer(ObjectType *object) : angle::BindingPointer(object) {} typename ResourceTypeToID::IDType id() const { ObjectType *obj = this->get(); if (obj) return obj->id(); return {0}; } }; template class OffsetBindingPointer : public BindingPointer { public: using ContextType = typename BindingPointer::ContextType; using ErrorType = typename BindingPointer::ErrorType; OffsetBindingPointer() : mOffset(0), mSize(0) {} void set(const ContextType *context, ObjectType *newObject, GLintptr offset, GLsizeiptr size) { set(context, newObject); updateOffsetAndSize(newObject, offset, size); } GLintptr getOffset() const { return mOffset; } GLsizeiptr getSize() const { return mSize; } bool operator==(const OffsetBindingPointer &other) const { return this->get() == other.get() && mOffset == other.mOffset && mSize == other.mSize; } bool operator!=(const OffsetBindingPointer &other) const { return !(*this == other); } void assign(ObjectType *newObject, GLintptr offset, GLsizeiptr size) { assign(newObject); updateOffsetAndSize(newObject, offset, size); } private: ANGLE_INLINE void updateOffsetAndSize(ObjectType *newObject, GLintptr offset, GLsizeiptr size) { if (newObject) { mOffset = offset; mSize = size; } else { mOffset = 0; mSize = 0; } } // Delete the unparameterized functions. This forces an explicit offset and size. using BindingPointer::set; using BindingPointer::assign; GLintptr mOffset; GLsizeiptr mSize; }; template class SubjectBindingPointer : protected BindingPointer, public angle::ObserverBindingBase { public: SubjectBindingPointer(angle::ObserverInterface *observer, angle::SubjectIndex index) : ObserverBindingBase(observer, index) {} ~SubjectBindingPointer() override {} SubjectBindingPointer(const SubjectBindingPointer &other) = default; SubjectBindingPointer &operator=(const SubjectBindingPointer &other) = default; void bind(const Context *context, SubjectT *subject) { // AddRef first in case subject == get() if (subject) { subject->addObserver(this); subject->addRef(); } if (get()) { get()->removeObserver(this); get()->release(context); } this->setImpl(subject); } using BindingPointer::get; using BindingPointer::operator->; friend class State; }; } // namespace gl namespace egl { class Display; using RefCountObject = angle::RefCountObject; template using RefCountObjectReleaser = angle::RefCountObjectReleaser; template using BindingPointer = angle::BindingPointer; } // namespace egl #endif // LIBANGLE_REFCOUNTOBJECT_H_