Optimize angle::BitSetIterator.

Adds a new custom bitset template to handle packing as many bits as
possible into a single variable. Intelligently select the right class
depending on platform features and bit sizes.

For now, always use a packed 64-bit set on 64-bit, instead of using
a 32-bit set for smaller bitsets.

BUG=angleproject:1814

Change-Id: I3ffef815c15515555833f6fc9302d8a4eee5423b
Reviewed-on: https://chromium-review.googlesource.com/471827
Reviewed-by: Geoff Lang <geofflang@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Jamie Madill <jmadill@chromium.org>
This commit is contained in:
Jamie Madill 2017-04-12 09:53:01 -04:00 коммит произвёл Commit Bot
Родитель a0e0aebbf2
Коммит 6de5185898
33 изменённых файлов: 622 добавлений и 129 удалений

Просмотреть файл

@ -59,6 +59,13 @@ config("internal_config") {
"GL_GLEXT_PROTOTYPES",
"EGL_EGLEXT_PROTOTYPES",
]
if (target_cpu == "x86") {
defines += [ "ANGLE_X86_CPU" ]
}
if (target_cpu == "x64") {
defines += [ "ANGLE_X64_CPU" ]
}
}
config("extra_warnings") {

Просмотреть файл

@ -281,6 +281,7 @@
'TargetMachine': '1', # x86
},
},
'defines': [ 'ANGLE_X86_CPU' ],
}, # x86_Base
'x64_Base':
@ -298,6 +299,7 @@
'TargetMachine': '17', # x86 - 64
},
},
'defines': [ 'ANGLE_X64_CPU' ],
}, # x64_Base
# Concrete configurations

Просмотреть файл

