Add PackedEnumBitSet, use it for buffer binding validation

Includes angle::BitSetT changes from jmadill@chromium.org

BUG=angleproject:2169

Change-Id: I9f896613f5c6cdc91281cb9a00134f67291870d9
Reviewed-on: https://chromium-review.googlesource.com/804177
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
diff --git a/src/common/bitset_utils.h b/src/common/bitset_utils.h
index 4166a56..7febb78 100644
--- a/src/common/bitset_utils.h
+++ b/src/common/bitset_utils.h
@@ -22,7 +22,7 @@
 namespace angle
 {
 
-template <size_t N, typename BitsT>
+template <size_t N, typename BitsT, typename ParamT = std::size_t>
 class BitSetT final
 {
   public:
@@ -73,10 +73,10 @@
     bool operator==(const BitSetT &other) const;
     bool operator!=(const BitSetT &other) const;
 
-    constexpr bool operator[](std::size_t pos) const;
-    Reference operator[](std::size_t pos) { return Reference(this, pos); }
+    constexpr bool operator[](ParamT pos) const;
+    Reference operator[](ParamT pos) { return Reference(this, pos); }
 
-    bool test(std::size_t pos) const;
+    bool test(ParamT pos) const;
 
     bool all() const;
     bool any() const;
@@ -96,13 +96,13 @@
     BitSetT &operator>>=(std::size_t pos);
 
     BitSetT &set();
-    BitSetT &set(std::size_t pos, bool value = true);
+    BitSetT &set(ParamT pos, bool value = true);
 
     BitSetT &reset();
-    BitSetT &reset(std::size_t pos);
+    BitSetT &reset(ParamT pos);
 
     BitSetT &flip();
-    BitSetT &flip(std::size_t pos);
+    BitSetT &flip(ParamT pos);
 
     unsigned long to_ulong() const { return static_cast<unsigned long>(mBits); }
     BitsT bits() const { return mBits; }
@@ -111,7 +111,10 @@
     Iterator end() const { return Iterator(BitSetT()); }
 
   private:
-    constexpr static BitsT Bit(std::size_t x) { return (static_cast<BitsT>(1) << x); }
+    constexpr static BitsT Bit(ParamT x)
+    {
+        return (static_cast<BitsT>(1) << static_cast<size_t>(x));
+    }
     constexpr static BitsT Mask(std::size_t x) { return ((Bit(x - 1) - 1) << 1) + 1; }
 
     BitsT mBits;
@@ -202,148 +205,148 @@
     return 0;
 }
 
-template <size_t N, typename BitsT>
-BitSetT<N, BitsT>::BitSetT() : mBits(0)
+template <size_t N, typename BitsT, typename ParamT>
+BitSetT<N, BitsT, ParamT>::BitSetT() : mBits(0)
 {
     static_assert(N > 0, "Bitset type cannot support zero bits.");
     static_assert(N <= sizeof(BitsT) * 8, "Bitset type cannot support a size this large.");
 }
 
-template <size_t N, typename BitsT>
-BitSetT<N, BitsT>::BitSetT(BitsT value) : mBits(value & Mask(N))
+template <size_t N, typename BitsT, typename ParamT>
+BitSetT<N, BitsT, ParamT>::BitSetT(BitsT value) : mBits(value & Mask(N))
 {
 }
 
-template <size_t N, typename BitsT>
-BitSetT<N, BitsT>::~BitSetT()
+template <size_t N, typename BitsT, typename ParamT>
+BitSetT<N, BitsT, ParamT>::~BitSetT()
 {
 }
 
-template <size_t N, typename BitsT>
-BitSetT<N, BitsT>::BitSetT(const BitSetT &other) : mBits(other.mBits)
+template <size_t N, typename BitsT, typename ParamT>
+BitSetT<N, BitsT, ParamT>::BitSetT(const BitSetT &other) : mBits(other.mBits)
 {
 }
 
-template <size_t N, typename BitsT>
-BitSetT<N, BitsT> &BitSetT<N, BitsT>::operator=(const BitSetT &other)
+template <size_t N, typename BitsT, typename ParamT>
+BitSetT<N, BitsT, ParamT> &BitSetT<N, BitsT, ParamT>::operator=(const BitSetT &other)
 {
     mBits = other.mBits;
     return *this;
 }
 
-template <size_t N, typename BitsT>
-bool BitSetT<N, BitsT>::operator==(const BitSetT &other) const
+template <size_t N, typename BitsT, typename ParamT>
+bool BitSetT<N, BitsT, ParamT>::operator==(const BitSetT &other) const
 {
     return mBits == other.mBits;
 }
 
-template <size_t N, typename BitsT>
-bool BitSetT<N, BitsT>::operator!=(const BitSetT &other) const
+template <size_t N, typename BitsT, typename ParamT>
+bool BitSetT<N, BitsT, ParamT>::operator!=(const BitSetT &other) const
 {
     return mBits != other.mBits;
 }
 
-template <size_t N, typename BitsT>
-constexpr bool BitSetT<N, BitsT>::operator[](std::size_t pos) const
+template <size_t N, typename BitsT, typename ParamT>
+constexpr bool BitSetT<N, BitsT, ParamT>::operator[](ParamT pos) const
 {
     return test(pos);
 }
 
-template <size_t N, typename BitsT>
-bool BitSetT<N, BitsT>::test(std::size_t pos) const
+template <size_t N, typename BitsT, typename ParamT>
+bool BitSetT<N, BitsT, ParamT>::test(ParamT pos) const
 {
     return (mBits & Bit(pos)) != 0;
 }
 
-template <size_t N, typename BitsT>
-bool BitSetT<N, BitsT>::all() const
+template <size_t N, typename BitsT, typename ParamT>
+bool BitSetT<N, BitsT, ParamT>::all() const
 {
     ASSERT(mBits == (mBits & Mask(N)));
     return mBits == Mask(N);
 }
 
-template <size_t N, typename BitsT>
-bool BitSetT<N, BitsT>::any() const
+template <size_t N, typename BitsT, typename ParamT>
+bool BitSetT<N, BitsT, ParamT>::any() const
 {
     ASSERT(mBits == (mBits & Mask(N)));
     return (mBits != 0);
 }
 
-template <size_t N, typename BitsT>
-bool BitSetT<N, BitsT>::none() const
+template <size_t N, typename BitsT, typename ParamT>
+bool BitSetT<N, BitsT, ParamT>::none() const
 {
     ASSERT(mBits == (mBits & Mask(N)));
     return (mBits == 0);
 }
 
-template <size_t N, typename BitsT>
-std::size_t BitSetT<N, BitsT>::count() const
+template <size_t N, typename BitsT, typename ParamT>
+std::size_t BitSetT<N, BitsT, ParamT>::count() const
 {
     return gl::BitCount(mBits);
 }
 
-template <size_t N, typename BitsT>
-BitSetT<N, BitsT> &BitSetT<N, BitsT>::operator&=(const BitSetT &other)
+template <size_t N, typename BitsT, typename ParamT>
+BitSetT<N, BitsT, ParamT> &BitSetT<N, BitsT, ParamT>::operator&=(const BitSetT &other)
 {
     mBits &= other.mBits;
     return *this;
 }
 
-template <size_t N, typename BitsT>
-BitSetT<N, BitsT> &BitSetT<N, BitsT>::operator|=(const BitSetT &other)
+template <size_t N, typename BitsT, typename ParamT>
+BitSetT<N, BitsT, ParamT> &BitSetT<N, BitsT, ParamT>::operator|=(const BitSetT &other)
 {
     mBits |= other.mBits;
     return *this;
 }
 
-template <size_t N, typename BitsT>
-BitSetT<N, BitsT> &BitSetT<N, BitsT>::operator^=(const BitSetT &other)
+template <size_t N, typename BitsT, typename ParamT>
+BitSetT<N, BitsT, ParamT> &BitSetT<N, BitsT, ParamT>::operator^=(const BitSetT &other)
 {
     mBits = (mBits ^ other.mBits) & Mask(N);
     return *this;
 }
 
-template <size_t N, typename BitsT>
-BitSetT<N, BitsT> BitSetT<N, BitsT>::operator~() const
+template <size_t N, typename BitsT, typename ParamT>
+BitSetT<N, BitsT, ParamT> BitSetT<N, BitsT, ParamT>::operator~() const
 {
-    return BitSetT<N, BitsT>(~mBits & Mask(N));
+    return BitSetT<N, BitsT, ParamT>(~mBits & Mask(N));
 }
 
-template <size_t N, typename BitsT>
-BitSetT<N, BitsT> BitSetT<N, BitsT>::operator<<(std::size_t pos) const
+template <size_t N, typename BitsT, typename ParamT>
+BitSetT<N, BitsT, ParamT> BitSetT<N, BitsT, ParamT>::operator<<(std::size_t pos) const
 {
-    return BitSetT<N, BitsT>((mBits << pos) & Mask(N));
+    return BitSetT<N, BitsT, ParamT>((mBits << pos) & Mask(N));
 }
 
-template <size_t N, typename BitsT>
-BitSetT<N, BitsT> &BitSetT<N, BitsT>::operator<<=(std::size_t pos)
+template <size_t N, typename BitsT, typename ParamT>
+BitSetT<N, BitsT, ParamT> &BitSetT<N, BitsT, ParamT>::operator<<=(std::size_t pos)
 {
     mBits = (mBits << pos & Mask(N));
     return *this;
 }
 
-template <size_t N, typename BitsT>
-BitSetT<N, BitsT> BitSetT<N, BitsT>::operator>>(std::size_t pos) const
+template <size_t N, typename BitsT, typename ParamT>
+BitSetT<N, BitsT, ParamT> BitSetT<N, BitsT, ParamT>::operator>>(std::size_t pos) const
 {
-    return BitSetT<N, BitsT>(mBits >> pos);
+    return BitSetT<N, BitsT, ParamT>(mBits >> pos);
 }
 
-template <size_t N, typename BitsT>
-BitSetT<N, BitsT> &BitSetT<N, BitsT>::operator>>=(std::size_t pos)
+template <size_t N, typename BitsT, typename ParamT>
+BitSetT<N, BitsT, ParamT> &BitSetT<N, BitsT, ParamT>::operator>>=(std::size_t pos)
 {
     mBits = ((mBits >> pos) & Mask(N));
     return *this;
 }
 
-template <size_t N, typename BitsT>
-BitSetT<N, BitsT> &BitSetT<N, BitsT>::set()
+template <size_t N, typename BitsT, typename ParamT>
+BitSetT<N, BitsT, ParamT> &BitSetT<N, BitsT, ParamT>::set()
 {
     mBits = Mask(N);
     return *this;
 }
 
-template <size_t N, typename BitsT>
-BitSetT<N, BitsT> &BitSetT<N, BitsT>::set(std::size_t pos, bool value)
+template <size_t N, typename BitsT, typename ParamT>
+BitSetT<N, BitsT, ParamT> &BitSetT<N, BitsT, ParamT>::set(ParamT pos, bool value)
 {
     if (value)
     {
@@ -356,36 +359,36 @@
     return *this;
 }
 
-template <size_t N, typename BitsT>
-BitSetT<N, BitsT> &BitSetT<N, BitsT>::reset()
+template <size_t N, typename BitsT, typename ParamT>
+BitSetT<N, BitsT, ParamT> &BitSetT<N, BitsT, ParamT>::reset()
 {
     mBits = 0;
     return *this;
 }
 
-template <size_t N, typename BitsT>
-BitSetT<N, BitsT> &BitSetT<N, BitsT>::reset(std::size_t pos)
+template <size_t N, typename BitsT, typename ParamT>
+BitSetT<N, BitsT, ParamT> &BitSetT<N, BitsT, ParamT>::reset(ParamT pos)
 {
     mBits &= ~Bit(pos);
     return *this;
 }
 
-template <size_t N, typename BitsT>
-BitSetT<N, BitsT> &BitSetT<N, BitsT>::flip()
+template <size_t N, typename BitsT, typename ParamT>
+BitSetT<N, BitsT, ParamT> &BitSetT<N, BitsT, ParamT>::flip()
 {
     mBits ^= Mask(N);
     return *this;
 }
 
-template <size_t N, typename BitsT>
-BitSetT<N, BitsT> &BitSetT<N, BitsT>::flip(std::size_t pos)
+template <size_t N, typename BitsT, typename ParamT>
+BitSetT<N, BitsT, ParamT> &BitSetT<N, BitsT, ParamT>::flip(ParamT pos)
 {
     mBits ^= Bit(pos);
     return *this;
 }
 
-template <size_t N, typename BitsT>
-BitSetT<N, BitsT>::Iterator::Iterator(const BitSetT &bits) : mBitsCopy(bits), mCurrentBit(0)
+template <size_t N, typename BitsT, typename ParamT>
+BitSetT<N, BitsT, ParamT>::Iterator::Iterator(const BitSetT &bits) : mBitsCopy(bits), mCurrentBit(0)
 {
     if (bits.any())
     {
@@ -393,8 +396,8 @@
     }
 }
 
-template <size_t N, typename BitsT>
-typename BitSetT<N, BitsT>::Iterator &BitSetT<N, BitsT>::Iterator::operator++()
+template <size_t N, typename BitsT, typename ParamT>
+typename BitSetT<N, BitsT, ParamT>::Iterator &BitSetT<N, BitsT, ParamT>::Iterator::operator++()
 {
     ASSERT(mBitsCopy.any());
     mBitsCopy.reset(mCurrentBit);
@@ -402,26 +405,26 @@
     return *this;
 }
 
-template <size_t N, typename BitsT>
-bool BitSetT<N, BitsT>::Iterator::operator==(const Iterator &other) const
+template <size_t N, typename BitsT, typename ParamT>
+bool BitSetT<N, BitsT, ParamT>::Iterator::operator==(const Iterator &other) const
 {
     return mBitsCopy == other.mBitsCopy;
 }
 
-template <size_t N, typename BitsT>
-bool BitSetT<N, BitsT>::Iterator::operator!=(const Iterator &other) const
+template <size_t N, typename BitsT, typename ParamT>
+bool BitSetT<N, BitsT, ParamT>::Iterator::operator!=(const Iterator &other) const
 {
     return !(*this == other);
 }
 
-template <size_t N, typename BitsT>
-std::size_t BitSetT<N, BitsT>::Iterator::operator*() const
+template <size_t N, typename BitsT, typename ParamT>
+std::size_t BitSetT<N, BitsT, ParamT>::Iterator::operator*() const
 {
     return mCurrentBit;
 }
 
-template <size_t N, typename BitsT>
-std::size_t BitSetT<N, BitsT>::Iterator::getNextBit()
+template <size_t N, typename BitsT, typename ParamT>
+std::size_t BitSetT<N, BitsT, ParamT>::Iterator::getNextBit()
 {
     if (mBitsCopy.none())
     {
@@ -474,25 +477,25 @@
 
 }  // angle
 
-template <size_t N, typename BitsT>
-inline angle::BitSetT<N, BitsT> operator&(const angle::BitSetT<N, BitsT> &lhs,
-                                          const angle::BitSetT<N, BitsT> &rhs)
+template <size_t N, typename BitsT, typename ParamT>
+inline angle::BitSetT<N, BitsT, ParamT> operator&(const angle::BitSetT<N, BitsT, ParamT> &lhs,
+                                                  const angle::BitSetT<N, BitsT, ParamT> &rhs)
 {
-    return angle::BitSetT<N, BitsT>(lhs.bits() & rhs.bits());
+    return angle::BitSetT<N, BitsT, ParamT>(lhs.bits() & rhs.bits());
 }
 
-template <size_t N, typename BitsT>
-inline angle::BitSetT<N, BitsT> operator|(const angle::BitSetT<N, BitsT> &lhs,
-                                          const angle::BitSetT<N, BitsT> &rhs)
+template <size_t N, typename BitsT, typename ParamT>
+inline angle::BitSetT<N, BitsT, ParamT> operator|(const angle::BitSetT<N, BitsT, ParamT> &lhs,
+                                                  const angle::BitSetT<N, BitsT, ParamT> &rhs)
 {
-    return angle::BitSetT<N, BitsT>(lhs.bits() | rhs.bits());
+    return angle::BitSetT<N, BitsT, ParamT>(lhs.bits() | rhs.bits());
 }
 
-template <size_t N, typename BitsT>
-inline angle::BitSetT<N, BitsT> operator^(const angle::BitSetT<N, BitsT> &lhs,
-                                          const angle::BitSetT<N, BitsT> &rhs)
+template <size_t N, typename BitsT, typename ParamT>
+inline angle::BitSetT<N, BitsT, ParamT> operator^(const angle::BitSetT<N, BitsT, ParamT> &lhs,
+                                                  const angle::BitSetT<N, BitsT, ParamT> &rhs)
 {
-    return angle::BitSetT<N, BitsT>(lhs.bits() ^ rhs.bits());
+    return angle::BitSetT<N, BitsT, ParamT>(lhs.bits() ^ rhs.bits());
 }
 
 #endif  // COMMON_BITSETITERATOR_H_
diff --git a/src/libANGLE/Context.cpp b/src/libANGLE/Context.cpp
index 18a2c3b..8115230 100644
--- a/src/libANGLE/Context.cpp
+++ b/src/libANGLE/Context.cpp
@@ -2780,6 +2780,33 @@
     {
         mMemoryProgramCache = nullptr;
     }
+
+    // Compute which buffer types are allowed
+    mValidBufferBindings.reset();
+    mValidBufferBindings.set(BufferBinding::ElementArray);
+    mValidBufferBindings.set(BufferBinding::Array);
+
+    if (mExtensions.pixelBufferObject || getClientVersion() >= ES_3_0)
+    {
+        mValidBufferBindings.set(BufferBinding::PixelPack);
+        mValidBufferBindings.set(BufferBinding::PixelUnpack);
+    }
+
+    if (getClientVersion() >= ES_3_0)
+    {
+        mValidBufferBindings.set(BufferBinding::CopyRead);
+        mValidBufferBindings.set(BufferBinding::CopyWrite);
+        mValidBufferBindings.set(BufferBinding::TransformFeedback);
+        mValidBufferBindings.set(BufferBinding::Uniform);
+    }
+
+    if (getClientVersion() >= ES_3_1)
+    {
+        mValidBufferBindings.set(BufferBinding::AtomicCounter);
+        mValidBufferBindings.set(BufferBinding::ShaderStorage);
+        mValidBufferBindings.set(BufferBinding::DrawIndirect);
+        mValidBufferBindings.set(BufferBinding::DispatchIndirect);
+    }
 }
 
 void Context::initWorkarounds()
diff --git a/src/libANGLE/ContextState.h b/src/libANGLE/ContextState.h
index e6e9f4c..86fbd05 100644
--- a/src/libANGLE/ContextState.h
+++ b/src/libANGLE/ContextState.h
@@ -140,11 +140,16 @@
     template <typename T>
     const T &getParams() const;
 
+    bool isValidBufferBinding(BufferBinding binding) const { return mValidBufferBindings[binding]; }
+
   protected:
     ContextState mState;
     bool mSkipValidation;
     bool mDisplayTextureShareGroup;
 
+    // Stores for each buffer binding type whether is it allowed to be used in this context.
+    angle::PackedEnumBitSet<BufferBinding> mValidBufferBindings;
+
     // Caches entry point parameters and values re-used between layers.
     mutable const ParamTypeInfo *mSavedArgsType;
     static constexpr size_t kParamsBufferSize = 64u;
diff --git a/src/libANGLE/PackedGLEnums.h b/src/libANGLE/PackedGLEnums.h
index 70e3291..c2917a4 100644
--- a/src/libANGLE/PackedGLEnums.h
+++ b/src/libANGLE/PackedGLEnums.h
@@ -12,11 +12,28 @@
 #include "libANGLE/PackedGLEnums_autogen.h"
 
 #include <array>
+#include <bitset>
 #include <cstddef>
 
+#include "common/bitset_utils.h"
+
 namespace angle
 {
 
+// Return the number of elements of a packed enum, including the InvalidEnum element.
+template <typename E>
+constexpr size_t EnumSize()
+{
+    using UnderlyingType = typename std::underlying_type<E>::type;
+    return static_cast<UnderlyingType>(E::EnumCount);
+}
+
+// Implementation of AllEnums which allows iterating over all the possible values for a packed enums
+// like so:
+//     for (auto value : AllEnums<MyPackedEnum>()) {
+//         // Do something with the enum.
+//     }
+
 template <typename E>
 class EnumIterator final
 {
@@ -45,13 +62,14 @@
     EnumIterator<E> end() const { return {E::InvalidEnum}; }
 };
 
+// PackedEnumMap<E, T> is like an std::array<T, E::EnumCount> but is indexed with enum values. It
+// implements all of the std::array interface except with enum values instead of indices.
 template <typename E, typename T>
 class PackedEnumMap
 {
   private:
     using UnderlyingType          = typename std::underlying_type<E>::type;
-    static constexpr size_t kSize = static_cast<UnderlyingType>(E::EnumCount);
-    using Storage                 = std::array<T, kSize>;
+    using Storage                 = std::array<T, EnumSize<E>()>;
 
     Storage mData;
 
@@ -106,6 +124,11 @@
     const T *data() const noexcept { return mData.data(); }
 };
 
+// PackedEnumBitSetE> is like an std::bitset<E::EnumCount> but is indexed with enum values. It
+// implements the std::bitset interface except with enum values instead of indices.
+template <typename E>
+using PackedEnumBitSet = BitSetT<EnumSize<E>(), uint32_t, E>;
+
 }  // namespace angle
 
 #endif  // LIBANGLE_PACKEDGLENUMS_H_
diff --git a/src/libANGLE/validationES.cpp b/src/libANGLE/validationES.cpp
index fe97d78..3a29a33 100644
--- a/src/libANGLE/validationES.cpp
+++ b/src/libANGLE/validationES.cpp
@@ -649,36 +649,6 @@
     }
 }
 
