bug 903481_- step 3 - [WebGL 2.0] implement TRANSFORM_FEEDBACK_BUFFER - r=jgilbert
authorGuillaume Abadie <gabadie@mozilla.com>
Tue, 20 Aug 2013 11:36:20 -0400
changeset 143241 5ddc04b616a979cab410aad281663dbc4051a3bf
parent 143240 07a69fca7c1475a03e3897bdbb13c8802c6cf590
child 143242 27cf1ae86abf6f3741f12d3e1e3f576f61901c11
push id25127
push userryanvm@gmail.com
push dateTue, 20 Aug 2013 19:30:18 +0000
treeherdermozilla-central@1718a2f065c6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjgilbert
milestone26.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 903481_- step 3 - [WebGL 2.0] implement TRANSFORM_FEEDBACK_BUFFER - r=jgilbert
content/canvas/src/WebGLContext.cpp
content/canvas/src/WebGLContext.h
content/canvas/src/WebGLContextBuffers.cpp
content/canvas/src/WebGLContextState.cpp
content/canvas/src/WebGLContextValidate.cpp
dom/base/nsWrapperCache.h
dom/webidl/WebGL2RenderingContext.webidl
--- a/content/canvas/src/WebGLContext.cpp
+++ b/content/canvas/src/WebGLContext.cpp
@@ -165,16 +165,17 @@ WebGLContext::WebGLContext()
     mGLMaxRenderbufferSize = 0;
     mGLMaxTextureImageUnits = 0;
     mGLMaxVertexTextureImageUnits = 0;
     mGLMaxVaryingVectors = 0;
     mGLMaxFragmentUniformVectors = 0;
     mGLMaxVertexUniformVectors = 0;
     mGLMaxColorAttachments = 1;
     mGLMaxDrawBuffers = 1;
+    mGLMaxTransformFeedbackSeparateAttribs = 0;
 
     // See OpenGL ES 2.0.25 spec, 6.2 State Tables, table 6.13
     mPixelStorePackAlignment = 4;
     mPixelStoreUnpackAlignment = 4;
 
     WebGLMemoryMultiReporterWrapper::AddWebGLContext(this);
 
     mAllowRestore = true;
@@ -230,16 +231,17 @@ WebGLContext::DestroyResourcesAndContext
     if (!gl)
         return;
 
     gl->MakeCurrent();
 
     mBound2DTextures.Clear();
     mBoundCubeMapTextures.Clear();
     mBoundArrayBuffer = nullptr;
+    mBoundTransformFeedbackBuffer = nullptr;
     mCurrentProgram = nullptr;
     mBoundFramebuffer = nullptr;
     mActiveOcclusionQuery = nullptr;
     mBoundRenderbuffer = nullptr;
     mBoundVertexArray = nullptr;
     mDefaultVertexArray = nullptr;
 
     while (!mTextures.isEmpty())
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -739,43 +739,52 @@ public:
 private:
     bool ValidateTargetParameter(WebGLenum target, const char* infos);
     WebGLRefPtr<WebGLQuery>& GetActiveQueryByTarget(WebGLenum target);
 
 // -----------------------------------------------------------------------------
 // Buffer Objects (WebGLContextBuffers.cpp)
 public:
     void BindBuffer(WebGLenum target, WebGLBuffer* buf);
+    void BindBufferBase(WebGLenum target, WebGLuint index, WebGLBuffer* buffer);
+    void BindBufferRange(WebGLenum target, WebGLuint index, WebGLBuffer* buffer,
+                         WebGLintptr offset, WebGLsizeiptr size);
     void BufferData(WebGLenum target, WebGLsizeiptr size, WebGLenum usage);
     void BufferData(WebGLenum target, const dom::ArrayBufferView &data,
                     WebGLenum usage);
     void BufferData(WebGLenum target,
                     const Nullable<dom::ArrayBuffer> &maybeData,
                     WebGLenum usage);
     void BufferSubData(WebGLenum target, WebGLsizeiptr byteOffset,
                        const dom::ArrayBufferView &data);
     void BufferSubData(WebGLenum target, WebGLsizeiptr byteOffset,
                        const Nullable<dom::ArrayBuffer> &maybeData);
     already_AddRefed<WebGLBuffer> CreateBuffer();
     void DeleteBuffer(WebGLBuffer *buf);
     bool IsBuffer(WebGLBuffer *buffer);
 
 private:
