Bug 1048745 - [WebGL2] Integer vertex attributes. r=jgilbert
authorDan Glastonbury <dglastonbury@mozilla.com>
Tue, 24 Jun 2014 10:56:21 +1000
changeset 218139 e5c404f95a9d010ebfb9df50e9eb9a595a4f2314
parent 218138 9ce25fd6315b7d7cef100d88c96940d5df78f736
child 218140 f5dc77e4a2a8a19566e7f43f8ca009ecb56ec08c
push id27916
push usercbook@mozilla.com
push dateMon, 01 Dec 2014 10:55:11 +0000
treeherdermozilla-central@af5fc587f98b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjgilbert
bugs1048745
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 1048745 - [WebGL2] Integer vertex attributes. r=jgilbert
dom/canvas/WebGL1Context.h
dom/canvas/WebGL1ContextUniforms.cpp
dom/canvas/WebGL2Context.h
dom/canvas/WebGL2ContextUniforms.cpp
dom/canvas/WebGLContext.h
dom/canvas/WebGLContextDraw.cpp
dom/canvas/WebGLContextValidate.cpp
dom/canvas/WebGLContextVertices.cpp
dom/canvas/WebGLVertexArray.h
dom/canvas/WebGLVertexArrayFake.cpp
dom/canvas/WebGLVertexAttribData.h
dom/canvas/moz.build
--- a/dom/canvas/WebGL1Context.h
+++ b/dom/canvas/WebGL1Context.h
@@ -23,13 +23,16 @@ public:
     virtual ~WebGL1Context();
 
     virtual bool IsWebGL2() const MOZ_OVERRIDE {
         return false;
     }
 
     // nsWrapperCache
     virtual JSObject* WrapObject(JSContext* cx) MOZ_OVERRIDE;
+
+private:
+    virtual bool ValidateAttribPointerType(bool integerMode, GLenum type, GLsizei* alignment, const char* info) MOZ_OVERRIDE;
 };
 
 } // namespace mozilla
 
 #endif // WEBGL_1_CONTEXT_H_
new file mode 100644
--- /dev/null
+++ b/dom/canvas/WebGL1ContextUniforms.cpp
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "WebGL1Context.h"
+
+using namespace mozilla;
+
+bool
+WebGL1Context::ValidateAttribPointerType(bool /*integerMode*/, GLenum type, GLsizei* out_alignment, const char* info)
+{
+    MOZ_ASSERT(out_alignment);
+    if (!out_alignment)
+        return false;
+
+    switch (type) {
+    case LOCAL_GL_BYTE:
+    case LOCAL_GL_UNSIGNED_BYTE:
+        *out_alignment = 1;
+        return true;
+
+    case LOCAL_GL_SHORT:
+    case LOCAL_GL_UNSIGNED_SHORT:
+        *out_alignment = 2;
+        return true;
+        // XXX case LOCAL_GL_FIXED:
+    case LOCAL_GL_FLOAT:
+        *out_alignment = 4;
+        return true;
+    }
+
+    ErrorInvalidEnumInfo(info, type);
+    return false;
+}
--- a/dom/canvas/WebGL2Context.h
+++ b/dom/canvas/WebGL2Context.h
@@ -30,17 +30,16 @@ public:
         return true;
     }
 
     // -------------------------------------------------------------------------
     // IMPLEMENT nsWrapperCache
 
     virtual JSObject* WrapObject(JSContext* cx) MOZ_OVERRIDE;
 
-
     // -------------------------------------------------------------------------
     // Buffer objects - WebGL2ContextBuffers.cpp
 
     void CopyBufferSubData(GLenum readTarget, GLenum writeTarget,
                            GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
     void GetBufferSubData(GLenum target, GLintptr offset, const dom::ArrayBuffer& returnedData);
     void GetBufferSubData(GLenum target, GLintptr offset, const dom::ArrayBufferView& returnedData);
 
@@ -121,16 +120,22 @@ public:
     void UniformMatrix2x4fv(WebGLUniformLocation* location, bool transpose, const dom::Sequence<GLfloat>& value);
     void UniformMatrix4x2fv(WebGLUniformLocation* location, bool transpose, const dom::Float32Array& value);
     void UniformMatrix4x2fv(WebGLUniformLocation* location, bool transpose, const dom::Sequence<GLfloat>& value);
     void UniformMatrix3x4fv(WebGLUniformLocation* location, bool transpose, const dom::Float32Array& value);
     void UniformMatrix3x4fv(WebGLUniformLocation* location, bool transpose, const dom::Sequence<GLfloat>& value);
     void UniformMatrix4x3fv(WebGLUniformLocation* location, bool transpose, const dom::Float32Array& value);
     void UniformMatrix4x3fv(WebGLUniformLocation* location, bool transpose, const dom::Sequence<GLfloat>& value);
 
+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
@@ -245,18 +250,21 @@ public:
     void DeleteVertexArray(WebGLVertexArrayObject* vertexArray);
     bool IsVertexArray(WebGLVertexArrayObject* vertexArray);
     void BindVertexArray(WebGLVertexArrayObject* vertexArray);
 */
 
 private:
     WebGL2Context();
 
+    JS::Value GetTexParameterInternal(const TexTarget& target, GLenum pname) MOZ_OVERRIDE;
+
     bool ValidateSizedInternalFormat(GLenum internalFormat, const char* info);
     bool ValidateTexStorage(GLenum target, GLsizei levels, GLenum internalformat,
                                 GLsizei width, GLsizei height, GLsizei depth,
                                 const char* info);
-    JS::Value GetTexParameterInternal(const TexTarget& target, GLenum pname) MOZ_OVERRIDE;
+
+    virtual bool ValidateAttribPointerType(bool integerMode, GLenum type, GLsizei* alignment, const char* info) MOZ_OVERRIDE;
 };
 
 } // namespace mozilla
 
 #endif