-bool ValidBufferType(const ValidationContext *context, BufferBinding target)
-{
-    switch (target)
-    {
-        case BufferBinding::ElementArray:
-        case BufferBinding::Array:
-            return true;
-
-        case BufferBinding::PixelPack:
-        case BufferBinding::PixelUnpack:
-            return (context->getExtensions().pixelBufferObject ||
-                    context->getClientMajorVersion() >= 3);
-
-        case BufferBinding::CopyRead:
-        case BufferBinding::CopyWrite:
-        case BufferBinding::TransformFeedback:
-        case BufferBinding::Uniform:
-            return (context->getClientMajorVersion() >= 3);
-
-        case BufferBinding::AtomicCounter:
-        case BufferBinding::ShaderStorage:
-        case BufferBinding::DrawIndirect:
-        case BufferBinding::DispatchIndirect:
-            return context->getClientVersion() >= Version(3, 1);
-
-        default:
-            return false;
-    }
-}
-
 bool ValidMipLevel(const ValidationContext *context, GLenum target, GLint level)
 {
     const auto &caps    = context->getCaps();
@@ -3497,7 +3467,7 @@
         return false;
     }
 
-    if (!ValidBufferType(context, target))
+    if (!context->isValidBufferBinding(target))
     {
         context->handleError(InvalidEnum() << "Buffer target not valid");
         return false;
@@ -3533,7 +3503,7 @@
 
 bool ValidateUnmapBufferBase(Context *context, BufferBinding target)
 {
-    if (!ValidBufferType(context, target))
+    if (!context->isValidBufferBinding(target))
     {
         ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidBufferTypes);
         return false;
@@ -3556,7 +3526,7 @@
                                 GLsizeiptr length,
                                 GLbitfield access)
 {
-    if (!ValidBufferType(context, target))
+    if (!context->isValidBufferBinding(target))
     {
         ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidBufferTypes);
         return false;
@@ -3663,7 +3633,7 @@
         return false;
     }
 
-    if (!ValidBufferType(context, target))
+    if (!context->isValidBufferBinding(target))
     {
         ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidBufferTypes);
         return false;
@@ -4704,7 +4674,7 @@
         *numParams = 0;
     }
 
