content/canvas/src/WebGLObjectModel.h

Thu, 15 Jan 2015 21:03:48 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 21:03:48 +0100
branch
TOR_BUG_9701
changeset 11
deefc01c0e14
permissions
-rw-r--r--

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.)

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

mercurial