summaryrefslogtreecommitdiffstats
path: root/gfx/angle/checkout/src/libANGLE/RefCountObject.h
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/angle/checkout/src/libANGLE/RefCountObject.h')
-rw-r--r--gfx/angle/checkout/src/libANGLE/RefCountObject.h327
1 files changed, 327 insertions, 0 deletions
diff --git a/gfx/angle/checkout/src/libANGLE/RefCountObject.h b/gfx/angle/checkout/src/libANGLE/RefCountObject.h
new file mode 100644
index 0000000000..f19b8c434a
--- /dev/null
+++ b/gfx/angle/checkout/src/libANGLE/RefCountObject.h
@@ -0,0 +1,327 @@
+//
+// 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 <cstddef>
+
+namespace angle
+{
+
+template <typename ContextT, typename ErrorT>
+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 ObjectType, typename ContextT, typename ErrorT = angle::Result>
+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<RefCountObject<ContextType, ErrorType> *>(mObject)->release(mContext);
+ mObject = nullptr;
+ }
+ }
+
+ private:
+ const ContextType *mContext = nullptr;
+ ObjectType *mObject = nullptr;
+};
+
+template <class ObjectType, typename ContextT, typename ErrorT = angle::Result>
+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<ObjectType, ContextType, ErrorT> 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<RefCountObject<ContextType, ErrorType> *>(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<ObjectType, ContextType, ErrorT>(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 ObjectType>
+class BindingPointer;
+
+using RefCountObjectNoID = angle::RefCountObject<Context, angle::Result>;
+
+template <typename IDType>
+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 ObjectType>
+class BindingPointer : public angle::BindingPointer<ObjectType, Context>
+{
+ public:
+ using ContextType = typename angle::BindingPointer<ObjectType, Context>::ContextType;
+ using ErrorType = typename angle::BindingPointer<ObjectType, Context>::ErrorType;
+
+ BindingPointer() {}
+
+ BindingPointer(ObjectType *object) : angle::BindingPointer<ObjectType, Context>(object) {}
+
+ typename ResourceTypeToID<ObjectType>::IDType id() const
+ {
+ ObjectType *obj = this->get();
+ if (obj)
+ return obj->id();
+ return {0};
+ }
+};
+
+template <class ObjectType>
+class OffsetBindingPointer : public BindingPointer<ObjectType>
+{
+ public:
+ using ContextType = typename BindingPointer<ObjectType>::ContextType;
+ using ErrorType = typename BindingPointer<ObjectType>::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<ObjectType> &other) const
+ {
+ return this->get() == other.get() && mOffset == other.mOffset && mSize == other.mSize;
+ }
+
+ bool operator!=(const OffsetBindingPointer<ObjectType> &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<ObjectType>::set;
+ using BindingPointer<ObjectType>::assign;
+
+ GLintptr mOffset;
+ GLsizeiptr mSize;
+};
+
+template <typename SubjectT>
+class SubjectBindingPointer : protected BindingPointer<SubjectT>, 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<SubjectT>::get;
+ using BindingPointer<SubjectT>::operator->;
+
+ friend class State;
+};
+} // namespace gl
+
+namespace egl
+{
+class Display;
+
+using RefCountObject = angle::RefCountObject<Display, Error>;
+
+template <class ObjectType>
+using RefCountObjectReleaser = angle::RefCountObjectReleaser<ObjectType, Display, Error>;
+
+template <class ObjectType>
+using BindingPointer = angle::BindingPointer<ObjectType, Display, Error>;
+
+} // namespace egl
+
+#endif // LIBANGLE_REFCOUNTOBJECT_H_