Bug 745840 - Rework WebGL uniform/attrib setters, remove the huge macros - r=bjacob
authorSaurabh Anand <saurabhanandiit@gmail.com>
Tue, 16 Oct 2012 17:47:01 +0530
changeset 110422 8ce5daee047019b2d579cfaad61e150e09611045
parent 110421 8cbc15e874a2a487b723699e0b2e552badc6e8e8
child 110423 e21bd5ae8cb26812a0808f3187757270266fd39c
push id23688
push userryanvm@gmail.com
push dateWed, 17 Oct 2012 01:52:19 +0000
treeherdermozilla-central@dac5700acf8b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbjacob
bugs745840
milestone19.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 745840 - Rework WebGL uniform/attrib setters, remove the huge macros - r=bjacob
content/canvas/src/WebGLContext.h
content/canvas/src/WebGLContextGL.cpp
content/canvas/src/WebGLContextValidate.cpp
--- a/content/canvas/src/WebGLContext.h
+++ b/content/canvas/src/WebGLContext.h
@@ -1036,17 +1036,25 @@ public:
         UniformMatrix4fv_base(location, transpose, value.Length(),
                               value.Elements());
     }
     void UniformMatrix4fv_base(WebGLUniformLocation* location,
                                WebGLboolean transpose, uint32_t arrayLength,
                                const float* data);
 
     void UseProgram(WebGLProgram *prog);
+    bool ValidateAttribArraySetter(const char* name, uint32_t cnt, uint32_t arrayLength);
+    bool ValidateUniformArraySetter(const char* name, uint32_t expectedElemSize, WebGLUniformLocation *location_object,
+                                    GLint& location, uint32_t& numElementsToUpload, uint32_t arrayLength);
+    bool ValidateUniformMatrixArraySetter(const char* name, int dim, WebGLUniformLocation *location_object,
+                                          GLint& location, uint32_t& numElementsToUpload, uint32_t arrayLength,
+                                          WebGLboolean aTranspose);
+    bool ValidateUniformSetter(const char* name, WebGLUniformLocation *location_object, GLint& location);
     void ValidateProgram(WebGLProgram *prog);
+    bool ValidateUniformLocation(const char* info, WebGLUniformLocation *location_object);
 
     void VertexAttrib1f(WebGLuint index, WebGLfloat x0);
     void VertexAttrib2f(WebGLuint index, WebGLfloat x0, WebGLfloat x1);
     void VertexAttrib3f(WebGLuint index, WebGLfloat x0, WebGLfloat x1,
                         WebGLfloat x2);
     void VertexAttrib4f(WebGLuint index, WebGLfloat x0, WebGLfloat x1,
                         WebGLfloat x2, WebGLfloat x3);
 
--- a/content/canvas/src/WebGLContextGL.cpp
+++ b/content/canvas/src/WebGLContextGL.cpp
@@ -3605,180 +3605,259 @@ WebGLContext::SurfaceFromElementResultTo
         default:
             NS_ASSERTION(false, "Unsupported image format. Unimplemented.");
             return NS_ERROR_NOT_IMPLEMENTED;
     }
 
     return NS_OK;
 }
 
