Optimize more front-end VertexArray binding.

Improves perf slightly (1-2%) in the Vulkan VBO state change test.

Bug: angleproject:3014
Change-Id: Ia8082b5b3f5e847a6b2775e896893fa8d38c1afd
Reviewed-on: https://chromium-review.googlesource.com/c/1393904
Commit-Queue: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org>
diff --git a/src/libANGLE/Context.cpp b/src/libANGLE/Context.cpp
index 545a0ac..a4ae976 100644
--- a/src/libANGLE/Context.cpp
+++ b/src/libANGLE/Context.cpp
@@ -4787,7 +4787,7 @@
                                   const void *ptr)
 {
     mState.setVertexAttribPointer(this, index, mState.getTargetBuffer(BufferBinding::Array), size,
-                                  type, ConvertToBool(normalized), false, stride, ptr);
+                                  type, ConvertToBool(normalized), stride, ptr);
     mStateCache.onVertexArrayStateChange(this);
 }
 
@@ -4834,8 +4834,8 @@
                                    GLsizei stride,
                                    const void *pointer)
 {
-    mState.setVertexAttribPointer(this, index, mState.getTargetBuffer(BufferBinding::Array), size,
-                                  type, false, true, stride, pointer);
+    mState.setVertexAttribIPointer(this, index, mState.getTargetBuffer(BufferBinding::Array), size,
+                                   type, stride, pointer);
     mStateCache.onVertexArrayStateChange(this);
 }
 
diff --git a/src/libANGLE/Framebuffer.cpp b/src/libANGLE/Framebuffer.cpp
index bcc7d76..c4e83d1 100644
--- a/src/libANGLE/Framebuffer.cpp
+++ b/src/libANGLE/Framebuffer.cpp
@@ -673,7 +673,7 @@
                           FramebufferAttachment::kDefaultMultiviewLayout,
                           FramebufferAttachment::kDefaultViewportOffsets);
     }
-    mState.mDrawBufferTypeMask.setIndex(getDrawbufferWriteType(0), 0);
+    SetComponentTypeMask(getDrawbufferWriteType(0), 0, &mState.mDrawBufferTypeMask);
 }
 
 Framebuffer::Framebuffer(rx::GLImplFactory *factory)
@@ -684,7 +684,7 @@
       mDirtyStencilAttachmentBinding(this, DIRTY_BIT_STENCIL_ATTACHMENT)
 {
     mDirtyColorAttachmentBindings.emplace_back(this, DIRTY_BIT_COLOR_ATTACHMENT_0);
-    mState.mDrawBufferTypeMask.setIndex(getDrawbufferWriteType(0), 0);
+    SetComponentTypeMask(getDrawbufferWriteType(0), 0, &mState.mDrawBufferTypeMask);
 }
 
 Framebuffer::~Framebuffer()
@@ -871,7 +871,7 @@
 
     for (size_t index = 0; index < count; ++index)
     {
-        mState.mDrawBufferTypeMask.setIndex(getDrawbufferWriteType(index), index);
+        SetComponentTypeMask(getDrawbufferWriteType(index), index, &mState.mDrawBufferTypeMask);
 
         if (drawStates[index] != GL_NONE && mState.mColorAttachments[index].isAttached())
         {
@@ -885,23 +885,24 @@
     return mState.getDrawBuffer(drawBuffer);
 }
 
-GLenum Framebuffer::getDrawbufferWriteType(size_t drawBuffer) const
+ComponentType Framebuffer::getDrawbufferWriteType(size_t drawBuffer) const
 {
     const FramebufferAttachment *attachment = mState.getDrawBuffer(drawBuffer);
     if (attachment == nullptr)
     {
-        return GL_NONE;
+        return ComponentType::NoType;
     }
 
     GLenum componentType = attachment->getFormat().info->componentType;
     switch (componentType)
     {
         case GL_INT:
+            return ComponentType::Int;
         case GL_UNSIGNED_INT:
-            return componentType;
+            return ComponentType::UnsignedInt;
 
         default:
-            return GL_FLOAT;
+            return ComponentType::Float;
     }
 }
 
@@ -1761,7 +1762,8 @@
             // formsRenderingFeedbackLoopWith
             bool enabled = (type != GL_NONE && getDrawBufferState(colorIndex) != GL_NONE);
             mState.mEnabledDrawBuffers.set(colorIndex, enabled);
-            mState.mDrawBufferTypeMask.setIndex(getDrawbufferWriteType(colorIndex), colorIndex);
+            SetComponentTypeMask(getDrawbufferWriteType(colorIndex), colorIndex,
+                                 &mState.mDrawBufferTypeMask);
         }
         break;
     }
