Bug 1048724 - [WebGL2] Transform Feedback. r=jgilbert draft
authorDan Glastonbury <dglastonbury@mozilla.com>
Mon, 18 Aug 2014 10:47:14 +1000
changeset 226500 5aec4e05c8fd69362dcb6c7c4c50ad1020cc76a5
parent 226499 7e6ec35d02cd9e0e4cbc4c3ba665849a95563642
child 226501 2b3c081be197be896cbf68154bc7549810b81c2b
push id53
push userdglastonbury@mozilla.com
push dateWed, 12 Nov 2014 02:04:58 +0000
reviewersjgilbert
bugs1048724
milestone36.0a1
Bug 1048724 - [WebGL2] Transform Feedback. r=jgilbert
dom/canvas/WebGL1Context.h
dom/canvas/WebGL1ContextBuffers.cpp
dom/canvas/WebGL2Context.cpp
dom/canvas/WebGL2Context.h
dom/canvas/WebGL2ContextBuffers.cpp
dom/canvas/WebGL2ContextTransformFeedback.cpp
dom/canvas/WebGLContext.cpp
dom/canvas/WebGLContext.h
dom/canvas/WebGLContextBuffers.cpp
dom/canvas/WebGLContextGL.cpp
dom/canvas/WebGLContextUnchecked.h
dom/canvas/WebGLTransformFeedback.cpp
dom/canvas/WebGLTransformFeedback.h
dom/canvas/moz.build
dom/webidl/WebGL2RenderingContext.webidl
--- a/dom/canvas/WebGL1Context.h
+++ b/dom/canvas/WebGL1Context.h
@@ -33,14 +33,16 @@ public:
     }
 
 
     // -------------------------------------------------------------------------
     // IMPLEMENT nsWrapperCache
 
     virtual JSObject* WrapObject(JSContext *cx) MOZ_OVERRIDE;
 
-
+private:
+    virtual bool ValidateBufferTarget(GLenum target, const char* info) MOZ_OVERRIDE;
+    virtual bool ValidateBufferIndexedTarget(GLenum target, const char* info) MOZ_OVERRIDE;
 };
 
 } // namespace mozilla
 
 #endif