-#define OBTAIN_UNIFORM_LOCATION(info)                                   \
-    if (!ValidateObjectAllowNull(info, location_object))                \
-        return;                                                         \
-    if (!location_object)                                               \
-        return;                                                         \
-    /* the need to check specifically for !mCurrentProgram here is explained in bug 657556 */ \
-    if (!mCurrentProgram) \
-        return ErrorInvalidOperation("%s: no program is currently bound", info); \
-    if (mCurrentProgram != location_object->Program()) \
-        return ErrorInvalidOperation("%s: this uniform location doesn't correspond to the current program", info); \
-    if (mCurrentProgram->Generation() != location_object->ProgramGeneration())            \
-        return ErrorInvalidOperation("%s: This uniform location is obsolete since the program has been relinked", info); \
-    GLint location = location_object->Location();
-
-#define SIMPLE_ARRAY_METHOD_UNIFORM(name, expectedElemSize, arrayType, ptrType) \
-void                                                                            \
-WebGLContext::name##_base(WebGLUniformLocation *location_object,                \
-                        uint32_t arrayLength, const ptrType* data) {            \
-    if (!IsContextStable()) {                                                   \
-        return;                                                                 \
-    }                                                                           \
-                                                                                \
-    OBTAIN_UNIFORM_LOCATION(#name ": location")                                 \
-    int uniformElemSize = location_object->ElementSize();                       \
-    if (expectedElemSize != uniformElemSize) {                                  \
-        return ErrorInvalidOperation(                                           \
-            #name ": this function expected a uniform of element size %d,"      \
-            " got a uniform of element size %d",                                \
-            expectedElemSize,                                                   \
-            uniformElemSize);                                                   \
-    }                                                                           \
-    const WebGLUniformInfo& info = location_object->Info();                     \
-    if (arrayLength == 0 ||                                                     \
-        arrayLength % expectedElemSize)                                         \
-    {                                                                           \
-        return ErrorInvalidValue("%s: expected an array of length a multiple"   \
-                                 " of %d, got an array of length %d",           \
-                                 #name,                                         \
-                                 expectedElemSize,                              \
-                                 arrayLength);                                  \
-    }                                                                           \
-    if (!info.isArray &&                                                        \
-        arrayLength != expectedElemSize) {                                      \
-        return ErrorInvalidOperation("%s: expected an array of length exactly"  \
-                                     " %d (since this uniform is not an array"  \
-                                     " uniform), got an array of length %d",    \
-                                     #name,                                     \
-                                     expectedElemSize,                          \
-                                     arrayLength);                              \
-    }                                                                           \
-                                                                                \
-    uint32_t numElementsToUpload =                                              \
-        NS_MIN(info.arraySize, arrayLength / expectedElemSize);                 \
-    MakeContextCurrent();                                                       \
-    gl->f##name(location, numElementsToUpload, data);                           \
+
+void
+WebGLContext::Uniform1i(WebGLUniformLocation *location_object, WebGLint a1)
+{
+    GLint location;
+    if (!ValidateUniformSetter("Uniform1i", location_object, location))
+        return;
+    MakeContextCurrent();
+    gl->fUniform1i(location, a1);
+}
+
+void
+WebGLContext::Uniform2i(WebGLUniformLocation *location_object, WebGLint a1,
+                        WebGLint a2)
+{
+    GLint location;
+    if (!ValidateUniformSetter("Uniform2i", location_object, location))
+        return;
+    MakeContextCurrent();
+    gl->fUniform2i(location, a1, a2);
+}
+
+void
+WebGLContext::Uniform3i(WebGLUniformLocation *location_object, WebGLint a1,
+                        WebGLint a2, WebGLint a3)
+{
+    GLint location;
+    if (!ValidateUniformSetter("Uniform3i", location_object, location))
+        return;
+    MakeContextCurrent();
+    gl->fUniform3i(location, a1, a2, a3);
+}
+
+void
+WebGLContext::Uniform4i(WebGLUniformLocation *location_object, WebGLint a1,
+                        WebGLint a2, WebGLint a3, WebGLint a4)
+{
+    GLint location;
+    if (!ValidateUniformSetter("Uniform4i", location_object, location))
+        return;
+    MakeContextCurrent();
+    gl->fUniform4i(location, a1, a2, a3, a4);
+}
+
+void
+WebGLContext::Uniform1f(WebGLUniformLocation *location_object, WebGLfloat a1)
+{
+    GLint location;
+    if (!ValidateUniformSetter("Uniform1f", location_object, location))
+        return;
+    MakeContextCurrent();
+    gl->fUniform1f(location, a1);
+}
+
+void
+WebGLContext::Uniform2f(WebGLUniformLocation *location_object, WebGLfloat a1,
+                        WebGLfloat a2)
+{
+    GLint location;
+    if (!ValidateUniformSetter("Uniform2f", location_object, location))
+        return;
+    MakeContextCurrent();
+    gl->fUniform2f(location, a1, a2);
+}
+
+void
+WebGLContext::Uniform3f(WebGLUniformLocation *location_object, WebGLfloat a1,
+                        WebGLfloat a2, WebGLfloat a3)
+{
+    GLint location;
+    if (!ValidateUniformSetter("Uniform3f", location_object, location))
+        return;
+    MakeContextCurrent();
+    gl->fUniform3f(location, a1, a2, a3);
+}
+
+void
+WebGLContext::Uniform4f(WebGLUniformLocation *location_object, WebGLfloat a1,
+                        WebGLfloat a2, WebGLfloat a3, WebGLfloat a4)
+{
+    GLint location;
+    if (!ValidateUniformSetter("Uniform4f", location_object, location))
+        return;
+    MakeContextCurrent();
+    gl->fUniform4f(location, a1, a2, a3, a4);
+}
+
+void
+WebGLContext::Uniform1iv_base(WebGLUniformLocation *location_object,
+                              uint32_t arrayLength, const WebGLint* data)
+{
+    uint32_t numElementsToUpload;
+    GLint location;
+    if (!ValidateUniformArraySetter("Uniform1iv", 1, location_object, location,
+                                    numElementsToUpload, arrayLength)) {
+        return;
+    }
+    MakeContextCurrent();
+    gl->fUniform1iv(location, numElementsToUpload, data);
+}
+
+void
+WebGLContext::Uniform2iv_base(WebGLUniformLocation *location_object,
+                              uint32_t arrayLength, const WebGLint* data)
+{
+    uint32_t numElementsToUpload;
+    GLint location;
+    if (!ValidateUniformArraySetter("Uniform2iv", 2, location_object, location,
+                                    numElementsToUpload, arrayLength)) {
+        return;
+    }
+    MakeContextCurrent();
+    gl->fUniform2iv(location, numElementsToUpload, data);
 }
 
-#define SIMPLE_MATRIX_METHOD_UNIFORM(name, dim)                                 \
-void                                                                            \
-WebGLContext::name##_base(WebGLUniformLocation* location_object,                \
-                          WebGLboolean aTranspose, uint32_t arrayLength,        \
-                          const float* data)                                    \
-{                                                                               \
-    uint32_t expectedElemSize = (dim)*(dim);                                    \
-    if (!IsContextStable()) {                                                   \
-        return;                                                                 \
-    }                                                                           \
-                                                                                \
-    OBTAIN_UNIFORM_LOCATION(#name ": location")                                 \
-    uint32_t uniformElemSize = location_object->ElementSize();                  \
-    if (expectedElemSize != uniformElemSize) {                                  \
-        return ErrorInvalidOperation(                                           \
-            #name ": this function expected a uniform of element size %d,"      \
-            " got a uniform of element size %d",                                \
-            expectedElemSize,                                                   \
-            uniformElemSize);                                                   \
-    }                                                                           \
-    const WebGLUniformInfo& info = location_object->Info();                     \
-    if (arrayLength == 0 ||                                                     \
-        arrayLength % expectedElemSize)                                         \
-    {                                                                           \
-        return ErrorInvalidValue("%s: expected an array of length a multiple"   \
-                                 " of %d, got an array of length %d",           \
-                                 #name,                                         \
-                                 expectedElemSize,                              \
-                                 arrayLength);                                  \
-    }                                                                           \
-    if (!info.isArray &&                                                        \
-        arrayLength != expectedElemSize) {                                      \
-        return ErrorInvalidOperation("%s: expected an array of length exactly"  \
-                                     " %d (since this uniform is not an array"  \
-                                     " uniform), got an array of length %d",    \
-                                     #name,                                     \
-                                     expectedElemSize,                          \
-                                     arrayLength);                              \
-    }                                                                           \
-    if (aTranspose) {                                                           \
-        return ErrorInvalidValue(#name ": transpose must be FALSE as per the "  \
-                                 "OpenGL ES 2.0 spec");                         \
-    }                                                                           \
-                                                                                \
-    MakeContextCurrent();                                                       \
-    uint32_t numElementsToUpload =                                              \
-        NS_MIN(info.arraySize, arrayLength / (expectedElemSize));               \
-    gl->f##name(location, numElementsToUpload, false, data); \
+void
+WebGLContext::Uniform3iv_base(WebGLUniformLocation *location_object,
+                              uint32_t arrayLength, const WebGLint* data)
+{
+    uint32_t numElementsToUpload;
+    GLint location;
+    if (!ValidateUniformArraySetter("Uniform3iv", 3, location_object, location,
+                                    numElementsToUpload, arrayLength)) {
+        return;
+    }
+    MakeContextCurrent();
+    gl->fUniform3iv(location, numElementsToUpload, data);
+}
+
+void
+WebGLContext::Uniform4iv_base(WebGLUniformLocation *location_object,
+                              uint32_t arrayLength, const WebGLint* data)
+{
+    uint32_t numElementsToUpload;
+    GLint location;
+    if (!ValidateUniformArraySetter("Uniform4iv", 4, location_object, location,
+                                    numElementsToUpload, arrayLength)) {
+        return;
+    }
+    MakeContextCurrent();
+    gl->fUniform4iv(location, numElementsToUpload, data);
+}
+
+void
+WebGLContext::Uniform1fv_base(WebGLUniformLocation *location_object,
+                              uint32_t arrayLength, const WebGLfloat* data)
+{
+    uint32_t numElementsToUpload;
+    GLint location;
+    if (!ValidateUniformArraySetter("Uniform1fv", 1, location_object, location,
+                                    numElementsToUpload, arrayLength)) {
+        return;
+    }
+    MakeContextCurrent();
+    gl->fUniform1fv(location, numElementsToUpload, data);
+}
+
+void
+WebGLContext::Uniform2fv_base(WebGLUniformLocation *location_object,
+                              uint32_t arrayLength, const WebGLfloat* data)
+{
+    uint32_t numElementsToUpload;
+    GLint location;
+    if (!ValidateUniformArraySetter("Uniform2fv", 2, location_object, location,
+                                    numElementsToUpload, arrayLength)) {
+        return;
+    }
+    MakeContextCurrent();
+    gl->fUniform2fv(location, numElementsToUpload, data);
 }
 
-#define SIMPLE_METHOD_UNIFORM_1(glname, name, t1)                               \
-void WebGLContext::name(WebGLUniformLocation *location_object, t1 a1) {         \
-    if (!IsContextStable())                                                     \
-        return;                                                                 \
-    OBTAIN_UNIFORM_LOCATION(#name ": location")                                 \
-    MakeContextCurrent(); gl->f##glname(location, a1);                          \
+void
+WebGLContext::Uniform3fv_base(WebGLUniformLocation *location_object,
+                              uint32_t arrayLength, const WebGLfloat* data)
+{
+    uint32_t numElementsToUpload;
+    GLint location;
+    if (!ValidateUniformArraySetter("Uniform3fv", 3, location_object, location,
+                                    numElementsToUpload, arrayLength)) {
+        return;
+    }
+    MakeContextCurrent();
+    gl->fUniform3fv(location, numElementsToUpload, data);
 }
 
-#define SIMPLE_METHOD_UNIFORM_2(glname, name, t1, t2)                           \
-void WebGLContext::name(WebGLUniformLocation *location_object, t1 a1, t2 a2) {  \
-    if (!IsContextStable())                                                     \
-        return;                                                                 \
-    OBTAIN_UNIFORM_LOCATION(#name ": location")                                 \
-    MakeContextCurrent(); gl->f##glname(location, a1, a2);                      \
-}
-
-#define SIMPLE_METHOD_UNIFORM_3(glname, name, t1, t2, t3)                       \
-void WebGLContext::name(WebGLUniformLocation *location_object,                  \
-                        t1 a1, t2 a2, t3 a3) {                                  \
-    if (!IsContextStable())                                                     \
-        return;                                                                 \
-    OBTAIN_UNIFORM_LOCATION(#name ": location")                                 \
-    MakeContextCurrent(); gl->f##glname(location, a1, a2, a3);                  \
+void
+WebGLContext::Uniform4fv_base(WebGLUniformLocation *location_object,
+                              uint32_t arrayLength, const WebGLfloat* data)
+{
+    uint32_t numElementsToUpload;
+    GLint location;
+    if (!ValidateUniformArraySetter("Uniform4fv", 4, location_object, location,
+                                    numElementsToUpload, arrayLength)) {
+        return;
+    }
+    MakeContextCurrent();
+    gl->fUniform4fv(location, numElementsToUpload, data);
 }
 
-#define SIMPLE_METHOD_UNIFORM_4(glname, name, t1, t2, t3, t4)                   \
-void WebGLContext::name(WebGLUniformLocation *location_object,                  \
-                        t1 a1, t2 a2, t3 a3, t4 a4) {                           \
-    if (!IsContextStable())                                                     \
-        return;                                                                 \
-    OBTAIN_UNIFORM_LOCATION(#name ": location")                                 \
-    MakeContextCurrent(); gl->f##glname(location, a1, a2, a3, a4);              \
+void
+WebGLContext::UniformMatrix2fv_base(WebGLUniformLocation* location_object,
+                                    WebGLboolean aTranspose, uint32_t arrayLength,
+                                    const float* data)
+{
+    uint32_t numElementsToUpload;
+    GLint location;
+    if (!ValidateUniformMatrixArraySetter("UniformMatrix2fv", 2, location_object, location,
+                                         numElementsToUpload, arrayLength, aTranspose)) {
+        return;
+    }
+    MakeContextCurrent();
+    gl->fUniformMatrix2fv(location, numElementsToUpload, false, data);
 }
 
-SIMPLE_METHOD_UNIFORM_1(Uniform1i, Uniform1i, WebGLint)
-SIMPLE_METHOD_UNIFORM_2(Uniform2i, Uniform2i, WebGLint, WebGLint)
-SIMPLE_METHOD_UNIFORM_3(Uniform3i, Uniform3i, WebGLint, WebGLint, WebGLint)
-SIMPLE_METHOD_UNIFORM_4(Uniform4i, Uniform4i, WebGLint, WebGLint, WebGLint, WebGLint)
-
-SIMPLE_METHOD_UNIFORM_1(Uniform1f, Uniform1f, WebGLfloat)
-SIMPLE_METHOD_UNIFORM_2(Uniform2f, Uniform2f, WebGLfloat, WebGLfloat)
-SIMPLE_METHOD_UNIFORM_3(Uniform3f, Uniform3f, WebGLfloat, WebGLfloat, WebGLfloat)
-SIMPLE_METHOD_UNIFORM_4(Uniform4f, Uniform4f, WebGLfloat, WebGLfloat, WebGLfloat, WebGLfloat)
-
-SIMPLE_ARRAY_METHOD_UNIFORM(Uniform1iv, 1, Int32, WebGLint)
-SIMPLE_ARRAY_METHOD_UNIFORM(Uniform2iv, 2, Int32, WebGLint)
-SIMPLE_ARRAY_METHOD_UNIFORM(Uniform3iv, 3, Int32, WebGLint)
-SIMPLE_ARRAY_METHOD_UNIFORM(Uniform4iv, 4, Int32, WebGLint)
-
-SIMPLE_ARRAY_METHOD_UNIFORM(Uniform1fv, 1, Float32, WebGLfloat)
-SIMPLE_ARRAY_METHOD_UNIFORM(Uniform2fv, 2, Float32, WebGLfloat)
-SIMPLE_ARRAY_METHOD_UNIFORM(Uniform3fv, 3, Float32, WebGLfloat)
-SIMPLE_ARRAY_METHOD_UNIFORM(Uniform4fv, 4, Float32, WebGLfloat)
-
-SIMPLE_MATRIX_METHOD_UNIFORM(UniformMatrix2fv, 2)
-SIMPLE_MATRIX_METHOD_UNIFORM(UniformMatrix3fv, 3)
-SIMPLE_MATRIX_METHOD_UNIFORM(UniformMatrix4fv, 4)
+void
+WebGLContext::UniformMatrix3fv_base(WebGLUniformLocation* location_object,
+                                    WebGLboolean aTranspose, uint32_t arrayLength,
+                                    const float* data)
+{
+    uint32_t numElementsToUpload;
+    GLint location;
+    if (!ValidateUniformMatrixArraySetter("UniformMatrix3fv", 3, location_object, location,
+                                         numElementsToUpload, arrayLength, aTranspose)) {
+        return;
+    }
+    MakeContextCurrent();
+    gl->fUniformMatrix3fv(location, numElementsToUpload, false, data);
+}
+
+void
+WebGLContext::UniformMatrix4fv_base(WebGLUniformLocation* location_object,
+                                    WebGLboolean aTranspose, uint32_t arrayLength,
+                                    const float* data)
+{
+    uint32_t numElementsToUpload;
+    GLint location;
+    if (!ValidateUniformMatrixArraySetter("UniformMatrix4fv", 4, location_object, location,
+                                         numElementsToUpload, arrayLength, aTranspose)) {
+        return;
+    }
+    MakeContextCurrent();
+    gl->fUniformMatrix4fv(location, numElementsToUpload, false, data);
+}
 
 void
 WebGLContext::VertexAttrib1f(WebGLuint index, WebGLfloat x0)
 {
     if (!IsContextStable())
         return;
 
     MakeContextCurrent();
@@ -3851,46 +3930,96 @@ WebGLContext::VertexAttrib4f(WebGLuint i
         mVertexAttrib0Vector[1] = x1;
         mVertexAttrib0Vector[2] = x2;
         mVertexAttrib0Vector[3] = x3;
         if (gl->IsGLES2())
             gl->fVertexAttrib4f(index, x0, x1, x2, x3);
     }
 }
 
-#define SIMPLE_ARRAY_METHOD_NO_COUNT(name, cnt, ptrType)                        \
-void                                                                            \
-WebGLContext::name##_base(WebGLuint idx, uint32_t arrayLength,                  \
-                          const WebGLfloat* ptr)                                \
-{                                                                               \
-    if (!IsContextStable()) {                                                   \
-        return;                                                                 \
-    }                                                                           \
-    if (arrayLength < cnt) {                                                    \
-        return ErrorInvalidOperation(#name ": array must be >= %d elements",    \
-                                     cnt);                                      \
-    }                                                                           \
-                                                                                \
-    MakeContextCurrent();                                                       \
-    if (idx) {                                                                  \
-        gl->f##name(idx, ptr);                                                  \
-    } else {                                                                    \
-        mVertexAttrib0Vector[0] = ptr[0];                                       \
-        mVertexAttrib0Vector[1] = cnt > 1 ? ptr[1] : ptrType(0);                \
-        mVertexAttrib0Vector[2] = cnt > 2 ? ptr[2] : ptrType(0);                \
-        mVertexAttrib0Vector[3] = cnt > 3 ? ptr[3] : ptrType(1);                \
-        if (gl->IsGLES2())                                                      \
-            gl->f##name(idx, ptr);                                              \
-    }                                                                           \
+
+void
+WebGLContext::VertexAttrib1fv_base(WebGLuint idx, uint32_t arrayLength,
+                                   const WebGLfloat* ptr)
+{
+    if (!ValidateAttribArraySetter("VertexAttrib1fv", 1, arrayLength))
+        return;
+
+    MakeContextCurrent();
+    if (idx) {
+        gl->fVertexAttrib1fv(idx, ptr);
+    } else {
+        mVertexAttrib0Vector[0] = ptr[0];
+        mVertexAttrib0Vector[1] = WebGLfloat(0);
+        mVertexAttrib0Vector[2] = WebGLfloat(0);
+        mVertexAttrib0Vector[3] = WebGLfloat(1);
+        if (gl->IsGLES2())
+            gl->fVertexAttrib1fv(idx, ptr);
+    }
+}
+
+void
+WebGLContext::VertexAttrib2fv_base(WebGLuint idx, uint32_t arrayLength,
+                                   const WebGLfloat* ptr)
+{
+    if (!ValidateAttribArraySetter("VertexAttrib2fv", 2, arrayLength))
+        return;
+
+    MakeContextCurrent();
+    if (idx) {
+        gl->fVertexAttrib2fv(idx, ptr);
+    } else {
+        mVertexAttrib0Vector[0] = ptr[0];
+        mVertexAttrib0Vector[1] = ptr[1];
+        mVertexAttrib0Vector[2] = WebGLfloat(0);
+        mVertexAttrib0Vector[3] = WebGLfloat(1);
+        if (gl->IsGLES2())
+            gl->fVertexAttrib2fv(idx, ptr);
+    }
 }
 
-SIMPLE_ARRAY_METHOD_NO_COUNT(VertexAttrib1fv, 1, WebGLfloat)
-SIMPLE_ARRAY_METHOD_NO_COUNT(VertexAttrib2fv, 2, WebGLfloat)
-SIMPLE_ARRAY_METHOD_NO_COUNT(VertexAttrib3fv, 3, WebGLfloat)
-SIMPLE_ARRAY_METHOD_NO_COUNT(VertexAttrib4fv, 4, WebGLfloat)
+void
+WebGLContext::VertexAttrib3fv_base(WebGLuint idx, uint32_t arrayLength,
+                                   const WebGLfloat* ptr)
+{
+    if (!ValidateAttribArraySetter("VertexAttrib3fv", 3, arrayLength))
+        return;
+
+    MakeContextCurrent();
+    if (idx) {
+        gl->fVertexAttrib3fv(idx, ptr);
+    } else {
+        mVertexAttrib0Vector[0] = ptr[0];
+        mVertexAttrib0Vector[1] = ptr[1];
+        mVertexAttrib0Vector[2] = ptr[2];
+        mVertexAttrib0Vector[3] = WebGLfloat(1);
+        if (gl->IsGLES2())
+            gl->fVertexAttrib3fv(idx, ptr);
+    }
+}
+
+void
+WebGLContext::VertexAttrib4fv_base(WebGLuint idx, uint32_t arrayLength,
+                                   const WebGLfloat* ptr)
+{
+    if (!ValidateAttribArraySetter("VertexAttrib4fv", 4, arrayLength))
+        return;
+
+    MakeContextCurrent();
+    if (idx) {
+        gl->fVertexAttrib4fv(idx, ptr);
+    } else {
+        mVertexAttrib0Vector[0] = ptr[0];
+        mVertexAttrib0Vector[1] = ptr[1];
+        mVertexAttrib0Vector[2] = ptr[2];
+        mVertexAttrib0Vector[3] = ptr[3];
+        if (gl->IsGLES2())
+            gl->fVertexAttrib4fv(idx, ptr);
+    }
+}
 
 void
 WebGLContext::UseProgram(WebGLProgram *prog)
 {
     if (!IsContextStable())
         return;
 
     if (!ValidateObjectAllowNull("useProgram", prog))
--- a/content/canvas/src/WebGLContextValidate.cpp
+++ b/content/canvas/src/WebGLContextValidate.cpp
@@ -652,16 +652,161 @@ bool WebGLContext::ValidateTexFormatAndT
         default:
             break;
         }
 
     ErrorInvalidEnum("%s: invalid type 0x%x", info, type);
     return false;
 }
 
+bool
+WebGLContext::ValidateUniformLocation(const char* info, WebGLUniformLocation *location_object)
+{
+    if (!ValidateObjectAllowNull(info, location_object))
+        return false;
+    if (!location_object)
+        return false;
+    /* the need to check specifically for !mCurrentProgram here is explained in bug 657556 */
+    if (!mCurrentProgram) {
+        ErrorInvalidOperation("%s: no program is currently bound", info);
+        return false;
+    }
+    if (mCurrentProgram != location_object->Program()) {
+        ErrorInvalidOperation("%s: this uniform location doesn't correspond to the current program", info);
+        return false;
+    }
+    if (mCurrentProgram->Generation() != location_object->ProgramGeneration()) {
+        ErrorInvalidOperation("%s: This uniform location is obsolete since the program has been relinked", info);
+        return false;
+    }
+    return true;
+}
+
+bool
+WebGLContext::ValidateAttribArraySetter(const char* name, uint32_t cnt, uint32_t arrayLength)
+{
+    if (!IsContextStable()) {
+        return false;
+    }
+    if (arrayLength < cnt) {
+        ErrorInvalidOperation("%s: array must be >= %d elements", name, cnt);
+        return false;
+    }
+    return true;
+}
+
+bool
+WebGLContext::ValidateUniformArraySetter(const char* name, uint32_t expectedElemSize, WebGLUniformLocation *location_object,
+                                         GLint& location, uint32_t& numElementsToUpload, uint32_t arrayLength)
+{
+    if (!IsContextStable())
+        return false;
+    nsCString nameString(name);
+    nsCString suffix = NS_LITERAL_CSTRING(": location");
+    nsCString concatenated = nameString + suffix;
+    if (!ValidateUniformLocation(concatenated.get(), location_object))
+        return false;
+    location = location_object->Location();
+    uint32_t uniformElemSize = location_object->ElementSize();
+    if (expectedElemSize != uniformElemSize) {
+        ErrorInvalidOperation("%s: this function expected a uniform of element size %d,"
+                              " got a uniform of element size %d", name,
+                              expectedElemSize,
+                              uniformElemSize);
+        return false;
+    }
+    const WebGLUniformInfo& info = location_object->Info();
+    if (arrayLength == 0 ||
+        arrayLength % expectedElemSize)
+    {
+        ErrorInvalidValue("%s: expected an array of length a multiple"
+                          " of %d, got an array of length %d", name,
+                          expectedElemSize,
+                          arrayLength);
+        return false;
+    }
+    if (!info.isArray &&
+        arrayLength != expectedElemSize) {
+        ErrorInvalidOperation("%s: expected an array of length exactly"
+                              " %d (since this uniform is not an array"
+                              " uniform), got an array of length %d", name,
+                              expectedElemSize,
+                              arrayLength);
+        return false;
+    }
+    numElementsToUpload =
+        NS_MIN(info.arraySize, arrayLength / expectedElemSize);
+    return true;
+}
+
+bool
+WebGLContext::ValidateUniformMatrixArraySetter(const char* name, int dim, WebGLUniformLocation *location_object,
+                                              GLint& location, uint32_t& numElementsToUpload, uint32_t arrayLength,
+                                              WebGLboolean aTranspose)
+{
+    uint32_t expectedElemSize = (dim)*(dim);
+    if (!IsContextStable())
+        return false;
+    nsCString nameString(name);
+    nsCString suffix = NS_LITERAL_CSTRING(": location");
+    nsCString concatenated = nameString + suffix;
+    if (!ValidateUniformLocation(concatenated.get(), location_object))
+        return false;
+    location = location_object->Location();
+    uint32_t uniformElemSize = location_object->ElementSize();
+    if (expectedElemSize != uniformElemSize) {
+        ErrorInvalidOperation("%s: this function expected a uniform of element size %d,"
+                              " got a uniform of element size %d", name,
+                              expectedElemSize,
+                              uniformElemSize);
+        return false;
+    }
+    const WebGLUniformInfo& info = location_object->Info();
+    if (arrayLength == 0 ||
+        arrayLength % expectedElemSize)
+    {
+        ErrorInvalidValue("%s: expected an array of length a multiple"
+                          " of %d, got an array of length %d", name,
+                          expectedElemSize,
+                          arrayLength);
+        return false;
+    }
+    if (!info.isArray &&
+        arrayLength != expectedElemSize) {
+        ErrorInvalidOperation("%s: expected an array of length exactly"
+                              " %d (since this uniform is not an array"
+                              " uniform), got an array of length %d", name,
+                              expectedElemSize,
+                              arrayLength);
+        return false;
+    }
+    if (aTranspose) {
+        ErrorInvalidValue("%s: transpose must be FALSE as per the "
+                          "OpenGL ES 2.0 spec", name);
+        return false;
+    }
+    numElementsToUpload =
+        NS_MIN(info.arraySize, arrayLength / (expectedElemSize));
+    return true;
+}
+
+bool
+WebGLContext::ValidateUniformSetter(const char* name, WebGLUniformLocation *location_object, GLint& location)
+{
+    if (!IsContextStable())
+        return false;
+    nsCString nameString(name);
+    nsCString suffix = NS_LITERAL_CSTRING(": location");
+    nsCString concatenated = nameString + suffix;
+    if (!ValidateUniformLocation(concatenated.get(), location_object))
+        return false;
+    location = location_object->Location();
+    return true;
+}
+
 bool WebGLContext::ValidateAttribIndex(WebGLuint index, const char *info)
 {
     if (index >= mAttribBuffers.Length()) {
         if (index == WebGLuint(-1)) {
              ErrorInvalidValue("%s: index -1 is invalid. That probably comes from a getAttribLocation() call, "
                                "where this return value -1 means that the passed name didn't correspond to an active attribute in "
                                "the specified program.", info);
         } else {