diff --git a/src/libANGLE/Framebuffer.h b/src/libANGLE/Framebuffer.h
index c936c95..69cf05f 100644
--- a/src/libANGLE/Framebuffer.h
+++ b/src/libANGLE/Framebuffer.h
@@ -217,7 +217,7 @@
     const std::vector<GLenum> &getDrawBufferStates() const;
     void setDrawBuffers(size_t count, const GLenum *buffers);
     const FramebufferAttachment *getDrawBuffer(size_t drawBuffer) const;
-    GLenum getDrawbufferWriteType(size_t drawBuffer) const;
+    ComponentType getDrawbufferWriteType(size_t drawBuffer) const;
     ComponentTypeMask getDrawBufferTypeMask() const;
     DrawBufferMask getDrawBufferMask() const;
     bool hasEnabledDrawBuffer() const;
diff --git a/src/libANGLE/MemoryProgramCache.cpp b/src/libANGLE/MemoryProgramCache.cpp
index 8d5617f..c1eb7c0 100644
--- a/src/libANGLE/MemoryProgramCache.cpp
+++ b/src/libANGLE/MemoryProgramCache.cpp
@@ -246,8 +246,8 @@
 
     static_assert(MAX_VERTEX_ATTRIBS * 2 <= sizeof(uint32_t) * 8,
                   "All bits of mAttributesTypeMask types and mask fit into 32 bits each");
-    state->mAttributesTypeMask.from_ulong(stream.readInt<uint32_t>());
-    state->mAttributesMask = stream.readInt<gl::AttributesMask>();
+    state->mAttributesTypeMask = gl::ComponentTypeMask(stream.readInt<uint32_t>());
+    state->mAttributesMask     = stream.readInt<gl::AttributesMask>();
 
     static_assert(MAX_VERTEX_ATTRIBS <= sizeof(unsigned long) * 8,
                   "Too many vertex attribs for mask");
@@ -404,7 +404,7 @@
     static_assert(IMPLEMENTATION_MAX_DRAW_BUFFERS * 2 <= 8 * sizeof(uint32_t),
                   "All bits of mDrawBufferTypeMask and mActiveOutputVariables types and mask fit "
                   "into 32 bits each");
-    state->mDrawBufferTypeMask.from_ulong(stream.readInt<uint32_t>());
+    state->mDrawBufferTypeMask    = gl::ComponentTypeMask(stream.readInt<uint32_t>());
     state->mActiveOutputVariables = stream.readInt<gl::DrawBufferMask>();
 
     unsigned int samplerRangeLow  = stream.readInt<unsigned int>();
diff --git a/src/libANGLE/Program.cpp b/src/libANGLE/Program.cpp
index 3938ba6..1bda45c 100644
--- a/src/libANGLE/Program.cpp
+++ b/src/libANGLE/Program.cpp
@@ -3097,8 +3097,10 @@
             // gl_VertexID and gl_InstanceID are active attributes but don't have a bound attribute.
             if (!attribute.isBuiltIn())
             {
-                mState.mAttributesTypeMask.setIndex(VariableComponentType(attribute.type),
-                                                    location);
+                ComponentType componentType =
+                    GLenumToComponentType(VariableComponentType(attribute.type));
+
+                SetComponentTypeMask(componentType, location, &mState.mAttributesTypeMask);
                 mState.mAttributesMask.set(location);
             }
         }
@@ -3648,7 +3650,9 @@
             ASSERT(location < mState.mActiveOutputVariables.size());
             mState.mActiveOutputVariables.set(location);
             mState.mOutputVariableTypes[location] = VariableComponentType(outputVariable.type);
-            mState.mDrawBufferTypeMask.setIndex(mState.mOutputVariableTypes[location], location);
+            ComponentType componentType =
+                GLenumToComponentType(mState.mOutputVariableTypes[location]);
+            SetComponentTypeMask(componentType, location, &mState.mDrawBufferTypeMask);
         }
     }
 
