Bug 1372157 - Fix IsFoo results in WebGL. r=kvark
☠☠ backed out by 13b39a6aa15f ☠ ☠
authorJeff Gilbert <jgilbert@mozilla.com>
Tue, 16 Oct 2018 23:54:28 -0700
changeset 491129 4b5b1ff23dd7247ed098ac805c60292743f8eb20
parent 491128 d3e5a0aa6867b2be1a9d651bbfc7efd97b928171
child 491130 c498bd18345d9061826a752b43d95a72e1593ceb
push id247
push userfmarier@mozilla.com
push dateSat, 27 Oct 2018 01:06:44 +0000
reviewerskvark
bugs1372157
milestone65.0a1
Bug 1372157 - Fix IsFoo results in WebGL. r=kvark Passes deqp/functional/gles3/lifetime.html. Differential Revision: https://phabricator.services.mozilla.com/D8956
dom/canvas/WebGL2ContextSamplers.cpp
dom/canvas/WebGL2ContextTransformFeedback.cpp
dom/canvas/WebGLContext.cpp
dom/canvas/WebGLContextGL.cpp
dom/canvas/WebGLContextUtils.cpp
dom/canvas/WebGLContextValidate.cpp
dom/canvas/WebGLContextVertexArray.cpp
dom/canvas/WebGLFramebuffer.cpp
dom/canvas/WebGLFramebuffer.h
dom/canvas/WebGLRenderbuffer.cpp
dom/canvas/WebGLRenderbuffer.h
dom/canvas/WebGLSampler.cpp
dom/canvas/WebGLSampler.h
dom/canvas/WebGLStrongTypes.h
dom/canvas/WebGLTexture.cpp
dom/canvas/WebGLTexture.h
dom/canvas/WebGLTransformFeedback.h
dom/canvas/WebGLVertexArray.cpp
dom/canvas/WebGLVertexArray.h
dom/canvas/WebGLVertexArrayFake.cpp
dom/canvas/WebGLVertexArrayFake.h
dom/canvas/WebGLVertexArrayGL.cpp
dom/canvas/WebGLVertexArrayGL.h
dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-vertex-array-object.html
--- a/dom/canvas/WebGL2ContextSamplers.cpp
+++ b/dom/canvas/WebGL2ContextSamplers.cpp
@@ -38,17 +38,20 @@ WebGL2Context::DeleteSampler(WebGLSample
 
 bool
 WebGL2Context::IsSampler(const WebGLSampler* const obj)
 {
     const FuncScope funcScope(*this, "isSampler");
     if (!ValidateIsObject(obj))
         return false;
 
-    return gl->fIsSampler(obj->mGLName);
+    if (obj->IsDeleteRequested())
+        return false;
+
+    return true;
 }
 
 void
 WebGL2Context::BindSampler(GLuint unit, WebGLSampler* sampler)
 {
     const FuncScope funcScope(*this, "bindSampler");
     if (IsContextLost())
         return;
--- a/dom/canvas/WebGL2ContextTransformFeedback.cpp
+++ b/dom/canvas/WebGL2ContextTransformFeedback.cpp
@@ -49,17 +49,20 @@ WebGL2Context::DeleteTransformFeedback(W
 
 bool
 WebGL2Context::IsTransformFeedback(const WebGLTransformFeedback* const obj)
 {
     const FuncScope funcScope(*this, "isTransformFeedback");
     if (!ValidateIsObject(obj))
         return false;
 
-    return gl->fIsTransformFeedback(obj->mGLName);
+    if (obj->IsDeleteRequested())
+        return false;
+
+    return obj->mHasBeenBound;
 }
 
 void
 WebGL2Context::BindTransformFeedback(GLenum target, WebGLTransformFeedback* tf)
 {
     const FuncScope funcScope(*this, "bindTransformFeedback");
     if (IsContextLost())
         return;
@@ -85,16 +88,17 @@ WebGL2Context::BindTransformFeedback(GLe
     }
 
     mBoundTransformFeedback = (tf ? tf : mDefaultTransformFeedback);
 
     gl->fBindTransformFeedback(target, mBoundTransformFeedback->mGLName);
 
     if (mBoundTransformFeedback) {
         mBoundTransformFeedback->AddBufferBindCounts(+1);
+        mBoundTransformFeedback->mHasBeenBound = true;
     }
 }
 
 void
 WebGL2Context::BeginTransformFeedback(GLenum primMode)
 {
     const FuncScope funcScope(*this, "beginTransformFeedback");
     if (IsContextLost())
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -2488,17 +2488,20 @@ WebGLContext::ValidateIsObject(const Web
         return false;
 
     if (!object)
         return false;
 
     if (!object->IsCompatibleWithContext(this))
         return false;
 
-    return !object->IsDeleted();
+    if (object->IsDeleted())
+        return false;
+
+    return true;
 }
 
 bool
 WebGLContext::ValidateDeleteObject(const WebGLDeletableObject* const object)
 {
     if (IsContextLost())
         return false;
 
--- a/dom/canvas/WebGLContextGL.cpp
+++ b/dom/canvas/WebGLContextGL.cpp
@@ -142,19 +142,17 @@ WebGLContext::BindFramebuffer(GLenum tar
     if (wfb && !ValidateObject("fb", *wfb))
         return;
 
     if (!wfb) {
         gl->fBindFramebuffer(target, 0);
     } else {
         GLuint framebuffername = wfb->mGLName;
         gl->fBindFramebuffer(target, framebuffername);
-#ifdef ANDROID
-        wfb->mIsFB = true;
-#endif
+        wfb->mHasBeenBound = true;
     }
 
     switch (target) {
     case LOCAL_GL_FRAMEBUFFER:
         mBoundDrawFramebuffer = wfb;
         mBoundReadFramebuffer = wfb;
         break;
     case LOCAL_GL_DRAW_FRAMEBUFFER:
@@ -1060,61 +1058,65 @@ WebGLContext::Hint(GLenum target, GLenum
 
 bool
 WebGLContext::IsBuffer(const WebGLBuffer* const obj)
 {
     const FuncScope funcScope(*this, "isBuffer");
     if (!ValidateIsObject(obj))
         return false;
 
-    return gl->fIsBuffer(obj->mGLName);
+    if (obj->IsDeleteRequested())
+        return false;
+
+    return obj->Content() != WebGLBuffer::Kind::Undefined;
 }
 
 bool
 WebGLContext::IsFramebuffer(const WebGLFramebuffer* const obj)
 {
     const FuncScope funcScope(*this, "isFramebuffer");
     if (!ValidateIsObject(obj))
         return false;
 
-#ifdef ANDROID
-    if (gl->WorkAroundDriverBugs() &&
-        gl->Renderer() == GLRenderer::AndroidEmulator)
-    {
-        return obj->mIsFB;
-    }
-#endif
-
-    return gl->fIsFramebuffer(obj->mGLName);
+    if (obj->IsDeleteRequested())
+        return false;
+
+    return obj->mHasBeenBound;
 }
 
 bool
 WebGLContext::IsProgram(const WebGLProgram* const obj)
 {
     const FuncScope funcScope(*this, "isProgram");
     return ValidateIsObject(obj);
 }
 
 bool
 WebGLContext::IsQuery(const WebGLQuery* const obj)
 {
     const FuncScope funcScope(*this, "isQuery");
     if (!ValidateIsObject(obj))
         return false;
 
-    return obj->IsQuery();
+    if (obj->IsDeleteRequested())
+        return false;
+
+    return bool(obj->Target());
 }
 
 bool
 WebGLContext::IsRenderbuffer(const WebGLRenderbuffer* const obj)
 {
     const FuncScope funcScope(*this, "isRenderbuffer");
     if (!ValidateIsObject(obj))
         return false;
 
+    if (obj->IsDeleteRequested())
+        return false;
+
     return obj->mHasBeenBound;
 }
 
 bool
 WebGLContext::IsShader(const WebGLShader* const obj)
 {
     const FuncScope funcScope(*this, "isShader");
     return ValidateIsObject(obj);
@@ -1122,27 +1124,33 @@ WebGLContext::IsShader(const WebGLShader
 
 bool
 WebGLContext::IsTexture(const WebGLTexture* const obj)
 {
     const FuncScope funcScope(*this, "isTexture");
     if (!ValidateIsObject(obj))
         return false;
 
-    return obj->IsTexture();
+    if (obj->IsDeleteRequested())
+        return false;
+
+    return bool(obj->Target());
 }
 
 bool
 WebGLContext::IsVertexArray(const WebGLVertexArray* const obj)
 {
     const FuncScope funcScope(*this, "isVertexArray");
     if (!ValidateIsObject(obj))
         return false;
 
-    return obj->IsVertexArray();
+    if (obj->IsDeleteRequested())
+        return false;
+
+    return obj->mHasBeenBound;
 }
 
 // -
 
 void
 WebGLContext::LinkProgram(WebGLProgram& prog)
 {
     const FuncScope funcScope(*this, "linkProgram");
--- a/dom/canvas/WebGLContextUtils.cpp
+++ b/dom/canvas/WebGLContextUtils.cpp
@@ -697,18 +697,18 @@ AssertUintParamCorrect(gl::GLContext*, G
 
 void
 WebGLContext::AssertCachedBindings() const
 {
 #ifdef DEBUG
     GetAndFlushUnderlyingGLErrors();
 
     if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::OES_vertex_array_object)) {
-        GLuint bound = mBoundVertexArray ? mBoundVertexArray->GLName() : 0;
-        AssertUintParamCorrect(gl, LOCAL_GL_VERTEX_ARRAY_BINDING, bound);
+        AssertUintParamCorrect(gl, LOCAL_GL_VERTEX_ARRAY_BINDING,
+                               mBoundVertexArray->mGLName);
     }
 
     GLint stencilBits = 0;
     if (GetStencilBits(&stencilBits)) { // Depends on current draw framebuffer.
         const GLuint stencilRefMask = (1 << stencilBits) - 1;
 
         AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_REF,      stencilRefMask, mStencilRefFront);
         AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_REF, stencilRefMask, mStencilRefBack);
--- a/dom/canvas/WebGLContextValidate.cpp
+++ b/dom/canvas/WebGLContextValidate.cpp
@@ -621,33 +621,27 @@ WebGLContext::InitAndValidateGL(FailureR
     }
 
     if (!gl->IsSupported(GLFeature::vertex_array_object)) {
         *out_failReason = { "FEATURE_FAILURE_WEBGL_VAOS",
                             "Requires vertex_array_object." };
         return false;
     }
 
-    mDefaultVertexArray = WebGLVertexArray::Create(this);
-    mDefaultVertexArray->mAttribs.SetLength(mGLMaxVertexAttribs);
-    mBoundVertexArray = mDefaultVertexArray;
-
     // OpenGL core profiles remove the default VAO object from version
     // 4.0.0. We create a default VAO for all core profiles,
     // regardless of version.
     //
     // GL Spec 4.0.0:
     // (https://www.opengl.org/registry/doc/glspec40.core.20100311.pdf)
     // in Section E.2.2 "Removed Features", pg 397: "[...] The default
     // vertex array object (the name zero) is also deprecated. [...]"
-
-    if (gl->IsCoreProfile()) {
-        mDefaultVertexArray->GenVertexArray();
-        mDefaultVertexArray->BindVertexArray();
-    }
+    mDefaultVertexArray = WebGLVertexArray::Create(this);
+    mDefaultVertexArray->BindVertexArray();
+    mDefaultVertexArray->mAttribs.SetLength(mGLMaxVertexAttribs);
 
     mPixelStore_FlipY = false;
     mPixelStore_PremultiplyAlpha = false;
     mPixelStore_ColorspaceConversion = BROWSER_DEFAULT_WEBGL;
     mPixelStore_RequireFastPath = false;
 
     // GLES 3.0.4, p259:
     mPixelStore_UnpackImageHeight = 0;
--- a/dom/canvas/WebGLContextVertexArray.cpp
+++ b/dom/canvas/WebGLContextVertexArray.cpp
@@ -30,30 +30,28 @@ WebGLContext::BindVertexArray(WebGLVerte
         array = mDefaultVertexArray;
     }
 
     array->BindVertexArray();
 
     MOZ_ASSERT(mBoundVertexArray == array);
     if (mBoundVertexArray) {
         mBoundVertexArray->AddBufferBindCounts(+1);
+        mBoundVertexArray->mHasBeenBound = true;
     }
 }
 
 already_AddRefed<WebGLVertexArray>
 WebGLContext::CreateVertexArray()
 {
     const FuncScope funcScope(*this, "createVertexArray");
     if (IsContextLost())
         return nullptr;
 
     RefPtr<WebGLVertexArray> globj = CreateVertexArrayImpl();
-
-    globj->GenVertexArray();
-
     return globj.forget();
 }
 
 WebGLVertexArray*
 WebGLContext::CreateVertexArrayImpl()
 {
     return WebGLVertexArray::Create(this);
 }
--- a/dom/canvas/WebGLFramebuffer.cpp
+++ b/dom/canvas/WebGLFramebuffer.cpp
@@ -503,20 +503,16 @@ WebGLFramebuffer::Delete()
 
     for (auto& cur : mColorAttachments) {
         cur.Clear();
     }
 
     mContext->gl->fDeleteFramebuffers(1, &mGLName);
 
     LinkedListElement<WebGLFramebuffer>::removeFrom(mContext->mFramebuffers);
-
-#ifdef ANDROID
-    mIsFB = false;
-#endif
 }
 
 ////
 
 Maybe<WebGLFBAttachPoint*>
 WebGLFramebuffer::GetColorAttachPoint(GLenum attachPoint)
 {
     if (attachPoint == LOCAL_GL_NONE)
@@ -1227,17 +1223,17 @@ WebGLFramebuffer::FramebufferTexture2D(G
         return;
     }
 
     // `texture`
     if (tex) {
         if (!mContext->ValidateObject("texture", *tex))
             return;
 
-        if (!tex->HasEverBeenBound()) {
+        if (!tex->Target()) {
             mContext->ErrorInvalidOperation("`texture` has never been bound.");
             return;
         }
 
         const TexTarget destTexTarget = TexImageTargetToTexTarget(texImageTarget);
         if (tex->Target() != destTexTarget) {
             mContext->ErrorInvalidOperation("Mismatched texture and texture target.");
             return;
@@ -1312,17 +1308,17 @@ WebGLFramebuffer::FramebufferTextureLaye
         return mContext->ErrorInvalidValue("`level` must be >= 0.");
 
     // `texture`
     GLenum texImageTarget = LOCAL_GL_TEXTURE_3D;
     if (tex) {
         if (!mContext->ValidateObject("texture", *tex))
             return;
 
-        if (!tex->HasEverBeenBound()) {
+        if (!tex->Target()) {
             mContext->ErrorInvalidOperation("`texture` has never been bound.");
             return;
         }
 
         texImageTarget = tex->Target().get();
         switch (texImageTarget) {
         case LOCAL_GL_TEXTURE_3D:
             if (uint32_t(layer) >= mContext->mGLMax3DTextureSize) {
--- a/dom/canvas/WebGLFramebuffer.h
+++ b/dom/canvas/WebGLFramebuffer.h
@@ -135,38 +135,28 @@ public:
 
 class WebGLFramebuffer final
     : public nsWrapperCache
     , public WebGLRefCountedObject<WebGLFramebuffer>
     , public LinkedListElement<WebGLFramebuffer>
     , public SupportsWeakPtr<WebGLFramebuffer>
     , public CacheInvalidator
 {
-    friend class WebGLContext;
-
 public:
     MOZ_DECLARE_WEAKREFERENCE_TYPENAME(WebGLFramebuffer)
 
     const GLuint mGLName;
+    bool mHasBeenBound = false;
 
 private:
     mutable uint64_t mNumFBStatusInvals = 0;
 
-protected:
-#ifdef ANDROID
-    // Bug 1140459: Some drivers (including our test slaves!) don't
-    // give reasonable answers for IsRenderbuffer, maybe others.
-    // This shows up on Android 2.3 emulator.
-    //
-    // So we track the `is a Framebuffer` state ourselves.
-    bool mIsFB = false;
-#endif
-
     ////
 
+protected:
     WebGLFBAttachPoint mDepthAttachment;
     WebGLFBAttachPoint mStencilAttachment;
     WebGLFBAttachPoint mDepthStencilAttachment;
 
     // In theory, this number can be unbounded based on the driver. However, no driver
     // appears to expose more than 8. We might as well stop there too, for now.
     // (http://opengl.gpuinfo.org/gl_stats_caps_single.php?listreportsbycap=GL_MAX_COLOR_ATTACHMENTS)
     static const size_t kMaxColorAttachments = 8; // jgilbert's MacBook Pro exposes 8.
--- a/dom/canvas/WebGLRenderbuffer.cpp
+++ b/dom/canvas/WebGLRenderbuffer.cpp
@@ -47,17 +47,16 @@ EmulatePackedDepthStencil(gl::GLContext*
     return !gl->IsSupported(gl::GLFeature::packed_depth_stencil);
 }
 
 WebGLRenderbuffer::WebGLRenderbuffer(WebGLContext* webgl)
     : WebGLRefCountedObject(webgl)
     , mPrimaryRB( DoCreateRenderbuffer(webgl->gl) )
     , mEmulatePackedDepthStencil( EmulatePackedDepthStencil(webgl->gl) )
     , mSecondaryRB(0)
-    , mHasBeenBound(false)
 {
     mContext->mRenderbuffers.insertBack(this);
 
     // Bind our RB, or we might end up calling FramebufferRenderbuffer before we ever call
     // BindRenderbuffer, since webgl.bindRenderbuffer doesn't actually call
     // glBindRenderbuffer anymore.
     mContext->gl->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mPrimaryRB);
 }
--- a/dom/canvas/WebGLRenderbuffer.h
+++ b/dom/canvas/WebGLRenderbuffer.h
@@ -21,26 +21,25 @@ struct FormatUsageInfo;
 
 class WebGLRenderbuffer final
     : public nsWrapperCache
     , public WebGLRefCountedObject<WebGLRenderbuffer>
     , public LinkedListElement<WebGLRenderbuffer>
     , public WebGLRectangleObject
     , public CacheInvalidator
 {
-    friend class WebGLContext;
     friend class WebGLFramebuffer;
     friend class WebGLFBAttachPoint;
 
 public:
     const GLuint mPrimaryRB;
+    bool mHasBeenBound = false;
 protected:
     const bool mEmulatePackedDepthStencil;
     GLuint mSecondaryRB;
-    bool mHasBeenBound;
     webgl::ImageInfo mImageInfo;
 
 public:
     NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLRenderbuffer)
     NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLRenderbuffer)
 
     explicit WebGLRenderbuffer(WebGLContext* webgl);
 
--- a/dom/canvas/WebGLSampler.cpp
+++ b/dom/canvas/WebGLSampler.cpp
@@ -6,18 +6,16 @@
 #include "WebGLSampler.h"
 
 #include "GLContext.h"
 #include "mozilla/dom/WebGL2RenderingContextBinding.h"
 #include "WebGLContext.h"
 
 namespace mozilla {
 
-
-
 WebGLSampler::WebGLSampler(WebGLContext* const webgl)
     : WebGLRefCountedObject(webgl)
     , mGLName([&]() {
         GLuint ret = 0;
         webgl->gl->fGenSamplers(1, &ret);
         return ret;
     }())
 {
--- a/dom/canvas/WebGLSampler.h
+++ b/dom/canvas/WebGLSampler.h
@@ -15,19 +15,16 @@
 namespace mozilla {
 
 class WebGLSampler final
     : public nsWrapperCache
     , public WebGLRefCountedObject<WebGLSampler>
     , public LinkedListElement<WebGLSampler>
     , public CacheInvalidator
 {
-    friend class WebGLContext2;
-    friend class WebGLTexture;
-
     NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLSampler)
     NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLSampler)
 
 public:
     const GLuint mGLName;
 private:
     webgl::SamplingState mState;
 
--- a/dom/canvas/WebGLStrongTypes.h
+++ b/dom/canvas/WebGLStrongTypes.h
@@ -150,16 +150,18 @@ public:
     bool operator<=(const StrongGLenum& other) const {
         return get() <= other.get();
     }
 
     bool operator>=(const StrongGLenum& other) const {
         return get() >= other.get();
     }
 
+    explicit operator bool() const { return bool(get()); }
+
     static bool IsValueLegal(GLenum value) {
         if (value > UINT16_MAX) {
             return false;
         }
         return std::binary_search(Details::values(),
                                   Details::values() + Details::valuesCount(),
                                   uint16_t(value));
     }
--- a/dom/canvas/WebGLTexture.cpp
+++ b/dom/canvas/WebGLTexture.cpp
@@ -693,17 +693,17 @@ WebGLTexture::ClampLevelBaseAndMax()
 bool
 WebGLTexture::BindTexture(TexTarget texTarget)
 {
     if (IsDeleted()) {
         mContext->ErrorInvalidOperation("bindTexture: Cannot bind a deleted object.");
         return false;
     }
 
-    const bool isFirstBinding = !HasEverBeenBound();
+    const bool isFirstBinding = !mTarget;
     if (!isFirstBinding && mTarget != texTarget) {
         mContext->ErrorInvalidOperation("bindTexture: This texture has already been bound"
                                         " to a different target.");
         return false;
     }
 
     mTarget = texTarget;
 
@@ -851,22 +851,16 @@ WebGLTexture::GetTexParameter(TexTarget 
         mContext->gl->fGetTexParameterfv(texTarget.get(), pname, &f);
         return JS::NumberValue(float(f));
 
     default:
         MOZ_CRASH("GFX: Unhandled pname.");
     }
 }
 
-bool
-WebGLTexture::IsTexture() const
-{
-    return HasEverBeenBound() && !IsDeleted();
-}
-
 // Here we have to support all pnames with both int and float params.
 // See this discussion:
 //   https://www.khronos.org/webgl/public-mailing-list/archives/1008/msg00014.html
 void
 WebGLTexture::TexParameter(TexTarget texTarget, GLenum pname, const FloatOrInt& param)
 {
     bool isPNameValid = false;
     switch (pname) {
--- a/dom/canvas/WebGLTexture.h
+++ b/dom/canvas/WebGLTexture.h
@@ -167,17 +167,16 @@ public:
 
     NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLTexture)
     NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLTexture)
 
     WebGLTexture(WebGLContext* webgl, GLuint tex);
 
     void Delete();
 
-    bool HasEverBeenBound() const { return mTarget != LOCAL_GL_NONE; }
     TexTarget Target() const { return mTarget; }
 
     WebGLContext* GetParentObject() const {
         return mContext;
     }
 
     virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) override;
 
@@ -187,17 +186,16 @@ protected:
     }
 
 public:
     ////////////////////////////////////
     // GL calls
     bool BindTexture(TexTarget texTarget);
     void GenerateMipmap();
     JS::Value GetTexParameter(TexTarget texTarget, GLenum pname);
-    bool IsTexture() const;
     void TexParameter(TexTarget texTarget, GLenum pname, const FloatOrInt& param);
 
     ////////////////////////////////////
     // WebGLTextureUpload.cpp
 
 protected:
     void TexOrSubImageBlob(bool isSubImage, TexImageTarget target,
                            GLint level, GLenum internalFormat, GLint xOffset,
--- a/dom/canvas/WebGLTransformFeedback.h
+++ b/dom/canvas/WebGLTransformFeedback.h
@@ -25,16 +25,17 @@ class WebGLTransformFeedback final
     friend class WebGL2Context;
     friend class WebGLProgram;
 
     friend const webgl::CachedDrawFetchLimits*
         ValidateDraw(WebGLContext*, GLenum, uint32_t);
 
 public:
     const GLuint mGLName;
+    bool mHasBeenBound = false;
 private:
     // GLES 3.0.4 p267, Table 6.24 "Transform Feedback State"
     // It's not yet in the ES3 spec, but the generic TF buffer bind point has been moved
     // to context state, instead of TFO state.
     std::vector<IndexedBufferBinding> mIndexedBindings;
     bool mIsPaused;
     bool mIsActive;
     // Not in state tables:
--- a/dom/canvas/WebGLVertexArray.cpp
+++ b/dom/canvas/WebGLVertexArray.cpp
@@ -15,19 +15,19 @@
 namespace mozilla {
 
 JSObject*
 WebGLVertexArray::WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto)
 {
     return dom::WebGLVertexArrayObject_Binding::Wrap(cx, this, givenProto);
 }
 
-WebGLVertexArray::WebGLVertexArray(WebGLContext* webgl)
+WebGLVertexArray::WebGLVertexArray(WebGLContext* const webgl, const GLuint name)
     : WebGLRefCountedObject(webgl)
-    , mGLName(0)
+    , mGLName(name)
 {
     mAttribs.SetLength(mContext->mGLMaxVertexAttribs);
     mContext->mVertexArrays.insertBack(this);
 }
 
 WebGLVertexArray::~WebGLVertexArray()
 {
     MOZ_ASSERT(IsDeleted());
@@ -60,22 +60,16 @@ WebGLVertexArray::Delete()
 {
     DeleteImpl();
 
     LinkedListElement<WebGLVertexArray>::removeFrom(mContext->mVertexArrays);
     mElementArrayBuffer = nullptr;
     mAttribs.Clear();
 }
 
-bool
-WebGLVertexArray::IsVertexArray() const
-{
-    return IsVertexArrayImpl();
-}
-
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLVertexArray,
                                       mAttribs,
                                       mElementArrayBuffer)
 
 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLVertexArray, AddRef)
 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLVertexArray, Release)
 
 } // namespace mozilla
--- a/dom/canvas/WebGLVertexArray.h
+++ b/dom/canvas/WebGLVertexArray.h
@@ -26,49 +26,40 @@ class WebGLVertexArray
     : public nsWrapperCache
     , public WebGLRefCountedObject<WebGLVertexArray>
     , public LinkedListElement<WebGLVertexArray>
     , public CacheInvalidator
 {
 public:
     static WebGLVertexArray* Create(WebGLContext* webgl);
 
-    void BindVertexArray() {
-        // Bind to dummy value to signal that this vertex array has ever been
-        // bound.
-        BindVertexArrayImpl();
-    };
-
-    // Implement parent classes:
     void Delete();
-    bool IsVertexArray() const;
 
     WebGLContext* GetParentObject() const {
         return mContext;
     }
 
     virtual JSObject* WrapObject(JSContext* cx, JS::Handle<JSObject*> givenProto) override;
 
     NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLVertexArray)
     NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLVertexArray)
 
-    GLuint GLName() const { return mGLName; }
-
     void AddBufferBindCounts(int8_t addVal) const;
 
 protected:
-    explicit WebGLVertexArray(WebGLContext* webgl);
+    WebGLVertexArray(WebGLContext* webgl, GLuint name);
     virtual ~WebGLVertexArray();
 
-    virtual void GenVertexArray() = 0;
-    virtual void BindVertexArrayImpl() = 0;
+    virtual void BindVertexArray() = 0;
     virtual void DeleteImpl() = 0;
-    virtual bool IsVertexArrayImpl() const = 0;
 
-    GLuint mGLName;
+public:
+    const GLuint mGLName;
+    bool mHasBeenBound = false;
+protected:
     nsTArray<WebGLVertexAttribData> mAttribs;
     WebGLRefPtr<WebGLBuffer> mElementArrayBuffer;
 
     friend class ScopedDrawHelper;
     friend class WebGLContext;
     friend class WebGLVertexArrayFake;
     friend class WebGL2Context;
     friend struct webgl::LinkedProgramInfo;
--- a/dom/canvas/WebGLVertexArrayFake.cpp
+++ b/dom/canvas/WebGLVertexArrayFake.cpp
@@ -6,22 +6,21 @@
 #include "WebGLVertexArrayFake.h"
 
 #include "GLContext.h"
 #include "WebGLContext.h"
 
 namespace mozilla {
 
 WebGLVertexArrayFake::WebGLVertexArrayFake(WebGLContext* webgl)
-    : WebGLVertexArray(webgl)
-    , mIsVAO(false)
+    : WebGLVertexArray(webgl, 0)
 { }
 
 void
-WebGLVertexArrayFake::BindVertexArrayImpl()
+WebGLVertexArrayFake::BindVertexArray()
 {
     // Go through and re-bind all buffers and setup all
     // vertex attribute pointers
     gl::GLContext* gl = mContext->gl;
 
     WebGLRefPtr<WebGLVertexArray> prevVertexArray = mContext->mBoundVertexArray;
 
     mContext->mBoundVertexArray = this;
@@ -47,24 +46,11 @@ WebGLVertexArrayFake::BindVertexArrayImp
         const auto& vd = prevVertexArray->mAttribs[i];
 
         if (vd.mEnabled) {
             gl->fDisableVertexAttribArray(i);
         }
     }
 
     mContext->BindBuffer(LOCAL_GL_ARRAY_BUFFER, prevBuffer);
-    mIsVAO = true;
-}
-
-void
-WebGLVertexArrayFake::DeleteImpl()
-{
-    mIsVAO = false;
-}
-
-bool
-WebGLVertexArrayFake::IsVertexArrayImpl() const
-{
-    return mIsVAO;
 }
 
 } // namespace mozilla
--- a/dom/canvas/WebGLVertexArrayFake.h
+++ b/dom/canvas/WebGLVertexArrayFake.h
@@ -11,26 +11,22 @@
 namespace mozilla {
 
 class WebGLVertexArrayFake final
     : public WebGLVertexArray
 {
     friend class WebGLVertexArray;
 
 protected:
-    virtual void BindVertexArrayImpl() override;
-    virtual void DeleteImpl() override;
-    virtual void GenVertexArray() override {};
-    virtual bool IsVertexArrayImpl() const override;
+    virtual void BindVertexArray() override;
+    virtual void DeleteImpl() override {}
 
 private:
     explicit WebGLVertexArrayFake(WebGLContext* webgl);
 
     ~WebGLVertexArrayFake() {
         DeleteOnce();
     }
-
-    bool mIsVAO;
 };
 
 } // namespace mozilla
 
 #endif // WEBGL_VERTEX_ARRAY_FAKE_H_
--- a/dom/canvas/WebGLVertexArrayGL.cpp
+++ b/dom/canvas/WebGLVertexArrayGL.cpp
@@ -6,55 +6,37 @@
 #include "WebGLVertexArrayGL.h"
 
 #include "GLContext.h"
 #include "WebGLContext.h"
 
 namespace mozilla {
 
 WebGLVertexArrayGL::WebGLVertexArrayGL(WebGLContext* webgl)
-    : WebGLVertexArray(webgl)
-    , mIsVAO(false)
+    : WebGLVertexArray(webgl,
+                       [&]() {
+                           GLuint ret = 0;
+                           webgl->gl->fGenVertexArrays(1, &ret);
+                           return ret;
+                       }())
 { }
 
 WebGLVertexArrayGL::~WebGLVertexArrayGL()
 {
     DeleteOnce();
 }
 
 void
 WebGLVertexArrayGL::DeleteImpl()
 {
     mElementArrayBuffer = nullptr;
 
     mContext->gl->fDeleteVertexArrays(1, &mGLName);
-
-    mIsVAO = false;
-}
-
-void
-WebGLVertexArrayGL::BindVertexArrayImpl()
-{
-    mContext->mBoundVertexArray = this;
-    mContext->gl->fBindVertexArray(mGLName);
-
-    mIsVAO = true;
 }
 
 void
-WebGLVertexArrayGL::GenVertexArray()
-{
-    mContext->gl->fGenVertexArrays(1, &mGLName);
-}
-
-bool
-WebGLVertexArrayGL::IsVertexArrayImpl() const
+WebGLVertexArrayGL::BindVertexArray()
 {
-    gl::GLContext* gl = mContext->gl;
-    if (gl->WorkAroundDriverBugs())
-    {
-        return mIsVAO;
-    }
-
-    return mContext->gl->fIsVertexArray(mGLName) != 0;
+    mContext->mBoundVertexArray = this;
+    mContext->gl->fBindVertexArray(mGLName);
 }
 
 } // namespace mozilla
--- a/dom/canvas/WebGLVertexArrayGL.h
+++ b/dom/canvas/WebGLVertexArrayGL.h
@@ -12,26 +12,18 @@ namespace mozilla {
 
 class WebGLVertexArrayGL
     : public WebGLVertexArray
 {
     friend class WebGLVertexArray;
 
 public:
     virtual void DeleteImpl() override;
-    virtual void BindVertexArrayImpl() override;
-    virtual void GenVertexArray() override;
-    virtual bool IsVertexArrayImpl() const override;
+    virtual void BindVertexArray() override;
 
 protected:
     explicit WebGLVertexArrayGL(WebGLContext* webgl);
     ~WebGLVertexArrayGL();
-
-    // Bug 1140459: Some drivers (including our test slaves!) don't
-    // give reasonable answers for IsVertexArray, maybe others.
-    //
-    // So we track the `is a VAO` state ourselves.
-    bool mIsVAO;
 };
 
 } // namespace mozilla
 
 #endif // WEBGL_VERTEX_ARRAY_GL_H_
--- a/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-vertex-array-object.html
+++ b/dom/canvas/test/webgl-conf/checkout/conformance/extensions/oes-vertex-array-object.html
@@ -640,22 +640,23 @@ function runBoundDeleteTests() {
         }
 
         // If retained, everything should still work. If cleared, drawing should now fail.
         gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_BYTE, 0);
         var expectedError = (expectRetained ? gl.NO_ERROR : gl.INVALID_OPERATION);
         wtu.glErrorShouldBe(gl, expectedError,
                             "Draw call should " + (expectRetained ? "not " : "") + "fail.");
 
-        if (!gl.isBuffer(positionBuffer)) {
-            testFailed("References from unbound VAOs keep Position buffer alive.");
-        }
-        if (!gl.isBuffer(colorBuffer)) {
-            testFailed("References from unbound VAOs keep Color buffer alive");
-        }
+        // https://github.com/KhronosGroup/WebGL/pull/2731
+        //if (!gl.isBuffer(positionBuffer)) {
+        //    testFailed("References from unbound VAOs keep Position buffer alive.");
+        //}
+        //if (!gl.isBuffer(colorBuffer)) {
+        //    testFailed("References from unbound VAOs keep Color buffer alive");
+        //}
     }
 }
 
 function runArrayBufferBindTests() {
     debug("");
     debug("Testing that buffer bindings on VAOs don't affect default VAO ARRAY_BUFFER binding.");
 
     ext.bindVertexArrayOES(null);