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

     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

mercurial