tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

RefCountObject.h (8884B)


      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 
     34    RefCountObject() : mRefCount(0) {}
     35 
     36    virtual void onDestroy(const ContextType *context) {}
     37 
     38    void addRef() const { ++mRefCount; }
     39 
     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 
     50    size_t getRefCount() const { return mRefCount; }
     51 
     52  protected:
     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 
     65    RefCountObjectReleaser() {}
     66    RefCountObjectReleaser(const ContextType *context, ObjectType *object)
     67        : mContext(context), mObject(object)
     68    {}
     69 
     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 
     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 
    109    BindingPointer() : mObject(nullptr) {}
    110 
    111    BindingPointer(ObjectType *object) : mObject(object)
    112    {
    113        if (mObject)
    114        {
    115            mObject->addRef();
    116        }
    117    }
    118 
    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 
    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 
    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 
    156    void assign(ObjectType *object) { mObject = object; }
    157 
    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:
    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:
    186    explicit RefCountObject(rx::Serial serial, IDType id) : mSerial(serial), mId(id) {}
    187 
    188    rx::Serial serial() const { return mSerial; }
    189    IDType id() const { return mId; }
    190 
    191  protected:
    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 
    207    BindingPointer() {}
    208 
    209    BindingPointer(ObjectType *object) : angle::BindingPointer<ObjectType, Context>(object) {}
    210 
    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 
    227    OffsetBindingPointer() : mOffset(0), mSize(0) {}
    228 
    229    void set(const ContextType *context, ObjectType *newObject, GLintptr offset, GLsizeiptr size)
    230    {
    231        set(context, newObject);
    232        updateOffsetAndSize(newObject, offset, size);
    233    }
    234 
    235    GLintptr getOffset() const { return mOffset; }
    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 
    248    void assign(ObjectType *newObject, GLintptr offset, GLsizeiptr size)
    249    {
    250        assign(newObject);
    251        updateOffsetAndSize(newObject, offset, size);
    252    }
    253 
    254  private:
    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:
    281    SubjectBindingPointer(angle::ObserverInterface *observer, angle::SubjectIndex index)
    282        : ObserverBindingBase(observer, index)
    283    {}
    284    ~SubjectBindingPointer() override {}
    285    SubjectBindingPointer(const SubjectBindingPointer &other) = default;
    286    SubjectBindingPointer &operator=(const SubjectBindingPointer &other) = default;
    287 
    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_