--- a/dom/canvas/WebGL2ContextUniforms.cpp
+++ b/dom/canvas/WebGL2ContextUniforms.cpp
@@ -1,26 +1,112 @@
 /* -*- 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 "WebGLVertexArray.h"
+#include "WebGLVertexAttribData.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
+typedef union { GLint i; GLfloat f; GLuint u; } fi_t;
+
+static inline
+GLfloat PuntToFloat(GLint i)
+{
+   fi_t tmp;
+   tmp.i = i;
+   return tmp.f;
+}
+
+static inline
+GLfloat PuntToFloat(GLuint u)
+{
+   fi_t tmp;
+   tmp.u = u;
+   return tmp.f;
+}
+
+bool
+WebGL2Context::ValidateAttribPointerType(bool integerMode, GLenum type, GLsizei* alignment, const char* info)
+{
+    MOZ_ASSERT(alignment);
+
+    switch (type) {
+    case LOCAL_GL_BYTE:
+    case LOCAL_GL_UNSIGNED_BYTE:
+        *alignment = 1;
+        return true;
+
+    case LOCAL_GL_SHORT:
+    case LOCAL_GL_UNSIGNED_SHORT:
+        *alignment = 2;
+        return true;
+
+    case LOCAL_GL_INT:
+    case LOCAL_GL_UNSIGNED_INT:
+        *alignment = 4;
+        return true;
+    }
+
+    if (!integerMode) {
+        switch (type) {
+        case LOCAL_GL_HALF_FLOAT:
+            *alignment = 2;
+            return true;
+
+        case LOCAL_GL_FLOAT:
+        case LOCAL_GL_FIXED:
+        case LOCAL_GL_INT_2_10_10_10_REV:
+        case LOCAL_GL_UNSIGNED_INT_2_10_10_10_REV:
+            *alignment = 4;
+            return true;
+        }
+    }
+
+    ErrorInvalidEnum("%s: invalid enum value 0x%x", info, type);
+    return false;
+}
+
 // -------------------------------------------------------------------------
 // Uniforms and attributes
 
 void
 WebGL2Context::VertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, GLintptr offset)
 {
-    MOZ_CRASH("Not Implemented.");
+    if (IsContextLost())
+        return;
+
+    if (!ValidateAttribIndex(index, "vertexAttribIPointer"))
+        return;
+
+    if (!ValidateAttribPointer(true, index, size, type, LOCAL_GL_FALSE, stride, offset, "vertexAttribIPointer"))
+        return;
+
+    MOZ_ASSERT(mBoundVertexArray);
+    mBoundVertexArray->EnsureAttrib(index);
+
+    InvalidateBufferFetching();
+
+    WebGLVertexAttribData& vd = mBoundVertexArray->mAttribs[index];
+
+    vd.buf = mBoundArrayBuffer;
+    vd.stride = stride;
+    vd.size = size;
+    vd.byteOffset = offset;
+    vd.type = type;
+    vd.normalized = false;
+    vd.integer = true;
+
+    MakeContextCurrent();
+    gl->fVertexAttribIPointer(index, size, type, stride, reinterpret_cast<void*>(offset));
 }
 
 void
 WebGL2Context::Uniform1ui(WebGLUniformLocation* location, GLuint v0)
 {
     MOZ_CRASH("Not Implemented.");
 }
 
@@ -136,35 +222,91 @@ void
 WebGL2Context::UniformMatrix4x3fv(WebGLUniformLocation* location, bool transpose, const dom::Sequence<GLfloat>& value)
 {
     MOZ_CRASH("Not Implemented.");
 }
 
 void
 WebGL2Context::VertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w)
 {
-    MOZ_CRASH("Not Implemented.");
+    if (IsContextLost())
+        return;
+
+    if (index || gl->IsGLES()) {
+        MakeContextCurrent();
+        gl->fVertexAttribI4i(index, x, y, z, w);
+    } else {
+        mVertexAttrib0Vector[0] = PuntToFloat(x);
+        mVertexAttrib0Vector[1] = PuntToFloat(y);
+        mVertexAttrib0Vector[2] = PuntToFloat(z);
+        mVertexAttrib0Vector[3] = PuntToFloat(w);
+    }
+}
+
+void
+WebGL2Context::VertexAttribI4iv(GLuint index, size_t length, const GLint* v)
+{
+    if (!ValidateAttribArraySetter("vertexAttribI4iv", 4, length))
+        return;
+
+    if (index || gl->IsGLES()) {
+        MakeContextCurrent();
+        gl->fVertexAttribI4iv(index, v);
+    } else {
+        mVertexAttrib0Vector[0] = PuntToFloat(v[0]);
+        mVertexAttrib0Vector[1] = PuntToFloat(v[1]);
+        mVertexAttrib0Vector[2] = PuntToFloat(v[2]);
+        mVertexAttrib0Vector[3] = PuntToFloat(v[3]);
+    }
 }
 
 void
 WebGL2Context::VertexAttribI4iv(GLuint index, const dom::Sequence<GLint>& v)
 {
-    MOZ_CRASH("Not Implemented.");
+    VertexAttribI4iv(index, v.Length(), v.Elements());
 }
 
 void
 WebGL2Context::VertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w)
 {
-    MOZ_CRASH("Not Implemented.");
+    if (IsContextLost())
+        return;
+
+    if (index || gl->IsGLES()) {
+        MakeContextCurrent();
+        gl->fVertexAttribI4ui(index, x, y, z, w);
+    } else {
+        mVertexAttrib0Vector[0] = PuntToFloat(x);
+        mVertexAttrib0Vector[1] = PuntToFloat(y);
+        mVertexAttrib0Vector[2] = PuntToFloat(z);
+        mVertexAttrib0Vector[3] = PuntToFloat(w);
+    }
+}
+
+void
+WebGL2Context::VertexAttribI4uiv(GLuint index, size_t length, const GLuint* v)
+{
+    if (IsContextLost())
+        return;
+
+    if (index || gl->IsGLES()) {
+        MakeContextCurrent();
+        gl->fVertexAttribI4uiv(index, v);
+    } else {
+        mVertexAttrib0Vector[0] = PuntToFloat(v[0]);
+        mVertexAttrib0Vector[1] = PuntToFloat(v[1]);
+        mVertexAttrib0Vector[2] = PuntToFloat(v[2]);
+        mVertexAttrib0Vector[3] = PuntToFloat(v[3]);
+    }
 }
 
 void
 WebGL2Context::VertexAttribI4uiv(GLuint index, const dom::Sequence<GLuint>& v)
 {
-    MOZ_CRASH("Not Implemented.");
+    VertexAttribI4uiv(index, v.Length(), v.Elements());
 }
 
 // -------------------------------------------------------------------------
 // Uniform Buffer Objects and Transform Feedback Buffers
 // TODO(djg): Implemented in WebGLContext
 /*
     void BindBufferBase(GLenum target, GLuint index, WebGLBuffer* buffer);
     void BindBufferRange(GLenum target, GLuint index, WebGLBuffer* buffer, GLintptr offset, GLsizeiptr size);
--- a/dom/canvas/WebGLContext.h
+++ b/dom/canvas/WebGLContext.h
@@ -47,17 +47,17 @@
 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
  * the values in the spec are ridiculously low. They are explicitly marked below
-*/
+ */
 #define MINVALUE_GL_MAX_TEXTURE_SIZE                  1024  // Different from the spec, which sets it to 64 on page 162
 #define MINVALUE_GL_MAX_CUBE_MAP_TEXTURE_SIZE         512   // Different from the spec, which sets it to 16 on page 162
 #define MINVALUE_GL_MAX_VERTEX_ATTRIBS                8     // Page 164
 #define MINVALUE_GL_MAX_FRAGMENT_UNIFORM_VECTORS      16    // Page 164
 #define MINVALUE_GL_MAX_VERTEX_UNIFORM_VECTORS        128   // Page 164
 #define MINVALUE_GL_MAX_VARYING_VECTORS               8     // Page 164
 #define MINVALUE_GL_MAX_TEXTURE_IMAGE_UNITS           8     // Page 164
 #define MINVALUE_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS    0     // Page 164
