Bug 1313541 - Uniform impl. - r=ethlin, a=gchang
authorJeff Gilbert (:jgilbert) <jgilbert@mozilla.com>
Thu, 13 Oct 2016 16:15:16 -0700
changeset 356587 a001d6e786d202d277bae6bac28ffdf9f2e8d7b3
parent 356586 0c0aba7c3d2e51e014003d63dcf793baeb220ff5
child 356588 4c980dc86a395c7534164c5d359b60c3d15e95c6
push id6570
push userraliiev@mozilla.com
push dateMon, 14 Nov 2016 12:26:13 +0000
treeherdermozilla-beta@f455459b2ae5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersethlin, gchang
bugs1313541
milestone51.0a2
Bug 1313541 - Uniform impl. - r=ethlin, a=gchang MozReview-Commit-ID: DN8sUfRR0z7
dom/canvas/WebGL2Context.h
dom/canvas/WebGL2ContextUniforms.cpp
dom/canvas/WebGL2ContextVertices.cpp
dom/canvas/WebGLContext.h
dom/canvas/WebGLContextGL.cpp
--- a/dom/canvas/WebGL2Context.h
+++ b/dom/canvas/WebGL2Context.h
@@ -170,91 +170,39 @@ public:
     // Programs and shaders - WebGL2ContextPrograms.cpp
     GLint GetFragDataLocation(WebGLProgram* program, const nsAString& name);
 
 
     // -------------------------------------------------------------------------
     // Uniforms and attributes - WebGL2ContextUniforms.cpp
     void VertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset);
 
-    // GL 3.0 & ES 3.0
-    void Uniform1ui(WebGLUniformLocation* loc, GLuint v0);
-    void Uniform2ui(WebGLUniformLocation* loc, GLuint v0, GLuint v1);
-    void Uniform3ui(WebGLUniformLocation* loc, GLuint v0, GLuint v1, GLuint v2);
-    void Uniform4ui(WebGLUniformLocation* loc, GLuint v0, GLuint v1, GLuint v2,
-                    GLuint v3);
-
     ////////////////
 
-protected:
-    typedef Arr<GLuint, dom::Uint32Array> UintArr;
-
-    void UniformNuiv(const char* funcName, uint8_t N, WebGLUniformLocation* loc,
-                     const UintArr& arr);
-
-    //////
+    // GL 3.0 & ES 3.0
+    void VertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w);
+    void VertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);
 