diff --git a/src/libANGLE/State.cpp b/src/libANGLE/State.cpp
index 2745b84..fb65fa3 100644
--- a/src/libANGLE/State.cpp
+++ b/src/libANGLE/State.cpp
@@ -355,7 +355,7 @@
     // Set all indexes in state attributes type mask to float (default)
     for (int i = 0; i < MAX_VERTEX_ATTRIBS; i++)
     {
-        mCurrentValuesTypeMask.setIndex(GL_FLOAT, i);
+        SetComponentTypeMask(ComponentType::Float, i, &mCurrentValuesTypeMask);
     }
 
     mUniformBuffers.resize(caps.maxUniformBufferBindings);
@@ -1621,7 +1621,7 @@
     mVertexAttribCurrentValues[index].setFloatValues(values);
     mDirtyBits.set(DIRTY_BIT_CURRENT_VALUES);
     mDirtyCurrentValues.set(index);
-    mCurrentValuesTypeMask.setIndex(GL_FLOAT, index);
+    SetComponentTypeMask(ComponentType::Float, index, &mCurrentValuesTypeMask);
 }
 
 void State::setVertexAttribu(GLuint index, const GLuint values[4])
@@ -1630,7 +1630,7 @@
     mVertexAttribCurrentValues[index].setUnsignedIntValues(values);
     mDirtyBits.set(DIRTY_BIT_CURRENT_VALUES);
     mDirtyCurrentValues.set(index);
-    mCurrentValuesTypeMask.setIndex(GL_UNSIGNED_INT, index);
+    SetComponentTypeMask(ComponentType::UnsignedInt, index, &mCurrentValuesTypeMask);
 }
 
 void State::setVertexAttribi(GLuint index, const GLint values[4])
@@ -1639,7 +1639,7 @@
     mVertexAttribCurrentValues[index].setIntValues(values);
     mDirtyBits.set(DIRTY_BIT_CURRENT_VALUES);
     mDirtyCurrentValues.set(index);
-    mCurrentValuesTypeMask.setIndex(GL_INT, index);
+    SetComponentTypeMask(ComponentType::Int, index, &mCurrentValuesTypeMask);
 }
 
 void State::setVertexAttribDivisor(const Context *context, GLuint index, GLuint divisor)
diff --git a/src/libANGLE/State.h b/src/libANGLE/State.h
index e3df1b8..df67277 100644
--- a/src/libANGLE/State.h
+++ b/src/libANGLE/State.h
@@ -347,12 +347,24 @@
                                              GLint size,
                                              VertexAttribType type,
                                              bool normalized,
-                                             bool pureInteger,
                                              GLsizei stride,
                                              const void *pointer)
     {
         mVertexArray->setVertexAttribPointer(context, attribNum, boundBuffer, size, type,
-                                             normalized, pureInteger, stride, pointer);
+                                             normalized, stride, pointer);
+        mDirtyObjects.set(DIRTY_OBJECT_VERTEX_ARRAY);
+    }
+
+    ANGLE_INLINE void setVertexAttribIPointer(const Context *context,
+                                              unsigned int attribNum,
+                                              Buffer *boundBuffer,
+                                              GLint size,
+                                              VertexAttribType type,
+                                              GLsizei stride,
+                                              const void *pointer)
+    {
+        mVertexArray->setVertexAttribIPointer(context, attribNum, boundBuffer, size, type, stride,
+                                              pointer);
         mDirtyObjects.set(DIRTY_OBJECT_VERTEX_ARRAY);
     }
 
diff --git a/src/libANGLE/VertexArray.cpp b/src/libANGLE/VertexArray.cpp
index 9b0e912..e475d42 100644
--- a/src/libANGLE/VertexArray.cpp
+++ b/src/libANGLE/VertexArray.cpp
@@ -24,30 +24,30 @@
     return (subjectIndex == MAX_VERTEX_ATTRIBS);
 }
 
