123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377 |
- /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
- /* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
- #ifndef WEBGLOBJECTMODEL_H_
- #define WEBGLOBJECTMODEL_H_
- #include "mozilla/WeakPtr.h"
- #include "nsCycleCollectionNoteChild.h"
- #include "WebGLTypes.h"
- namespace mozilla {
- template<typename> class LinkedList;
- class WebGLContext;
- ////
- // This class is a mixin for objects that are tied to a specific
- // context (which is to say, all of them). They provide initialization
- // as well as comparison with the current context.
- class WebGLContextBoundObject
- {
- public:
- const WeakPtr<WebGLContext> mContext;
- private:
- const uint32_t mContextGeneration;
- public:
- explicit WebGLContextBoundObject(WebGLContext* webgl);
- bool IsCompatibleWithContext(const WebGLContext* other) const;
- };
- ////
- class WebGLDeletableObject : public WebGLContextBoundObject
- {
- template<typename> friend class WebGLRefCountedObject;
- private:
- enum DeletionStatus { Default, DeleteRequested, Deleted };
- DeletionStatus mDeletionStatus;
- ////
- explicit WebGLDeletableObject(WebGLContext* webgl)
- : WebGLContextBoundObject(webgl)
- , mDeletionStatus(Default)
- { }
- ~WebGLDeletableObject() {
- MOZ_ASSERT(mDeletionStatus == Deleted,
- "Derived class destructor must call DeleteOnce().");
- }
- public:
- bool IsDeleted() const { return mDeletionStatus == Deleted; }
- bool IsDeleteRequested() const { return mDeletionStatus != Default; }
- };
- /* Each WebGL object class WebGLFoo wants to:
- * - inherit WebGLRefCountedObject<WebGLFoo>
- * - implement a Delete() method
- * - have its destructor call DeleteOnce()
- *
- * This base class provides two features to WebGL object types:
- * 1. support for OpenGL object reference counting
- * 2. support for OpenGL deletion statuses
- *
- ***** 1. OpenGL object reference counting *****
- *
- * WebGL objects such as WebGLTexture's really have two different refcounts:
- * the XPCOM refcount, that is directly exposed to JavaScript, and the OpenGL
- * refcount.
- *
- * For example, when in JavaScript one does: var newname = existingTexture;
- * that increments the XPCOM refcount, but doesn't affect the OpenGL refcount.
- * When one attaches the texture to a framebuffer object, that does increment
- * its OpenGL refcount (and also its XPCOM refcount, to prevent the regular
- * XPCOM refcounting mechanism from destroying objects prematurely).
- *
- * The actual OpenGL refcount is opaque to us (it's internal to the OpenGL
- * implementation) but is affects the WebGL semantics that we have to implement:
- * for example, a WebGLTexture that is attached to a WebGLFramebuffer must not
- * be actually deleted, even if deleteTexture has been called on it, and even
- * if JavaScript doesn't have references to it anymore. We can't just rely on
- * OpenGL to keep alive the underlying OpenGL texture for us, for a variety of
- * reasons, most importantly: we'd need to know when OpenGL objects are actually
- * deleted, and OpenGL doesn't notify us about that, so we would have to query
- * status very often with glIsXxx calls which isn't practical.
- *
- * This means that we have to keep track of the OpenGL refcount ourselves,
- * in addition to the XPCOM refcount.
- *
- * This class implements such a refcount, see the mWebGLRefCnt
- * member. In order to avoid name clashes (with regular XPCOM refcounting)
- * in the derived class, we prefix members with 'WebGL', whence the names
- * WebGLAddRef, WebGLRelease, etc.
- *
- * In practice, WebGLAddRef and WebGLRelease are only called from the
- * WebGLRefPtr class.
- *
- ***** 2. OpenGL deletion statuses *****
- *
- * In OpenGL, an object can go through 3 different deletion statuses during its
- * lifetime, which correspond to the 3 enum values for DeletionStatus in this
- * class:
- * - the Default status, which it has from its creation to when the suitable
- * glDeleteXxx function is called on it;
- * - the DeleteRequested status, which is has from when the suitable
- * glDeleteXxx function is called on it to when it is no longer referenced by
- * other OpenGL objects. For example, a texture that is attached to a
- * non-current FBO will enter that status when glDeleteTexture is called on
- * it. For objects with that status, GL_DELETE_STATUS queries return true,
- * but glIsXxx functions still return true.
- * - the Deleted status, which is the status of objects on which the suitable
- * glDeleteXxx function has been called, and that are not referenced by other
- * OpenGL objects.
- *
- * This state is stored in the mDeletionStatus member of this class.
- *
- * When the GL refcount hits zero, if the status is DeleteRequested then we call
- * the Delete() method on the derived class and the status becomes Deleted. This
- * is what the MaybeDelete() function does.
- *
- * The DeleteOnce() function implemented here is a helper to ensure that we
- * don't call Delete() twice on the same object. Since the derived class's
- * destructor needs to call DeleteOnce() which calls Delete(), we can't allow
- * either to be virtual. Strictly speaking, we could let them be virtual if the
- * derived class were final, but that would be impossible to enforce and would
- * lead to strange bugs if it were subclassed.
- *
- * This WebGLRefCountedObject class takes the Derived type as template
- * parameter, as a means to allow DeleteOnce to call Delete() on the Derived
- * class, without either method being virtual. This is a common C++ pattern
- * known as the "curiously recursive template pattern (CRTP)".
- */
- template<typename Derived>
- class WebGLRefCountedObject : public WebGLDeletableObject
- {
- friend class WebGLContext;
- template<typename T> friend void ClearLinkedList(LinkedList<T>& list);
- private:
- nsAutoRefCnt mWebGLRefCnt;
- public:
- explicit WebGLRefCountedObject(WebGLContext* webgl)
- : WebGLDeletableObject(webgl)
- { }
- ~WebGLRefCountedObject() {
- MOZ_ASSERT(mWebGLRefCnt == 0,
- "Destroying WebGL object still referenced by other WebGL"
- " objects.");
- }
- // called by WebGLRefPtr
- void WebGLAddRef() {
- ++mWebGLRefCnt;
- }
- // called by WebGLRefPtr
- void WebGLRelease() {
- MOZ_ASSERT(mWebGLRefCnt > 0,
- "Releasing WebGL object with WebGL refcnt already zero");
- --mWebGLRefCnt;
- MaybeDelete();
- }
- // this is the function that WebGL.deleteXxx() functions want to call
- void RequestDelete() {
- if (mDeletionStatus == Default)
- mDeletionStatus = DeleteRequested;
- MaybeDelete();
- }
- protected:
- void DeleteOnce() {
- if (mDeletionStatus != Deleted) {
- static_cast<Derived*>(this)->Delete();
- mDeletionStatus = Deleted;
- }
- }
- private:
- void MaybeDelete() {
- if (mWebGLRefCnt == 0 &&
- mDeletionStatus == DeleteRequested)
- {
- DeleteOnce();
- }
- }
- };
- /* This WebGLRefPtr class is meant to be used for references between WebGL
- * objects. For example, a WebGLProgram holds WebGLRefPtr's to the WebGLShader's
- * attached to it.
- *
- * Why the need for a separate refptr class? The only special thing that
- * WebGLRefPtr does is that it increments and decrements the WebGL refcount of
- * WebGLRefCountedObject's, in addition to incrementing and decrementing the
- * usual XPCOM refcount.
- *
- * This means that by using a WebGLRefPtr instead of a nsRefPtr, you ensure that
- * the WebGL refcount is incremented, which means that the object will be kept
- * alive by this reference even if the matching webgl.deleteXxx() function is
- * called on it.
- */
- template<typename T>
- class WebGLRefPtr
- {
- public:
- WebGLRefPtr()
- : mRawPtr(0)
- {}
- WebGLRefPtr(const WebGLRefPtr<T>& smartPtr)
- : mRawPtr(smartPtr.mRawPtr)
- {
- AddRefOnPtr(mRawPtr);
- }
- explicit WebGLRefPtr(T* rawPtr)
- : mRawPtr(rawPtr)
- {
- AddRefOnPtr(mRawPtr);
- }
- ~WebGLRefPtr() {
- ReleasePtr(mRawPtr);
- }
- WebGLRefPtr<T>&
- operator=(const WebGLRefPtr<T>& rhs)
- {
- assign_with_AddRef(rhs.mRawPtr);
- return *this;
- }
- WebGLRefPtr<T>&
- operator=(T* rhs)
- {
- assign_with_AddRef(rhs);
- return *this;
- }
- T* get() const {
- return static_cast<T*>(mRawPtr);
- }
- operator T*() const {
- return get();
- }
- T* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN {
- MOZ_ASSERT(mRawPtr != 0, "You can't dereference a nullptr WebGLRefPtr with operator->()!");
- return get();
- }
- T& operator*() const {
- MOZ_ASSERT(mRawPtr != 0, "You can't dereference a nullptr WebGLRefPtr with operator*()!");
- return *get();
- }
- private:
- static void AddRefOnPtr(T* rawPtr) {
- if (rawPtr) {
- rawPtr->WebGLAddRef();
- rawPtr->AddRef();
- }
- }
- static void ReleasePtr(T* rawPtr) {
- if (rawPtr) {
- rawPtr->WebGLRelease(); // must be done first before Release(), as Release() might actually destroy the object
- rawPtr->Release();
- }
- }
- void assign_with_AddRef(T* rawPtr) {
- AddRefOnPtr(rawPtr);
- assign_assuming_AddRef(rawPtr);
- }
- void assign_assuming_AddRef(T* newPtr) {
- T* oldPtr = mRawPtr;
- mRawPtr = newPtr;
- ReleasePtr(oldPtr);
- }
- protected:
- T* mRawPtr;
- };
- // this class is a mixin for GL objects that have dimensions
- // that we need to track.
- class WebGLRectangleObject
- {
- public:
- WebGLRectangleObject()
- : mWidth(0)
- , mHeight(0)
- {}
- WebGLRectangleObject(GLsizei width, GLsizei height)
- : mWidth(width)
- , mHeight(height)
- {}
- GLsizei Width() const { return mWidth; }
- void width(GLsizei value) { mWidth = value; }
- GLsizei Height() const { return mHeight; }
- void height(GLsizei value) { mHeight = value; }
- void setDimensions(GLsizei width, GLsizei height) {
- mWidth = width;
- mHeight = height;
- }
- void setDimensions(WebGLRectangleObject* rect) {
- if (rect) {
- mWidth = rect->Width();
- mHeight = rect->Height();
- } else {
- mWidth = 0;
- mHeight = 0;
- }
- }
- bool HasSameDimensionsAs(const WebGLRectangleObject& other) const {
- return Width() == other.Width() && Height() == other.Height();
- }
- protected:
- GLsizei mWidth;
- GLsizei mHeight;
- };
- }// namespace mozilla
- template <typename T>
- inline void
- ImplCycleCollectionUnlink(mozilla::WebGLRefPtr<T>& field)
- {
- field = nullptr;
- }
- template <typename T>
- inline void
- ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& callback,
- mozilla::WebGLRefPtr<T>& field,
- const char* name,
- uint32_t flags = 0)
- {
- CycleCollectionNoteChild(callback, field.get(), name, flags);
- }
- template <typename T>
- inline void
- ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& callback,
- const mozilla::WebGLRefPtr<T>& field,
- const char* name,
- uint32_t flags = 0)
- {
- CycleCollectionNoteChild(callback, field.get(), name, flags);
- }
- #endif
|