-public:
-    template<typename T>
-    void Uniform1uiv(WebGLUniformLocation* loc, const T& arr) {
-        UniformNuiv("uniform1uiv", 1, loc, UintArr(arr));
-    }
-    template<typename T>
-    void Uniform2uiv(WebGLUniformLocation* loc, const T& arr) {
-        UniformNuiv("uniform2uiv", 2, loc, UintArr(arr));
-    }
-    template<typename T>
-    void Uniform3uiv(WebGLUniformLocation* loc, const T& arr) {
-        UniformNuiv("uniform3uiv", 3, loc, UintArr(arr));
-    }
-    template<typename T>
-    void Uniform4uiv(WebGLUniformLocation* loc, const T& arr) {
-        UniformNuiv("uniform4uiv", 4, loc, UintArr(arr));
+    void VertexAttribI4iv(GLuint index, const Int32ListU& list) {
+        const auto& arr = Int32Arr::From(list);
+        if (!ValidateAttribArraySetter("vertexAttribI4iv", 4, arr.elemCount))
+            return;
+
+        const auto& itr = arr.elemBytes;
+        VertexAttribI4i(index, itr[0], itr[1], itr[2], itr[3]);
     }
 
-    //////
+    void VertexAttribI4uiv(GLuint index, const Uint32ListU& list) {
+        const auto& arr = Uint32Arr::From(list);
+        if (!ValidateAttribArraySetter("vertexAttribI4uiv", 4, arr.elemCount))
+            return;
 
-    template<typename T>
-    void UniformMatrix2x3fv(WebGLUniformLocation* loc, bool transpose, const T& arr) {
-        UniformMatrixAxBfv("uniformMatrix2x3fv", 2, 3, loc, transpose, FloatArr(arr));
-    }
-    template<typename T>
-    void UniformMatrix2x4fv(WebGLUniformLocation* loc, bool transpose, const T& arr) {
-        UniformMatrixAxBfv("uniformMatrix2x4fv", 2, 4, loc, transpose, FloatArr(arr));
-    }
-    template<typename T>
-    void UniformMatrix3x2fv(WebGLUniformLocation* loc, bool transpose, const T& arr) {
-        UniformMatrixAxBfv("uniformMatrix3x2fv", 3, 2, loc, transpose, FloatArr(arr));
-    }
-    template<typename T>
-    void UniformMatrix3x4fv(WebGLUniformLocation* loc, bool transpose, const T& arr) {
-        UniformMatrixAxBfv("uniformMatrix3x4fv", 3, 4, loc, transpose, FloatArr(arr));
+        const auto& itr = arr.elemBytes;
+        VertexAttribI4ui(index, itr[0], itr[1], itr[2], itr[3]);
     }
-    template<typename T>
-    void UniformMatrix4x2fv(WebGLUniformLocation* loc, bool transpose, const T& arr) {
-        UniformMatrixAxBfv("uniformMatrix4x2fv", 4, 2, loc, transpose, FloatArr(arr));
-    }
-    template<typename T>
-    void UniformMatrix4x3fv(WebGLUniformLocation* loc, bool transpose, const T& arr) {
-        UniformMatrixAxBfv("uniformMatrix4x3fv", 4, 3, loc, transpose, FloatArr(arr));
-    }
-
-    ////////////////
-
-private:
-    void VertexAttribI4iv(GLuint index, size_t length, const GLint* v);
-    void VertexAttribI4uiv(GLuint index, size_t length, const GLuint* v);
-
-public:
-    // GL 3.0 & ES 3.0
-    void VertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w);
-    void VertexAttribI4iv(GLuint index, const dom::Sequence<GLint>& v);
-    void VertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);
-    void VertexAttribI4uiv(GLuint index, const dom::Sequence<GLuint>& v);
-
 
     // -------------------------------------------------------------------------
     // Writing to the drawing buffer
 
     /* Implemented in WebGLContext
     void VertexAttribDivisor(GLuint index, GLuint divisor);
     void DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount);
     void DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, GLintptr offset, GLsizei instanceCount);
--- a/dom/canvas/WebGL2ContextUniforms.cpp
+++ b/dom/canvas/WebGL2ContextUniforms.cpp
@@ -22,57 +22,56 @@ WebGL2Context::ValidateUniformMatrixTran
 {
     return true;
 }
 
 // -------------------------------------------------------------------------
 // Uniforms
 
 void
-WebGL2Context::Uniform1ui(WebGLUniformLocation* loc, GLuint v0)
+WebGLContext::Uniform1ui(WebGLUniformLocation* loc, GLuint v0)
 {
     if (!ValidateUniformSetter(loc, 1, LOCAL_GL_UNSIGNED_INT, "uniform1ui"))
         return;
 
     MakeContextCurrent();
     gl->fUniform1ui(loc->mLoc, v0);
 }
 
 void
-WebGL2Context::Uniform2ui(WebGLUniformLocation* loc, GLuint v0, GLuint v1)
+WebGLContext::Uniform2ui(WebGLUniformLocation* loc, GLuint v0, GLuint v1)
 {
     if (!ValidateUniformSetter(loc, 2, LOCAL_GL_UNSIGNED_INT, "uniform2ui"))
         return;
 
     MakeContextCurrent();
     gl->fUniform2ui(loc->mLoc, v0, v1);
 }
 
 void
-WebGL2Context::Uniform3ui(WebGLUniformLocation* loc, GLuint v0, GLuint v1, GLuint v2)
+WebGLContext::Uniform3ui(WebGLUniformLocation* loc, GLuint v0, GLuint v1, GLuint v2)
 {
     if (!ValidateUniformSetter(loc, 3, LOCAL_GL_UNSIGNED_INT, "uniform3ui"))
         return;
 
     MakeContextCurrent();
     gl->fUniform3ui(loc->mLoc, v0, v1, v2);
 }
 
 void
-WebGL2Context::Uniform4ui(WebGLUniformLocation* loc, GLuint v0, GLuint v1, GLuint v2,
-                          GLuint v3)
+WebGLContext::Uniform4ui(WebGLUniformLocation* loc, GLuint v0, GLuint v1, GLuint v2,
+                         GLuint v3)
 {
     if (!ValidateUniformSetter(loc, 4, LOCAL_GL_UNSIGNED_INT, "uniform4ui"))
         return;
 
     MakeContextCurrent();
     gl->fUniform4ui(loc->mLoc, v0, v1, v2, v3);
 }
 
-
 // -------------------------------------------------------------------------
 // Uniform Buffer Objects and Transform Feedback Buffers
 
 void
 WebGL2Context::GetIndexedParameter(GLenum target, GLuint index,
                                    dom::Nullable<dom::OwningWebGLBufferOrLongLong>& retval)
 {
     const char funcName[] = "getIndexedParameter";
--- a/dom/canvas/WebGL2ContextVertices.cpp
+++ b/dom/canvas/WebGL2ContextVertices.cpp
@@ -112,48 +112,16 @@ WebGL2Context::VertexAttribI4i(GLuint in
     mVertexAttrib0Vector[3] = BitwiseCast<GLfloat>(w);
     if (gl->IsGLES()) {
       gl->fVertexAttribI4i(index, x, y, z, w);
     }
   }
 }
 
 void
-WebGL2Context::VertexAttribI4iv(GLuint index, size_t length, const GLint* v)
-{
-  if (!ValidateAttribArraySetter("vertexAttribI4iv", 4, length))
-    return;
-
-  if (!ValidateAttribIndex(index, "vertexAttribI4iv"))
-    return;
-
-  mVertexAttribType[index] = LOCAL_GL_INT;
-
-  MakeContextCurrent();
-
-  if (index) {
-    gl->fVertexAttribI4iv(index, v);
-  } else {
-    mVertexAttrib0Vector[0] = BitwiseCast<GLfloat>(v[0]);
-    mVertexAttrib0Vector[1] = BitwiseCast<GLfloat>(v[1]);
-    mVertexAttrib0Vector[2] = BitwiseCast<GLfloat>(v[2]);
-    mVertexAttrib0Vector[3] = BitwiseCast<GLfloat>(v[3]);
-    if (gl->IsGLES()) {
-      gl->fVertexAttribI4iv(index, v);
-    }
-  }
-}
-
-void
-WebGL2Context::VertexAttribI4iv(GLuint index, const dom::Sequence<GLint>& v)
-{
-  VertexAttribI4iv(index, v.Length(), v.Elements());
-}
-
-void
 WebGL2Context::VertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w)
 {
   if (IsContextLost())
     return;
 
   if (!ValidateAttribIndex(index, "vertexAttribI4ui"))
     return;
 
@@ -169,44 +137,9 @@ WebGL2Context::VertexAttribI4ui(GLuint i
     mVertexAttrib0Vector[2] = BitwiseCast<GLfloat>(z);
     mVertexAttrib0Vector[3] = BitwiseCast<GLfloat>(w);
     if (gl->IsGLES()) {
       gl->fVertexAttribI4ui(index, x, y, z, w);
     }
   }
 }
 
-void
-WebGL2Context::VertexAttribI4uiv(GLuint index, size_t length, const GLuint* v)
-{
-  if (IsContextLost())
-    return;
-
-  if (!ValidateAttribArraySetter("vertexAttribI4uiv", 4, length))
-    return;
-
-  if (!ValidateAttribIndex(index, "vertexAttribI4uiv"))
-    return;
-
-  mVertexAttribType[index] = LOCAL_GL_UNSIGNED_INT;
-
-  MakeContextCurrent();
-
-  if (index) {
-    gl->fVertexAttribI4uiv(index, v);
-  } else {
-    mVertexAttrib0Vector[0] = BitwiseCast<GLfloat>(v[0]);
-    mVertexAttrib0Vector[1] = BitwiseCast<GLfloat>(v[1]);
-    mVertexAttrib0Vector[2] = BitwiseCast<GLfloat>(v[2]);
-    mVertexAttrib0Vector[3] = BitwiseCast<GLfloat>(v[3]);
-    if (gl->IsGLES()) {
-      gl->fVertexAttribI4uiv(index, v);
-    }
-  }
-}
-
-void
-WebGL2Context::VertexAttribI4uiv(GLuint index, const dom::Sequence<GLuint>& v)
-{
-  VertexAttribI4uiv(index, v.Length(), v.Elements());
-}
-
 } // namespace mozilla
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -43,16 +43,18 @@
 // Generated
 #include "nsIDOMEventListener.h"
 #include "nsIDOMWebGLRenderingContext.h"
 #include "nsICanvasRenderingContextInternal.h"
 #include "nsIObserver.h"
 #include "mozilla/dom/HTMLCanvasElement.h"
 #include "nsWrapperCache.h"
 #include "nsLayoutUtils.h"
+#include "mozilla/dom/WebGLRenderingContextBinding.h"
+#include "mozilla/dom/WebGL2RenderingContextBinding.h"
 
 class nsIDocShell;
 
 /*
  * Minimum value constants defined in 6.2 State Tables of OpenGL ES - 2.0.25
  *   https://bugzilla.mozilla.org/show_bug.cgi?id=686732
  *
  * Exceptions: some of the following values are set to higher values than in the spec because
@@ -610,114 +612,184 @@ public:
     void StencilMask(GLuint mask);
     void StencilMaskSeparate(GLenum face, GLuint mask);
     void StencilOp(GLenum sfail, GLenum dpfail, GLenum dppass);
     void StencilOpSeparate(GLenum face, GLenum sfail, GLenum dpfail,
                            GLenum dppass);
 
     //////
 
-    void Uniform1i(WebGLUniformLocation* loc, GLint x);
-    void Uniform2i(WebGLUniformLocation* loc, GLint x, GLint y);
-    void Uniform3i(WebGLUniformLocation* loc, GLint x, GLint y, GLint z);
-    void Uniform4i(WebGLUniformLocation* loc, GLint x, GLint y, GLint z, GLint w);
-
     void Uniform1f(WebGLUniformLocation* loc, GLfloat x);
     void Uniform2f(WebGLUniformLocation* loc, GLfloat x, GLfloat y);
     void Uniform3f(WebGLUniformLocation* loc, GLfloat x, GLfloat y, GLfloat z);
     void Uniform4f(WebGLUniformLocation* loc, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
 
+    void Uniform1i(WebGLUniformLocation* loc, GLint x);
+    void Uniform2i(WebGLUniformLocation* loc, GLint x, GLint y);
+    void Uniform3i(WebGLUniformLocation* loc, GLint x, GLint y, GLint z);
+    void Uniform4i(WebGLUniformLocation* loc, GLint x, GLint y, GLint z, GLint w);
+
+    void Uniform1ui(WebGLUniformLocation* loc, GLuint v0);
+    void Uniform2ui(WebGLUniformLocation* loc, GLuint v0, GLuint v1);
+    void Uniform3ui(WebGLUniformLocation* loc, GLuint v0, GLuint v1, GLuint v2);
+    void Uniform4ui(WebGLUniformLocation* loc, GLuint v0, GLuint v1, GLuint v2,
+                    GLuint v3);
+
     //////////////////////////
 
+    typedef dom::Float32ArrayOrUnrestrictedFloatSequence Float32ListU;
+    typedef dom::Int32ArrayOrLongSequence Int32ListU;
+    typedef dom::Uint32ArrayOrUnsignedLongSequence Uint32ListU;
+
 protected:
-    template<typename elemT, typename arrT>
+    template<typename elemT, typename viewT>
     struct Arr {
-        size_t dataCount;
-        const elemT* data;
+        const size_t elemCount;
+        const elemT* const elemBytes;
 
-        explicit Arr(const arrT& arr) {
-            arr.ComputeLengthAndData();
-            dataCount = arr.LengthAllowShared();
-            data = arr.DataAllowShared();
+    private:
+        static size_t ComputeAndReturnLength(const viewT& view) {
+            view.ComputeLengthAndData();
+            return view.LengthAllowShared();
         }
 
-        explicit Arr(const dom::Sequence<elemT>& arr) {
-            dataCount = arr.Length();
-            data = arr.Elements();
+    public:
+        explicit Arr(const viewT& view)
+            : elemCount(ComputeAndReturnLength(view))
+            , elemBytes(view.DataAllowShared())
+        { }
+
+        explicit Arr(const dom::Sequence<elemT>& seq)
+            : elemCount(seq.Length())
+            , elemBytes(seq.Elements())
+        { }
+
+        Arr(size_t _elemCount, const elemT* _elemBytes)
+            : elemCount(_elemCount)
+            , elemBytes(_elemBytes)
+        { }
+
+        ////
+
+        static Arr From(const Float32ListU& list) {
+            if (list.IsFloat32Array())
+                return Arr(list.GetAsFloat32Array());
+
+            return Arr(list.GetAsUnrestrictedFloatSequence());
+        }
+
+        static Arr From(const Int32ListU& list) {
+            if (list.IsInt32Array())
+                return Arr(list.GetAsInt32Array());
+
+            return Arr(list.GetAsLongSequence());
+        }
+
+        static Arr From(const Uint32ListU& list) {
+            if (list.IsUint32Array())
+                return Arr(list.GetAsUint32Array());
+
+            return Arr(list.GetAsUnsignedLongSequence());
         }
     };
 
-    typedef Arr<GLint, dom::Int32Array> IntArr;
-    typedef Arr<GLfloat, dom::Float32Array> FloatArr;
+    typedef Arr<GLfloat, dom::Float32Array> Float32Arr;
+    typedef Arr<GLint, dom::Int32Array> Int32Arr;
+    typedef Arr<GLuint, dom::Uint32Array> Uint32Arr;
 
     ////////////////
 
+    void UniformNfv(const char* funcName, uint8_t N, WebGLUniformLocation* loc,
+                    const Float32Arr& arr, GLuint elemOffset, GLuint elemCountOverride);
     void UniformNiv(const char* funcName, uint8_t N, WebGLUniformLocation* loc,
-                    const IntArr& arr);
-
-    void UniformNfv(const char* funcName, uint8_t N, WebGLUniformLocation* loc,
-                    const FloatArr& arr);
+                    const Int32Arr& arr, GLuint elemOffset, GLuint elemCountOverride);
+    void UniformNuiv(const char* funcName, uint8_t N, WebGLUniformLocation* loc,
+                     const Uint32Arr& arr, GLuint elemOffset, GLuint elemCountOverride);
 
     void UniformMatrixAxBfv(const char* funcName, uint8_t A, uint8_t B,
                             WebGLUniformLocation* loc, bool transpose,
-                            const FloatArr& arr);
+                            const Float32Arr& arr, GLuint elemOffset,
+                            GLuint elemCountOverride);
 
     ////////////////
 
 public:
-    template<typename T>
-    void Uniform1iv(WebGLUniformLocation* loc, const T& arr) {
-        UniformNiv("uniform1iv", 1, loc, IntArr(arr));
-    }
-    template<typename T>
-    void Uniform2iv(WebGLUniformLocation* loc, const T& arr) {
-        UniformNiv("uniform2iv", 2, loc, IntArr(arr));
-    }
-    template<typename T>
-    void Uniform3iv(WebGLUniformLocation* loc, const T& arr) {
-        UniformNiv("uniform3iv", 3, loc, IntArr(arr));
-    }
-    template<typename T>
-    void Uniform4iv(WebGLUniformLocation* loc, const T& arr) {
-        UniformNiv("uniform4iv", 4, loc, IntArr(arr));
-    }
+    #define FOO(N) \
+        void Uniform ## N ## fv(WebGLUniformLocation* loc, const Float32ListU& list,  \
+                                GLuint elemOffset = 0, GLuint elemCountOverride = 0)  \
+        {                                                                             \
+            UniformNfv("uniform" #N "fv", N, loc, Float32Arr::From(list), elemOffset, \
+                       elemCountOverride);                                            \
+        }
+
+    FOO(1)
+    FOO(2)
+    FOO(3)
+    FOO(4)
+
+    #undef FOO
+
+    //////
+
+    #define FOO(N) \
+        void Uniform ## N ## iv(WebGLUniformLocation* loc, const Int32ListU& list,   \
+                                GLuint elemOffset = 0, GLuint elemCountOverride = 0) \
+        {                                                                            \
+            UniformNiv("uniform" #N "iv", N, loc, Int32Arr::From(list), elemOffset,  \
+                       elemCountOverride);                                           \
+        }
+
+    FOO(1)
+    FOO(2)
+    FOO(3)
+    FOO(4)
+
+    #undef FOO
 
     //////
 
-    template<typename T>
-    void Uniform1fv(WebGLUniformLocation* loc, const T& arr) {
-        UniformNfv("uniform1fv", 1, loc, FloatArr(arr));
-    }
-    template<typename T>
-    void Uniform2fv(WebGLUniformLocation* loc, const T& arr) {
-        UniformNfv("uniform2fv", 2, loc, FloatArr(arr));
-    }
-    template<typename T>
-    void Uniform3fv(WebGLUniformLocation* loc, const T& arr) {
-        UniformNfv("uniform3fv", 3, loc, FloatArr(arr));
-    }
-    template<typename T>
-    void Uniform4fv(WebGLUniformLocation* loc, const T& arr) {
-        UniformNfv("uniform4fv", 4, loc, FloatArr(arr));
-    }
+    #define FOO(N) \
+        void Uniform ## N ## uiv(WebGLUniformLocation* loc, const Uint32ListU& list,   \
+                                 GLuint elemOffset = 0, GLuint elemCountOverride = 0)  \
+        {                                                                              \
+            UniformNuiv("uniform" #N "uiv", N, loc, Uint32Arr::From(list), elemOffset, \
+                        elemCountOverride);                                            \
+        }
+
+    FOO(1)
+    FOO(2)
+    FOO(3)
+    FOO(4)
+
+    #undef FOO
 
     //////
 
-    template<typename T>
-    void UniformMatrix2fv(WebGLUniformLocation* loc, bool transpose, const T& arr) {
-        UniformMatrixAxBfv("uniformMatrix2fv", 2, 2, loc, transpose, FloatArr(arr));
-    }
-    template<typename T>
-    void UniformMatrix3fv(WebGLUniformLocation* loc, bool transpose, const T& arr) {
-        UniformMatrixAxBfv("uniformMatrix3fv", 3, 3, loc, transpose, FloatArr(arr));
-    }
-    template<typename T>
-    void UniformMatrix4fv(WebGLUniformLocation* loc, bool transpose, const T& arr) {
-        UniformMatrixAxBfv("uniformMatrix4fv", 4, 4, loc, transpose, FloatArr(arr));
-    }
+    #define FOO(X,A,B) \
+        void UniformMatrix ## X ## fv(WebGLUniformLocation* loc, bool transpose,       \
+                                      const Float32ListU& list, GLuint elemOffset = 0, \
+                                      GLuint elemCountOverride = 0)                    \
+        {                                                                              \
+            UniformMatrixAxBfv("uniformMatrix" #X "fv", A, B, loc, transpose,          \
+                               Float32Arr::From(list), elemOffset, elemCountOverride); \
+        }
+
+    FOO(2,2,2)
+    FOO(2x3,2,3)
+    FOO(2x4,2,4)
+
+    FOO(3x2,3,2)
+    FOO(3,3,3)
+    FOO(3x4,3,4)
+
+    FOO(4x2,4,2)
+    FOO(4x3,4,3)
+    FOO(4,4,4)
+
+    #undef FOO
 
     ////////////////////////////////////
 
     void UseProgram(WebGLProgram* prog);
 
     bool ValidateAttribArraySetter(const char* name, uint32_t count,
                                    uint32_t arrayLength);
     bool ValidateUniformLocation(WebGLUniformLocation* loc, const char* funcName);
--- a/dom/canvas/WebGLContextGL.cpp
+++ b/dom/canvas/WebGLContextGL.cpp
@@ -2018,100 +2018,158 @@ WebGLContext::Uniform4f(WebGLUniformLoca
 
     MakeContextCurrent();
     gl->fUniform4f(loc->mLoc, a1, a2, a3, a4);
 }
 
 ////////////////////////////////////////
 // Array
 
+static bool
+ValidateArrOffsetAndCount(WebGLContext* webgl, const char* funcName, size_t elemsAvail,
+                          GLuint elemOffset, GLuint elemCountOverride,
+                          size_t* const out_elemCount)
+{
+    if (elemOffset > elemsAvail) {
+        webgl->ErrorInvalidValue("%s: Bad offset into list.", funcName);
+        return false;
+    }
+    elemsAvail -= elemOffset;
+
+    if (elemCountOverride) {
+        if (elemCountOverride > elemsAvail) {
+            webgl->ErrorInvalidValue("%s: Bad count override for sub-list.", funcName);
+            return false;
+        }
+        elemsAvail = elemCountOverride;
+    }
+
+    *out_elemCount = elemsAvail;
+    return true;
+}
+
 void
 WebGLContext::UniformNiv(const char* funcName, uint8_t N, WebGLUniformLocation* loc,
-                         const IntArr& arr)
+                         const Int32Arr& arr, GLuint elemOffset, GLuint elemCountOverride)
 {
+    size_t elemCount;
+    if (!ValidateArrOffsetAndCount(this, funcName, arr.elemCount, elemOffset,
+                                   elemCountOverride, &elemCount))
+    {
+        return;
+    }
+    const auto elemBytes = arr.elemBytes + elemOffset;
+
     uint32_t numElementsToUpload;
-    if (!ValidateUniformArraySetter(loc, N, LOCAL_GL_INT, arr.dataCount, funcName,
+    if (!ValidateUniformArraySetter(loc, N, LOCAL_GL_INT, elemCount, funcName,
                                     &numElementsToUpload))
     {
         return;
     }
 
     bool error;
     const ValidateIfSampler samplerValidator(this, funcName, loc, numElementsToUpload,
-                                             arr.data, &error);
+                                             elemBytes, &error);
     if (error)
         return;
 
     static const decltype(&gl::GLContext::fUniform1iv) kFuncList[] = {
         &gl::GLContext::fUniform1iv,
         &gl::GLContext::fUniform2iv,
         &gl::GLContext::fUniform3iv,
         &gl::GLContext::fUniform4iv
     };
     const auto func = kFuncList[N-1];
 
     MakeContextCurrent();
-    (gl->*func)(loc->mLoc, numElementsToUpload, arr.data);
+    (gl->*func)(loc->mLoc, numElementsToUpload, elemBytes);
 }
 
 void
-WebGL2Context::UniformNuiv(const char* funcName, uint8_t N, WebGLUniformLocation* loc,
-                           const UintArr& arr)
+WebGLContext::UniformNuiv(const char* funcName, uint8_t N, WebGLUniformLocation* loc,
+                          const Uint32Arr& arr, GLuint elemOffset,
+                          GLuint elemCountOverride)
 {
+    size_t elemCount;
+    if (!ValidateArrOffsetAndCount(this, funcName, arr.elemCount, elemOffset,
+                                   elemCountOverride, &elemCount))
+    {
+        return;
+    }
+    const auto elemBytes = arr.elemBytes + elemOffset;
+
     uint32_t numElementsToUpload;
-    if (!ValidateUniformArraySetter(loc, N, LOCAL_GL_UNSIGNED_INT, arr.dataCount,
-                                    funcName, &numElementsToUpload))
+    if (!ValidateUniformArraySetter(loc, N, LOCAL_GL_UNSIGNED_INT, elemCount, funcName,
+                                    &numElementsToUpload))
     {
         return;
     }
     MOZ_ASSERT(!loc->mInfo->mSamplerTexList, "Should not be a sampler.");
 
     static const decltype(&gl::GLContext::fUniform1uiv) kFuncList[] = {
         &gl::GLContext::fUniform1uiv,
         &gl::GLContext::fUniform2uiv,
         &gl::GLContext::fUniform3uiv,
         &gl::GLContext::fUniform4uiv
     };
     const auto func = kFuncList[N-1];
 
     MakeContextCurrent();
-    (gl->*func)(loc->mLoc, numElementsToUpload, arr.data);
+    (gl->*func)(loc->mLoc, numElementsToUpload, elemBytes);
 }
 
 void
 WebGLContext::UniformNfv(const char* funcName, uint8_t N, WebGLUniformLocation* loc,
-                         const FloatArr& arr)
+                         const Float32Arr& arr, GLuint elemOffset,
+                         GLuint elemCountOverride)
 {
+    size_t elemCount;
+    if (!ValidateArrOffsetAndCount(this, funcName, arr.elemCount, elemOffset,
+                                   elemCountOverride, &elemCount))
+    {
+        return;
+    }
+    const auto elemBytes = arr.elemBytes + elemOffset;
+
     uint32_t numElementsToUpload;
-    if (!ValidateUniformArraySetter(loc, N, LOCAL_GL_FLOAT, arr.dataCount, funcName,
+    if (!ValidateUniformArraySetter(loc, N, LOCAL_GL_FLOAT, elemCount, funcName,
                                     &numElementsToUpload))
     {
         return;
     }
     MOZ_ASSERT(!loc->mInfo->mSamplerTexList, "Should not be a sampler.");
 
     static const decltype(&gl::GLContext::fUniform1fv) kFuncList[] = {
         &gl::GLContext::fUniform1fv,
         &gl::GLContext::fUniform2fv,
         &gl::GLContext::fUniform3fv,
         &gl::GLContext::fUniform4fv
     };
     const auto func = kFuncList[N-1];
 
     MakeContextCurrent();
-    (gl->*func)(loc->mLoc, numElementsToUpload, arr.data);
+    (gl->*func)(loc->mLoc, numElementsToUpload, elemBytes);
 }
 
 void
 WebGLContext::UniformMatrixAxBfv(const char* funcName, uint8_t A, uint8_t B,
                                  WebGLUniformLocation* loc, bool transpose,
-                                 const FloatArr& arr)
+                                 const Float32Arr& arr, GLuint elemOffset,
+                                 GLuint elemCountOverride)
 {
+    size_t elemCount;
+    if (!ValidateArrOffsetAndCount(this, funcName, arr.elemCount, elemOffset,
+                                   elemCountOverride, &elemCount))
+    {
+        return;
+    }
+    const auto elemBytes = arr.elemBytes + elemOffset;
+
     uint32_t numElementsToUpload;
-    if (!ValidateUniformMatrixArraySetter(loc, A, B, LOCAL_GL_FLOAT, arr.dataCount,
+    if (!ValidateUniformMatrixArraySetter(loc, A, B, LOCAL_GL_FLOAT, elemCount,
                                           transpose, funcName, &numElementsToUpload))
     {
         return;
     }
     MOZ_ASSERT(!loc->mInfo->mSamplerTexList, "Should not be a sampler.");
 
     static const decltype(&gl::GLContext::fUniformMatrix2fv) kFuncList[] = {
         &gl::GLContext::fUniformMatrix2fv,
@@ -2124,17 +2182,17 @@ WebGLContext::UniformMatrixAxBfv(const c
 
         &gl::GLContext::fUniformMatrix4x2fv,
         &gl::GLContext::fUniformMatrix4x3fv,
         &gl::GLContext::fUniformMatrix4fv
     };
     const auto func = kFuncList[3*(A-2) + (B-2)];
 
     MakeContextCurrent();
-    (gl->*func)(loc->mLoc, numElementsToUpload, false, arr.data);
+    (gl->*func)(loc->mLoc, numElementsToUpload, false, elemBytes);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 
 void
 WebGLContext::UseProgram(WebGLProgram* prog)
 {
     if (IsContextLost())