Bug 1002281 - WebGL2 - Refactor common functions into WebGLBindableName.; r=jgilbert
authorDan Glastonbury <dglastonbury@mozilla.com>
Wed, 07 May 2014 13:11:18 +1000
changeset 212502 baa68b41e879b9ed1e6d056732e5a33448e00667
parent 212501 969587e6bfcfa3774dab41c021933d0f31b12d86
child 212503 01d12ccde2bb16d89b553e57adb5231a47080d33
push idunknown
push userunknown
push dateunknown
reviewersjgilbert
bugs1002281
milestone34.0a1
Bug 1002281 - WebGL2 - Refactor common functions into WebGLBindableName.; r=jgilbert WebGLBindableName represents a GL 'name' (GLuint) that can be bound to part of the GL state machine. Similar code appeared in a number of classes that represent GL bindable names, such as WebGLBuffer, WebGLTexture, WebGLFramebuffer, etc. Cleanup to reduce copy-n-paste code that's needed for creating new objects for WebGL 2.
dom/canvas/WebGLBindableName.cpp
dom/canvas/WebGLBindableName.h
dom/canvas/WebGLBuffer.cpp
dom/canvas/WebGLBuffer.h
dom/canvas/WebGLContextBuffers.cpp
dom/canvas/WebGLContextGL.cpp
dom/canvas/WebGLContextVertexArray.cpp
dom/canvas/WebGLFramebuffer.cpp
dom/canvas/WebGLFramebuffer.h
dom/canvas/WebGLRenderbuffer.cpp
dom/canvas/WebGLRenderbuffer.h
dom/canvas/WebGLTexture.cpp
dom/canvas/WebGLTexture.h
dom/canvas/WebGLVertexArray.cpp
dom/canvas/WebGLVertexArray.h
dom/canvas/moz.build
new file mode 100644
--- /dev/null
+++ b/dom/canvas/WebGLBindableName.cpp
@@ -0,0 +1,27 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "WebGLBindableName.h"
+#include "GLConsts.h"
+#include "mozilla/Assertions.h"
+
+using namespace mozilla;
+
+WebGLBindableName::WebGLBindableName()
+    : mGLName(LOCAL_GL_NONE)
+    , mTarget(LOCAL_GL_NONE)
+{ }
+
+void
+WebGLBindableName::BindTo(GLenum target)
+{
+    MOZ_ASSERT(target != LOCAL_GL_NONE, "Can't bind to GL_NONE.");
+    MOZ_ASSERT(mTarget == LOCAL_GL_NONE || mTarget == target, "Rebinding is illegal.");
+
+    bool targetChanged = (target != mTarget);
+    mTarget = target;
+    if (targetChanged)
+        OnTargetChanged();
+}
new file mode 100644
--- /dev/null
+++ b/dom/canvas/WebGLBindableName.h
@@ -0,0 +1,36 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef WEBGLBINDABLENAME_H_
+#define WEBGLBINDABLENAME_H_
+
+#include "WebGLTypes.h"
+
+namespace mozilla {
+
+/** Represents a GL name that can be bound to a target.
+ */
+class WebGLBindableName
+{
+public:
+    WebGLBindableName();
+    void BindTo(GLenum target);
+
+    bool HasEverBeenBound() const { return mTarget != 0; }
+    GLuint GLName() const { return mGLName; }
+    GLenum Target() const { return mTarget; }
+
+protected:
+
+    //! Called after mTarget has been changed by BindTo(target).
+    virtual void OnTargetChanged() {}
+
+    GLuint mGLName;
+    GLenum mTarget;
+};
+
+} // namespace mozilla
+
+#endif // !WEBGLBINDABLENAME_H_
--- a/dom/canvas/WebGLBuffer.cpp
+++ b/dom/canvas/WebGLBuffer.cpp
@@ -8,20 +8,19 @@
 #include "GLContext.h"
 #include "mozilla/dom/WebGLRenderingContextBinding.h"
 #include "WebGLContext.h"
 #include "WebGLElementArrayCache.h"
 
 using namespace mozilla;
 
 WebGLBuffer::WebGLBuffer(WebGLContext *context)
