Bug 1521243 - Show a warning for invalid declarations and filter icon for overridden...
[gecko.git] / dom / canvas / WebGLObjectModel.h
blobbb52cd65c5e31b601f17a321a7742e08f7b05763
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifndef WEBGLOBJECTMODEL_H_
7 #define WEBGLOBJECTMODEL_H_
9 #include "nsCycleCollectionNoteChild.h"
11 #include "WebGLTypes.h"
13 namespace mozilla {
15 template <typename>
16 class LinkedList;
17 class WebGLContext;
19 ////
21 // This class is a mixin for objects that are tied to a specific
22 // context (which is to say, all of them). They provide initialization
23 // as well as comparison with the current context.
24 class WebGLContextBoundObject {
25 public:
26 WebGLContext* const mContext;
28 private:
29 const uint32_t mContextGeneration;
31 public:
32 explicit WebGLContextBoundObject(WebGLContext* webgl);
34 bool IsCompatibleWithContext(const WebGLContext* other) const;
37 ////
39 class WebGLDeletableObject : public WebGLContextBoundObject {
40 template <typename>
41 friend class WebGLRefCountedObject;
43 private:
44 enum DeletionStatus { Default, DeleteRequested, Deleted };
46 DeletionStatus mDeletionStatus;
48 ////
50 explicit WebGLDeletableObject(WebGLContext* webgl)
51 : WebGLContextBoundObject(webgl), mDeletionStatus(Default) {}
53 ~WebGLDeletableObject() {
54 MOZ_ASSERT(mDeletionStatus == Deleted,
55 "Derived class destructor must call DeleteOnce().");
58 public:
59 bool IsDeleted() const { return mDeletionStatus == Deleted; }
60 bool IsDeleteRequested() const { return mDeletionStatus != Default; }
63 /* Each WebGL object class WebGLFoo wants to:
64 * - inherit WebGLRefCountedObject<WebGLFoo>
65 * - implement a Delete() method
66 * - have its destructor call DeleteOnce()
68 * This base class provides two features to WebGL object types:
69 * 1. support for OpenGL object reference counting
70 * 2. support for OpenGL deletion statuses
72 ***** 1. OpenGL object reference counting *****
74 * WebGL objects such as WebGLTexture's really have two different refcounts:
75 * the XPCOM refcount, that is directly exposed to JavaScript, and the OpenGL
76 * refcount.
78 * For example, when in JavaScript one does: var newname = existingTexture;
79 * that increments the XPCOM refcount, but doesn't affect the OpenGL refcount.
80 * When one attaches the texture to a framebuffer object, that does increment
81 * its OpenGL refcount (and also its XPCOM refcount, to prevent the regular
82 * XPCOM refcounting mechanism from destroying objects prematurely).
84 * The actual OpenGL refcount is opaque to us (it's internal to the OpenGL
85 * implementation) but is affects the WebGL semantics that we have to implement:
86 * for example, a WebGLTexture that is attached to a WebGLFramebuffer must not
87 * be actually deleted, even if deleteTexture has been called on it, and even
88 * if JavaScript doesn't have references to it anymore. We can't just rely on
89 * OpenGL to keep alive the underlying OpenGL texture for us, for a variety of
90 * reasons, most importantly: we'd need to know when OpenGL objects are actually
91 * deleted, and OpenGL doesn't notify us about that, so we would have to query
92 * status very often with glIsXxx calls which isn't practical.
94 * This means that we have to keep track of the OpenGL refcount ourselves,
95 * in addition to the XPCOM refcount.
97 * This class implements such a refcount, see the mWebGLRefCnt
98 * member. In order to avoid name clashes (with regular XPCOM refcounting)
99 * in the derived class, we prefix members with 'WebGL', whence the names
100 * WebGLAddRef, WebGLRelease, etc.
102 * In practice, WebGLAddRef and WebGLRelease are only called from the
103 * WebGLRefPtr class.
105 ***** 2. OpenGL deletion statuses *****
107 * In OpenGL, an object can go through 3 different deletion statuses during its
108 * lifetime, which correspond to the 3 enum values for DeletionStatus in this
109 * class:
110 * - the Default status, which it has from its creation to when the suitable
111 * glDeleteXxx function is called on it;
112 * - the DeleteRequested status, which is has from when the suitable
113 * glDeleteXxx function is called on it to when it is no longer referenced by
114 * other OpenGL objects. For example, a texture that is attached to a
115 * non-current FBO will enter that status when glDeleteTexture is called on
116 * it. For objects with that status, GL_DELETE_STATUS queries return true,
117 * but glIsXxx functions still return true.
118 * - the Deleted status, which is the status of objects on which the suitable
119 * glDeleteXxx function has been called, and that are not referenced by other
120 * OpenGL objects.
122 * This state is stored in the mDeletionStatus member of this class.
124 * When the GL refcount hits zero, if the status is DeleteRequested then we call
125 * the Delete() method on the derived class and the status becomes Deleted. This
126 * is what the MaybeDelete() function does.
128 * The DeleteOnce() function implemented here is a helper to ensure that we
129 * don't call Delete() twice on the same object. Since the derived class's
130 * destructor needs to call DeleteOnce() which calls Delete(), we can't allow
131 * either to be virtual. Strictly speaking, we could let them be virtual if the
132 * derived class were final, but that would be impossible to enforce and would
133 * lead to strange bugs if it were subclassed.
135 * This WebGLRefCountedObject class takes the Derived type as template
136 * parameter, as a means to allow DeleteOnce to call Delete() on the Derived
137 * class, without either method being virtual. This is a common C++ pattern
138 * known as the "curiously recursive template pattern (CRTP)".
141 template <typename Derived>
142 class WebGLRefCountedObject : public WebGLDeletableObject {
143 friend class WebGLContext;
144 template <typename T>
145 friend void ClearLinkedList(LinkedList<T>& list);
147 private:
148 nsAutoRefCnt mWebGLRefCnt;
150 public:
151 explicit WebGLRefCountedObject(WebGLContext* webgl)
152 : WebGLDeletableObject(webgl) {}
154 ~WebGLRefCountedObject() {
155 MOZ_ASSERT(mWebGLRefCnt == 0,
156 "Destroying WebGL object still referenced by other WebGL"
157 " objects.");
160 // called by WebGLRefPtr
161 void WebGLAddRef() { ++mWebGLRefCnt; }
163 // called by WebGLRefPtr
164 void WebGLRelease() {
165 MOZ_ASSERT(mWebGLRefCnt > 0,
166 "Releasing WebGL object with WebGL refcnt already zero");
167 --mWebGLRefCnt;
168 MaybeDelete();
171 // this is the function that WebGL.deleteXxx() functions want to call
172 void RequestDelete() {
173 if (mDeletionStatus == Default) mDeletionStatus = DeleteRequested;
174 MaybeDelete();
177 protected:
178 void DeleteOnce() {
179 if (mDeletionStatus != Deleted) {
180 static_cast<Derived*>(this)->Delete();
181 mDeletionStatus = Deleted;
185 private:
186 void MaybeDelete() {
187 if (mWebGLRefCnt == 0 && mDeletionStatus == DeleteRequested) {
188 DeleteOnce();
193 /* This WebGLRefPtr class is meant to be used for references between WebGL
194 * objects. For example, a WebGLProgram holds WebGLRefPtr's to the WebGLShader's
195 * attached to it.
197 * Why the need for a separate refptr class? The only special thing that
198 * WebGLRefPtr does is that it increments and decrements the WebGL refcount of
199 * WebGLRefCountedObject's, in addition to incrementing and decrementing the
200 * usual XPCOM refcount.
202 * This means that by using a WebGLRefPtr instead of a nsRefPtr, you ensure that
203 * the WebGL refcount is incremented, which means that the object will be kept
204 * alive by this reference even if the matching webgl.deleteXxx() function is
205 * called on it.
207 template <typename T>
208 class WebGLRefPtr {
209 public:
210 WebGLRefPtr() : mRawPtr(0) {}
212 WebGLRefPtr(const WebGLRefPtr<T>& smartPtr) : mRawPtr(smartPtr.mRawPtr) {
213 AddRefOnPtr(mRawPtr);
216 explicit WebGLRefPtr(T* rawPtr) : mRawPtr(rawPtr) { AddRefOnPtr(mRawPtr); }
218 ~WebGLRefPtr() { ReleasePtr(mRawPtr); }
220 WebGLRefPtr<T>& operator=(const WebGLRefPtr<T>& rhs) {
221 assign_with_AddRef(rhs.mRawPtr);
222 return *this;
225 WebGLRefPtr<T>& operator=(T* rhs) {
226 assign_with_AddRef(rhs);
227 return *this;
230 T* get() const { return static_cast<T*>(mRawPtr); }
232 operator T*() const { return get(); }
234 T* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN {
235 MOZ_ASSERT(
236 mRawPtr != 0,
237 "You can't dereference a nullptr WebGLRefPtr with operator->()!");
238 return get();
241 T& operator*() const {
242 MOZ_ASSERT(mRawPtr != 0,
243 "You can't dereference a nullptr WebGLRefPtr with operator*()!");
244 return *get();
247 private:
248 static void AddRefOnPtr(T* rawPtr) {
249 if (rawPtr) {
250 rawPtr->WebGLAddRef();
251 rawPtr->AddRef();
255 static void ReleasePtr(T* rawPtr) {
256 if (rawPtr) {
257 rawPtr->WebGLRelease(); // must be done first before Release(), as
258 // Release() might actually destroy the object
259 rawPtr->Release();
263 void assign_with_AddRef(T* rawPtr) {
264 AddRefOnPtr(rawPtr);
265 assign_assuming_AddRef(rawPtr);
268 void assign_assuming_AddRef(T* newPtr) {
269 T* oldPtr = mRawPtr;
270 mRawPtr = newPtr;
271 ReleasePtr(oldPtr);
274 protected:
275 T* mRawPtr;
278 // this class is a mixin for GL objects that have dimensions
279 // that we need to track.
280 class WebGLRectangleObject {
281 public:
282 WebGLRectangleObject() : mWidth(0), mHeight(0) {}
284 WebGLRectangleObject(GLsizei width, GLsizei height)
285 : mWidth(width), mHeight(height) {}
287 GLsizei Width() const { return mWidth; }
288 void width(GLsizei value) { mWidth = value; }
290 GLsizei Height() const { return mHeight; }
291 void height(GLsizei value) { mHeight = value; }
293 void setDimensions(GLsizei width, GLsizei height) {
294 mWidth = width;
295 mHeight = height;
298 void setDimensions(WebGLRectangleObject* rect) {
299 if (rect) {
300 mWidth = rect->Width();
301 mHeight = rect->Height();
302 } else {
303 mWidth = 0;
304 mHeight = 0;
308 bool HasSameDimensionsAs(const WebGLRectangleObject& other) const {
309 return Width() == other.Width() && Height() == other.Height();
312 protected:
313 GLsizei mWidth;
314 GLsizei mHeight;
317 } // namespace mozilla
319 template <typename T>
320 inline void ImplCycleCollectionUnlink(mozilla::WebGLRefPtr<T>& field) {
321 field = nullptr;
324 template <typename T>
325 inline void ImplCycleCollectionTraverse(
326 nsCycleCollectionTraversalCallback& callback,
327 const mozilla::WebGLRefPtr<T>& field, const char* name,
328 uint32_t flags = 0) {
329 CycleCollectionNoteChild(callback, field.get(), name, flags);
332 #endif