-ANGLE_INLINE GLenum GetVertexAttributeBaseType(const VertexAttribute &attrib)
+ANGLE_INLINE ComponentType GetVertexAttributeComponentType(bool pureInteger, VertexAttribType type)
 {
-    if (attrib.pureInteger)
+    if (pureInteger)
     {
-        switch (attrib.type)
+        switch (type)
         {
             case VertexAttribType::Byte:
             case VertexAttribType::Short:
             case VertexAttribType::Int:
-                return GL_INT;
+                return ComponentType::Int;
 
             case VertexAttribType::UnsignedByte:
             case VertexAttribType::UnsignedShort:
             case VertexAttribType::UnsignedInt:
-                return GL_UNSIGNED_INT;
+                return ComponentType::UnsignedInt;
 
             default:
                 UNREACHABLE();
-                return GL_NONE;
+                return ComponentType::NoType;
         }
     }
     else
     {
-        return GL_FLOAT;
+        return ComponentType::Float;
     }
 }
 
@@ -321,23 +321,16 @@
     }
 }
 
-ANGLE_INLINE void VertexArray::setVertexAttribFormatImpl(size_t attribIndex,
+ANGLE_INLINE void VertexArray::setVertexAttribFormatImpl(VertexAttribute *attrib,
                                                          GLint size,
                                                          VertexAttribType type,
                                                          bool normalized,
-                                                         bool pureInteger,
                                                          GLuint relativeOffset)
 {
-    ASSERT(attribIndex < getMaxAttribs());
-
-    VertexAttribute *attrib = &mState.mVertexAttributes[attribIndex];
-
     attrib->size           = size;
     attrib->type           = type;
     attrib->normalized     = normalized;
-    attrib->pureInteger    = pureInteger;
     attrib->relativeOffset = relativeOffset;
-    mState.mVertexAttributesTypeMask.setIndex(GetVertexAttributeBaseType(*attrib), attribIndex);
 }
 
 void VertexArray::setVertexAttribFormat(size_t attribIndex,
@@ -347,10 +340,15 @@
                                         bool pureInteger,
                                         GLuint relativeOffset)
 {
-    setVertexAttribFormatImpl(attribIndex, size, type, normalized, pureInteger, relativeOffset);
+    VertexAttribute &attrib = mState.mVertexAttributes[attribIndex];
+    attrib.pureInteger      = pureInteger;
+
+    ComponentType componentType = GetVertexAttributeComponentType(pureInteger, type);
+    SetComponentTypeMask(componentType, attribIndex, &mState.mVertexAttributesTypeMask);
+
+    setVertexAttribFormatImpl(&attrib, size, type, normalized, relativeOffset);
     setDirtyAttribBit(attribIndex, DIRTY_ATTRIB_FORMAT);
 
-    VertexAttribute &attrib = mState.mVertexAttributes[attribIndex];
     attrib.updateCachedElementLimit(mState.mVertexBindings[attrib.bindingIndex]);
 }
 
@@ -383,24 +381,28 @@
         mState.mCachedMappedArrayBuffers & mState.mEnabledAttributesMask;
 }
 
-void VertexArray::setVertexAttribPointer(const Context *context,
-                                         size_t attribIndex,
-                                         gl::Buffer *boundBuffer,
-                                         GLint size,
-                                         VertexAttribType type,
-                                         bool normalized,
-                                         bool pureInteger,
-                                         GLsizei stride,
-                                         const void *pointer)
+ANGLE_INLINE void VertexArray::setVertexAttribPointerImpl(const Context *context,
+                                                          ComponentType componentType,
+                                                          bool pureInteger,
+                                                          size_t attribIndex,
+                                                          Buffer *boundBuffer,
+                                                          GLint size,
+                                                          VertexAttribType type,
+                                                          bool normalized,
+                                                          GLsizei stride,
+                                                          const void *pointer)
 {
     ASSERT(attribIndex < getMaxAttribs());
 
     GLintptr offset = boundBuffer ? reinterpret_cast<GLintptr>(pointer) : 0;
 
-    setVertexAttribFormatImpl(attribIndex, size, type, normalized, pureInteger, 0);
-    setVertexAttribBinding(context, attribIndex, static_cast<GLuint>(attribIndex));
-
     VertexAttribute &attrib = mState.mVertexAttributes[attribIndex];
+    attrib.pureInteger      = pureInteger;
+
+    SetComponentTypeMask(componentType, attribIndex, &mState.mVertexAttributesTypeMask);
+
+    setVertexAttribFormatImpl(&attrib, size, type, normalized, 0);
+    setVertexAttribBinding(context, attribIndex, static_cast<GLuint>(attribIndex));
 
     GLsizei effectiveStride =
         stride != 0 ? stride : static_cast<GLsizei>(ComputeVertexAttributeTypeSize(attrib));
@@ -415,6 +417,32 @@
                                                    boundBuffer == nullptr && pointer == nullptr);
 }
 
