Thu, 15 Jan 2015 21:03:48 +0100
Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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"
10 #include "nsICanvasRenderingContextInternal.h"
11 #include "WebGLTypes.h"
13 namespace mozilla {
15 class WebGLBuffer;
16 class WebGLContext;
18 /* Each WebGL object class WebGLFoo wants to:
19 * - inherit WebGLRefCountedObject<WebGLFoo>
20 * - implement a Delete() method
21 * - have its destructor call DeleteOnce()
22 *
23 * This base class provides two features to WebGL object types:
24 * 1. support for OpenGL object reference counting
25 * 2. support for OpenGL deletion statuses
26 *
27 ***** 1. OpenGL object reference counting *****
28 *
29 * WebGL objects such as WebGLTexture's really have two different refcounts:
30 * the XPCOM refcount, that is directly exposed to JavaScript, and the OpenGL
31 * refcount.
32 *
33 * For example, when in JavaScript one does: var newname = existingTexture;
34 * that increments the XPCOM refcount, but doesn't affect the OpenGL refcount.
35 * When one attaches the texture to a framebuffer object, that does increment
36 * its OpenGL refcount (and also its XPCOM refcount, to prevent the regular
37 * XPCOM refcounting mechanism from destroying objects prematurely).
38 *
39 * The actual OpenGL refcount is opaque to us (it's internal to the OpenGL
40 * implementation) but is affects the WebGL semantics that we have to implement:
41 * for example, a WebGLTexture that is attached to a WebGLFramebuffer must not
42 * be actually deleted, even if deleteTexture has been called on it, and even
43 * if JavaScript doesn't have references to it anymore. We can't just rely on
44 * OpenGL to keep alive the underlying OpenGL texture for us, for a variety of
45 * reasons, most importantly: we'd need to know when OpenGL objects are actually
46 * deleted, and OpenGL doesn't notify us about that, so we would have to query
47 * status very often with glIsXxx calls which isn't practical.
48 *
49 * This means that we have to keep track of the OpenGL refcount ourselves,
50 * in addition to the XPCOM refcount.
51 *
52 * This class implements such a refcount, see the mWebGLRefCnt
53 * member. In order to avoid name clashes (with regular XPCOM refcounting)
54 * in the derived class, we prefix members with 'WebGL', whence the names
55 * WebGLAddRef, WebGLRelease, etc.
56 *
57 * In practice, WebGLAddRef and WebGLRelease are only called from the
58 * WebGLRefPtr class.
59 *
60 ***** 2. OpenGL deletion statuses *****
61 *
62 * In OpenGL, an object can go through 3 different deletion statuses during its
63 * lifetime, which correspond to the 3 enum values for DeletionStatus in this class:
64 * - the Default status, which it has from its creation to when the
65 * suitable glDeleteXxx function is called on it;
66 * - the DeleteRequested status, which is has from when the suitable glDeleteXxx
67 * function is called on it to when it is no longer referenced by other OpenGL
68 * objects. For example, a texture that is attached to a non-current FBO
69 * will enter that status when glDeleteTexture is called on it. For objects
70 * with that status, GL_DELETE_STATUS queries return true, but glIsXxx
71 * functions still return true.
72 * - the Deleted status, which is the status of objects on which the
73 * suitable glDeleteXxx function has been called, and that are not referenced
74 * by other OpenGL objects.
75 *
76 * This state is stored in the mDeletionStatus member of this class.
77 *
78 * When the GL refcount hits zero, if the status is DeleteRequested then we call
79 * the Delete() method on the derived class and the status becomes Deleted. This is
80 * what the MaybeDelete() function does.
81 *
82 * The DeleteOnce() function implemented here is a helper to ensure that we don't
83 * call Delete() twice on the same object. Since the derived class' destructor
84 * needs to call DeleteOnce() which calls Delete(), we can't allow either to be
85 * virtual. Strictly speaking, we could let them be virtual if the derived class
86 * were final, but that would be impossible to enforce and would lead to strange
87 * bugs if it were subclassed.
88 *
89 * This WebGLRefCountedObject class takes the Derived type
90 * as template parameter, as a means to allow DeleteOnce to call Delete()
91 * on the Derived class, without either method being virtual. This is a common
92 * C++ pattern known as the "curiously recursive template pattern (CRTP)".
93 */
94 template<typename Derived>
95 class WebGLRefCountedObject
96 {
97 public:
98 enum DeletionStatus { Default, DeleteRequested, Deleted };
100 WebGLRefCountedObject()
101 : mDeletionStatus(Default)
102 { }
104 ~WebGLRefCountedObject() {
105 MOZ_ASSERT(mWebGLRefCnt == 0, "destroying WebGL object still referenced by other WebGL objects");
106 MOZ_ASSERT(mDeletionStatus == Deleted, "Derived class destructor must call DeleteOnce()");
107 }
109 // called by WebGLRefPtr
110 void WebGLAddRef() {
111 ++mWebGLRefCnt;
112 }
114 // called by WebGLRefPtr
115 void WebGLRelease() {
116 MOZ_ASSERT(mWebGLRefCnt > 0, "releasing WebGL object with WebGL refcnt already zero");
117 --mWebGLRefCnt;
118 MaybeDelete();
119 }
121 // this is the function that WebGL.deleteXxx() functions want to call
122 void RequestDelete() {
123 if (mDeletionStatus == Default)
124 mDeletionStatus = DeleteRequested;
125 MaybeDelete();
126 }
128 bool IsDeleted() const {
129 return mDeletionStatus == Deleted;
130 }
132 bool IsDeleteRequested() const {
133 return mDeletionStatus != Default;
134 }
136 void DeleteOnce() {
137 if (mDeletionStatus != Deleted) {
138 static_cast<Derived*>(this)->Delete();
139 mDeletionStatus = Deleted;
140 }
141 }
143 private:
144 void MaybeDelete() {
145 if (mWebGLRefCnt == 0 &&
146 mDeletionStatus == DeleteRequested)
147 {
148 DeleteOnce();
149 }
150 }
152 protected:
153 nsAutoRefCnt mWebGLRefCnt;
154 DeletionStatus mDeletionStatus;
155 };
157 /* This WebGLRefPtr class is meant to be used for references between WebGL objects.
158 * For example, a WebGLProgram holds WebGLRefPtr's to the WebGLShader's attached
159 * to it.
160 *
161 * Why the need for a separate refptr class? The only special thing that WebGLRefPtr
162 * does is that it increments and decrements the WebGL refcount of
163 * WebGLRefCountedObject's, in addition to incrementing and decrementing the
164 * usual XPCOM refcount.
165 *
166 * This means that by using a WebGLRefPtr instead of a nsRefPtr, you ensure that
167 * the WebGL refcount is incremented, which means that the object will be kept
168 * alive by this reference even if the matching webgl.deleteXxx() function is
169 * called on it.
170 */
171 template<typename T>
172 class WebGLRefPtr
173 {
174 public:
175 WebGLRefPtr()
176 : mRawPtr(0)
177 { }
179 WebGLRefPtr(const WebGLRefPtr<T>& aSmartPtr)
180 : mRawPtr(aSmartPtr.mRawPtr)
181 {
182 AddRefOnPtr(mRawPtr);
183 }
185 WebGLRefPtr(T *aRawPtr)
186 : mRawPtr(aRawPtr)
187 {
188 AddRefOnPtr(mRawPtr);
189 }
191 ~WebGLRefPtr() {
192 ReleasePtr(mRawPtr);
193 }
195 WebGLRefPtr<T>&
196 operator=(const WebGLRefPtr<T>& rhs)
197 {
198 assign_with_AddRef(rhs.mRawPtr);
199 return *this;
200 }
202 WebGLRefPtr<T>&
203 operator=(T* rhs)
204 {
205 assign_with_AddRef(rhs);
206 return *this;
207 }
209 T* get() const {
210 return static_cast<T*>(mRawPtr);
211 }
213 operator T*() const {
214 return get();
215 }
217 T* operator->() const {
218 MOZ_ASSERT(mRawPtr != 0, "You can't dereference a nullptr WebGLRefPtr with operator->()!");
219 return get();
220 }
222 T& operator*() const {
223 MOZ_ASSERT(mRawPtr != 0, "You can't dereference a nullptr WebGLRefPtr with operator*()!");
224 return *get();
225 }
227 private:
229 static void AddRefOnPtr(T* rawPtr) {
230 if (rawPtr) {
231 rawPtr->WebGLAddRef();
232 rawPtr->AddRef();
233 }
234 }
236 static void ReleasePtr(T* rawPtr) {
237 if (rawPtr) {
238 rawPtr->WebGLRelease(); // must be done first before Release(), as Release() might actually destroy the object
239 rawPtr->Release();
240 }
241 }
243 void assign_with_AddRef(T* rawPtr) {
244 AddRefOnPtr(rawPtr);
245 assign_assuming_AddRef(rawPtr);
246 }
248 void assign_assuming_AddRef(T* newPtr) {
249 T* oldPtr = mRawPtr;
250 mRawPtr = newPtr;
251 ReleasePtr(oldPtr);
252 }
254 protected:
255 T *mRawPtr;
256 };
258 // This class is a mixin for objects that are tied to a specific
259 // context (which is to say, all of them). They provide initialization
260 // as well as comparison with the current context.
261 class WebGLContextBoundObject
262 {
263 public:
264 WebGLContextBoundObject(WebGLContext *context);
266 bool IsCompatibleWithContext(WebGLContext *other);
268 WebGLContext *Context() const { return mContext; }
270 protected:
271 WebGLContext *mContext;
272 uint32_t mContextGeneration;
273 };
275 // this class is a mixin for GL objects that have dimensions
276 // that we need to track.
277 class WebGLRectangleObject
278 {
279 public:
280 WebGLRectangleObject()
281 : mWidth(0), mHeight(0) { }
283 WebGLRectangleObject(GLsizei width, GLsizei height)
284 : mWidth(width), mHeight(height) { }
286 GLsizei Width() const { return mWidth; }
287 void width(GLsizei value) { mWidth = value; }
289 GLsizei Height() const { return mHeight; }
290 void height(GLsizei value) { mHeight = value; }
292 void setDimensions(GLsizei width, GLsizei height) {
293 mWidth = width;
294 mHeight = height;
295 }
297 void setDimensions(WebGLRectangleObject *rect) {
298 if (rect) {
299 mWidth = rect->Width();
300 mHeight = rect->Height();
301 } else {
302 mWidth = 0;
303 mHeight = 0;
304 }
305 }
307 bool HasSameDimensionsAs(const WebGLRectangleObject& other) const {
308 return Width() == other.Width() && Height() == other.Height();
309 }
311 protected:
312 GLsizei mWidth;
313 GLsizei mHeight;
314 };
316 }// namespace mozilla
318 template <typename T>
319 inline void
320 ImplCycleCollectionUnlink(mozilla::WebGLRefPtr<T>& aField)
321 {
322 aField = nullptr;
323 }
325 template <typename T>
326 inline void
327 ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
328 mozilla::WebGLRefPtr<T>& aField,
329 const char* aName,
330 uint32_t aFlags = 0)
331 {
332 CycleCollectionNoteChild(aCallback, aField.get(), aName, aFlags);
333 }
335 #endif