-    if (!ValidBufferType(context, target))
+    if (!context->isValidBufferBinding(target))
     {
         ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidBufferTypes);
         return false;
diff --git a/src/libANGLE/validationES.h b/src/libANGLE/validationES.h
index d63b6a4..c17261f 100644
--- a/src/libANGLE/validationES.h
+++ b/src/libANGLE/validationES.h
@@ -39,7 +39,6 @@
 bool ValidTexture3DDestinationTarget(const ValidationContext *context, GLenum target);
 bool ValidTexLevelDestinationTarget(const ValidationContext *context, GLenum target);
 bool ValidFramebufferTarget(const ValidationContext *context, GLenum target);
-bool ValidBufferType(const ValidationContext *context, BufferBinding target);
 bool ValidBufferParameter(const ValidationContext *context, GLenum pname, GLsizei *numParams);
 bool ValidMipLevel(const ValidationContext *context, GLenum target, GLint level);
 bool ValidImageSizeParameters(ValidationContext *context,
diff --git a/src/libANGLE/validationES2.cpp b/src/libANGLE/validationES2.cpp
index 0cc6d0b..001c91a 100644
--- a/src/libANGLE/validationES2.cpp
+++ b/src/libANGLE/validationES2.cpp
@@ -2838,7 +2838,7 @@
         return false;
     }
 