@@ -129,21 +129,23 @@ struct WebGLContextOptions
 };
 
 // From WebGLContextUtils
 TexTarget TexImageTargetToTexTarget(TexImageTarget texImageTarget);
 
 class WebGLIntOrFloat {
     enum {
         Int,
-        Float
+        Float,
+        Uint
     } mType;
     union {
         GLint i;
         GLfloat f;
+        GLuint u;
     } mValue;
 
 public:
     explicit WebGLIntOrFloat(GLint i) : mType(Int) { mValue.i = i; }
     explicit WebGLIntOrFloat(GLfloat f) : mType(Float) { mValue.f = f; }
 
     GLint AsInt() const { return (mType == Int) ? mValue.i : NS_lroundf(mValue.f); }
     GLfloat AsFloat() const { return (mType == Float) ? mValue.f : GLfloat(mValue.i); }
@@ -153,16 +155,17 @@ class WebGLContext
     : public nsIDOMWebGLRenderingContext
     , public nsICanvasRenderingContextInternal
     , public nsSupportsWeakReference
     , public WebGLContextUnchecked
     , public WebGLRectangleObject
     , public nsWrapperCache
     , public SupportsWeakPtr<WebGLContext>
 {
+    friend class WebGL2Context;
     friend class WebGLContextUserData;
     friend class WebGLExtensionCompressedTextureATC;
     friend class WebGLExtensionCompressedTextureETC1;
     friend class WebGLExtensionCompressedTexturePVRTC;
     friend class WebGLExtensionCompressedTextureS3TC;
     friend class WebGLExtensionDepthTexture;
     friend class WebGLExtensionDrawBuffers;
     friend class WebGLExtensionLoseContext;
@@ -1001,16 +1004,17 @@ 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,
@@ -1187,16 +1191,20 @@ protected:
                                              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);
+    bool ValidateAttribPointer(bool integerMode, GLuint index, GLint size, GLenum type,
+                               WebGLboolean normalized, GLsizei stride,
+                               WebGLintptr byteOffset, const char* info);
     bool ValidateStencilParamsForDrawCall();
 
     bool ValidateGLSLVariableName(const nsAString& name, const char* info);
     bool ValidateGLSLCharacter(char16_t c);
     bool ValidateGLSLString(const nsAString& string, const char* info);
 
     bool ValidateCopyTexImage(GLenum internalFormat, WebGLTexImageFunc func,
                               WebGLTexDimensions dims);
@@ -1324,16 +1332,21 @@ protected:
     bool ValidateObjectAllowDeleted(const char* info, ObjectType* object);
 
 private:
     // Like ValidateObject, but only for cases when `object` is known to not be
     // null already.
     template<class ObjectType>
     bool ValidateObjectAssumeNonNull(const char* info, ObjectType* object);
 
+private:
+    // -------------------------------------------------------------------------
+    // Context customization points
+    virtual bool ValidateAttribPointerType(bool integerMode, GLenum type, GLsizei* alignment, const char* info) = 0;
+
 protected:
     int32_t MaxTextureSizeForTarget(TexTarget target) const {
         return (target == LOCAL_GL_TEXTURE_2D) ? mGLMaxTextureSize
                                                : mGLMaxCubeMapTextureSize;
     }
 
     int32_t
     MaxTextureLevelForTexImageTarget(TexImageTarget texImageTarget) const {
--- a/dom/canvas/WebGLContextDraw.cpp
+++ b/dom/canvas/WebGLContextDraw.cpp
@@ -616,22 +616,30 @@ WebGLContext::UndoFakeVertexAttrib0()
     WebGLVertexAttrib0Status whatDoesAttrib0Need = WhatDoesVertexAttrib0Need();
 
     if (MOZ_LIKELY(whatDoesAttrib0Need == WebGLVertexAttrib0Status::Default))
         return;
 
     if (mBoundVertexArray->HasAttrib(0) && mBoundVertexArray->mAttribs[0].buf) {
         const WebGLVertexAttribData& attrib0 = mBoundVertexArray->mAttribs[0];
         gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, attrib0.buf->GLName());
-        gl->fVertexAttribPointer(0,
-                                 attrib0.size,
-                                 attrib0.type,
-                                 attrib0.normalized,
-                                 attrib0.stride,
-                                 reinterpret_cast<const GLvoid *>(attrib0.byteOffset));
+        if (attrib0.integer) {
+            gl->fVertexAttribIPointer(0,
+                                      attrib0.size,
+                                      attrib0.type,
+                                      attrib0.stride,
+                                      reinterpret_cast<const GLvoid*>(attrib0.byteOffset));
+        } else {
+            gl->fVertexAttribPointer(0,
+                                     attrib0.size,
+                                     attrib0.type,
+                                     attrib0.normalized,
+                                     attrib0.stride,
+                                     reinterpret_cast<const GLvoid*>(attrib0.byteOffset));
+        }
     } else {
         gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
     }
 
     gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mBoundArrayBuffer ? mBoundArrayBuffer->GLName() : 0);
 }
 
 WebGLContextFakeBlackStatus