-    // ARRAY_BUFFER binding point
+    // ARRAY_BUFFER slot
     WebGLRefPtr<WebGLBuffer> mBoundArrayBuffer;
 
-    bool ValidateBufferTarget(GLenum target, const char* infos);
+    // TRANSFORM_FEEDBACK_BUFFER slot
+    WebGLRefPtr<WebGLBuffer> mBoundTransformFeedbackBuffer;
+
+    // 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);
     bool ValidateBufferUsageEnum(WebGLenum target, const char* infos);
 
 // -----------------------------------------------------------------------------
 // State and State Requests (WebGLContextState.cpp)
 public:
     void Disable(WebGLenum cap);
     void Enable(WebGLenum cap);
     JS::Value GetParameter(JSContext* cx, WebGLenum pname, ErrorResult& rv);
+    JS::Value GetParameterIndexed(JSContext* cx, WebGLenum pname, WebGLuint index);
     bool IsEnabled(WebGLenum cap);
 
 private:
     bool ValidateCapabilityEnum(WebGLenum cap, const char* info);
 
 // -----------------------------------------------------------------------------
 // Vertices Feature (WebGLContextVertices.cpp)
 public:
@@ -922,16 +931,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;
 
     // Represents current status, or state, of the context. That is, is it lost
     // or stable and what part of the context lost process are we currently at.
     // This is used to support the WebGL spec's asyncronous nature in handling
     // context loss.
     enum ContextStatus {
         // The context is stable; there either are none or we don't know of any.
         ContextStable,
--- a/content/canvas/src/WebGLContextBuffers.cpp
+++ b/content/canvas/src/WebGLContextBuffers.cpp
@@ -18,63 +18,131 @@ WebGLContext::BindBuffer(WebGLenum targe
 
     if (!ValidateObjectAllowDeletedOrNull("bindBuffer", buffer))
         return;
 
     // silently ignore a deleted buffer
     if (buffer && buffer->IsDeleted())
         return;
 
-    if (!ValidateBufferTarget(target, "bindBuffer")) {
+    WebGLRefPtr<WebGLBuffer>* bufferSlot = GetBufferSlotByTarget(target, "bindBuffer");
+
+    if (!bufferSlot) {
+        return;
+    }
+
+    if (buffer) {
+        if (!buffer->Target()) {
+            buffer->SetTarget(target);
+            buffer->SetHasEverBeenBound(true);
+        } else if (target != buffer->Target()) {
+            return ErrorInvalidOperation("bindBuffer: buffer already bound to a different target");
+        }
+    }
+
+    *bufferSlot = buffer;
+
+    MakeContextCurrent();
+
+    gl->fBindBuffer(target, buffer ? buffer->GLName() : 0);
+}
+
+void
+WebGLContext::BindBufferBase(WebGLenum target, WebGLuint index, WebGLBuffer* buffer)
+{
+    if (!IsContextStable())
+        return;
+
+    if (!ValidateObjectAllowDeletedOrNull("bindBufferBase", buffer))
+        return;
+
+    // silently ignore a deleted buffer
+    if (buffer && buffer->IsDeleted()) {
+        return;
+    }
+
+    WebGLRefPtr<WebGLBuffer>* bufferSlot = GetBufferSlotByTargetIndexed(target, index, "bindBufferBase");
+
+    if (!bufferSlot) {
         return;
     }
 
     if (buffer) {
-        if ((buffer->Target() != LOCAL_GL_NONE) && (target != buffer->Target()))
+        if (!buffer->Target()) {
+            buffer->SetTarget(target);
+            buffer->SetHasEverBeenBound(true);
+        } else if (target != buffer->Target()) {
             return ErrorInvalidOperation("bindBuffer: buffer already bound to a different target");
-        buffer->SetTarget(target);
-        buffer->SetHasEverBeenBound(true);
+        }
     }
 
-    // we really want to do this AFTER all the validation is done, otherwise our bookkeeping could get confused.
-    // see bug 656752
-    if (target == LOCAL_GL_ARRAY_BUFFER) {
-        mBoundArrayBuffer = buffer;
-    } else if (target == LOCAL_GL_ELEMENT_ARRAY_BUFFER) {
-        mBoundVertexArray->mBoundElementArrayBuffer = buffer;
-    }
+    *bufferSlot = buffer;
 
     MakeContextCurrent();
 
-    gl->fBindBuffer(target, buffer ? buffer->GLName() : 0);
+    gl->fBindBufferBase(target, index, buffer ? buffer->GLName() : 0);
+}
+
+void
+WebGLContext::BindBufferRange(WebGLenum target, WebGLuint index, WebGLBuffer* buffer,
+                              WebGLintptr offset, WebGLsizeiptr size)
+{
+    if (!IsContextStable())
+        return;
+
+    if (!ValidateObjectAllowDeletedOrNull("bindBufferRange", buffer))
+        return;
+
+    // silently ignore a deleted buffer
+    if (buffer && buffer->IsDeleted())
+        return;
+
+    WebGLRefPtr<WebGLBuffer>* bufferSlot = GetBufferSlotByTargetIndexed(target, index, "bindBufferBase");
+
+    if (!bufferSlot) {
+        return;
+    }
+
+    if (buffer) {
+        if (!buffer->Target()) {
+            buffer->SetTarget(target);
+            buffer->SetHasEverBeenBound(true);
+        } else if (target != buffer->Target()) {
+            return ErrorInvalidOperation("bindBuffer: buffer already bound to a different target");
+        }
+    }
+
+    *bufferSlot = buffer;
+
+    MakeContextCurrent();
+
+    gl->fBindBufferRange(target, index, buffer ? buffer->GLName() : 0, offset, size);
 }
 
 void
 WebGLContext::BufferData(WebGLenum target, WebGLsizeiptr size,
                          WebGLenum usage)
 {
     if (!IsContextStable())
         return;
 
-    WebGLBuffer *boundBuffer = nullptr;
+    WebGLRefPtr<WebGLBuffer>* bufferSlot = GetBufferSlotByTarget(target, "bufferData");
 
-    if (target == LOCAL_GL_ARRAY_BUFFER) {
-        boundBuffer = mBoundArrayBuffer;
-    } else if (target == LOCAL_GL_ELEMENT_ARRAY_BUFFER) {
-        boundBuffer = mBoundVertexArray->mBoundElementArrayBuffer;
-    } else {
-        return ErrorInvalidEnumInfo("bufferData: target", target);
+    if (!bufferSlot) {
+        return;
     }
 
     if (size < 0)
         return ErrorInvalidValue("bufferData: negative size");
 
     if (!ValidateBufferUsageEnum(usage, "bufferData: usage"))
         return;
 
+    WebGLBuffer* boundBuffer = bufferSlot->get();
+
     if (!boundBuffer)
         return ErrorInvalidOperation("bufferData: no buffer bound!");
 
     void* zeroBuffer = calloc(size, 1);
     if (!zeroBuffer)
         return ErrorOutOfMemory("bufferData: out of memory");
 
     MakeContextCurrent();
@@ -102,31 +170,29 @@ WebGLContext::BufferData(WebGLenum targe
     if (!IsContextStable())
         return;
 
     if (maybeData.IsNull()) {
         // see http://www.khronos.org/bugzilla/show_bug.cgi?id=386
         return ErrorInvalidValue("bufferData: null object passed");
     }
 
-    const ArrayBuffer& data = maybeData.Value();
-
-    WebGLBuffer *boundBuffer = nullptr;
+    WebGLRefPtr<WebGLBuffer>* bufferSlot = GetBufferSlotByTarget(target, "bufferData");
 
-    if (target == LOCAL_GL_ARRAY_BUFFER) {
-        boundBuffer = mBoundArrayBuffer;
-    } else if (target == LOCAL_GL_ELEMENT_ARRAY_BUFFER) {
-        boundBuffer = mBoundVertexArray->mBoundElementArrayBuffer;
-    } else {
-        return ErrorInvalidEnumInfo("bufferData: target", target);
+    if (!bufferSlot) {
+        return;
     }
 
+    const ArrayBuffer& data = maybeData.Value();
+
     if (!ValidateBufferUsageEnum(usage, "bufferData: usage"))
         return;
 
+    WebGLBuffer* boundBuffer = bufferSlot->get();
+
     if (!boundBuffer)
         return ErrorInvalidOperation("bufferData: no buffer bound!");
 
     MakeContextCurrent();
     InvalidateBufferFetching();
 
     GLenum error = CheckedBufferData(target, data.Length(), data.Data(), usage);
 
@@ -143,29 +209,27 @@ WebGLContext::BufferData(WebGLenum targe
 
 void
 WebGLContext::BufferData(WebGLenum target, const ArrayBufferView& data,
                          WebGLenum usage)
 {
     if (!IsContextStable())
         return;
 
-    WebGLBuffer *boundBuffer = nullptr;
+    WebGLRefPtr<WebGLBuffer>* bufferSlot = GetBufferSlotByTarget(target, "bufferSubData");
 
-    if (target == LOCAL_GL_ARRAY_BUFFER) {
-        boundBuffer = mBoundArrayBuffer;
-    } else if (target == LOCAL_GL_ELEMENT_ARRAY_BUFFER) {
-        boundBuffer = mBoundVertexArray->mBoundElementArrayBuffer;
-    } else {
-        return ErrorInvalidEnumInfo("bufferData: target", target);
+    if (!bufferSlot) {
+        return;
     }
 
     if (!ValidateBufferUsageEnum(usage, "bufferData: usage"))
         return;
 
+    WebGLBuffer* boundBuffer = bufferSlot->get();
+
     if (!boundBuffer)
         return ErrorInvalidOperation("bufferData: no buffer bound!");
 
     InvalidateBufferFetching();
     MakeContextCurrent();
 
     GLenum error = CheckedBufferData(target, data.Length(), data.Data(), usage);
     if (error) {
@@ -186,31 +250,29 @@ WebGLContext::BufferSubData(GLenum targe
     if (!IsContextStable())
         return;
 
     if (maybeData.IsNull()) {
         // see http://www.khronos.org/bugzilla/show_bug.cgi?id=386
         return;
     }
 
-    const ArrayBuffer& data = maybeData.Value();
-
-    WebGLBuffer *boundBuffer = nullptr;
+    WebGLRefPtr<WebGLBuffer>* bufferSlot = GetBufferSlotByTarget(target, "bufferSubData");
 
-    if (target == LOCAL_GL_ARRAY_BUFFER) {
-        boundBuffer = mBoundArrayBuffer;
-    } else if (target == LOCAL_GL_ELEMENT_ARRAY_BUFFER) {
-        boundBuffer = mBoundVertexArray->mBoundElementArrayBuffer;
-    } else {
-        return ErrorInvalidEnumInfo("bufferSubData: target", target);
+    if (!bufferSlot) {
+        return;
     }
 
+    const ArrayBuffer& data = maybeData.Value();
+
     if (byteOffset < 0)
         return ErrorInvalidValue("bufferSubData: negative offset");
 
+    WebGLBuffer* boundBuffer = bufferSlot->get();
+
     if (!boundBuffer)
         return ErrorInvalidOperation("bufferData: no buffer bound!");
 
     CheckedUint32 checked_neededByteLength = CheckedUint32(byteOffset) + data.Length();
     if (!checked_neededByteLength.isValid())
         return ErrorInvalidValue("bufferSubData: integer overflow computing the needed byte length");
 
     if (checked_neededByteLength.value() > boundBuffer->ByteLength())
@@ -226,29 +288,27 @@ WebGLContext::BufferSubData(GLenum targe
 
 void
 WebGLContext::BufferSubData(WebGLenum target, WebGLsizeiptr byteOffset,
                             const ArrayBufferView& data)
 {
     if (!IsContextStable())
         return;
 
-    WebGLBuffer *boundBuffer = nullptr;
+    WebGLRefPtr<WebGLBuffer>* bufferSlot = GetBufferSlotByTarget(target, "bufferSubData");
 
-    if (target == LOCAL_GL_ARRAY_BUFFER) {
-        boundBuffer = mBoundArrayBuffer;
-    } else if (target == LOCAL_GL_ELEMENT_ARRAY_BUFFER) {
-        boundBuffer = mBoundVertexArray->mBoundElementArrayBuffer;
-    } else {
-        return ErrorInvalidEnumInfo("bufferSubData: target", target);
+    if (!bufferSlot) {
+        return;
     }
 
     if (byteOffset < 0)
         return ErrorInvalidValue("bufferSubData: negative offset");
 
+    WebGLBuffer* boundBuffer = bufferSlot->get();
+
     if (!boundBuffer)
         return ErrorInvalidOperation("bufferSubData: no buffer bound!");
 
     CheckedUint32 checked_neededByteLength = CheckedUint32(byteOffset) + data.Length();
     if (!checked_neededByteLength.isValid())
         return ErrorInvalidValue("bufferSubData: integer overflow computing the needed byte length");
 
     if (checked_neededByteLength.value() > boundBuffer->ByteLength())
@@ -308,39 +368,65 @@ WebGLContext::IsBuffer(WebGLBuffer *buff
         return false;
 
     return ValidateObjectAllowDeleted("isBuffer", buffer) &&
            !buffer->IsDeleted() &&
            buffer->HasEverBeenBound();
 }
 
 bool
-WebGLContext::ValidateBufferTarget(WebGLenum target, const char* infos)
-{
-    switch(target)
-    {
-        case LOCAL_GL_ARRAY_BUFFER:
-        case LOCAL_GL_ELEMENT_ARRAY_BUFFER:
-            return true;
-
-        default:
-            break;
-    }
-
-    ErrorInvalidEnum("%s: target: invalid enum value 0x%x", infos, target);
-    return false;
-}
-
-bool
 WebGLContext::ValidateBufferUsageEnum(WebGLenum target, const char *infos)
 {
     switch (target) {
         case LOCAL_GL_STREAM_DRAW:
         case LOCAL_GL_STATIC_DRAW:
         case LOCAL_GL_DYNAMIC_DRAW:
             return true;
         default:
             break;
     }
 
     ErrorInvalidEnumInfo(infos, target);
     return false;
 }
+
+WebGLRefPtr<WebGLBuffer>*
+WebGLContext::GetBufferSlotByTarget(GLenum target, const char* infos)
+{
+    switch (target) {
+        case LOCAL_GL_ARRAY_BUFFER:
+            return &mBoundArrayBuffer;
+
+        case LOCAL_GL_ELEMENT_ARRAY_BUFFER:
+            return &mBoundVertexArray->mBoundElementArrayBuffer;
+
+        case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
+            if (!IsWebGL2()) {
+                break;
+            }
+            return &mBoundTransformFeedbackBuffer;
+
+        default:
+            break;
+    }
+
+    ErrorInvalidEnum("%s: target: invalid enum value 0x%x", infos, target);
+    return nullptr;
+}
+
+WebGLRefPtr<WebGLBuffer>*
+WebGLContext::GetBufferSlotByTargetIndexed(GLenum target, GLuint index, const char* infos)
+{
+    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
+
+        default:
+            break;
+    }
+
+    ErrorInvalidEnum("%s: target: invalid enum value 0x%x", infos, target);
+    return nullptr;
+}
--- a/content/canvas/src/WebGLContextState.cpp
+++ b/content/canvas/src/WebGLContextState.cpp
@@ -297,16 +297,23 @@ WebGLContext::GetParameter(JSContext* cx
         {
             uint32_t length = mCompressedTextureFormats.Length();
             JSObject* obj = Uint32Array::Create(cx, this, length, mCompressedTextureFormats.Elements());
             if (!obj) {
                 rv = NS_ERROR_OUT_OF_MEMORY;
             }
             return JS::ObjectOrNullValue(obj);
         }
+        case LOCAL_GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS:
+        {
+            if (!IsWebGL2()) {
+                break;
+            }
+            return JS::Int32Value(mGLMaxTransformFeedbackSeparateAttribs);
+        }
 
         // unsigned int. here we may have to return very large values like 2^32-1 that can't be represented as
         // javascript integer values. We just return them as doubles and javascript doesn't care.
         case LOCAL_GL_STENCIL_BACK_VALUE_MASK:
         case LOCAL_GL_STENCIL_BACK_WRITEMASK:
         case LOCAL_GL_STENCIL_VALUE_MASK:
         case LOCAL_GL_STENCIL_WRITEMASK:
         {
@@ -430,16 +437,24 @@ WebGLContext::GetParameter(JSContext* cx
             return JS::ObjectOrNullValue(obj);
         }
 
         case LOCAL_GL_ARRAY_BUFFER_BINDING:
         {
             return WebGLObjectAsJSValue(cx, mBoundArrayBuffer.get(), rv);
         }
 
+        case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
+        {
+            if (!IsWebGL2()) {
+                break;
+            }
+            return WebGLObjectAsJSValue(cx, mBoundTransformFeedbackBuffer.get(), rv);
+        }
+
         case LOCAL_GL_ELEMENT_ARRAY_BUFFER_BINDING:
         {
             return WebGLObjectAsJSValue(cx, mBoundVertexArray->mBoundElementArrayBuffer.get(), rv);
         }
 
         case LOCAL_GL_RENDERBUFFER_BINDING:
         {
             return WebGLObjectAsJSValue(cx, mBoundRenderbuffer.get(), rv);
@@ -467,16 +482,42 @@ WebGLContext::GetParameter(JSContext* cx
 
         default:
             ErrorInvalidEnumInfo("getParameter: parameter", pname);
     }
 
     return JS::NullValue();
 }
 
+JS::Value
+WebGLContext::GetParameterIndexed(JSContext* cx, WebGLenum pname, WebGLuint index)
+{
+    if (!IsContextStable())
+        return JS::NullValue();
+
+    MakeContextCurrent();
+
+    switch (pname) {
+        case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER_BINDING:
+        {
+            if (index >= mGLMaxTransformFeedbackSeparateAttribs) {
+                ErrorInvalidValue("getParameterIndexed: index should be less than MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS", index);
+                return JS::NullValue();
+            }
+            return JS::NullValue(); // See bug 903594
+        }
+
+        default:
+            break;
+    }
+
+    ErrorInvalidEnumInfo("getParameterIndexed: parameter", pname);
+    return JS::NullValue();
+}
+
 bool
 WebGLContext::IsEnabled(WebGLenum cap)
 {
     if (!IsContextStable())
         return false;
 
     if (!ValidateCapabilityEnum(cap, "isEnabled"))
         return false;
--- a/content/canvas/src/WebGLContextValidate.cpp
+++ b/content/canvas/src/WebGLContextValidate.cpp
@@ -802,16 +802,17 @@ WebGLContext::InitAndValidateGL()
 
     mActiveTexture = 0;
     mWebGLError = LOCAL_GL_NO_ERROR;
 
     mBound2DTextures.Clear();
     mBoundCubeMapTextures.Clear();
 
     mBoundArrayBuffer = nullptr;
+    mBoundTransformFeedbackBuffer = nullptr;
     mCurrentProgram = nullptr;
 
     mBoundFramebuffer = nullptr;
     mBoundRenderbuffer = nullptr;
 
     MakeContextCurrent();
 
     // on desktop OpenGL, we always keep vertex attrib 0 array enabled
@@ -901,20 +902,24 @@ WebGLContext::InitAndValidateGL()
                     mGLMaxVaryingVectors = std::min(maxVertexOutputComponents, minFragmentInputComponents) / 4;
                     break;
                 case LOCAL_GL_INVALID_ENUM:
                     mGLMaxVaryingVectors = 16; // = 64/4, 64 is the min value for maxVertexOutputComponents in OpenGL 3.2 spec
                     break;
                 default:
                     GenerateWarning("GL error 0x%x occurred during WebGL context initialization!", error);
                     return false;
-            }   
+            }
         }
     }
 
+    if (IsWebGL2()) {
+        gl->GetUIntegerv(LOCAL_GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS, &mGLMaxTransformFeedbackSeparateAttribs);
+    }
+
     // Always 1 for GLES2
     mMaxFramebufferColorAttachments = 1;
 
     if (!gl->IsGLES2()) {
         // gl_PointSize is always available in ES2 GLSL, but has to be
         // specifically enabled on desktop GLSL.
         gl->fEnable(LOCAL_GL_VERTEX_PROGRAM_POINT_SIZE);
 
--- a/dom/base/nsWrapperCache.h
+++ b/dom/base/nsWrapperCache.h
@@ -608,9 +608,52 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsWrapperC
     NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field7)                  \
     NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field8)                  \
     NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field9)                  \
     NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field10)                 \
     NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS            \
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END                         \
   NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(_class)
 
+#define NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_11(_class,        \
+                                                 _field1,       \
+                                                 _field2,       \
+                                                 _field3,       \
+                                                 _field4,       \
+                                                 _field5,       \
+                                                 _field6,       \
+                                                 _field7,       \
+                                                 _field8,       \
+                                                 _field9,       \
+                                                 _field10,      \
+                                                 _field11)      \
+  NS_IMPL_CYCLE_COLLECTION_CLASS(_class)                        \
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(_class)                 \
+    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field1)                    \
+    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field2)                    \
+    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field3)                    \
+    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field4)                    \
+    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field5)                    \
+    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field6)                    \
+    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field7)                    \
+    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field8)                    \
+    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field9)                    \
+    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field10)                   \
+    NS_IMPL_CYCLE_COLLECTION_UNLINK(_field11)                   \
+    NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER           \
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_END                           \
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(_class)               \
+    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field1)                  \
+    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field2)                  \
+    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field3)                  \
+    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field4)                  \
+    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field5)                  \
+    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field6)                  \
+    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field7)                  \
+    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field8)                  \
+    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field9)                  \
+    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field10)                 \
+    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(_field11)                 \
+    NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS            \
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END                         \
+  NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(_class)
+
 #endif /* nsWrapperCache_h___ */
