1 //
2 // Copyright (c) 2002-2010 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/debug.h"
17 #include "libANGLE/Error.h"
18 
19 #include <cstddef>
20 
21 namespace gl
22 {
23 class Context;
24 
25 class RefCountObjectNoID : angle::NonCopyable
26 {
27   public:
RefCountObjectNoID()28     RefCountObjectNoID() : mRefCount(0) {}
29     virtual Error onDestroy(const Context *context);
30 
addRef()31     void addRef() const { ++mRefCount; }
32 
release()33     void release() const
34     {
35         ASSERT(mRefCount > 0);
36 
37         if (--mRefCount == 0)
38         {
39             delete this;
40         }
41     }
42 
getRefCount()43     size_t getRefCount() const { return mRefCount; }
44 
45   protected:
46     virtual ~RefCountObjectNoID();
47 
48     // A specialized release method for objects which need a destroy context.
release(const gl::Context * context)49     void release(const gl::Context *context)
50     {
51         ASSERT(mRefCount > 0);
52         if (--mRefCount == 0)
53         {
54             ANGLE_SWALLOW_ERR(onDestroy(context));
55             delete this;
56         }
57     }
58 
59     template <class ObjectType>
60     friend class BindingPointer;
61     mutable std::size_t mRefCount;
62 };
63 
~RefCountObjectNoID()64 inline RefCountObjectNoID::~RefCountObjectNoID()
65 {
66     ASSERT(mRefCount == 0);
67 }
68 
onDestroy(const Context * context)69 inline Error RefCountObjectNoID::onDestroy(const Context *context)
70 {
71     return NoError();
72 }
73 
74 template <class ObjectType>
75 class BindingPointer;
76 
77 class RefCountObject : RefCountObjectNoID
78 {
79   public:
RefCountObject(GLuint id)80     explicit RefCountObject(GLuint id) : mId(id) {}
81 
id()82     GLuint id() const { return mId; }
83 
84     using RefCountObjectNoID::release;
85     using RefCountObjectNoID::addRef;
86     using RefCountObjectNoID::getRefCount;
87 
88   protected:
~RefCountObject()89     ~RefCountObject() override {}
90 
91   private:
92     GLuint mId;
93 };
94 
95 template <class ObjectType>
96 class BindingPointer
97 {
98   public:
BindingPointer()99     BindingPointer()
100         : mObject(nullptr)
101     {
102     }
103 
BindingPointer(ObjectType * object)104     BindingPointer(ObjectType *object) : mObject(object) { mObject->addRef(); }
105 
BindingPointer(const BindingPointer<ObjectType> & other)106     BindingPointer(const BindingPointer<ObjectType> &other) : mObject(other.mObject)
107     {
108         mObject->addRef();
109     }
110 
111     BindingPointer &operator=(BindingPointer<ObjectType> &&other)
112     {
113         std::swap(mObject, other.mObject);
114         return *this;
115     }
116 
~BindingPointer()117     virtual ~BindingPointer()
118     {
119         // Objects have to be released before the resource manager is destroyed, so they must be explicitly cleaned up.
120         ASSERT(mObject == nullptr);
121     }
122 
set(const Context * context,ObjectType * newObject)123     virtual void set(const Context *context, ObjectType *newObject)
124     {
125         // addRef first in case newObject == mObject and this is the last reference to it.
126         if (newObject != nullptr) reinterpret_cast<const RefCountObjectNoID*>(newObject)->addRef();
127         if (mObject != nullptr)
128             reinterpret_cast<RefCountObjectNoID *>(mObject)->release(context);
129         mObject = newObject;
130     }
131 
get()132     ObjectType *get() const { return mObject; }
133     ObjectType *operator->() const { return mObject; }
134 
id()135     GLuint id() const { return (mObject != nullptr) ? mObject->id() : 0; }
136 
137     bool operator==(const BindingPointer<ObjectType> &other) const
138     {
139         return mObject == other.mObject;
140     }
141 
142     bool operator!=(const BindingPointer<ObjectType> &other) const { return !(*this == other); }
143 
144   private:
145     ObjectType *mObject;
146 };
147 
148 template <class ObjectType>
149 class OffsetBindingPointer : public BindingPointer<ObjectType>
150 {
151   public:
OffsetBindingPointer()152     OffsetBindingPointer() : mOffset(0), mSize(0) { }
153 
set(const Context * context,ObjectType * newObject)154     void set(const Context *context, ObjectType *newObject) override
155     {
156         BindingPointer<ObjectType>::set(context, newObject);
157         mOffset = 0;
158         mSize = 0;
159     }
160 
set(const Context * context,ObjectType * newObject,GLintptr offset,GLsizeiptr size)161     void set(const Context *context, ObjectType *newObject, GLintptr offset, GLsizeiptr size)
162     {
163         BindingPointer<ObjectType>::set(context, newObject);
164         mOffset = offset;
165         mSize = size;
166     }
167 
getOffset()168     GLintptr getOffset() const { return mOffset; }
getSize()169     GLsizeiptr getSize() const { return mSize; }
170 
171     bool operator==(const OffsetBindingPointer<ObjectType> &other) const
172     {
173         return this->get() == other.get() && mOffset == other.mOffset && mSize == other.mSize;
174     }
175 
176     bool operator!=(const OffsetBindingPointer<ObjectType> &other) const
177     {
178         return !(*this == other);
179     }
180 
181   private:
182     GLintptr mOffset;
183     GLsizeiptr mSize;
184 };
185 }  // namespace gl
186 
187 #endif   // LIBANGLE_REFCOUNTOBJECT_H_
188