--- a/dom/canvas/WebGLContextValidate.cpp
+++ b/dom/canvas/WebGLContextValidate.cpp
@@ -1714,16 +1714,88 @@ WebGLContext::ValidateUniformMatrixArray
 
     *out_rawLoc = loc->Location();
     *out_numElementsToUpload = std::min((size_t)loc->Info().arraySize,
                                         setterArraySize / setterElemSize);
     return true;
 }
 
 bool
+WebGLContext::ValidateAttribIndex(GLuint index, const char* info)
+{
+    bool valid = (index < MaxVertexAttribs());
+
+    if (!valid) {
+        if (index == GLuint(-1)) {
+            ErrorInvalidValue("%s: -1 is not a valid `index`. This value"
+                              " 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 {
+            ErrorInvalidValue("%s: `index` must be less than"
+                              " MAX_VERTEX_ATTRIBS.", info);
+        }
+    }
+
+    return valid;
+}
+
+bool
+WebGLContext::ValidateAttribPointer(bool integerMode, GLuint index, GLint size, GLenum type,
+                                    WebGLboolean normalized, GLsizei stride,
+                                    WebGLintptr byteOffset, const char* info)
+{
+    WebGLBuffer* buffer = mBoundArrayBuffer;
+    if (!buffer) {
+        ErrorInvalidOperation("%s: must have valid GL_ARRAY_BUFFER binding", info);
+        return false;
+    }
+
+    GLsizei requiredAlignment = 0;
+    if (!ValidateAttribPointerType(integerMode, type, &requiredAlignment, info))
+        return false;
+
+    // requiredAlignment should always be a power of two
+    MOZ_ASSERT(IsPOTAssumingNonnegative(requiredAlignment));
+    GLsizei requiredAlignmentMask = requiredAlignment - 1;
+
+    if (size < 1 || size > 4) {
+        ErrorInvalidValue("%s: invalid element size", info);
+        return false;
+    }
+
+    // see WebGL spec section 6.6 "Vertex Attribute Data Stride"
+    if (stride < 0 || stride > 255) {
+        ErrorInvalidValue("%s: negative or too large stride", info);
+        return false;
+    }
+
+    if (byteOffset < 0) {
+        ErrorInvalidValue("%s: negative offset", info);
+        return false;
+    }
+
+    if (stride & requiredAlignmentMask) {
+        ErrorInvalidOperation("%s: stride doesn't satisfy the alignment "
+                              "requirement of given type", info);
+        return false;
+    }
+
+    if (byteOffset & requiredAlignmentMask) {
+        ErrorInvalidOperation("%s: byteOffset doesn't satisfy the alignment "
+                              "requirement of given type", info);
+        return false;
+    }
+
+    return true;
+}
+
+bool
 WebGLContext::ValidateStencilParamsForDrawCall()
 {
     const char msg[] = "%s set different front and back stencil %s. Drawing in"
                        " this configuration is not allowed.";
 
     if (mStencilRefFront != mStencilRefBack) {
         ErrorInvalidOperation(msg, "stencilFuncSeparate", "reference values");
         return false;
--- a/dom/canvas/WebGLContextVertices.cpp
+++ b/dom/canvas/WebGLContextVertices.cpp
@@ -15,44 +15,23 @@
 #include "WebGLTexture.h"
 #include "WebGLUniformInfo.h"
 #include "WebGLVertexArray.h"
 #include "WebGLVertexAttribData.h"
 
 using namespace mozilla;
 using namespace dom;
 
-static bool
-CheckAttribIndex(WebGLContext& webgl, GLuint index, const char* info)
-{
-    if (index >= webgl.MaxVertexAttribs()) {
-        if (index == GLuint(-1)) {
-            webgl.ErrorInvalidValue("%s: -1 is not a valid `index`. This value"
-                                    " 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 {
-            webgl.ErrorInvalidValue("%s: `index` must be less than"
-                                    " MAX_VERTEX_ATTRIBS.", info);
-        }
-        return false;
-    }
-
-    return true;
-}
-
 void
 WebGLContext::VertexAttrib1f(GLuint index, GLfloat x0)
 {
     if (IsContextLost())
         return;
 
-    if (!CheckAttribIndex(*this, index, "vertexAttrib1f"))
+    if (!ValidateAttribIndex(index, "vertexAttrib1f"))
         return;
 
     MakeContextCurrent();
 
     if (index) {
         gl->fVertexAttrib1f(index, x0);
     } else {
         mVertexAttrib0Vector[0] = x0;
@@ -65,17 +44,17 @@ WebGLContext::VertexAttrib1f(GLuint inde
 }
 
 void
 WebGLContext::VertexAttrib2f(GLuint index, GLfloat x0, GLfloat x1)
 {
     if (IsContextLost())
         return;
 
-    if (!CheckAttribIndex(*this, index, "vertexAttrib2f"))
+    if (!ValidateAttribIndex(index, "vertexAttrib2f"))
         return;
 
     MakeContextCurrent();
 
     if (index) {
         gl->fVertexAttrib2f(index, x0, x1);
     } else {
         mVertexAttrib0Vector[0] = x0;
@@ -88,17 +67,17 @@ WebGLContext::VertexAttrib2f(GLuint inde
 }
 
 void
 WebGLContext::VertexAttrib3f(GLuint index, GLfloat x0, GLfloat x1, GLfloat x2)
 {
     if (IsContextLost())
         return;
 
-    if (!CheckAttribIndex(*this, index, "vertexAttrib3f"))
+    if (!ValidateAttribIndex(index, "vertexAttrib3f"))
         return;
 
     MakeContextCurrent();
 
     if (index) {
         gl->fVertexAttrib3f(index, x0, x1, x2);
     } else {
         mVertexAttrib0Vector[0] = x0;
@@ -112,17 +91,17 @@ WebGLContext::VertexAttrib3f(GLuint inde
 
 void
 WebGLContext::VertexAttrib4f(GLuint index, GLfloat x0, GLfloat x1,
                              GLfloat x2, GLfloat x3)
 {
     if (IsContextLost())
         return;
 
-    if (!CheckAttribIndex(*this, index, "vertexAttrib4f"))
+    if (!ValidateAttribIndex(index, "vertexAttrib4f"))
         return;
 
     MakeContextCurrent();
 
     if (index) {
         gl->fVertexAttrib4f(index, x0, x1, x2, x3);
     } else {
         mVertexAttrib0Vector[0] = x0;
@@ -137,17 +116,17 @@ WebGLContext::VertexAttrib4f(GLuint inde
 
 void
 WebGLContext::VertexAttrib1fv_base(GLuint index, uint32_t arrayLength,
                                    const GLfloat* ptr)
 {
     if (!ValidateAttribArraySetter("VertexAttrib1fv", 1, arrayLength))
         return;
 
-    if (!CheckAttribIndex(*this, index, "vertexAttrib1fv"))
+    if (!ValidateAttribIndex(index, "vertexAttrib1fv"))
         return;
 
     MakeContextCurrent();
     if (index) {
         gl->fVertexAttrib1fv(index, ptr);
     } else {
         mVertexAttrib0Vector[0] = ptr[0];
         mVertexAttrib0Vector[1] = GLfloat(0);
@@ -160,17 +139,17 @@ WebGLContext::VertexAttrib1fv_base(GLuin
 
 void
 WebGLContext::VertexAttrib2fv_base(GLuint index, uint32_t arrayLength,
                                    const GLfloat* ptr)
 {
     if (!ValidateAttribArraySetter("VertexAttrib2fv", 2, arrayLength))
         return;
 
-    if (!CheckAttribIndex(*this, index, "vertexAttrib2fv"))
+    if (!ValidateAttribIndex(index, "vertexAttrib2fv"))
         return;
 
     MakeContextCurrent();
     if (index) {
         gl->fVertexAttrib2fv(index, ptr);
     } else {
         mVertexAttrib0Vector[0] = ptr[0];
         mVertexAttrib0Vector[1] = ptr[1];
@@ -183,17 +162,17 @@ WebGLContext::VertexAttrib2fv_base(GLuin
 
 void
 WebGLContext::VertexAttrib3fv_base(GLuint index, uint32_t arrayLength,
                                    const GLfloat* ptr)
 {
     if (!ValidateAttribArraySetter("VertexAttrib3fv", 3, arrayLength))
         return;
 
-    if (!CheckAttribIndex(*this, index, "vertexAttrib3fv"))
+    if (!ValidateAttribIndex(index, "vertexAttrib3fv"))
         return;
 
     MakeContextCurrent();
     if (index) {
         gl->fVertexAttrib3fv(index, ptr);
     } else {
         mVertexAttrib0Vector[0] = ptr[0];
         mVertexAttrib0Vector[1] = ptr[1];
@@ -206,17 +185,17 @@ WebGLContext::VertexAttrib3fv_base(GLuin
 
 void
 WebGLContext::VertexAttrib4fv_base(GLuint index, uint32_t arrayLength,
                                    const GLfloat* ptr)
 {
     if (!ValidateAttribArraySetter("VertexAttrib4fv", 4, arrayLength))
         return;
 
-    if (!CheckAttribIndex(*this, index, "vertexAttrib4fv"))
+    if (!ValidateAttribIndex(index, "vertexAttrib4fv"))
         return;
 
     MakeContextCurrent();
     if (index) {
         gl->fVertexAttrib4fv(index, ptr);
     } else {
         mVertexAttrib0Vector[0] = ptr[0];
         mVertexAttrib0Vector[1] = ptr[1];
@@ -228,17 +207,17 @@ WebGLContext::VertexAttrib4fv_base(GLuin
 }
 
 void
 WebGLContext::EnableVertexAttribArray(GLuint index)
 {
     if (IsContextLost())
         return;
 
-    if (!CheckAttribIndex(*this, index, "enableVertexAttribArray"))
+    if (!ValidateAttribIndex(index, "enableVertexAttribArray"))
         return;
 
     MakeContextCurrent();
     InvalidateBufferFetching();
 
     gl->fEnableVertexAttribArray(index);
 
     MOZ_ASSERT(mBoundVertexArray);
@@ -247,17 +226,17 @@ WebGLContext::EnableVertexAttribArray(GL
 }
 
 void
 WebGLContext::DisableVertexAttribArray(GLuint index)
 {
     if (IsContextLost())
         return;
 
-    if (!CheckAttribIndex(*this, index, "disableVertexAttribArray"))
+    if (!ValidateAttribIndex(index, "disableVertexAttribArray"))
         return;
 
     MakeContextCurrent();
     InvalidateBufferFetching();
 
     if (index || gl->IsGLES())
         gl->fDisableVertexAttribArray(index);
 
@@ -268,17 +247,17 @@ WebGLContext::DisableVertexAttribArray(G
 
 JS::Value
 WebGLContext::GetVertexAttrib(JSContext* cx, GLuint index, GLenum pname,
                               ErrorResult& rv)
 {
     if (IsContextLost())
         return JS::NullValue();
 
-    if (!CheckAttribIndex(*this, index, "getVertexAttrib"))
+    if (!ValidateAttribIndex(index, "getVertexAttrib"))
         return JS::NullValue();
 
     MOZ_ASSERT(mBoundVertexArray);
     mBoundVertexArray->EnsureAttrib(index);
 
     MakeContextCurrent();
 
     switch (pname) {
@@ -354,17 +333,17 @@ WebGLContext::GetVertexAttrib(JSContext*
 }
 
 WebGLsizeiptr
 WebGLContext::GetVertexAttribOffset(GLuint index, GLenum pname)
 {
     if (IsContextLost())
         return 0;
 
-    if (!CheckAttribIndex(*this, index, "getVertexAttribOffset"))
+    if (!ValidateAttribIndex(index, "getVertexAttribOffset"))
         return 0;
 
     if (pname != LOCAL_GL_VERTEX_ATTRIB_ARRAY_POINTER) {
         ErrorInvalidEnum("getVertexAttribOffset: bad parameter");
         return 0;
     }
 
     MOZ_ASSERT(mBoundVertexArray);
@@ -375,96 +354,54 @@ WebGLContext::GetVertexAttribOffset(GLui
 void
 WebGLContext::VertexAttribPointer(GLuint index, GLint size, GLenum type,
                                   WebGLboolean normalized, GLsizei stride,
                                   WebGLintptr byteOffset)
 {
     if (IsContextLost())
         return;
 
-    if (!CheckAttribIndex(*this, index, "vertexAttribPointer"))
+    if (!ValidateAttribIndex(index, "vertexAttribPointer"))
         return;
 
-    if (mBoundArrayBuffer == nullptr)
-        return ErrorInvalidOperation("vertexAttribPointer: must have valid GL_ARRAY_BUFFER binding");
-
-    GLsizei requiredAlignment = 1;
-    switch (type) {
-        case LOCAL_GL_BYTE:
-        case LOCAL_GL_UNSIGNED_BYTE:
-            requiredAlignment = 1;
-            break;
-        case LOCAL_GL_SHORT:
-        case LOCAL_GL_UNSIGNED_SHORT:
-            requiredAlignment = 2;
-            break;
-            // XXX case LOCAL_GL_FIXED:
-        case LOCAL_GL_FLOAT:
-            requiredAlignment = 4;
-            break;
-        default:
-            return ErrorInvalidEnumInfo("vertexAttribPointer: type", type);
-    }
-
-    // requiredAlignment should always be a power of two.
-    GLsizei requiredAlignmentMask = requiredAlignment - 1;
+    if (!ValidateAttribPointer(false, index, size, type, normalized, stride, byteOffset, "vertexAttribPointer"))
+        return;
 
     MOZ_ASSERT(mBoundVertexArray);
     mBoundVertexArray->EnsureAttrib(index);
 
-    if (size < 1 || size > 4)
-        return ErrorInvalidValue("vertexAttribPointer: invalid element size");
-
-    if (stride < 0 || stride > 255) // see WebGL spec section 6.6 "Vertex Attribute Data Stride"
-        return ErrorInvalidValue("vertexAttribPointer: negative or too large stride");
-
-    if (byteOffset < 0)
-        return ErrorInvalidValue("vertexAttribPointer: negative offset");
-
-    if (stride & requiredAlignmentMask) {
-        return ErrorInvalidOperation("vertexAttribPointer: stride doesn't satisfy the alignment "
-                                     "requirement of given type");
-    }
-
-    if (byteOffset & requiredAlignmentMask) {
-        return ErrorInvalidOperation("vertexAttribPointer: byteOffset doesn't satisfy the alignment "
-                                     "requirement of given type");
-
-    }
-
     InvalidateBufferFetching();
 
     /* XXX make work with bufferSubData & heterogeneous types
      if (type != mBoundArrayBuffer->GLType())
      return ErrorInvalidOperation("vertexAttribPointer: type must match bound VBO type: %d != %d", type, mBoundArrayBuffer->GLType());
      */
 
     WebGLVertexAttribData& vd = mBoundVertexArray->mAttribs[index];
 
     vd.buf = mBoundArrayBuffer;
     vd.stride = stride;
     vd.size = size;
     vd.byteOffset = byteOffset;
     vd.type = type;
     vd.normalized = normalized;
+    vd.integer = false;
 
     MakeContextCurrent();
-
-    gl->fVertexAttribPointer(index, size, type, normalized,
-                             stride,
+    gl->fVertexAttribPointer(index, size, type, normalized, stride,
                              reinterpret_cast<void*>(byteOffset));
 }
 
 void
 WebGLContext::VertexAttribDivisor(GLuint index, GLuint divisor)
 {
     if (IsContextLost())
         return;
 
-    if (!CheckAttribIndex(*this, index, "vertexAttribDivisor"))
+    if (!ValidateAttribIndex(index, "vertexAttribDivisor"))
         return;
 
     MOZ_ASSERT(mBoundVertexArray);
     mBoundVertexArray->EnsureAttrib(index);
 
     WebGLVertexAttribData& vd = mBoundVertexArray->mAttribs[index];
     vd.divisor = divisor;
 
--- a/dom/canvas/WebGLVertexArray.h
+++ b/dom/canvas/WebGLVertexArray.h
@@ -69,13 +69,14 @@ protected:
     }
 
     GLuint mGLName;
     nsTArray<WebGLVertexAttribData> mAttribs;
     WebGLRefPtr<WebGLBuffer> mElementArrayBuffer;
 
     friend class WebGLContext;
     friend class WebGLVertexArrayFake;
+    friend class WebGL2Context;
 };
 
 } // namespace mozilla
 
 #endif // WEBGL_VERTEX_ARRAY_H_
--- a/dom/canvas/WebGLVertexArrayFake.cpp
+++ b/dom/canvas/WebGLVertexArrayFake.cpp
@@ -24,18 +24,23 @@ WebGLVertexArrayFake::BindVertexArrayImp
     WebGLRefPtr<WebGLBuffer> prevBuffer = mContext->mBoundArrayBuffer;
     mContext->BindBuffer(LOCAL_GL_ELEMENT_ARRAY_BUFFER, mElementArrayBuffer);
 
     for (size_t i = 0; i < mAttribs.Length(); ++i) {
         const WebGLVertexAttribData& vd = mAttribs[i];
 
         mContext->BindBuffer(LOCAL_GL_ARRAY_BUFFER, vd.buf);
 
-        gl->fVertexAttribPointer(i, vd.size, vd.type, vd.normalized, vd.stride,
-                                 reinterpret_cast<void*>(vd.byteOffset));
+        if (vd.integer) {
+            gl->fVertexAttribIPointer(i, vd.size, vd.type, vd.stride,
+                                      reinterpret_cast<const GLvoid*>(vd.byteOffset));
+        } else {
+            gl->fVertexAttribPointer(i, vd.size, vd.type, vd.normalized, vd.stride,
+                                     reinterpret_cast<const GLvoid*>(vd.byteOffset));
+        }
 
         if (vd.enabled)
             gl->fEnableVertexAttribArray(i);
         else
             gl->fDisableVertexAttribArray(i);
     }
 
     size_t len = prevVertexArray->mAttribs.Length();
--- a/dom/canvas/WebGLVertexAttribData.h
+++ b/dom/canvas/WebGLVertexAttribData.h
@@ -20,26 +20,28 @@ struct WebGLVertexAttribData
         : buf(0)
         , stride(0)
         , size(4)
         , divisor(0) // OpenGL ES 3.0 specs paragraphe 6.2 p240
         , byteOffset(0)
         , type(LOCAL_GL_FLOAT)
         , enabled(false)
         , normalized(false)
+        , integer(false)
     {}
 
     WebGLRefPtr<WebGLBuffer> buf;
     GLuint stride;
     GLuint size;
     GLuint divisor;
     GLuint byteOffset;
     GLenum type;
     bool enabled;
     bool normalized;
+    bool integer;
 
     GLuint componentSize() const {
         switch(type) {
         case LOCAL_GL_BYTE:
             return sizeof(GLbyte);
 
         case LOCAL_GL_UNSIGNED_BYTE:
             return sizeof(GLubyte);
--- a/dom/canvas/moz.build
+++ b/dom/canvas/moz.build
@@ -37,16 +37,17 @@ UNIFIED_SOURCES += [
     'DocumentRendererParent.cpp',
     'ImageData.cpp',
 ]
 
 # WebGL Sources
 UNIFIED_SOURCES += [
     'MurmurHash3.cpp',
     'WebGL1Context.cpp',
+    'WebGL1ContextUniforms.cpp',
     'WebGL2Context.cpp',
     'WebGL2ContextBuffers.cpp',
     'WebGL2ContextDraw.cpp',
     'WebGL2ContextFramebuffers.cpp',
     'WebGL2ContextMRTs.cpp',
     'WebGL2ContextPrograms.cpp',
     'WebGL2ContextQueries.cpp',
     'WebGL2ContextSamplers.cpp',