diff --git a/content/canvas/src/WebGLContext.cpp b/content/canvas/src/WebGLContext.cpp index 9ad85da3e11..0a7ef968024 100644 --- a/content/canvas/src/WebGLContext.cpp +++ b/content/canvas/src/WebGLContext.cpp @@ -237,7 +237,6 @@ WebGLContext::WebGLContext() mShaderValidation = true; mMapBuffers.Init(); - mMapTextures.Init(); mMapPrograms.Init(); mMapShaders.Init(); mMapFramebuffers.Init(); @@ -348,7 +347,8 @@ WebGLContext::DestroyResourcesAndContext() mAttribBuffers.Clear(); - DeleteWebGLObjectsHashTable(mMapTextures); + while (mTextures.Length()) + mTextures.Last()->DeleteOnce(); DeleteWebGLObjectsHashTable(mMapRenderbuffers); DeleteWebGLObjectsHashTable(mMapFramebuffers); DeleteWebGLObjectsHashTable(mMapBuffers); diff --git a/content/canvas/src/WebGLContext.h b/content/canvas/src/WebGLContext.h index de79fcc97bb..32368e17af5 100644 --- a/content/canvas/src/WebGLContext.h +++ b/content/canvas/src/WebGLContext.h @@ -365,6 +365,76 @@ protected: T *mRawPtr; }; +typedef PRUint64 WebGLMonotonicHandle; + +/* WebGLFastArray offers a fast array for the use case where all what one needs is to append + * and remove elements. Removal is fast because the array is always kept sorted with respect + * to "monotonic handles". Appending an element returns such a "monotonic handle" which the + * user needs to keep for future use for when it will want to remove the element. + */ +template +class WebGLFastArray +{ + struct Entry { + ElementType mElement; + WebGLMonotonicHandle mMonotonicHandle; + + Entry(ElementType elem, WebGLMonotonicHandle monotonicHandle) + : mElement(elem), mMonotonicHandle(monotonicHandle) + {} + + struct Comparator { + bool Equals(const Entry& a, const Entry& b) const { + return a.mMonotonicHandle == b.mMonotonicHandle; + } + bool LessThan(const Entry& a, const Entry& b) const { + return a.mMonotonicHandle < b.mMonotonicHandle; + } + }; + }; + +public: + WebGLFastArray() + : mCurrentMonotonicHandle(0) // CheckedInt already does it, this is just defensive coding + {} + + ElementType operator[](size_t index) const { + return mArray[index].mElement; + } + + size_t Length() const { + return mArray.Length(); + } + + ElementType Last() const { + return operator[](Length() - 1); + } + + WebGLMonotonicHandle AppendElement(ElementType elem) + { + WebGLMonotonicHandle monotonicHandle = NextMonotonicHandle(); + mArray.AppendElement(Entry(elem, monotonicHandle)); + return monotonicHandle; + } + + void RemoveElement(WebGLMonotonicHandle monotonicHandle) + { + mArray.RemoveElementSorted(Entry(ElementType(), monotonicHandle), + typename Entry::Comparator()); + } + +private: + WebGLMonotonicHandle NextMonotonicHandle() { + ++mCurrentMonotonicHandle; + if (!mCurrentMonotonicHandle.valid()) + NS_RUNTIMEABORT("ran out of monotonic ids!"); + return mCurrentMonotonicHandle.value(); + } + + nsTArray mArray; + CheckedInt mCurrentMonotonicHandle; +}; + struct WebGLContextOptions { // these are defaults WebGLContextOptions() @@ -578,6 +648,9 @@ protected: bool mDisableExtensions; bool mHasRobustness; + template + void DeleteWebGLObjectsArray(nsTArray& array); + WebGLuint mActiveTexture; WebGLenum mWebGLError; @@ -752,7 +825,7 @@ protected: WebGLRefPtr mBoundRenderbuffer; // lookup tables for GL name -> object wrapper - nsRefPtrHashtable mMapTextures; + WebGLFastArray mTextures; nsRefPtrHashtable mMapBuffers; nsRefPtrHashtable mMapPrograms; nsRefPtrHashtable mMapShaders; @@ -1065,6 +1138,7 @@ public: { mContext->MakeContextCurrent(); mContext->gl->fGenTextures(1, &mGLName); + mMonotonicHandle = mContext->mTextures.AppendElement(this); } ~WebGLTexture() { @@ -1075,6 +1149,7 @@ public: mImageInfos.Clear(); mContext->MakeContextCurrent(); mContext->gl->fDeleteTextures(1, &mGLName); + mContext->mTextures.RemoveElement(mMonotonicHandle); } bool HasEverBeenBound() { return mHasEverBeenBound; } @@ -1157,6 +1232,8 @@ public: } PRInt64 MemoryUsage() const { + if (IsDeleted()) + return 0; PRInt64 result = 0; for(size_t face = 0; face < mFacesCount; face++) { if (mHaveGeneratedMipmap) { @@ -1183,6 +1260,8 @@ protected: bool mHaveGeneratedMipmap; FakeBlackStatus mFakeBlackStatus; + WebGLMonotonicHandle mMonotonicHandle; + void EnsureMaxLevelWithCustomImagesAtLeast(size_t aMaxLevelWithCustomImages) { mMaxLevelWithCustomImages = NS_MAX(mMaxLevelWithCustomImages, aMaxLevelWithCustomImages); mImageInfos.EnsureLengthAtLeast((mMaxLevelWithCustomImages + 1) * mFacesCount); @@ -2390,33 +2469,23 @@ class WebGLMemoryReporter } } - static PLDHashOperator TextureMemoryUsageFunction(const PRUint32&, WebGLTexture *aValue, void *aData) - { - PRInt64 *result = (PRInt64*) aData; - *result += aValue->MemoryUsage(); - return PL_DHASH_NEXT; - } - static PRInt64 GetTextureMemoryUsed() { const ContextsArrayType & contexts = Contexts(); PRInt64 result = 0; - for(size_t i = 0; i < contexts.Length(); ++i) { - PRInt64 textureMemoryUsageForThisContext = 0; - contexts[i]->mMapTextures.EnumerateRead(TextureMemoryUsageFunction, &textureMemoryUsageForThisContext); - result += textureMemoryUsageForThisContext; - } + for(size_t i = 0; i < contexts.Length(); ++i) + for (size_t t = 0; t < contexts[i]->mTextures.Length(); ++t) + result += contexts[i]->mTextures[t]->MemoryUsage(); return result; } - + static PRInt64 GetTextureCount() { const ContextsArrayType & contexts = Contexts(); PRInt64 result = 0; - for(size_t i = 0; i < contexts.Length(); ++i) { - result += contexts[i]->mMapTextures.Count(); - } + for(size_t i = 0; i < contexts.Length(); ++i) + result += contexts[i]->mTextures.Length(); return result; } - + static PLDHashOperator BufferMemoryUsageFunction(const PRUint32&, WebGLBuffer *aValue, void *aData) { PRInt64 *result = (PRInt64*) aData; diff --git a/content/canvas/src/WebGLContextGL.cpp b/content/canvas/src/WebGLContextGL.cpp index 32bb738e53d..c5b5bd7a4ec 100644 --- a/content/canvas/src/WebGLContextGL.cpp +++ b/content/canvas/src/WebGLContextGL.cpp @@ -1236,7 +1236,6 @@ WebGLContext::DeleteTexture(nsIWebGLTexture *tobj) ActiveTexture(LOCAL_GL_TEXTURE0 + mActiveTexture); tex->RequestDelete(); - mMapTextures.Remove(texname); return NS_OK; } @@ -2551,7 +2550,6 @@ WebGLContext::CreateTexture(nsIWebGLTexture **retval) WebGLTexture *globj = new WebGLTexture(this); NS_ADDREF(*retval = globj); - mMapTextures.Put(globj->GLName(), globj); return NS_OK; } diff --git a/content/canvas/src/WebGLContextValidate.cpp b/content/canvas/src/WebGLContextValidate.cpp index bc8a00117de..04362015742 100644 --- a/content/canvas/src/WebGLContextValidate.cpp +++ b/content/canvas/src/WebGLContextValidate.cpp @@ -525,7 +525,6 @@ WebGLContext::InitAndValidateGL() mBoundFramebuffer = nsnull; mBoundRenderbuffer = nsnull; - mMapTextures.Clear(); mMapBuffers.Clear(); mMapPrograms.Clear(); mMapShaders.Clear();