LCOV - code coverage report
Current view: top level - dom/canvas - WebGLObjectModel.h (source / functions) Hit Total Coverage
Test: output.info Lines: 0 95 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 205 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13