@ -21,13 +21,104 @@
namespace angle
{
template <size_t N>
class BitSetIterator final
template <size_t N, typename BitsT>
class BitSetT final
{
public:
BitSetIterator(const std::bitset<N> &bitset);
BitSetIterator(const BitSetIterator &other);
BitSetIterator &operator=(const BitSetIterator &other);
class Reference final
{
public:
~Reference() {}
Reference &operator=(bool x) { mParent->set(mBit, x); }
operator bool() const { return mParent->test(mBit); }
private:
friend class BitSetT;
Reference(BitSetT *parent, std::size_t bit) : mParent(parent), mBit(bit) {}
BitSetT *mParent;
std::size_t mBit;
};
class Iterator final
{
public:
Iterator(const BitSetT &bits);
Iterator &operator++();
bool operator==(const Iterator &other) const;
bool operator!=(const Iterator &other) const;
std::size_t operator*() const;
private:
std::size_t getNextBit();
BitSetT mBitsCopy;
std::size_t mCurrentBit;
};
BitSetT();
BitSetT(BitsT value);
~BitSetT();
BitSetT(const BitSetT &other);
BitSetT &operator=(const BitSetT &other);
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); }
bool test(std::size_t pos) const;
bool all() const;
bool any() const;
bool none() const;
std::size_t count() const;
constexpr std::size_t size() const { return N; }
BitSetT &operator&=(const BitSetT &other);
BitSetT &operator|=(const BitSetT &other);
BitSetT &operator^=(const BitSetT &other);
BitSetT operator~() const;
BitSetT operator<<(std::size_t pos) const;
BitSetT &operator<<=(std::size_t pos);
BitSetT operator>>(std::size_t pos) const;
BitSetT &operator>>=(std::size_t pos);
BitSetT &set();
BitSetT &set(std::size_t pos, bool value = true);
BitSetT &reset();
BitSetT &reset(std::size_t pos);
BitSetT &flip();
BitSetT &flip(std::size_t pos);
unsigned long to_ulong() const { return static_cast<unsigned long>(mBits); }
BitsT bits() const { return mBits; }
Iterator begin() const { return Iterator(*this); }
Iterator end() const { return Iterator(BitSetT()); }
private:
constexpr static BitsT Bit(std::size_t x) { return (static_cast<BitsT>(1) << x); }
constexpr static BitsT Mask(std::size_t x) { return ((Bit(x - 1) - 1) << 1) + 1; }
BitsT mBits;
};
template <size_t N>
class IterableBitSet : public std::bitset<N>
{
public:
IterableBitSet() {}
IterableBitSet(const std::bitset<N> &implicitBitSet) : std::bitset<N>(implicitBitSet) {}
class Iterator final
{
@ -42,41 +133,21 @@ class BitSetIterator final
private:
unsigned long getNextBit();
static const size_t BitsPerWord = sizeof(unsigned long) * 8;
static constexpr size_t BitsPerWord = sizeof(uint32_t) * 8;
std::bitset<N> mBits;
unsigned long mCurrentBit;
unsigned long mOffset;
};
Iterator begin() const { return Iterator(mBits); }
Iterator begin() const { return Iterator(*this); }
Iterator end() const { return Iterator(std::bitset<N>(0)); }
private:
const std::bitset<N> mBits;
};
template <size_t N>
BitSetIterator<N>::BitSetIterator(const std::bitset<N> &bitset) : mBits(bitset)
IterableBitSet<N>::Iterator::Iterator(const std::bitset<N> &bitset)
: mBits(bitset), mCurrentBit(0), mOffset(0)
{
}
template <size_t N>
BitSetIterator<N>::BitSetIterator(const BitSetIterator &other) : mBits(other.mBits)
{
}
template <size_t N>
BitSetIterator<N> &BitSetIterator<N>::operator=(const BitSetIterator &other)
{
mBits = other.mBits;
return *this;
}
template <size_t N>
BitSetIterator<N>::Iterator::Iterator(const std::bitset<N> &bits)
: mBits(bits), mCurrentBit(0), mOffset(0)
{
if (bits.any())
if (mBits.any())
{
mCurrentBit = getNextBit();
}
@ -87,7 +158,7 @@ BitSetIterator<N>::Iterator::Iterator(const std::bitset<N> &bits)
}
template <size_t N>
typename BitSetIterator<N>::Iterator &BitSetIterator<N>::Iterator::operator++()
typename IterableBitSet<N>::Iterator &IterableBitSet<N>::Iterator::operator++()
{
ASSERT(mBits.any());
mBits.set(mCurrentBit - mOffset, 0);
@ -96,26 +167,27 @@ typename BitSetIterator<N>::Iterator &BitSetIterator<N>::Iterator::operator++()
}
template <size_t N>
bool BitSetIterator<N>::Iterator::operator==(const Iterator &other) const
bool IterableBitSet<N>::Iterator::operator==(const Iterator &other) const
{
return mOffset == other.mOffset && mBits == other.mBits;
}
template <size_t N>
bool BitSetIterator<N>::Iterator::operator!=(const Iterator &other) const
bool IterableBitSet<N>::Iterator::operator!=(const Iterator &other) const
{
return !(*this == other);
}
template <size_t N>
unsigned long BitSetIterator<N>::Iterator::getNextBit()
unsigned long IterableBitSet<N>::Iterator::getNextBit()
{
static std::bitset<N> wordMask(std::numeric_limits<unsigned long>::max());
// TODO(jmadill): Use 64-bit scan when possible.
static constexpr std::bitset<N> wordMask(std::numeric_limits<uint32_t>::max());
while (mOffset < N)
{
unsigned long wordBits = (mBits & wordMask).to_ulong();
if (wordBits != 0ul)
uint32_t wordBits = static_cast<uint32_t>((mBits & wordMask).to_ulong());
if (wordBits != 0)
{
return gl::ScanForward(wordBits) + mOffset;
}
@ -126,13 +198,297 @@ unsigned long BitSetIterator<N>::Iterator::getNextBit()
return 0;
}
// Helper to avoid needing to specify the template parameter size
template <size_t N>
BitSetIterator<N> IterateBitSet(const std::bitset<N> &bitset)
template <size_t N, typename BitsT>
BitSetT<N, BitsT>::BitSetT() : mBits(0)
{
return BitSetIterator<N>(bitset);
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>
BitSetT<N, BitsT>::~BitSetT()
{
}
template <size_t N, typename BitsT>
BitSetT<N, BitsT>::BitSetT(const BitSetT &other) : mBits(other.mBits)
{
}
template <size_t N, typename BitsT>
BitSetT<N, BitsT> &BitSetT<N, BitsT>::operator=(const BitSetT &other)
{
mBits = other.mBits;
return *this;
}
template <size_t N, typename BitsT>
bool BitSetT<N, BitsT>::operator==(const BitSetT &other) const
{
return mBits == other.mBits;
}
template <size_t N, typename BitsT>
bool BitSetT<N, BitsT>::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
{
return test(pos);
}
template <size_t N, typename BitsT>
bool BitSetT<N, BitsT>::test(std::size_t pos) const
{
return (mBits & Bit(pos)) != 0;
}
template <size_t N, typename BitsT>
bool BitSetT<N, BitsT>::all() const
{
ASSERT(mBits == (mBits & Mask(N)));
return mBits == Mask(N);
}
template <size_t N, typename BitsT>
bool BitSetT<N, BitsT>::any() const
{
ASSERT(mBits == (mBits & Mask(N)));
return (mBits != 0);
}
template <size_t N, typename BitsT>
bool BitSetT<N, BitsT>::none() const
{
ASSERT(mBits == (mBits & Mask(N)));
return (mBits == 0);
}
template <size_t N, typename BitsT>
std::size_t BitSetT<N, BitsT>::count() const
{
return gl::BitCount(mBits);
}
template <size_t N, typename BitsT>
BitSetT<N, BitsT> &BitSetT<N, BitsT>::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)
{
mBits |= other.mBits;
return *this;
}
template <size_t N, typename BitsT>
BitSetT<N, BitsT> &BitSetT<N, BitsT>::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
{
return BitSetT<N, BitsT>(~mBits & Mask(N));
}
template <size_t N, typename BitsT>
BitSetT<N, BitsT> BitSetT<N, BitsT>::operator<<(std::size_t pos) const
{
return BitSetT<N, BitsT>((mBits << pos) & Mask(N));
}
template <size_t N, typename BitsT>
BitSetT<N, BitsT> &BitSetT<N, BitsT>::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
{
return BitSetT<N, BitsT>(mBits >> pos);
}
template <size_t N, typename BitsT>
BitSetT<N, BitsT> &BitSetT<N, BitsT>::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()
{
mBits = Mask(N);
return *this;
}
template <size_t N, typename BitsT>
BitSetT<N, BitsT> &BitSetT<N, BitsT>::set(std::size_t pos, bool value)
{
if (value)
{
mBits |= Bit(pos);
}
else
{
reset(pos);
}
return *this;
}
template <size_t N, typename BitsT>
BitSetT<N, BitsT> &BitSetT<N, BitsT>::reset()
{
mBits = 0;
return *this;
}
template <size_t N, typename BitsT>
BitSetT<N, BitsT> &BitSetT<N, BitsT>::reset(std::size_t pos)
{
mBits &= ~Bit(pos);
return *this;
}
template <size_t N, typename BitsT>
BitSetT<N, BitsT> &BitSetT<N, BitsT>::flip()
{
mBits ^= Mask(N);
return *this;
}
template <size_t N, typename BitsT>
BitSetT<N, BitsT> &BitSetT<N, BitsT>::flip(std::size_t pos)
{
mBits ^= Bit(pos);
return *this;
}
template <size_t N, typename BitsT>
BitSetT<N, BitsT>::Iterator::Iterator(const BitSetT &bits) : mBitsCopy(bits), mCurrentBit(0)
{
if (bits.any())
{
mCurrentBit = getNextBit();
}
}
template <size_t N, typename BitsT>
typename BitSetT<N, BitsT>::Iterator &BitSetT<N, BitsT>::Iterator::operator++()
{
ASSERT(mBitsCopy.any());
mBitsCopy.reset(mCurrentBit);
mCurrentBit = getNextBit();
return *this;
}
template <size_t N, typename BitsT>
bool BitSetT<N, BitsT>::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
{
return !(*this == other);
}
template <size_t N, typename BitsT>
std::size_t BitSetT<N, BitsT>::Iterator::operator*() const
{
return mCurrentBit;
}
template <size_t N, typename BitsT>
std::size_t BitSetT<N, BitsT>::Iterator::getNextBit()
{
if (mBitsCopy.none())
{
return 0;
}
return gl::ScanForward(mBitsCopy.mBits);
}
template <size_t N>
using BitSet32 = BitSetT<N, uint32_t>;
// ScanForward for 64-bits requires a 64-bit implementation.
#if defined(ANGLE_X64_CPU)
template <size_t N>
using BitSet64 = BitSetT<N, uint64_t>;
#endif // defined(ANGLE_X64_CPU)
namespace priv
{
template <size_t N, typename T>
using EnableIfBitsFit = typename std::enable_if<N <= sizeof(T) * 8>::type;
template <size_t N, typename Enable = void>
struct GetBitSet
{
using Type = IterableBitSet<N>;
};
// Prefer 64-bit bitsets on 64-bit CPUs. They seem faster than 32-bit.
#if defined(ANGLE_X64_CPU)
template <size_t N>
struct GetBitSet<N, EnableIfBitsFit<N, uint64_t>>
{
using Type = BitSet64<N>;
};
#else
template <size_t N>
struct GetBitSet<N, EnableIfBitsFit<N, uint32_t>>
{
using Type = BitSet32<N>;
};
#endif // defined(ANGLE_X64_CPU)
} // namespace priv
template <size_t N>
using BitSet = typename priv::GetBitSet<N>::Type;
} // 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)
{
return angle::BitSetT<N, BitsT>(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)
{
return angle::BitSetT<N, BitsT>(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)
{
return angle::BitSetT<N, BitsT>(lhs.bits() ^ rhs.bits());
}
#endif // COMMON_BITSETITERATOR_H_

Просмотреть файл

@ -18,25 +18,25 @@ namespace
class BitSetIteratorTest : public testing::Test
{
protected:
std::bitset<40> mStateBits;
BitSet<40> mStateBits;
};
// Simple iterator test.
TEST_F(BitSetIteratorTest, Iterator)
{
std::set<unsigned long> originalValues;
std::set<size_t> originalValues;
originalValues.insert(2);
originalValues.insert(6);
originalValues.insert(8);
originalValues.insert(35);
for (unsigned long value : originalValues)
for (size_t value : originalValues)
{
mStateBits.set(value);
}
std::set<unsigned long> readValues;
for (unsigned long bit : IterateBitSet(mStateBits))
std::set<size_t> readValues;
for (size_t bit : mStateBits)
{
EXPECT_EQ(1u, originalValues.count(bit));
EXPECT_EQ(0u, readValues.count(bit));
@ -52,7 +52,7 @@ TEST_F(BitSetIteratorTest, EmptySet)
// We don't use the FAIL gtest macro here since it returns immediately,
// causing an unreachable code warning in MSVS
bool sawBit = false;
for (unsigned long bit : IterateBitSet(mStateBits))
for (size_t bit : mStateBits)
{
sawBit = true;
UNUSED_VARIABLE(bit);
@ -63,7 +63,7 @@ TEST_F(BitSetIteratorTest, EmptySet)
// Test iterating a result of combining two bitsets.
TEST_F(BitSetIteratorTest, NonLValueBitset)
{
std::bitset<40> otherBits;
BitSet<40> otherBits;
mStateBits.set(1);
mStateBits.set(2);
@ -75,9 +75,10 @@ TEST_F(BitSetIteratorTest, NonLValueBitset)
otherBits.set(3);
otherBits.set(5);
std::set<unsigned long> seenBits;
std::set<size_t> seenBits;
for (unsigned long bit : IterateBitSet(mStateBits & otherBits))
angle::BitSet<40> maskedBits = (mStateBits & otherBits);
for (size_t bit : maskedBits)
{
EXPECT_EQ(0u, seenBits.count(bit));
seenBits.insert(bit);

Просмотреть файл

@ -805,34 +805,73 @@ inline uint32_t BitfieldReverse(uint32_t value)
}
// Count the 1 bits.
inline int BitCount(unsigned int bits)
#if defined(ANGLE_PLATFORM_WINDOWS)
inline int BitCount(uint32_t bits)
{
#if defined(_MSC_VER)
return static_cast<int>(__popcnt(bits));
#elif defined(__GNUC__)
}
#if defined(ANGLE_X64_CPU)
inline int BitCount(uint64_t bits)
{
return static_cast<int>(__popcnt64(bits));
}
#endif // defined(ANGLE_X64_CPU)
#endif // defined(ANGLE_PLATFORM_WINDOWS)
#if defined(ANGLE_PLATFORM_POSIX)
inline int BitCount(uint32_t bits)
{
return __builtin_popcount(bits);
#else
#error Please implement bit count for your platform!
#endif
}
#if defined(ANGLE_X64_CPU)
inline int BitCount(uint64_t bits)
{
return __builtin_popcountll(bits);
}
#endif // defined(ANGLE_X64_CPU)
#endif // defined(ANGLE_PLATFORM_POSIX)
#if defined(ANGLE_PLATFORM_WINDOWS)
// Return the index of the least significant bit set. Indexing is such that bit 0 is the least
// significant bit.
inline unsigned long ScanForward(unsigned long bits)
// significant bit. Implemented for different bit widths on different platforms.
inline unsigned long ScanForward(uint32_t bits)
{
ASSERT(bits != 0u);
#if defined(ANGLE_PLATFORM_WINDOWS)
unsigned long firstBitIndex = 0ul;
unsigned char ret = _BitScanForward(&firstBitIndex, bits);
ASSERT(ret != 0u);
return firstBitIndex;
#elif defined(ANGLE_PLATFORM_POSIX)
return static_cast<unsigned long>(__builtin_ctzl(bits));
#else
#error Please implement bit-scan-forward for your platform!
#endif
}
#if defined(ANGLE_X64_CPU)
inline unsigned long ScanForward(uint64_t bits)
{
ASSERT(bits != 0u);
unsigned long firstBitIndex = 0ul;
unsigned char ret = _BitScanForward64(&firstBitIndex, bits);
ASSERT(ret != 0u);
return firstBitIndex;
}
#endif // defined(ANGLE_X64_CPU)
#endif // defined(ANGLE_PLATFORM_WINDOWS)
#if defined(ANGLE_PLATFORM_POSIX)
inline unsigned long ScanForward(uint32_t bits)
{
ASSERT(bits != 0u);
return static_cast<unsigned long>(__builtin_ctz(bits));
}
#if defined(ANGLE_X64_CPU)
inline unsigned long ScanForward(uint64_t bits)
{
ASSERT(bits != 0u);
return static_cast<unsigned long>(__builtin_ctzll(bits));
}
#endif // defined(ANGLE_X64_CPU)
#endif // defined(ANGLE_PLATFORM_POSIX)
// Return the index of the most significant bit set. Indexing is such that bit 0 is the least
// significant bit.
inline unsigned long ScanReverse(unsigned long bits)
@ -851,8 +890,10 @@ inline unsigned long ScanReverse(unsigned long bits)
}
// Returns -1 on 0, otherwise the index of the least significant 1 bit as in GLSL.
inline int FindLSB(uint32_t bits)
template <typename T>
int FindLSB(T bits)
{
static_assert(std::is_integral<T>::value, "must be integral type.");
if (bits == 0u)
{
return -1;
@ -864,8 +905,10 @@ inline int FindLSB(uint32_t bits)
}
// Returns -1 on 0, otherwise the index of the most significant 1 bit as in GLSL.
inline int FindMSB(uint32_t bits)
template <typename T>
int FindMSB(T bits)
{
static_assert(std::is_integral<T>::value, "must be integral type.");
if (bits == 0u)
{
return -1;

Просмотреть файл

@ -274,14 +274,26 @@ TEST(MathUtilTest, BitCount)
EXPECT_EQ(0, gl::BitCount(0u));
EXPECT_EQ(32, gl::BitCount(0xFFFFFFFFu));
EXPECT_EQ(10, gl::BitCount(0x17103121u));
#if defined(ANGLE_X64_CPU)
EXPECT_EQ(0, gl::BitCount(0ull));
EXPECT_EQ(32, gl::BitCount(0xFFFFFFFFull));
EXPECT_EQ(10, gl::BitCount(0x17103121ull));
#endif // defined(ANGLE_X64_CPU)
}
// Test ScanForward, which scans for the least significant 1 bit from a non-zero integer.
TEST(MathUtilTest, ScanForward)
{
EXPECT_EQ(0ul, gl::ScanForward(1ul));
EXPECT_EQ(16ul, gl::ScanForward(0x80010000ul));
EXPECT_EQ(31ul, gl::ScanForward(0x80000000ul));
EXPECT_EQ(0ul, gl::ScanForward(1u));
EXPECT_EQ(16ul, gl::ScanForward(0x80010000u));
EXPECT_EQ(31ul, gl::ScanForward(0x80000000u));
#if defined(ANGLE_X64_CPU)
EXPECT_EQ(0ul, gl::ScanForward(1ull));
EXPECT_EQ(16ul, gl::ScanForward(0x80010000ull));
EXPECT_EQ(31ul, gl::ScanForward(0x80000000ull));
#endif // defined(ANGLE_X64_CPU)
}
// Test ScanReverse, which scans for the most significant 1 bit from a non-zero integer.

Просмотреть файл

@ -1263,7 +1263,7 @@ bool Framebuffer::formsRenderingFeedbackLoopWith(const State &state) const
}
// The bitset will skip inactive draw buffers.
for (GLuint drawIndex : angle::IterateBitSet(mState.mEnabledDrawBuffers))
for (size_t drawIndex : mState.mEnabledDrawBuffers)
{
const FramebufferAttachment *attachment = getDrawBuffer(drawIndex);
if (attachment && attachment->type() == GL_TEXTURE)

Просмотреть файл

@ -100,7 +100,7 @@ class FramebufferState final : angle::NonCopyable
std::vector<GLenum> mDrawBufferStates;
GLenum mReadBufferState;
std::bitset<IMPLEMENTATION_MAX_DRAW_BUFFERS> mEnabledDrawBuffers;
angle::BitSet<IMPLEMENTATION_MAX_DRAW_BUFFERS> mEnabledDrawBuffers;
GLint mDefaultWidth;
GLint mDefaultHeight;
@ -259,7 +259,7 @@ class Framebuffer final : public LabeledObject, public OnAttachmentDirtyReceiver
DIRTY_BIT_MAX = DIRTY_BIT_UNKNOWN
};
typedef std::bitset<DIRTY_BIT_MAX> DirtyBits;
typedef angle::BitSet<DIRTY_BIT_MAX> DirtyBits;
bool hasAnyDirtyBit() const { return mDirtyBits.any(); }
void syncState(const Context *context);

Просмотреть файл

@ -260,7 +260,7 @@ class ProgramState final : angle::NonCopyable
UniformBlockBindingMask mActiveUniformBlockBindings;
std::vector<sh::Attribute> mAttributes;
std::bitset<MAX_VERTEX_ATTRIBS> mActiveAttribLocationsMask;
angle::BitSet<MAX_VERTEX_ATTRIBS> mActiveAttribLocationsMask;
// Uniforms are sorted in order:
// 1. Non-sampler uniforms

Просмотреть файл

@ -1370,9 +1370,9 @@ void State::setVertexAttribDivisor(GLuint index, GLuint divisor)
mDirtyObjects.set(DIRTY_OBJECT_VERTEX_ARRAY);
}
const VertexAttribCurrentValueData &State::getVertexAttribCurrentValue(unsigned int attribNum) const
const VertexAttribCurrentValueData &State::getVertexAttribCurrentValue(size_t attribNum) const
{
ASSERT(static_cast<size_t>(attribNum) < mVertexAttribCurrentValues.size());
ASSERT(attribNum < mVertexAttribCurrentValues.size());
return mVertexAttribCurrentValues[attribNum];
}
@ -2114,7 +2114,7 @@ void State::syncDirtyObjects(const Context *context)
void State::syncDirtyObjects(const Context *context, const DirtyObjects &bitset)
{
for (auto dirtyObject : angle::IterateBitSet(bitset))
for (auto dirtyObject : bitset)
{
switch (dirtyObject)
{

Просмотреть файл

@ -13,6 +13,7 @@
#include <memory>
#include "common/angleutils.h"
#include "common/bitset_utils.h"
#include "common/Color.h"
#include "libANGLE/Debug.h"
#include "libANGLE/Program.h"
@ -266,7 +267,7 @@ class State : angle::NonCopyable
void setVertexAttribState(unsigned int attribNum, Buffer *boundBuffer, GLint size, GLenum type,
bool normalized, bool pureInteger, GLsizei stride, const void *pointer);
void setVertexAttribDivisor(GLuint index, GLuint divisor);
const VertexAttribCurrentValueData &getVertexAttribCurrentValue(unsigned int attribNum) const;
const VertexAttribCurrentValueData &getVertexAttribCurrentValue(size_t attribNum) const;
const void *getVertexAttribPointer(unsigned int attribNum) const;
void bindVertexBuffer(GLuint bindingIndex,
Buffer *boundBuffer,
@ -425,13 +426,13 @@ class State : angle::NonCopyable
DIRTY_OBJECT_MAX = DIRTY_OBJECT_UNKNOWN,
};
typedef std::bitset<DIRTY_BIT_MAX> DirtyBits;
typedef angle::BitSet<DIRTY_BIT_MAX> DirtyBits;
const DirtyBits &getDirtyBits() const { return mDirtyBits; }
void clearDirtyBits() { mDirtyBits.reset(); }
void clearDirtyBits(const DirtyBits &bitset) { mDirtyBits &= ~bitset; }
void setAllDirtyBits() { mDirtyBits.set(); }
typedef std::bitset<DIRTY_OBJECT_MAX> DirtyObjects;
typedef angle::BitSet<DIRTY_OBJECT_MAX> DirtyObjects;
void clearDirtyObjects() { mDirtyObjects.reset(); }
void setAllDirtyObjects() { mDirtyObjects.set(); }
void syncDirtyObjects(const Context *context);

Просмотреть файл

@ -395,7 +395,7 @@ class Texture final : public egl::ImageSibling,
DIRTY_BIT_COUNT,
};
using DirtyBits = std::bitset<DIRTY_BIT_COUNT>;
using DirtyBits = angle::BitSet<DIRTY_BIT_COUNT>;
void syncImplState();
bool hasAnyDirtyBit() const { return mDirtyBits.any(); }

Просмотреть файл

@ -93,7 +93,7 @@ const VertexBinding &VertexArray::getVertexBinding(size_t bindingIndex) const
return mState.mVertexBindings[bindingIndex];
}
size_t VertexArray::GetAttribIndex(unsigned long dirtyBit)
size_t VertexArray::GetAttribIndex(size_t dirtyBit)
{
static_assert(gl::MAX_VERTEX_ATTRIBS == gl::MAX_VERTEX_ATTRIB_BINDINGS,
"The stride of vertex attributes should equal to that of vertex bindings.");

Просмотреть файл

@ -168,9 +168,9 @@ class VertexArray final : public LabeledObject
DIRTY_BIT_MAX = DIRTY_BIT_UNKNOWN,
};
typedef std::bitset<DIRTY_BIT_MAX> DirtyBits;
typedef angle::BitSet<DIRTY_BIT_MAX> DirtyBits;
static size_t GetAttribIndex(unsigned long dirtyBit);
static size_t GetAttribIndex(size_t dirtyBit);
void syncImplState(const Context *context);
bool hasAnyDirtyBit() const { return mDirtyBits.any(); }

Просмотреть файл

@ -26,7 +26,7 @@ TEST(VertexArrayTest, VerifyGetAttribIndex)
dirtyBits.set(bits[i]);
}
for (unsigned long dirtyBit : angle::IterateBitSet(dirtyBits))
for (size_t dirtyBit : dirtyBits)
{
size_t index = VertexArray::GetAttribIndex(dirtyBit);
if (dirtyBit < VertexArray::DIRTY_BIT_ATTRIB_MAX_ENABLED)

Просмотреть файл

@ -9,6 +9,7 @@
#ifndef LIBANGLE_ANGLETYPES_H_
#define LIBANGLE_ANGLETYPES_H_
#include "common/bitset_utils.h"
#include "libANGLE/Constants.h"
#include "libANGLE/RefCountObject.h"
@ -253,10 +254,10 @@ struct PixelPackState : PixelStoreStateBase
};
// Used in Program and VertexArray.
typedef std::bitset<MAX_VERTEX_ATTRIBS> AttributesMask;
using AttributesMask = angle::BitSet<MAX_VERTEX_ATTRIBS>;
// Use in Program
typedef std::bitset<IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS> UniformBlockBindingMask;
using UniformBlockBindingMask = angle::BitSet<IMPLEMENTATION_MAX_COMBINED_SHADER_UNIFORM_BUFFERS>;
// A map of GL objects indexed by object ID. The specific map implementation may change.
// Client code should treat it as a std::map.

Просмотреть файл

@ -306,7 +306,7 @@ void FramebufferD3D::syncState(ContextImpl *contextImpl,
invalidateColorAttachmentCache = true;
}
for (auto dirtyBit : angle::IterateBitSet(dirtyBits))
for (auto dirtyBit : dirtyBits)
{
if ((dirtyBit >= gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0 &&
dirtyBit < gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_MAX) ||

Просмотреть файл

@ -2359,7 +2359,7 @@ void ProgramD3D::updateCachedInputLayout(const gl::State &state)
mCachedInputLayout.clear();
const auto &vertexAttributes = state.getVertexArray()->getVertexAttributes();
for (unsigned int locationIndex : IterateBitSet(mState.getActiveAttribLocationsMask()))
for (size_t locationIndex : mState.getActiveAttribLocationsMask())
{
int d3dSemantic = mAttribLocationToD3DSemantic[locationIndex];

Просмотреть файл

@ -241,8 +241,7 @@ gl::Error VertexDataManager::prepareVertexData(const gl::State &state,
translatedAttribs->resize(attribIndex + 1);
TranslatedAttribute *translated = &(*translatedAttribs)[attribIndex];
auto currentValueData =
state.getVertexAttribCurrentValue(static_cast<unsigned int>(attribIndex));
auto currentValueData = state.getVertexAttribCurrentValue(attribIndex);
// Record the attribute now
translated->active = true;
@ -401,14 +400,14 @@ gl::Error VertexDataManager::storeDynamicAttribs(
StreamingBufferUnmapper localUnmapper(mStreamingBuffer);
// Reserve the required space for the dynamic buffers.
for (auto attribIndex : IterateBitSet(dynamicAttribsMask))
for (auto attribIndex : dynamicAttribsMask)
{
const auto &dynamicAttrib = (*translatedAttribs)[attribIndex];
ANGLE_TRY(reserveSpaceForAttrib(dynamicAttrib, count, instances));
}
// Store dynamic attributes
for (auto attribIndex : IterateBitSet(dynamicAttribsMask))
for (auto attribIndex : dynamicAttribsMask)
{
auto *dynamicAttrib = &(*translatedAttribs)[attribIndex];
ANGLE_TRY(storeDynamicAttrib(dynamicAttrib, start, count, instances));
@ -422,7 +421,7 @@ void VertexDataManager::PromoteDynamicAttribs(
const gl::AttributesMask &dynamicAttribsMask,
GLsizei count)
{
for (auto attribIndex : IterateBitSet(dynamicAttribsMask))
for (auto attribIndex : dynamicAttribsMask)
{
const auto &dynamicAttrib = translatedAttribs[attribIndex];
const auto &binding = *dynamicAttrib.binding;

Просмотреть файл

@ -384,7 +384,7 @@ void Framebuffer11::syncState(ContextImpl *contextImpl, const gl::Framebuffer::D
const auto &mergedDirtyBits = dirtyBits | mInternalDirtyBits;
mInternalDirtyBits.reset();
for (auto dirtyBit : IterateBitSet(mergedDirtyBits))
for (auto dirtyBit : mergedDirtyBits)
{
switch (dirtyBit)
{

Просмотреть файл

@ -47,7 +47,7 @@ gl::InputLayout GetInputLayout(const std::vector<const TranslatedAttribute *> &t
return inputLayout;
}
GLenum GetGLSLAttributeType(const std::vector<sh::Attribute> &shaderAttributes, int index)
GLenum GetGLSLAttributeType(const std::vector<sh::Attribute> &shaderAttributes, size_t index)
{
// Count matrices differently
for (const sh::Attribute &attrib : shaderAttributes)
@ -59,8 +59,9 @@ GLenum GetGLSLAttributeType(const std::vector<sh::Attribute> &shaderAttributes,
GLenum transposedType = gl::TransposeMatrixType(attrib.type);
int rows = gl::VariableRowCount(transposedType);
int intIndex = static_cast<int>(index);
if (index >= attrib.location && index < attrib.location + rows)
if (intIndex >= attrib.location && intIndex < attrib.location + rows)
{
return transposedType;
}
@ -105,7 +106,7 @@ void SortAttributesByLayout(const gl::Program *program,
const auto &locationToSemantic =
GetImplAs<ProgramD3D>(program)->getAttribLocationToD3DSemantics();
for (auto locationIndex : angle::IterateBitSet(program->getActiveAttribLocationsMask()))
for (auto locationIndex : program->getActiveAttribLocationsMask())
{
int d3dSemantic = locationToSemantic[locationIndex];
if (sortedAttributesOut->size() <= static_cast<size_t>(d3dSemantic))
@ -485,7 +486,7 @@ gl::Error InputLayoutCache::updateInputLayout(const gl::State &state,
const auto &bindings = state.getVertexArray()->getVertexBindings();
const auto &locationToSemantic = programD3D->getAttribLocationToD3DSemantics();
for (unsigned long attribIndex : angle::IterateBitSet(program->getActiveAttribLocationsMask()))
for (size_t attribIndex : program->getActiveAttribLocationsMask())
{
// Record the type of the associated vertex shader vector in our key
// This will prevent mismatched vertex shaders from using the same input layout
@ -495,7 +496,8 @@ gl::Error InputLayoutCache::updateInputLayout(const gl::State &state,
const auto &binding = bindings[attrib.bindingIndex];
int d3dSemantic = locationToSemantic[attribIndex];
const auto &currentValue = state.getVertexAttribCurrentValue(attribIndex);
const auto &currentValue =
state.getVertexAttribCurrentValue(static_cast<unsigned int>(attribIndex));
gl::VertexFormatType vertexFormatType = gl::GetVertexFormatType(attrib, currentValue.Type);
layout.addAttributeData(glslElementType, d3dSemantic, vertexFormatType, binding.divisor);

Просмотреть файл

@ -253,7 +253,7 @@ void StateManager11::syncState(const gl::State &state, const gl::State::DirtyBit
return;
}
for (auto dirtyBit : angle::IterateBitSet(dirtyBits))
for (auto dirtyBit : dirtyBits)
{
switch (dirtyBit)
{
@ -1103,15 +1103,14 @@ gl::Error StateManager11::updateCurrentValueAttribs(const gl::State &state,
const auto &dirtyActiveAttribs = (activeAttribsMask & mDirtyCurrentValueAttribs);
const auto &vertexAttributes = state.getVertexArray()->getVertexAttributes();
for (auto attribIndex : angle::IterateBitSet(dirtyActiveAttribs))
for (auto attribIndex : dirtyActiveAttribs)
{
if (vertexAttributes[attribIndex].enabled)
continue;
mDirtyCurrentValueAttribs.reset(attribIndex);
const auto &currentValue =
state.getVertexAttribCurrentValue(static_cast<unsigned int>(attribIndex));
const auto &currentValue = state.getVertexAttribCurrentValue(attribIndex);
auto currentValueAttrib = &mCurrentValueAttribs[attribIndex];
currentValueAttrib->currentValueType = currentValue.Type;
currentValueAttrib->attribute = &vertexAttributes[attribIndex];

Просмотреть файл

@ -42,7 +42,7 @@ VertexArray11::~VertexArray11()
void VertexArray11::syncState(ContextImpl *contextImpl, const gl::VertexArray::DirtyBits &dirtyBits)
{
for (auto dirtyBit : angle::IterateBitSet(dirtyBits))
for (auto dirtyBit : dirtyBits)
{
if (dirtyBit == gl::VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER)
continue;
@ -62,9 +62,9 @@ void VertexArray11::flushAttribUpdates(const gl::State &state)
if (mAttribsToUpdate.any())
{
// Skip attrib locations the program doesn't use.
const auto &activeToUpdate = (mAttribsToUpdate & activeLocations);
gl::AttributesMask activeToUpdate = mAttribsToUpdate & activeLocations;
for (auto toUpdateIndex : angle::IterateBitSet(activeToUpdate))
for (auto toUpdateIndex : activeToUpdate)
{
mAttribsToUpdate.reset(toUpdateIndex);
updateVertexAttribStorage(toUpdateIndex);
@ -155,15 +155,14 @@ gl::Error VertexArray11::updateDirtyAndDynamicAttribs(VertexDataManager *vertexD
if (mAttribsToTranslate.any())
{
// Skip attrib locations the program doesn't use, saving for the next frame.
const auto &dirtyActiveAttribs = (mAttribsToTranslate & activeLocations);
gl::AttributesMask dirtyActiveAttribs = (mAttribsToTranslate & activeLocations);
for (auto dirtyAttribIndex : angle::IterateBitSet(dirtyActiveAttribs))
for (auto dirtyAttribIndex : dirtyActiveAttribs)
{
mAttribsToTranslate.reset(dirtyAttribIndex);
auto *translatedAttrib = &mTranslatedAttribs[dirtyAttribIndex];
const auto &currentValue =
state.getVertexAttribCurrentValue(static_cast<unsigned int>(dirtyAttribIndex));
const auto &currentValue = state.getVertexAttribCurrentValue(dirtyAttribIndex);
// Record basic attrib info
translatedAttrib->attribute = &attribs[dirtyAttribIndex];
@ -195,11 +194,10 @@ gl::Error VertexArray11::updateDirtyAndDynamicAttribs(VertexDataManager *vertexD
{
auto activeDynamicAttribs = (mDynamicAttribsMask & activeLocations);
for (auto dynamicAttribIndex : angle::IterateBitSet(activeDynamicAttribs))
for (auto dynamicAttribIndex : activeDynamicAttribs)
{
auto *dynamicAttrib = &mTranslatedAttribs[dynamicAttribIndex];
const auto &currentValue =
state.getVertexAttribCurrentValue(static_cast<unsigned int>(dynamicAttribIndex));
const auto &currentValue = state.getVertexAttribCurrentValue(dynamicAttribIndex);
// Record basic attrib info
dynamicAttrib->attribute = &attribs[dynamicAttribIndex];

Просмотреть файл

@ -120,7 +120,7 @@ void StateManager9::syncState(const gl::State &state, const gl::State::DirtyBits
return;
}
for (auto dirtyBit : angle::IterateBitSet(dirtyBits))
for (auto dirtyBit : dirtyBits)
{
switch (dirtyBit)
{
@ -396,7 +396,7 @@ gl::Error StateManager9::setBlendDepthRasterStates(const gl::State &glState,
mCurFrontFaceCCW = frontFaceCCW;
}
for (auto dirtyBit : angle::IterateBitSet(mDirtyBits))
for (auto dirtyBit : mDirtyBits)
{
switch (dirtyBit)
{

Просмотреть файл

@ -155,7 +155,7 @@ class StateManager9 final : angle::NonCopyable
DIRTY_BIT_MAX
};
typedef std::bitset<DIRTY_BIT_MAX> DirtyBits;
using DirtyBits = angle::BitSet<DIRTY_BIT_MAX>;
bool mUsingZeroColorMaskWorkaround;

Просмотреть файл

@ -417,7 +417,7 @@ void FramebufferGL::syncState(ContextImpl *contextImpl, const Framebuffer::Dirty
mStateManager->bindFramebuffer(GL_FRAMEBUFFER, mFramebufferID);
for (auto dirtyBit : angle::IterateBitSet(dirtyBits))
for (auto dirtyBit : dirtyBits)
{
switch (dirtyBit)
{

Просмотреть файл

@ -75,9 +75,10 @@ LinkResult ProgramGL::load(const ContextImpl *contextImpl,
const WorkaroundsGL &workaroundsGL = GetAs<ContextGL>(contextImpl)->getWorkaroundsGL();
if (workaroundsGL.reapplyUBOBindingsAfterLoadingBinaryProgram)
{
for (GLuint bindingIndex : angle::IterateBitSet(mState.getActiveUniformBlockBindingsMask()))
for (size_t bindingIndex : mState.getActiveUniformBlockBindingsMask())
{
setUniformBlockBinding(bindingIndex, mState.getUniformBlockBinding(bindingIndex));
GLuint uintIndex = static_cast<GLuint>(bindingIndex);
setUniformBlockBinding(uintIndex, mState.getUniformBlockBinding(uintIndex));
}
}

Просмотреть файл

@ -1394,7 +1394,7 @@ void StateManagerGL::syncState(const gl::ContextState &data,
mLocalDirtyBits.set(gl::State::DIRTY_BIT_FRAMEBUFFER_SRGB);
}
const auto &glAndLocalDirtyBits = (glDirtyBits | mLocalDirtyBits);
const gl::State::DirtyBits &glAndLocalDirtyBits = (glDirtyBits | mLocalDirtyBits);
if (!glAndLocalDirtyBits.any())
{
@ -1402,7 +1402,7 @@ void StateManagerGL::syncState(const gl::ContextState &data,
}
// TODO(jmadill): Investigate only syncing vertex state for active attributes
for (auto dirtyBit : angle::IterateBitSet(glAndLocalDirtyBits))
for (auto dirtyBit : glAndLocalDirtyBits)
{
switch (dirtyBit)
{
@ -1648,8 +1648,8 @@ void StateManagerGL::syncState(const gl::ContextState &data,
dirtyBit < gl::State::DIRTY_BIT_CURRENT_VALUE_MAX);
size_t attribIndex =
static_cast<size_t>(dirtyBit) - gl::State::DIRTY_BIT_CURRENT_VALUE_0;
setAttributeCurrentData(attribIndex, state.getVertexAttribCurrentValue(
static_cast<unsigned int>(attribIndex)));
setAttributeCurrentData(attribIndex,
state.getVertexAttribCurrentValue(attribIndex));
break;
}
}

Просмотреть файл

@ -942,7 +942,7 @@ void TextureGL::syncState(const gl::Texture::DirtyBits &dirtyBits)
mLocalDirtyBits |= GetLevelWorkaroundDirtyBits();
}
for (auto dirtyBit : angle::IterateBitSet(dirtyBits | mLocalDirtyBits))
for (auto dirtyBit : (dirtyBits | mLocalDirtyBits))
{
switch (dirtyBit)
{

Просмотреть файл

@ -257,7 +257,10 @@ void VertexArrayGL::computeStreamingAttributeSizes(const gl::AttributesMask &act
const auto &attribs = mData.getVertexAttributes();
const auto &bindings = mData.getVertexBindings();
for (auto idx : angle::IterateBitSet(mAttributesNeedStreaming & activeAttributesMask))
gl::AttributesMask attribsToStream = (mAttributesNeedStreaming & activeAttributesMask);
for (auto idx : attribsToStream)
{
const auto &attrib = attribs[idx];
const auto &binding = bindings[attrib.bindingIndex];
@ -320,7 +323,10 @@ gl::Error VertexArrayGL::streamAttributes(const gl::AttributesMask &activeAttrib
const auto &attribs = mData.getVertexAttributes();
const auto &bindings = mData.getVertexBindings();
for (auto idx : angle::IterateBitSet(mAttributesNeedStreaming & activeAttributesMask))
gl::AttributesMask attribsToStream = (mAttributesNeedStreaming & activeAttributesMask);
for (auto idx : attribsToStream)
{
const auto &attrib = attribs[idx];
const auto &binding = bindings[attrib.bindingIndex];
@ -526,7 +532,7 @@ void VertexArrayGL::updateAttribDivisor(size_t attribIndex)
void VertexArrayGL::syncState(ContextImpl *contextImpl, const VertexArray::DirtyBits &dirtyBits)
{
for (unsigned long dirtyBit : angle::IterateBitSet(dirtyBits))
for (size_t dirtyBit : dirtyBits)
{
if (dirtyBit == VertexArray::DIRTY_BIT_ELEMENT_ARRAY_BUFFER)
{

Просмотреть файл

@ -99,7 +99,7 @@ gl::Error ContextVk::initPipeline()
std::vector<VkVertexInputBindingDescription> vertexBindings;
std::vector<VkVertexInputAttributeDescription> vertexAttribs;
for (auto attribIndex : angle::IterateBitSet(programGL->getActiveAttribLocationsMask()))
for (auto attribIndex : programGL->getActiveAttribLocationsMask())
{
const auto &attrib = attribs[attribIndex];
const auto &binding = bindings[attrib.bindingIndex];
@ -293,7 +293,7 @@ gl::Error ContextVk::drawArrays(GLenum mode, GLint first, GLsizei count)
std::vector<VkBuffer> vertexHandles;
std::vector<VkDeviceSize> vertexOffsets;
for (auto attribIndex : angle::IterateBitSet(programGL->getActiveAttribLocationsMask()))
for (auto attribIndex : programGL->getActiveAttribLocationsMask())
{
const auto &attrib = attribs[attribIndex];
const auto &binding = bindings[attrib.bindingIndex];

Просмотреть файл

@ -19,6 +19,7 @@
'<(angle_path)/src/tests/perf_tests/ANGLEPerfTest.h',
'<(angle_path)/src/tests/perf_tests/BlitFramebufferPerf.cpp',
'<(angle_path)/src/tests/perf_tests/BindingPerf.cpp',
'<(angle_path)/src/tests/perf_tests/BitSetIteratorPerf.cpp',
'<(angle_path)/src/tests/perf_tests/BufferSubData.cpp',
'<(angle_path)/src/tests/perf_tests/DrawCallPerf.cpp',
'<(angle_path)/src/tests/perf_tests/DrawCallPerfParams.cpp',

Просмотреть файл

@ -0,0 +1,64 @@
//
// Copyright 2015 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// IndexDataManagerPerfTest:
// Performance test for index buffer management.
//
#include "ANGLEPerfTest.h"
#include <gmock/gmock.h>
#include "angle_unittests_utils.h"
#include "common/bitset_utils.h"
using namespace testing;
namespace
{
template <typename T>
class BitSetIteratorPerfTest : public ANGLEPerfTest
{
public:
BitSetIteratorPerfTest();
void step() override;
T mBits;
};
template <typename T>
BitSetIteratorPerfTest<T>::BitSetIteratorPerfTest() : ANGLEPerfTest("BitSetIteratorPerf", "_run")
{
}
template <typename T>
void BitSetIteratorPerfTest<T>::step()
{
mBits.flip();
for (size_t bit : mBits)
{
UNUSED_VARIABLE(bit);
}
mBits.reset();
}
// These type names unfortunately don't get printed correctly in Gtest.
#if defined(ANGLE_X64_CPU)
using TestTypes = Types<angle::IterableBitSet<32>, angle::BitSet32<32>, angle::BitSet64<32>>;
#else
using TestTypes = Types<angle::IterableBitSet<32>, angle::BitSet32<32>>;
#endif // defined(ANGLE_X64_CPU)
TYPED_TEST_CASE(BitSetIteratorPerfTest, TestTypes);
TYPED_TEST(BitSetIteratorPerfTest, Run)
{
this->run();
}
} // anonymous namespace