Bug 1048745 - [WebGL2] Integer vertex attributes. r=jgilbert
authorDan Glastonbury <dglastonbury@mozilla.com>
Tue, 24 Jun 2014 10:56:21 +1000
changeset 232837 e5c404f95a9d010ebfb9df50e9eb9a595a4f2314
parent 232836 9ce25fd6315b7d7cef100d88c96940d5df78f736
child 232839 f5dc77e4a2a8a19566e7f43f8ca009ecb56ec08c
push idunknown
push userunknown
push dateunknown
reviewersjgilbert
bugs1048745
milestone37.0a1
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',