From 5f8de423f190bbb79a62f804151bc24824fa32d8 Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Fri, 2 Feb 2018 04:16:08 -0500 Subject: Add m-esr52 at 52.6.0 --- dom/canvas/WebGLObjectModel.h | 365 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 365 insertions(+) create mode 100644 dom/canvas/WebGLObjectModel.h (limited to 'dom/canvas/WebGLObjectModel.h') diff --git a/dom/canvas/WebGLObjectModel.h b/dom/canvas/WebGLObjectModel.h new file mode 100644 index 000000000..e19d2fd8e --- /dev/null +++ b/dom/canvas/WebGLObjectModel.h @@ -0,0 +1,365 @@ +/* -*- 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 "nsCycleCollectionNoteChild.h" + +#include "WebGLTypes.h" + +namespace mozilla { + +template 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: + WebGLContext* const mContext; +private: + const uint32_t mContextGeneration; + +public: + explicit WebGLContextBoundObject(WebGLContext* webgl); + + bool IsCompatibleWithContext(const WebGLContext* other) const; +}; + +//// + +class WebGLDeletableObject : public WebGLContextBoundObject +{ + template 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 + * - 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 +class WebGLRefCountedObject : public WebGLDeletableObject +{ + friend class WebGLContext; + template friend void ClearLinkedList(LinkedList& 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(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 +class WebGLRefPtr +{ +public: + WebGLRefPtr() + : mRawPtr(0) + {} + + WebGLRefPtr(const WebGLRefPtr& smartPtr) + : mRawPtr(smartPtr.mRawPtr) + { + AddRefOnPtr(mRawPtr); + } + + explicit WebGLRefPtr(T* rawPtr) + : mRawPtr(rawPtr) + { + AddRefOnPtr(mRawPtr); + } + + ~WebGLRefPtr() { + ReleasePtr(mRawPtr); + } + + WebGLRefPtr& + operator=(const WebGLRefPtr& rhs) + { + assign_with_AddRef(rhs.mRawPtr); + return *this; + } + + WebGLRefPtr& + operator=(T* rhs) + { + assign_with_AddRef(rhs); + return *this; + } + + T* get() const { + return static_cast(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 +inline void +ImplCycleCollectionUnlink(mozilla::WebGLRefPtr& field) +{ + field = nullptr; +} + +template +inline void +ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& callback, + const mozilla::WebGLRefPtr& field, + const char* name, + uint32_t flags = 0) +{ + CycleCollectionNoteChild(callback, field.get(), name, flags); +} + +#endif -- cgit v1.2.3