Bug 1048731 - [WebGL2] Implement new buffer binding targets. r=jgilbert
authorDan Glastonbury <dglastonbury@mozilla.com>
Fri, 05 Dec 2014 17:04:55 +1000
changeset 218929 c9c62f7fb8b236f7dd1a89e04f2eea2cb68af575
parent 218928 a790927adb607e89f88210d7cfb30c62f3c4eecd
child 218930 6ff5dad95494dfcccdf2d7c6290f880a7d480db6
push id27949
push usercbook@mozilla.com
push dateWed, 10 Dec 2014 10:50:45 +0000
treeherdermozilla-central@551c3cd74dbd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjgilbert
bugs1048731
milestone37.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 1048731 - [WebGL2] Implement new buffer binding targets. r=jgilbert
dom/canvas/WebGL1Context.h
dom/canvas/WebGL1ContextBuffers.cpp
dom/canvas/WebGL2Context.cpp
dom/canvas/WebGL2Context.h
dom/canvas/WebGL2ContextBuffers.cpp
dom/canvas/WebGLContext.cpp
dom/canvas/WebGLContext.h
dom/canvas/WebGLContextBuffers.cpp
dom/canvas/WebGLContextGL.cpp
dom/canvas/WebGLContextUnchecked.cpp
dom/canvas/WebGLContextUnchecked.h
dom/canvas/WebGLContextValidate.cpp
dom/canvas/WebGLTransformFeedback.cpp
--- a/dom/canvas/WebGL1Context.h
+++ b/dom/canvas/WebGL1Context.h
@@ -28,13 +28,14 @@ public:
 
     // nsWrapperCache
     virtual JSObject* WrapObject(JSContext* cx) MOZ_OVERRIDE;
 
 private:
     virtual bool ValidateAttribPointerType(bool integerMode, GLenum type, GLsizei* alignment, const char* info) MOZ_OVERRIDE;
     virtual bool ValidateBufferTarget(GLenum target, const char* info) MOZ_OVERRIDE;
     virtual bool ValidateBufferIndexedTarget(GLenum target, const char* info) MOZ_OVERRIDE;
+    virtual bool ValidateBufferForTarget(GLenum target, WebGLBuffer* buffer, const char* info) MOZ_OVERRIDE;
 };
 
 } // namespace mozilla
 
 #endif // WEBGL_1_CONTEXT_H_
--- a/dom/canvas/WebGL1ContextBuffers.cpp
+++ b/dom/canvas/WebGL1ContextBuffers.cpp
@@ -29,8 +29,24 @@ WebGL1Context::ValidateBufferTarget(GLen
 }
 
 bool
 WebGL1Context::ValidateBufferIndexedTarget(GLenum target, const char* info)
 {
     ErrorInvalidEnumInfo(info, target);
     return false;
 }
+
+/** Buffer and Target validation for BindBuffer */
+bool
+WebGL1Context::ValidateBufferForTarget(GLenum target, WebGLBuffer* buffer,
+                                       const char* info)
+{
+    if (!buffer)
+        return true;
+
+    if (buffer->HasEverBeenBound() && target != buffer->Target()) {
+        ErrorInvalidOperation("%s: buffer already bound to a different target", info);
+        return false;
+    }
+
+    return true;
+}
--- a/dom/canvas/WebGL2Context.cpp
+++ b/dom/canvas/WebGL2Context.cpp
@@ -134,16 +134,23 @@ WebGLContext::InitWebGL2()
         EnableExtension(kNativelySupportedExtensions[i]);
 
         MOZ_ASSERT(IsExtensionEnabled(kNativelySupportedExtensions[i]));
     }
 
     // we initialise WebGL 2 related stuff.
     gl->GetUIntegerv(LOCAL_GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS,
                      &mGLMaxTransformFeedbackSeparateAttribs);
+    gl->GetUIntegerv(LOCAL_GL_MAX_UNIFORM_BUFFER_BINDINGS,
+                     &mGLMaxUniformBufferBindings);
+
+    mBoundTransformFeedbackBuffers =
+        MakeUnique<WebGLRefPtr<WebGLBuffer>[]>(mGLMaxTransformFeedbackSeparateAttribs);
+    mBoundUniformBuffers =
+        MakeUnique<WebGLRefPtr<WebGLBuffer>[]>(mGLMaxUniformBufferBindings);
 
     mDefaultTransformFeedback = new WebGLTransformFeedback(this, 0);
     mBoundTransformFeedback = mDefaultTransformFeedback;
     auto xfBuffers = new WebGLRefPtr<WebGLBuffer>[mGLMaxTransformFeedbackSeparateAttribs];
     mBoundTransformFeedbackBuffers.reset(xfBuffers);
 
     return true;
 }
--- a/dom/canvas/WebGL2Context.h
+++ b/dom/canvas/WebGL2Context.h
@@ -259,13 +259,14 @@ private:
     bool ValidateSizedInternalFormat(GLenum internalFormat, const char* info);
     bool ValidateTexStorage(GLenum target, GLsizei levels, GLenum internalformat,
                                 GLsizei width, GLsizei height, GLsizei depth,
                                 const char* info);
 
     virtual bool ValidateAttribPointerType(bool integerMode, GLenum type, GLsizei* alignment, const char* info) MOZ_OVERRIDE;
     virtual bool ValidateBufferTarget(GLenum target, const char* info) MOZ_OVERRIDE;
     virtual bool ValidateBufferIndexedTarget(GLenum target, const char* info) MOZ_OVERRIDE;
+    virtual bool ValidateBufferForTarget(GLenum target, WebGLBuffer* buffer, const char* info) MOZ_OVERRIDE;
 };
 
 } // namespace mozilla
 
 #endif
