author | Benoit Jacob <bjacob@mozilla.com> |
Sun, 04 Dec 2011 14:15:42 -0500 | |
changeset 81406 | e8de56f450c95cc9b4d7f77b1950535e1764ed6a |
parent 81405 | 539c05fd263cdd8362c8531d1f78c93e4539fad1 |
child 81407 | 9d44f155bdbb2bba1a54efab894137c4954532d3 |
push id | 21570 |
push user | mbrubeck@mozilla.com |
push date | Mon, 05 Dec 2011 18:08:26 +0000 |
treeherder | mozilla-central@fafaf614791f [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | jgilbert |
bugs | 704839 |
milestone | 11.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/content/canvas/src/WebGLContext.cpp +++ b/content/canvas/src/WebGLContext.cpp @@ -309,107 +309,56 @@ WebGLContext::WebGLContext() WebGLContext::~WebGLContext() { DestroyResourcesAndContext(); WebGLMemoryReporter::RemoveWebGLContext(this); TerminateRobustnessTimer(); mContextRestorer = nsnull; } +template<typename WebGLObjectType> static PLDHashOperator -DeleteTextureFunction(const PRUint32& aKey, WebGLTexture *aValue, void *aData) +WebGLObjectDeleteFunction(const PRUint32& aKey, WebGLObjectType *aValue, void *) { - gl::GLContext *gl = (gl::GLContext *) aData; - NS_ASSERTION(!aValue->Deleted(), "Texture is still in mMapTextures, but is deleted?"); - GLuint name = aValue->GLName(); - gl->fDeleteTextures(1, &name); - aValue->Delete(); - return PL_DHASH_NEXT; -} - -static PLDHashOperator -DeleteBufferFunction(const PRUint32& aKey, WebGLBuffer *aValue, void *aData) -{ - gl::GLContext *gl = (gl::GLContext *) aData; - NS_ASSERTION(!aValue->Deleted(), "Buffer is still in mMapBuffers, but is deleted?"); - GLuint name = aValue->GLName(); - gl->fDeleteBuffers(1, &name); - aValue->Delete(); + aValue->DeleteOnce(); return PL_DHASH_NEXT; } -static PLDHashOperator -DeleteFramebufferFunction(const PRUint32& aKey, WebGLFramebuffer *aValue, void *aData) -{ - gl::GLContext *gl = (gl::GLContext *) aData; - NS_ASSERTION(!aValue->Deleted(), "Framebuffer is still in mMapFramebuffers, but is deleted?"); - GLuint name = aValue->GLName(); - gl->fDeleteFramebuffers(1, &name); - aValue->Delete(); - return PL_DHASH_NEXT; -} - -static PLDHashOperator -DeleteRenderbufferFunction(const PRUint32& aKey, WebGLRenderbuffer *aValue, void *aData) +template<typename WebGLObjectType> +void +DeleteWebGLObjectsHashTable(nsRefPtrHashtable<nsUint32HashKey, WebGLObjectType>& table) { - gl::GLContext *gl = (gl::GLContext *) aData; - NS_ASSERTION(!aValue->Deleted(), "Renderbuffer is still in mMapRenderbuffers, but is deleted?"); - GLuint name = aValue->GLName(); - gl->fDeleteRenderbuffers(1, &name); - aValue->Delete(); - return PL_DHASH_NEXT; -} - -static PLDHashOperator -DeleteProgramFunction(const PRUint32& aKey, WebGLProgram *aValue, void *aData) -{ - gl::GLContext *gl = (gl::GLContext *) aData; - NS_ASSERTION(!aValue->Deleted(), "Program is still in mMapPrograms, but is deleted?"); - GLuint name = aValue->GLName(); - gl->fDeleteProgram(name); - aValue->Delete(); - return PL_DHASH_NEXT; -} - -static PLDHashOperator -DeleteShaderFunction(const PRUint32& aKey, WebGLShader *aValue, void *aData) -{ - gl::GLContext *gl = (gl::GLContext *) aData; - NS_ASSERTION(!aValue->Deleted(), "Shader is still in mMapShaders, but is deleted?"); - GLuint name = aValue->GLName(); - gl->fDeleteShader(name); - aValue->Delete(); - return PL_DHASH_NEXT; + table.EnumerateRead(WebGLObjectDeleteFunction<WebGLObjectType>, nsnull); + table.Clear(); } void WebGLContext::DestroyResourcesAndContext() { if (!gl) return; gl->MakeCurrent(); - mMapTextures.EnumerateRead(DeleteTextureFunction, gl); - mMapTextures.Clear(); - - mMapBuffers.EnumerateRead(DeleteBufferFunction, gl); - mMapBuffers.Clear(); - - mMapPrograms.EnumerateRead(DeleteProgramFunction, gl); - mMapPrograms.Clear(); + mBound2DTextures.Clear(); + mBoundCubeMapTextures.Clear(); + mBoundArrayBuffer = nsnull; + mBoundElementArrayBuffer = nsnull; + mCurrentProgram = nsnull; + mBoundFramebuffer = nsnull; + mBoundRenderbuffer = nsnull; - mMapShaders.EnumerateRead(DeleteShaderFunction, gl); - mMapShaders.Clear(); + mAttribBuffers.Clear(); - mMapFramebuffers.EnumerateRead(DeleteFramebufferFunction, gl); - mMapFramebuffers.Clear(); - - mMapRenderbuffers.EnumerateRead(DeleteRenderbufferFunction, gl); - mMapRenderbuffers.Clear(); + DeleteWebGLObjectsHashTable(mMapTextures); + DeleteWebGLObjectsHashTable(mMapRenderbuffers); + DeleteWebGLObjectsHashTable(mMapFramebuffers); + DeleteWebGLObjectsHashTable(mMapBuffers); + DeleteWebGLObjectsHashTable(mMapShaders); + DeleteWebGLObjectsHashTable(mMapPrograms); if (mBlackTexturesAreInitialized) { gl->fDeleteTextures(1, &mBlackTexture2D); gl->fDeleteTextures(1, &mBlackTextureCubeMap); mBlackTexturesAreInitialized = false; } if (mFakeVertexAttrib0BufferObject) {
--- a/content/canvas/src/WebGLContext.h +++ b/content/canvas/src/WebGLContext.h @@ -90,16 +90,17 @@ namespace mozilla { class WebGLTexture; class WebGLBuffer; class WebGLProgram; class WebGLShader; class WebGLFramebuffer; class WebGLRenderbuffer; class WebGLUniformLocation; class WebGLExtension; +class WebGLVertexAttribData; template<int PreallocatedOwnersCapacity> class WebGLZeroingObject; class WebGLContextBoundObject; enum FakeBlackStatus { DoNotNeedFakeBlack, DoNeedFakeBlack, DontKnowIfNeedFakeBlack }; struct VertexAttrib0Status { enum { Default, EmulatedUninitializedArray, EmulatedInitializedArray }; @@ -495,26 +496,24 @@ private: mRawPtr = newPtr; if (oldPtr) { oldPtr->RemoveRefOwner(this); oldPtr->Release(); } } }; -class WebGLBuffer; - struct WebGLVertexAttribData { // note that these initial values are what GL initializes vertex attribs to WebGLVertexAttribData() : buf(0), stride(0), size(4), byteOffset(0), type(LOCAL_GL_FLOAT), enabled(false), normalized(false) { } - WebGLObjectRefPtr<WebGLBuffer> buf; + WebGLRefPtr<WebGLBuffer> buf; WebGLuint stride; WebGLuint size; GLuint byteOffset; GLenum type; bool enabled; bool normalized; GLuint componentSize() const { @@ -542,16 +541,17 @@ struct WebGLVertexAttribData { } GLuint actualStride() const { if (stride) return stride; return size * componentSize(); } }; + struct WebGLContextOptions { // these are defaults WebGLContextOptions() : alpha(true), depth(true), stencil(false), premultipliedAlpha(true), antialias(true), preserveDrawingBuffer(false) { } @@ -915,32 +915,28 @@ protected: void MaybeRestoreContext(); void ForceLoseContext(); void ForceRestoreContext(); // the buffers bound to the current program's attribs nsTArray<WebGLVertexAttribData> mAttribBuffers; - - // textures bound to - nsTArray<WebGLObjectRefPtr<WebGLTexture> > mBound2DTextures; - nsTArray<WebGLObjectRefPtr<WebGLTexture> > mBoundCubeMapTextures; - - WebGLObjectRefPtr<WebGLBuffer> mBoundArrayBuffer; - WebGLObjectRefPtr<WebGLBuffer> mBoundElementArrayBuffer; - // note nsRefPtr -- this stays alive even after being deleted, - // and is only explicitly removed from the current state via - // a call to UseProgram. - nsRefPtr<WebGLProgram> mCurrentProgram; + nsTArray<WebGLRefPtr<WebGLTexture> > mBound2DTextures; + nsTArray<WebGLRefPtr<WebGLTexture> > mBoundCubeMapTextures; + + WebGLRefPtr<WebGLBuffer> mBoundArrayBuffer; + WebGLRefPtr<WebGLBuffer> mBoundElementArrayBuffer; + + WebGLRefPtr<WebGLProgram> mCurrentProgram; PRUint32 mMaxFramebufferColorAttachments; - nsRefPtr<WebGLFramebuffer> mBoundFramebuffer; - nsRefPtr<WebGLRenderbuffer> mBoundRenderbuffer; + WebGLRefPtr<WebGLFramebuffer> mBoundFramebuffer; + WebGLRefPtr<WebGLRenderbuffer> mBoundRenderbuffer; // lookup tables for GL name -> object wrapper nsRefPtrHashtable<nsUint32HashKey, WebGLTexture> mMapTextures; nsRefPtrHashtable<nsUint32HashKey, WebGLBuffer> mMapBuffers; nsRefPtrHashtable<nsUint32HashKey, WebGLProgram> mMapPrograms; nsRefPtrHashtable<nsUint32HashKey, WebGLShader> mMapShaders; nsRefPtrHashtable<nsUint32HashKey, WebGLFramebuffer> mMapFramebuffers; nsRefPtrHashtable<nsUint32HashKey, WebGLRenderbuffer> mMapRenderbuffers; @@ -983,17 +979,20 @@ public: // console logging helpers static void LogMessage(const char *fmt, ...); static void LogMessage(const char *fmt, va_list ap); void LogMessageIfVerbose(const char *fmt, ...); void LogMessageIfVerbose(const char *fmt, va_list ap); friend class WebGLTexture; friend class WebGLFramebuffer; + friend class WebGLRenderbuffer; friend class WebGLProgram; + friend class WebGLBuffer; + friend class WebGLShader; }; // this class is a mixin for the named type wrappers, and is used // by WebGLObjectRefPtr to tell the object who holds references, so that // we can zero them out appropriately when the object is deleted, because // it will be unbound in the GL. // // PreallocatedOwnersCapacity is the preallocated capacity for the array of refptrs to owners. @@ -1022,16 +1021,18 @@ public: owners[i]->Zero(); } mRefOwners.Clear(); } protected: nsAutoTArray<WebGLObjectBaseRefPtr *, PreallocatedOwnersCapacity> mRefOwners; + friend class WebGLShader; + friend class WebGLBuffer; }; // this class is a mixin for GL objects that have dimensions // that we need to track. class WebGLRectangleObject { protected: WebGLRectangleObject() @@ -1084,45 +1085,45 @@ public: mContextGeneration == other->Generation(); } protected: WebGLContext *mContext; PRUint32 mContextGeneration; }; -class WebGLBuffer : - public nsIWebGLBuffer, - public WebGLZeroingObject<8>, // almost never has more than 8 owners - public WebGLContextBoundObject +class WebGLBuffer + : public nsIWebGLBuffer + , public WebGLRefCountedObject<WebGLBuffer> + , public WebGLContextBoundObject { public: - WebGLBuffer(WebGLContext *context, WebGLuint name) : - WebGLContextBoundObject(context), - mGLName(name), mDeleted(false), mHasEverBeenBound(false), - mByteLength(0), mTarget(LOCAL_GL_NONE), mData(nsnull) - {} + WebGLBuffer(WebGLContext *context) + : WebGLContextBoundObject(context) + , mHasEverBeenBound(false) + , mByteLength(0) + , mTarget(LOCAL_GL_NONE) + , mData(nsnull) + { + mContext->MakeContextCurrent(); + mContext->gl->fGenBuffers(1, &mGLName); + } ~WebGLBuffer() { - Delete(); + DeleteOnce(); } void Delete() { - if (mDeleted) - return; - ZeroOwners(); - + mContext->MakeContextCurrent(); + mContext->gl->fDeleteBuffers(1, &mGLName); free(mData); mData = nsnull; - - mDeleted = true; mByteLength = 0; } - bool Deleted() const { return mDeleted; } bool HasEverBeenBound() { return mHasEverBeenBound; } void SetHasEverBeenBound(bool x) { mHasEverBeenBound = x; } GLuint GLName() const { return mGLName; } GLuint ByteLength() const { return mByteLength; } GLenum Target() const { return mTarget; } const void *Data() const { return mData; } void SetByteLength(GLuint byteLength) { mByteLength = byteLength; } @@ -1199,74 +1200,78 @@ public: mHasCachedMaxUshortElement = true; mCachedMaxUshortElement = FindMaxElementInSubArray<GLshort>(mByteLength>>1, 0); return mCachedMaxUshortElement; } } NS_DECL_ISUPPORTS NS_DECL_NSIWEBGLBUFFER + protected: + WebGLuint mGLName; - bool mDeleted; bool mHasEverBeenBound; GLuint mByteLength; GLenum mTarget; PRUint8 mCachedMaxUbyteElement; bool mHasCachedMaxUbyteElement; PRUint16 mCachedMaxUshortElement; bool mHasCachedMaxUshortElement; void* mData; // in the case of an Element Array Buffer, we keep a copy. }; - -class WebGLTexture : - public nsIWebGLTexture, - public WebGLZeroingObject<8>, // almost never has more than 8 owners - public WebGLContextBoundObject +class WebGLTexture + : public nsIWebGLTexture + , public WebGLRefCountedObject<WebGLTexture> + , public WebGLContextBoundObject { public: - - WebGLTexture(WebGLContext *context, WebGLuint name) : - WebGLContextBoundObject(context), - mDeleted(false), mHasEverBeenBound(false), mGLName(name), - mTarget(0), - mMinFilter(LOCAL_GL_NEAREST_MIPMAP_LINEAR), - mMagFilter(LOCAL_GL_LINEAR), - mWrapS(LOCAL_GL_REPEAT), - mWrapT(LOCAL_GL_REPEAT), - mFacesCount(0), - mMaxLevelWithCustomImages(0), - mHaveGeneratedMipmap(false), - mFakeBlackStatus(DoNotNeedFakeBlack) + WebGLTexture(WebGLContext *context) + : WebGLContextBoundObject(context) + , mHasEverBeenBound(false) + , mTarget(0) + , mMinFilter(LOCAL_GL_NEAREST_MIPMAP_LINEAR) + , mMagFilter(LOCAL_GL_LINEAR) + , mWrapS(LOCAL_GL_REPEAT) + , mWrapT(LOCAL_GL_REPEAT) + , mFacesCount(0) + , mMaxLevelWithCustomImages(0) + , mHaveGeneratedMipmap(false) + , mFakeBlackStatus(DoNotNeedFakeBlack) { + mContext->MakeContextCurrent(); + mContext->gl->fGenTextures(1, &mGLName); + } + + ~WebGLTexture() { + DeleteOnce(); } void Delete() { - if (mDeleted) - return; - ZeroOwners(); - mDeleted = true; + mImageInfos.Clear(); + mContext->MakeContextCurrent(); + mContext->gl->fDeleteTextures(1, &mGLName); } - bool Deleted() { return mDeleted; } bool HasEverBeenBound() { return mHasEverBeenBound; } void SetHasEverBeenBound(bool x) { mHasEverBeenBound = x; } WebGLuint GLName() { return mGLName; } + GLenum Target() const { return mTarget; } NS_DECL_ISUPPORTS NS_DECL_NSIWEBGLTEXTURE protected: + friend class WebGLContext; friend class WebGLFramebuffer; - bool mDeleted; bool mHasEverBeenBound; WebGLuint mGLName; // we store information about the various images that are part of // this texture (cubemap faces, mipmap levels) public: @@ -1650,65 +1655,45 @@ public: if (mFakeBlackStatus == DontKnowIfNeedFakeBlack) mFakeBlackStatus = DoNotNeedFakeBlack; } return mFakeBlackStatus == DoNeedFakeBlack; } }; -class WebGLShader : - public nsIWebGLShader, - public WebGLZeroingObject<8>, // almost never has more than 8 owners - public WebGLContextBoundObject +class WebGLShader + : public nsIWebGLShader + , public WebGLRefCountedObject<WebGLShader> + , public WebGLContextBoundObject { public: - WebGLShader(WebGLContext *context, WebGLuint name, WebGLenum stype) : - WebGLContextBoundObject(context), - mGLName(name), mDeleted(false), mType(stype), - mNeedsTranslation(true), mAttachCount(0), - mDeletePending(false) - { } - - void DetachedFromProgram() { - DecrementAttachCount(); - if (mDeletePending && AttachCount() <= 0) { - DeleteWhenNotAttached(); - } + WebGLShader(WebGLContext *context, WebGLenum stype) + : WebGLContextBoundObject(context) + , mType(stype) + , mNeedsTranslation(true) + { + mContext->MakeContextCurrent(); + mGLName = mContext->gl->fCreateShader(mType); } - void DeleteWhenNotAttached() { - if (mDeleted) - return; - - if (AttachCount() > 0) { - mDeletePending = true; - return; - } - - Delete(); + ~WebGLShader() { + DeleteOnce(); } void Delete() { - if (mDeleted) - return; - - ZeroOwners(); - mDeleted = true; - mDeletePending = false; + mSource.Truncate(); + mTranslationLog.Truncate(); + mContext->MakeContextCurrent(); + mContext->gl->fDeleteShader(mGLName); } - bool Deleted() { return mDeleted; } WebGLuint GLName() { return mGLName; } WebGLenum ShaderType() { return mType; } - PRInt32 AttachCount() { return mAttachCount; } - void IncrementAttachCount() { mAttachCount++; } - void DecrementAttachCount() { mAttachCount--; } - void SetSource(const nsAString& src) { // XXX do some quick gzip here maybe -- getting this will be very rare mSource.Assign(src); } const nsString& Source() const { return mSource; } void SetNeedsTranslation() { mNeedsTranslation = true; } @@ -1722,115 +1707,93 @@ public: void SetTranslationFailure(const nsCString& msg) { mTranslationLog.Assign(msg); } const nsCString& TranslationLog() const { return mTranslationLog; } NS_DECL_ISUPPORTS NS_DECL_NSIWEBGLSHADER + protected: + WebGLuint mGLName; - bool mDeleted; WebGLenum mType; nsString mSource; nsCString mTranslationLog; bool mNeedsTranslation; - PRInt32 mAttachCount; - bool mDeletePending; }; -class WebGLProgram : - public nsIWebGLProgram, - public WebGLZeroingObject<8>, // can actually have many more owners (WebGLUniformLocations), - // but that shouldn't be performance-critical as references to the uniformlocations are stored - // in mMapUniformLocations, limiting the churning - public WebGLContextBoundObject +class WebGLProgram + : public nsIWebGLProgram + , public WebGLRefCountedObject<WebGLProgram> + , public WebGLContextBoundObject { public: - - WebGLProgram(WebGLContext *context, WebGLuint name) : - WebGLContextBoundObject(context), - mGLName(name), mDeleted(false), mDeletePending(false), - mLinkStatus(false), mGeneration(0), - mUniformMaxNameLength(0), mAttribMaxNameLength(0), - mUniformCount(0), mAttribCount(0) + WebGLProgram(WebGLContext *context) + : WebGLContextBoundObject(context) + , mLinkStatus(false) + , mGeneration(0) + , mUniformMaxNameLength(0) + , mAttribMaxNameLength(0) + , mUniformCount(0) + , mAttribCount(0) { + mMapUniformLocations.Init(); + mContext->MakeContextCurrent(); + mGLName = mContext->gl->fCreateProgram(); } - void DeleteWhenNotCurrent() { - if (mDeleted) - return; - - if (mContext->mCurrentProgram == this) { - mDeletePending = true; - return; - } - - Delete(); + ~WebGLProgram() { + DeleteOnce(); } void Delete() { - if (mDeleted) - return; - DetachShaders(); - ZeroOwners(); - mDeleted = true; - mDeletePending = false; + mContext->MakeContextCurrent(); + mContext->gl->fDeleteProgram(mGLName); + mMapUniformLocations.EnumerateRead(NotifyUniformLocationOfProgramDeletion, nsnull); } void DetachShaders() { - for (PRUint32 i = 0; i < mAttachedShaders.Length(); ++i) { - WebGLShader* shader = mAttachedShaders[i]; - if (shader) - shader->DetachedFromProgram(); - } mAttachedShaders.Clear(); } - void NoLongerCurrent() { - if (mDeletePending) { - DetachShaders(); - DeleteWhenNotCurrent(); - } - } - - bool Deleted() { return mDeleted; } - void SetDeletePending() { mDeletePending = true; } - void ClearDeletePending() { mDeletePending = false; } - bool HasDeletePending() { return mDeletePending; } - WebGLuint GLName() { return mGLName; } - const nsTArray<nsRefPtr<WebGLShader> >& AttachedShaders() const { return mAttachedShaders; } + const nsTArray<WebGLRefPtr<WebGLShader> >& AttachedShaders() const { return mAttachedShaders; } bool LinkStatus() { return mLinkStatus; } PRUint32 Generation() const { return mGeneration.value(); } void SetLinkStatus(bool val) { mLinkStatus = val; } bool ContainsShader(WebGLShader *shader) { return mAttachedShaders.Contains(shader); } // return true if the shader wasn't already attached bool AttachShader(WebGLShader *shader) { if (ContainsShader(shader)) return false; mAttachedShaders.AppendElement(shader); - shader->IncrementAttachCount(); + + mContext->MakeContextCurrent(); + mContext->gl->fAttachShader(GLName(), shader->GLName()); + return true; } // return true if the shader was found and removed bool DetachShader(WebGLShader *shader) { - if (mAttachedShaders.RemoveElement(shader)) { - shader->DetachedFromProgram(); - return true; - } - return false; + if (!mAttachedShaders.RemoveElement(shader)) + return false; + + mContext->MakeContextCurrent(); + mContext->gl->fDetachShader(GLName(), shader->GLName()); + + return true; } bool HasAttachedShaderOfType(GLenum shaderType) { for (PRUint32 i = 0; i < mAttachedShaders.Length(); ++i) { if (mAttachedShaders[i] && mAttachedShaders[i]->ShaderType() == shaderType) { return true; } } @@ -1846,73 +1809,85 @@ public: bool NextGeneration() { if (!(mGeneration+1).valid()) return false; // must exit without changing mGeneration ++mGeneration; mMapUniformLocations.Clear(); return true; } - already_AddRefed<WebGLUniformLocation> GetUniformLocationObject(GLint glLocation); /* Called only after LinkProgram */ bool UpdateInfo(gl::GLContext *gl); /* Getters for cached program info */ WebGLint UniformMaxNameLength() const { return mUniformMaxNameLength; } WebGLint AttribMaxNameLength() const { return mAttribMaxNameLength; } WebGLint UniformCount() const { return mUniformCount; } WebGLint AttribCount() const { return mAttribCount; } bool IsAttribInUse(unsigned i) const { return mAttribsInUse[i]; } NS_DECL_ISUPPORTS NS_DECL_NSIWEBGLPROGRAM + protected: + WebGLuint mGLName; - bool mDeleted; - bool mDeletePending; bool mLinkStatus; // attached shaders of the program object - nsTArray<nsRefPtr<WebGLShader> > mAttachedShaders; + nsTArray<WebGLRefPtr<WebGLShader> > mAttachedShaders; CheckedUint32 mGeneration; // post-link data + + // uniform location objects can't be deleted by an explicit webgl.deleteXxx() function, + // so the XPCOM refcount is all what matters for them, that's why plain nsRefPtr's are enough here. nsRefPtrHashtable<nsUint32HashKey, WebGLUniformLocation> mMapUniformLocations; + GLint mUniformMaxNameLength; GLint mAttribMaxNameLength; GLint mUniformCount; GLint mAttribCount; std::vector<bool> mAttribsInUse; + +private: + static PLDHashOperator + NotifyUniformLocationOfProgramDeletion(const PRUint32& aKey, WebGLUniformLocation *aValue, void *); }; -class WebGLRenderbuffer : - public nsIWebGLRenderbuffer, - public WebGLZeroingObject<8>, // almost never has more than 8 owners - public WebGLRectangleObject, - public WebGLContextBoundObject +class WebGLRenderbuffer + : public nsIWebGLRenderbuffer + , public WebGLRefCountedObject<WebGLRenderbuffer> + , public WebGLRectangleObject + , public WebGLContextBoundObject { public: - - WebGLRenderbuffer(WebGLContext *context, WebGLuint name, WebGLuint secondBufferName = 0) : - WebGLContextBoundObject(context), - mGLName(name), - mInternalFormat(0), - mInternalFormatForGL(0), - mDeleted(false), mHasEverBeenBound(false), mInitialized(false) - { } + WebGLRenderbuffer(WebGLContext *context) + : WebGLContextBoundObject(context) + , mInternalFormat(0) + , mInternalFormatForGL(0) + , mHasEverBeenBound(false) + , mInitialized(false) + { + + mContext->MakeContextCurrent(); + mContext->gl->fGenRenderbuffers(1, &mGLName); + } + + ~WebGLRenderbuffer() { + DeleteOnce(); + } void Delete() { - if (mDeleted) - return; - ZeroOwners(); - mDeleted = true; + mContext->MakeContextCurrent(); + mContext->gl->fDeleteRenderbuffers(1, &mGLName); } - bool Deleted() const { return mDeleted; } + bool HasEverBeenBound() { return mHasEverBeenBound; } void SetHasEverBeenBound(bool x) { mHasEverBeenBound = x; } WebGLuint GLName() const { return mGLName; } bool Initialized() const { return mInitialized; } void SetInitialized(bool aInitialized) { mInitialized = aInitialized; } WebGLenum InternalFormat() const { return mInternalFormat; } @@ -1943,33 +1918,33 @@ public: NS_ABORT(); return 0; } NS_DECL_ISUPPORTS NS_DECL_NSIWEBGLRENDERBUFFER protected: + WebGLuint mGLName; WebGLenum mInternalFormat; WebGLenum mInternalFormatForGL; - bool mDeleted; bool mHasEverBeenBound; bool mInitialized; friend class WebGLFramebuffer; }; class WebGLFramebufferAttachment : public WebGLRectangleObject { // deleting a texture or renderbuffer immediately detaches it - WebGLObjectRefPtr<WebGLTexture> mTexturePtr; - WebGLObjectRefPtr<WebGLRenderbuffer> mRenderbufferPtr; + WebGLRefPtr<WebGLTexture> mTexturePtr; + WebGLRefPtr<WebGLRenderbuffer> mRenderbufferPtr; WebGLenum mAttachmentPoint; WebGLint mTextureLevel; WebGLenum mTextureCubeMapFace; public: WebGLFramebufferAttachment(WebGLenum aAttachmentPoint) : mAttachmentPoint(aAttachmentPoint) {} @@ -2046,43 +2021,52 @@ public: return false; // no attachment at all, so no incompatibility } bool HasUninitializedRenderbuffer() const { return mRenderbufferPtr && !mRenderbufferPtr->Initialized(); } }; -class WebGLFramebuffer : - public nsIWebGLFramebuffer, - public WebGLZeroingObject<8>, // almost never has more than 8 owners - public WebGLContextBoundObject +class WebGLFramebuffer + : public nsIWebGLFramebuffer + , public WebGLRefCountedObject<WebGLFramebuffer> + , public WebGLContextBoundObject { public: - - WebGLFramebuffer(WebGLContext *context, WebGLuint name) : - WebGLContextBoundObject(context), - mGLName(name), mDeleted(false), mHasEverBeenBound(false), - mColorAttachment(LOCAL_GL_COLOR_ATTACHMENT0), - mDepthAttachment(LOCAL_GL_DEPTH_ATTACHMENT), - mStencilAttachment(LOCAL_GL_STENCIL_ATTACHMENT), - mDepthStencilAttachment(LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) - { } + WebGLFramebuffer(WebGLContext *context) + : WebGLContextBoundObject(context) + , mHasEverBeenBound(false) + , mColorAttachment(LOCAL_GL_COLOR_ATTACHMENT0) + , mDepthAttachment(LOCAL_GL_DEPTH_ATTACHMENT) + , mStencilAttachment(LOCAL_GL_STENCIL_ATTACHMENT) + , mDepthStencilAttachment(LOCAL_GL_DEPTH_STENCIL_ATTACHMENT) + { + mContext->MakeContextCurrent(); + mContext->gl->fGenFramebuffers(1, &mGLName); + } + + ~WebGLFramebuffer() { + DeleteOnce(); + } void Delete() { - if (mDeleted) - return; - ZeroOwners(); - mDeleted = true; + mColorAttachment.Reset(); + mDepthAttachment.Reset(); + mStencilAttachment.Reset(); + mDepthStencilAttachment.Reset(); + + mContext->MakeContextCurrent(); + mContext->gl->fDeleteFramebuffers(1, &mGLName); } - bool Deleted() { return mDeleted; } + bool HasEverBeenBound() { return mHasEverBeenBound; } void SetHasEverBeenBound(bool x) { mHasEverBeenBound = x; } WebGLuint GLName() { return mGLName; } - + WebGLsizei width() { return mColorAttachment.width(); } WebGLsizei height() { return mColorAttachment.height(); } nsresult FramebufferRenderbuffer(WebGLenum target, WebGLenum attachment, WebGLenum rbtarget, nsIWebGLRenderbuffer *rbobj) { @@ -2305,91 +2289,85 @@ protected: if (mStencilAttachment.HasUninitializedRenderbuffer()) mStencilAttachment.Renderbuffer()->SetInitialized(true); if (mDepthStencilAttachment.HasUninitializedRenderbuffer()) mDepthStencilAttachment.Renderbuffer()->SetInitialized(true); } WebGLuint mGLName; - bool mDeleted; bool mHasEverBeenBound; // we only store pointers to attached renderbuffers, not to attached textures, because // we will only need to initialize renderbuffers. Textures are already initialized. WebGLFramebufferAttachment mColorAttachment, mDepthAttachment, mStencilAttachment, mDepthStencilAttachment; }; -class WebGLUniformLocation : - public nsIWebGLUniformLocation, - public WebGLZeroingObject<2>, // never saw a WebGLUniformLocation have more than 2 owners, and since these - // are small objects and there are many of them, it's worth saving some memory - // by using a small value such as 2 here. - public WebGLContextBoundObject +class WebGLUniformLocation + : public nsIWebGLUniformLocation + , public WebGLContextBoundObject { public: - - WebGLUniformLocation(WebGLContext *context, WebGLProgram *program, GLint location) : - WebGLContextBoundObject(context), mProgram(program), mProgramGeneration(program->Generation()), - mLocation(location) { } + WebGLUniformLocation(WebGLContext *context, WebGLProgram *program, GLint location) + : WebGLContextBoundObject(context) + , mProgram(program) + , mProgramGeneration(program->Generation()) + , mLocation(location) + { } + + // Needed for GetConcreteObject helpers. + bool IsDeleted() { return false; } WebGLProgram *Program() const { return mProgram; } GLint Location() const { return mLocation; } PRUint32 ProgramGeneration() const { return mProgramGeneration; } - // needed for our generic helpers to check nsIxxx parameters, see GetConcreteObject. - bool Deleted() { return false; } - NS_DECL_ISUPPORTS NS_DECL_NSIWEBGLUNIFORMLOCATION protected: - WebGLObjectRefPtr<WebGLProgram> mProgram; + WebGLProgram *mProgram; PRUint32 mProgramGeneration; GLint mLocation; + + friend class WebGLProgram; }; -class WebGLActiveInfo : - public nsIWebGLActiveInfo +class WebGLActiveInfo + : public nsIWebGLActiveInfo { public: WebGLActiveInfo(WebGLint size, WebGLenum type, const char *nameptr, PRUint32 namelength) : - mDeleted(false), mSize(size), mType(type) { mName.AssignASCII(nameptr, namelength); } - void Delete() { - if (mDeleted) - return; - mDeleted = true; - } - - bool Deleted() { return mDeleted; } - NS_DECL_ISUPPORTS NS_DECL_NSIWEBGLACTIVEINFO protected: - bool mDeleted; WebGLint mSize; WebGLenum mType; nsString mName; }; - -class WebGLExtension : - public nsIWebGLExtension, - public WebGLContextBoundObject, - public WebGLZeroingObject<2> // WebGLExtensions probably won't have many owers and - // can be very small objects. Also, we have a static array of those. So, saving some memory - // by using a small value such as 2 here. +inline PLDHashOperator +WebGLProgram::NotifyUniformLocationOfProgramDeletion(const PRUint32& aKey, WebGLUniformLocation *aValue, void *) +{ + aValue->mProgram = nsnull; + return PL_DHASH_NEXT; +} + + +class WebGLExtension + : public nsIWebGLExtension + , public WebGLContextBoundObject { public: WebGLExtension(WebGLContext *baseContext) : WebGLContextBoundObject(baseContext) {} NS_DECL_ISUPPORTS NS_DECL_NSIWEBGLEXTENSION @@ -2435,27 +2413,28 @@ WebGLContext::GetConcreteObject(const ch } } if (isNull) *isNull = false; // the key to why this static_cast is all we need to do (as opposed to the QueryInterface check we used to do) // is that since bug 638328, WebGL interfaces are marked 'builtinclass' in the IDL - *aConcreteObject = static_cast<ConcreteObjectType*>(aInterface); - - if (!(*aConcreteObject)->IsCompatibleWithContext(this)) { + ConcreteObjectType *concrete = static_cast<ConcreteObjectType*>(aInterface); + *aConcreteObject = concrete; + + if (!concrete->IsCompatibleWithContext(this)) { // the object doesn't belong to this WebGLContext if (generateErrors) ErrorInvalidOperation("%s: object from different WebGL context (or older generation of this one) " "passed as argument", info); return false; } - if ((*aConcreteObject)->Deleted()) { + if (concrete->IsDeleted()) { if (NS_LIKELY(isDeleted)) { // non-null isDeleted means that the caller will accept a deleted arg *isDeleted = true; return true; } else { if (generateErrors) ErrorInvalidValue("%s: deleted object passed as argument", info); return false;
--- a/content/canvas/src/WebGLContextGL.cpp +++ b/content/canvas/src/WebGLContextGL.cpp @@ -181,20 +181,16 @@ WebGLContext::AttachShader(nsIWebGLProgr // attached. This renders the next test somewhat moot, but we'll // leave it for when we support more than one shader of each type. if (program->HasAttachedShaderOfType(shader->ShaderType())) return ErrorInvalidOperation("AttachShader: only one of each type of shader may be attached to a program"); if (!program->AttachShader(shader)) return ErrorInvalidOperation("AttachShader: shader is already attached"); - MakeContextCurrent(); - - gl->fAttachShader(progname, shadername); - return NS_OK; } NS_IMETHODIMP WebGLContext::BindAttribLocation(nsIWebGLProgram *pobj, WebGLuint location, const nsAString& name) { if (mContextLost) @@ -1082,23 +1078,19 @@ WebGLContext::CopyTexSubImage2D(WebGLenu NS_IMETHODIMP WebGLContext::CreateProgram(nsIWebGLProgram **retval) { if (mContextLost) return NS_OK; *retval = nsnull; - MakeContextCurrent(); - - WebGLuint name = gl->fCreateProgram(); - - WebGLProgram *prog = new WebGLProgram(this, name); + WebGLProgram *prog = new WebGLProgram(this); NS_ADDREF(*retval = prog); - mMapPrograms.Put(name, prog); + mMapPrograms.Put(prog->GLName(), prog); return NS_OK; } NS_IMETHODIMP WebGLContext::CreateShader(WebGLenum type, nsIWebGLShader **retval) { if (mContextLost) @@ -1107,23 +1099,19 @@ WebGLContext::CreateShader(WebGLenum typ *retval = nsnull; if (type != LOCAL_GL_VERTEX_SHADER && type != LOCAL_GL_FRAGMENT_SHADER) { return ErrorInvalidEnumInfo("createShader: type", type); } - MakeContextCurrent(); - - WebGLuint name = gl->fCreateShader(type); - - WebGLShader *shader = new WebGLShader(this, name, type); + WebGLShader *shader = new WebGLShader(this, type); NS_ADDREF(*retval = shader); - mMapShaders.Put(name, shader); + mMapShaders.Put(shader->GLName(), shader); return NS_OK; } NS_IMETHODIMP WebGLContext::CullFace(WebGLenum face) { if (mContextLost) @@ -1147,110 +1135,106 @@ WebGLContext::DeleteBuffer(nsIWebGLBuffe WebGLBuffer *buf; bool isNull, isDeleted; if (!GetConcreteObjectAndGLName("deleteBuffer", bobj, &buf, &bufname, &isNull, &isDeleted)) return NS_OK; if (isNull || isDeleted) return NS_OK; - MakeContextCurrent(); - - gl->fDeleteBuffers(1, &bufname); - buf->Delete(); + if (mBoundArrayBuffer == buf) + BindBuffer(LOCAL_GL_ARRAY_BUFFER, nsnull); + if (mBoundElementArrayBuffer == buf) + BindBuffer(LOCAL_GL_ELEMENT_ARRAY_BUFFER, nsnull); + + for (int i = 0; i < mGLMaxVertexAttribs; i++) { + if (mAttribBuffers[i].buf == buf) + mAttribBuffers[i].buf = nsnull; + } + + buf->RequestDelete(); mMapBuffers.Remove(bufname); return NS_OK; } NS_IMETHODIMP WebGLContext::DeleteFramebuffer(nsIWebGLFramebuffer *fbobj) { if (mContextLost) return NS_OK; + WebGLFramebuffer *fbuf; WebGLuint fbufname; - WebGLFramebuffer *fbuf; bool isNull, isDeleted; if (!GetConcreteObjectAndGLName("deleteFramebuffer", fbobj, &fbuf, &fbufname, &isNull, &isDeleted)) return NS_OK; if (isNull || isDeleted) return NS_OK; - MakeContextCurrent(); - - gl->fDeleteFramebuffers(1, &fbufname); - fbuf->Delete(); + fbuf->RequestDelete(); mMapFramebuffers.Remove(fbufname); - if (mBoundFramebuffer && mBoundFramebuffer->GLName() == fbufname) - mBoundFramebuffer = NULL; + if (mBoundFramebuffer == fbuf) + BindFramebuffer(LOCAL_GL_FRAMEBUFFER, nsnull); return NS_OK; } NS_IMETHODIMP WebGLContext::DeleteRenderbuffer(nsIWebGLRenderbuffer *rbobj) { if (mContextLost) return NS_OK; + WebGLRenderbuffer *rbuf; WebGLuint rbufname; - WebGLRenderbuffer *rbuf; bool isNull, isDeleted; if (!GetConcreteObjectAndGLName("deleteRenderbuffer", rbobj, &rbuf, &rbufname, &isNull, &isDeleted)) return NS_OK; if (isNull || isDeleted) return NS_OK; - MakeContextCurrent(); - - // XXX we need to track renderbuffer attachments; from glDeleteRenderbuffers man page: - - /* - If a renderbuffer object that is currently bound is deleted, the binding reverts - to 0 (the absence of any renderbuffer object). Additionally, special care - must be taken when deleting a renderbuffer object if the image of the renderbuffer - is attached to a framebuffer object. In this case, if the deleted renderbuffer object is - attached to the currently bound framebuffer object, it is - automatically detached. However, attachments to any other framebuffer objects are the - responsibility of the application. - */ - - gl->fDeleteRenderbuffers(1, &rbufname); - rbuf->Delete(); + if (mBoundRenderbuffer == rbuf) + BindRenderbuffer(LOCAL_GL_RENDERBUFFER, nsnull); + + rbuf->RequestDelete(); mMapRenderbuffers.Remove(rbufname); - if (mBoundRenderbuffer && mBoundRenderbuffer->GLName() == rbufname) - mBoundRenderbuffer = NULL; - return NS_OK; } NS_IMETHODIMP WebGLContext::DeleteTexture(nsIWebGLTexture *tobj) { if (mContextLost) return NS_OK; + WebGLTexture *tex; WebGLuint texname; - WebGLTexture *tex; bool isNull, isDeleted; if (!GetConcreteObjectAndGLName("deleteTexture", tobj, &tex, &texname, &isNull, &isDeleted)) return NS_OK; if (isNull || isDeleted) return NS_OK; - MakeContextCurrent(); - - gl->fDeleteTextures(1, &texname); - tex->Delete(); + for (int i = 0; i < mGLMaxTextureUnits; i++) { + if ((tex->Target() == LOCAL_GL_TEXTURE_2D && mBound2DTextures[i] == tex) || + (tex->Target() == LOCAL_GL_TEXTURE_CUBE_MAP && mBoundCubeMapTextures[i] == tex)) + { + ActiveTexture(LOCAL_GL_TEXTURE0 + i); + BindTexture(tex->Target(), nsnull); + } + } + ActiveTexture(LOCAL_GL_TEXTURE0 + mActiveTexture); + + tex->RequestDelete(); mMapTextures.Remove(texname); return NS_OK; } NS_IMETHODIMP WebGLContext::DeleteProgram(nsIWebGLProgram *pobj) { @@ -1261,21 +1245,17 @@ WebGLContext::DeleteProgram(nsIWebGLProg WebGLProgram *prog; bool isNull, isDeleted; if (!GetConcreteObjectAndGLName("deleteProgram", pobj, &prog, &progname, &isNull, &isDeleted)) return NS_OK; if (isNull || isDeleted) return NS_OK; - MakeContextCurrent(); - - gl->fDeleteProgram(progname); - - prog->DeleteWhenNotCurrent(); + prog->RequestDelete(); mMapPrograms.Remove(progname); return NS_OK; } NS_IMETHODIMP WebGLContext::DeleteShader(nsIWebGLShader *sobj) { @@ -1286,20 +1266,17 @@ WebGLContext::DeleteShader(nsIWebGLShade WebGLShader *shader; bool isNull, isDeleted; if (!GetConcreteObjectAndGLName("deleteShader", sobj, &shader, &shadername, &isNull, &isDeleted)) return NS_OK; if (isNull || isDeleted) return NS_OK; - MakeContextCurrent(); - - gl->fDeleteShader(shadername); - shader->DeleteWhenNotAttached(); + shader->RequestDelete(); mMapShaders.Remove(shadername); return NS_OK; } NS_IMETHODIMP WebGLContext::DetachShader(nsIWebGLProgram *pobj, nsIWebGLShader *shobj) { @@ -1314,22 +1291,16 @@ WebGLContext::DetachShader(nsIWebGLProgr !GetConcreteObjectAndGLName("detachShader: shader", shobj, &shader, &shadername, nsnull, &shaderDeleted)) return NS_OK; // shaderDeleted is ignored -- it's valid to attempt to detach a // deleted shader, since it's still a shader if (!program->DetachShader(shader)) return ErrorInvalidOperation("DetachShader: shader is not attached"); - MakeContextCurrent(); - - gl->fDetachShader(progname, shadername); - - shader->DetachedFromProgram(); - return NS_OK; } NS_IMETHODIMP WebGLContext::DepthFunc(WebGLenum func) { if (mContextLost) return NS_OK; @@ -2550,44 +2521,36 @@ WebGLContext::GetRenderbufferParameter(W NS_IMETHODIMP WebGLContext::CreateBuffer(nsIWebGLBuffer **retval) { if (mContextLost) return NS_OK; *retval = nsnull; - MakeContextCurrent(); - - WebGLuint name; - gl->fGenBuffers(1, &name); - - WebGLBuffer *globj = new WebGLBuffer(this, name); + WebGLBuffer *globj = new WebGLBuffer(this); NS_ADDREF(*retval = globj); - mMapBuffers.Put(name, globj); + mMapBuffers.Put(globj->GLName(), globj); return NS_OK; } NS_IMETHODIMP WebGLContext::CreateTexture(nsIWebGLTexture **retval) { if (mContextLost) return NS_OK; *retval = nsnull; MakeContextCurrent(); - WebGLuint name; - gl->fGenTextures(1, &name); - - WebGLTexture *globj = new WebGLTexture(this, name); + WebGLTexture *globj = new WebGLTexture(this); NS_ADDREF(*retval = globj); - mMapTextures.Put(name, globj); + mMapTextures.Put(globj->GLName(), globj); return NS_OK; } NS_IMETHODIMP WebGLContext::GetError(WebGLenum *_retval) { if (!mContextLost) { @@ -2989,17 +2952,16 @@ WebGLContext::GetUniformLocation(nsIWebG return NS_OK; MakeContextCurrent(); GLint intlocation = gl->fGetUniformLocation(progname, NS_LossyConvertUTF16toASCII(name).get()); nsRefPtr<nsIWebGLUniformLocation> loc = prog->GetUniformLocationObject(intlocation); *retval = loc.forget().get(); - return NS_OK; } NS_IMETHODIMP WebGLContext::GetVertexAttrib(WebGLuint index, WebGLenum pname, nsIVariant **retval) { if (mContextLost) return NS_OK; @@ -4331,22 +4293,18 @@ WebGLContext::UseProgram(nsIWebGLProgram MakeContextCurrent(); if (prog && !prog->LinkStatus()) return ErrorInvalidOperation("UseProgram: program was not linked successfully"); gl->fUseProgram(progname); - WebGLProgram* previous = mCurrentProgram; mCurrentProgram = prog; - if (previous) - previous->NoLongerCurrent(); - return NS_OK; } NS_IMETHODIMP WebGLContext::ValidateProgram(nsIWebGLProgram *pobj) { if (mContextLost) return NS_OK; @@ -4371,44 +4329,34 @@ WebGLContext::ValidateProgram(nsIWebGLPr NS_IMETHODIMP WebGLContext::CreateFramebuffer(nsIWebGLFramebuffer **retval) { if (mContextLost) return NS_OK; *retval = 0; - MakeContextCurrent(); - - GLuint name; - gl->fGenFramebuffers(1, &name); - - WebGLFramebuffer *globj = new WebGLFramebuffer(this, name); + WebGLFramebuffer *globj = new WebGLFramebuffer(this); NS_ADDREF(*retval = globj); - mMapFramebuffers.Put(name, globj); + mMapFramebuffers.Put(globj->GLName(), globj); return NS_OK; } NS_IMETHODIMP WebGLContext::CreateRenderbuffer(nsIWebGLRenderbuffer **retval) { if (mContextLost) return NS_OK; *retval = 0; - MakeContextCurrent(); - - GLuint name; - gl->fGenRenderbuffers(1, &name); - - WebGLRenderbuffer *globj = new WebGLRenderbuffer(this, name); + WebGLRenderbuffer *globj = new WebGLRenderbuffer(this); NS_ADDREF(*retval = globj); - mMapRenderbuffers.Put(name, globj); + mMapRenderbuffers.Put(globj->GLName(), globj); return NS_OK; } NS_IMETHODIMP WebGLContext::Viewport(WebGLint x, WebGLint y, WebGLsizei width, WebGLsizei height) { if (mContextLost)