new file mode 100644
--- /dev/null
+++ b/dom/canvas/WebGL1ContextBuffers.cpp
@@ -0,0 +1,34 @@
+/* -*- 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 "WebGL1Context.h"
+#include "WebGLBuffer.h"
+#include "GLContext.h"
+
+using namespace mozilla;
+using namespace mozilla::dom;
+
+// -------------------------------------------------------------------------
+// Buffer objects
+
+/** Target validation for BindBuffer, etc */
+bool
+WebGL1Context::ValidateBufferTarget(GLenum target, const char* info)
+{
+    bool valid = (target == LOCAL_GL_ARRAY_BUFFER ||
+                  target == LOCAL_GL_ELEMENT_ARRAY_BUFFER);
+
+    if (!valid)
+        ErrorInvalidEnumInfo(info, target);
+
+    return valid;
+}
+
+bool
+WebGL1Context::ValidateBufferIndexedTarget(GLenum target, const char* info)
+{
+    ErrorInvalidEnumInfo(info, target);
+    return false;
+}
--- a/dom/canvas/WebGL2Context.cpp
+++ b/dom/canvas/WebGL2Context.cpp
@@ -1,14 +1,15 @@
 /* -*- Mode: C++; tab-width: 20; 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 "WebGL2Context.h"
+#include "WebGLTransformFeedback.h"
 #include "GLContext.h"
 #include "mozilla/dom/WebGL2RenderingContextBinding.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Telemetry.h"
 
 using namespace mozilla;
 using namespace mozilla::gl;
 
@@ -73,10 +74,13 @@ WebGLContext::InitWebGL2()
             GenerateWarning("WebGL 2 requires GLFeature::%s!", GLContext::GetFeatureName(feature));
             return false;
         }
     }
 
     // we initialise WebGL 2 related stuff.
     gl->GetUIntegerv(LOCAL_GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, &mGLMaxTransformFeedbackSeparateAttribs);
 
+    mDefaultTransformFeedback = new WebGLTransformFeedback(this);
+    mBoundTransformFeedback = mDefaultTransformFeedback;
+
     return true;
 }
--- a/dom/canvas/WebGL2Context.h
+++ b/dom/canvas/WebGL2Context.h
@@ -30,17 +30,16 @@ public:
         return true;
     }
 
     // -------------------------------------------------------------------------
     // IMPLEMENT nsWrapperCache
 
     virtual JSObject* WrapObject(JSContext *cx) MOZ_OVERRIDE;
 
-
     // -------------------------------------------------------------------------
     // Buffer objects - WebGL2ContextBuffers.cpp
 
     void CopyBufferSubData(GLenum readTarget, GLenum writeTarget,
                            GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
     void GetBufferSubData(GLenum target, GLintptr offset, const dom::ArrayBuffer& returnedData);
     void GetBufferSubData(GLenum target, GLintptr offset, const dom::ArrayBufferView& returnedData);
 
@@ -202,24 +201,23 @@ public:
     void GetSyncParameter(JSContext*, WebGLSync* sync, GLenum pname, JS::MutableHandleValue retval);
 
 
     // -------------------------------------------------------------------------
     // Transform Feedback - WebGL2ContextTransformFeedback.cpp
     already_AddRefed<WebGLTransformFeedback> CreateTransformFeedback();
     void DeleteTransformFeedback(WebGLTransformFeedback* tf);
     bool IsTransformFeedback(WebGLTransformFeedback* tf);
-    void BindTransformFeedback(GLenum target, GLuint id);
+    void BindTransformFeedback(GLenum target, WebGLTransformFeedback* tf);
     void BeginTransformFeedback(GLenum primitiveMode);
     void EndTransformFeedback();
-    void TransformFeedbackVaryings(WebGLProgram* program, GLsizei count,
-                                   const dom::Sequence<nsString>& varyings, GLenum bufferMode);
-    already_AddRefed<WebGLActiveInfo> GetTransformFeedbackVarying(WebGLProgram* program, GLuint index);
     void PauseTransformFeedback();
     void ResumeTransformFeedback();
+    void TransformFeedbackVaryings(WebGLProgram* program, const dom::Sequence<nsString>& varyings, GLenum bufferMode);
+    already_AddRefed<WebGLActiveInfo> GetTransformFeedbackVarying(WebGLProgram* program, GLuint index);
 
 
     // -------------------------------------------------------------------------
     // Uniform Buffer Objects and Transform Feedback Buffers - WebGL2ContextUniforms.cpp
     // TODO(djg): Implemented in WebGLContext
 /*
     void BindBufferBase(GLenum target, GLuint index, WebGLBuffer* buffer);
     void BindBufferRange(GLenum target, GLuint index, WebGLBuffer* buffer, GLintptr offset, GLsizeiptr size);
@@ -248,13 +246,16 @@ private:
 
     WebGL2Context();
 
     bool ValidateSizedInternalFormat(GLenum internalFormat, const char* info);
     bool ValidateTexStorage(GLenum target, GLsizei levels, GLenum internalformat,
                                 GLsizei width, GLsizei height, GLsizei depth,
                                 const char* info);
     JS::Value GetTexParameterInternal(const TexTarget& target, GLenum pname) MOZ_OVERRIDE;
+
+    virtual bool ValidateBufferTarget(GLenum target, const char* info) MOZ_OVERRIDE;
+    virtual bool ValidateBufferIndexedTarget(GLenum target, const char* info) MOZ_OVERRIDE;
 };
 
 } // namespace mozilla
 
 #endif
--- a/dom/canvas/WebGL2ContextBuffers.cpp
+++ b/dom/canvas/WebGL2ContextBuffers.cpp
@@ -4,16 +4,40 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "WebGL2Context.h"
 #include "GLContext.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
+bool
+WebGL2Context::ValidateBufferTarget(GLenum target, const char* info)
+{
+    bool valid = (target == LOCAL_GL_ARRAY_BUFFER ||
+                  target == LOCAL_GL_ELEMENT_ARRAY_BUFFER ||
+                  target == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER);
+
+    if (!valid)
+        ErrorInvalidEnumInfo(info, target);
+
+    return valid;
+}
+
+bool
+WebGL2Context::ValidateBufferIndexedTarget(GLenum target, const char* info)
+{
+    bool valid = (target == LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER ||
+                  target == LOCAL_GL_UNIFORM_BUFFER);
+    if (!valid)
+        ErrorInvalidEnumInfo(info, target);
+
+    return valid;
+}
+
 // -------------------------------------------------------------------------
 // Buffer objects
 
 void
 WebGL2Context::CopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset,
                                  GLintptr writeOffset, GLsizeiptr size)
 {
     MakeContextCurrent();
--- a/dom/canvas/WebGL2ContextTransformFeedback.cpp
+++ b/dom/canvas/WebGL2ContextTransformFeedback.cpp
@@ -1,78 +1,240 @@
 /* -*- 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 "WebGL2Context.h"
+#include "WebGLActiveInfo.h"
+#include "WebGLProgram.h"
+#include "WebGLTransformFeedback.h"
 #include "GLContext.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 // -------------------------------------------------------------------------
 // Transform Feedback
 
 already_AddRefed<WebGLTransformFeedback>
 WebGL2Context::CreateTransformFeedback()
 {
-    MOZ_CRASH("Not Implemented.");
-    return nullptr;
+    if (IsContextLost())
+        return nullptr;
+
+    nsRefPtr<WebGLTransformFeedback> globj = new WebGLTransformFeedback(this);
+    return globj.forget();
 }
 
 void
 WebGL2Context::DeleteTransformFeedback(WebGLTransformFeedback* tf)
 {
-    MOZ_CRASH("Not Implemented.");
+    if (IsContextLost())
+        return;
+
+    if (!ValidateObjectAllowDeletedOrNull("deleteTransformFeedback", tf))
+        return;
+
+    if (!tf || tf->IsDeleted())
+        return;
+
+    if (mBoundTransformFeedback == tf)
+        BindTransformFeedback(LOCAL_GL_TRANSFORM_FEEDBACK, tf);
+
+    tf->RequestDelete();
 }
 
 bool
 WebGL2Context::IsTransformFeedback(WebGLTransformFeedback* tf)
 {
-    MOZ_CRASH("Not Implemented.");
-    return false;
+    if (IsContextLost())
+        return false;
+
+    MakeContextCurrent();
+    return ValidateObjectAllowDeleted("isTransformFeedback", tf) &&
+        !tf->IsDeleted() &&
+        gl->fIsTransformFeedback(tf->GLName());
 }
 
 void
-WebGL2Context::BindTransformFeedback(GLenum target, GLuint id)
+WebGL2Context::BindTransformFeedback(GLenum target, WebGLTransformFeedback* tf)
 {
-    MOZ_CRASH("Not Implemented.");
+    if (IsContextLost())
+        return;
+
+    if (!ValidateObjectAllowDeletedOrNull("bindTransformFeedback", tf))
+        return;
+
+    if (target != LOCAL_GL_TRANSFORM_FEEDBACK)
+        return ErrorInvalidEnum("bindTransformFeedback: target must be TRANSFORM_FEEDBACK");
+
+    WebGLTransformFeedbackRefPtr currentTF = mBoundTransformFeedback;
+    if (currentTF && currentTF->IsActive() && !currentTF->IsPaused())
+        return ErrorInvalidOperation("bindTransformFeedback: Currently bound transform feedback is active and not paused");
+
+    if (tf && tf->IsDeleted())
+        return ErrorInvalidOperation("bindTransformFeedback: Attempt to bind deleted id");
+
+    if (tf)
+        tf->BindTo(LOCAL_GL_TRANSFORM_FEEDBACK);
+
+    MakeContextCurrent();
+    gl->fBindTransformFeedback(target, tf ? tf->GLName() : 0);
+    if (tf)
+        mBoundTransformFeedback = tf;
+    else
+        mBoundTransformFeedback = mDefaultTransformFeedback;
 }
 
 void
 WebGL2Context::BeginTransformFeedback(GLenum primitiveMode)
 {
-    MOZ_CRASH("Not Implemented.");
+    if (IsContextLost())
+        return;
+
+    WebGLTransformFeedback* tf = mBoundTransformFeedback;
+    MOZ_ASSERT(tf);
+    if (!tf)
+        return;
+
+    if (tf->IsActive())
+        return ErrorInvalidOperation("beginTransformFeedback: transform feedback is active");
+
+    GLenum mode = tf->Mode();
+    if (mode != LOCAL_GL_POINTS && mode != LOCAL_GL_LINES && mode != LOCAL_GL_TRIANGLES)
+        return ErrorInvalidEnum("beginTransformFeedback: primitive must be one of POINTS, LINES, or TRIANGLES");
+
+    // GL_INVALID_OPERATION is generated by glBeginTransformFeedback
+    // if any binding point used in transform feedback mode does not
+    // have a buffer object bound. In interleaved mode, only the first
+    // buffer object binding point is ever written to.
+
+    // GL_INVALID_OPERATION is generated by glBeginTransformFeedback
+    // if no binding points would be used, either because no program
+    // object is active of because the active program object has
+    // specified no varying variables to record.
+    if (!mCurrentProgram)
+        return ErrorInvalidOperation("beginTransformFeedback: no program is active");
+
+    MakeContextCurrent();
+    gl->fBeginTransformFeedback(primitiveMode);
+    tf->SetActive(true);
+    tf->SetPaused(false);
 }
 
 void
 WebGL2Context::EndTransformFeedback()
 {
-    MOZ_CRASH("Not Implemented.");
+    if (IsContextLost())
+        return;
+
+    WebGLTransformFeedback* tf = mBoundTransformFeedback;
+    MOZ_ASSERT(tf);
+    if (!tf)
+        return;
+
+    if (!tf->IsActive())
+        return ErrorInvalidOperation("endTransformFeedback: transform feedback in not active");
+
+    MakeContextCurrent();
+    gl->fEndTransformFeedback();
+    tf->SetActive(false);
+    tf->SetPaused(false);
+}
+
+void
+WebGL2Context::PauseTransformFeedback()
+{
+    if (IsContextLost())
+        return;
+
+    WebGLTransformFeedback* tf = mBoundTransformFeedback;
+    MOZ_ASSERT(tf);
+    if (!tf)
+        return;
+
+    if (!tf->IsActive() || tf->IsPaused())
+        return ErrorInvalidOperation("pauseTransformFeedback: transform feedback is not active or is paused");
+
+    MakeContextCurrent();
+    gl->fPauseTransformFeedback();
+    tf->SetPaused(true);
 }
 
 void
-WebGL2Context::TransformFeedbackVaryings(WebGLProgram* program, GLsizei count,
-                                         const dom::Sequence<nsString>& varyings, GLenum bufferMode)
+WebGL2Context::ResumeTransformFeedback()
 {
-    MOZ_CRASH("Not Implemented.");
+    if (IsContextLost())
+        return;
+
+    WebGLTransformFeedback* tf = mBoundTransformFeedback;
+    MOZ_ASSERT(tf);
+    if (!tf)
+        return;
+
+    if (!tf->IsActive() || !tf->IsPaused())
+        return ErrorInvalidOperation("resumeTransformFeedback: transform feedback is not active or is not paused");
+
+    MakeContextCurrent();
+    gl->fResumeTransformFeedback();
+    tf->SetPaused(false);
+}
+
+void
+WebGL2Context::TransformFeedbackVaryings(WebGLProgram* program,
+                                         const dom::Sequence<nsString>& varyings,
+                                         GLenum bufferMode)
+{
+    if (IsContextLost())
+        return;
+
+    if (!ValidateObject("transformFeedbackVaryings: program", program))
+        return;
+
+    GLsizei count = varyings.Length();
+    GLchar** tmpVaryings = (GLchar**) nsMemory::Alloc(count * sizeof(GLchar*));
+
+    for (GLsizei n = 0; n < count; n++) {
+        tmpVaryings[n] = (GLchar*) ToNewCString(varyings[n]);
+    }
+
+    GLuint progname = program->GLName();
+    MakeContextCurrent();
+    gl->fTransformFeedbackVaryings(progname, count, tmpVaryings, bufferMode);
+
+    NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(count, tmpVaryings);
 }
 
 
 already_AddRefed<WebGLActiveInfo>
 WebGL2Context::GetTransformFeedbackVarying(WebGLProgram* program, GLuint index)
 {
-    MOZ_CRASH("Not Implemented.");
-    return nullptr;
-}
+    if (IsContextLost())
+        return nullptr;
+
+    if (!ValidateObject("getTransformFeedbackVarying: program", program))
+        return nullptr;
+
+    MakeContextCurrent();
+
+    GLint len = 0;
+    GLuint progname = program->GLName();
+    gl->fGetProgramiv(progname, LOCAL_GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH, &len);
+    if (!len)
+        return nullptr;
 
-void
-WebGL2Context::PauseTransformFeedback()
-{
-    MOZ_CRASH("Not Implemented.");
-}
+    nsAutoArrayPtr<char> name(new char[len]);
+
+    GLint tfsize = 0;
+    GLuint tftype = 0;
 
-void
-WebGL2Context::ResumeTransformFeedback()
-{
-    MOZ_CRASH("Not Implemented.");
+    gl->fGetTransformFeedbackVarying(progname, index, len, &len, &tfsize, &tftype, name);
+    if (len == 0 || tfsize == 0 || tftype == 0)
+        return nullptr;
+
+    // TODO(djg): Reverse lookup of name
+    // nsCString reverseMappedName;
+    // prog->ReverveMapIdentifier(nsDependentCString(name), &reverseMappedName);
+
+    nsRefPtr<WebGLActiveInfo> result = new WebGLActiveInfo(tfsize, tftype, nsDependentCString(name));
+    return result.forget();
 }
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -10,16 +10,17 @@
 #include "WebGLBuffer.h"
 #include "WebGLContextUtils.h"
 #include "WebGLExtensions.h"
 #include "WebGLFramebuffer.h"
 #include "WebGLMemoryTracker.h"
 #include "WebGLObjectModel.h"
 #include "WebGLQuery.h"
 #include "WebGLSampler.h"
+#include "WebGLTransformFeedback.h"
 #include "WebGLVertexArray.h"
 #include "WebGLVertexAttribData.h"
 
 #include "GLBlitHelper.h"
 #include "AccessCheck.h"
 #include "nsIConsoleService.h"
 #include "nsServiceManagerUtils.h"
 #include "nsIClassInfoImpl.h"
@@ -350,16 +351,21 @@ WebGLContext::DestroyResourcesAndContext
     mBoundArrayBuffer = nullptr;
     mBoundTransformFeedbackBuffer = nullptr;
     mCurrentProgram = nullptr;
     mBoundFramebuffer = nullptr;
     mActiveOcclusionQuery = nullptr;
     mBoundRenderbuffer = nullptr;
     mBoundVertexArray = nullptr;
     mDefaultVertexArray = nullptr;
+    mBoundTransformFeedback = nullptr;
+    mDefaultTransformFeedback = nullptr;
+
+    for (GLuint i = 0; i < mGLMaxTransformFeedbackSeparateAttribs; i++)
+        mBoundTransformFeedbackBuffers[i] = nullptr;
 
     while (!mTextures.isEmpty())
         mTextures.getLast()->DeleteOnce();
     while (!mVertexArrays.isEmpty())
         mVertexArrays.getLast()->DeleteOnce();
     while (!mBuffers.isEmpty())
         mBuffers.getLast()->DeleteOnce();
     while (!mRenderbuffers.isEmpty())
@@ -369,16 +375,18 @@ WebGLContext::DestroyResourcesAndContext
     while (!mShaders.isEmpty())
         mShaders.getLast()->DeleteOnce();
     while (!mPrograms.isEmpty())
         mPrograms.getLast()->DeleteOnce();
     while (!mQueries.isEmpty())
         mQueries.getLast()->DeleteOnce();
     while (!mSamplers.isEmpty())
         mSamplers.getLast()->DeleteOnce();
+    while (!mTransformFeedbacks.isEmpty())
+        mTransformFeedbacks.getLast()->DeleteOnce();
 
     mBlackOpaqueTexture2D = nullptr;
     mBlackOpaqueTextureCubeMap = nullptr;
     mBlackTransparentTexture2D = nullptr;
     mBlackTransparentTextureCubeMap = nullptr;
 
     if (mFakeVertexAttrib0BufferObject) {
         gl->fDeleteBuffers(1, &mFakeVertexAttrib0BufferObject);
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -77,31 +77,40 @@ class WebGLShader;
 class WebGLProgram;
 class WebGLQuery;
 class WebGLUniformLocation;
 class WebGLFramebuffer;
 class WebGLRenderbuffer;
 class WebGLSampler;
 class WebGLShaderPrecisionFormat;
 class WebGLTexture;
+class WebGLTransformFeedback;
 class WebGLVertexArray;
 
 
+
 namespace dom {
 class ImageData;
 class Element;
 
 struct WebGLContextAttributes;
 template<typename> struct Nullable;
 }
 
 namespace gfx {
 class SourceSurface;
 }
 
+typedef WebGLRefPtr<WebGLBuffer> WebGLBufferRefPtr;
+typedef WebGLRefPtr<WebGLFramebuffer> WebGLFramebufferRefPtr;
+typedef WebGLRefPtr<WebGLRenderbuffer> WebGLRenderbufferRefPtr;
+typedef WebGLRefPtr<WebGLTexture> WebGLTextureRefPtr;
+typedef WebGLRefPtr<WebGLTransformFeedback> WebGLTransformFeedbackRefPtr;
+typedef WebGLRefPtr<WebGLVertexArray> WebGLVertexArrayRefPtr;
+
 WebGLTexelFormat GetWebGLTexelFormat(TexInternalFormat format);
 
 void AssertUintParamCorrect(gl::GLContext* gl, GLenum pname, GLuint shadow);
 
 struct WebGLContextOptions {
     // these are defaults
     WebGLContextOptions();
 
@@ -860,26 +869,25 @@ public:
     void BufferSubData(GLenum target, WebGLsizeiptr byteOffset,
                        const dom::ArrayBufferView &data);
     void BufferSubData(GLenum target, WebGLsizeiptr byteOffset,
                        const Nullable<dom::ArrayBuffer> &maybeData);
     already_AddRefed<WebGLBuffer> CreateBuffer();
     void DeleteBuffer(WebGLBuffer *buf);
     bool IsBuffer(WebGLBuffer *buffer);
 
-private:
-    // ARRAY_BUFFER slot
-    WebGLRefPtr<WebGLBuffer> mBoundArrayBuffer;
+protected:
+    // bound buffer state
+    WebGLBufferRefPtr mBoundArrayBuffer;
+    WebGLBufferRefPtr mBoundTransformFeedbackBuffer;
 
-    // TRANSFORM_FEEDBACK_BUFFER slot
-    WebGLRefPtr<WebGLBuffer> mBoundTransformFeedbackBuffer;
+    UniquePtr<WebGLBufferRefPtr[]> mBoundTransformFeedbackBuffers;
 
-    // these two functions emit INVALID_ENUM for invalid `target`.
-    WebGLRefPtr<WebGLBuffer>* GetBufferSlotByTarget(GLenum target, const char* infos);
-    WebGLRefPtr<WebGLBuffer>* GetBufferSlotByTargetIndexed(GLenum target, GLuint index, const char* infos);
+    WebGLBufferRefPtr* GetBufferSlotByTarget(GLenum target);
+    WebGLBufferRefPtr* GetBufferSlotByTargetIndexed(GLenum target, GLuint index);
     bool ValidateBufferUsageEnum(GLenum target, const char* infos);
 
 // -----------------------------------------------------------------------------
 // State and State Requests (WebGLContextState.cpp)
 public:
     void Disable(GLenum cap);
     void Enable(GLenum cap);
     bool GetStencilBits(GLint* out_stencilBits);
@@ -1070,17 +1078,17 @@ protected:
     int32_t mGLMaxRenderbufferSize;
     int32_t mGLMaxTextureImageUnits;
     int32_t mGLMaxVertexTextureImageUnits;
     int32_t mGLMaxVaryingVectors;
     int32_t mGLMaxFragmentUniformVectors;
     int32_t mGLMaxVertexUniformVectors;
     int32_t mGLMaxColorAttachments;
     int32_t mGLMaxDrawBuffers;
-    uint32_t mGLMaxTransformFeedbackSeparateAttribs;
+    GLuint  mGLMaxTransformFeedbackSeparateAttribs;
 
 public:
     GLuint MaxVertexAttribs() const {
         return mGLMaxVertexAttribs;
     }
 
 protected:
     // Represents current status of the context with respect to context loss.
@@ -1294,16 +1302,21 @@ protected:
     template<class ObjectType>
     bool ValidateObjectAllowDeleted(const char* info, ObjectType *aObject);
 private:
     // Like ValidateObject, but only for cases when aObject is known
     // to not be null already.
     template<class ObjectType>
     bool ValidateObjectAssumeNonNull(const char* info, ObjectType *aObject);
 
+    // -------------------------------------------------------------------------
+    // Context customization points
+    virtual bool ValidateBufferTarget(GLenum target, const char* info) = 0;
+    virtual bool ValidateBufferIndexedTarget(GLenum target, const char* info) = 0;
+
 protected:
     int32_t MaxTextureSizeForTarget(TexTarget target) const {
         return (target == LOCAL_GL_TEXTURE_2D) ? mGLMaxTextureSize : mGLMaxCubeMapTextureSize;
     }
 
     int32_t MaxTextureLevelForTexImageTarget(TexImageTarget texImageTarget) const {
         const TexTarget target = TexImageTargetToTexTarget(texImageTarget);
         return (target == LOCAL_GL_TEXTURE_2D) ? mGLMaxTextureSizeLog2 : mGLMaxCubeMapTextureSizeLog2;
@@ -1325,41 +1338,44 @@ protected:
                              GLint border,
                              TexFormat format,
                              TexType type,
                              const GLvoid *data);
 
     void ForceLoseContext(bool simulateLosing = false);
     void ForceRestoreContext();
 
-    nsTArray<WebGLRefPtr<WebGLTexture> > mBound2DTextures;
-    nsTArray<WebGLRefPtr<WebGLTexture> > mBoundCubeMapTextures;
-    nsTArray<WebGLRefPtr<WebGLTexture> > mBound3DTextures;
+    nsTArray<WebGLTextureRefPtr> mBound2DTextures;
+    nsTArray<WebGLTextureRefPtr> mBoundCubeMapTextures;
+    nsTArray<WebGLTextureRefPtr> mBound3DTextures;
 
     WebGLRefPtr<WebGLProgram> mCurrentProgram;
 
     uint32_t mMaxFramebufferColorAttachments;
 
-    WebGLRefPtr<WebGLFramebuffer> mBoundFramebuffer;
-    WebGLRefPtr<WebGLRenderbuffer> mBoundRenderbuffer;
-    WebGLRefPtr<WebGLVertexArray> mBoundVertexArray;
+    WebGLFramebufferRefPtr mBoundFramebuffer;
+    WebGLRenderbufferRefPtr mBoundRenderbuffer;
+    WebGLTransformFeedbackRefPtr mBoundTransformFeedback;
+    WebGLVertexArrayRefPtr mBoundVertexArray;
 
     LinkedList<WebGLTexture> mTextures;
     LinkedList<WebGLBuffer> mBuffers;
     LinkedList<WebGLProgram> mPrograms;
     LinkedList<WebGLQuery> mQueries;
     LinkedList<WebGLShader> mShaders;
     LinkedList<WebGLRenderbuffer> mRenderbuffers;
     LinkedList<WebGLFramebuffer> mFramebuffers;
     LinkedList<WebGLVertexArray> mVertexArrays;
 
     // TODO(djg): Does this need a rethink? Should it be WebGL2Context?
     LinkedList<WebGLSampler> mSamplers;
+    LinkedList<WebGLTransformFeedback> mTransformFeedbacks;
 
     WebGLRefPtr<WebGLVertexArray> mDefaultVertexArray;
+    WebGLTransformFeedbackRefPtr mDefaultTransformFeedback;
 
     // PixelStore parameters
     uint32_t mPixelStorePackAlignment, mPixelStoreUnpackAlignment, mPixelStoreColorspaceConversion;
     bool mPixelStoreFlipY, mPixelStorePremultiplyAlpha;
 
     WebGLContextFakeBlackStatus mFakeBlackStatus;
 
     class FakeBlackTexture
@@ -1466,16 +1482,17 @@ public:
     friend class WebGLTexture;
     friend class WebGLFramebuffer;
     friend class WebGLRenderbuffer;
     friend class WebGLProgram;
     friend class WebGLQuery;
     friend class WebGLBuffer;
     friend class WebGLSampler;
     friend class WebGLShader;
+    friend class WebGLTransformFeedback;
     friend class WebGLUniformLocation;
     friend class WebGLVertexArray;
     friend class WebGLVertexArrayFake;
     friend class WebGLVertexArrayGL;
 };
 
 // used by DOM bindings in conjunction with GetParentObject
 inline nsISupports*
--- a/dom/canvas/WebGLContextBuffers.cpp
+++ b/dom/canvas/WebGLContextBuffers.cpp
@@ -19,21 +19,21 @@ WebGLContext::BindBuffer(GLenum target, 
 
     if (!ValidateObjectAllowDeletedOrNull("bindBuffer", buffer))
         return;
 
     // silently ignore a deleted buffer
     if (buffer && buffer->IsDeleted())
         return;
 
-    WebGLRefPtr<WebGLBuffer>* bufferSlot = GetBufferSlotByTarget(target, "bindBuffer");
+    if (!ValidateBufferTarget(target, "bindBuffer"))
+        return;
 
-    if (!bufferSlot) {
-        return;
-    }
+    WebGLRefPtr<WebGLBuffer>* bufferSlot = GetBufferSlotByTarget(target);
+    MOZ_ASSERT(bufferSlot);
 
     if (buffer) {
         if (!buffer->HasEverBeenBound()) {
             buffer->BindTo(target);
         } else if (target != buffer->Target()) {
             return ErrorInvalidOperation("bindBuffer: buffer already bound to a different target");
         }
     }
@@ -54,32 +54,38 @@ WebGLContext::BindBufferBase(GLenum targ
     if (!ValidateObjectAllowDeletedOrNull("bindBufferBase", buffer))
         return;
 
     // silently ignore a deleted buffer
     if (buffer && buffer->IsDeleted()) {
         return;
     }
 
-    WebGLRefPtr<WebGLBuffer>* indexedBufferSlot = GetBufferSlotByTargetIndexed(target, index, "bindBufferBase");
+    // ValidateBufferTarget
+    switch (target) {
+    case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
+        if (index >= mGLMaxTransformFeedbackSeparateAttribs)
+            return ErrorInvalidValue("bindBufferBase: index should be less than "
+                                     "MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS");
+    default:
+        return ErrorInvalidEnumInfo("bindBufferBase: target", target);
+    }
 
-    if (!indexedBufferSlot) {
-        return;
-    }
+    WebGLBufferRefPtr* indexedBufferSlot = GetBufferSlotByTargetIndexed(target, index);
+    MOZ_ASSERT(indexedBufferSlot);
 
     if (buffer) {
         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");
-
+    WebGLRefPtr<WebGLBuffer>* bufferSlot = GetBufferSlotByTarget(target);
     MOZ_ASSERT(bufferSlot, "GetBufferSlotByTarget(Indexed) mismatch");
 
     *indexedBufferSlot = buffer;
     *bufferSlot = buffer;
 
     MakeContextCurrent();
 
     gl->fBindBufferBase(target, index, buffer ? buffer->GLName() : 0);
@@ -94,39 +100,46 @@ WebGLContext::BindBufferRange(GLenum tar
 
     if (!ValidateObjectAllowDeletedOrNull("bindBufferRange", buffer))
         return;
 
     // silently ignore a deleted buffer
     if (buffer && buffer->IsDeleted())
         return;
 
-    WebGLRefPtr<WebGLBuffer>* indexedBufferSlot = GetBufferSlotByTargetIndexed(target, index, "bindBufferBase");
+    // ValidateBufferTarget
+    switch (target) {
+    case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
+        if (index >= mGLMaxTransformFeedbackSeparateAttribs)
+            return ErrorInvalidValue("bindBufferRange: index should be less than "
+                                     "MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS");
 
-    if (!indexedBufferSlot) {
-        return;
+    default:
+        return ErrorInvalidEnumInfo("bindBufferRange: target", target);
     }
 
+    WebGLBufferRefPtr* indexedBufferSlot = GetBufferSlotByTargetIndexed(target, index);
+    MOZ_ASSERT(indexedBufferSlot);
+
     if (buffer) {
         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");
         }
     }
 
-    WebGLRefPtr<WebGLBuffer>* bufferSlot = GetBufferSlotByTarget(target, "bindBuffer");
-
+    WebGLBufferRefPtr* bufferSlot = GetBufferSlotByTarget(target);
     MOZ_ASSERT(bufferSlot, "GetBufferSlotByTarget(Indexed) mismatch");
 
     *indexedBufferSlot = buffer;
     *bufferSlot = buffer;
 
     MakeContextCurrent();
 
     gl->fBindBufferRange(target, index, buffer ? buffer->GLName() : 0, offset, size);
@@ -134,21 +147,21 @@ WebGLContext::BindBufferRange(GLenum tar
 
 void
 WebGLContext::BufferData(GLenum target, WebGLsizeiptr size,
                          GLenum usage)
 {
     if (IsContextLost())
         return;
 
-    WebGLRefPtr<WebGLBuffer>* bufferSlot = GetBufferSlotByTarget(target, "bufferData");
+    if (!ValidateBufferTarget(target, "bufferData"))
+        return;
 
-    if (!bufferSlot) {
-        return;
-    }
+    WebGLBufferRefPtr* bufferSlot = GetBufferSlotByTarget(target);
+    MOZ_ASSERT(bufferSlot);
 
     if (size < 0)
         return ErrorInvalidValue("bufferData: negative size");
 
     if (!ValidateBufferUsageEnum(usage, "bufferData: usage"))
         return;
 
     // careful: WebGLsizeiptr is always 64-bit, but GLsizeiptr is like intptr_t.
@@ -188,21 +201,21 @@ WebGLContext::BufferData(GLenum target,
     if (IsContextLost())
         return;
 
     if (maybeData.IsNull()) {
         // see http://www.khronos.org/bugzilla/show_bug.cgi?id=386
         return ErrorInvalidValue("bufferData: null object passed");
     }
 
-    WebGLRefPtr<WebGLBuffer>* bufferSlot = GetBufferSlotByTarget(target, "bufferData");
+    if (!ValidateBufferTarget(target, "bufferData"))
+        return;
 
-    if (!bufferSlot) {
-        return;
-    }
+    WebGLBufferRefPtr* bufferSlot = GetBufferSlotByTarget(target);
+    MOZ_ASSERT(bufferSlot);
 
     const ArrayBuffer& data = maybeData.Value();
     data.ComputeLengthAndData();
 
     // Careful: data.Length() could conceivably be any uint32_t, but GLsizeiptr
     // is like intptr_t.
     if (!CheckedInt<GLsizeiptr>(data.Length()).isValid())
         return ErrorOutOfMemory("bufferData: bad size");
@@ -233,21 +246,21 @@ WebGLContext::BufferData(GLenum target,
 
 void
 WebGLContext::BufferData(GLenum target, const ArrayBufferView& data,
                          GLenum usage)
 {
     if (IsContextLost())
         return;
 
-    WebGLRefPtr<WebGLBuffer>* bufferSlot = GetBufferSlotByTarget(target, "bufferSubData");
+    if (!ValidateBufferTarget(target, "bufferData"))
+        return;
 
-    if (!bufferSlot) {
-        return;
-    }
+    WebGLBufferRefPtr* bufferSlot = GetBufferSlotByTarget(target);
+    MOZ_ASSERT(bufferSlot);
 
     if (!ValidateBufferUsageEnum(usage, "bufferData: usage"))
         return;
 
     WebGLBuffer* boundBuffer = bufferSlot->get();
 
     if (!boundBuffer)
         return ErrorInvalidOperation("bufferData: no buffer bound!");
@@ -281,21 +294,21 @@ WebGLContext::BufferSubData(GLenum targe
     if (IsContextLost())
         return;
 
     if (maybeData.IsNull()) {
         // see http://www.khronos.org/bugzilla/show_bug.cgi?id=386
         return;
     }
 
-    WebGLRefPtr<WebGLBuffer>* bufferSlot = GetBufferSlotByTarget(target, "bufferSubData");
+    if (!ValidateBufferTarget(target, "bufferSubData"))
+        return;
 
-    if (!bufferSlot) {
-        return;
-    }
+    WebGLBufferRefPtr* bufferSlot = GetBufferSlotByTarget(target);
+    MOZ_ASSERT(bufferSlot);
 
     if (byteOffset < 0)
         return ErrorInvalidValue("bufferSubData: negative offset");
 
     WebGLBuffer* boundBuffer = bufferSlot->get();
 
     if (!boundBuffer)
         return ErrorInvalidOperation("bufferData: no buffer bound!");
@@ -320,21 +333,21 @@ WebGLContext::BufferSubData(GLenum targe
 
 void
 WebGLContext::BufferSubData(GLenum target, WebGLsizeiptr byteOffset,
                             const ArrayBufferView& data)
 {
     if (IsContextLost())
         return;
 
-    WebGLRefPtr<WebGLBuffer>* bufferSlot = GetBufferSlotByTarget(target, "bufferSubData");
+    if (!ValidateBufferTarget(target, "bufferSubData"))
+        return;
 
-    if (!bufferSlot) {
-        return;
-    }
+    WebGLRefPtr<WebGLBuffer>* bufferSlot = GetBufferSlotByTarget(target);
+    MOZ_ASSERT(bufferSlot);
 
     if (byteOffset < 0)
         return ErrorInvalidValue("bufferSubData: negative offset");
 
     WebGLBuffer* boundBuffer = bufferSlot->get();
 
     if (!boundBuffer)
         return ErrorInvalidOperation("bufferSubData: no buffer bound!");
@@ -417,57 +430,40 @@ WebGLContext::ValidateBufferUsageEnum(GL
         default:
             break;
     }
 
     ErrorInvalidEnumInfo(infos, target);
     return false;
 }
 
-WebGLRefPtr<WebGLBuffer>*
-WebGLContext::GetBufferSlotByTarget(GLenum target, const char* infos)
+WebGLBufferRefPtr*
+WebGLContext::GetBufferSlotByTarget(GLenum target)
 {
+    /* This function assumes that target has been validated for either WebGL1 or WebGL. */
     switch (target) {
-        case LOCAL_GL_ARRAY_BUFFER:
-            return &mBoundArrayBuffer;
-
-        case LOCAL_GL_ELEMENT_ARRAY_BUFFER:
-            return &mBoundVertexArray->mElementArrayBuffer;
-
-        case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
-            if (!IsWebGL2()) {
-                break;
-            }
-            return &mBoundTransformFeedbackBuffer;
-
+        case LOCAL_GL_ARRAY_BUFFER:              return &mBoundArrayBuffer;
+        case LOCAL_GL_ELEMENT_ARRAY_BUFFER:      return &mBoundVertexArray->mElementArrayBuffer;
+        case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER: return &mBoundTransformFeedbackBuffer;
         default:
-            break;
+            return nullptr;
     }