-    : WebGLContextBoundObject(context)
-    , mHasEverBeenBound(false)
+    : WebGLBindableName()
+    , WebGLContextBoundObject(context)
     , mByteLength(0)
-    , mTarget(LOCAL_GL_NONE)
 {
     SetIsDOMBinding();
     mContext->MakeContextCurrent();
     mContext->gl->fGenBuffers(1, &mGLName);
     mContext->mBuffers.insertBack(this);
 }
 
 WebGLBuffer::~WebGLBuffer() {
@@ -33,18 +32,17 @@ WebGLBuffer::Delete() {
     mContext->MakeContextCurrent();
     mContext->gl->fDeleteBuffers(1, &mGLName);
     mByteLength = 0;
     mCache = nullptr;
     LinkedListElement<WebGLBuffer>::remove(); // remove from mContext->mBuffers
 }
 
 void
-WebGLBuffer::SetTarget(GLenum target) {
-    mTarget = target;
+WebGLBuffer::OnTargetChanged() {
     if (!mCache && mTarget == LOCAL_GL_ELEMENT_ARRAY_BUFFER)
         mCache = new WebGLElementArrayCache;
 }
 
 bool
 WebGLBuffer::ElementArrayCacheBufferData(const void* ptr, size_t buffer_size_in_bytes) {
     if (mTarget == LOCAL_GL_ELEMENT_ARRAY_BUFFER)
         return mCache->BufferData(ptr, buffer_size_in_bytes);
--- a/dom/canvas/WebGLBuffer.h
+++ b/dom/canvas/WebGLBuffer.h
@@ -5,46 +5,42 @@
 
 #ifndef WEBGLBUFFER_H_
 #define WEBGLBUFFER_H_
 
 #include "GLDefs.h"
 #include "mozilla/LinkedList.h"
 #include "mozilla/MemoryReporting.h"
 #include "nsWrapperCache.h"
+#include "WebGLBindableName.h"
 #include "WebGLObjectModel.h"
 #include "WebGLTypes.h"
 
 namespace mozilla {
 
 class WebGLElementArrayCache;
 
 class WebGLBuffer MOZ_FINAL
     : public nsWrapperCache
+    , public WebGLBindableName
     , public WebGLRefCountedObject<WebGLBuffer>
     , public LinkedListElement<WebGLBuffer>
     , public WebGLContextBoundObject
 {
 public:
     WebGLBuffer(WebGLContext *context);
 
     void Delete();
 
     size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
 
-    bool HasEverBeenBound() { return mHasEverBeenBound; }
-    void SetHasEverBeenBound(bool x) { mHasEverBeenBound = x; }
-    GLuint GLName() const { return mGLName; }
     WebGLsizeiptr ByteLength() const { return mByteLength; }
-    GLenum Target() const { return mTarget; }
 
     void SetByteLength(WebGLsizeiptr byteLength) { mByteLength = byteLength; }
 
-    void SetTarget(GLenum target);
-
     bool ElementArrayCacheBufferData(const void* ptr, size_t buffer_size_in_bytes);
 
     void ElementArrayCacheBufferSubData(size_t pos, const void* ptr, size_t update_size_in_bytes);
 
     bool Validate(GLenum type, uint32_t max_allowed, size_t first, size_t count,
                   uint32_t* out_upperBound);
 
     bool IsElementArrayUsedWithMultipleTypes() const;
@@ -56,17 +52,16 @@ public:
     virtual JSObject* WrapObject(JSContext *cx) MOZ_OVERRIDE;
 
     NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLBuffer)
     NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLBuffer)
 
 protected:
     ~WebGLBuffer();
 
-    GLuint mGLName;
-    bool mHasEverBeenBound;
+    virtual void OnTargetChanged() MOZ_OVERRIDE;
+
     WebGLsizeiptr mByteLength;
-    GLenum mTarget;
 
     nsAutoPtr<WebGLElementArrayCache> mCache;
 };
 }
 #endif //WEBGLBUFFER_H_
--- a/dom/canvas/WebGLContextBuffers.cpp
+++ b/dom/canvas/WebGLContextBuffers.cpp
@@ -26,19 +26,18 @@ WebGLContext::BindBuffer(GLenum target, 
 
     WebGLRefPtr<WebGLBuffer>* bufferSlot = GetBufferSlotByTarget(target, "bindBuffer");
 
     if (!bufferSlot) {
         return;
     }
 
     if (buffer) {
-        if (!buffer->Target()) {
-            buffer->SetTarget(target);
-            buffer->SetHasEverBeenBound(true);
+        if (!buffer->HasEverBeenBound()) {
+            buffer->BindTo(target);
         } else if (target != buffer->Target()) {
             return ErrorInvalidOperation("bindBuffer: buffer already bound to a different target");
         }
     }
 
     *bufferSlot = buffer;
 
     MakeContextCurrent();
@@ -62,22 +61,21 @@ WebGLContext::BindBufferBase(GLenum targ
 
     WebGLRefPtr<WebGLBuffer>* indexedBufferSlot = GetBufferSlotByTargetIndexed(target, index, "bindBufferBase");
 
     if (!indexedBufferSlot) {
         return;
     }
 
     if (buffer) {
-        if (!buffer->Target()) {
-            buffer->SetTarget(target);
-            buffer->SetHasEverBeenBound(true);
-        } else if (target != buffer->Target()) {
+        if (!buffer->HasEverBeenBound())
+            buffer->BindTo(target);
+
+        if (target != buffer->Target())
             return ErrorInvalidOperation("bindBuffer: buffer already bound to a different target");
-        }
     }
 
     WebGLRefPtr<WebGLBuffer>* bufferSlot = GetBufferSlotByTarget(target, "bindBuffer");
 
     MOZ_ASSERT(bufferSlot, "GetBufferSlotByTarget(Indexed) mismatch");
 
     *indexedBufferSlot = buffer;
     *bufferSlot = buffer;
@@ -103,22 +101,22 @@ WebGLContext::BindBufferRange(GLenum tar
 
     WebGLRefPtr<WebGLBuffer>* indexedBufferSlot = GetBufferSlotByTargetIndexed(target, index, "bindBufferBase");
 
     if (!indexedBufferSlot) {
         return;
     }
 
     if (buffer) {
-        if (!buffer->Target()) {
-            buffer->SetTarget(target);
-            buffer->SetHasEverBeenBound(true);
-        } else if (target != buffer->Target()) {
+        if (!buffer->HasEverBeenBound())
+            buffer->BindTo(target);
+
+        if (target != buffer->Target())
             return ErrorInvalidOperation("bindBuffer: buffer already bound to a different target");
-        }
+
         CheckedInt<WebGLsizeiptr> checked_neededByteLength = CheckedInt<WebGLsizeiptr>(offset) + size;
         if (!checked_neededByteLength.isValid() ||
             checked_neededByteLength.value() > buffer->ByteLength())
         {
             return ErrorInvalidValue("bindBufferRange: invalid range");
         }
     }
 
--- a/dom/canvas/WebGLContextGL.cpp
+++ b/dom/canvas/WebGLContextGL.cpp
@@ -169,19 +169,19 @@ WebGLContext::BindFramebuffer(GLenum tar
     if (wfb && wfb->IsDeleted())
         return;
 
     MakeContextCurrent();
 
     if (!wfb) {
         gl->fBindFramebuffer(target, 0);
     } else {
+        wfb->BindTo(target);
         GLuint framebuffername = wfb->GLName();
         gl->fBindFramebuffer(target, framebuffername);
-        wfb->SetHasEverBeenBound(true);
     }
 
     mBoundFramebuffer = wfb;
 }
 
 void
 WebGLContext::BindRenderbuffer(GLenum target, WebGLRenderbuffer *wrb)
 {
@@ -194,17 +194,17 @@ WebGLContext::BindRenderbuffer(GLenum ta
     if (!ValidateObjectAllowDeletedOrNull("bindRenderbuffer", wrb))
         return;
 
     // silently ignore a deleted buffer
     if (wrb && wrb->IsDeleted())
         return;
 
     if (wrb)
-        wrb->SetHasEverBeenBound(true);
+        wrb->BindTo(target);
 
     MakeContextCurrent();
 
     // Sometimes we emulate renderbuffers (depth-stencil emu), so there's not
     // always a 1-1 mapping from `wrb` to GL name. Just have `wrb` handle it.
     if (wrb) {
         wrb->BindRenderbuffer();
     } else {
--- a/dom/canvas/WebGLContextVertexArray.cpp
+++ b/dom/canvas/WebGLContextVertexArray.cpp
@@ -84,10 +84,8 @@ WebGLContext::IsVertexArray(WebGLVertexA
 
     if (!array)
         return false;
 
     return ValidateObjectAllowDeleted("isVertexArray", array) &&
            !array->IsDeleted() &&
            array->HasEverBeenBound();
 }
-
-
--- a/dom/canvas/WebGLFramebuffer.cpp
+++ b/dom/canvas/WebGLFramebuffer.cpp
@@ -19,19 +19,19 @@ using namespace mozilla::gl;
 
 JSObject*
 WebGLFramebuffer::WrapObject(JSContext* cx)
 {
     return dom::WebGLFramebufferBinding::Wrap(cx, this);
 }
 
 WebGLFramebuffer::WebGLFramebuffer(WebGLContext* context)
-    : WebGLContextBoundObject(context)
+    : WebGLBindableName()
+    , WebGLContextBoundObject(context)
     , mStatus(0)
-    , mHasEverBeenBound(false)
     , mDepthAttachment(LOCAL_GL_DEPTH_ATTACHMENT)
     , mStencilAttachment(LOCAL_GL_STENCIL_ATTACHMENT)
     , mDepthStencilAttachment(LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
 {
     SetIsDOMBinding();
     mContext->MakeContextCurrent();
     mContext->gl->fGenFramebuffers(1, &mGLName);
     mContext->mFramebuffers.insertBack(this);
@@ -74,38 +74,42 @@ WebGLFramebuffer::Attachment::HasAlpha()
     else if (Renderbuffer())
         format = Renderbuffer()->InternalFormat();
     return FormatHasAlpha(format);
 }
 
 bool
 WebGLFramebuffer::Attachment::IsReadableFloat() const
 {
-    if (Texture() && Texture()->HasImageInfoAt(mTexImageTarget, mTexImageLevel)) {
-        GLenum type = Texture()->ImageInfoAt(mTexImageTarget, mTexImageLevel).WebGLType();
+    const WebGLTexture* tex = Texture();
+    if (tex && tex->HasImageInfoAt(mTexImageTarget, mTexImageLevel)) {
+        GLenum type = tex->ImageInfoAt(mTexImageTarget, mTexImageLevel).WebGLType();
         switch (type) {
         case LOCAL_GL_FLOAT:
         case LOCAL_GL_HALF_FLOAT_OES:
             return true;
         }
         return false;
     }
 
-    if (Renderbuffer()) {
-        GLenum format = Renderbuffer()->InternalFormat();
+    const WebGLRenderbuffer* rb = Renderbuffer();
+    if (rb) {
+        GLenum format = rb->InternalFormat();
         switch (format) {
         case LOCAL_GL_RGB16F:
         case LOCAL_GL_RGBA16F:
         case LOCAL_GL_RGB32F:
         case LOCAL_GL_RGBA32F:
             return true;
         }
         return false;
     }
 
+    // If we arrive here Attachment isn't correct setup because it has
+    // no texture nor render buffer pointer.
     MOZ_ASSERT(false, "Should not get here.");
     return false;
 }
 
 void
 WebGLFramebuffer::Attachment::SetTexImage(WebGLTexture* tex, GLenum target, GLint level)
 {
     mTexturePtr = tex;
--- a/dom/canvas/WebGLFramebuffer.h
+++ b/dom/canvas/WebGLFramebuffer.h
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef WEBGLFRAMEBUFFER_H_
 #define WEBGLFRAMEBUFFER_H_
 
+#include "WebGLBindableName.h"
 #include "WebGLObjectModel.h"
 
 #include "nsWrapperCache.h"
 
 #include "mozilla/LinkedList.h"
 
 namespace mozilla {
 
@@ -18,16 +19,17 @@ class WebGLFramebufferAttachable;
 class WebGLTexture;
 class WebGLRenderbuffer;
 namespace gl {
     class GLContext;
 }
 
 class WebGLFramebuffer MOZ_FINAL
     : public nsWrapperCache
+    , public WebGLBindableName
     , public WebGLRefCountedObject<WebGLFramebuffer>
     , public LinkedListElement<WebGLFramebuffer>
     , public WebGLContextBoundObject
     , public SupportsWeakPtr<WebGLFramebuffer>
 {
 public:
     MOZ_DECLARE_REFCOUNTED_TYPENAME(WebGLFramebuffer)
 
@@ -87,20 +89,16 @@ public:
         bool HasImage() const;
         bool IsComplete() const;
 
         void FinalizeAttachment(gl::GLContext* gl, GLenum attachmentLoc) const;
     };
 
     void Delete();
 
-    bool HasEverBeenBound() { return mHasEverBeenBound; }
-    void SetHasEverBeenBound(bool x) { mHasEverBeenBound = x; }
-    GLuint GLName() { return mGLName; }
-
     void FramebufferRenderbuffer(GLenum target,
                                  GLenum attachment,
                                  GLenum rbtarget,
                                  WebGLRenderbuffer* wrb);
 
     void FramebufferTexture2D(GLenum target,
                               GLenum attachment,
                               GLenum textarget,
@@ -178,19 +176,16 @@ public:
 
 private:
     ~WebGLFramebuffer() {
         DeleteOnce();
     }
 
     mutable GLenum mStatus;
 
-    GLuint mGLName;
-    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.
     nsTArray<Attachment> mColorAttachments;
     Attachment mDepthAttachment,
                mStencilAttachment,
                mDepthStencilAttachment;
 };
 
--- a/dom/canvas/WebGLRenderbuffer.cpp
+++ b/dom/canvas/WebGLRenderbuffer.cpp
@@ -38,22 +38,22 @@ NeedsDepthStencilEmu(GLContext* gl, GLen
 }
 
 JSObject*
 WebGLRenderbuffer::WrapObject(JSContext *cx) {
     return dom::WebGLRenderbufferBinding::Wrap(cx, this);
 }
 
 WebGLRenderbuffer::WebGLRenderbuffer(WebGLContext *context)
-    : WebGLContextBoundObject(context)
+    : WebGLBindableName()
+    , WebGLContextBoundObject(context)
     , mPrimaryRB(0)
     , mSecondaryRB(0)
     , mInternalFormat(0)
     , mInternalFormatForGL(0)
-    , mHasEverBeenBound(false)
     , mImageDataStatus(WebGLImageDataStatus::NoImageData)
 {
     SetIsDOMBinding();
     mContext->MakeContextCurrent();
 
     mContext->gl->fGenRenderbuffers(1, &mPrimaryRB);
     if (!SupportsDepthStencil(mContext->gl))
         mContext->gl->fGenRenderbuffers(1, &mSecondaryRB);
--- a/dom/canvas/WebGLRenderbuffer.h
+++ b/dom/canvas/WebGLRenderbuffer.h
@@ -1,41 +1,40 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef WEBGLRENDERBUFFER_H_
 #define WEBGLRENDERBUFFER_H_
 
+#include "WebGLBindableName.h"
 #include "WebGLObjectModel.h"
 #include "WebGLFramebufferAttachable.h"
 
 #include "nsWrapperCache.h"
 
 #include "mozilla/LinkedList.h"
 
 namespace mozilla {
 
 class WebGLRenderbuffer MOZ_FINAL
     : public nsWrapperCache
+    , public WebGLBindableName
     , public WebGLRefCountedObject<WebGLRenderbuffer>
     , public LinkedListElement<WebGLRenderbuffer>
     , public WebGLRectangleObject
     , public WebGLContextBoundObject
     , public WebGLFramebufferAttachable
 {
 public:
     WebGLRenderbuffer(WebGLContext *context);
 
     void Delete();
 
-    bool HasEverBeenBound() { return mHasEverBeenBound; }
-    void SetHasEverBeenBound(bool x) { mHasEverBeenBound = x; }
-
     bool HasUninitializedImageData() const { return mImageDataStatus == WebGLImageDataStatus::UninitializedImageData; }
     void SetImageDataStatus(WebGLImageDataStatus x) {
         // there is no way to go from having image data to not having any
         MOZ_ASSERT(x != WebGLImageDataStatus::NoImageData ||
                    mImageDataStatus == WebGLImageDataStatus::NoImageData);
         mImageDataStatus = x;
     }
 
@@ -66,16 +65,15 @@ protected:
     ~WebGLRenderbuffer() {
         DeleteOnce();
     }
 
     GLuint mPrimaryRB;
     GLuint mSecondaryRB;
     GLenum mInternalFormat;
     GLenum mInternalFormatForGL;
-    bool mHasEverBeenBound;
     WebGLImageDataStatus mImageDataStatus;
 
     friend class WebGLFramebuffer;
 };
 } // namespace mozilla
 
 #endif
--- a/dom/canvas/WebGLTexture.cpp
+++ b/dom/canvas/WebGLTexture.cpp
@@ -18,19 +18,18 @@
 using namespace mozilla;
 
 JSObject*
 WebGLTexture::WrapObject(JSContext *cx) {
     return dom::WebGLTextureBinding::Wrap(cx, this);
 }
 
 WebGLTexture::WebGLTexture(WebGLContext *context)
-    : WebGLContextBoundObject(context)
-    , mHasEverBeenBound(false)
-    , mTarget(0)
+    : WebGLBindableName()
+    , WebGLContextBoundObject(context)
     , 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(WebGLTextureFakeBlackStatus::IncompleteTexture)
@@ -103,51 +102,58 @@ WebGLTexture::DoesTexture2DMipmapHaveAll
     return false;
 }
 
 void
 WebGLTexture::Bind(GLenum aTarget) {
     // this function should only be called by bindTexture().
     // it assumes that the GL context is already current.
 
-    bool firstTimeThisTextureIsBound = !mHasEverBeenBound;
+    bool firstTimeThisTextureIsBound = !HasEverBeenBound();
 
-    if (!firstTimeThisTextureIsBound && aTarget != mTarget) {
+    if (firstTimeThisTextureIsBound) {
+        BindTo(aTarget);
+    } else if (aTarget != Target()) {
         mContext->ErrorInvalidOperation("bindTexture: this texture has already been bound to a different target");
         // very important to return here before modifying texture state! This was the place when I lost a whole day figuring
         // very strange 'invalid write' crashes.
         return;
     }
 
-    mTarget = aTarget;
+    GLuint name = GLName();
+    GLenum target = Target();
 
-    mContext->gl->fBindTexture(mTarget, mGLName);
+    mContext->gl->fBindTexture(target, name);
 
     if (firstTimeThisTextureIsBound) {
         mFacesCount = (mTarget == LOCAL_GL_TEXTURE_2D) ? 1 : 6;
         EnsureMaxLevelWithCustomImagesAtLeast(0);
         SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
 
         // thanks to the WebKit people for finding this out: GL_TEXTURE_WRAP_R is not
         // present in GLES 2, but is present in GL and it seems as if for cube maps
         // we need to set it to GL_CLAMP_TO_EDGE to get the expected GLES behavior.
         if (mTarget == LOCAL_GL_TEXTURE_CUBE_MAP && !mContext->gl->IsGLES())
             mContext->gl->fTexParameteri(mTarget, LOCAL_GL_TEXTURE_WRAP_R, LOCAL_GL_CLAMP_TO_EDGE);
     }
-
-    mHasEverBeenBound = true;
 }
 
 void
 WebGLTexture::SetImageInfo(GLenum aTarget, GLint aLevel,
                   GLsizei aWidth, GLsizei aHeight,
                   GLenum aFormat, GLenum aType, WebGLImageDataStatus aStatus)
 {
-    if ( (aTarget == LOCAL_GL_TEXTURE_2D) != (mTarget == LOCAL_GL_TEXTURE_2D) )
+    // TODO(djg): I suspected the following ASSERT and check are
+    //            trying to express more than they're saying, probably
+    //            to do with cubemap targets. We should do this
+    //            properly. https://bugzilla.mozilla.org/show_bug.cgi?id=1006908
+    MOZ_ASSERT((aTarget == LOCAL_GL_TEXTURE_2D) == (mTarget == LOCAL_GL_TEXTURE_2D));
+    if ((aTarget == LOCAL_GL_TEXTURE_2D) != (mTarget == LOCAL_GL_TEXTURE_2D)) {
         return;
+    }
 
     EnsureMaxLevelWithCustomImagesAtLeast(aLevel);
 
     ImageInfoAt(aTarget, aLevel) = ImageInfo(aWidth, aHeight, aFormat, aType, aStatus);
 
     if (aLevel > 0)
         SetCustomMipmap();
 
--- a/dom/canvas/WebGLTexture.h
+++ b/dom/canvas/WebGLTexture.h
@@ -1,18 +1,19 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef WEBGLTEXTURE_H_
 #define WEBGLTEXTURE_H_
 
+#include "WebGLBindableName.h"
+#include "WebGLFramebufferAttachable.h"
 #include "WebGLObjectModel.h"
-#include "WebGLFramebufferAttachable.h"
 
 #include "nsWrapperCache.h"
 
 #include "mozilla/CheckedInt.h"
 #include "mozilla/LinkedList.h"
 #include <algorithm>
 
 namespace mozilla {
@@ -22,31 +23,27 @@ inline bool is_pot_assuming_nonnegative(
 {
     return x && (x & (x-1)) == 0;
 }
 
 // NOTE: When this class is switched to new DOM bindings, update the (then-slow)
 // WrapObject calls in GetParameter and GetFramebufferAttachmentParameter.
 class WebGLTexture MOZ_FINAL
     : public nsWrapperCache
+    , public WebGLBindableName
     , public WebGLRefCountedObject<WebGLTexture>
     , public LinkedListElement<WebGLTexture>
     , public WebGLContextBoundObject
     , public WebGLFramebufferAttachable
 {
 public:
     WebGLTexture(WebGLContext *context);
 
     void Delete();
 
-    bool HasEverBeenBound() const { return mHasEverBeenBound; }
-    void SetHasEverBeenBound(bool x) { mHasEverBeenBound = x; }
-    GLuint GLName() const { return mGLName; }
-    GLenum Target() const { return mTarget; }
-
     WebGLContext *GetParentObject() const {
         return Context();
     }
 
     virtual JSObject* WrapObject(JSContext *cx) MOZ_OVERRIDE;
 
     NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLTexture)
     NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLTexture)
@@ -54,19 +51,16 @@ public:
 protected:
     ~WebGLTexture() {
         DeleteOnce();
     }
 
     friend class WebGLContext;
     friend class WebGLFramebuffer;
 
-    bool mHasEverBeenBound;
-    GLuint mGLName;
-
     // we store information about the various images that are part of
     // this texture (cubemap faces, mipmap levels)
 
 public:
 
     class ImageInfo
         : public WebGLRectangleObject
     {
@@ -200,17 +194,16 @@ public:
         }
         imageInfo.mImageDataStatus = newStatus;
     }
 
     void DoDeferredImageInitialization(GLenum imageTarget, GLint level);
 
 protected:
 
-    GLenum mTarget;
     GLenum mMinFilter, mMagFilter, mWrapS, mWrapT;
 
     size_t mFacesCount, mMaxLevelWithCustomImages;
     nsTArray<ImageInfo> mImageInfos;
 
     bool mHaveGeneratedMipmap;
     WebGLTextureFakeBlackStatus mFakeBlackStatus;
 
@@ -273,17 +266,17 @@ public:
 
     bool IsMipmapTexture2DComplete() const;
 
     bool IsCubeComplete() const;
 
     bool IsMipmapCubeComplete() const;
 
     void SetFakeBlackStatus(WebGLTextureFakeBlackStatus x);
-    
+
     // Returns the current fake-black-status, except if it was Unknown,
     // in which case this function resolves it first, so it never returns Unknown.
     WebGLTextureFakeBlackStatus ResolvedFakeBlackStatus();
 };
 
 } // namespace mozilla
 
 #endif
--- a/dom/canvas/WebGLVertexArray.cpp
+++ b/dom/canvas/WebGLVertexArray.cpp
@@ -15,19 +15,18 @@
 using namespace mozilla;
 
 JSObject*
 WebGLVertexArray::WrapObject(JSContext *cx) {
     return dom::WebGLVertexArrayBinding::Wrap(cx, this);
 }
 
 WebGLVertexArray::WebGLVertexArray(WebGLContext* context)
-    : WebGLContextBoundObject(context)
-    , mGLName(0)
-    , mHasEverBeenBound(false)
+    : WebGLBindableName()
+    , WebGLContextBoundObject(context)
 {
     SetIsDOMBinding();
     context->mVertexArrays.insertBack(this);
 }
 
 WebGLVertexArray*
 WebGLVertexArray::Create(WebGLContext* context)
 {
--- a/dom/canvas/WebGLVertexArray.h
+++ b/dom/canvas/WebGLVertexArray.h
@@ -1,41 +1,45 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef WEBGLVERTEXARRAY_H_
 #define WEBGLVERTEXARRAY_H_
 
+#include "WebGLBindableName.h"
 #include "WebGLObjectModel.h"
 #include "WebGLBuffer.h"
 #include "WebGLVertexAttribData.h"
 
 #include "nsWrapperCache.h"
 
 #include "mozilla/LinkedList.h"
 
 namespace mozilla {
 
 class WebGLVertexArrayFake;
 
 class WebGLVertexArray
     : public nsWrapperCache
+    , public WebGLBindableName
     , public WebGLRefCountedObject<WebGLVertexArray>
     , public LinkedListElement<WebGLVertexArray>
     , public WebGLContextBoundObject
 {
 // -----------------------------------------------------------------------------
 // PUBLIC
 public:
     static WebGLVertexArray* Create(WebGLContext* context);
 
     void BindVertexArray() {
-        SetHasEverBeenBound(true);
+        /* Bind to dummy value to signal that this vertex array has
+           ever been bound */
+        BindTo(LOCAL_GL_VERTEX_ARRAY_BINDING);
         BindVertexArrayImpl();
     };
 
     virtual void GenVertexArray() = 0;
     virtual void BindVertexArrayImpl() = 0;
 
     GLuint GLName() const { return mGLName; }
 
@@ -53,19 +57,16 @@ public:
     virtual JSObject* WrapObject(JSContext *cx) MOZ_OVERRIDE;
 
     NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLVertexArray)
     NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLVertexArray)
 
     // -------------------------------------------------------------------------
     // MEMBER FUNCTIONS
 
-    bool HasEverBeenBound() { return mHasEverBeenBound; }
-    void SetHasEverBeenBound(bool x) { mHasEverBeenBound = x; }
-
     bool EnsureAttrib(GLuint index, const char *info);
     bool HasAttrib(GLuint index) {
         return index < mAttribs.Length();
     }
     bool IsAttribArrayEnabled(GLuint index) {
         return HasAttrib(index) && mAttribs[index].enabled;
     }
 
@@ -77,18 +78,16 @@ protected:
 
     virtual ~WebGLVertexArray() {
         MOZ_ASSERT(IsDeleted());
     };
 
     // -------------------------------------------------------------------------
     // MEMBERS
 
-    GLuint mGLName;
-    bool mHasEverBeenBound;
     nsTArray<WebGLVertexAttribData> mAttribs;
     WebGLRefPtr<WebGLBuffer> mElementArrayBuffer;
 
     // -------------------------------------------------------------------------
     // FRIENDSHIPS
 
     friend class WebGLVertexArrayFake;
     friend class WebGLContext;
--- a/dom/canvas/moz.build
+++ b/dom/canvas/moz.build
@@ -36,16 +36,17 @@ UNIFIED_SOURCES += [
 ]
 
 if CONFIG['MOZ_WEBGL']:
     UNIFIED_SOURCES += [
         'MurmurHash3.cpp',
         'WebGL1Context.cpp',
         'WebGL2Context.cpp',
         'WebGLActiveInfo.cpp',
+        'WebGLBindableName.cpp',
         'WebGLBuffer.cpp',
         'WebGLContext.cpp',
         'WebGLContextAsyncQueries.cpp',
         'WebGLContextBuffers.cpp',
         'WebGLContextDraw.cpp',
         'WebGLContextExtensions.cpp',
         'WebGLContextFramebufferOperations.cpp',
         'WebGLContextGL.cpp',