+void VertexArray::setVertexAttribPointer(const Context *context,
+                                         size_t attribIndex,
+                                         gl::Buffer *boundBuffer,
+                                         GLint size,
+                                         VertexAttribType type,
+                                         bool normalized,
+                                         GLsizei stride,
+                                         const void *pointer)
+{
+    setVertexAttribPointerImpl(context, ComponentType::Float, false, attribIndex, boundBuffer, size,
+                               type, normalized, stride, pointer);
+}
+
+void VertexArray::setVertexAttribIPointer(const Context *context,
+                                          size_t attribIndex,
+                                          gl::Buffer *boundBuffer,
+                                          GLint size,
+                                          VertexAttribType type,
+                                          GLsizei stride,
+                                          const void *pointer)
+{
+    ComponentType componentType = GetVertexAttributeComponentType(true, type);
+    setVertexAttribPointerImpl(context, componentType, true, attribIndex, boundBuffer, size, type,
+                               false, stride, pointer);
+}
+
 angle::Result VertexArray::syncState(const Context *context)
 {
     if (mDirtyBits.any())
diff --git a/src/libANGLE/VertexArray.h b/src/libANGLE/VertexArray.h
index 19f32e6..891d217 100644
--- a/src/libANGLE/VertexArray.h
+++ b/src/libANGLE/VertexArray.h
@@ -119,15 +119,24 @@
     void detachBuffer(const Context *context, GLuint bufferName);
     void setVertexAttribDivisor(const Context *context, size_t index, GLuint divisor);
     void enableAttribute(size_t attribIndex, bool enabledState);
+
     void setVertexAttribPointer(const Context *context,
                                 size_t attribIndex,
                                 Buffer *boundBuffer,
                                 GLint size,
                                 VertexAttribType type,
                                 bool normalized,
-                                bool pureInteger,
                                 GLsizei stride,
                                 const void *pointer);
+
+    void setVertexAttribIPointer(const Context *context,
+                                 size_t attribIndex,
+                                 Buffer *boundBuffer,
+                                 GLint size,
+                                 VertexAttribType type,
+                                 GLsizei stride,
+                                 const void *pointer);
+
     void setVertexAttribFormat(size_t attribIndex,
                                GLint size,
                                VertexAttribType type,
@@ -141,11 +150,10 @@
                           GLsizei stride);
     void setVertexAttribBinding(const Context *context, size_t attribIndex, GLuint bindingIndex);
     void setVertexBindingDivisor(size_t bindingIndex, GLuint divisor);
-    void setVertexAttribFormatImpl(size_t attribIndex,
+    void setVertexAttribFormatImpl(VertexAttribute *attrib,
                                    GLint size,
                                    VertexAttribType type,
                                    bool normalized,
-                                   bool pureInteger,
                                    GLuint relativeOffset);
     void bindVertexBufferImpl(const Context *context,
                               size_t bindingIndex,
@@ -296,6 +304,17 @@
                                     const void *indices,
                                     IndexRange *indexRangeOut) const;
 
+    void setVertexAttribPointerImpl(const Context *context,
+                                    ComponentType componentType,
+                                    bool pureInteger,
+                                    size_t attribIndex,
+                                    Buffer *boundBuffer,
+                                    GLint size,
+                                    VertexAttribType type,
+                                    bool normalized,
+                                    GLsizei stride,
+                                    const void *pointer);
+
     GLuint mId;
 
     VertexArrayState mState;
diff --git a/src/libANGLE/VertexAttribute.cpp b/src/libANGLE/VertexAttribute.cpp
index 3bd6727..857f2e5 100644
--- a/src/libANGLE/VertexAttribute.cpp
+++ b/src/libANGLE/VertexAttribute.cpp
@@ -145,40 +145,6 @@
     mCachedElementLimit = elementLimit.ValueOrDefault(kIntegerOverflow);
 }
 
-size_t ComputeVertexAttributeTypeSize(const VertexAttribute &attrib)
-{
-    switch (attrib.type)
-    {
-        case VertexAttribType::Byte:
-            return attrib.size * sizeof(GLbyte);
-        case VertexAttribType::UnsignedByte:
-            return attrib.size * sizeof(GLubyte);
-        case VertexAttribType::Short:
-            return attrib.size * sizeof(GLshort);
-        case VertexAttribType::UnsignedShort:
-            return attrib.size * sizeof(GLushort);
-        case VertexAttribType::Int:
-            return attrib.size * sizeof(GLint);
-        case VertexAttribType::UnsignedInt:
-            return attrib.size * sizeof(GLuint);
-        case VertexAttribType::Float:
-            return attrib.size * sizeof(GLfloat);
-        case VertexAttribType::HalfFloat:
-            return attrib.size * sizeof(GLhalf);
-        case VertexAttribType::Fixed:
-            return attrib.size * sizeof(GLfixed);
-        case VertexAttribType::Int2101010:
-            // Packed attribute types don't scale by their component size.
-            return 4;
-        case VertexAttribType::UnsignedInt2101010:
-            // Packed attribute types don't scale by their component size.
-            return 4;
-        default:
-            UNREACHABLE();
-            return 0;
-    }
-}
-
 size_t ComputeVertexAttributeStride(const VertexAttribute &attrib, const VertexBinding &binding)
 {
     // In ES 3.1, VertexAttribPointer will store the type size in the binding stride.
diff --git a/src/libANGLE/VertexAttribute.h b/src/libANGLE/VertexAttribute.h
index 3fb951f..de0cb07 100644
--- a/src/libANGLE/VertexAttribute.h
+++ b/src/libANGLE/VertexAttribute.h
@@ -104,7 +104,39 @@
     GLint64 mCachedElementLimit;
 };
 
-size_t ComputeVertexAttributeTypeSize(const VertexAttribute &attrib);
+ANGLE_INLINE size_t ComputeVertexAttributeTypeSize(const VertexAttribute &attrib)
+{
+    switch (attrib.type)
+    {
+        case VertexAttribType::Byte:
+            return attrib.size * sizeof(GLbyte);
+        case VertexAttribType::UnsignedByte:
+            return attrib.size * sizeof(GLubyte);
+        case VertexAttribType::Short:
+            return attrib.size * sizeof(GLshort);
+        case VertexAttribType::UnsignedShort:
+            return attrib.size * sizeof(GLushort);
+        case VertexAttribType::Int:
+            return attrib.size * sizeof(GLint);
+        case VertexAttribType::UnsignedInt:
+            return attrib.size * sizeof(GLuint);
+        case VertexAttribType::Float:
+            return attrib.size * sizeof(GLfloat);
+        case VertexAttribType::HalfFloat:
+            return attrib.size * sizeof(GLhalf);
+        case VertexAttribType::Fixed:
+            return attrib.size * sizeof(GLfixed);
+        case VertexAttribType::Int2101010:
+            // Packed attribute types don't scale by their component size.
+            return 4;
+        case VertexAttribType::UnsignedInt2101010:
+            // Packed attribute types don't scale by their component size.
+            return 4;
+        default:
+            UNREACHABLE();
+            return 0;
+    }
+}
 
 // Warning: you should ensure binding really matches attrib.bindingIndex before using this function.
 size_t ComputeVertexAttributeStride(const VertexAttribute &attrib, const VertexBinding &binding);
diff --git a/src/libANGLE/angletypes.cpp b/src/libANGLE/angletypes.cpp
index ad29013..1b51947 100644
--- a/src/libANGLE/angletypes.cpp
+++ b/src/libANGLE/angletypes.cpp
@@ -314,72 +314,15 @@
     return !(lhs == rhs);
 }
 