--- a/dom/webidl/WebGL2RenderingContext.webidl
+++ b/dom/webidl/WebGL2RenderingContext.webidl
@@ -65,17 +65,30 @@ interface WebGL2RenderingContext : WebGL
     const GLenum QUERY_RESULT_AVAILABLE      = 0x8867;
 
     /* instanced array */
     const GLenum VERTEX_ATTRIB_ARRAY_DIVISOR = 0x88FE;
 
     void vertexAttribDivisor(GLuint index, GLuint divisor);
 
     /* transform feedback */
-    const GLenum RASTERIZER_DISCARD          = 0x8C89;
+    const GLenum RASTERIZER_DISCARD                      = 0x8C89;
+    const GLenum TRANSFORM_FEEDBACK_BUFFER               = 0x8C8E;
+    const GLenum TRANSFORM_FEEDBACK_BUFFER_BINDING       = 0x8C8F;
+    const GLenum TRANSFORM_FEEDBACK_BUFFER_START         = 0x8C84;
+    const GLenum TRANSFORM_FEEDBACK_BUFFER_SIZE          = 0x8C85;
+    const GLenum MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS = 0x8C8B;
+
+    /* buffer objects */
+    void bindBufferBase(GLenum target, GLuint index, WebGLBuffer? buffer);
+    void bindBufferRange(GLenum target, GLuint index, WebGLBuffer? buffer,
+                         GLintptr offset, GLsizeiptr size);
+
+    /* state requests */
+    any getParameterIndexed(GLenum pname, GLuint index);
 
 
     void beginQuery(GLenum target, WebGLQuery? queryObject);
     void bindVertexArray(WebGLVertexArray? arrayObject);
     WebGLQuery? createQuery();
     WebGLVertexArray? createVertexArray();
     void drawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei primcount);
     void drawBuffers(sequence<GLenum> buffers);