--- a/dom/canvas/WebGL2ContextBuffers.cpp
+++ b/dom/canvas/WebGL2ContextBuffers.cpp
@@ -1,26 +1,33 @@
 /* -*- 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 "GLContext.h"
+#include "WebGLBuffer.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 bool
 WebGL2Context::ValidateBufferTarget(GLenum target, const char* info)
 {
     switch (target) {
     case LOCAL_GL_ARRAY_BUFFER:
+    case LOCAL_GL_COPY_READ_BUFFER:
+    case LOCAL_GL_COPY_WRITE_BUFFER:
     case LOCAL_GL_ELEMENT_ARRAY_BUFFER:
+    case LOCAL_GL_PIXEL_PACK_BUFFER:
+    case LOCAL_GL_PIXEL_UNPACK_BUFFER:
     case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
+    case LOCAL_GL_UNIFORM_BUFFER:
         return true;
 
     default:
         ErrorInvalidEnumInfo(info, target);
         return false;
     }
 }
 
@@ -33,30 +40,103 @@ WebGL2Context::ValidateBufferIndexedTarg
         return true;
 
     default:
         ErrorInvalidEnumInfo(info, target);
         return false;
     }
 }
 
+bool
+WebGL2Context::ValidateBufferForTarget(GLenum target, WebGLBuffer* buffer,
+                                       const char* info)
+{
+    if (!buffer)
+        return true;
+
+    switch (target) {
+    case LOCAL_GL_COPY_READ_BUFFER:
+    case LOCAL_GL_COPY_WRITE_BUFFER:
+        return true;
+
+    case LOCAL_GL_ELEMENT_ARRAY_BUFFER:
+        return !buffer->HasEverBeenBound() ||
+            buffer->Target() == LOCAL_GL_ELEMENT_ARRAY_BUFFER;
+
+    case LOCAL_GL_ARRAY_BUFFER:
+    case LOCAL_GL_PIXEL_PACK_BUFFER:
+    case LOCAL_GL_PIXEL_UNPACK_BUFFER:
+    case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
+    case LOCAL_GL_UNIFORM_BUFFER:
+        return !buffer->HasEverBeenBound() ||
+            buffer->Target() != LOCAL_GL_ELEMENT_ARRAY_BUFFER;
+    }
+
+    ErrorInvalidOperation("%s: buffer already bound to a incompatible target %s",
+                          info, EnumName(buffer->Target().get()));
+    return false;
+}
+
 // -------------------------------------------------------------------------
 // Buffer objects
 
 void
-WebGL2Context::CopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset,
-                                 GLintptr writeOffset, GLsizeiptr size)
+WebGL2Context::CopyBufferSubData(GLenum readTarget, GLenum writeTarget,
+                                 GLintptr readOffset, GLintptr writeOffset,
+                                 GLsizeiptr size)
 {
-    MakeContextCurrent();
-    gl->fCopyBufferSubData(readTarget, writeTarget, readOffset, writeOffset, size);
+    if (IsContextLost())
+        return;
+
+    if (!ValidateBufferTarget(readTarget, "copyBufferSubData") ||
+        !ValidateBufferTarget(writeTarget, "copyBufferSubData"))
+    {
+        return;
+    }
+
+    const WebGLRefPtr<WebGLBuffer>& readBufferSlot = GetBufferSlotByTarget(readTarget);
+    const WebGLRefPtr<WebGLBuffer>& writeBufferSlot = GetBufferSlotByTarget(writeTarget);
+    if (!readBufferSlot || !writeBufferSlot)
+        return;
+
+    const WebGLBuffer* readBuffer = readBufferSlot.get();
+    if (!readBuffer)
+        return ErrorInvalidOperation("copyBufferSubData: No buffer bound to readTarget");
+
+    const WebGLBuffer* writeBuffer = writeBufferSlot.get();
+    if (!writeBuffer)
+        return ErrorInvalidOperation("copyBufferSubData: No buffer bound to writeTarget");
+
+    if (!ValidateDataOffsetSize(readOffset, size, readBuffer->ByteLength(),
+        "copyBufferSubData"))
+    {
+        return;
+    }
+
+    if (!ValidateDataOffsetSize(writeOffset, size, writeBuffer->ByteLength(),
+        "copyBufferSubData"))
+    {
+        return;
+    }
+
+    if (readTarget == writeTarget &&
+        !ValidateDataRanges(readOffset, writeOffset, size, "copyBufferSubData"))
+    {
+        return;
+    }
+
+    WebGLContextUnchecked::CopyBufferSubData(readTarget, writeTarget, readOffset,
+                                             writeOffset, size);
 }
 
 void
-WebGL2Context::GetBufferSubData(GLenum target, GLintptr offset, const dom::ArrayBuffer& returnedData)
+WebGL2Context::GetBufferSubData(GLenum target, GLintptr offset,
+                                const dom::ArrayBuffer& returnedData)
 {
     MOZ_CRASH("Not Implemented.");
 }
 
 void
-WebGL2Context::GetBufferSubData(GLenum target, GLintptr offset, const dom::ArrayBufferView& returnedData)
+WebGL2Context::GetBufferSubData(GLenum target, GLintptr offset,
+                                const dom::ArrayBufferView& returnedData)
 {
     MOZ_CRASH("Not Implemented.");
 }
--- a/dom/canvas/WebGLContext.cpp
+++ b/dom/canvas/WebGLContext.cpp
@@ -252,16 +252,17 @@ WebGLContext::WebGLContext()
     mGLMaxTextureImageUnits = 0;
     mGLMaxVertexTextureImageUnits = 0;
     mGLMaxVaryingVectors = 0;
     mGLMaxFragmentUniformVectors = 0;
     mGLMaxVertexUniformVectors = 0;
     mGLMaxColorAttachments = 1;
     mGLMaxDrawBuffers = 1;
     mGLMaxTransformFeedbackSeparateAttribs = 0;
+    mGLMaxUniformBufferBindings = 0;
 
     // See OpenGL ES 2.0.25 spec, 6.2 State Tables, table 6.13
     mPixelStorePackAlignment = 4;
     mPixelStoreUnpackAlignment = 4;
 
     WebGLMemoryTracker::AddWebGLContext(this);
 
     mAllowContextRestore = true;
@@ -317,32 +318,40 @@ WebGLContext::DestroyResourcesAndContext
         return;
 
     gl->MakeCurrent();
 
     mBound2DTextures.Clear();
     mBoundCubeMapTextures.Clear();
     mBound3DTextures.Clear();
     mBoundArrayBuffer = nullptr;
+    mBoundCopyReadBuffer = nullptr;
+    mBoundCopyWriteBuffer = nullptr;
+    mBoundPixelPackBuffer = nullptr;
+    mBoundPixelUnpackBuffer = nullptr;
     mBoundTransformFeedbackBuffer = nullptr;
+    mBoundUniformBuffer = nullptr;
     mCurrentProgram = nullptr;
     mBoundFramebuffer = nullptr;
     mActiveOcclusionQuery = nullptr;
     mBoundRenderbuffer = nullptr;
     mBoundVertexArray = nullptr;
     mDefaultVertexArray = nullptr;
     mBoundTransformFeedback = nullptr;
     mDefaultTransformFeedback = nullptr;
 
     if (mBoundTransformFeedbackBuffers) {
         for (GLuint i = 0; i < mGLMaxTransformFeedbackSeparateAttribs; i++) {
             mBoundTransformFeedbackBuffers[i] = nullptr;
         }
     }
 
+    for (GLuint i = 0; i < mGLMaxUniformBufferBindings; i++)
+        mBoundUniformBuffers[i] = nullptr;
+
     while (!mTextures.isEmpty())
         mTextures.getLast()->DeleteOnce();
     while (!mVertexArrays.isEmpty())
         mVertexArrays.getLast()->DeleteOnce();
     while (!mBuffers.isEmpty())
         mBuffers.getLast()->DeleteOnce();
     while (!mRenderbuffers.isEmpty())
         mRenderbuffers.getLast()->DeleteOnce();
@@ -1857,30 +1866,35 @@ WebGLContext::ScopedMaskWorkaround::~Sco
 }
 ////////////////////////////////////////////////////////////////////////////////
 // XPCOM goop
 
 NS_IMPL_CYCLE_COLLECTING_ADDREF(WebGLContext)
 NS_IMPL_CYCLE_COLLECTING_RELEASE(WebGLContext)
 
 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLContext,
-                                      mCanvasElement,
-                                      mExtensions,
-                                      mBound2DTextures,
-                                      mBoundCubeMapTextures,
-                                      mBound3DTextures,
-                                      mBoundArrayBuffer,
-                                      mBoundTransformFeedbackBuffer,
-                                      mCurrentProgram,
-                                      mBoundFramebuffer,
-                                      mBoundRenderbuffer,
-                                      mBoundVertexArray,
-                                      mDefaultVertexArray,
-                                      mActiveOcclusionQuery,
-                                      mActiveTransformFeedbackQuery)
+  mCanvasElement,
+  mExtensions,
+  mBound2DTextures,
+  mBoundCubeMapTextures,
+  mBound3DTextures,
+  mBoundArrayBuffer,
+  mBoundCopyReadBuffer,
+  mBoundCopyWriteBuffer,
+  mBoundPixelPackBuffer,
+  mBoundPixelUnpackBuffer,
+  mBoundTransformFeedbackBuffer,
+  mBoundUniformBuffer,
+  mCurrentProgram,
+  mBoundFramebuffer,
+  mBoundRenderbuffer,
+  mBoundVertexArray,
+  mDefaultVertexArray,
+  mActiveOcclusionQuery,
+  mActiveTransformFeedbackQuery)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WebGLContext)
     NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
     NS_INTERFACE_MAP_ENTRY(nsIDOMWebGLRenderingContext)
     NS_INTERFACE_MAP_ENTRY(nsICanvasRenderingContextInternal)
     NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
     // If the exact way we cast to nsISupports here ever changes, fix our
     // ToSupports() method.
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -859,43 +859,65 @@ public:
 // -----------------------------------------------------------------------------
 // WEBGL_lose_context
 public:
     void LoseContext();
     void RestoreContext();
 
 // -----------------------------------------------------------------------------
 // Buffer Objects (WebGLContextBuffers.cpp)
+private:
+    void UpdateBoundBuffer(GLenum target, WebGLBuffer* buffer);
+    void UpdateBoundBufferIndexed(GLenum target, GLuint index, WebGLBuffer* buffer);
+
 public:
-    void BindBuffer(GLenum target, WebGLBuffer* buf);
+    void BindBuffer(GLenum target, WebGLBuffer* buffer);
     void BindBufferBase(GLenum target, GLuint index, WebGLBuffer* buf);
     void BindBufferRange(GLenum target, GLuint index, WebGLBuffer* buf,
                          WebGLintptr offset, WebGLsizeiptr size);
+
+private:
+    void BufferDataUnchecked(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage);
+    void BufferData(GLenum target, WebGLsizeiptr size, void* data, GLenum usage);
+
+public:
     void BufferData(GLenum target, WebGLsizeiptr size, GLenum usage);
     void BufferData(GLenum target, const dom::ArrayBufferView& data,
                     GLenum usage);
     void BufferData(GLenum target, const Nullable<dom::ArrayBuffer>& maybeData,
                     GLenum usage);
+
+private:
+    void BufferSubDataUnchecked(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data);
+    void BufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data);
+
+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* buf);
 
 protected:
     // bound buffer state
     WebGLRefPtr<WebGLBuffer> mBoundArrayBuffer;
+    WebGLRefPtr<WebGLBuffer> mBoundCopyReadBuffer;
+    WebGLRefPtr<WebGLBuffer> mBoundCopyWriteBuffer;
+    WebGLRefPtr<WebGLBuffer> mBoundPixelPackBuffer;
+    WebGLRefPtr<WebGLBuffer> mBoundPixelUnpackBuffer;
     WebGLRefPtr<WebGLBuffer> mBoundTransformFeedbackBuffer;
+    WebGLRefPtr<WebGLBuffer> mBoundUniformBuffer;
 
+    UniquePtr<WebGLRefPtr<WebGLBuffer>[]> mBoundUniformBuffers;
     UniquePtr<WebGLRefPtr<WebGLBuffer>[]> mBoundTransformFeedbackBuffers;
 
-    WebGLRefPtr<WebGLBuffer>* GetBufferSlotByTarget(GLenum target);
-    WebGLRefPtr<WebGLBuffer>* GetBufferSlotByTargetIndexed(GLenum target,
+    WebGLRefPtr<WebGLBuffer>& GetBufferSlotByTarget(GLenum target);
+    WebGLRefPtr<WebGLBuffer>& GetBufferSlotByTargetIndexed(GLenum target,
                                                            GLuint index);
     bool ValidateBufferUsageEnum(GLenum target, const char* info);
 
 // -----------------------------------------------------------------------------
 // Queries (WebGL2ContextQueries.cpp)
 protected:
     WebGLRefPtr<WebGLQuery>* GetQueryTargetSlot(GLenum target);
 
@@ -1000,24 +1022,16 @@ public:
 private:
     // Cache the max number of vertices and instances that can be read from
     // bound VBOs (result of ValidateBuffers).
     bool mBufferFetchingIsVerified;
     bool mBufferFetchingHasPerVertex;
     uint32_t mMaxFetchedVertices;
     uint32_t mMaxFetchedInstances;
 
-protected:
-    inline void InvalidateBufferFetching() {
-        mBufferFetchingIsVerified = false;
-        mBufferFetchingHasPerVertex = false;
-        mMaxFetchedVertices = 0;
-        mMaxFetchedInstances = 0;
-    }
-
     bool DrawArrays_check(GLint first, GLsizei count, GLsizei primcount,
                           const char* info);
     bool DrawElements_check(GLsizei count, GLenum type, WebGLintptr byteOffset,
                             GLsizei primcount, const char* info,
                             GLuint* out_upperBound);
     bool DrawInstanced_check(const char* info);
     void Draw_cleanup();
 
@@ -1061,16 +1075,24 @@ protected:
 
     // Returns x rounded to the next highest multiple of y.
     static CheckedUint32 RoundedToNextMultipleOf(CheckedUint32 x,
                                                  CheckedUint32 y)
     {
         return ((x + y - 1) / y) * y;
     }
 
+    inline void InvalidateBufferFetching()
+    {
+        mBufferFetchingIsVerified = false;
+        mBufferFetchingHasPerVertex = false;
+        mMaxFetchedVertices = 0;
+        mMaxFetchedInstances = 0;
+    }
+
     CheckedUint32 mGeneration;
 
     WebGLContextOptions mOptions;
 
     bool mInvalidated;
     bool mResetLayer;
     bool mOptionsFrozen;
     bool mMinCapability;
@@ -1108,16 +1130,17 @@ protected:
     int32_t mGLMaxTextureImageUnits;
     int32_t mGLMaxVertexTextureImageUnits;
     int32_t mGLMaxVaryingVectors;
     int32_t mGLMaxFragmentUniformVectors;
     int32_t mGLMaxVertexUniformVectors;
     int32_t mGLMaxColorAttachments;
     int32_t mGLMaxDrawBuffers;
     GLuint  mGLMaxTransformFeedbackSeparateAttribs;
+    GLuint  mGLMaxUniformBufferBindings;
 
 public:
     GLuint MaxVertexAttribs() const {
         return mGLMaxVertexAttribs;
     }
 
 
     bool IsFormatValidForFB(GLenum sizedFormat) const;
@@ -1180,16 +1203,18 @@ protected:
     bool CreateOffscreenGL(bool forceEnabled);
     bool InitAndValidateGL();
     bool ResizeBackbuffer(uint32_t width, uint32_t height);
     bool ValidateBlendEquationEnum(GLenum cap, const char* info);
     bool ValidateBlendFuncDstEnum(GLenum mode, const char* info);
     bool ValidateBlendFuncSrcEnum(GLenum mode, const char* info);
     bool ValidateBlendFuncEnumsCompatibility(GLenum sfactor, GLenum dfactor,
                                              const char* info);
+    bool ValidateDataOffsetSize(WebGLintptr offset, WebGLsizeiptr size, WebGLsizeiptr bufferSize, const char* info);
+    bool ValidateDataRanges(WebGLintptr readOffset, WebGLintptr writeOffset, WebGLsizeiptr size, const char* info);
     bool ValidateTextureTargetEnum(GLenum target, const char* info);
     bool ValidateComparisonEnum(GLenum target, const char* info);
     bool ValidateStencilOpEnum(GLenum action, const char* info);
     bool ValidateFaceEnum(GLenum face, const char* info);
     bool ValidateTexInputData(GLenum type, js::Scalar::Type jsArrayType,
                               WebGLTexImageFunc func, WebGLTexDimensions dims);
     bool ValidateDrawModeEnum(GLenum mode, const char* info);
     bool ValidateAttribIndex(GLuint index, const char* info);
@@ -1334,16 +1359,17 @@ private:
     bool ValidateObjectAssumeNonNull(const char* info, ObjectType* object);
 
 private:
     // -------------------------------------------------------------------------
     // Context customization points
     virtual bool ValidateAttribPointerType(bool integerMode, GLenum type, GLsizei* alignment, const char* info) = 0;
     virtual bool ValidateBufferTarget(GLenum target, const char* info) = 0;
     virtual bool ValidateBufferIndexedTarget(GLenum target, const char* info) = 0;
+    virtual bool ValidateBufferForTarget(GLenum target, WebGLBuffer* buffer, const char* info) = 0;
 
 protected:
     int32_t MaxTextureSizeForTarget(TexTarget target) const {
         return (target == LOCAL_GL_TEXTURE_2D) ? mGLMaxTextureSize
                                                : mGLMaxCubeMapTextureSize;
     }
 
     int32_t
@@ -1391,18 +1417,18 @@ protected:
     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<WebGLTransformFeedback> mDefaultTransformFeedback;
     WebGLRefPtr<WebGLVertexArray> mDefaultVertexArray;
-    WebGLRefPtr<WebGLTransformFeedback> mDefaultTransformFeedback;
 
     // PixelStore parameters
     uint32_t mPixelStorePackAlignment;
     uint32_t mPixelStoreUnpackAlignment;
     uint32_t mPixelStoreColorspaceConversion;
     bool mPixelStoreFlipY;
     bool mPixelStorePremultiplyAlpha;
 
--- a/dom/canvas/WebGLContextBuffers.cpp
+++ b/dom/canvas/WebGLContextBuffers.cpp
@@ -7,99 +7,113 @@
 
 #include "GLContext.h"
 #include "WebGLBuffer.h"
 #include "WebGLVertexArray.h"
 
 namespace mozilla {
 
 void
+WebGLContext::UpdateBoundBuffer(GLenum target, WebGLBuffer* buffer)
+{
+    WebGLRefPtr<WebGLBuffer>& bufferSlot = GetBufferSlotByTarget(target);
+    bufferSlot = buffer;
+
+    if (!buffer)
+        return;
+
+    /* https://www.khronos.org/registry/webgl/specs/latest/2.0/#5.1
+     *
+     * In the WebGL 2 API, buffers have their WebGL buffer type
+     * initially set to undefined. Calling bindBuffer, bindBufferRange
+     * or bindBufferBase with the target argument set to any buffer
+     * binding point except COPY_READ_BUFFER or COPY_WRITE_BUFFER will
+     * then set the WebGL buffer type of the buffer being bound
+     * according to the table above.
+     *
+     * Any call to one of these functions which attempts to bind a
+     * WebGLBuffer that has the element array WebGL buffer type to a
+     * binding point that falls under other data, or bind a
+     * WebGLBuffer which has the other data WebGL buffer type to
+     * ELEMENT_ARRAY_BUFFER will generate an INVALID_OPERATION error,
+     * and the state of the binding point will remain untouched.
+     */
+    if (target != LOCAL_GL_COPY_READ_BUFFER && target != LOCAL_GL_COPY_WRITE_BUFFER)
+        buffer->BindTo(target);
+}
+
+void
+WebGLContext::UpdateBoundBufferIndexed(GLenum target, GLuint index, WebGLBuffer* buffer)
+{
+    UpdateBoundBuffer(target, buffer);
+
+    WebGLRefPtr<WebGLBuffer>& bufferIndexSlot =
+        GetBufferSlotByTargetIndexed(target, index);
+    bufferIndexSlot = buffer;
+}
+
+void
 WebGLContext::BindBuffer(GLenum target, WebGLBuffer* buffer)
 {
     if (IsContextLost())
         return;
 
     if (!ValidateObjectAllowDeletedOrNull("bindBuffer", buffer))
         return;
 
     // silently ignore a deleted buffer
     if (buffer && buffer->IsDeleted())
         return;
 
     if (!ValidateBufferTarget(target, "bindBuffer"))
         return;
 
-    WebGLRefPtr<WebGLBuffer>* bufferSlot = GetBufferSlotByTarget(target);
-    MOZ_ASSERT(bufferSlot);
+    if (!ValidateBufferForTarget(target, buffer, "bindBuffer"))
+        return;
 
-    if (buffer) {
-        if (!buffer->HasEverBeenBound()) {
-            buffer->BindTo(target);
-        } else if (target != buffer->Target()) {
-            ErrorInvalidOperation("bindBuffer: Buffer already bound to a"
-                                  " different target.");
-            return;
-        }
-    }
+    WebGLContextUnchecked::BindBuffer(target, buffer);
 
-    *bufferSlot = buffer;
-
-    MakeContextCurrent();
-
-    gl->fBindBuffer(target, buffer ? buffer->GLName() : 0);
+    UpdateBoundBuffer(target, buffer);
 }
 
 void
 WebGLContext::BindBufferBase(GLenum target, GLuint index, WebGLBuffer* buffer)
 {
     if (IsContextLost())
         return;
 
     if (!ValidateObjectAllowDeletedOrNull("bindBufferBase", buffer))
         return;
 
     // silently ignore a deleted buffer
-    if (buffer && buffer->IsDeleted()) {
+    if (buffer && buffer->IsDeleted())
         return;
-    }
 
     // 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");
+
+    case LOCAL_GL_UNIFORM_BUFFER:
+        if (index >= mGLMaxUniformBufferBindings)
+            return ErrorInvalidValue("bindBufferBase: index should be less than "
+                                     "MAX_UNIFORM_BUFFER_BINDINGS");
+
     default:
         return ErrorInvalidEnumInfo("bindBufferBase: target", target);
     }
 