-
-    ErrorInvalidEnum("%s: target: invalid enum value 0x%x", infos, target);
-    return nullptr;
 }
 
-WebGLRefPtr<WebGLBuffer>*
-WebGLContext::GetBufferSlotByTargetIndexed(GLenum target, GLuint index, const char* infos)
+WebGLBufferRefPtr*
+WebGLContext::GetBufferSlotByTargetIndexed(GLenum target, GLuint index)
 {
+    /* This function assumes that target has been validated for either WebGL1 or WebGL. */
     switch (target) {
-        case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
-            if (index >= mGLMaxTransformFeedbackSeparateAttribs) {
-                ErrorInvalidValue("%s: index should be less than MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS", infos, index);
-                return nullptr;
-            }
-            return nullptr; // See bug 903594
+    case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
+        return &mBoundTransformFeedbackBuffers[index];
 
-        default:
-            break;
+    default:
+        return nullptr;
     }
-
-    ErrorInvalidEnum("%s: target: invalid enum value 0x%x", infos, target);
-    return nullptr;
 }
 
 GLenum
 WebGLContext::CheckedBufferData(GLenum target,
                                 GLsizeiptr size,
                                 const GLvoid *data,
                                 GLenum usage)
 {
--- a/dom/canvas/WebGLContextGL.cpp
+++ b/dom/canvas/WebGLContextGL.cpp
@@ -1098,22 +1098,22 @@ WebGLContext::GetAttribLocation(WebGLPro
 }
 
 JS::Value
 WebGLContext::GetBufferParameter(GLenum target, GLenum pname)
 {
     if (IsContextLost())
         return JS::NullValue();
 
-
-    WebGLRefPtr<WebGLBuffer>* slot = GetBufferSlotByTarget(target,
-                                                           "getBufferParameter");
-    if (!slot)
+    if (!ValidateBufferTarget(target, "getBufferParameter"))
         return JS::NullValue();
 
+    WebGLBufferRefPtr* slot = GetBufferSlotByTarget(target);
+    MOZ_ASSERT(slot);
+
     if (!*slot) {
         ErrorInvalidOperation("No buffer bound to `target` (0x%4x).", target);
         return JS::NullValue();
     }
 
     MakeContextCurrent();
 
     switch (pname) {
--- a/dom/canvas/WebGLContextUnchecked.h
+++ b/dom/canvas/WebGLContextUnchecked.h
@@ -9,17 +9,20 @@
 
 #include "GLDefs.h"
 #include "WebGLTypes.h"
 #include "nsAutoPtr.h"
 #include "nsTArray.h"
 
 namespace mozilla {
 
+class WebGLBuffer;
 class WebGLSampler;
+class WebGLTransformFeedback;
+
 namespace gl { class GLContext; }
 
 class WebGLContextUnchecked
 {
 public:
     explicit WebGLContextUnchecked(gl::GLContext* gl);
 
     // -------------------------------------------------------------------------
--- a/dom/canvas/WebGLTransformFeedback.cpp
+++ b/dom/canvas/WebGLTransformFeedback.cpp
@@ -8,35 +8,47 @@
 
 #include "GLContext.h"
 
 #include "mozilla/dom/WebGL2RenderingContextBinding.h"
 
 using namespace mozilla;
 
 WebGLTransformFeedback::WebGLTransformFeedback(WebGLContext* context)
-    : WebGLContextBoundObject(context)
+    : WebGLBindableName()
+    , WebGLContextBoundObject(context)
+    , mMode(LOCAL_GL_NONE)
+    , mIsActive(false)
+    , mIsPaused(false)
 {
-    MOZ_CRASH("Not Implemented.");
+    context->MakeContextCurrent();
+    context->gl->fGenTransformFeedbacks(1, &mGLName);
+    context->mTransformFeedbacks.insertBack(this);
 }
 
 WebGLTransformFeedback::~WebGLTransformFeedback()
-{}
+{
+    mMode = LOCAL_GL_NONE;
+    mIsActive = false;
+    mIsPaused = false;
+    DeleteOnce();
+}
 
 void
 WebGLTransformFeedback::Delete()
 {
-    MOZ_CRASH("Not Implemented.");
+    mContext->MakeContextCurrent();
+    mContext->gl->fDeleteTransformFeedbacks(1, &mGLName);
+    removeFrom(mContext->mTransformFeedbacks);
 }
 
 WebGLContext*
 WebGLTransformFeedback::GetParentObject() const
 {
-    MOZ_CRASH("Not Implemented.");
-    return nullptr;
+    return Context();
 }
 
 JSObject*
 WebGLTransformFeedback::WrapObject(JSContext* cx)
 {
     return dom::WebGLTransformFeedbackBinding::Wrap(cx, this);
 }
 
--- a/dom/canvas/WebGLTransformFeedback.h
+++ b/dom/canvas/WebGLTransformFeedback.h
@@ -26,23 +26,35 @@ class WebGLTransformFeedback MOZ_FINAL
 
 public:
 
     explicit WebGLTransformFeedback(WebGLContext* aContext);
 
     void Delete();
     WebGLContext* GetParentObject() const;
 
+    bool IsActive() const { return mIsActive; }
+    bool IsPaused() const { return mIsPaused; }
+    GLenum Mode() const { return mMode; }
+
+    void SetActive(bool active) { mIsActive = active; }
+    void SetPaused(bool paused) { mIsPaused = paused; }
+    void SetMode(GLenum mode) { mMode = mode; }
+
     // -------------------------------------------------------------------------
     // IMPLEMENT NS
     virtual JSObject* WrapObject(JSContext* cx) MOZ_OVERRIDE;
 
     NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLTransformFeedback)
     NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLTransformFeedback)
 
 private:
 
     ~WebGLTransformFeedback();
+
+    GLenum mMode;
+    bool mIsActive;
+    bool mIsPaused;
 };
 
 }
 
 #endif // !WEBGLTRANSFORMFEEDBACK_H_
--- a/dom/canvas/moz.build
+++ b/dom/canvas/moz.build
@@ -34,16 +34,17 @@ UNIFIED_SOURCES += [
     'DocumentRendererParent.cpp',
     'ImageData.cpp',
 ]
 
 # WebGL Sources
 UNIFIED_SOURCES += [
     'MurmurHash3.cpp',
     'WebGL1Context.cpp',
+    'WebGL1ContextBuffers.cpp',
     'WebGL2Context.cpp',
     'WebGL2ContextBuffers.cpp',
     'WebGL2ContextDraw.cpp',
     'WebGL2ContextFramebuffers.cpp',
     'WebGL2ContextMRTs.cpp',
     'WebGL2ContextPrograms.cpp',
     'WebGL2ContextQueries.cpp',
     'WebGL2ContextSamplers.cpp',
--- a/dom/webidl/WebGL2RenderingContext.webidl
+++ b/dom/webidl/WebGL2RenderingContext.webidl
@@ -438,20 +438,20 @@ interface WebGL2RenderingContext : WebGL
     GLenum clientWaitSync(WebGLSync? sync, GLbitfield flags, GLint64 timeout);
     void waitSync(WebGLSync? sync, GLbitfield flags, GLint64 timeout);
     any getSyncParameter(WebGLSync? sync, GLenum pname);
 
     /* Transform Feedback */
     WebGLTransformFeedback? createTransformFeedback();
     void deleteTransformFeedback(WebGLTransformFeedback? tf);
     [WebGLHandlesContextLoss] GLboolean isTransformFeedback(WebGLTransformFeedback? tf);
-    void bindTransformFeedback(GLenum target, GLuint id);
+    void bindTransformFeedback(GLenum target, WebGLTransformFeedback? tf);
     void beginTransformFeedback(GLenum primitiveMode);
     void endTransformFeedback();
-    void transformFeedbackVaryings(WebGLProgram? program, GLsizei count, sequence<DOMString> varyings, GLenum bufferMode);
+    void transformFeedbackVaryings(WebGLProgram? program, sequence<DOMString> varyings, GLenum bufferMode);
     [NewObject] WebGLActiveInfo? getTransformFeedbackVarying(WebGLProgram? program, GLuint index);
     void pauseTransformFeedback();
     void resumeTransformFeedback();
 
     /* Uniform Buffer Objects and Transform Feedback Buffers */
     void bindBufferBase(GLenum target, GLuint index, WebGLBuffer? buffer);
     void bindBufferRange(GLenum target, GLuint index, WebGLBuffer? buffer, GLintptr offset, GLsizeiptr size);
     any getIndexedParameter(GLenum target, GLuint index);