Bug 704839 - [4/9] - Refactor mutual ownership of WebGL objects - r=jgilbert
authorBenoit Jacob <bjacob@mozilla.com>
Sun, 04 Dec 2011 14:15:42 -0500
changeset 82004 e8de56f450c95cc9b4d7f77b1950535e1764ed6a
parent 82003 539c05fd263cdd8362c8531d1f78c93e4539fad1
child 82005 9d44f155bdbb2bba1a54efab894137c4954532d3
push idunknown
push userunknown
push dateunknown
reviewersjgilbert
bugs704839
milestone11.0a1
Bug 704839 - [4/9] - Refactor mutual ownership of WebGL objects - r=jgilbert This patch switches to the new mutual ownership pattern for WebGL objects, based on maintaining a second WebGL-specific refcount mirroring the OpenGL refcount which we can't access, using the helper classes that were introduced in patches 1 and 2.
content/canvas/src/WebGLContext.cpp
content/canvas/src/WebGLContext.h
content/canvas/src/WebGLContextGL.cpp
--- 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)