-    if (!ValidBufferType(context, target))
+    if (!context->isValidBufferBinding(target))
     {
         ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidBufferTypes);
         return false;
@@ -4206,7 +4206,7 @@
             return false;
     }
 
-    if (!ValidBufferType(context, target))
+    if (!context->isValidBufferBinding(target))
     {
         ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidBufferTypes);
         return false;
@@ -4241,7 +4241,7 @@
         return false;
     }
 
-    if (!ValidBufferType(context, target))
+    if (!context->isValidBufferBinding(target))
     {
         ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidBufferTypes);
         return false;
@@ -4408,7 +4408,7 @@
 
 bool ValidateBindBuffer(ValidationContext *context, BufferBinding target, GLuint buffer)
 {
-    if (!ValidBufferType(context, target))
+    if (!context->isValidBufferBinding(target))
     {
         ANGLE_VALIDATION_ERR(context, InvalidEnum(), InvalidBufferTypes);
         return false;
diff --git a/src/libANGLE/validationES3.cpp b/src/libANGLE/validationES3.cpp
index 1aadfc8..1c1edb1 100644
--- a/src/libANGLE/validationES3.cpp
+++ b/src/libANGLE/validationES3.cpp
@@ -2466,7 +2466,7 @@
         return false;
     }
 
-    if (!ValidBufferType(context, readTarget) || !ValidBufferType(context, writeTarget))
+    if (!context->isValidBufferBinding(readTarget) || !context->isValidBufferBinding(writeTarget))
     {
         context->handleError(InvalidEnum() << "Invalid buffer target");
         return false;