-ComponentTypeMask::ComponentTypeMask()
+bool ValidateComponentTypeMasks(unsigned long outputTypes,
+                                unsigned long inputTypes,
+                                unsigned long outputMask,
+                                unsigned long inputMask)
 {
-    mTypeMask.reset();
-}
-
-ComponentTypeMask::ComponentTypeMask(const ComponentTypeMask &other) = default;
-
-ComponentTypeMask::~ComponentTypeMask() = default;
-
-void ComponentTypeMask::reset()
-{
-    mTypeMask.reset();
-}
-
-bool ComponentTypeMask::none()
-{
-    return mTypeMask.none();
-}
-
-void ComponentTypeMask::setIndex(GLenum type, size_t index)
-{
-    ASSERT(index <= MAX_COMPONENT_TYPE_MASK_INDEX);
-
-    mTypeMask &= ~(0x10001 << index);
-
-    uint32_t m = 0;
-    switch (type)
-    {
-        case GL_INT:
-            m = 0x00001;
-            break;
-        case GL_UNSIGNED_INT:
-            m = 0x10000;
-            break;
-        case GL_FLOAT:
-            m = 0x10001;
-            break;
-        case GL_NONE:
-            m = 0x00000;
-            break;
-        default:
-            UNREACHABLE();
-    }
-
-    mTypeMask |= m << index;
-}
-
-unsigned long ComponentTypeMask::to_ulong() const
-{
-    return mTypeMask.to_ulong();
-}
-
-void ComponentTypeMask::from_ulong(unsigned long mask)
-{
-    mTypeMask = angle::BitSet<MAX_COMPONENT_TYPE_MASK_INDEX * 2>(mask);
-}
-
-bool ComponentTypeMask::Validate(unsigned long outputTypes,
-                                 unsigned long inputTypes,
-                                 unsigned long outputMask,
-                                 unsigned long inputMask)
-{
-    static_assert(IMPLEMENTATION_MAX_DRAW_BUFFERS <= MAX_COMPONENT_TYPE_MASK_INDEX,
+    static_assert(IMPLEMENTATION_MAX_DRAW_BUFFERS <= kMaxComponentTypeMaskIndex,
                   "Output/input masks should fit into 16 bits - 1 bit per draw buffer. The "
                   "corresponding type masks should fit into 32 bits - 2 bits per draw buffer.");
-    static_assert(MAX_VERTEX_ATTRIBS <= MAX_COMPONENT_TYPE_MASK_INDEX,
+    static_assert(MAX_VERTEX_ATTRIBS <= kMaxComponentTypeMaskIndex,
                   "Output/input masks should fit into 16 bits - 1 bit per attrib. The "
                   "corresponding type masks should fit into 32 bits - 2 bits per attrib.");
 
@@ -389,8 +332,8 @@
     // with the elswewhere used DrawBufferMask or AttributeMask.
 
     // OR the masks with themselves, shifted 16 bits. This is to match our split type bits.
-    outputMask |= (outputMask << MAX_COMPONENT_TYPE_MASK_INDEX);
-    inputMask |= (inputMask << MAX_COMPONENT_TYPE_MASK_INDEX);
+    outputMask |= (outputMask << kMaxComponentTypeMaskIndex);
+    inputMask |= (inputMask << kMaxComponentTypeMaskIndex);
 
     // To validate:
     // 1. Remove any indexes that are not enabled in the input (& inputMask)
diff --git a/src/libANGLE/angletypes.h b/src/libANGLE/angletypes.h
index 9daa801..12e4122 100644
--- a/src/libANGLE/angletypes.h
+++ b/src/libANGLE/angletypes.h
@@ -383,27 +383,54 @@
 template <typename T>
 using TexLevelArray = std::array<T, IMPLEMENTATION_MAX_TEXTURE_LEVELS>;
 
-constexpr size_t MAX_COMPONENT_TYPE_MASK_INDEX = 16;
-struct ComponentTypeMask final
+enum class ComponentType
 {
-    ComponentTypeMask();
-    ComponentTypeMask(const ComponentTypeMask &other);
-    ~ComponentTypeMask();
-    void reset();
-    bool none();
-    void setIndex(GLenum type, size_t index);
-    unsigned long to_ulong() const;
-    void from_ulong(unsigned long mask);
-    static bool Validate(unsigned long outputTypes,
-                         unsigned long inputTypes,
-                         unsigned long outputMask,
-                         unsigned long inputMask);
-
-  private:
-    // Each index type is represented by 2 bits
-    angle::BitSet<MAX_COMPONENT_TYPE_MASK_INDEX * 2> mTypeMask;
+    Float       = 0,
+    Int         = 1,
+    UnsignedInt = 2,
+    NoType      = 3,
+    EnumCount   = 4,
+    InvalidEnum = 4,
 };
 
+constexpr ComponentType GLenumToComponentType(GLenum componentType)
+{
+    switch (componentType)
+    {
+        case GL_FLOAT:
+            return ComponentType::Float;
+        case GL_INT:
+            return ComponentType::Int;
+        case GL_UNSIGNED_INT:
+            return ComponentType::UnsignedInt;
+        case GL_NONE:
+            return ComponentType::NoType;
+        default:
+            return ComponentType::InvalidEnum;
+    }
+}
+
+constexpr angle::PackedEnumMap<ComponentType, uint32_t> kComponentMasks = {{
+    {ComponentType::Float, 0x10001},
+    {ComponentType::Int, 0x00001},
+    {ComponentType::UnsignedInt, 0x10000},
+}};
+
+constexpr size_t kMaxComponentTypeMaskIndex = 16;
+using ComponentTypeMask                     = angle::BitSet<kMaxComponentTypeMaskIndex * 2>;
+
+ANGLE_INLINE void SetComponentTypeMask(ComponentType type, size_t index, ComponentTypeMask *mask)
+{
+    ASSERT(index <= kMaxComponentTypeMaskIndex);
+    *mask &= ~(0x10001 << index);
+    *mask |= kComponentMasks[type] << index;
+}
+
+bool ValidateComponentTypeMasks(unsigned long outputTypes,
+                                unsigned long inputTypes,
+                                unsigned long outputMask,
+                                unsigned long inputMask);
+
 using ContextID = uintptr_t;
 
 constexpr size_t kCubeFaceCount = 6;
diff --git a/src/libANGLE/validationES.cpp b/src/libANGLE/validationES.cpp
index 976241a..b427aba 100644
--- a/src/libANGLE/validationES.cpp
+++ b/src/libANGLE/validationES.cpp
@@ -367,10 +367,10 @@
     const Program *program         = context->getState().getLinkedProgram(context);
     const Framebuffer *framebuffer = context->getState().getDrawFramebuffer();
 
-    return ComponentTypeMask::Validate(program->getDrawBufferTypeMask().to_ulong(),
-                                       framebuffer->getDrawBufferTypeMask().to_ulong(),
-                                       program->getActiveOutputVariables().to_ulong(),
-                                       framebuffer->getDrawBufferMask().to_ulong());
+    return ValidateComponentTypeMasks(program->getDrawBufferTypeMask().to_ulong(),
+                                      framebuffer->getDrawBufferTypeMask().to_ulong(),
+                                      program->getActiveOutputVariables().to_ulong(),
+                                      framebuffer->getDrawBufferMask().to_ulong());
 }
 
 bool ValidateVertexShaderAttributeTypeMatch(Context *context)
@@ -383,13 +383,13 @@
     unsigned long vaoAttribTypeBits          = vao->getAttributesTypeMask().to_ulong();
     unsigned long vaoAttribEnabledMask       = vao->getAttributesMask().to_ulong();
 
-    vaoAttribEnabledMask |= vaoAttribEnabledMask << MAX_COMPONENT_TYPE_MASK_INDEX;
+    vaoAttribEnabledMask |= vaoAttribEnabledMask << kMaxComponentTypeMaskIndex;
     vaoAttribTypeBits = (vaoAttribEnabledMask & vaoAttribTypeBits);
     vaoAttribTypeBits |= (~vaoAttribEnabledMask & stateCurrentValuesTypeBits);
 
-    return ComponentTypeMask::Validate(program->getAttributesTypeMask().to_ulong(),
-                                       vaoAttribTypeBits, program->getAttributesMask().to_ulong(),
-                                       0xFFFF);
+    return ValidateComponentTypeMasks(program->getAttributesTypeMask().to_ulong(),
+                                      vaoAttribTypeBits, program->getAttributesMask().to_ulong(),
+                                      0xFFFF);
 }
 
 bool IsCompatibleDrawModeWithGeometryShader(PrimitiveMode drawMode,