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 442797 4b5b1ff23dd7247ed098ac805c60292743f8eb20
parent 442796 d3e5a0aa6867b2be1a9d651bbfc7efd97b928171
child 442798 c498bd18345d9061826a752b43d95a72e1593ceb
push id109239
push userjgilbert@mozilla.com
push dateWed, 24 Oct 2018 18:24:45 +0000
treeherdermozilla-inbound@4b5b1ff23dd7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskvark
bugs1372157
milestone65.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 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);