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 81405 e8de56f450c95cc9b4d7f77b1950535e1764ed6a
parent 81404 539c05fd263cdd8362c8531d1f78c93e4539fad1
child 81406 9d44f155bdbb2bba1a54efab894137c4954532d3
push id3801
push userbjacob@mozilla.com
push dateSun, 04 Dec 2011 19:18:01 +0000
treeherdermozilla-inbound@d75664a67e3b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjgilbert
bugs704839
milestone11.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
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)