-    WebGLRefPtr<WebGLBuffer>* indexedBufferSlot;
-    indexedBufferSlot = GetBufferSlotByTargetIndexed(target, index);
-    MOZ_ASSERT(indexedBufferSlot);
-
-    if (buffer) {
-        if (!buffer->HasEverBeenBound())
-            buffer->BindTo(target);
+    if (!ValidateBufferForTarget(target, buffer, "bindBufferBase"))
+        return;
 
-        if (target != buffer->Target()) {
-            ErrorInvalidOperation("bindBuffer: Buffer already bound to a"
-                                  " different target.");
-            return;
-        }
-    }
+    WebGLContextUnchecked::BindBufferBase(target, index, buffer);
 
-    WebGLRefPtr<WebGLBuffer>* bufferSlot = GetBufferSlotByTarget(target);
-    MOZ_ASSERT(bufferSlot, "GetBufferSlotByTarget(Indexed) mismatch");
-
-    *indexedBufferSlot = buffer;
-    *bufferSlot = buffer;
-
-    MakeContextCurrent();
-
-    gl->fBindBufferBase(target, index, buffer ? buffer->GLName() : 0);
+    UpdateBoundBufferIndexed(target, index, buffer);
 }
 
 void
 WebGLContext::BindBufferRange(GLenum target, GLuint index, WebGLBuffer* buffer,
                               WebGLintptr offset, WebGLsizeiptr size)
 {
     if (IsContextLost())
         return;
@@ -113,77 +127,54 @@ WebGLContext::BindBufferRange(GLenum tar
 
     // 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");
 
+    case LOCAL_GL_UNIFORM_BUFFER:
+        if (index >= mGLMaxUniformBufferBindings)
+            return ErrorInvalidValue("bindBufferRange: index should be less than "
+                                     "MAX_UNIFORM_BUFFER_BINDINGS");
     default:
         return ErrorInvalidEnumInfo("bindBufferRange: target", target);
     }
 
-    WebGLRefPtr<WebGLBuffer>* indexedBufferSlot;
-    indexedBufferSlot = GetBufferSlotByTargetIndexed(target, index);
-    MOZ_ASSERT(indexedBufferSlot);
-
-    if (buffer) {
-        if (!buffer->HasEverBeenBound())
-            buffer->BindTo(target);
-
-        if (target != buffer->Target()) {
-            ErrorInvalidOperation("bindBuffer: Buffer already bound to a"
-                                  " different target.");
-            return;
-        }
+    if (!ValidateBufferForTarget(target, buffer, "bindBufferRange"))
+        return;
 
-        CheckedInt<WebGLsizeiptr> checked_neededByteLength = CheckedInt<WebGLsizeiptr>(offset) + size;
-        if (!checked_neededByteLength.isValid() ||
-            checked_neededByteLength.value() > buffer->ByteLength())
-        {
-            return ErrorInvalidValue("bindBufferRange: invalid range");
-        }
-    }
+    WebGLContextUnchecked::BindBufferRange(target, index, buffer, offset, size);
 
-    WebGLRefPtr<WebGLBuffer>* bufferSlot = GetBufferSlotByTarget(target);
-    MOZ_ASSERT(bufferSlot, "GetBufferSlotByTarget(Indexed) mismatch");
-
-    *indexedBufferSlot = buffer;
-    *bufferSlot = buffer;
-
-    MakeContextCurrent();
-
-    gl->fBindBufferRange(target, index, buffer ? buffer->GLName() : 0, offset,
-                         size);
+    UpdateBoundBufferIndexed(target, index, buffer);
 }
 
 void
 WebGLContext::BufferData(GLenum target, WebGLsizeiptr size, GLenum usage)
 {
     if (IsContextLost())
         return;
 
     if (!ValidateBufferTarget(target, "bufferData"))
         return;
 
-    WebGLRefPtr<WebGLBuffer>* bufferSlot = GetBufferSlotByTarget(target);
-    MOZ_ASSERT(bufferSlot);
+    WebGLRefPtr<WebGLBuffer>& bufferSlot = GetBufferSlotByTarget(target);
 
     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.
     if (!CheckedInt<GLsizeiptr>(size).isValid())
         return ErrorOutOfMemory("bufferData: bad size");
 
-    WebGLBuffer* boundBuffer = bufferSlot->get();
+    WebGLBuffer* boundBuffer = bufferSlot.get();
 
     if (!boundBuffer)
         return ErrorInvalidOperation("bufferData: no buffer bound!");
 
     UniquePtr<uint8_t> zeroBuffer((uint8_t*)moz_calloc(size, 1));
     if (!zeroBuffer)
         return ErrorOutOfMemory("bufferData: out of memory");
 
@@ -214,31 +205,30 @@ WebGLContext::BufferData(GLenum target,
     if (maybeData.IsNull()) {
         // see http://www.khronos.org/bugzilla/show_bug.cgi?id=386
         return ErrorInvalidValue("bufferData: null object passed");
     }
 
     if (!ValidateBufferTarget(target, "bufferData"))
         return;
 
-    WebGLRefPtr<WebGLBuffer>* bufferSlot = GetBufferSlotByTarget(target);
-    MOZ_ASSERT(bufferSlot);
+    const WebGLRefPtr<WebGLBuffer>& bufferSlot = GetBufferSlotByTarget(target);
 
     const dom::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");
 
     if (!ValidateBufferUsageEnum(usage, "bufferData: usage"))
         return;
 
-    WebGLBuffer* boundBuffer = bufferSlot->get();
+    WebGLBuffer* boundBuffer = bufferSlot.get();
 
     if (!boundBuffer)
         return ErrorInvalidOperation("bufferData: no buffer bound!");
 
     MakeContextCurrent();
     InvalidateBufferFetching();
 
     GLenum error = CheckedBufferData(target, data.Length(), data.Data(), usage);
@@ -258,24 +248,22 @@ WebGLContext::BufferData(GLenum target, 
                          GLenum usage)
 {
     if (IsContextLost())
         return;
 
     if (!ValidateBufferTarget(target, "bufferData"))
         return;
 
-    WebGLRefPtr<WebGLBuffer>* bufferSlot = GetBufferSlotByTarget(target);
-    MOZ_ASSERT(bufferSlot);
+    WebGLRefPtr<WebGLBuffer>& bufferSlot = GetBufferSlotByTarget(target);
 
     if (!ValidateBufferUsageEnum(usage, "bufferData: usage"))
         return;
 
-    WebGLBuffer* boundBuffer = bufferSlot->get();
-
+    WebGLBuffer* boundBuffer = bufferSlot.get();
     if (!boundBuffer)
         return ErrorInvalidOperation("bufferData: no buffer bound!");
 
     data.ComputeLengthAndData();
 
     // Careful: data.Length() could conceivably be any uint32_t, but GLsizeiptr
     // is like intptr_t.
     if (!CheckedInt<GLsizeiptr>(data.Length()).isValid())
@@ -305,31 +293,31 @@ WebGLContext::BufferSubData(GLenum targe
     if (maybeData.IsNull()) {
         // see http://www.khronos.org/bugzilla/show_bug.cgi?id=386
         return;
     }
 
     if (!ValidateBufferTarget(target, "bufferSubData"))
         return;
 
-    WebGLRefPtr<WebGLBuffer>* bufferSlot = GetBufferSlotByTarget(target);
-    MOZ_ASSERT(bufferSlot);
+    WebGLRefPtr<WebGLBuffer>& bufferSlot = GetBufferSlotByTarget(target);
 
     if (byteOffset < 0)
         return ErrorInvalidValue("bufferSubData: negative offset");
 
-    WebGLBuffer* boundBuffer = bufferSlot->get();
-
+    WebGLBuffer* boundBuffer = bufferSlot.get();
     if (!boundBuffer)
         return ErrorInvalidOperation("bufferData: no buffer bound!");
 
     const dom::ArrayBuffer& data = maybeData.Value();
     data.ComputeLengthAndData();
 
-    CheckedInt<WebGLsizeiptr> checked_neededByteLength = CheckedInt<WebGLsizeiptr>(byteOffset) + data.Length();
+    CheckedInt<WebGLsizeiptr> checked_neededByteLength =
+        CheckedInt<WebGLsizeiptr>(byteOffset) + data.Length();
+
     if (!checked_neededByteLength.isValid()) {
         ErrorInvalidValue("bufferSubData: Integer overflow computing the needed"
                           " byte length.");
         return;
     }
 
     if (checked_neededByteLength.value() > boundBuffer->ByteLength()) {
         ErrorInvalidValue("bufferSubData: Not enough data. Operation requires"
@@ -351,30 +339,30 @@ WebGLContext::BufferSubData(GLenum targe
                             const dom::ArrayBufferView& data)
 {
     if (IsContextLost())
         return;
 
     if (!ValidateBufferTarget(target, "bufferSubData"))
         return;
 
-    WebGLRefPtr<WebGLBuffer>* bufferSlot = GetBufferSlotByTarget(target);
-    MOZ_ASSERT(bufferSlot);
+    WebGLRefPtr<WebGLBuffer>& bufferSlot = GetBufferSlotByTarget(target);
 
     if (byteOffset < 0)
         return ErrorInvalidValue("bufferSubData: negative offset");
 
-    WebGLBuffer* boundBuffer = bufferSlot->get();
-
+    WebGLBuffer* boundBuffer = bufferSlot.get();
     if (!boundBuffer)
         return ErrorInvalidOperation("bufferSubData: no buffer bound!");
 
     data.ComputeLengthAndData();
 
-    CheckedInt<WebGLsizeiptr> checked_neededByteLength = CheckedInt<WebGLsizeiptr>(byteOffset) + data.Length();
+    CheckedInt<WebGLsizeiptr> checked_neededByteLength =
+        CheckedInt<WebGLsizeiptr>(byteOffset) + data.Length();
+
     if (!checked_neededByteLength.isValid()) {
         ErrorInvalidValue("bufferSubData: Integer overflow computing the needed"
                           " byte length.");
         return;
     }
 
     if (checked_neededByteLength.value() > boundBuffer->ByteLength()) {
         ErrorInvalidValue("bufferSubData: Not enough data. Operation requires"
@@ -458,70 +446,86 @@ WebGLContext::ValidateBufferUsageEnum(GL
     default:
         break;
     }
 
     ErrorInvalidEnumInfo(info, target);
     return false;
 }
 
-WebGLRefPtr<WebGLBuffer>*
+WebGLRefPtr<WebGLBuffer>&
 WebGLContext::GetBufferSlotByTarget(GLenum target)
 {
-    /* This function assumes that target has been validated for either WebGL1 or WebGL. */
+    /* This function assumes that target has been validated for either
+     * WebGL1 or WebGL2.
+     */
     switch (target) {
-        case LOCAL_GL_ARRAY_BUFFER:
-            return &mBoundArrayBuffer;
+    case LOCAL_GL_ARRAY_BUFFER:
+        return mBoundArrayBuffer;
+
+    case LOCAL_GL_COPY_READ_BUFFER:
+        return mBoundCopyReadBuffer;
+
+    case LOCAL_GL_COPY_WRITE_BUFFER:
+        return mBoundCopyWriteBuffer;
 
-        case LOCAL_GL_ELEMENT_ARRAY_BUFFER:
-            return &mBoundVertexArray->mElementArrayBuffer;
+    case LOCAL_GL_ELEMENT_ARRAY_BUFFER:
+        return mBoundVertexArray->mElementArrayBuffer;
+
+    case LOCAL_GL_PIXEL_PACK_BUFFER:
+        return mBoundPixelPackBuffer;
+
+    case LOCAL_GL_PIXEL_UNPACK_BUFFER:
+        return mBoundPixelUnpackBuffer;
 
-        case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
-            return &mBoundTransformFeedbackBuffer;
+    case LOCAL_GL_TRANSFORM_FEEDBACK_BUFFER:
+        return mBoundTransformFeedbackBuffer;
 
-        default:
-            return nullptr;
+    case LOCAL_GL_UNIFORM_BUFFER:
+        return mBoundUniformBuffer;
+
+    default:
+        MOZ_CRASH("Should not get here.");
     }
 }
 
-WebGLRefPtr<WebGLBuffer>*
+WebGLRefPtr<WebGLBuffer>&
 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:
         MOZ_ASSERT(index < mGLMaxTransformFeedbackSeparateAttribs);
-        return &mBoundTransformFeedbackBuffers[index];
-    }
+        return mBoundTransformFeedbackBuffers[index];
+    case LOCAL_GL_UNIFORM_BUFFER:
+        MOZ_ASSERT(index < mGLMaxUniformBufferBindings);
+        return mBoundUniformBuffers[index];
 
-    MOZ_CRASH("Should not get here.");
-    return nullptr;
+    default:
+        MOZ_CRASH("Should not get here.");
+    }
 }
 
 GLenum
 WebGLContext::CheckedBufferData(GLenum target, GLsizeiptr size,
                                 const GLvoid* data, GLenum usage)
 {
 #ifdef XP_MACOSX
     // bug 790879
     if (gl->WorkAroundDriverBugs() &&
-        int64_t(size) > INT32_MAX) // the cast avoids a potential always-true warning on 32bit
+        int64_t(size) > INT32_MAX) // cast avoids a potential always-true warning on 32bit
     {
         GenerateWarning("Rejecting valid bufferData call with size %lu to avoid"
                         " a Mac bug", size);
         return LOCAL_GL_INVALID_VALUE;
     }
 #endif
 
-    WebGLBuffer* boundBuffer = nullptr;
-    if (target == LOCAL_GL_ARRAY_BUFFER) {
-        boundBuffer = mBoundArrayBuffer;
-    } else if (target == LOCAL_GL_ELEMENT_ARRAY_BUFFER) {
-        boundBuffer = mBoundVertexArray->mElementArrayBuffer;
-    }
+    WebGLRefPtr<WebGLBuffer>& bufferSlot = GetBufferSlotByTarget(target);
+    WebGLBuffer* boundBuffer = bufferSlot.get();
     MOZ_ASSERT(boundBuffer, "No buffer bound for this target.");
 
     bool sizeChanges = uint32_t(size) != boundBuffer->ByteLength();
     if (sizeChanges) {
         GetAndFlushUnderlyingGLErrors();
         gl->fBufferData(target, size, data, usage);
         GLenum error = GetAndFlushUnderlyingGLErrors();
         return error;
--- a/dom/canvas/WebGLContextGL.cpp
+++ b/dom/canvas/WebGLContextGL.cpp
@@ -1103,20 +1103,18 @@ JS::Value
 WebGLContext::GetBufferParameter(GLenum target, GLenum pname)
 {
     if (IsContextLost())
         return JS::NullValue();
 
     if (!ValidateBufferTarget(target, "getBufferParameter"))
         return JS::NullValue();
 
-    WebGLRefPtr<WebGLBuffer>* slot = GetBufferSlotByTarget(target);
-    MOZ_ASSERT(slot);
-
-    if (!*slot) {
+    WebGLRefPtr<WebGLBuffer>& slot = GetBufferSlotByTarget(target);
+    if (!slot) {
         ErrorInvalidOperation("No buffer bound to `target` (0x%4x).", target);
         return JS::NullValue();
     }
 
     MakeContextCurrent();
 
     switch (pname) {
         case LOCAL_GL_BUFFER_SIZE:
--- a/dom/canvas/WebGLContextUnchecked.cpp
+++ b/dom/canvas/WebGLContextUnchecked.cpp
@@ -2,26 +2,59 @@
 /* vim: set ts=8 sts=4 et sw=4 tw=80: */
 /* 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 "WebGLContextUnchecked.h"
 
 #include "GLContext.h"
+#include "WebGLBuffer.h"
 #include "WebGLSampler.h"
 
 namespace mozilla {
 
 WebGLContextUnchecked::WebGLContextUnchecked(gl::GLContext* gl)
     : gl(gl)
 { }
 
 
 // -----------------------------------------------------------------------------
+// Buffer Objects
+
+void
+WebGLContextUnchecked::BindBuffer(GLenum target, WebGLBuffer* buffer)
+{
+    gl->MakeCurrent();
+    gl->fBindBuffer(target, buffer ? buffer->GLName() : 0);
+}
+
+void
+WebGLContextUnchecked::BindBufferBase(GLenum target, GLuint index, WebGLBuffer* buffer)
+{
+    gl->MakeCurrent();
+    gl->fBindBufferBase(target, index, buffer ? buffer->GLName() : 0);
+}
+
+void
+WebGLContextUnchecked::BindBufferRange(GLenum target, GLuint index, WebGLBuffer* buffer, WebGLintptr offset, WebGLsizeiptr size)
+{
+    gl->MakeCurrent();
+    gl->fBindBufferRange(target, index, buffer ? buffer->GLName() : 0, offset, size);
+}
+
+void
+WebGLContextUnchecked::CopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size)
+{
+    gl->MakeCurrent();
+    gl->fCopyBufferSubData(readTarget, writeTarget, readOffset, writeOffset, size);
+}
+
+
+// -----------------------------------------------------------------------------
 // Sampler Objects
 
 void
 WebGLContextUnchecked::BindSampler(GLuint unit, WebGLSampler* sampler)
 {
     gl->MakeCurrent();
     gl->fBindSampler(unit, sampler ? sampler->GLName() : 0);
     if (sampler)
--- a/dom/canvas/WebGLContextUnchecked.h
+++ b/dom/canvas/WebGLContextUnchecked.h
@@ -3,33 +3,40 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef WEBGLCONTEXTUNCHECKED_H
 #define WEBGLCONTEXTUNCHECKED_H
 
 #include "GLDefs.h"
+#include "nsRefPtr.h"
 #include "WebGLTypes.h"
-#include "nsAutoPtr.h"
-#include "nsTArray.h"
 
 namespace mozilla {
 
+class WebGLBuffer;
 class WebGLSampler;
 namespace gl {
     class GLContext;
 }
 
 class WebGLContextUnchecked
 {
 public:
     explicit WebGLContextUnchecked(gl::GLContext* gl);
 
     // -------------------------------------------------------------------------
+    // Buffer Objects
+    void BindBuffer(GLenum target, WebGLBuffer* buffer);
+    void BindBufferBase(GLenum target, GLuint index, WebGLBuffer* buffer);
+    void BindBufferRange(GLenum taret, GLuint index, WebGLBuffer* buffer, WebGLintptr offset, WebGLsizeiptr size);
+    void CopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
+
+    // -------------------------------------------------------------------------
     // Sampler Objects
     void BindSampler(GLuint unit, WebGLSampler* sampler);
 
     GLint   GetSamplerParameteriv(WebGLSampler* sampler, GLenum pname);
     GLfloat GetSamplerParameterfv(WebGLSampler* sampler, GLenum pname);
 
     void SamplerParameteri(WebGLSampler* sampler, GLenum pname, GLint param);
     void SamplerParameteriv(WebGLSampler* sampler, GLenum pname, const GLint* param);
--- a/dom/canvas/WebGLContextValidate.cpp
+++ b/dom/canvas/WebGLContextValidate.cpp
@@ -223,16 +223,60 @@ WebGLContext::ValidateBlendFuncEnumsComp
                               " the WebGL 1.0 spec", info);
         return false;
     }
 
     return true;
 }
 
 bool
+WebGLContext::ValidateDataOffsetSize(WebGLintptr offset, WebGLsizeiptr size, WebGLsizeiptr bufferSize, const char* info)
+{
+    if (offset < 0) {
+        ErrorInvalidValue("%s: offset must be positive", info);
+        return false;
+    }
+
+    if (size < 0) {
+        ErrorInvalidValue("%s: size must be positive", info);
+        return false;
+    }
+
+    // *** Careful *** WebGLsizeiptr is always 64-bits but GLsizeiptr
+    // is like intptr_t. On some platforms it is 32-bits.
+    CheckedInt<GLsizeiptr> neededBytes = CheckedInt<GLsizeiptr>(offset) + size;
+    if (!neededBytes.isValid() || neededBytes.value() > bufferSize) {
+        ErrorInvalidValue("%s: invalid range", info);
+        return false;
+    }
+
+    return true;
+}
+
+/**
+ * Check data ranges [readOffset, readOffset + size] and [writeOffset,
+ * writeOffset + size] for overlap.
+ *
+ * It is assumed that offset and size have already been validated with
+ * ValidateDataOffsetSize().
+ */
+bool
+WebGLContext::ValidateDataRanges(WebGLintptr readOffset, WebGLintptr writeOffset, WebGLsizeiptr size, const char* info)
+{
+    MOZ_ASSERT((CheckedInt<WebGLsizeiptr>(readOffset) + size).isValid());
+    MOZ_ASSERT((CheckedInt<WebGLsizeiptr>(writeOffset) + size).isValid());
+
+    bool separate = (readOffset + size < writeOffset || writeOffset + size < readOffset);
+    if (!separate)
+        ErrorInvalidValue("%s: ranges [readOffset, readOffset + size) and [writeOffset, writeOffset + size) overlap");
+
+    return separate;
+}
+
+bool
 WebGLContext::ValidateTextureTargetEnum(GLenum target, const char* info)
 {
     switch (target) {
     case LOCAL_GL_TEXTURE_2D:
     case LOCAL_GL_TEXTURE_CUBE_MAP:
         return true;
 
     case LOCAL_GL_TEXTURE_3D:
--- a/dom/canvas/WebGLTransformFeedback.cpp
+++ b/dom/canvas/WebGLTransformFeedback.cpp
@@ -6,25 +6,25 @@
 #include "WebGLTransformFeedback.h"
 
 #include "GLContext.h"
 #include "mozilla/dom/WebGL2RenderingContextBinding.h"
 #include "WebGL2Context.h"
 
 namespace mozilla {
 
-WebGLTransformFeedback::WebGLTransformFeedback(WebGLContext* context,
+WebGLTransformFeedback::WebGLTransformFeedback(WebGLContext* webgl,
                                                GLuint tf)
     : WebGLBindableName<GLenum>(tf)
-    , WebGLContextBoundObject(context)
+    , WebGLContextBoundObject(webgl)
     , mMode(LOCAL_GL_NONE)
     , mIsActive(false)
     , mIsPaused(false)
 {
-    context->mTransformFeedbacks.insertBack(this);
+    mContext->mTransformFeedbacks.insertBack(this);
 }
 
 WebGLTransformFeedback::~WebGLTransformFeedback()
 {
     mMode = LOCAL_GL_NONE;
     mIsActive = false;
     mIsPaused = false;
     DeleteOnce();