diff options
Diffstat (limited to 'gfx/angle/src/common')
39 files changed, 9188 insertions, 0 deletions
diff --git a/gfx/angle/src/common/BitSetIterator.h b/gfx/angle/src/common/BitSetIterator.h new file mode 100755 index 000000000..7fecd3769 --- /dev/null +++ b/gfx/angle/src/common/BitSetIterator.h @@ -0,0 +1,155 @@ +// +// 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. +// +// BitSetIterator: +// A helper class to quickly bitscan bitsets for set bits. +// + +#ifndef COMMON_BITSETITERATOR_H_ +#define COMMON_BITSETITERATOR_H_ + +#include <stdint.h> + +#include <bitset> + +#include "common/angleutils.h" +#include "common/debug.h" +#include "common/mathutil.h" +#include "common/platform.h" + +namespace angle +{ +template <size_t N> +class BitSetIterator final +{ + public: + BitSetIterator(const std::bitset<N> &bitset); + BitSetIterator(const BitSetIterator &other); + BitSetIterator &operator=(const BitSetIterator &other); + + class Iterator final + { + public: + Iterator(const std::bitset<N> &bits); + Iterator &operator++(); + + bool operator==(const Iterator &other) const; + bool operator!=(const Iterator &other) const; + unsigned long operator*() const { return mCurrentBit; } + + private: + unsigned long getNextBit(); + + static const size_t BitsPerWord = sizeof(unsigned long) * 8; + std::bitset<N> mBits; + unsigned long mCurrentBit; + unsigned long mOffset; + }; + + Iterator begin() const { return Iterator(mBits); } + 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) +{ +} + +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()) + { + mCurrentBit = getNextBit(); + } + else + { + mOffset = static_cast<unsigned long>(rx::roundUp(N, BitsPerWord)); + } +} + +template <size_t N> +typename BitSetIterator<N>::Iterator &BitSetIterator<N>::Iterator::operator++() +{ + ASSERT(mBits.any()); + mBits.set(mCurrentBit - mOffset, 0); + mCurrentBit = getNextBit(); + return *this; +} + +inline unsigned long ScanForward(unsigned long bits) +{ + ASSERT(bits != 0); +#if defined(ANGLE_PLATFORM_WINDOWS) + unsigned long firstBitIndex = 0ul; + unsigned char ret = _BitScanForward(&firstBitIndex, bits); + ASSERT(ret != 0); + 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 +} + +template <size_t N> +bool BitSetIterator<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 +{ + return !(*this == other); +} + +template <size_t N> +unsigned long BitSetIterator<N>::Iterator::getNextBit() +{ + static std::bitset<N> wordMask(std::numeric_limits<unsigned long>::max()); + + while (mOffset < N) + { + unsigned long wordBits = (mBits & wordMask).to_ulong(); + if (wordBits != 0ul) + { + return ScanForward(wordBits) + mOffset; + } + + mBits >>= BitsPerWord; + mOffset += BitsPerWord; + } + return 0; +} + +// Helper to avoid needing to specify the template parameter size +template <size_t N> +BitSetIterator<N> IterateBitSet(const std::bitset<N> &bitset) +{ + return BitSetIterator<N>(bitset); +} + +} // angle + +#endif // COMMON_BITSETITERATOR_H_ diff --git a/gfx/angle/src/common/BitSetIterator_unittest.cpp b/gfx/angle/src/common/BitSetIterator_unittest.cpp new file mode 100755 index 000000000..e965f2c56 --- /dev/null +++ b/gfx/angle/src/common/BitSetIterator_unittest.cpp @@ -0,0 +1,91 @@ +// +// 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. +// +// BitSetIteratorTest: +// Test the IterableBitSet class. +// + +#include <gtest/gtest.h> + +#include "common/BitSetIterator.h" + +using namespace angle; + +namespace +{ +class BitSetIteratorTest : public testing::Test +{ + protected: + std::bitset<40> mStateBits; +}; + +// Simple iterator test. +TEST_F(BitSetIteratorTest, Iterator) +{ + std::set<unsigned long> originalValues; + originalValues.insert(2); + originalValues.insert(6); + originalValues.insert(8); + originalValues.insert(35); + + for (unsigned long value : originalValues) + { + mStateBits.set(value); + } + + std::set<unsigned long> readValues; + for (unsigned long bit : IterateBitSet(mStateBits)) + { + EXPECT_EQ(1u, originalValues.count(bit)); + EXPECT_EQ(0u, readValues.count(bit)); + readValues.insert(bit); + } + + EXPECT_EQ(originalValues.size(), readValues.size()); +} + +// Test an empty iterator. +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)) + { + sawBit = true; + UNUSED_VARIABLE(bit); + } + EXPECT_FALSE(sawBit); +} + +// Test iterating a result of combining two bitsets. +TEST_F(BitSetIteratorTest, NonLValueBitset) +{ + std::bitset<40> otherBits; + + mStateBits.set(1); + mStateBits.set(2); + mStateBits.set(3); + mStateBits.set(4); + + otherBits.set(0); + otherBits.set(1); + otherBits.set(3); + otherBits.set(5); + + std::set<unsigned long> seenBits; + + for (unsigned long bit : IterateBitSet(mStateBits & otherBits)) + { + EXPECT_EQ(0u, seenBits.count(bit)); + seenBits.insert(bit); + EXPECT_TRUE(mStateBits[bit]); + EXPECT_TRUE(otherBits[bit]); + } + + EXPECT_EQ((mStateBits & otherBits).count(), seenBits.size()); +} + +} // anonymous namespace diff --git a/gfx/angle/src/common/Color.h b/gfx/angle/src/common/Color.h new file mode 100755 index 000000000..2b4d2f6fb --- /dev/null +++ b/gfx/angle/src/common/Color.h @@ -0,0 +1,53 @@ +// +// Copyright (c) 2016 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. +// + +// Color.h : Defines the Color type used throughout the ANGLE libraries + +#ifndef COMMON_COLOR_H_ +#define COMMON_COLOR_H_ + +namespace angle +{ + +template <typename T> +struct Color +{ + T red; + T green; + T blue; + T alpha; + + Color(); + Color(T r, T g, T b, T a); +}; + +template <typename T> +bool operator==(const Color<T> &a, const Color<T> &b); + +template <typename T> +bool operator!=(const Color<T> &a, const Color<T> &b); + +typedef Color<float> ColorF; +typedef Color<int> ColorI; +typedef Color<unsigned int> ColorUI; + +} // namespace angle + +// TODO: Move this fully into the angle namespace +namespace gl +{ + +template <typename T> +using Color = angle::Color<T>; +using ColorF = angle::ColorF; +using ColorI = angle::ColorI; +using ColorUI = angle::ColorUI; + +} // namespace gl + +#include "Color.inl" + +#endif // COMMON_COLOR_H_ diff --git a/gfx/angle/src/common/Color.inl b/gfx/angle/src/common/Color.inl new file mode 100755 index 000000000..c3073256b --- /dev/null +++ b/gfx/angle/src/common/Color.inl @@ -0,0 +1,37 @@ +// +// Copyright (c) 2016 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. +// + +// Color.inl : Inline definitions of some functions from Color.h + +namespace angle +{ + +template <typename T> +Color<T>::Color() : Color(0, 0, 0, 0) +{ +} + +template <typename T> +Color<T>::Color(T r, T g, T b, T a) : red(r), green(g), blue(b), alpha(a) +{ +} + +template <typename T> +bool operator==(const Color<T> &a, const Color<T> &b) +{ + return a.red == b.red && + a.green == b.green && + a.blue == b.blue && + a.alpha == b.alpha; +} + +template <typename T> +bool operator!=(const Color<T> &a, const Color<T> &b) +{ + return !(a == b); +} + +} // namespace angle diff --git a/gfx/angle/src/common/Float16ToFloat32.cpp b/gfx/angle/src/common/Float16ToFloat32.cpp new file mode 100755 index 000000000..acd0d88b6 --- /dev/null +++ b/gfx/angle/src/common/Float16ToFloat32.cpp @@ -0,0 +1,2205 @@ +// +// Copyright (c) 2012 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. +// + +// This file is automatically generated. + +#include "common/mathutil.h" + +namespace gl +{ + +const static unsigned g_mantissa[2048] = { + 0x00000000, + 0x33800000, + 0x34000000, + 0x34400000, + 0x34800000, + 0x34a00000, + 0x34c00000, + 0x34e00000, + 0x35000000, + 0x35100000, + 0x35200000, + 0x35300000, + 0x35400000, + 0x35500000, + 0x35600000, + 0x35700000, + 0x35800000, + 0x35880000, + 0x35900000, + 0x35980000, + 0x35a00000, + 0x35a80000, + 0x35b00000, + 0x35b80000, + 0x35c00000, + 0x35c80000, + 0x35d00000, + 0x35d80000, + 0x35e00000, + 0x35e80000, + 0x35f00000, + 0x35f80000, + 0x36000000, + 0x36040000, + 0x36080000, + 0x360c0000, + 0x36100000, + 0x36140000, + 0x36180000, + 0x361c0000, + 0x36200000, + 0x36240000, + 0x36280000, + 0x362c0000, + 0x36300000, + 0x36340000, + 0x36380000, + 0x363c0000, + 0x36400000, + 0x36440000, + 0x36480000, + 0x364c0000, + 0x36500000, + 0x36540000, + 0x36580000, + 0x365c0000, + 0x36600000, + 0x36640000, + 0x36680000, + 0x366c0000, + 0x36700000, + 0x36740000, + 0x36780000, + 0x367c0000, + 0x36800000, + 0x36820000, + 0x36840000, + 0x36860000, + 0x36880000, + 0x368a0000, + 0x368c0000, + 0x368e0000, + 0x36900000, + 0x36920000, + 0x36940000, + 0x36960000, + 0x36980000, + 0x369a0000, + 0x369c0000, + 0x369e0000, + 0x36a00000, + 0x36a20000, + 0x36a40000, + 0x36a60000, + 0x36a80000, + 0x36aa0000, + 0x36ac0000, + 0x36ae0000, + 0x36b00000, + 0x36b20000, + 0x36b40000, + 0x36b60000, + 0x36b80000, + 0x36ba0000, + 0x36bc0000, + 0x36be0000, + 0x36c00000, + 0x36c20000, + 0x36c40000, + 0x36c60000, + 0x36c80000, + 0x36ca0000, + 0x36cc0000, + 0x36ce0000, + 0x36d00000, + 0x36d20000, + 0x36d40000, + 0x36d60000, + 0x36d80000, + 0x36da0000, + 0x36dc0000, + 0x36de0000, + 0x36e00000, + 0x36e20000, + 0x36e40000, + 0x36e60000, + 0x36e80000, + 0x36ea0000, + 0x36ec0000, + 0x36ee0000, + 0x36f00000, + 0x36f20000, + 0x36f40000, + 0x36f60000, + 0x36f80000, + 0x36fa0000, + 0x36fc0000, + 0x36fe0000, + 0x37000000, + 0x37010000, + 0x37020000, + 0x37030000, + 0x37040000, + 0x37050000, + 0x37060000, + 0x37070000, + 0x37080000, + 0x37090000, + 0x370a0000, + 0x370b0000, + 0x370c0000, + 0x370d0000, + 0x370e0000, + 0x370f0000, + 0x37100000, + 0x37110000, + 0x37120000, + 0x37130000, + 0x37140000, + 0x37150000, + 0x37160000, + 0x37170000, + 0x37180000, + 0x37190000, + 0x371a0000, + 0x371b0000, + 0x371c0000, + 0x371d0000, + 0x371e0000, + 0x371f0000, + 0x37200000, + 0x37210000, + 0x37220000, + 0x37230000, + 0x37240000, + 0x37250000, + 0x37260000, + 0x37270000, + 0x37280000, + 0x37290000, + 0x372a0000, + 0x372b0000, + 0x372c0000, + 0x372d0000, + 0x372e0000, + 0x372f0000, + 0x37300000, + 0x37310000, + 0x37320000, + 0x37330000, + 0x37340000, + 0x37350000, + 0x37360000, + 0x37370000, + 0x37380000, + 0x37390000, + 0x373a0000, + 0x373b0000, + 0x373c0000, + 0x373d0000, + 0x373e0000, + 0x373f0000, + 0x37400000, + 0x37410000, + 0x37420000, + 0x37430000, + 0x37440000, + 0x37450000, + 0x37460000, + 0x37470000, + 0x37480000, + 0x37490000, + 0x374a0000, + 0x374b0000, + 0x374c0000, + 0x374d0000, + 0x374e0000, + 0x374f0000, + 0x37500000, + 0x37510000, + 0x37520000, + 0x37530000, + 0x37540000, + 0x37550000, + 0x37560000, + 0x37570000, + 0x37580000, + 0x37590000, + 0x375a0000, + 0x375b0000, + 0x375c0000, + 0x375d0000, + 0x375e0000, + 0x375f0000, + 0x37600000, + 0x37610000, + 0x37620000, + 0x37630000, + 0x37640000, + 0x37650000, + 0x37660000, + 0x37670000, + 0x37680000, + 0x37690000, + 0x376a0000, + 0x376b0000, + 0x376c0000, + 0x376d0000, + 0x376e0000, + 0x376f0000, + 0x37700000, + 0x37710000, + 0x37720000, + 0x37730000, + 0x37740000, + 0x37750000, + 0x37760000, + 0x37770000, + 0x37780000, + 0x37790000, + 0x377a0000, + 0x377b0000, + 0x377c0000, + 0x377d0000, + 0x377e0000, + 0x377f0000, + 0x37800000, + 0x37808000, + 0x37810000, + 0x37818000, + 0x37820000, + 0x37828000, + 0x37830000, + 0x37838000, + 0x37840000, + 0x37848000, + 0x37850000, + 0x37858000, + 0x37860000, + 0x37868000, + 0x37870000, + 0x37878000, + 0x37880000, + 0x37888000, + 0x37890000, + 0x37898000, + 0x378a0000, + 0x378a8000, + 0x378b0000, + 0x378b8000, + 0x378c0000, + 0x378c8000, + 0x378d0000, + 0x378d8000, + 0x378e0000, + 0x378e8000, + 0x378f0000, + 0x378f8000, + 0x37900000, + 0x37908000, + 0x37910000, + 0x37918000, + 0x37920000, + 0x37928000, + 0x37930000, + 0x37938000, + 0x37940000, + 0x37948000, + 0x37950000, + 0x37958000, + 0x37960000, + 0x37968000, + 0x37970000, + 0x37978000, + 0x37980000, + 0x37988000, + 0x37990000, + 0x37998000, + 0x379a0000, + 0x379a8000, + 0x379b0000, + 0x379b8000, + 0x379c0000, + 0x379c8000, + 0x379d0000, + 0x379d8000, + 0x379e0000, + 0x379e8000, + 0x379f0000, + 0x379f8000, + 0x37a00000, + 0x37a08000, + 0x37a10000, + 0x37a18000, + 0x37a20000, + 0x37a28000, + 0x37a30000, + 0x37a38000, + 0x37a40000, + 0x37a48000, + 0x37a50000, + 0x37a58000, + 0x37a60000, + 0x37a68000, + 0x37a70000, + 0x37a78000, + 0x37a80000, + 0x37a88000, + 0x37a90000, + 0x37a98000, + 0x37aa0000, + 0x37aa8000, + 0x37ab0000, + 0x37ab8000, + 0x37ac0000, + 0x37ac8000, + 0x37ad0000, + 0x37ad8000, + 0x37ae0000, + 0x37ae8000, + 0x37af0000, + 0x37af8000, + 0x37b00000, + 0x37b08000, + 0x37b10000, + 0x37b18000, + 0x37b20000, + 0x37b28000, + 0x37b30000, + 0x37b38000, + 0x37b40000, + 0x37b48000, + 0x37b50000, + 0x37b58000, + 0x37b60000, + 0x37b68000, + 0x37b70000, + 0x37b78000, + 0x37b80000, + 0x37b88000, + 0x37b90000, + 0x37b98000, + 0x37ba0000, + 0x37ba8000, + 0x37bb0000, + 0x37bb8000, + 0x37bc0000, + 0x37bc8000, + 0x37bd0000, + 0x37bd8000, + 0x37be0000, + 0x37be8000, + 0x37bf0000, + 0x37bf8000, + 0x37c00000, + 0x37c08000, + 0x37c10000, + 0x37c18000, + 0x37c20000, + 0x37c28000, + 0x37c30000, + 0x37c38000, + 0x37c40000, + 0x37c48000, + 0x37c50000, + 0x37c58000, + 0x37c60000, + 0x37c68000, + 0x37c70000, + 0x37c78000, + 0x37c80000, + 0x37c88000, + 0x37c90000, + 0x37c98000, + 0x37ca0000, + 0x37ca8000, + 0x37cb0000, + 0x37cb8000, + 0x37cc0000, + 0x37cc8000, + 0x37cd0000, + 0x37cd8000, + 0x37ce0000, + 0x37ce8000, + 0x37cf0000, + 0x37cf8000, + 0x37d00000, + 0x37d08000, + 0x37d10000, + 0x37d18000, + 0x37d20000, + 0x37d28000, + 0x37d30000, + 0x37d38000, + 0x37d40000, + 0x37d48000, + 0x37d50000, + 0x37d58000, + 0x37d60000, + 0x37d68000, + 0x37d70000, + 0x37d78000, + 0x37d80000, + 0x37d88000, + 0x37d90000, + 0x37d98000, + 0x37da0000, + 0x37da8000, + 0x37db0000, + 0x37db8000, + 0x37dc0000, + 0x37dc8000, + 0x37dd0000, + 0x37dd8000, + 0x37de0000, + 0x37de8000, + 0x37df0000, + 0x37df8000, + 0x37e00000, + 0x37e08000, + 0x37e10000, + 0x37e18000, + 0x37e20000, + 0x37e28000, + 0x37e30000, + 0x37e38000, + 0x37e40000, + 0x37e48000, + 0x37e50000, + 0x37e58000, + 0x37e60000, + 0x37e68000, + 0x37e70000, + 0x37e78000, + 0x37e80000, + 0x37e88000, + 0x37e90000, + 0x37e98000, + 0x37ea0000, + 0x37ea8000, + 0x37eb0000, + 0x37eb8000, + 0x37ec0000, + 0x37ec8000, + 0x37ed0000, + 0x37ed8000, + 0x37ee0000, + 0x37ee8000, + 0x37ef0000, + 0x37ef8000, + 0x37f00000, + 0x37f08000, + 0x37f10000, + 0x37f18000, + 0x37f20000, + 0x37f28000, + 0x37f30000, + 0x37f38000, + 0x37f40000, + 0x37f48000, + 0x37f50000, + 0x37f58000, + 0x37f60000, + 0x37f68000, + 0x37f70000, + 0x37f78000, + 0x37f80000, + 0x37f88000, + 0x37f90000, + 0x37f98000, + 0x37fa0000, + 0x37fa8000, + 0x37fb0000, + 0x37fb8000, + 0x37fc0000, + 0x37fc8000, + 0x37fd0000, + 0x37fd8000, + 0x37fe0000, + 0x37fe8000, + 0x37ff0000, + 0x37ff8000, + 0x38000000, + 0x38004000, + 0x38008000, + 0x3800c000, + 0x38010000, + 0x38014000, + 0x38018000, + 0x3801c000, + 0x38020000, + 0x38024000, + 0x38028000, + 0x3802c000, + 0x38030000, + 0x38034000, + 0x38038000, + 0x3803c000, + 0x38040000, + 0x38044000, + 0x38048000, + 0x3804c000, + 0x38050000, + 0x38054000, + 0x38058000, + 0x3805c000, + 0x38060000, + 0x38064000, + 0x38068000, + 0x3806c000, + 0x38070000, + 0x38074000, + 0x38078000, + 0x3807c000, + 0x38080000, + 0x38084000, + 0x38088000, + 0x3808c000, + 0x38090000, + 0x38094000, + 0x38098000, + 0x3809c000, + 0x380a0000, + 0x380a4000, + 0x380a8000, + 0x380ac000, + 0x380b0000, + 0x380b4000, + 0x380b8000, + 0x380bc000, + 0x380c0000, + 0x380c4000, + 0x380c8000, + 0x380cc000, + 0x380d0000, + 0x380d4000, + 0x380d8000, + 0x380dc000, + 0x380e0000, + 0x380e4000, + 0x380e8000, + 0x380ec000, + 0x380f0000, + 0x380f4000, + 0x380f8000, + 0x380fc000, + 0x38100000, + 0x38104000, + 0x38108000, + 0x3810c000, + 0x38110000, + 0x38114000, + 0x38118000, + 0x3811c000, + 0x38120000, + 0x38124000, + 0x38128000, + 0x3812c000, + 0x38130000, + 0x38134000, + 0x38138000, + 0x3813c000, + 0x38140000, + 0x38144000, + 0x38148000, + 0x3814c000, + 0x38150000, + 0x38154000, + 0x38158000, + 0x3815c000, + 0x38160000, + 0x38164000, + 0x38168000, + 0x3816c000, + 0x38170000, + 0x38174000, + 0x38178000, + 0x3817c000, + 0x38180000, + 0x38184000, + 0x38188000, + 0x3818c000, + 0x38190000, + 0x38194000, + 0x38198000, + 0x3819c000, + 0x381a0000, + 0x381a4000, + 0x381a8000, + 0x381ac000, + 0x381b0000, + 0x381b4000, + 0x381b8000, + 0x381bc000, + 0x381c0000, + 0x381c4000, + 0x381c8000, + 0x381cc000, + 0x381d0000, + 0x381d4000, + 0x381d8000, + 0x381dc000, + 0x381e0000, + 0x381e4000, + 0x381e8000, + 0x381ec000, + 0x381f0000, + 0x381f4000, + 0x381f8000, + 0x381fc000, + 0x38200000, + 0x38204000, + 0x38208000, + 0x3820c000, + 0x38210000, + 0x38214000, + 0x38218000, + 0x3821c000, + 0x38220000, + 0x38224000, + 0x38228000, + 0x3822c000, + 0x38230000, + 0x38234000, + 0x38238000, + 0x3823c000, + 0x38240000, + 0x38244000, + 0x38248000, + 0x3824c000, + 0x38250000, + 0x38254000, + 0x38258000, + 0x3825c000, + 0x38260000, + 0x38264000, + 0x38268000, + 0x3826c000, + 0x38270000, + 0x38274000, + 0x38278000, + 0x3827c000, + 0x38280000, + 0x38284000, + 0x38288000, + 0x3828c000, + 0x38290000, + 0x38294000, + 0x38298000, + 0x3829c000, + 0x382a0000, + 0x382a4000, + 0x382a8000, + 0x382ac000, + 0x382b0000, + 0x382b4000, + 0x382b8000, + 0x382bc000, + 0x382c0000, + 0x382c4000, + 0x382c8000, + 0x382cc000, + 0x382d0000, + 0x382d4000, + 0x382d8000, + 0x382dc000, + 0x382e0000, + 0x382e4000, + 0x382e8000, + 0x382ec000, + 0x382f0000, + 0x382f4000, + 0x382f8000, + 0x382fc000, + 0x38300000, + 0x38304000, + 0x38308000, + 0x3830c000, + 0x38310000, + 0x38314000, + 0x38318000, + 0x3831c000, + 0x38320000, + 0x38324000, + 0x38328000, + 0x3832c000, + 0x38330000, + 0x38334000, + 0x38338000, + 0x3833c000, + 0x38340000, + 0x38344000, + 0x38348000, + 0x3834c000, + 0x38350000, + 0x38354000, + 0x38358000, + 0x3835c000, + 0x38360000, + 0x38364000, + 0x38368000, + 0x3836c000, + 0x38370000, + 0x38374000, + 0x38378000, + 0x3837c000, + 0x38380000, + 0x38384000, + 0x38388000, + 0x3838c000, + 0x38390000, + 0x38394000, + 0x38398000, + 0x3839c000, + 0x383a0000, + 0x383a4000, + 0x383a8000, + 0x383ac000, + 0x383b0000, + 0x383b4000, + 0x383b8000, + 0x383bc000, + 0x383c0000, + 0x383c4000, + 0x383c8000, + 0x383cc000, + 0x383d0000, + 0x383d4000, + 0x383d8000, + 0x383dc000, + 0x383e0000, + 0x383e4000, + 0x383e8000, + 0x383ec000, + 0x383f0000, + 0x383f4000, + 0x383f8000, + 0x383fc000, + 0x38400000, + 0x38404000, + 0x38408000, + 0x3840c000, + 0x38410000, + 0x38414000, + 0x38418000, + 0x3841c000, + 0x38420000, + 0x38424000, + 0x38428000, + 0x3842c000, + 0x38430000, + 0x38434000, + 0x38438000, + 0x3843c000, + 0x38440000, + 0x38444000, + 0x38448000, + 0x3844c000, + 0x38450000, + 0x38454000, + 0x38458000, + 0x3845c000, + 0x38460000, + 0x38464000, + 0x38468000, + 0x3846c000, + 0x38470000, + 0x38474000, + 0x38478000, + 0x3847c000, + 0x38480000, + 0x38484000, + 0x38488000, + 0x3848c000, + 0x38490000, + 0x38494000, + 0x38498000, + 0x3849c000, + 0x384a0000, + 0x384a4000, + 0x384a8000, + 0x384ac000, + 0x384b0000, + 0x384b4000, + 0x384b8000, + 0x384bc000, + 0x384c0000, + 0x384c4000, + 0x384c8000, + 0x384cc000, + 0x384d0000, + 0x384d4000, + 0x384d8000, + 0x384dc000, + 0x384e0000, + 0x384e4000, + 0x384e8000, + 0x384ec000, + 0x384f0000, + 0x384f4000, + 0x384f8000, + 0x384fc000, + 0x38500000, + 0x38504000, + 0x38508000, + 0x3850c000, + 0x38510000, + 0x38514000, + 0x38518000, + 0x3851c000, + 0x38520000, + 0x38524000, + 0x38528000, + 0x3852c000, + 0x38530000, + 0x38534000, + 0x38538000, + 0x3853c000, + 0x38540000, + 0x38544000, + 0x38548000, + 0x3854c000, + 0x38550000, + 0x38554000, + 0x38558000, + 0x3855c000, + 0x38560000, + 0x38564000, + 0x38568000, + 0x3856c000, + 0x38570000, + 0x38574000, + 0x38578000, + 0x3857c000, + 0x38580000, + 0x38584000, + 0x38588000, + 0x3858c000, + 0x38590000, + 0x38594000, + 0x38598000, + 0x3859c000, + 0x385a0000, + 0x385a4000, + 0x385a8000, + 0x385ac000, + 0x385b0000, + 0x385b4000, + 0x385b8000, + 0x385bc000, + 0x385c0000, + 0x385c4000, + 0x385c8000, + 0x385cc000, + 0x385d0000, + 0x385d4000, + 0x385d8000, + 0x385dc000, + 0x385e0000, + 0x385e4000, + 0x385e8000, + 0x385ec000, + 0x385f0000, + 0x385f4000, + 0x385f8000, + 0x385fc000, + 0x38600000, + 0x38604000, + 0x38608000, + 0x3860c000, + 0x38610000, + 0x38614000, + 0x38618000, + 0x3861c000, + 0x38620000, + 0x38624000, + 0x38628000, + 0x3862c000, + 0x38630000, + 0x38634000, + 0x38638000, + 0x3863c000, + 0x38640000, + 0x38644000, + 0x38648000, + 0x3864c000, + 0x38650000, + 0x38654000, + 0x38658000, + 0x3865c000, + 0x38660000, + 0x38664000, + 0x38668000, + 0x3866c000, + 0x38670000, + 0x38674000, + 0x38678000, + 0x3867c000, + 0x38680000, + 0x38684000, + 0x38688000, + 0x3868c000, + 0x38690000, + 0x38694000, + 0x38698000, + 0x3869c000, + 0x386a0000, + 0x386a4000, + 0x386a8000, + 0x386ac000, + 0x386b0000, + 0x386b4000, + 0x386b8000, + 0x386bc000, + 0x386c0000, + 0x386c4000, + 0x386c8000, + 0x386cc000, + 0x386d0000, + 0x386d4000, + 0x386d8000, + 0x386dc000, + 0x386e0000, + 0x386e4000, + 0x386e8000, + 0x386ec000, + 0x386f0000, + 0x386f4000, + 0x386f8000, + 0x386fc000, + 0x38700000, + 0x38704000, + 0x38708000, + 0x3870c000, + 0x38710000, + 0x38714000, + 0x38718000, + 0x3871c000, + 0x38720000, + 0x38724000, + 0x38728000, + 0x3872c000, + 0x38730000, + 0x38734000, + 0x38738000, + 0x3873c000, + 0x38740000, + 0x38744000, + 0x38748000, + 0x3874c000, + 0x38750000, + 0x38754000, + 0x38758000, + 0x3875c000, + 0x38760000, + 0x38764000, + 0x38768000, + 0x3876c000, + 0x38770000, + 0x38774000, + 0x38778000, + 0x3877c000, + 0x38780000, + 0x38784000, + 0x38788000, + 0x3878c000, + 0x38790000, + 0x38794000, + 0x38798000, + 0x3879c000, + 0x387a0000, + 0x387a4000, + 0x387a8000, + 0x387ac000, + 0x387b0000, + 0x387b4000, + 0x387b8000, + 0x387bc000, + 0x387c0000, + 0x387c4000, + 0x387c8000, + 0x387cc000, + 0x387d0000, + 0x387d4000, + 0x387d8000, + 0x387dc000, + 0x387e0000, + 0x387e4000, + 0x387e8000, + 0x387ec000, + 0x387f0000, + 0x387f4000, + 0x387f8000, + 0x387fc000, + 0x38000000, + 0x38002000, + 0x38004000, + 0x38006000, + 0x38008000, + 0x3800a000, + 0x3800c000, + 0x3800e000, + 0x38010000, + 0x38012000, + 0x38014000, + 0x38016000, + 0x38018000, + 0x3801a000, + 0x3801c000, + 0x3801e000, + 0x38020000, + 0x38022000, + 0x38024000, + 0x38026000, + 0x38028000, + 0x3802a000, + 0x3802c000, + 0x3802e000, + 0x38030000, + 0x38032000, + 0x38034000, + 0x38036000, + 0x38038000, + 0x3803a000, + 0x3803c000, + 0x3803e000, + 0x38040000, + 0x38042000, + 0x38044000, + 0x38046000, + 0x38048000, + 0x3804a000, + 0x3804c000, + 0x3804e000, + 0x38050000, + 0x38052000, + 0x38054000, + 0x38056000, + 0x38058000, + 0x3805a000, + 0x3805c000, + 0x3805e000, + 0x38060000, + 0x38062000, + 0x38064000, + 0x38066000, + 0x38068000, + 0x3806a000, + 0x3806c000, + 0x3806e000, + 0x38070000, + 0x38072000, + 0x38074000, + 0x38076000, + 0x38078000, + 0x3807a000, + 0x3807c000, + 0x3807e000, + 0x38080000, + 0x38082000, + 0x38084000, + 0x38086000, + 0x38088000, + 0x3808a000, + 0x3808c000, + 0x3808e000, + 0x38090000, + 0x38092000, + 0x38094000, + 0x38096000, + 0x38098000, + 0x3809a000, + 0x3809c000, + 0x3809e000, + 0x380a0000, + 0x380a2000, + 0x380a4000, + 0x380a6000, + 0x380a8000, + 0x380aa000, + 0x380ac000, + 0x380ae000, + 0x380b0000, + 0x380b2000, + 0x380b4000, + 0x380b6000, + 0x380b8000, + 0x380ba000, + 0x380bc000, + 0x380be000, + 0x380c0000, + 0x380c2000, + 0x380c4000, + 0x380c6000, + 0x380c8000, + 0x380ca000, + 0x380cc000, + 0x380ce000, + 0x380d0000, + 0x380d2000, + 0x380d4000, + 0x380d6000, + 0x380d8000, + 0x380da000, + 0x380dc000, + 0x380de000, + 0x380e0000, + 0x380e2000, + 0x380e4000, + 0x380e6000, + 0x380e8000, + 0x380ea000, + 0x380ec000, + 0x380ee000, + 0x380f0000, + 0x380f2000, + 0x380f4000, + 0x380f6000, + 0x380f8000, + 0x380fa000, + 0x380fc000, + 0x380fe000, + 0x38100000, + 0x38102000, + 0x38104000, + 0x38106000, + 0x38108000, + 0x3810a000, + 0x3810c000, + 0x3810e000, + 0x38110000, + 0x38112000, + 0x38114000, + 0x38116000, + 0x38118000, + 0x3811a000, + 0x3811c000, + 0x3811e000, + 0x38120000, + 0x38122000, + 0x38124000, + 0x38126000, + 0x38128000, + 0x3812a000, + 0x3812c000, + 0x3812e000, + 0x38130000, + 0x38132000, + 0x38134000, + 0x38136000, + 0x38138000, + 0x3813a000, + 0x3813c000, + 0x3813e000, + 0x38140000, + 0x38142000, + 0x38144000, + 0x38146000, + 0x38148000, + 0x3814a000, + 0x3814c000, + 0x3814e000, + 0x38150000, + 0x38152000, + 0x38154000, + 0x38156000, + 0x38158000, + 0x3815a000, + 0x3815c000, + 0x3815e000, + 0x38160000, + 0x38162000, + 0x38164000, + 0x38166000, + 0x38168000, + 0x3816a000, + 0x3816c000, + 0x3816e000, + 0x38170000, + 0x38172000, + 0x38174000, + 0x38176000, + 0x38178000, + 0x3817a000, + 0x3817c000, + 0x3817e000, + 0x38180000, + 0x38182000, + 0x38184000, + 0x38186000, + 0x38188000, + 0x3818a000, + 0x3818c000, + 0x3818e000, + 0x38190000, + 0x38192000, + 0x38194000, + 0x38196000, + 0x38198000, + 0x3819a000, + 0x3819c000, + 0x3819e000, + 0x381a0000, + 0x381a2000, + 0x381a4000, + 0x381a6000, + 0x381a8000, + 0x381aa000, + 0x381ac000, + 0x381ae000, + 0x381b0000, + 0x381b2000, + 0x381b4000, + 0x381b6000, + 0x381b8000, + 0x381ba000, + 0x381bc000, + 0x381be000, + 0x381c0000, + 0x381c2000, + 0x381c4000, + 0x381c6000, + 0x381c8000, + 0x381ca000, + 0x381cc000, + 0x381ce000, + 0x381d0000, + 0x381d2000, + 0x381d4000, + 0x381d6000, + 0x381d8000, + 0x381da000, + 0x381dc000, + 0x381de000, + 0x381e0000, + 0x381e2000, + 0x381e4000, + 0x381e6000, + 0x381e8000, + 0x381ea000, + 0x381ec000, + 0x381ee000, + 0x381f0000, + 0x381f2000, + 0x381f4000, + 0x381f6000, + 0x381f8000, + 0x381fa000, + 0x381fc000, + 0x381fe000, + 0x38200000, + 0x38202000, + 0x38204000, + 0x38206000, + 0x38208000, + 0x3820a000, + 0x3820c000, + 0x3820e000, + 0x38210000, + 0x38212000, + 0x38214000, + 0x38216000, + 0x38218000, + 0x3821a000, + 0x3821c000, + 0x3821e000, + 0x38220000, + 0x38222000, + 0x38224000, + 0x38226000, + 0x38228000, + 0x3822a000, + 0x3822c000, + 0x3822e000, + 0x38230000, + 0x38232000, + 0x38234000, + 0x38236000, + 0x38238000, + 0x3823a000, + 0x3823c000, + 0x3823e000, + 0x38240000, + 0x38242000, + 0x38244000, + 0x38246000, + 0x38248000, + 0x3824a000, + 0x3824c000, + 0x3824e000, + 0x38250000, + 0x38252000, + 0x38254000, + 0x38256000, + 0x38258000, + 0x3825a000, + 0x3825c000, + 0x3825e000, + 0x38260000, + 0x38262000, + 0x38264000, + 0x38266000, + 0x38268000, + 0x3826a000, + 0x3826c000, + 0x3826e000, + 0x38270000, + 0x38272000, + 0x38274000, + 0x38276000, + 0x38278000, + 0x3827a000, + 0x3827c000, + 0x3827e000, + 0x38280000, + 0x38282000, + 0x38284000, + 0x38286000, + 0x38288000, + 0x3828a000, + 0x3828c000, + 0x3828e000, + 0x38290000, + 0x38292000, + 0x38294000, + 0x38296000, + 0x38298000, + 0x3829a000, + 0x3829c000, + 0x3829e000, + 0x382a0000, + 0x382a2000, + 0x382a4000, + 0x382a6000, + 0x382a8000, + 0x382aa000, + 0x382ac000, + 0x382ae000, + 0x382b0000, + 0x382b2000, + 0x382b4000, + 0x382b6000, + 0x382b8000, + 0x382ba000, + 0x382bc000, + 0x382be000, + 0x382c0000, + 0x382c2000, + 0x382c4000, + 0x382c6000, + 0x382c8000, + 0x382ca000, + 0x382cc000, + 0x382ce000, + 0x382d0000, + 0x382d2000, + 0x382d4000, + 0x382d6000, + 0x382d8000, + 0x382da000, + 0x382dc000, + 0x382de000, + 0x382e0000, + 0x382e2000, + 0x382e4000, + 0x382e6000, + 0x382e8000, + 0x382ea000, + 0x382ec000, + 0x382ee000, + 0x382f0000, + 0x382f2000, + 0x382f4000, + 0x382f6000, + 0x382f8000, + 0x382fa000, + 0x382fc000, + 0x382fe000, + 0x38300000, + 0x38302000, + 0x38304000, + 0x38306000, + 0x38308000, + 0x3830a000, + 0x3830c000, + 0x3830e000, + 0x38310000, + 0x38312000, + 0x38314000, + 0x38316000, + 0x38318000, + 0x3831a000, + 0x3831c000, + 0x3831e000, + 0x38320000, + 0x38322000, + 0x38324000, + 0x38326000, + 0x38328000, + 0x3832a000, + 0x3832c000, + 0x3832e000, + 0x38330000, + 0x38332000, + 0x38334000, + 0x38336000, + 0x38338000, + 0x3833a000, + 0x3833c000, + 0x3833e000, + 0x38340000, + 0x38342000, + 0x38344000, + 0x38346000, + 0x38348000, + 0x3834a000, + 0x3834c000, + 0x3834e000, + 0x38350000, + 0x38352000, + 0x38354000, + 0x38356000, + 0x38358000, + 0x3835a000, + 0x3835c000, + 0x3835e000, + 0x38360000, + 0x38362000, + 0x38364000, + 0x38366000, + 0x38368000, + 0x3836a000, + 0x3836c000, + 0x3836e000, + 0x38370000, + 0x38372000, + 0x38374000, + 0x38376000, + 0x38378000, + 0x3837a000, + 0x3837c000, + 0x3837e000, + 0x38380000, + 0x38382000, + 0x38384000, + 0x38386000, + 0x38388000, + 0x3838a000, + 0x3838c000, + 0x3838e000, + 0x38390000, + 0x38392000, + 0x38394000, + 0x38396000, + 0x38398000, + 0x3839a000, + 0x3839c000, + 0x3839e000, + 0x383a0000, + 0x383a2000, + 0x383a4000, + 0x383a6000, + 0x383a8000, + 0x383aa000, + 0x383ac000, + 0x383ae000, + 0x383b0000, + 0x383b2000, + 0x383b4000, + 0x383b6000, + 0x383b8000, + 0x383ba000, + 0x383bc000, + 0x383be000, + 0x383c0000, + 0x383c2000, + 0x383c4000, + 0x383c6000, + 0x383c8000, + 0x383ca000, + 0x383cc000, + 0x383ce000, + 0x383d0000, + 0x383d2000, + 0x383d4000, + 0x383d6000, + 0x383d8000, + 0x383da000, + 0x383dc000, + 0x383de000, + 0x383e0000, + 0x383e2000, + 0x383e4000, + 0x383e6000, + 0x383e8000, + 0x383ea000, + 0x383ec000, + 0x383ee000, + 0x383f0000, + 0x383f2000, + 0x383f4000, + 0x383f6000, + 0x383f8000, + 0x383fa000, + 0x383fc000, + 0x383fe000, + 0x38400000, + 0x38402000, + 0x38404000, + 0x38406000, + 0x38408000, + 0x3840a000, + 0x3840c000, + 0x3840e000, + 0x38410000, + 0x38412000, + 0x38414000, + 0x38416000, + 0x38418000, + 0x3841a000, + 0x3841c000, + 0x3841e000, + 0x38420000, + 0x38422000, + 0x38424000, + 0x38426000, + 0x38428000, + 0x3842a000, + 0x3842c000, + 0x3842e000, + 0x38430000, + 0x38432000, + 0x38434000, + 0x38436000, + 0x38438000, + 0x3843a000, + 0x3843c000, + 0x3843e000, + 0x38440000, + 0x38442000, + 0x38444000, + 0x38446000, + 0x38448000, + 0x3844a000, + 0x3844c000, + 0x3844e000, + 0x38450000, + 0x38452000, + 0x38454000, + 0x38456000, + 0x38458000, + 0x3845a000, + 0x3845c000, + 0x3845e000, + 0x38460000, + 0x38462000, + 0x38464000, + 0x38466000, + 0x38468000, + 0x3846a000, + 0x3846c000, + 0x3846e000, + 0x38470000, + 0x38472000, + 0x38474000, + 0x38476000, + 0x38478000, + 0x3847a000, + 0x3847c000, + 0x3847e000, + 0x38480000, + 0x38482000, + 0x38484000, + 0x38486000, + 0x38488000, + 0x3848a000, + 0x3848c000, + 0x3848e000, + 0x38490000, + 0x38492000, + 0x38494000, + 0x38496000, + 0x38498000, + 0x3849a000, + 0x3849c000, + 0x3849e000, + 0x384a0000, + 0x384a2000, + 0x384a4000, + 0x384a6000, + 0x384a8000, + 0x384aa000, + 0x384ac000, + 0x384ae000, + 0x384b0000, + 0x384b2000, + 0x384b4000, + 0x384b6000, + 0x384b8000, + 0x384ba000, + 0x384bc000, + 0x384be000, + 0x384c0000, + 0x384c2000, + 0x384c4000, + 0x384c6000, + 0x384c8000, + 0x384ca000, + 0x384cc000, + 0x384ce000, + 0x384d0000, + 0x384d2000, + 0x384d4000, + 0x384d6000, + 0x384d8000, + 0x384da000, + 0x384dc000, + 0x384de000, + 0x384e0000, + 0x384e2000, + 0x384e4000, + 0x384e6000, + 0x384e8000, + 0x384ea000, + 0x384ec000, + 0x384ee000, + 0x384f0000, + 0x384f2000, + 0x384f4000, + 0x384f6000, + 0x384f8000, + 0x384fa000, + 0x384fc000, + 0x384fe000, + 0x38500000, + 0x38502000, + 0x38504000, + 0x38506000, + 0x38508000, + 0x3850a000, + 0x3850c000, + 0x3850e000, + 0x38510000, + 0x38512000, + 0x38514000, + 0x38516000, + 0x38518000, + 0x3851a000, + 0x3851c000, + 0x3851e000, + 0x38520000, + 0x38522000, + 0x38524000, + 0x38526000, + 0x38528000, + 0x3852a000, + 0x3852c000, + 0x3852e000, + 0x38530000, + 0x38532000, + 0x38534000, + 0x38536000, + 0x38538000, + 0x3853a000, + 0x3853c000, + 0x3853e000, + 0x38540000, + 0x38542000, + 0x38544000, + 0x38546000, + 0x38548000, + 0x3854a000, + 0x3854c000, + 0x3854e000, + 0x38550000, + 0x38552000, + 0x38554000, + 0x38556000, + 0x38558000, + 0x3855a000, + 0x3855c000, + 0x3855e000, + 0x38560000, + 0x38562000, + 0x38564000, + 0x38566000, + 0x38568000, + 0x3856a000, + 0x3856c000, + 0x3856e000, + 0x38570000, + 0x38572000, + 0x38574000, + 0x38576000, + 0x38578000, + 0x3857a000, + 0x3857c000, + 0x3857e000, + 0x38580000, + 0x38582000, + 0x38584000, + 0x38586000, + 0x38588000, + 0x3858a000, + 0x3858c000, + 0x3858e000, + 0x38590000, + 0x38592000, + 0x38594000, + 0x38596000, + 0x38598000, + 0x3859a000, + 0x3859c000, + 0x3859e000, + 0x385a0000, + 0x385a2000, + 0x385a4000, + 0x385a6000, + 0x385a8000, + 0x385aa000, + 0x385ac000, + 0x385ae000, + 0x385b0000, + 0x385b2000, + 0x385b4000, + 0x385b6000, + 0x385b8000, + 0x385ba000, + 0x385bc000, + 0x385be000, + 0x385c0000, + 0x385c2000, + 0x385c4000, + 0x385c6000, + 0x385c8000, + 0x385ca000, + 0x385cc000, + 0x385ce000, + 0x385d0000, + 0x385d2000, + 0x385d4000, + 0x385d6000, + 0x385d8000, + 0x385da000, + 0x385dc000, + 0x385de000, + 0x385e0000, + 0x385e2000, + 0x385e4000, + 0x385e6000, + 0x385e8000, + 0x385ea000, + 0x385ec000, + 0x385ee000, + 0x385f0000, + 0x385f2000, + 0x385f4000, + 0x385f6000, + 0x385f8000, + 0x385fa000, + 0x385fc000, + 0x385fe000, + 0x38600000, + 0x38602000, + 0x38604000, + 0x38606000, + 0x38608000, + 0x3860a000, + 0x3860c000, + 0x3860e000, + 0x38610000, + 0x38612000, + 0x38614000, + 0x38616000, + 0x38618000, + 0x3861a000, + 0x3861c000, + 0x3861e000, + 0x38620000, + 0x38622000, + 0x38624000, + 0x38626000, + 0x38628000, + 0x3862a000, + 0x3862c000, + 0x3862e000, + 0x38630000, + 0x38632000, + 0x38634000, + 0x38636000, + 0x38638000, + 0x3863a000, + 0x3863c000, + 0x3863e000, + 0x38640000, + 0x38642000, + 0x38644000, + 0x38646000, + 0x38648000, + 0x3864a000, + 0x3864c000, + 0x3864e000, + 0x38650000, + 0x38652000, + 0x38654000, + 0x38656000, + 0x38658000, + 0x3865a000, + 0x3865c000, + 0x3865e000, + 0x38660000, + 0x38662000, + 0x38664000, + 0x38666000, + 0x38668000, + 0x3866a000, + 0x3866c000, + 0x3866e000, + 0x38670000, + 0x38672000, + 0x38674000, + 0x38676000, + 0x38678000, + 0x3867a000, + 0x3867c000, + 0x3867e000, + 0x38680000, + 0x38682000, + 0x38684000, + 0x38686000, + 0x38688000, + 0x3868a000, + 0x3868c000, + 0x3868e000, + 0x38690000, + 0x38692000, + 0x38694000, + 0x38696000, + 0x38698000, + 0x3869a000, + 0x3869c000, + 0x3869e000, + 0x386a0000, + 0x386a2000, + 0x386a4000, + 0x386a6000, + 0x386a8000, + 0x386aa000, + 0x386ac000, + 0x386ae000, + 0x386b0000, + 0x386b2000, + 0x386b4000, + 0x386b6000, + 0x386b8000, + 0x386ba000, + 0x386bc000, + 0x386be000, + 0x386c0000, + 0x386c2000, + 0x386c4000, + 0x386c6000, + 0x386c8000, + 0x386ca000, + 0x386cc000, + 0x386ce000, + 0x386d0000, + 0x386d2000, + 0x386d4000, + 0x386d6000, + 0x386d8000, + 0x386da000, + 0x386dc000, + 0x386de000, + 0x386e0000, + 0x386e2000, + 0x386e4000, + 0x386e6000, + 0x386e8000, + 0x386ea000, + 0x386ec000, + 0x386ee000, + 0x386f0000, + 0x386f2000, + 0x386f4000, + 0x386f6000, + 0x386f8000, + 0x386fa000, + 0x386fc000, + 0x386fe000, + 0x38700000, + 0x38702000, + 0x38704000, + 0x38706000, + 0x38708000, + 0x3870a000, + 0x3870c000, + 0x3870e000, + 0x38710000, + 0x38712000, + 0x38714000, + 0x38716000, + 0x38718000, + 0x3871a000, + 0x3871c000, + 0x3871e000, + 0x38720000, + 0x38722000, + 0x38724000, + 0x38726000, + 0x38728000, + 0x3872a000, + 0x3872c000, + 0x3872e000, + 0x38730000, + 0x38732000, + 0x38734000, + 0x38736000, + 0x38738000, + 0x3873a000, + 0x3873c000, + 0x3873e000, + 0x38740000, + 0x38742000, + 0x38744000, + 0x38746000, + 0x38748000, + 0x3874a000, + 0x3874c000, + 0x3874e000, + 0x38750000, + 0x38752000, + 0x38754000, + 0x38756000, + 0x38758000, + 0x3875a000, + 0x3875c000, + 0x3875e000, + 0x38760000, + 0x38762000, + 0x38764000, + 0x38766000, + 0x38768000, + 0x3876a000, + 0x3876c000, + 0x3876e000, + 0x38770000, + 0x38772000, + 0x38774000, + 0x38776000, + 0x38778000, + 0x3877a000, + 0x3877c000, + 0x3877e000, + 0x38780000, + 0x38782000, + 0x38784000, + 0x38786000, + 0x38788000, + 0x3878a000, + 0x3878c000, + 0x3878e000, + 0x38790000, + 0x38792000, + 0x38794000, + 0x38796000, + 0x38798000, + 0x3879a000, + 0x3879c000, + 0x3879e000, + 0x387a0000, + 0x387a2000, + 0x387a4000, + 0x387a6000, + 0x387a8000, + 0x387aa000, + 0x387ac000, + 0x387ae000, + 0x387b0000, + 0x387b2000, + 0x387b4000, + 0x387b6000, + 0x387b8000, + 0x387ba000, + 0x387bc000, + 0x387be000, + 0x387c0000, + 0x387c2000, + 0x387c4000, + 0x387c6000, + 0x387c8000, + 0x387ca000, + 0x387cc000, + 0x387ce000, + 0x387d0000, + 0x387d2000, + 0x387d4000, + 0x387d6000, + 0x387d8000, + 0x387da000, + 0x387dc000, + 0x387de000, + 0x387e0000, + 0x387e2000, + 0x387e4000, + 0x387e6000, + 0x387e8000, + 0x387ea000, + 0x387ec000, + 0x387ee000, + 0x387f0000, + 0x387f2000, + 0x387f4000, + 0x387f6000, + 0x387f8000, + 0x387fa000, + 0x387fc000, + 0x387fe000, +}; + +const static unsigned g_exponent[64] = { + 0x00000000, + 0x00800000, + 0x01000000, + 0x01800000, + 0x02000000, + 0x02800000, + 0x03000000, + 0x03800000, + 0x04000000, + 0x04800000, + 0x05000000, + 0x05800000, + 0x06000000, + 0x06800000, + 0x07000000, + 0x07800000, + 0x08000000, + 0x08800000, + 0x09000000, + 0x09800000, + 0x0a000000, + 0x0a800000, + 0x0b000000, + 0x0b800000, + 0x0c000000, + 0x0c800000, + 0x0d000000, + 0x0d800000, + 0x0e000000, + 0x0e800000, + 0x0f000000, + 0x47800000, + 0x80000000, + 0x80800000, + 0x81000000, + 0x81800000, + 0x82000000, + 0x82800000, + 0x83000000, + 0x83800000, + 0x84000000, + 0x84800000, + 0x85000000, + 0x85800000, + 0x86000000, + 0x86800000, + 0x87000000, + 0x87800000, + 0x88000000, + 0x88800000, + 0x89000000, + 0x89800000, + 0x8a000000, + 0x8a800000, + 0x8b000000, + 0x8b800000, + 0x8c000000, + 0x8c800000, + 0x8d000000, + 0x8d800000, + 0x8e000000, + 0x8e800000, + 0x8f000000, + 0xc7800000, +}; + +const static unsigned g_offset[64] = { + 0x00000000, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000000, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, + 0x00000400, +}; + +float float16ToFloat32(unsigned short h) +{ + unsigned i32 = g_mantissa[g_offset[h >> 10] + (h & 0x3ff)] + g_exponent[h >> 10]; + return bitCast<float>(i32); +} +} + diff --git a/gfx/angle/src/common/Float16ToFloat32.py b/gfx/angle/src/common/Float16ToFloat32.py new file mode 100755 index 000000000..7705f7b61 --- /dev/null +++ b/gfx/angle/src/common/Float16ToFloat32.py @@ -0,0 +1,80 @@ +# Copyright (c) 2012 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. +# + +# This script generates a function that converts 16-bit precision floating +# point numbers to 32-bit. +# It is based on ftp://ftp.fox-toolkit.org/pub/fasthalffloatconversion.pdf. + +#include "common/mathutil.h" + +def convertMantissa(i): + if i == 0: + return 0 + elif i < 1024: + m = i << 13 + e = 0 + while not (m & 0x00800000): + e -= 0x00800000 + m = m << 1 + m &= ~0x00800000 + e += 0x38800000 + return m | e + else: + return 0x38000000 + ((i - 1024) << 13) + +def convertExponent(i): + if i == 0: + return 0 + elif i in range(1, 31): + return i << 23 + elif i == 31: + return 0x47800000 + elif i == 32: + return 0x80000000 + elif i in range(33, 63): + return 0x80000000 + ((i - 32) << 23) + else: + return 0xC7800000 + +def convertOffset(i): + if i == 0 or i == 32: + return 0 + else: + return 1024 + +print """// +// Copyright (c) 2012 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. +// + +// This file is automatically generated. + +namespace gl +{ +""" + +print "const static unsigned g_mantissa[2048] = {" +for i in range(0, 2048): + print " %#010x," % convertMantissa(i) +print "};\n" + +print "const static unsigned g_exponent[64] = {" +for i in range(0, 64): + print " %#010x," % convertExponent(i) +print "};\n" + +print "const static unsigned g_offset[64] = {" +for i in range(0, 64): + print " %#010x," % convertOffset(i) +print "};\n" + +print """float float16ToFloat32(unsigned short h) +{ + unsigned i32 = g_mantissa[g_offset[h >> 10] + (h & 0x3ff)] + g_exponent[h >> 10]; + return bitCast<float>(i32); +} +} +""" diff --git a/gfx/angle/src/common/MemoryBuffer.cpp b/gfx/angle/src/common/MemoryBuffer.cpp new file mode 100755 index 000000000..e7a3fb4a2 --- /dev/null +++ b/gfx/angle/src/common/MemoryBuffer.cpp @@ -0,0 +1,80 @@ +// +// Copyright (c) 2014 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. +// + +#include "common/MemoryBuffer.h" + +#include <algorithm> +#include <cstdlib> + +#include "common/debug.h" + +namespace rx +{ + +MemoryBuffer::MemoryBuffer() + : mSize(0), + mData(NULL) +{ +} + +MemoryBuffer::~MemoryBuffer() +{ + free(mData); + mData = NULL; +} + +bool MemoryBuffer::resize(size_t size) +{ + if (size == 0) + { + free(mData); + mData = NULL; + mSize = 0; + return true; + } + + if (size == mSize) + { + return true; + } + + // Only reallocate if the size has changed. + uint8_t *newMemory = reinterpret_cast<uint8_t*>(malloc(sizeof(uint8_t) * size)); + if (newMemory == NULL) + { + return false; + } + + if (mData) + { + // Copy the intersection of the old data and the new data + std::copy(mData, mData + std::min(mSize, size), newMemory); + free(mData); + } + + mData = newMemory; + mSize = size; + + return true; +} + +size_t MemoryBuffer::size() const +{ + return mSize; +} + +const uint8_t *MemoryBuffer::data() const +{ + return mData; +} + +uint8_t *MemoryBuffer::data() +{ + ASSERT(mData); + return mData; +} + +} diff --git a/gfx/angle/src/common/MemoryBuffer.h b/gfx/angle/src/common/MemoryBuffer.h new file mode 100755 index 000000000..ec621cbca --- /dev/null +++ b/gfx/angle/src/common/MemoryBuffer.h @@ -0,0 +1,38 @@ +// +// Copyright (c) 2014 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. +// + +#ifndef COMMON_MEMORYBUFFER_H_ +#define COMMON_MEMORYBUFFER_H_ + +#include "common/angleutils.h" + +#include <cstddef> +#include <stdint.h> + +namespace rx +{ + +class MemoryBuffer : angle::NonCopyable +{ + public: + MemoryBuffer(); + ~MemoryBuffer(); + + bool resize(size_t size); + size_t size() const; + bool empty() const { return mSize == 0; } + + const uint8_t *data() const; + uint8_t *data(); + + private: + size_t mSize; + uint8_t *mData; +}; + +} + +#endif // COMMON_MEMORYBUFFER_H_ diff --git a/gfx/angle/src/common/Optional.h b/gfx/angle/src/common/Optional.h new file mode 100755 index 000000000..5a79048d6 --- /dev/null +++ b/gfx/angle/src/common/Optional.h @@ -0,0 +1,74 @@ +// +// Copyright (c) 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. +// +// Optional.h: +// Represents a type that may be invalid, similar to std::optional. +// + +#ifndef COMMON_OPTIONAL_H_ +#define COMMON_OPTIONAL_H_ + +template <class T> +struct Optional +{ + Optional() + : mValid(false), + mValue(T()) + {} + + Optional(const T &valueIn) : mValid(true), mValue(valueIn) {} + + Optional(const Optional &other) + : mValid(other.mValid), + mValue(other.mValue) + {} + + Optional &operator=(const Optional &other) + { + this->mValid = other.mValid; + this->mValue = other.mValue; + return *this; + } + + Optional &operator=(const T &value) + { + mValue = value; + mValid = true; + return *this; + } + + Optional &operator=(T &&value) + { + mValue = std::move(value); + mValid = true; + return *this; + } + + void reset() + { + mValid = false; + } + + static Optional Invalid() { return Optional(); } + + bool valid() const { return mValid; } + const T &value() const { return mValue; } + + bool operator==(const Optional &other) const + { + return ((mValid == other.mValid) && (!mValid || (mValue == other.mValue))); + } + + bool operator!=(const Optional &other) const + { + return !(*this == other); + } + + private: + bool mValid; + T mValue; +}; + +#endif // COMMON_OPTIONAL_H_ diff --git a/gfx/angle/src/common/Optional_unittest.cpp b/gfx/angle/src/common/Optional_unittest.cpp new file mode 100755 index 000000000..810046184 --- /dev/null +++ b/gfx/angle/src/common/Optional_unittest.cpp @@ -0,0 +1,47 @@ +// +// Copyright (c) 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. +// +// Unit tests for ANGLE's Optional helper class. +// + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +#include "common/Optional.h" + +namespace +{ + +TEST(OptionalTest, BasicInvalid) +{ + Optional<int> testInvalid; + ASSERT_FALSE(testInvalid.valid()); + ASSERT_EQ(Optional<int>::Invalid(), testInvalid); +} + +TEST(OptionalTest, BasicValid) +{ + Optional<int> testValid(3); + ASSERT_TRUE(testValid.valid()); + ASSERT_EQ(3, testValid.value()); + ASSERT_NE(Optional<int>::Invalid(), testValid); +} + +TEST(OptionalTest, Copies) +{ + Optional<int> testValid(3); + Optional<int> testInvalid; + + Optional<int> testCopy = testInvalid; + ASSERT_FALSE(testCopy.valid()); + ASSERT_EQ(testInvalid, testCopy); + + testCopy = testValid; + ASSERT_TRUE(testCopy.valid()); + ASSERT_EQ(3, testCopy.value()); + ASSERT_EQ(testValid, testCopy); +} + +} // namespace diff --git a/gfx/angle/src/common/angleutils.cpp b/gfx/angle/src/common/angleutils.cpp new file mode 100755 index 000000000..7099c2173 --- /dev/null +++ b/gfx/angle/src/common/angleutils.cpp @@ -0,0 +1,52 @@ +// +// Copyright (c) 2014 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. +// + +#include "common/angleutils.h" +#include "common/debug.h" + +#include <stdio.h> + +#include <limits> +#include <vector> + +namespace angle +{ +const uintptr_t DirtyPointer = std::numeric_limits<uintptr_t>::max(); +} + +size_t FormatStringIntoVector(const char *fmt, va_list vararg, std::vector<char>& outBuffer) +{ + // Attempt to just print to the current buffer + int len = vsnprintf(&(outBuffer.front()), outBuffer.size(), fmt, vararg); + if (len < 0 || static_cast<size_t>(len) >= outBuffer.size()) + { + // Buffer was not large enough, calculate the required size and resize the buffer + len = vsnprintf(NULL, 0, fmt, vararg); + outBuffer.resize(len + 1); + + // Print again + len = vsnprintf(&(outBuffer.front()), outBuffer.size(), fmt, vararg); + } + ASSERT(len >= 0); + return static_cast<size_t>(len); +} + +std::string FormatString(const char *fmt, va_list vararg) +{ + static std::vector<char> buffer(512); + + size_t len = FormatStringIntoVector(fmt, vararg, buffer); + return std::string(&buffer[0], len); +} + +std::string FormatString(const char *fmt, ...) +{ + va_list vararg; + va_start(vararg, fmt); + std::string result = FormatString(fmt, vararg); + va_end(vararg); + return result; +} diff --git a/gfx/angle/src/common/angleutils.h b/gfx/angle/src/common/angleutils.h new file mode 100755 index 000000000..f5ef7bdc1 --- /dev/null +++ b/gfx/angle/src/common/angleutils.h @@ -0,0 +1,187 @@ +// +// Copyright (c) 2002-2014 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. +// + +// angleutils.h: Common ANGLE utilities. + +#ifndef COMMON_ANGLEUTILS_H_ +#define COMMON_ANGLEUTILS_H_ + +#include "common/platform.h" + +#include <climits> +#include <cstdarg> +#include <cstddef> +#include <string> +#include <set> +#include <sstream> +#include <vector> + +// A helper class to disallow copy and assignment operators +namespace angle +{ + +class NonCopyable +{ + public: + NonCopyable() = default; + ~NonCopyable() = default; + protected: + NonCopyable(const NonCopyable&) = delete; + void operator=(const NonCopyable&) = delete; +}; + +extern const uintptr_t DirtyPointer; +} // namespace angle + +template <typename T, size_t N> +constexpr inline size_t ArraySize(T (&)[N]) +{ + return N; +} + +template <typename T, unsigned int N> +void SafeRelease(T (&resourceBlock)[N]) +{ + for (unsigned int i = 0; i < N; i++) + { + SafeRelease(resourceBlock[i]); + } +} + +template <typename T> +void SafeRelease(T& resource) +{ + if (resource) + { + resource->Release(); + resource = NULL; + } +} + +template <typename T> +void SafeDelete(T *&resource) +{ + delete resource; + resource = NULL; +} + +template <typename T> +void SafeDeleteContainer(T& resource) +{ + for (auto &element : resource) + { + SafeDelete(element); + } + resource.clear(); +} + +template <typename T> +void SafeDeleteArray(T*& resource) +{ + delete[] resource; + resource = NULL; +} + +// Provide a less-than function for comparing structs +// Note: struct memory must be initialized to zero, because of packing gaps +template <typename T> +inline bool StructLessThan(const T &a, const T &b) +{ + return (memcmp(&a, &b, sizeof(T)) < 0); +} + +// Provide a less-than function for comparing structs +// Note: struct memory must be initialized to zero, because of packing gaps +template <typename T> +inline bool StructEquals(const T &a, const T &b) +{ + return (memcmp(&a, &b, sizeof(T)) == 0); +} + +template <typename T> +inline void StructZero(T *obj) +{ + memset(obj, 0, sizeof(T)); +} + +template <typename T> +inline bool IsMaskFlagSet(T mask, T flag) +{ + // Handles multibit flags as well + return (mask & flag) == flag; +} + +inline const char* MakeStaticString(const std::string &str) +{ + static std::set<std::string> strings; + std::set<std::string>::iterator it = strings.find(str); + if (it != strings.end()) + { + return it->c_str(); + } + + return strings.insert(str).first->c_str(); +} + +inline std::string ArrayString(unsigned int i) +{ + // We assume UINT_MAX and GL_INVALID_INDEX are equal + // See DynamicHLSL.cpp + if (i == UINT_MAX) + { + return ""; + } + + std::stringstream strstr; + + strstr << "["; + strstr << i; + strstr << "]"; + + return strstr.str(); +} + +inline std::string Str(int i) +{ + std::stringstream strstr; + strstr << i; + return strstr.str(); +} + +size_t FormatStringIntoVector(const char *fmt, va_list vararg, std::vector<char>& buffer); + +std::string FormatString(const char *fmt, va_list vararg); +std::string FormatString(const char *fmt, ...); + +template <typename T> +std::string ToString(const T &value) +{ + std::ostringstream o; + o << value; + return o.str(); +} + +// snprintf is not defined with MSVC prior to to msvc14 +#if defined(_MSC_VER) && _MSC_VER < 1900 +#define snprintf _snprintf +#endif + +#define GL_BGR565_ANGLEX 0x6ABB +#define GL_BGRA4_ANGLEX 0x6ABC +#define GL_BGR5_A1_ANGLEX 0x6ABD +#define GL_INT_64_ANGLEX 0x6ABE +#define GL_STRUCT_ANGLEX 0x6ABF + +// Hidden enum for the NULL D3D device type. +#define EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE 0x6AC0 + +#define ANGLE_TRY_CHECKED_MATH(result) \ + if (!result.IsValid()) \ + { \ + return gl::Error(GL_INVALID_OPERATION, "Integer overflow."); \ + } + +#endif // COMMON_ANGLEUTILS_H_ diff --git a/gfx/angle/src/common/debug.cpp b/gfx/angle/src/common/debug.cpp new file mode 100755 index 000000000..f64d9322f --- /dev/null +++ b/gfx/angle/src/common/debug.cpp @@ -0,0 +1,179 @@ +// +// Copyright (c) 2002-2010 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. +// + +// debug.cpp: Debugging utilities. + +#include "common/debug.h" + +#include <stdarg.h> + +#include <cstdio> +#include <fstream> +#include <iostream> +#include <vector> + +#include "common/angleutils.h" +#include "common/platform.h" +#include "common/Optional.h" + +namespace gl +{ + +namespace +{ + +class FormattedString final : angle::NonCopyable +{ + public: + FormattedString(const char *format, va_list vararg) : mFormat(format) + { + va_copy(mVarArg, vararg); + } + + const char *c_str() { return str().c_str(); } + + const std::string &str() + { + if (!mMessage.valid()) + { + mMessage = FormatString(mFormat, mVarArg); + } + return mMessage.value(); + } + + size_t length() + { + c_str(); + return mMessage.value().length(); + } + + private: + const char *mFormat; + va_list mVarArg; + Optional<std::string> mMessage; +}; +enum DebugTraceOutputType +{ + DebugTraceOutputTypeNone, + DebugTraceOutputTypeSetMarker, + DebugTraceOutputTypeBeginEvent +}; + +DebugAnnotator *g_debugAnnotator = nullptr; + +void output(bool traceInDebugOnly, MessageType messageType, DebugTraceOutputType outputType, + const char *format, va_list vararg) +{ + if (DebugAnnotationsActive()) + { + static std::vector<char> buffer(512); + size_t len = FormatStringIntoVector(format, vararg, buffer); + std::wstring formattedWideMessage(buffer.begin(), buffer.begin() + len); + + ASSERT(g_debugAnnotator != nullptr); + switch (outputType) + { + case DebugTraceOutputTypeNone: + break; + case DebugTraceOutputTypeBeginEvent: + g_debugAnnotator->beginEvent(formattedWideMessage.c_str()); + break; + case DebugTraceOutputTypeSetMarker: + g_debugAnnotator->setMarker(formattedWideMessage.c_str()); + break; + } + } + + FormattedString formattedMessage(format, vararg); + + if (messageType == MESSAGE_ERR) + { + std::cerr << formattedMessage.c_str(); +#if !defined(NDEBUG) && defined(_MSC_VER) + OutputDebugStringA(formattedMessage.c_str()); +#endif // !defined(NDEBUG) && defined(_MSC_VER) + } + +#if defined(ANGLE_ENABLE_DEBUG_TRACE) +#if defined(NDEBUG) + if (traceInDebugOnly) + { + return; + } +#endif // NDEBUG + static std::ofstream file(TRACE_OUTPUT_FILE, std::ofstream::app); + if (file) + { + file.write(formattedMessage.c_str(), formattedMessage.length()); + file.flush(); + } + +#if defined(ANGLE_ENABLE_DEBUG_TRACE_TO_DEBUGGER) + OutputDebugStringA(formattedMessage.c_str()); +#endif // ANGLE_ENABLE_DEBUG_TRACE_TO_DEBUGGER + +#endif // ANGLE_ENABLE_DEBUG_TRACE +} + +} // namespace + +bool DebugAnnotationsActive() +{ +#if defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS) + return g_debugAnnotator != nullptr && g_debugAnnotator->getStatus(); +#else + return false; +#endif +} + +void InitializeDebugAnnotations(DebugAnnotator *debugAnnotator) +{ + UninitializeDebugAnnotations(); + g_debugAnnotator = debugAnnotator; +} + +void UninitializeDebugAnnotations() +{ + // Pointer is not managed. + g_debugAnnotator = nullptr; +} + +void trace(bool traceInDebugOnly, MessageType messageType, const char *format, ...) +{ + va_list vararg; + va_start(vararg, format); + output(traceInDebugOnly, messageType, DebugTraceOutputTypeSetMarker, format, vararg); + va_end(vararg); +} + +ScopedPerfEventHelper::ScopedPerfEventHelper(const char* format, ...) +{ +#if !defined(ANGLE_ENABLE_DEBUG_TRACE) + if (!DebugAnnotationsActive()) + { + return; + } +#endif // !ANGLE_ENABLE_DEBUG_TRACE + va_list vararg; + va_start(vararg, format); + output(true, MESSAGE_EVENT, DebugTraceOutputTypeBeginEvent, format, vararg); + va_end(vararg); +} + +ScopedPerfEventHelper::~ScopedPerfEventHelper() +{ + if (DebugAnnotationsActive()) + { + g_debugAnnotator->endEvent(); + } +} + +std::ostream &DummyStream() +{ + return std::cout; +} + +} // namespace gl diff --git a/gfx/angle/src/common/debug.h b/gfx/angle/src/common/debug.h new file mode 100755 index 000000000..9356090ae --- /dev/null +++ b/gfx/angle/src/common/debug.h @@ -0,0 +1,174 @@ +// +// Copyright (c) 2002-2010 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. +// + +// debug.h: Debugging utilities. + +#ifndef COMMON_DEBUG_H_ +#define COMMON_DEBUG_H_ + +#include <assert.h> +#include <stdio.h> +#include <string> + +#include "common/angleutils.h" + +#if !defined(TRACE_OUTPUT_FILE) +#define TRACE_OUTPUT_FILE "angle_debug.txt" +#endif + +namespace gl +{ + +enum MessageType +{ + MESSAGE_TRACE, + MESSAGE_FIXME, + MESSAGE_ERR, + MESSAGE_EVENT, +}; + +// Outputs text to the debugging log, or the debugging window +void trace(bool traceInDebugOnly, MessageType messageType, const char *format, ...); + +// Pairs a D3D begin event with an end event. +class ScopedPerfEventHelper : angle::NonCopyable +{ + public: + ScopedPerfEventHelper(const char* format, ...); + ~ScopedPerfEventHelper(); +}; + +// Wraps the D3D9/D3D11 debug annotation functions. +class DebugAnnotator : angle::NonCopyable +{ + public: + DebugAnnotator() { }; + virtual ~DebugAnnotator() { }; + virtual void beginEvent(const wchar_t *eventName) = 0; + virtual void endEvent() = 0; + virtual void setMarker(const wchar_t *markerName) = 0; + virtual bool getStatus() = 0; +}; + +void InitializeDebugAnnotations(DebugAnnotator *debugAnnotator); +void UninitializeDebugAnnotations(); +bool DebugAnnotationsActive(); + +// This class is used to explicitly ignore values in the conditional logging macros. This avoids +// compiler warnings like "value computed is not used" and "statement has no effect". +class LogMessageVoidify +{ + public: + LogMessageVoidify() {} + // This has to be an operator with a precedence lower than << but higher than ?: + void operator&(std::ostream &) {} +}; + +// This can be any ostream, it is unused, but needs to be a valid reference. +std::ostream &DummyStream(); + +} // namespace gl + +#if defined(ANGLE_ENABLE_DEBUG_TRACE) || defined(ANGLE_ENABLE_DEBUG_ANNOTATIONS) +#define ANGLE_TRACE_ENABLED +#endif + +#define ANGLE_EMPTY_STATEMENT for (;;) break +#if !defined(NDEBUG) || defined(ANGLE_ENABLE_RELEASE_ASSERTS) +#define ANGLE_ENABLE_ASSERTS +#endif + +// A macro to output a trace of a function call and its arguments to the debugging log +#if defined(ANGLE_TRACE_ENABLED) +#define TRACE(message, ...) gl::trace(true, gl::MESSAGE_TRACE, "trace: %s(%d): " message "\n", __FUNCTION__, __LINE__, ##__VA_ARGS__) +#else +#define TRACE(message, ...) (void(0)) +#endif + +// A macro to output a function call and its arguments to the debugging log, to denote an item in need of fixing. +#if defined(ANGLE_TRACE_ENABLED) +#define FIXME(message, ...) gl::trace(false, gl::MESSAGE_FIXME, "fixme: %s(%d): " message "\n", __FUNCTION__, __LINE__, ##__VA_ARGS__) +#else +#define FIXME(message, ...) (void(0)) +#endif + +// A macro to output a function call and its arguments to the debugging log, in case of error. +#if defined(ANGLE_TRACE_ENABLED) || defined(ANGLE_ENABLE_ASSERTS) +#define ERR(message, ...) gl::trace(false, gl::MESSAGE_ERR, "err: %s(%d): " message "\n", __FUNCTION__, __LINE__, ##__VA_ARGS__) +#else +#define ERR(message, ...) (void(0)) +#endif + +// A macro to log a performance event around a scope. +#if defined(ANGLE_TRACE_ENABLED) +#if defined(_MSC_VER) +#define EVENT(message, ...) gl::ScopedPerfEventHelper scopedPerfEventHelper ## __LINE__("%s" message "\n", __FUNCTION__, __VA_ARGS__); +#else +#define EVENT(message, ...) gl::ScopedPerfEventHelper scopedPerfEventHelper("%s" message "\n", __FUNCTION__, ##__VA_ARGS__); +#endif // _MSC_VER +#else +#define EVENT(message, ...) (void(0)) +#endif + +#if defined(ANGLE_TRACE_ENABLED) +#undef ANGLE_TRACE_ENABLED +#endif + +#if defined(COMPILER_GCC) || defined(__clang__) +#define ANGLE_CRASH() __builtin_trap() +#else +#define ANGLE_CRASH() ((void)(*(volatile char *)0 = 0)) +#endif + +#if !defined(NDEBUG) +#define ANGLE_ASSERT_IMPL(expression) assert(expression) +#else +// TODO(jmadill): Detect if debugger is attached and break. +#define ANGLE_ASSERT_IMPL(expression) ANGLE_CRASH() +#endif // !defined(NDEBUG) + +// Helper macro which avoids evaluating the arguments to a stream if the condition doesn't hold. +// Condition is evaluated once and only once. +#define ANGLE_LAZY_STREAM(stream, condition) \ + !(condition) ? static_cast<void>(0) : ::gl::LogMessageVoidify() & (stream) + +#if defined(NDEBUG) && !defined(ANGLE_ENABLE_ASSERTS) +#define ANGLE_ASSERTS_ON 0 +#else +#define ANGLE_ASSERTS_ON 1 +#endif + +// A macro asserting a condition and outputting failures to the debug log +#if ANGLE_ASSERTS_ON +#define ASSERT(expression) \ + (expression ? static_cast<void>(0) \ + : (ERR("\t! Assert failed in %s(%d): %s\n", __FUNCTION__, __LINE__, #expression), \ + ANGLE_ASSERT_IMPL(expression))) +#else +#define ASSERT(condition) \ + ANGLE_LAZY_STREAM(::gl::DummyStream(), ANGLE_ASSERTS_ON ? !(condition) : false) \ + << "Check failed: " #condition ". " +#endif // ANGLE_ASSERTS_ON + +#define UNUSED_VARIABLE(variable) ((void)variable) + +// A macro to indicate unimplemented functionality +#ifndef NOASSERT_UNIMPLEMENTED +#define NOASSERT_UNIMPLEMENTED 1 +#endif + +#define UNIMPLEMENTED() \ + { \ + ERR("\t! Unimplemented: %s(%d)\n", __FUNCTION__, __LINE__); \ + ASSERT(NOASSERT_UNIMPLEMENTED); \ + } \ + ANGLE_EMPTY_STATEMENT + +// A macro for code which is not expected to be reached under valid assumptions +#define UNREACHABLE() \ + (ERR("\t! Unreachable reached: %s(%d)\n", __FUNCTION__, __LINE__), ASSERT(false)) + +#endif // COMMON_DEBUG_H_ diff --git a/gfx/angle/src/common/event_tracer.cpp b/gfx/angle/src/common/event_tracer.cpp new file mode 100755 index 000000000..c9eb5e307 --- /dev/null +++ b/gfx/angle/src/common/event_tracer.cpp @@ -0,0 +1,56 @@ +// Copyright (c) 2012 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. + +#include "common/event_tracer.h" + +#include "common/debug.h" + +namespace angle +{ + +const unsigned char *GetTraceCategoryEnabledFlag(const char *name) +{ + angle::Platform *platform = ANGLEPlatformCurrent(); + ASSERT(platform); + + const unsigned char *categoryEnabledFlag = platform->getTraceCategoryEnabledFlag(name); + if (categoryEnabledFlag != nullptr) + { + return categoryEnabledFlag; + } + + static unsigned char disabled = 0; + return &disabled; +} + +Platform::TraceEventHandle AddTraceEvent(char phase, const unsigned char* categoryGroupEnabled, const char* name, unsigned long long id, + int numArgs, const char** argNames, const unsigned char* argTypes, + const unsigned long long* argValues, unsigned char flags) +{ + angle::Platform *platform = ANGLEPlatformCurrent(); + ASSERT(platform); + + double timestamp = platform->monotonicallyIncreasingTime(); + + if (timestamp != 0) + { + angle::Platform::TraceEventHandle handle = + platform->addTraceEvent(phase, + categoryGroupEnabled, + name, + id, + timestamp, + numArgs, + argNames, + argTypes, + argValues, + flags); + ASSERT(handle != 0); + return handle; + } + + return static_cast<Platform::TraceEventHandle>(0); +} + +} // namespace angle diff --git a/gfx/angle/src/common/event_tracer.h b/gfx/angle/src/common/event_tracer.h new file mode 100755 index 000000000..ed70f249d --- /dev/null +++ b/gfx/angle/src/common/event_tracer.h @@ -0,0 +1,22 @@ +// Copyright (c) 2012 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. + +#ifndef COMMON_EVENT_TRACER_H_ +#define COMMON_EVENT_TRACER_H_ + +#include "common/platform.h" +#include "platform/Platform.h" + +namespace angle +{ + +const unsigned char *GetTraceCategoryEnabledFlag(const char* name); +Platform::TraceEventHandle AddTraceEvent(char phase, const unsigned char* categoryGroupEnabled, const char* name, + unsigned long long id, int numArgs, const char** argNames, + const unsigned char* argTypes, const unsigned long long* argValues, + unsigned char flags); + +} + +#endif // COMMON_EVENT_TRACER_H_ diff --git a/gfx/angle/src/common/mathutil.cpp b/gfx/angle/src/common/mathutil.cpp new file mode 100755 index 000000000..5db997c66 --- /dev/null +++ b/gfx/angle/src/common/mathutil.cpp @@ -0,0 +1,73 @@ +// +// Copyright (c) 2013 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. +// + +// mathutil.cpp: Math and bit manipulation functions. + +#include "common/mathutil.h" + +#include <algorithm> +#include <math.h> + +namespace gl +{ + +namespace +{ + +struct RGB9E5Data +{ + unsigned int R : 9; + unsigned int G : 9; + unsigned int B : 9; + unsigned int E : 5; +}; + +// B is the exponent bias (15) +constexpr int g_sharedexp_bias = 15; + +// N is the number of mantissa bits per component (9) +constexpr int g_sharedexp_mantissabits = 9; + +// Emax is the maximum allowed biased exponent value (31) +constexpr int g_sharedexp_maxexponent = 31; + +constexpr float g_sharedexp_max = + ((static_cast<float>(1 << g_sharedexp_mantissabits) - 1) / + static_cast<float>(1 << g_sharedexp_mantissabits)) * + static_cast<float>(1 << (g_sharedexp_maxexponent - g_sharedexp_bias)); + +} // anonymous namespace + +unsigned int convertRGBFloatsTo999E5(float red, float green, float blue) +{ + const float red_c = std::max<float>(0, std::min(g_sharedexp_max, red)); + const float green_c = std::max<float>(0, std::min(g_sharedexp_max, green)); + const float blue_c = std::max<float>(0, std::min(g_sharedexp_max, blue)); + + const float max_c = std::max<float>(std::max<float>(red_c, green_c), blue_c); + const float exp_p = std::max<float>(-g_sharedexp_bias - 1, floor(log(max_c))) + 1 + g_sharedexp_bias; + const int max_s = static_cast<int>(floor((max_c / (pow(2.0f, exp_p - g_sharedexp_bias - g_sharedexp_mantissabits))) + 0.5f)); + const int exp_s = static_cast<int>((max_s < pow(2.0f, g_sharedexp_mantissabits)) ? exp_p : exp_p + 1); + + RGB9E5Data output; + output.R = static_cast<unsigned int>(floor((red_c / (pow(2.0f, exp_s - g_sharedexp_bias - g_sharedexp_mantissabits))) + 0.5f)); + output.G = static_cast<unsigned int>(floor((green_c / (pow(2.0f, exp_s - g_sharedexp_bias - g_sharedexp_mantissabits))) + 0.5f)); + output.B = static_cast<unsigned int>(floor((blue_c / (pow(2.0f, exp_s - g_sharedexp_bias - g_sharedexp_mantissabits))) + 0.5f)); + output.E = exp_s; + + return bitCast<unsigned int>(output); +} + +void convert999E5toRGBFloats(unsigned int input, float *red, float *green, float *blue) +{ + const RGB9E5Data *inputData = reinterpret_cast<const RGB9E5Data*>(&input); + + *red = inputData->R * pow(2.0f, (int)inputData->E - g_sharedexp_bias - g_sharedexp_mantissabits); + *green = inputData->G * pow(2.0f, (int)inputData->E - g_sharedexp_bias - g_sharedexp_mantissabits); + *blue = inputData->B * pow(2.0f, (int)inputData->E - g_sharedexp_bias - g_sharedexp_mantissabits); +} + +} // namespace gl diff --git a/gfx/angle/src/common/mathutil.h b/gfx/angle/src/common/mathutil.h new file mode 100755 index 000000000..630b6c088 --- /dev/null +++ b/gfx/angle/src/common/mathutil.h @@ -0,0 +1,852 @@ +// +// Copyright (c) 2002-2013 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. +// + +// mathutil.h: Math and bit manipulation functions. + +#ifndef COMMON_MATHUTIL_H_ +#define COMMON_MATHUTIL_H_ + +#include <limits> +#include <algorithm> +#include <math.h> +#include <string.h> +#include <stdint.h> +#include <stdlib.h> + +#include <base/numerics/safe_math.h> + +#include "common/debug.h" +#include "common/platform.h" + +namespace angle +{ +using base::CheckedNumeric; +using base::IsValueInRangeForNumericType; +} + +namespace gl +{ + +const unsigned int Float32One = 0x3F800000; +const unsigned short Float16One = 0x3C00; + +struct Vector4 +{ + Vector4() {} + Vector4(float x, float y, float z, float w) : x(x), y(y), z(z), w(w) {} + + float x; + float y; + float z; + float w; +}; + +struct Vector2 +{ + Vector2() {} + Vector2(float x, float y) : x(x), y(y) {} + + float x; + float y; +}; + +inline bool isPow2(int x) +{ + return (x & (x - 1)) == 0 && (x != 0); +} + +inline int log2(int x) +{ + int r = 0; + while ((x >> r) > 1) r++; + return r; +} + +inline unsigned int ceilPow2(unsigned int x) +{ + if (x != 0) x--; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + x++; + + return x; +} + +inline int clampToInt(unsigned int x) +{ + return static_cast<int>(std::min(x, static_cast<unsigned int>(std::numeric_limits<int>::max()))); +} + +template <typename DestT, typename SrcT> +inline DestT clampCast(SrcT value) +{ + static const DestT destLo = std::numeric_limits<DestT>::min(); + static const DestT destHi = std::numeric_limits<DestT>::max(); + static const SrcT srcLo = static_cast<SrcT>(destLo); + static const SrcT srcHi = static_cast<SrcT>(destHi); + + // When value is outside of or equal to the limits for DestT we use the DestT limit directly. + // This avoids undefined behaviors due to loss of precision when converting from floats to + // integers: + // destHi for ints is 2147483647 but the closest float number is around 2147483648, so when + // doing a conversion from float to int we run into an UB because the float is outside of the + // range representable by the int. + if (value <= srcLo) + { + return destLo; + } + else if (value >= srcHi) + { + return destHi; + } + else + { + return static_cast<DestT>(value); + } +} + +template<typename T, typename MIN, typename MAX> +inline T clamp(T x, MIN min, MAX max) +{ + // Since NaNs fail all comparison tests, a NaN value will default to min + return x > min ? (x > max ? max : x) : min; +} + +inline float clamp01(float x) +{ + return clamp(x, 0.0f, 1.0f); +} + +template<const int n> +inline unsigned int unorm(float x) +{ + const unsigned int max = 0xFFFFFFFF >> (32 - n); + + if (x > 1) + { + return max; + } + else if (x < 0) + { + return 0; + } + else + { + return (unsigned int)(max * x + 0.5f); + } +} + +inline bool supportsSSE2() +{ +#if defined(ANGLE_USE_SSE) + static bool checked = false; + static bool supports = false; + + if (checked) + { + return supports; + } + +#if defined(ANGLE_PLATFORM_WINDOWS) && !defined(_M_ARM) + { + int info[4]; + __cpuid(info, 0); + + if (info[0] >= 1) + { + __cpuid(info, 1); + + supports = (info[3] >> 26) & 1; + } + } +#endif // defined(ANGLE_PLATFORM_WINDOWS) && !defined(_M_ARM) + checked = true; + return supports; +#else // defined(ANGLE_USE_SSE) + return false; +#endif +} + +template <typename destType, typename sourceType> +destType bitCast(const sourceType &source) +{ + size_t copySize = std::min(sizeof(destType), sizeof(sourceType)); + destType output; + memcpy(&output, &source, copySize); + return output; +} + +inline unsigned short float32ToFloat16(float fp32) +{ + unsigned int fp32i = bitCast<unsigned int>(fp32); + unsigned int sign = (fp32i & 0x80000000) >> 16; + unsigned int abs = fp32i & 0x7FFFFFFF; + + if(abs > 0x47FFEFFF) // Infinity + { + return static_cast<unsigned short>(sign | 0x7FFF); + } + else if(abs < 0x38800000) // Denormal + { + unsigned int mantissa = (abs & 0x007FFFFF) | 0x00800000; + int e = 113 - (abs >> 23); + + if(e < 24) + { + abs = mantissa >> e; + } + else + { + abs = 0; + } + + return static_cast<unsigned short>(sign | (abs + 0x00000FFF + ((abs >> 13) & 1)) >> 13); + } + else + { + return static_cast<unsigned short>(sign | (abs + 0xC8000000 + 0x00000FFF + ((abs >> 13) & 1)) >> 13); + } +} + +float float16ToFloat32(unsigned short h); + +unsigned int convertRGBFloatsTo999E5(float red, float green, float blue); +void convert999E5toRGBFloats(unsigned int input, float *red, float *green, float *blue); + +inline unsigned short float32ToFloat11(float fp32) +{ + const unsigned int float32MantissaMask = 0x7FFFFF; + const unsigned int float32ExponentMask = 0x7F800000; + const unsigned int float32SignMask = 0x80000000; + const unsigned int float32ValueMask = ~float32SignMask; + const unsigned int float32ExponentFirstBit = 23; + const unsigned int float32ExponentBias = 127; + + const unsigned short float11Max = 0x7BF; + const unsigned short float11MantissaMask = 0x3F; + const unsigned short float11ExponentMask = 0x7C0; + const unsigned short float11BitMask = 0x7FF; + const unsigned int float11ExponentBias = 14; + + const unsigned int float32Maxfloat11 = 0x477E0000; + const unsigned int float32Minfloat11 = 0x38800000; + + const unsigned int float32Bits = bitCast<unsigned int>(fp32); + const bool float32Sign = (float32Bits & float32SignMask) == float32SignMask; + + unsigned int float32Val = float32Bits & float32ValueMask; + + if ((float32Val & float32ExponentMask) == float32ExponentMask) + { + // INF or NAN + if ((float32Val & float32MantissaMask) != 0) + { + return float11ExponentMask | (((float32Val >> 17) | (float32Val >> 11) | (float32Val >> 6) | (float32Val)) & float11MantissaMask); + } + else if (float32Sign) + { + // -INF is clamped to 0 since float11 is positive only + return 0; + } + else + { + return float11ExponentMask; + } + } + else if (float32Sign) + { + // float11 is positive only, so clamp to zero + return 0; + } + else if (float32Val > float32Maxfloat11) + { + // The number is too large to be represented as a float11, set to max + return float11Max; + } + else + { + if (float32Val < float32Minfloat11) + { + // The number is too small to be represented as a normalized float11 + // Convert it to a denormalized value. + const unsigned int shift = (float32ExponentBias - float11ExponentBias) - (float32Val >> float32ExponentFirstBit); + float32Val = ((1 << float32ExponentFirstBit) | (float32Val & float32MantissaMask)) >> shift; + } + else + { + // Rebias the exponent to represent the value as a normalized float11 + float32Val += 0xC8000000; + } + + return ((float32Val + 0xFFFF + ((float32Val >> 17) & 1)) >> 17) & float11BitMask; + } +} + +inline unsigned short float32ToFloat10(float fp32) +{ + const unsigned int float32MantissaMask = 0x7FFFFF; + const unsigned int float32ExponentMask = 0x7F800000; + const unsigned int float32SignMask = 0x80000000; + const unsigned int float32ValueMask = ~float32SignMask; + const unsigned int float32ExponentFirstBit = 23; + const unsigned int float32ExponentBias = 127; + + const unsigned short float10Max = 0x3DF; + const unsigned short float10MantissaMask = 0x1F; + const unsigned short float10ExponentMask = 0x3E0; + const unsigned short float10BitMask = 0x3FF; + const unsigned int float10ExponentBias = 14; + + const unsigned int float32Maxfloat10 = 0x477C0000; + const unsigned int float32Minfloat10 = 0x38800000; + + const unsigned int float32Bits = bitCast<unsigned int>(fp32); + const bool float32Sign = (float32Bits & float32SignMask) == float32SignMask; + + unsigned int float32Val = float32Bits & float32ValueMask; + + if ((float32Val & float32ExponentMask) == float32ExponentMask) + { + // INF or NAN + if ((float32Val & float32MantissaMask) != 0) + { + return float10ExponentMask | (((float32Val >> 18) | (float32Val >> 13) | (float32Val >> 3) | (float32Val)) & float10MantissaMask); + } + else if (float32Sign) + { + // -INF is clamped to 0 since float11 is positive only + return 0; + } + else + { + return float10ExponentMask; + } + } + else if (float32Sign) + { + // float10 is positive only, so clamp to zero + return 0; + } + else if (float32Val > float32Maxfloat10) + { + // The number is too large to be represented as a float11, set to max + return float10Max; + } + else + { + if (float32Val < float32Minfloat10) + { + // The number is too small to be represented as a normalized float11 + // Convert it to a denormalized value. + const unsigned int shift = (float32ExponentBias - float10ExponentBias) - (float32Val >> float32ExponentFirstBit); + float32Val = ((1 << float32ExponentFirstBit) | (float32Val & float32MantissaMask)) >> shift; + } + else + { + // Rebias the exponent to represent the value as a normalized float11 + float32Val += 0xC8000000; + } + + return ((float32Val + 0x1FFFF + ((float32Val >> 18) & 1)) >> 18) & float10BitMask; + } +} + +inline float float11ToFloat32(unsigned short fp11) +{ + unsigned short exponent = (fp11 >> 6) & 0x1F; + unsigned short mantissa = fp11 & 0x3F; + + if (exponent == 0x1F) + { + // INF or NAN + return bitCast<float>(0x7f800000 | (mantissa << 17)); + } + else + { + if (exponent != 0) + { + // normalized + } + else if (mantissa != 0) + { + // The value is denormalized + exponent = 1; + + do + { + exponent--; + mantissa <<= 1; + } + while ((mantissa & 0x40) == 0); + + mantissa = mantissa & 0x3F; + } + else // The value is zero + { + exponent = static_cast<unsigned short>(-112); + } + + return bitCast<float>(((exponent + 112) << 23) | (mantissa << 17)); + } +} + +inline float float10ToFloat32(unsigned short fp11) +{ + unsigned short exponent = (fp11 >> 5) & 0x1F; + unsigned short mantissa = fp11 & 0x1F; + + if (exponent == 0x1F) + { + // INF or NAN + return bitCast<float>(0x7f800000 | (mantissa << 17)); + } + else + { + if (exponent != 0) + { + // normalized + } + else if (mantissa != 0) + { + // The value is denormalized + exponent = 1; + + do + { + exponent--; + mantissa <<= 1; + } + while ((mantissa & 0x20) == 0); + + mantissa = mantissa & 0x1F; + } + else // The value is zero + { + exponent = static_cast<unsigned short>(-112); + } + + return bitCast<float>(((exponent + 112) << 23) | (mantissa << 18)); + } +} + +template <typename T> +inline float normalizedToFloat(T input) +{ + static_assert(std::numeric_limits<T>::is_integer, "T must be an integer."); + + const float inverseMax = 1.0f / std::numeric_limits<T>::max(); + return input * inverseMax; +} + +template <unsigned int inputBitCount, typename T> +inline float normalizedToFloat(T input) +{ + static_assert(std::numeric_limits<T>::is_integer, "T must be an integer."); + static_assert(inputBitCount < (sizeof(T) * 8), "T must have more bits than inputBitCount."); + + const float inverseMax = 1.0f / ((1 << inputBitCount) - 1); + return input * inverseMax; +} + +template <typename T> +inline T floatToNormalized(float input) +{ + return static_cast<T>(std::numeric_limits<T>::max() * input + 0.5f); +} + +template <unsigned int outputBitCount, typename T> +inline T floatToNormalized(float input) +{ + static_assert(outputBitCount < (sizeof(T) * 8), "T must have more bits than outputBitCount."); + return static_cast<T>(((1 << outputBitCount) - 1) * input + 0.5f); +} + +template <unsigned int inputBitCount, unsigned int inputBitStart, typename T> +inline T getShiftedData(T input) +{ + static_assert(inputBitCount + inputBitStart <= (sizeof(T) * 8), + "T must have at least as many bits as inputBitCount + inputBitStart."); + const T mask = (1 << inputBitCount) - 1; + return (input >> inputBitStart) & mask; +} + +template <unsigned int inputBitCount, unsigned int inputBitStart, typename T> +inline T shiftData(T input) +{ + static_assert(inputBitCount + inputBitStart <= (sizeof(T) * 8), + "T must have at least as many bits as inputBitCount + inputBitStart."); + const T mask = (1 << inputBitCount) - 1; + return (input & mask) << inputBitStart; +} + +inline unsigned int CountLeadingZeros(uint32_t x) +{ + // Use binary search to find the amount of leading zeros. + unsigned int zeros = 32u; + uint32_t y; + + y = x >> 16u; + if (y != 0) + { + zeros = zeros - 16u; + x = y; + } + y = x >> 8u; + if (y != 0) + { + zeros = zeros - 8u; + x = y; + } + y = x >> 4u; + if (y != 0) + { + zeros = zeros - 4u; + x = y; + } + y = x >> 2u; + if (y != 0) + { + zeros = zeros - 2u; + x = y; + } + y = x >> 1u; + if (y != 0) + { + return zeros - 2u; + } + return zeros - x; +} + +inline unsigned char average(unsigned char a, unsigned char b) +{ + return ((a ^ b) >> 1) + (a & b); +} + +inline signed char average(signed char a, signed char b) +{ + return ((short)a + (short)b) / 2; +} + +inline unsigned short average(unsigned short a, unsigned short b) +{ + return ((a ^ b) >> 1) + (a & b); +} + +inline signed short average(signed short a, signed short b) +{ + return ((int)a + (int)b) / 2; +} + +inline unsigned int average(unsigned int a, unsigned int b) +{ + return ((a ^ b) >> 1) + (a & b); +} + +inline int average(int a, int b) +{ + long long average = (static_cast<long long>(a) + static_cast<long long>(b)) / 2ll; + return static_cast<int>(average); +} + +inline float average(float a, float b) +{ + return (a + b) * 0.5f; +} + +inline unsigned short averageHalfFloat(unsigned short a, unsigned short b) +{ + return float32ToFloat16((float16ToFloat32(a) + float16ToFloat32(b)) * 0.5f); +} + +inline unsigned int averageFloat11(unsigned int a, unsigned int b) +{ + return float32ToFloat11((float11ToFloat32(static_cast<unsigned short>(a)) + float11ToFloat32(static_cast<unsigned short>(b))) * 0.5f); +} + +inline unsigned int averageFloat10(unsigned int a, unsigned int b) +{ + return float32ToFloat10((float10ToFloat32(static_cast<unsigned short>(a)) + float10ToFloat32(static_cast<unsigned short>(b))) * 0.5f); +} + +template <typename T> +struct Range +{ + Range() {} + Range(T lo, T hi) : start(lo), end(hi) { ASSERT(lo <= hi); } + + T start; + T end; + + T length() const { return end - start; } + + bool intersects(Range<T> other) + { + if (start <= other.start) + { + return other.start < end; + } + else + { + return start < other.end; + } + } + + void extend(T value) + { + start = value > start ? value : start; + end = value < end ? value : end; + } + + bool empty() const + { + return end <= start; + } +}; + +typedef Range<int> RangeI; +typedef Range<unsigned int> RangeUI; + +struct IndexRange +{ + IndexRange() : IndexRange(0, 0, 0) {} + IndexRange(size_t start_, size_t end_, size_t vertexIndexCount_) + : start(start_), end(end_), vertexIndexCount(vertexIndexCount_) + { + ASSERT(start <= end); + } + + // Number of vertices in the range. + size_t vertexCount() const { return (end - start) + 1; } + + // Inclusive range of indices that are not primitive restart + size_t start; + size_t end; + + // Number of non-primitive restart indices + size_t vertexIndexCount; +}; + +// First, both normalized floating-point values are converted into 16-bit integer values. +// Then, the results are packed into the returned 32-bit unsigned integer. +// The first float value will be written to the least significant bits of the output; +// the last float value will be written to the most significant bits. +// The conversion of each value to fixed point is done as follows : +// packSnorm2x16 : round(clamp(c, -1, +1) * 32767.0) +inline uint32_t packSnorm2x16(float f1, float f2) +{ + int16_t leastSignificantBits = static_cast<int16_t>(roundf(clamp(f1, -1.0f, 1.0f) * 32767.0f)); + int16_t mostSignificantBits = static_cast<int16_t>(roundf(clamp(f2, -1.0f, 1.0f) * 32767.0f)); + return static_cast<uint32_t>(mostSignificantBits) << 16 | + (static_cast<uint32_t>(leastSignificantBits) & 0xFFFF); +} + +// First, unpacks a single 32-bit unsigned integer u into a pair of 16-bit unsigned integers. Then, each +// component is converted to a normalized floating-point value to generate the returned two float values. +// The first float value will be extracted from the least significant bits of the input; +// the last float value will be extracted from the most-significant bits. +// The conversion for unpacked fixed-point value to floating point is done as follows: +// unpackSnorm2x16 : clamp(f / 32767.0, -1, +1) +inline void unpackSnorm2x16(uint32_t u, float *f1, float *f2) +{ + int16_t leastSignificantBits = static_cast<int16_t>(u & 0xFFFF); + int16_t mostSignificantBits = static_cast<int16_t>(u >> 16); + *f1 = clamp(static_cast<float>(leastSignificantBits) / 32767.0f, -1.0f, 1.0f); + *f2 = clamp(static_cast<float>(mostSignificantBits) / 32767.0f, -1.0f, 1.0f); +} + +// First, both normalized floating-point values are converted into 16-bit integer values. +// Then, the results are packed into the returned 32-bit unsigned integer. +// The first float value will be written to the least significant bits of the output; +// the last float value will be written to the most significant bits. +// The conversion of each value to fixed point is done as follows: +// packUnorm2x16 : round(clamp(c, 0, +1) * 65535.0) +inline uint32_t packUnorm2x16(float f1, float f2) +{ + uint16_t leastSignificantBits = static_cast<uint16_t>(roundf(clamp(f1, 0.0f, 1.0f) * 65535.0f)); + uint16_t mostSignificantBits = static_cast<uint16_t>(roundf(clamp(f2, 0.0f, 1.0f) * 65535.0f)); + return static_cast<uint32_t>(mostSignificantBits) << 16 | static_cast<uint32_t>(leastSignificantBits); +} + +// First, unpacks a single 32-bit unsigned integer u into a pair of 16-bit unsigned integers. Then, each +// component is converted to a normalized floating-point value to generate the returned two float values. +// The first float value will be extracted from the least significant bits of the input; +// the last float value will be extracted from the most-significant bits. +// The conversion for unpacked fixed-point value to floating point is done as follows: +// unpackUnorm2x16 : f / 65535.0 +inline void unpackUnorm2x16(uint32_t u, float *f1, float *f2) +{ + uint16_t leastSignificantBits = static_cast<uint16_t>(u & 0xFFFF); + uint16_t mostSignificantBits = static_cast<uint16_t>(u >> 16); + *f1 = static_cast<float>(leastSignificantBits) / 65535.0f; + *f2 = static_cast<float>(mostSignificantBits) / 65535.0f; +} + +// Returns an unsigned integer obtained by converting the two floating-point values to the 16-bit +// floating-point representation found in the OpenGL ES Specification, and then packing these +// two 16-bit integers into a 32-bit unsigned integer. +// f1: The 16 least-significant bits of the result; +// f2: The 16 most-significant bits. +inline uint32_t packHalf2x16(float f1, float f2) +{ + uint16_t leastSignificantBits = static_cast<uint16_t>(float32ToFloat16(f1)); + uint16_t mostSignificantBits = static_cast<uint16_t>(float32ToFloat16(f2)); + return static_cast<uint32_t>(mostSignificantBits) << 16 | static_cast<uint32_t>(leastSignificantBits); +} + +// Returns two floating-point values obtained by unpacking a 32-bit unsigned integer into a pair of 16-bit values, +// interpreting those values as 16-bit floating-point numbers according to the OpenGL ES Specification, +// and converting them to 32-bit floating-point values. +// The first float value is obtained from the 16 least-significant bits of u; +// the second component is obtained from the 16 most-significant bits of u. +inline void unpackHalf2x16(uint32_t u, float *f1, float *f2) +{ + uint16_t leastSignificantBits = static_cast<uint16_t>(u & 0xFFFF); + uint16_t mostSignificantBits = static_cast<uint16_t>(u >> 16); + + *f1 = float16ToFloat32(leastSignificantBits); + *f2 = float16ToFloat32(mostSignificantBits); +} + +// Returns whether the argument is Not a Number. +// IEEE 754 single precision NaN representation: Exponent(8 bits) - 255, Mantissa(23 bits) - non-zero. +inline bool isNaN(float f) +{ + // Exponent mask: ((1u << 8) - 1u) << 23 = 0x7f800000u + // Mantissa mask: ((1u << 23) - 1u) = 0x7fffffu + return ((bitCast<uint32_t>(f) & 0x7f800000u) == 0x7f800000u) && (bitCast<uint32_t>(f) & 0x7fffffu); +} + +// Returns whether the argument is infinity. +// IEEE 754 single precision infinity representation: Exponent(8 bits) - 255, Mantissa(23 bits) - zero. +inline bool isInf(float f) +{ + // Exponent mask: ((1u << 8) - 1u) << 23 = 0x7f800000u + // Mantissa mask: ((1u << 23) - 1u) = 0x7fffffu + return ((bitCast<uint32_t>(f) & 0x7f800000u) == 0x7f800000u) && !(bitCast<uint32_t>(f) & 0x7fffffu); +} + +namespace priv +{ +template <unsigned int N, unsigned int R> +struct iSquareRoot +{ + static constexpr unsigned int solve() + { + return (R * R > N) + ? 0 + : ((R * R == N) ? R : static_cast<unsigned int>(iSquareRoot<N, R + 1>::value)); + } + enum Result + { + value = iSquareRoot::solve() + }; +}; + +template <unsigned int N> +struct iSquareRoot<N, N> +{ + enum result + { + value = N + }; +}; + +} // namespace priv + +template <unsigned int N> +constexpr unsigned int iSquareRoot() +{ + return priv::iSquareRoot<N, 1>::value; +} + +// Sum, difference and multiplication operations for signed ints that wrap on 32-bit overflow. +// +// Unsigned types are defined to do arithmetic modulo 2^n in C++. For signed types, overflow +// behavior is undefined. + +template <typename T> +inline T WrappingSum(T lhs, T rhs) +{ + uint32_t lhsUnsigned = static_cast<uint32_t>(lhs); + uint32_t rhsUnsigned = static_cast<uint32_t>(rhs); + return static_cast<T>(lhsUnsigned + rhsUnsigned); +} + +template <typename T> +inline T WrappingDiff(T lhs, T rhs) +{ + uint32_t lhsUnsigned = static_cast<uint32_t>(lhs); + uint32_t rhsUnsigned = static_cast<uint32_t>(rhs); + return static_cast<T>(lhsUnsigned - rhsUnsigned); +} + +inline int32_t WrappingMul(int32_t lhs, int32_t rhs) +{ + int64_t lhsWide = static_cast<int64_t>(lhs); + int64_t rhsWide = static_cast<int64_t>(rhs); + // The multiplication is guaranteed not to overflow. + int64_t resultWide = lhsWide * rhsWide; + // Implement the desired wrapping behavior by masking out the high-order 32 bits. + resultWide = resultWide & 0xffffffffll; + // Casting to a narrower signed type is fine since the casted value is representable in the + // narrower type. + return static_cast<int32_t>(resultWide); +} + +} // namespace gl + +namespace rx +{ + +template <typename T> +T roundUp(const T value, const T alignment) +{ + auto temp = value + alignment - static_cast<T>(1); + return temp - temp % alignment; +} + +template <typename T> +angle::CheckedNumeric<T> CheckedRoundUp(const T value, const T alignment) +{ + angle::CheckedNumeric<T> checkedValue(value); + angle::CheckedNumeric<T> checkedAlignment(alignment); + return roundUp(checkedValue, checkedAlignment); +} + +inline unsigned int UnsignedCeilDivide(unsigned int value, unsigned int divisor) +{ + unsigned int divided = value / divisor; + return (divided + ((value % divisor == 0) ? 0 : 1)); +} + +#if defined(_MSC_VER) + +#define ANGLE_ROTL(x,y) _rotl(x,y) +#define ANGLE_ROTR16(x,y) _rotr16(x,y) + +#else + +inline uint32_t RotL(uint32_t x, int8_t r) +{ + return (x << r) | (x >> (32 - r)); +} + +inline uint16_t RotR16(uint16_t x, int8_t r) +{ + return (x >> r) | (x << (16 - r)); +} + +#define ANGLE_ROTL(x, y) ::rx::RotL(x, y) +#define ANGLE_ROTR16(x, y) ::rx::RotR16(x, y) + +#endif // namespace rx + +} + +#endif // COMMON_MATHUTIL_H_ diff --git a/gfx/angle/src/common/mathutil_unittest.cpp b/gfx/angle/src/common/mathutil_unittest.cpp new file mode 100755 index 000000000..bf443b72b --- /dev/null +++ b/gfx/angle/src/common/mathutil_unittest.cpp @@ -0,0 +1,210 @@ +// +// 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. +// +// mathutil_unittest: +// Unit tests for the utils defined in mathutil.h +// + +#include "mathutil.h" + +#include <gtest/gtest.h> + +using namespace gl; + +namespace +{ + +// Test the correctness of packSnorm2x16 and unpackSnorm2x16 functions. +// For floats f1 and f2, unpackSnorm2x16(packSnorm2x16(f1, f2)) should be same as f1 and f2. +TEST(MathUtilTest, packAndUnpackSnorm2x16) +{ + const float input[8][2] = + { + { 0.0f, 0.0f }, + { 1.0f, 1.0f }, + { -1.0f, 1.0f }, + { -1.0f, -1.0f }, + { 0.875f, 0.75f }, + { 0.00392f, -0.99215f }, + { -0.000675f, 0.004954f }, + { -0.6937f, -0.02146f } + }; + const float floatFaultTolerance = 0.0001f; + float outputVal1, outputVal2; + + for (size_t i = 0; i < 8; i++) + { + unpackSnorm2x16(packSnorm2x16(input[i][0], input[i][1]), &outputVal1, &outputVal2); + EXPECT_NEAR(input[i][0], outputVal1, floatFaultTolerance); + EXPECT_NEAR(input[i][1], outputVal2, floatFaultTolerance); + } +} + +// Test the correctness of packSnorm2x16 and unpackSnorm2x16 functions with infinity values, +// result should be clamped to [-1, 1]. +TEST(MathUtilTest, packAndUnpackSnorm2x16Infinity) +{ + const float floatFaultTolerance = 0.0001f; + float outputVal1, outputVal2; + + unpackSnorm2x16(packSnorm2x16(std::numeric_limits<float>::infinity(), + std::numeric_limits<float>::infinity()), &outputVal1, &outputVal2); + EXPECT_NEAR(1.0f, outputVal1, floatFaultTolerance); + EXPECT_NEAR(1.0f, outputVal2, floatFaultTolerance); + + unpackSnorm2x16(packSnorm2x16(std::numeric_limits<float>::infinity(), + -std::numeric_limits<float>::infinity()), &outputVal1, &outputVal2); + EXPECT_NEAR(1.0f, outputVal1, floatFaultTolerance); + EXPECT_NEAR(-1.0f, outputVal2, floatFaultTolerance); + + unpackSnorm2x16(packSnorm2x16(-std::numeric_limits<float>::infinity(), + -std::numeric_limits<float>::infinity()), &outputVal1, &outputVal2); + EXPECT_NEAR(-1.0f, outputVal1, floatFaultTolerance); + EXPECT_NEAR(-1.0f, outputVal2, floatFaultTolerance); +} + +// Test the correctness of packUnorm2x16 and unpackUnorm2x16 functions. +// For floats f1 and f2, unpackUnorm2x16(packUnorm2x16(f1, f2)) should be same as f1 and f2. +TEST(MathUtilTest, packAndUnpackUnorm2x16) +{ + const float input[8][2] = + { + { 0.0f, 0.0f }, + { 1.0f, 1.0f }, + { -1.0f, 1.0f }, + { -1.0f, -1.0f }, + { 0.875f, 0.75f }, + { 0.00392f, -0.99215f }, + { -0.000675f, 0.004954f }, + { -0.6937f, -0.02146f } + }; + const float floatFaultTolerance = 0.0001f; + float outputVal1, outputVal2; + + for (size_t i = 0; i < 8; i++) + { + unpackUnorm2x16(packUnorm2x16(input[i][0], input[i][1]), &outputVal1, &outputVal2); + float expected = input[i][0] < 0.0f ? 0.0f : input[i][0]; + EXPECT_NEAR(expected, outputVal1, floatFaultTolerance); + expected = input[i][1] < 0.0f ? 0.0f : input[i][1]; + EXPECT_NEAR(expected, outputVal2, floatFaultTolerance); + } +} + +// Test the correctness of packUnorm2x16 and unpackUnorm2x16 functions with infinity values, +// result should be clamped to [0, 1]. +TEST(MathUtilTest, packAndUnpackUnorm2x16Infinity) +{ + const float floatFaultTolerance = 0.0001f; + float outputVal1, outputVal2; + + unpackUnorm2x16(packUnorm2x16(std::numeric_limits<float>::infinity(), + std::numeric_limits<float>::infinity()), &outputVal1, &outputVal2); + EXPECT_NEAR(1.0f, outputVal1, floatFaultTolerance); + EXPECT_NEAR(1.0f, outputVal2, floatFaultTolerance); + + unpackUnorm2x16(packUnorm2x16(std::numeric_limits<float>::infinity(), + -std::numeric_limits<float>::infinity()), &outputVal1, &outputVal2); + EXPECT_NEAR(1.0f, outputVal1, floatFaultTolerance); + EXPECT_NEAR(0.0f, outputVal2, floatFaultTolerance); + + unpackUnorm2x16(packUnorm2x16(-std::numeric_limits<float>::infinity(), + -std::numeric_limits<float>::infinity()), &outputVal1, &outputVal2); + EXPECT_NEAR(0.0f, outputVal1, floatFaultTolerance); + EXPECT_NEAR(0.0f, outputVal2, floatFaultTolerance); +} + +// Test the correctness of packHalf2x16 and unpackHalf2x16 functions. +// For floats f1 and f2, unpackHalf2x16(packHalf2x16(f1, f2)) should be same as f1 and f2. +TEST(MathUtilTest, packAndUnpackHalf2x16) +{ + const float input[8][2] = + { + { 0.0f, 0.0f }, + { 1.0f, 1.0f }, + { -1.0f, 1.0f }, + { -1.0f, -1.0f }, + { 0.875f, 0.75f }, + { 0.00392f, -0.99215f }, + { -0.000675f, 0.004954f }, + { -0.6937f, -0.02146f }, + }; + const float floatFaultTolerance = 0.0005f; + float outputVal1, outputVal2; + + for (size_t i = 0; i < 8; i++) + { + unpackHalf2x16(packHalf2x16(input[i][0], input[i][1]), &outputVal1, &outputVal2); + EXPECT_NEAR(input[i][0], outputVal1, floatFaultTolerance); + EXPECT_NEAR(input[i][1], outputVal2, floatFaultTolerance); + } +} + +// Test the correctness of gl::isNaN function. +TEST(MathUtilTest, isNaN) +{ + EXPECT_TRUE(isNaN(bitCast<float>(0xffu << 23 | 1u))); + EXPECT_TRUE(isNaN(bitCast<float>(1u << 31 | 0xffu << 23 | 1u))); + EXPECT_TRUE(isNaN(bitCast<float>(1u << 31 | 0xffu << 23 | 0x400000u))); + EXPECT_TRUE(isNaN(bitCast<float>(1u << 31 | 0xffu << 23 | 0x7fffffu))); + EXPECT_FALSE(isNaN(0.0f)); + EXPECT_FALSE(isNaN(bitCast<float>(1u << 31 | 0xffu << 23))); + EXPECT_FALSE(isNaN(bitCast<float>(0xffu << 23))); +} + +// Test the correctness of gl::isInf function. +TEST(MathUtilTest, isInf) +{ + EXPECT_TRUE(isInf(bitCast<float>(0xffu << 23))); + EXPECT_TRUE(isInf(bitCast<float>(1u << 31 | 0xffu << 23))); + EXPECT_FALSE(isInf(0.0f)); + EXPECT_FALSE(isInf(bitCast<float>(0xffu << 23 | 1u))); + EXPECT_FALSE(isInf(bitCast<float>(1u << 31 | 0xffu << 23 | 1u))); + EXPECT_FALSE(isInf(bitCast<float>(1u << 31 | 0xffu << 23 | 0x400000u))); + EXPECT_FALSE(isInf(bitCast<float>(1u << 31 | 0xffu << 23 | 0x7fffffu))); + EXPECT_FALSE(isInf(bitCast<float>(0xfeu << 23 | 0x7fffffu))); + EXPECT_FALSE(isInf(bitCast<float>(1u << 31 | 0xfeu << 23 | 0x7fffffu))); +} + +TEST(MathUtilTest, CountLeadingZeros) +{ + for (unsigned int i = 0; i < 32u; ++i) + { + uint32_t iLeadingZeros = 1u << (31u - i); + EXPECT_EQ(i, CountLeadingZeros(iLeadingZeros)); + } + EXPECT_EQ(32u, CountLeadingZeros(0)); +} + +// Some basic tests. Tests that rounding up zero produces zero. +TEST(MathUtilTest, BasicRoundUp) +{ + EXPECT_EQ(0u, rx::roundUp(0u, 4u)); + EXPECT_EQ(4u, rx::roundUp(1u, 4u)); + EXPECT_EQ(4u, rx::roundUp(4u, 4u)); +} + +// Test that rounding up zero produces zero for checked ints. +TEST(MathUtilTest, CheckedRoundUpZero) +{ + auto checkedValue = rx::CheckedRoundUp(0u, 4u); + ASSERT_TRUE(checkedValue.IsValid()); + ASSERT_EQ(0u, checkedValue.ValueOrDie()); +} + +// Test out-of-bounds with CheckedRoundUp +TEST(MathUtilTest, CheckedRoundUpInvalid) +{ + // The answer to this query is out of bounds. + auto limit = std::numeric_limits<unsigned int>::max(); + auto checkedValue = rx::CheckedRoundUp(limit, limit - 1); + ASSERT_FALSE(checkedValue.IsValid()); + + // Our implementation can't handle this query, despite the parameters being in range. + auto checkedLimit = rx::CheckedRoundUp(limit - 1, limit); + ASSERT_FALSE(checkedLimit.IsValid()); +} + +} // anonymous namespace diff --git a/gfx/angle/src/common/matrix_utils.h b/gfx/angle/src/common/matrix_utils.h new file mode 100755 index 000000000..aa3f89536 --- /dev/null +++ b/gfx/angle/src/common/matrix_utils.h @@ -0,0 +1,386 @@ +// +// 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. +// +// Matrix: +// Utility class implementing various matrix operations. +// Supports matrices with minimum 2 and maximum 4 number of rows/columns. +// +// TODO: Check if we can merge Matrix.h in sample_util with this and replace it with this implementation. +// TODO: Rename this file to Matrix.h once we remove Matrix.h in sample_util. + +#ifndef COMMON_MATRIX_UTILS_H_ +#define COMMON_MATRIX_UTILS_H_ + +#include <vector> + +#include "common/debug.h" +#include "common/mathutil.h" + +namespace angle +{ + +template<typename T> +class Matrix +{ + public: + Matrix(const std::vector<T> &elements, const unsigned int &numRows, const unsigned int &numCols) + : mElements(elements), + mRows(numRows), + mCols(numCols) + { + ASSERT(rows() >= 1 && rows() <= 4); + ASSERT(columns() >= 1 && columns() <= 4); + } + + Matrix(const std::vector<T> &elements, const unsigned int &size) + : mElements(elements), + mRows(size), + mCols(size) + { + ASSERT(rows() >= 1 && rows() <= 4); + ASSERT(columns() >= 1 && columns() <= 4); + } + + Matrix(const T *elements, const unsigned int &size) + : mRows(size), + mCols(size) + { + ASSERT(rows() >= 1 && rows() <= 4); + ASSERT(columns() >= 1 && columns() <= 4); + for (size_t i = 0; i < size * size; i++) + mElements.push_back(elements[i]); + } + + const T &operator()(const unsigned int &rowIndex, const unsigned int &columnIndex) const + { + return mElements[rowIndex * columns() + columnIndex]; + } + + T &operator()(const unsigned int &rowIndex, const unsigned int &columnIndex) + { + return mElements[rowIndex * columns() + columnIndex]; + } + + const T &at(const unsigned int &rowIndex, const unsigned int &columnIndex) const + { + return operator()(rowIndex, columnIndex); + } + + Matrix<T> operator*(const Matrix<T> &m) + { + ASSERT(columns() == m.rows()); + + unsigned int resultRows = rows(); + unsigned int resultCols = m.columns(); + Matrix<T> result(std::vector<T>(resultRows * resultCols), resultRows, resultCols); + for (unsigned int i = 0; i < resultRows; i++) + { + for (unsigned int j = 0; j < resultCols; j++) + { + T tmp = 0.0f; + for (unsigned int k = 0; k < columns(); k++) + tmp += at(i, k) * m(k, j); + result(i, j) = tmp; + } + } + + return result; + } + + unsigned int size() const + { + ASSERT(rows() == columns()); + return rows(); + } + + unsigned int rows() const { return mRows; } + + unsigned int columns() const { return mCols; } + + std::vector<T> elements() const { return mElements; } + + Matrix<T> compMult(const Matrix<T> &mat1) const + { + Matrix result(std::vector<T>(mElements.size()), size()); + for (unsigned int i = 0; i < columns(); i++) + for (unsigned int j = 0; j < rows(); j++) + result(i, j) = at(i, j) * mat1(i, j); + + return result; + } + + Matrix<T> outerProduct(const Matrix<T> &mat1) const + { + unsigned int cols = mat1.columns(); + Matrix result(std::vector<T>(rows() * cols), rows(), cols); + for (unsigned int i = 0; i < rows(); i++) + for (unsigned int j = 0; j < cols; j++) + result(i, j) = at(i, 0) * mat1(0, j); + + return result; + } + + Matrix<T> transpose() const + { + Matrix result(std::vector<T>(mElements.size()), columns(), rows()); + for (unsigned int i = 0; i < columns(); i++) + for (unsigned int j = 0; j < rows(); j++) + result(i, j) = at(j, i); + + return result; + } + + T determinant() const + { + ASSERT(rows() == columns()); + + switch (size()) + { + case 2: + return at(0, 0) * at(1, 1) - at(0, 1) * at(1, 0); + + case 3: + return at(0, 0) * at(1, 1) * at(2, 2) + + at(0, 1) * at(1, 2) * at(2, 0) + + at(0, 2) * at(1, 0) * at(2, 1) - + at(0, 2) * at(1, 1) * at(2, 0) - + at(0, 1) * at(1, 0) * at(2, 2) - + at(0, 0) * at(1, 2) * at(2, 1); + + case 4: + { + const float minorMatrices[4][3 * 3] = + { + { + at(1, 1), at(2, 1), at(3, 1), + at(1, 2), at(2, 2), at(3, 2), + at(1, 3), at(2, 3), at(3, 3), + }, + { + at(1, 0), at(2, 0), at(3, 0), + at(1, 2), at(2, 2), at(3, 2), + at(1, 3), at(2, 3), at(3, 3), + }, + { + at(1, 0), at(2, 0), at(3, 0), + at(1, 1), at(2, 1), at(3, 1), + at(1, 3), at(2, 3), at(3, 3), + }, + { + at(1, 0), at(2, 0), at(3, 0), + at(1, 1), at(2, 1), at(3, 1), + at(1, 2), at(2, 2), at(3, 2), + } + }; + return at(0, 0) * Matrix<T>(minorMatrices[0], 3).determinant() - + at(0, 1) * Matrix<T>(minorMatrices[1], 3).determinant() + + at(0, 2) * Matrix<T>(minorMatrices[2], 3).determinant() - + at(0, 3) * Matrix<T>(minorMatrices[3], 3).determinant(); + } + + default: + UNREACHABLE(); + break; + } + + return T(); + } + + Matrix<T> inverse() const + { + ASSERT(rows() == columns()); + + Matrix<T> cof(std::vector<T>(mElements.size()), rows(), columns()); + switch (size()) + { + case 2: + cof(0, 0) = at(1, 1); + cof(0, 1) = -at(1, 0); + cof(1, 0) = -at(0, 1); + cof(1, 1) = at(0, 0); + break; + + case 3: + cof(0, 0) = at(1, 1) * at(2, 2) - + at(2, 1) * at(1, 2); + cof(0, 1) = -(at(1, 0) * at(2, 2) - + at(2, 0) * at(1, 2)); + cof(0, 2) = at(1, 0) * at(2, 1) - + at(2, 0) * at(1, 1); + cof(1, 0) = -(at(0, 1) * at(2, 2) - + at(2, 1) * at(0, 2)); + cof(1, 1) = at(0, 0) * at(2, 2) - + at(2, 0) * at(0, 2); + cof(1, 2) = -(at(0, 0) * at(2, 1) - + at(2, 0) * at(0, 1)); + cof(2, 0) = at(0, 1) * at(1, 2) - + at(1, 1) * at(0, 2); + cof(2, 1) = -(at(0, 0) * at(1, 2) - + at(1, 0) * at(0, 2)); + cof(2, 2) = at(0, 0) * at(1, 1) - + at(1, 0) * at(0, 1); + break; + + case 4: + cof(0, 0) = at(1, 1) * at(2, 2) * at(3, 3) + + at(2, 1) * at(3, 2) * at(1, 3) + + at(3, 1) * at(1, 2) * at(2, 3) - + at(1, 1) * at(3, 2) * at(2, 3) - + at(2, 1) * at(1, 2) * at(3, 3) - + at(3, 1) * at(2, 2) * at(1, 3); + cof(0, 1) = -(at(1, 0) * at(2, 2) * at(3, 3) + + at(2, 0) * at(3, 2) * at(1, 3) + + at(3, 0) * at(1, 2) * at(2, 3) - + at(1, 0) * at(3, 2) * at(2, 3) - + at(2, 0) * at(1, 2) * at(3, 3) - + at(3, 0) * at(2, 2) * at(1, 3)); + cof(0, 2) = at(1, 0) * at(2, 1) * at(3, 3) + + at(2, 0) * at(3, 1) * at(1, 3) + + at(3, 0) * at(1, 1) * at(2, 3) - + at(1, 0) * at(3, 1) * at(2, 3) - + at(2, 0) * at(1, 1) * at(3, 3) - + at(3, 0) * at(2, 1) * at(1, 3); + cof(0, 3) = -(at(1, 0) * at(2, 1) * at(3, 2) + + at(2, 0) * at(3, 1) * at(1, 2) + + at(3, 0) * at(1, 1) * at(2, 2) - + at(1, 0) * at(3, 1) * at(2, 2) - + at(2, 0) * at(1, 1) * at(3, 2) - + at(3, 0) * at(2, 1) * at(1, 2)); + cof(1, 0) = -(at(0, 1) * at(2, 2) * at(3, 3) + + at(2, 1) * at(3, 2) * at(0, 3) + + at(3, 1) * at(0, 2) * at(2, 3) - + at(0, 1) * at(3, 2) * at(2, 3) - + at(2, 1) * at(0, 2) * at(3, 3) - + at(3, 1) * at(2, 2) * at(0, 3)); + cof(1, 1) = at(0, 0) * at(2, 2) * at(3, 3) + + at(2, 0) * at(3, 2) * at(0, 3) + + at(3, 0) * at(0, 2) * at(2, 3) - + at(0, 0) * at(3, 2) * at(2, 3) - + at(2, 0) * at(0, 2) * at(3, 3) - + at(3, 0) * at(2, 2) * at(0, 3); + cof(1, 2) = -(at(0, 0) * at(2, 1) * at(3, 3) + + at(2, 0) * at(3, 1) * at(0, 3) + + at(3, 0) * at(0, 1) * at(2, 3) - + at(0, 0) * at(3, 1) * at(2, 3) - + at(2, 0) * at(0, 1) * at(3, 3) - + at(3, 0) * at(2, 1) * at(0, 3)); + cof(1, 3) = at(0, 0) * at(2, 1) * at(3, 2) + + at(2, 0) * at(3, 1) * at(0, 2) + + at(3, 0) * at(0, 1) * at(2, 2) - + at(0, 0) * at(3, 1) * at(2, 2) - + at(2, 0) * at(0, 1) * at(3, 2) - + at(3, 0) * at(2, 1) * at(0, 2); + cof(2, 0) = at(0, 1) * at(1, 2) * at(3, 3) + + at(1, 1) * at(3, 2) * at(0, 3) + + at(3, 1) * at(0, 2) * at(1, 3) - + at(0, 1) * at(3, 2) * at(1, 3) - + at(1, 1) * at(0, 2) * at(3, 3) - + at(3, 1) * at(1, 2) * at(0, 3); + cof(2, 1) = -(at(0, 0) * at(1, 2) * at(3, 3) + + at(1, 0) * at(3, 2) * at(0, 3) + + at(3, 0) * at(0, 2) * at(1, 3) - + at(0, 0) * at(3, 2) * at(1, 3) - + at(1, 0) * at(0, 2) * at(3, 3) - + at(3, 0) * at(1, 2) * at(0, 3)); + cof(2, 2) = at(0, 0) * at(1, 1) * at(3, 3) + + at(1, 0) * at(3, 1) * at(0, 3) + + at(3, 0) * at(0, 1) * at(1, 3) - + at(0, 0) * at(3, 1) * at(1, 3) - + at(1, 0) * at(0, 1) * at(3, 3) - + at(3, 0) * at(1, 1) * at(0, 3); + cof(2, 3) = -(at(0, 0) * at(1, 1) * at(3, 2) + + at(1, 0) * at(3, 1) * at(0, 2) + + at(3, 0) * at(0, 1) * at(1, 2) - + at(0, 0) * at(3, 1) * at(1, 2) - + at(1, 0) * at(0, 1) * at(3, 2) - + at(3, 0) * at(1, 1) * at(0, 2)); + cof(3, 0) = -(at(0, 1) * at(1, 2) * at(2, 3) + + at(1, 1) * at(2, 2) * at(0, 3) + + at(2, 1) * at(0, 2) * at(1, 3) - + at(0, 1) * at(2, 2) * at(1, 3) - + at(1, 1) * at(0, 2) * at(2, 3) - + at(2, 1) * at(1, 2) * at(0, 3)); + cof(3, 1) = at(0, 0) * at(1, 2) * at(2, 3) + + at(1, 0) * at(2, 2) * at(0, 3) + + at(2, 0) * at(0, 2) * at(1, 3) - + at(0, 0) * at(2, 2) * at(1, 3) - + at(1, 0) * at(0, 2) * at(2, 3) - + at(2, 0) * at(1, 2) * at(0, 3); + cof(3, 2) = -(at(0, 0) * at(1, 1) * at(2, 3) + + at(1, 0) * at(2, 1) * at(0, 3) + + at(2, 0) * at(0, 1) * at(1, 3) - + at(0, 0) * at(2, 1) * at(1, 3) - + at(1, 0) * at(0, 1) * at(2, 3) - + at(2, 0) * at(1, 1) * at(0, 3)); + cof(3, 3) = at(0, 0) * at(1, 1) * at(2, 2) + + at(1, 0) * at(2, 1) * at(0, 2) + + at(2, 0) * at(0, 1) * at(1, 2) - + at(0, 0) * at(2, 1) * at(1, 2) - + at(1, 0) * at(0, 1) * at(2, 2) - + at(2, 0) * at(1, 1) * at(0, 2); + break; + + default: + UNREACHABLE(); + break; + } + + // The inverse of A is the transpose of the cofactor matrix times the reciprocal of the determinant of A. + Matrix<T> adjugateMatrix(cof.transpose()); + T det = determinant(); + Matrix<T> result(std::vector<T>(mElements.size()), rows(), columns()); + for (unsigned int i = 0; i < rows(); i++) + for (unsigned int j = 0; j < columns(); j++) + result(i, j) = det ? adjugateMatrix(i, j) / det : T(); + + return result; + } + + void setToIdentity() + { + ASSERT(rows() == columns()); + + const auto one = T(1); + const auto zero = T(0); + + for (auto &e : mElements) + e = zero; + + for (unsigned int i = 0; i < rows(); ++i) + { + const auto pos = i * columns() + (i % columns()); + mElements[pos] = one; + } + } + + template <unsigned int Size> + static void setToIdentity(T(&matrix)[Size]) + { + static_assert(gl::iSquareRoot<Size>() != 0, "Matrix is not square."); + + const auto cols = gl::iSquareRoot<Size>(); + const auto one = T(1); + const auto zero = T(0); + + for (auto &e : matrix) + e = zero; + + for (unsigned int i = 0; i < cols; ++i) + { + const auto pos = i * cols + (i % cols); + matrix[pos] = one; + } + } + + private: + std::vector<T> mElements; + unsigned int mRows; + unsigned int mCols; +}; + +} // namespace angle + +#endif // COMMON_MATRIX_UTILS_H_ + diff --git a/gfx/angle/src/common/matrix_utils_unittest.cpp b/gfx/angle/src/common/matrix_utils_unittest.cpp new file mode 100755 index 000000000..6e9f92d9a --- /dev/null +++ b/gfx/angle/src/common/matrix_utils_unittest.cpp @@ -0,0 +1,184 @@ +// +// 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. +// +// matrix_utils_unittests: +// Unit tests for the matrix utils. +// + +#include "matrix_utils.h" + +#include <gtest/gtest.h> + +using namespace angle; + +namespace +{ + +const unsigned int minDimensions = 2; +const unsigned int maxDimensions = 4; + +TEST(MatrixUtilsTest, MatrixConstructorTest) +{ + for (unsigned int i = minDimensions; i <= maxDimensions; i++) + { + for (unsigned int j = minDimensions; j <= maxDimensions; j++) + { + unsigned int numElements = i * j; + Matrix<float> m(std::vector<float>(numElements, 1.0f), i, j); + EXPECT_EQ(m.rows(), i); + EXPECT_EQ(m.columns(), j); + EXPECT_EQ(m.elements(), std::vector<float>(numElements, 1.0f)); + } + } + + for (unsigned int i = minDimensions; i <= maxDimensions; i++) + { + unsigned int numElements = i * i; + Matrix<float> m(std::vector<float>(numElements, 1.0f), i); + EXPECT_EQ(m.size(), i); + EXPECT_EQ(m.columns(), m.columns()); + EXPECT_EQ(m.elements(), std::vector<float>(numElements, 1.0f)); + } +} + +TEST(MatrixUtilsTest, MatrixCompMultTest) +{ + for (unsigned int i = minDimensions; i <= maxDimensions; i++) + { + unsigned int numElements = i * i; + Matrix<float> m1(std::vector<float>(numElements, 2.0f), i); + Matrix<float> actualResult = m1.compMult(m1); + std::vector<float> actualResultElements = actualResult.elements(); + std::vector<float> expectedResultElements(numElements, 4.0f); + EXPECT_EQ(expectedResultElements, actualResultElements); + } +} + +TEST(MatrixUtilsTest, MatrixOuterProductTest) +{ + for (unsigned int i = minDimensions; i <= maxDimensions; i++) + { + for (unsigned int j = minDimensions; j <= maxDimensions; j++) + { + unsigned int numElements = i * j; + Matrix<float> m1(std::vector<float>(numElements, 2.0f), i, 1); + Matrix<float> m2(std::vector<float>(numElements, 2.0f), 1, j); + Matrix<float> actualResult = m1.outerProduct(m2); + EXPECT_EQ(actualResult.rows(), i); + EXPECT_EQ(actualResult.columns(), j); + std::vector<float> actualResultElements = actualResult.elements(); + std::vector<float> expectedResultElements(numElements, 4.0f); + EXPECT_EQ(expectedResultElements, actualResultElements); + } + } +} + +TEST(MatrixUtilsTest, MatrixTransposeTest) +{ + for (unsigned int i = minDimensions; i <= maxDimensions; i++) + { + for (unsigned int j = minDimensions; j <= maxDimensions; j++) + { + unsigned int numElements = i * j; + Matrix<float> m1(std::vector<float>(numElements, 2.0f), i, j); + Matrix<float> expectedResult = Matrix<float>(std::vector<float>(numElements, 2.0f), j, i); + Matrix<float> actualResult = m1.transpose(); + EXPECT_EQ(expectedResult.elements(), actualResult.elements()); + EXPECT_EQ(actualResult.rows(), expectedResult.rows()); + EXPECT_EQ(actualResult.columns(), expectedResult.columns()); + // transpose(transpose(A)) = A + Matrix<float> m2 = actualResult.transpose(); + EXPECT_EQ(m1.elements(), m2.elements()); + } + } +} + +TEST(MatrixUtilsTest, MatrixDeterminantTest) +{ + for (unsigned int i = minDimensions; i <= maxDimensions; i++) + { + unsigned int numElements = i * i; + Matrix<float> m(std::vector<float>(numElements, 2.0f), i); + EXPECT_EQ(m.determinant(), 0.0f); + } +} + +TEST(MatrixUtilsTest, 2x2MatrixInverseTest) +{ + float inputElements[] = + { + 2.0f, 5.0f, + 3.0f, 7.0f + }; + unsigned int numElements = 4; + std::vector<float> input(inputElements, inputElements + numElements); + Matrix<float> inputMatrix(input, 2); + float identityElements[] = + { + 1.0f, 0.0f, + 0.0f, 1.0f + }; + std::vector<float> identityMatrix(identityElements, identityElements + numElements); + // A * inverse(A) = I, where I is identity matrix. + Matrix<float> result = inputMatrix * inputMatrix.inverse(); + EXPECT_EQ(identityMatrix, result.elements()); +} + +TEST(MatrixUtilsTest, 3x3MatrixInverseTest) +{ + float inputElements[] = + { + 11.0f, 23.0f, 37.0f, + 13.0f, 29.0f, 41.0f, + 19.0f, 31.0f, 43.0f + }; + unsigned int numElements = 9; + std::vector<float> input(inputElements, inputElements + numElements); + Matrix<float> inputMatrix(input, 3); + float identityElements[] = + { + 1.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 1.0f + }; + std::vector<float> identityMatrix(identityElements, identityElements + numElements); + // A * inverse(A) = I, where I is identity matrix. + Matrix<float> result = inputMatrix * inputMatrix.inverse(); + std::vector<float> resultElements = result.elements(); + const float floatFaultTolarance = 0.000001f; + for (size_t i = 0; i < numElements; i++) + EXPECT_NEAR(resultElements[i], identityMatrix[i], floatFaultTolarance); +} + +TEST(MatrixUtilsTest, 4x4MatrixInverseTest) +{ + float inputElements[] = + { + 29.0f, 43.0f, 61.0f, 79.0f, + 31.0f, 47.0f, 67.0f, 83.0f, + 37.0f, 53.0f, 71.0f, 89.0f, + 41.0f, 59.0f, 73.0f, 97.0f + }; + unsigned int numElements = 16; + std::vector<float> input(inputElements, inputElements + numElements); + Matrix<float> inputMatrix(input, 4); + float identityElements[] = + { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f, + }; + std::vector<float> identityMatrix(identityElements, identityElements + numElements); + // A * inverse(A) = I, where I is identity matrix. + Matrix<float> result = inputMatrix * inputMatrix.inverse(); + std::vector<float> resultElements = result.elements(); + const float floatFaultTolarance = 0.00001f; + for (unsigned int i = 0; i < numElements; i++) + EXPECT_NEAR(resultElements[i], identityMatrix[i], floatFaultTolarance); +} + +} + diff --git a/gfx/angle/src/common/platform.h b/gfx/angle/src/common/platform.h new file mode 100755 index 000000000..15dac456c --- /dev/null +++ b/gfx/angle/src/common/platform.h @@ -0,0 +1,92 @@ +// +// Copyright (c) 2014 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. +// + +// platform.h: Operating system specific includes and defines. + +#ifndef COMMON_PLATFORM_H_ +#define COMMON_PLATFORM_H_ + +#if defined(_WIN32) || defined(_WIN64) +# define ANGLE_PLATFORM_WINDOWS 1 +#elif defined(__APPLE__) +# define ANGLE_PLATFORM_APPLE 1 +# define ANGLE_PLATFORM_POSIX 1 +#elif defined(ANDROID) +# define ANGLE_PLATFORM_ANDROID 1 +# define ANGLE_PLATFORM_POSIX 1 +#elif defined(__linux__) || defined(EMSCRIPTEN) +# define ANGLE_PLATFORM_LINUX 1 +# define ANGLE_PLATFORM_POSIX 1 +#elif defined(__FreeBSD__) || \ + defined(__OpenBSD__) || \ + defined(__NetBSD__) || \ + defined(__DragonFly__) || \ + defined(__sun) || \ + defined(__GLIBC__) || \ + defined(__GNU__) || \ + defined(__QNX__) +# define ANGLE_PLATFORM_POSIX 1 +#else +# error Unsupported platform. +#endif + +#ifdef ANGLE_PLATFORM_WINDOWS +# ifndef STRICT +# define STRICT 1 +# endif +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN 1 +# endif +# ifndef NOMINMAX +# define NOMINMAX 1 +# endif + +# include <windows.h> +# include <intrin.h> + +# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP) +# define ANGLE_ENABLE_WINDOWS_STORE 1 +# endif + +# if defined(ANGLE_ENABLE_D3D9) +# include <d3d9.h> +# include <d3dcompiler.h> +# endif + +# if defined(ANGLE_ENABLE_D3D11) +# include <d3d10_1.h> +# include <d3d11.h> +# include <d3d11_1.h> +# include <dxgi.h> +# include <dxgi1_2.h> +# include <d3dcompiler.h> +# endif + +# if defined(ANGLE_ENABLE_WINDOWS_STORE) +# include <dxgi1_3.h> +# if defined(_DEBUG) +# include <DXProgrammableCapture.h> +# include <dxgidebug.h> +# endif +# endif + +# undef near +# undef far +#endif + +#if defined(_MSC_VER) && !defined(_M_ARM) +#include <intrin.h> +#define ANGLE_USE_SSE +#elif defined(__GNUC__) && (defined(__x86_64__) || defined(__i386__)) +#include <x86intrin.h> +#define ANGLE_USE_SSE +#endif + +// The MemoryBarrier function name collides with a macro under Windows +// We will undef the macro so that the function name does not get replaced +#undef MemoryBarrier + +#endif // COMMON_PLATFORM_H_ diff --git a/gfx/angle/src/common/string_utils.cpp b/gfx/angle/src/common/string_utils.cpp new file mode 100755 index 000000000..bb1edd245 --- /dev/null +++ b/gfx/angle/src/common/string_utils.cpp @@ -0,0 +1,182 @@ +// +// 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. +// +// string_utils: +// String helper functions. +// + +#include "string_utils.h" + +#include <algorithm> +#include <stdlib.h> +#include <string.h> +#include <fstream> +#include <sstream> + +#include "common/platform.h" + +namespace angle +{ + +const char kWhitespaceASCII[] = " \f\n\r\t\v"; + +std::vector<std::string> SplitString(const std::string &input, + const std::string &delimiters, + WhitespaceHandling whitespace, + SplitResult resultType) +{ + std::vector<std::string> result; + if (input.empty()) + { + return result; + } + + std::string::size_type start = 0; + while (start != std::string::npos) + { + auto end = input.find_first_of(delimiters, start); + + std::string piece; + if (end == std::string::npos) + { + piece = input.substr(start); + start = std::string::npos; + } + else + { + piece = input.substr(start, end - start); + start = end + 1; + } + + if (whitespace == TRIM_WHITESPACE) + { + piece = TrimString(piece, kWhitespaceASCII); + } + + if (resultType == SPLIT_WANT_ALL || !piece.empty()) + { + result.push_back(piece); + } + } + + return result; +} + +void SplitStringAlongWhitespace(const std::string &input, + std::vector<std::string> *tokensOut) +{ + + std::istringstream stream(input); + std::string line; + + while (std::getline(stream, line)) + { + size_t prev = 0, pos; + while ((pos = line.find_first_of(kWhitespaceASCII, prev)) != std::string::npos) + { + if (pos > prev) + tokensOut->push_back(line.substr(prev, pos - prev)); + prev = pos + 1; + } + if (prev < line.length()) + tokensOut->push_back(line.substr(prev, std::string::npos)); + } +} + +std::string TrimString(const std::string &input, const std::string &trimChars) +{ + auto begin = input.find_first_not_of(trimChars); + if (begin == std::string::npos) + { + return ""; + } + + std::string::size_type end = input.find_last_not_of(trimChars); + if (end == std::string::npos) + { + return input.substr(begin); + } + + return input.substr(begin, end - begin + 1); +} + +bool HexStringToUInt(const std::string &input, unsigned int *uintOut) +{ + unsigned int offset = 0; + + if (input.size() >= 2 && input[0] == '0' && input[1] == 'x') + { + offset = 2u; + } + + // Simple validity check + if (input.find_first_not_of("0123456789ABCDEFabcdef", offset) != std::string::npos) + { + return false; + } + + std::stringstream inStream(input); + inStream >> std::hex >> *uintOut; + return !inStream.fail(); +} + +bool ReadFileToString(const std::string &path, std::string *stringOut) +{ + std::ifstream inFile(path.c_str()); + if (inFile.fail()) + { + return false; + } + + inFile.seekg(0, std::ios::end); + stringOut->reserve(static_cast<std::string::size_type>(inFile.tellg())); + inFile.seekg(0, std::ios::beg); + + stringOut->assign(std::istreambuf_iterator<char>(inFile), std::istreambuf_iterator<char>()); + return !inFile.fail(); +} + +Optional<std::vector<wchar_t>> WidenString(size_t length, const char *cString) +{ + std::vector<wchar_t> wcstring(length + 1); +#if !defined(ANGLE_PLATFORM_WINDOWS) + size_t written = mbstowcs(wcstring.data(), cString, length + 1); + if (written == 0) + { + return Optional<std::vector<wchar_t>>::Invalid(); + } +#else + size_t convertedChars = 0; + errno_t err = mbstowcs_s(&convertedChars, wcstring.data(), length + 1, cString, _TRUNCATE); + if (err != 0) + { + return Optional<std::vector<wchar_t>>::Invalid(); + } +#endif + return Optional<std::vector<wchar_t>>(wcstring); +} + +bool BeginsWith(const std::string &str, const char *prefix) +{ + return strncmp(str.c_str(), prefix, strlen(prefix)) == 0; +} + +bool BeginsWith(const char *str, const char *prefix) +{ + return strncmp(str, prefix, strlen(prefix)) == 0; +} + +bool EndsWith(const std::string &str, const char *suffix) +{ + const auto len = strlen(suffix); + if (len > str.size()) + return false; + + const char *end = str.c_str() + str.size() - len; + + return memcmp(end, suffix, len) == 0; +} + +} // namespace angle diff --git a/gfx/angle/src/common/string_utils.h b/gfx/angle/src/common/string_utils.h new file mode 100755 index 000000000..c649c64d6 --- /dev/null +++ b/gfx/angle/src/common/string_utils.h @@ -0,0 +1,67 @@ +// +// 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. +// +// string_utils: +// String helper functions. +// + +#ifndef LIBANGLE_STRING_UTILS_H_ +#define LIBANGLE_STRING_UTILS_H_ + +#include <string> +#include <vector> + +#include "common/Optional.h" + +namespace angle +{ + +extern const char kWhitespaceASCII[]; + +enum WhitespaceHandling +{ + KEEP_WHITESPACE, + TRIM_WHITESPACE, +}; + +enum SplitResult +{ + SPLIT_WANT_ALL, + SPLIT_WANT_NONEMPTY, +}; + +std::vector<std::string> SplitString(const std::string &input, + const std::string &delimiters, + WhitespaceHandling whitespace, + SplitResult resultType); + +void SplitStringAlongWhitespace(const std::string &input, + std::vector<std::string> *tokensOut); + +std::string TrimString(const std::string &input, const std::string &trimChars); + +bool HexStringToUInt(const std::string &input, unsigned int *uintOut); + +bool ReadFileToString(const std::string &path, std::string *stringOut); + +Optional<std::vector<wchar_t>> WidenString(size_t length, const char *cString); + +// Check if the string str begins with the given prefix. +// Prefix may not be NULL and needs to be NULL terminated. +// The comparison is case sensitive. +bool BeginsWith(const std::string &str, const char *prefix); + +// Check if the string str begins with the given prefix. +// str and prefix may not be NULL and need to be NULL terminated. +// The comparison is case sensitive. +bool BeginsWith(const char *str, const char *prefix); + +// Check if the string str ends with the given suffix. +// Suffix may not be NUL and needs to be NULL terminated. +// The comparison is case sensitive. +bool EndsWith(const std::string& str, const char* suffix); +} + +#endif // LIBANGLE_STRING_UTILS_H_ diff --git a/gfx/angle/src/common/string_utils_unittest.cpp b/gfx/angle/src/common/string_utils_unittest.cpp new file mode 100755 index 000000000..e7ce8a62d --- /dev/null +++ b/gfx/angle/src/common/string_utils_unittest.cpp @@ -0,0 +1,163 @@ +// +// 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. +// +// string_utils_unittests: +// Unit tests for the string utils. +// + +#include "string_utils.h" + +#include <gtest/gtest.h> + +using namespace angle; + +namespace +{ + +// Basic SplitString tests +TEST(StringUtilsTest, SplitString_Basics) +{ + std::vector<std::string> r; + + r = SplitString(std::string(), ",:;", KEEP_WHITESPACE, SPLIT_WANT_ALL); + EXPECT_TRUE(r.empty()); + + // Empty separator list + r = SplitString("hello, world", "", KEEP_WHITESPACE, SPLIT_WANT_ALL); + ASSERT_EQ(1u, r.size()); + EXPECT_EQ("hello, world", r[0]); + + // Should split on any of the separators. + r = SplitString("::,,;;", ",:;", KEEP_WHITESPACE, SPLIT_WANT_ALL); + ASSERT_EQ(7u, r.size()); + for (auto str : r) + ASSERT_TRUE(str.empty()); + + r = SplitString("red, green; blue:", ",:;", TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY); + ASSERT_EQ(3u, r.size()); + EXPECT_EQ("red", r[0]); + EXPECT_EQ("green", r[1]); + EXPECT_EQ("blue", r[2]); + + // Want to split a string along whitespace sequences. + r = SplitString(" red green \tblue\n", " \t\n", TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY); + ASSERT_EQ(3u, r.size()); + EXPECT_EQ("red", r[0]); + EXPECT_EQ("green", r[1]); + EXPECT_EQ("blue", r[2]); + + // Weird case of splitting on spaces but not trimming. + r = SplitString(" red ", " ", TRIM_WHITESPACE, SPLIT_WANT_ALL); + ASSERT_EQ(3u, r.size()); + EXPECT_EQ("", r[0]); // Before the first space. + EXPECT_EQ("red", r[1]); + EXPECT_EQ("", r[2]); // After the last space. +} + +// Check different whitespace and result types for SplitString +TEST(StringUtilsTest, SplitString_WhitespaceAndResultType) +{ + std::vector<std::string> r; + + // Empty input handling. + r = SplitString(std::string(), ",", KEEP_WHITESPACE, SPLIT_WANT_ALL); + EXPECT_TRUE(r.empty()); + r = SplitString(std::string(), ",", KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY); + EXPECT_TRUE(r.empty()); + + // Input string is space and we're trimming. + r = SplitString(" ", ",", TRIM_WHITESPACE, SPLIT_WANT_ALL); + ASSERT_EQ(1u, r.size()); + EXPECT_EQ("", r[0]); + r = SplitString(" ", ",", TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY); + EXPECT_TRUE(r.empty()); + + // Test all 4 combinations of flags on ", ,". + r = SplitString(", ,", ",", KEEP_WHITESPACE, SPLIT_WANT_ALL); + ASSERT_EQ(3u, r.size()); + EXPECT_EQ("", r[0]); + EXPECT_EQ(" ", r[1]); + EXPECT_EQ("", r[2]); + r = SplitString(", ,", ",", KEEP_WHITESPACE, SPLIT_WANT_NONEMPTY); + ASSERT_EQ(1u, r.size()); + ASSERT_EQ(" ", r[0]); + r = SplitString(", ,", ",", TRIM_WHITESPACE, SPLIT_WANT_ALL); + ASSERT_EQ(3u, r.size()); + EXPECT_EQ("", r[0]); + EXPECT_EQ("", r[1]); + EXPECT_EQ("", r[2]); + r = SplitString(", ,", ",", TRIM_WHITESPACE, SPLIT_WANT_NONEMPTY); + ASSERT_TRUE(r.empty()); +} + +// Tests for TrimString +TEST(StringUtilsTest, TrimString) +{ + // Basic tests + EXPECT_EQ("a", TrimString("a", kWhitespaceASCII)); + EXPECT_EQ("a", TrimString(" a", kWhitespaceASCII)); + EXPECT_EQ("a", TrimString("a ", kWhitespaceASCII)); + EXPECT_EQ("a", TrimString(" a ", kWhitespaceASCII)); + + // Tests with empty strings + EXPECT_EQ("", TrimString("", kWhitespaceASCII)); + EXPECT_EQ("", TrimString(" \n\r\t", kWhitespaceASCII)); + EXPECT_EQ(" foo ", TrimString(" foo ", "")); + + // Tests it doesn't removes characters in the middle + EXPECT_EQ("foo bar", TrimString(" foo bar ", kWhitespaceASCII)); + + // Test with non-whitespace trimChars + EXPECT_EQ(" ", TrimString("foo bar", "abcdefghijklmnopqrstuvwxyz")); +} + +// Basic functionality tests for HexStringToUInt +TEST(StringUtilsTest, HexStringToUIntBasic) +{ + unsigned int uintValue; + + std::string emptyString; + ASSERT_FALSE(HexStringToUInt(emptyString, &uintValue)); + + std::string testStringA("0xBADF00D"); + ASSERT_TRUE(HexStringToUInt(testStringA, &uintValue)); + EXPECT_EQ(0xBADF00Du, uintValue); + + std::string testStringB("0xBADFOOD"); + EXPECT_FALSE(HexStringToUInt(testStringB, &uintValue)); + + std::string testStringC("BADF00D"); + EXPECT_TRUE(HexStringToUInt(testStringC, &uintValue)); + EXPECT_EQ(0xBADF00Du, uintValue); + + std::string testStringD("0x BADF00D"); + EXPECT_FALSE(HexStringToUInt(testStringD, &uintValue)); +} + +// Note: ReadFileToString is harder to test + + +TEST(StringUtilsTest, BeginsEndsWith) +{ + ASSERT_FALSE(BeginsWith("foo", "bar")); + ASSERT_FALSE(BeginsWith("", "foo")); + ASSERT_FALSE(BeginsWith("foo", "foobar")); + + ASSERT_TRUE(BeginsWith("foobar", "foo")); + ASSERT_TRUE(BeginsWith("foobar", "")); + ASSERT_TRUE(BeginsWith("foo", "foo")); + ASSERT_TRUE(BeginsWith("", "")); + + ASSERT_FALSE(EndsWith("foo", "bar")); + ASSERT_FALSE(EndsWith("", "bar")); + ASSERT_FALSE(EndsWith("foo", "foobar")); + + ASSERT_TRUE(EndsWith("foobar", "bar")); + ASSERT_TRUE(EndsWith("foobar", "")); + ASSERT_TRUE(EndsWith("bar", "bar")); + ASSERT_TRUE(EndsWith("", "")); +} + +}
\ No newline at end of file diff --git a/gfx/angle/src/common/third_party/numerics/README.angle b/gfx/angle/src/common/third_party/numerics/README.angle new file mode 100755 index 000000000..c7df1a849 --- /dev/null +++ b/gfx/angle/src/common/third_party/numerics/README.angle @@ -0,0 +1,16 @@ +Name: Chromium: base/numerics +Short Name: base::numerics +Version: +URL: https://chromium.googlesource.com/chromium/src.git/+/lkcr/base/numerics/ +SOURCE CODE: Copy the Chromium folder manually into this folder and run git cl format. +Date: 30/05/2016 +Revision: 28b5bbb227d331c01e6ff9b2f8729732135aadc7 (Chromium) +Security Critical: no +License: Chromium +License File: LICENSE in Chromium/src + +Description: +base::numerics is a library for doing some simple safe math and conversions. To update the checkout, simply +overwrite the base/numerics folder with Chromium's latest. The only modifications are to the base/logging.h +file which defines CHECK to be ASSERT to be compatible with ANGLE. + diff --git a/gfx/angle/src/common/third_party/numerics/base/logging.h b/gfx/angle/src/common/third_party/numerics/base/logging.h new file mode 100755 index 000000000..6cf05b4e6 --- /dev/null +++ b/gfx/angle/src/common/third_party/numerics/base/logging.h @@ -0,0 +1,22 @@ +// +// Copyright 2016 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. +// +// logging.h: Compatiblity hacks for importing Chromium's base/numerics. + +#ifndef BASE_LOGGING_H_ +#define BASE_LOGGING_H_ + +#include "common/debug.h" + +#ifndef CHECK +#define CHECK(X) ASSERT(X) +#endif + +// Unfortunately ANGLE relies on ASSERT being an empty statement, which these libs don't respect. +#ifndef NOTREACHED +#define NOTREACHED() UNREACHABLE() +#endif + +#endif // BASE_LOGGING_H_ diff --git a/gfx/angle/src/common/third_party/numerics/base/numerics/OWNERS b/gfx/angle/src/common/third_party/numerics/base/numerics/OWNERS new file mode 100755 index 000000000..41f35fc79 --- /dev/null +++ b/gfx/angle/src/common/third_party/numerics/base/numerics/OWNERS @@ -0,0 +1,3 @@ +jschuh@chromium.org +tsepez@chromium.org + diff --git a/gfx/angle/src/common/third_party/numerics/base/numerics/safe_conversions.h b/gfx/angle/src/common/third_party/numerics/base/numerics/safe_conversions.h new file mode 100755 index 000000000..3fe496c21 --- /dev/null +++ b/gfx/angle/src/common/third_party/numerics/base/numerics/safe_conversions.h @@ -0,0 +1,174 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_NUMERICS_SAFE_CONVERSIONS_H_ +#define BASE_NUMERICS_SAFE_CONVERSIONS_H_ + +#include <stddef.h> + +#include <limits> +#include <type_traits> + +#include "base/logging.h" +#include "base/numerics/safe_conversions_impl.h" + +namespace base +{ + +// Convenience function that returns true if the supplied value is in range +// for the destination type. +template <typename Dst, typename Src> +constexpr bool IsValueInRangeForNumericType(Src value) +{ + return internal::DstRangeRelationToSrcRange<Dst>(value) == internal::RANGE_VALID; +} + +// Convenience function for determining if a numeric value is negative without +// throwing compiler warnings on: unsigned(value) < 0. +template <typename T> +constexpr typename std::enable_if<std::numeric_limits<T>::is_signed, bool>::type IsValueNegative( + T value) +{ + static_assert(std::numeric_limits<T>::is_specialized, "Argument must be numeric."); + return value < 0; +} + +template <typename T> +constexpr typename std::enable_if<!std::numeric_limits<T>::is_signed, bool>::type IsValueNegative(T) +{ + static_assert(std::numeric_limits<T>::is_specialized, "Argument must be numeric."); + return false; +} + +// checked_cast<> is analogous to static_cast<> for numeric types, +// except that it CHECKs that the specified numeric conversion will not +// overflow or underflow. NaN source will always trigger a CHECK. +template <typename Dst, typename Src> +inline Dst checked_cast(Src value) +{ + CHECK(IsValueInRangeForNumericType<Dst>(value)); + return static_cast<Dst>(value); +} + +// HandleNaN will cause this class to CHECK(false). +struct SaturatedCastNaNBehaviorCheck +{ + template <typename T> + static T HandleNaN() + { + CHECK(false); + return T(); + } +}; + +// HandleNaN will return 0 in this case. +struct SaturatedCastNaNBehaviorReturnZero +{ + template <typename T> + static constexpr T HandleNaN() + { + return T(); + } +}; + +namespace internal +{ +// This wrapper is used for C++11 constexpr support by avoiding the declaration +// of local variables in the saturated_cast template function. +template <typename Dst, class NaNHandler, typename Src> +constexpr Dst saturated_cast_impl(const Src value, const RangeConstraint constraint) +{ + return constraint == RANGE_VALID + ? static_cast<Dst>(value) + : (constraint == RANGE_UNDERFLOW + ? std::numeric_limits<Dst>::min() + : (constraint == RANGE_OVERFLOW + ? std::numeric_limits<Dst>::max() + : (constraint == RANGE_INVALID + ? NaNHandler::template HandleNaN<Dst>() + : (NOTREACHED(), static_cast<Dst>(value))))); +} +} // namespace internal + +// saturated_cast<> is analogous to static_cast<> for numeric types, except +// that the specified numeric conversion will saturate rather than overflow or +// underflow. NaN assignment to an integral will defer the behavior to a +// specified class. By default, it will return 0. +template <typename Dst, class NaNHandler = SaturatedCastNaNBehaviorReturnZero, typename Src> +constexpr Dst saturated_cast(Src value) +{ + return std::numeric_limits<Dst>::is_iec559 + ? static_cast<Dst>(value) // Floating point optimization. + : internal::saturated_cast_impl<Dst, NaNHandler>( + value, internal::DstRangeRelationToSrcRange<Dst>(value)); +} + +// strict_cast<> is analogous to static_cast<> for numeric types, except that +// it will cause a compile failure if the destination type is not large enough +// to contain any value in the source type. It performs no runtime checking. +template <typename Dst, typename Src> +constexpr Dst strict_cast(Src value) +{ + static_assert(std::numeric_limits<Src>::is_specialized, "Argument must be numeric."); + static_assert(std::numeric_limits<Dst>::is_specialized, "Result must be numeric."); + static_assert((internal::StaticDstRangeRelationToSrcRange<Dst, Src>::value == + internal::NUMERIC_RANGE_CONTAINED), + "The numeric conversion is out of range for this type. You " + "should probably use one of the following conversion " + "mechanisms on the value you want to pass:\n" + "- base::checked_cast\n" + "- base::saturated_cast\n" + "- base::CheckedNumeric"); + + return static_cast<Dst>(value); +} + +// StrictNumeric implements compile time range checking between numeric types by +// wrapping assignment operations in a strict_cast. This class is intended to be +// used for function arguments and return types, to ensure the destination type +// can always contain the source type. This is essentially the same as enforcing +// -Wconversion in gcc and C4302 warnings on MSVC, but it can be applied +// incrementally at API boundaries, making it easier to convert code so that it +// compiles cleanly with truncation warnings enabled. +// This template should introduce no runtime overhead, but it also provides no +// runtime checking of any of the associated mathematical operations. Use +// CheckedNumeric for runtime range checks of the actual value being assigned. +template <typename T> +class StrictNumeric +{ + public: + typedef T type; + + constexpr StrictNumeric() : value_(0) {} + + // Copy constructor. + template <typename Src> + constexpr StrictNumeric(const StrictNumeric<Src> &rhs) : value_(strict_cast<T>(rhs.value_)) + { + } + + // This is not an explicit constructor because we implicitly upgrade regular + // numerics to StrictNumerics to make them easier to use. + template <typename Src> + constexpr StrictNumeric(Src value) : value_(strict_cast<T>(value)) + { + } + + // The numeric cast operator basically handles all the magic. + template <typename Dst> + constexpr operator Dst() const + { + return strict_cast<Dst>(value_); + } + + private: + const T value_; +}; + +// Explicitly make a shorter size_t typedef for convenience. +typedef StrictNumeric<size_t> SizeT; + +} // namespace base + +#endif // BASE_NUMERICS_SAFE_CONVERSIONS_H_ diff --git a/gfx/angle/src/common/third_party/numerics/base/numerics/safe_conversions_impl.h b/gfx/angle/src/common/third_party/numerics/base/numerics/safe_conversions_impl.h new file mode 100755 index 000000000..1591b9c8c --- /dev/null +++ b/gfx/angle/src/common/third_party/numerics/base/numerics/safe_conversions_impl.h @@ -0,0 +1,269 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_ +#define BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_ + +#include <limits.h> +#include <stdint.h> + +#include <climits> +#include <limits> + +namespace base +{ +namespace internal +{ + +// The std library doesn't provide a binary max_exponent for integers, however +// we can compute one by adding one to the number of non-sign bits. This allows +// for accurate range comparisons between floating point and integer types. +template <typename NumericType> +struct MaxExponent +{ + static_assert(std::is_arithmetic<NumericType>::value, "Argument must be numeric."); + static const int value = + std::numeric_limits<NumericType>::is_iec559 + ? std::numeric_limits<NumericType>::max_exponent + : (sizeof(NumericType) * CHAR_BIT + 1 - std::numeric_limits<NumericType>::is_signed); +}; + +enum IntegerRepresentation +{ + INTEGER_REPRESENTATION_UNSIGNED, + INTEGER_REPRESENTATION_SIGNED +}; + +// A range for a given nunmeric Src type is contained for a given numeric Dst +// type if both numeric_limits<Src>::max() <= numeric_limits<Dst>::max() and +// numeric_limits<Src>::min() >= numeric_limits<Dst>::min() are true. +// We implement this as template specializations rather than simple static +// comparisons to ensure type correctness in our comparisons. +enum NumericRangeRepresentation +{ + NUMERIC_RANGE_NOT_CONTAINED, + NUMERIC_RANGE_CONTAINED +}; + +// Helper templates to statically determine if our destination type can contain +// maximum and minimum values represented by the source type. + +template <typename Dst, + typename Src, + IntegerRepresentation DstSign = std::numeric_limits<Dst>::is_signed + ? INTEGER_REPRESENTATION_SIGNED + : INTEGER_REPRESENTATION_UNSIGNED, + IntegerRepresentation SrcSign = std::numeric_limits<Src>::is_signed + ? INTEGER_REPRESENTATION_SIGNED + : INTEGER_REPRESENTATION_UNSIGNED> +struct StaticDstRangeRelationToSrcRange; + +// Same sign: Dst is guaranteed to contain Src only if its range is equal or +// larger. +template <typename Dst, typename Src, IntegerRepresentation Sign> +struct StaticDstRangeRelationToSrcRange<Dst, Src, Sign, Sign> +{ + static const NumericRangeRepresentation value = + MaxExponent<Dst>::value >= MaxExponent<Src>::value ? NUMERIC_RANGE_CONTAINED + : NUMERIC_RANGE_NOT_CONTAINED; +}; + +// Unsigned to signed: Dst is guaranteed to contain source only if its range is +// larger. +template <typename Dst, typename Src> +struct StaticDstRangeRelationToSrcRange<Dst, + Src, + INTEGER_REPRESENTATION_SIGNED, + INTEGER_REPRESENTATION_UNSIGNED> +{ + static const NumericRangeRepresentation value = + MaxExponent<Dst>::value > MaxExponent<Src>::value ? NUMERIC_RANGE_CONTAINED + : NUMERIC_RANGE_NOT_CONTAINED; +}; + +// Signed to unsigned: Dst cannot be statically determined to contain Src. +template <typename Dst, typename Src> +struct StaticDstRangeRelationToSrcRange<Dst, + Src, + INTEGER_REPRESENTATION_UNSIGNED, + INTEGER_REPRESENTATION_SIGNED> +{ + static const NumericRangeRepresentation value = NUMERIC_RANGE_NOT_CONTAINED; +}; + +enum RangeConstraint : unsigned char +{ + RANGE_VALID = 0x0, // Value can be represented by the destination type. + RANGE_UNDERFLOW = 0x1, // Value would overflow. + RANGE_OVERFLOW = 0x2, // Value would underflow. + RANGE_INVALID = RANGE_UNDERFLOW | RANGE_OVERFLOW // Invalid (i.e. NaN). +}; + +// Helper function for coercing an int back to a RangeContraint. +constexpr RangeConstraint GetRangeConstraint(int integer_range_constraint) +{ + // TODO(jschuh): Once we get full C++14 support we want this + // assert(integer_range_constraint >= RANGE_VALID && + // integer_range_constraint <= RANGE_INVALID) + return static_cast<RangeConstraint>(integer_range_constraint); +} + +// This function creates a RangeConstraint from an upper and lower bound +// check by taking advantage of the fact that only NaN can be out of range in +// both directions at once. +constexpr inline RangeConstraint GetRangeConstraint(bool is_in_upper_bound, bool is_in_lower_bound) +{ + return GetRangeConstraint((is_in_upper_bound ? 0 : RANGE_OVERFLOW) | + (is_in_lower_bound ? 0 : RANGE_UNDERFLOW)); +} + +// The following helper template addresses a corner case in range checks for +// conversion from a floating-point type to an integral type of smaller range +// but larger precision (e.g. float -> unsigned). The problem is as follows: +// 1. Integral maximum is always one less than a power of two, so it must be +// truncated to fit the mantissa of the floating point. The direction of +// rounding is implementation defined, but by default it's always IEEE +// floats, which round to nearest and thus result in a value of larger +// magnitude than the integral value. +// Example: float f = UINT_MAX; // f is 4294967296f but UINT_MAX +// // is 4294967295u. +// 2. If the floating point value is equal to the promoted integral maximum +// value, a range check will erroneously pass. +// Example: (4294967296f <= 4294967295u) // This is true due to a precision +// // loss in rounding up to float. +// 3. When the floating point value is then converted to an integral, the +// resulting value is out of range for the target integral type and +// thus is implementation defined. +// Example: unsigned u = (float)INT_MAX; // u will typically overflow to 0. +// To fix this bug we manually truncate the maximum value when the destination +// type is an integral of larger precision than the source floating-point type, +// such that the resulting maximum is represented exactly as a floating point. +template <typename Dst, typename Src> +struct NarrowingRange +{ + typedef typename std::numeric_limits<Src> SrcLimits; + typedef typename std::numeric_limits<Dst> DstLimits; + // The following logic avoids warnings where the max function is + // instantiated with invalid values for a bit shift (even though + // such a function can never be called). + static const int shift = (MaxExponent<Src>::value > MaxExponent<Dst>::value && + SrcLimits::digits < DstLimits::digits && + SrcLimits::is_iec559 && + DstLimits::is_integer) + ? (DstLimits::digits - SrcLimits::digits) + : 0; + + static constexpr Dst max() + { + // We use UINTMAX_C below to avoid compiler warnings about shifting floating + // points. Since it's a compile time calculation, it shouldn't have any + // performance impact. + return DstLimits::max() - static_cast<Dst>((UINTMAX_C(1) << shift) - 1); + } + + static constexpr Dst min() + { + return std::numeric_limits<Dst>::is_iec559 ? -DstLimits::max() : DstLimits::min(); + } +}; + +template <typename Dst, + typename Src, + IntegerRepresentation DstSign = std::numeric_limits<Dst>::is_signed + ? INTEGER_REPRESENTATION_SIGNED + : INTEGER_REPRESENTATION_UNSIGNED, + IntegerRepresentation SrcSign = std::numeric_limits<Src>::is_signed + ? INTEGER_REPRESENTATION_SIGNED + : INTEGER_REPRESENTATION_UNSIGNED, + NumericRangeRepresentation DstRange = StaticDstRangeRelationToSrcRange<Dst, Src>::value> +struct DstRangeRelationToSrcRangeImpl; + +// The following templates are for ranges that must be verified at runtime. We +// split it into checks based on signedness to avoid confusing casts and +// compiler warnings on signed an unsigned comparisons. + +// Dst range is statically determined to contain Src: Nothing to check. +template <typename Dst, typename Src, IntegerRepresentation DstSign, IntegerRepresentation SrcSign> +struct DstRangeRelationToSrcRangeImpl<Dst, Src, DstSign, SrcSign, NUMERIC_RANGE_CONTAINED> +{ + static constexpr RangeConstraint Check(Src value) { return RANGE_VALID; } +}; + +// Signed to signed narrowing: Both the upper and lower boundaries may be +// exceeded. +template <typename Dst, typename Src> +struct DstRangeRelationToSrcRangeImpl<Dst, + Src, + INTEGER_REPRESENTATION_SIGNED, + INTEGER_REPRESENTATION_SIGNED, + NUMERIC_RANGE_NOT_CONTAINED> +{ + static constexpr RangeConstraint Check(Src value) + { + return GetRangeConstraint((value <= NarrowingRange<Dst, Src>::max()), + (value >= NarrowingRange<Dst, Src>::min())); + } +}; + +// Unsigned to unsigned narrowing: Only the upper boundary can be exceeded. +template <typename Dst, typename Src> +struct DstRangeRelationToSrcRangeImpl<Dst, + Src, + INTEGER_REPRESENTATION_UNSIGNED, + INTEGER_REPRESENTATION_UNSIGNED, + NUMERIC_RANGE_NOT_CONTAINED> +{ + static constexpr RangeConstraint Check(Src value) + { + return GetRangeConstraint(value <= NarrowingRange<Dst, Src>::max(), true); + } +}; + +// Unsigned to signed: The upper boundary may be exceeded. +template <typename Dst, typename Src> +struct DstRangeRelationToSrcRangeImpl<Dst, + Src, + INTEGER_REPRESENTATION_SIGNED, + INTEGER_REPRESENTATION_UNSIGNED, + NUMERIC_RANGE_NOT_CONTAINED> +{ + static constexpr RangeConstraint Check(Src value) + { + return sizeof(Dst) > sizeof(Src) + ? RANGE_VALID + : GetRangeConstraint(value <= static_cast<Src>(NarrowingRange<Dst, Src>::max()), + true); + } +}; + +// Signed to unsigned: The upper boundary may be exceeded for a narrower Dst, +// and any negative value exceeds the lower boundary. +template <typename Dst, typename Src> +struct DstRangeRelationToSrcRangeImpl<Dst, + Src, + INTEGER_REPRESENTATION_UNSIGNED, + INTEGER_REPRESENTATION_SIGNED, + NUMERIC_RANGE_NOT_CONTAINED> +{ + static constexpr RangeConstraint Check(Src value) + { + return (MaxExponent<Dst>::value >= MaxExponent<Src>::value) + ? GetRangeConstraint(true, value >= static_cast<Src>(0)) + : GetRangeConstraint(value <= static_cast<Src>(NarrowingRange<Dst, Src>::max()), + value >= static_cast<Src>(0)); + } +}; + +template <typename Dst, typename Src> +constexpr RangeConstraint DstRangeRelationToSrcRange(Src value) +{ + static_assert(std::numeric_limits<Src>::is_specialized, "Argument must be numeric."); + static_assert(std::numeric_limits<Dst>::is_specialized, "Result must be numeric."); + return DstRangeRelationToSrcRangeImpl<Dst, Src>::Check(value); +} + +} // namespace internal +} // namespace base + +#endif // BASE_NUMERICS_SAFE_CONVERSIONS_IMPL_H_ diff --git a/gfx/angle/src/common/third_party/numerics/base/numerics/safe_math.h b/gfx/angle/src/common/third_party/numerics/base/numerics/safe_math.h new file mode 100755 index 000000000..505efde38 --- /dev/null +++ b/gfx/angle/src/common/third_party/numerics/base/numerics/safe_math.h @@ -0,0 +1,324 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_NUMERICS_SAFE_MATH_H_ +#define BASE_NUMERICS_SAFE_MATH_H_ + +#include <stddef.h> + +#include <limits> +#include <type_traits> + +#include "base/logging.h" +#include "base/numerics/safe_math_impl.h" + +namespace base +{ + +namespace internal +{ + +// CheckedNumeric implements all the logic and operators for detecting integer +// boundary conditions such as overflow, underflow, and invalid conversions. +// The CheckedNumeric type implicitly converts from floating point and integer +// data types, and contains overloads for basic arithmetic operations (i.e.: +, +// -, *, /, %). +// +// The following methods convert from CheckedNumeric to standard numeric values: +// IsValid() - Returns true if the underlying numeric value is valid (i.e. has +// has not wrapped and is not the result of an invalid conversion). +// ValueOrDie() - Returns the underlying value. If the state is not valid this +// call will crash on a CHECK. +// ValueOrDefault() - Returns the current value, or the supplied default if the +// state is not valid. +// ValueFloating() - Returns the underlying floating point value (valid only +// only for floating point CheckedNumeric types). +// +// Bitwise operations are explicitly not supported, because correct +// handling of some cases (e.g. sign manipulation) is ambiguous. Comparison +// operations are explicitly not supported because they could result in a crash +// on a CHECK condition. You should use patterns like the following for these +// operations: +// Bitwise operation: +// CheckedNumeric<int> checked_int = untrusted_input_value; +// int x = checked_int.ValueOrDefault(0) | kFlagValues; +// Comparison: +// CheckedNumeric<size_t> checked_size = untrusted_input_value; +// checked_size += HEADER LENGTH; +// if (checked_size.IsValid() && checked_size.ValueOrDie() < buffer_size) +// Do stuff... +template <typename T> +class CheckedNumeric +{ + static_assert(std::is_arithmetic<T>::value, "CheckedNumeric<T>: T must be a numeric type."); + + public: + typedef T type; + + CheckedNumeric() {} + + // Copy constructor. + template <typename Src> + CheckedNumeric(const CheckedNumeric<Src> &rhs) : state_(rhs.ValueUnsafe(), rhs.validity()) + { + } + + template <typename Src> + CheckedNumeric(Src value, RangeConstraint validity) : state_(value, validity) + { + } + + // This is not an explicit constructor because we implicitly upgrade regular + // numerics to CheckedNumerics to make them easier to use. + template <typename Src> + CheckedNumeric(Src value) // NOLINT(runtime/explicit) + : state_(value) + { + static_assert(std::numeric_limits<Src>::is_specialized, "Argument must be numeric."); + } + + // This is not an explicit constructor because we want a seamless conversion + // from StrictNumeric types. + template <typename Src> + CheckedNumeric(StrictNumeric<Src> value) // NOLINT(runtime/explicit) + : state_(static_cast<Src>(value)) + { + } + + // IsValid() is the public API to test if a CheckedNumeric is currently valid. + bool IsValid() const { return validity() == RANGE_VALID; } + + // ValueOrDie() The primary accessor for the underlying value. If the current + // state is not valid it will CHECK and crash. + T ValueOrDie() const + { + CHECK(IsValid()); + return state_.value(); + } + + // ValueOrDefault(T default_value) A convenience method that returns the + // current value if the state is valid, and the supplied default_value for + // any other state. + T ValueOrDefault(T default_value) const { return IsValid() ? state_.value() : default_value; } + + // ValueFloating() - Since floating point values include their validity state, + // we provide an easy method for extracting them directly, without a risk of + // crashing on a CHECK. + T ValueFloating() const + { + static_assert(std::numeric_limits<T>::is_iec559, "Argument must be float."); + return CheckedNumeric<T>::cast(*this).ValueUnsafe(); + } + + // validity() - DO NOT USE THIS IN EXTERNAL CODE - It is public right now for + // tests and to avoid a big matrix of friend operator overloads. But the + // values it returns are likely to change in the future. + // Returns: current validity state (i.e. valid, overflow, underflow, nan). + // TODO(jschuh): crbug.com/332611 Figure out and implement semantics for + // saturation/wrapping so we can expose this state consistently and implement + // saturated arithmetic. + RangeConstraint validity() const { return state_.validity(); } + + // ValueUnsafe() - DO NOT USE THIS IN EXTERNAL CODE - It is public right now + // for tests and to avoid a big matrix of friend operator overloads. But the + // values it returns are likely to change in the future. + // Returns: the raw numeric value, regardless of the current state. + // TODO(jschuh): crbug.com/332611 Figure out and implement semantics for + // saturation/wrapping so we can expose this state consistently and implement + // saturated arithmetic. + T ValueUnsafe() const { return state_.value(); } + + // Prototypes for the supported arithmetic operator overloads. + template <typename Src> + CheckedNumeric &operator+=(Src rhs); + template <typename Src> + CheckedNumeric &operator-=(Src rhs); + template <typename Src> + CheckedNumeric &operator*=(Src rhs); + template <typename Src> + CheckedNumeric &operator/=(Src rhs); + template <typename Src> + CheckedNumeric &operator%=(Src rhs); + + CheckedNumeric operator-() const + { + RangeConstraint validity; + T value = CheckedNeg(state_.value(), &validity); + // Negation is always valid for floating point. + if (std::numeric_limits<T>::is_iec559) + return CheckedNumeric<T>(value); + + validity = GetRangeConstraint(state_.validity() | validity); + return CheckedNumeric<T>(value, validity); + } + + CheckedNumeric Abs() const + { + RangeConstraint validity; + T value = CheckedAbs(state_.value(), &validity); + // Absolute value is always valid for floating point. + if (std::numeric_limits<T>::is_iec559) + return CheckedNumeric<T>(value); + + validity = GetRangeConstraint(state_.validity() | validity); + return CheckedNumeric<T>(value, validity); + } + + // This function is available only for integral types. It returns an unsigned + // integer of the same width as the source type, containing the absolute value + // of the source, and properly handling signed min. + CheckedNumeric<typename UnsignedOrFloatForSize<T>::type> UnsignedAbs() const + { + return CheckedNumeric<typename UnsignedOrFloatForSize<T>::type>( + CheckedUnsignedAbs(state_.value()), state_.validity()); + } + + CheckedNumeric &operator++() + { + *this += 1; + return *this; + } + + CheckedNumeric operator++(int) + { + CheckedNumeric value = *this; + *this += 1; + return value; + } + + CheckedNumeric &operator--() + { + *this -= 1; + return *this; + } + + CheckedNumeric operator--(int) + { + CheckedNumeric value = *this; + *this -= 1; + return value; + } + + // These static methods behave like a convenience cast operator targeting + // the desired CheckedNumeric type. As an optimization, a reference is + // returned when Src is the same type as T. + template <typename Src> + static CheckedNumeric<T> cast( + Src u, + typename std::enable_if<std::numeric_limits<Src>::is_specialized, int>::type = 0) + { + return u; + } + + template <typename Src> + static CheckedNumeric<T> cast( + const CheckedNumeric<Src> &u, + typename std::enable_if<!std::is_same<Src, T>::value, int>::type = 0) + { + return u; + } + + static const CheckedNumeric<T> &cast(const CheckedNumeric<T> &u) { return u; } + + private: + template <typename NumericType> + struct UnderlyingType + { + using type = NumericType; + }; + + template <typename NumericType> + struct UnderlyingType<CheckedNumeric<NumericType>> + { + using type = NumericType; + }; + + CheckedNumericState<T> state_; +}; + +// This is the boilerplate for the standard arithmetic operator overloads. A +// macro isn't the prettiest solution, but it beats rewriting these five times. +// Some details worth noting are: +// * We apply the standard arithmetic promotions. +// * We skip range checks for floating points. +// * We skip range checks for destination integers with sufficient range. +// TODO(jschuh): extract these out into templates. +#define BASE_NUMERIC_ARITHMETIC_OPERATORS(NAME, OP, COMPOUND_OP) \ + /* Binary arithmetic operator for CheckedNumerics of the same type. */ \ + template <typename T> \ + CheckedNumeric<typename ArithmeticPromotion<T>::type> operator OP( \ + const CheckedNumeric<T> &lhs, const CheckedNumeric<T> &rhs) \ + { \ + typedef typename ArithmeticPromotion<T>::type Promotion; \ + /* Floating point always takes the fast path */ \ + if (std::numeric_limits<T>::is_iec559) \ + return CheckedNumeric<T>(lhs.ValueUnsafe() OP rhs.ValueUnsafe()); \ + if (IsIntegerArithmeticSafe<Promotion, T, T>::value) \ + return CheckedNumeric<Promotion>(lhs.ValueUnsafe() OP rhs.ValueUnsafe(), \ + GetRangeConstraint(rhs.validity() | lhs.validity())); \ + RangeConstraint validity = RANGE_VALID; \ + T result = \ + static_cast<T>(Checked##NAME(static_cast<Promotion>(lhs.ValueUnsafe()), \ + static_cast<Promotion>(rhs.ValueUnsafe()), &validity)); \ + return CheckedNumeric<Promotion>( \ + result, GetRangeConstraint(validity | lhs.validity() | rhs.validity())); \ + } \ + /* Assignment arithmetic operator implementation from CheckedNumeric. */ \ + template <typename T> \ + template <typename Src> \ + CheckedNumeric<T> &CheckedNumeric<T>::operator COMPOUND_OP(Src rhs) \ + { \ + *this = CheckedNumeric<T>::cast(*this) \ + OP CheckedNumeric<typename UnderlyingType<Src>::type>::cast(rhs); \ + return *this; \ + } \ + /* Binary arithmetic operator for CheckedNumeric of different type. */ \ + template <typename T, typename Src> \ + CheckedNumeric<typename ArithmeticPromotion<T, Src>::type> operator OP( \ + const CheckedNumeric<Src> &lhs, const CheckedNumeric<T> &rhs) \ + { \ + typedef typename ArithmeticPromotion<T, Src>::type Promotion; \ + if (IsIntegerArithmeticSafe<Promotion, T, Src>::value) \ + return CheckedNumeric<Promotion>(lhs.ValueUnsafe() OP rhs.ValueUnsafe(), \ + GetRangeConstraint(rhs.validity() | lhs.validity())); \ + return CheckedNumeric<Promotion>::cast(lhs) OP CheckedNumeric<Promotion>::cast(rhs); \ + } \ + /* Binary arithmetic operator for left CheckedNumeric and right numeric. */ \ + template <typename T, typename Src, \ + typename std::enable_if<std::is_arithmetic<Src>::value>::type * = nullptr> \ + CheckedNumeric<typename ArithmeticPromotion<T, Src>::type> operator OP( \ + const CheckedNumeric<T> &lhs, Src rhs) \ + { \ + typedef typename ArithmeticPromotion<T, Src>::type Promotion; \ + if (IsIntegerArithmeticSafe<Promotion, T, Src>::value) \ + return CheckedNumeric<Promotion>(lhs.ValueUnsafe() OP rhs, lhs.validity()); \ + return CheckedNumeric<Promotion>::cast(lhs) OP CheckedNumeric<Promotion>::cast(rhs); \ + } \ + /* Binary arithmetic operator for left numeric and right CheckedNumeric. */ \ + template <typename T, typename Src, \ + typename std::enable_if<std::is_arithmetic<Src>::value>::type * = nullptr> \ + CheckedNumeric<typename ArithmeticPromotion<T, Src>::type> operator OP( \ + Src lhs, const CheckedNumeric<T> &rhs) \ + { \ + typedef typename ArithmeticPromotion<T, Src>::type Promotion; \ + if (IsIntegerArithmeticSafe<Promotion, T, Src>::value) \ + return CheckedNumeric<Promotion>(lhs OP rhs.ValueUnsafe(), rhs.validity()); \ + return CheckedNumeric<Promotion>::cast(lhs) OP CheckedNumeric<Promotion>::cast(rhs); \ + } + +BASE_NUMERIC_ARITHMETIC_OPERATORS(Add, +, +=) +BASE_NUMERIC_ARITHMETIC_OPERATORS(Sub, -, -=) +BASE_NUMERIC_ARITHMETIC_OPERATORS(Mul, *, *=) +BASE_NUMERIC_ARITHMETIC_OPERATORS(Div, /, /=) +BASE_NUMERIC_ARITHMETIC_OPERATORS(Mod, %, %=) + +#undef BASE_NUMERIC_ARITHMETIC_OPERATORS + +} // namespace internal + +using internal::CheckedNumeric; + +} // namespace base + +#endif // BASE_NUMERICS_SAFE_MATH_H_ diff --git a/gfx/angle/src/common/third_party/numerics/base/numerics/safe_math_impl.h b/gfx/angle/src/common/third_party/numerics/base/numerics/safe_math_impl.h new file mode 100755 index 000000000..341cdbc2b --- /dev/null +++ b/gfx/angle/src/common/third_party/numerics/base/numerics/safe_math_impl.h @@ -0,0 +1,570 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_NUMERICS_SAFE_MATH_IMPL_H_ +#define BASE_NUMERICS_SAFE_MATH_IMPL_H_ + +#include <stddef.h> +#include <stdint.h> + +#include <climits> +#include <cmath> +#include <cstdlib> +#include <limits> +#include <type_traits> + +#include "base/numerics/safe_conversions.h" + +namespace base +{ +namespace internal +{ + +// Everything from here up to the floating point operations is portable C++, +// but it may not be fast. This code could be split based on +// platform/architecture and replaced with potentially faster implementations. + +// Integer promotion templates used by the portable checked integer arithmetic. +template <size_t Size, bool IsSigned> +struct IntegerForSizeAndSign; +template <> +struct IntegerForSizeAndSign<1, true> +{ + typedef int8_t type; +}; +template <> +struct IntegerForSizeAndSign<1, false> +{ + typedef uint8_t type; +}; +template <> +struct IntegerForSizeAndSign<2, true> +{ + typedef int16_t type; +}; +template <> +struct IntegerForSizeAndSign<2, false> +{ + typedef uint16_t type; +}; +template <> +struct IntegerForSizeAndSign<4, true> +{ + typedef int32_t type; +}; +template <> +struct IntegerForSizeAndSign<4, false> +{ + typedef uint32_t type; +}; +template <> +struct IntegerForSizeAndSign<8, true> +{ + typedef int64_t type; +}; +template <> +struct IntegerForSizeAndSign<8, false> +{ + typedef uint64_t type; +}; + +// WARNING: We have no IntegerForSizeAndSign<16, *>. If we ever add one to +// support 128-bit math, then the ArithmeticPromotion template below will need +// to be updated (or more likely replaced with a decltype expression). + +template <typename Integer> +struct UnsignedIntegerForSize +{ + typedef + typename std::enable_if<std::numeric_limits<Integer>::is_integer, + typename IntegerForSizeAndSign<sizeof(Integer), false>::type>::type + type; +}; + +template <typename Integer> +struct SignedIntegerForSize +{ + typedef + typename std::enable_if<std::numeric_limits<Integer>::is_integer, + typename IntegerForSizeAndSign<sizeof(Integer), true>::type>::type + type; +}; + +template <typename Integer> +struct TwiceWiderInteger +{ + typedef typename std::enable_if< + std::numeric_limits<Integer>::is_integer, + typename IntegerForSizeAndSign<sizeof(Integer) * 2, + std::numeric_limits<Integer>::is_signed>::type>::type type; +}; + +template <typename Integer> +struct PositionOfSignBit +{ + static const typename std::enable_if<std::numeric_limits<Integer>::is_integer, size_t>::type + value = CHAR_BIT * sizeof(Integer) - 1; +}; + +// This is used for UnsignedAbs, where we need to support floating-point +// template instantiations even though we don't actually support the operations. +// However, there is no corresponding implementation of e.g. CheckedUnsignedAbs, +// so the float versions will not compile. +template <typename Numeric, + bool IsInteger = std::numeric_limits<Numeric>::is_integer, + bool IsFloat = std::numeric_limits<Numeric>::is_iec559> +struct UnsignedOrFloatForSize; + +template <typename Numeric> +struct UnsignedOrFloatForSize<Numeric, true, false> +{ + typedef typename UnsignedIntegerForSize<Numeric>::type type; +}; + +template <typename Numeric> +struct UnsignedOrFloatForSize<Numeric, false, true> +{ + typedef Numeric type; +}; + +// Helper templates for integer manipulations. + +template <typename T> +constexpr bool HasSignBit(T x) +{ + // Cast to unsigned since right shift on signed is undefined. + return !!(static_cast<typename UnsignedIntegerForSize<T>::type>(x) >> + PositionOfSignBit<T>::value); +} + +// This wrapper undoes the standard integer promotions. +template <typename T> +constexpr T BinaryComplement(T x) +{ + return static_cast<T>(~x); +} + +// Here are the actual portable checked integer math implementations. +// TODO(jschuh): Break this code out from the enable_if pattern and find a clean +// way to coalesce things into the CheckedNumericState specializations below. + +template <typename T> +typename std::enable_if<std::numeric_limits<T>::is_integer, T>::type +CheckedAdd(T x, T y, RangeConstraint *validity) +{ + // Since the value of x+y is undefined if we have a signed type, we compute + // it using the unsigned type of the same size. + typedef typename UnsignedIntegerForSize<T>::type UnsignedDst; + UnsignedDst ux = static_cast<UnsignedDst>(x); + UnsignedDst uy = static_cast<UnsignedDst>(y); + UnsignedDst uresult = static_cast<UnsignedDst>(ux + uy); + // Addition is valid if the sign of (x + y) is equal to either that of x or + // that of y. + if (std::numeric_limits<T>::is_signed) + { + if (HasSignBit(BinaryComplement(static_cast<UnsignedDst>((uresult ^ ux) & (uresult ^ uy))))) + { + *validity = RANGE_VALID; + } + else + { // Direction of wrap is inverse of result sign. + *validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW; + } + } + else + { // Unsigned is either valid or overflow. + *validity = BinaryComplement(x) >= y ? RANGE_VALID : RANGE_OVERFLOW; + } + return static_cast<T>(uresult); +} + +template <typename T> +typename std::enable_if<std::numeric_limits<T>::is_integer, T>::type +CheckedSub(T x, T y, RangeConstraint *validity) +{ + // Since the value of x+y is undefined if we have a signed type, we compute + // it using the unsigned type of the same size. + typedef typename UnsignedIntegerForSize<T>::type UnsignedDst; + UnsignedDst ux = static_cast<UnsignedDst>(x); + UnsignedDst uy = static_cast<UnsignedDst>(y); + UnsignedDst uresult = static_cast<UnsignedDst>(ux - uy); + // Subtraction is valid if either x and y have same sign, or (x-y) and x have + // the same sign. + if (std::numeric_limits<T>::is_signed) + { + if (HasSignBit(BinaryComplement(static_cast<UnsignedDst>((uresult ^ ux) & (ux ^ uy))))) + { + *validity = RANGE_VALID; + } + else + { // Direction of wrap is inverse of result sign. + *validity = HasSignBit(uresult) ? RANGE_OVERFLOW : RANGE_UNDERFLOW; + } + } + else + { // Unsigned is either valid or underflow. + *validity = x >= y ? RANGE_VALID : RANGE_UNDERFLOW; + } + return static_cast<T>(uresult); +} + +// Integer multiplication is a bit complicated. In the fast case we just +// we just promote to a twice wider type, and range check the result. In the +// slow case we need to manually check that the result won't be truncated by +// checking with division against the appropriate bound. +template <typename T> +typename std::enable_if<std::numeric_limits<T>::is_integer && sizeof(T) * 2 <= sizeof(uintmax_t), + T>::type +CheckedMul(T x, T y, RangeConstraint *validity) +{ + typedef typename TwiceWiderInteger<T>::type IntermediateType; + IntermediateType tmp = static_cast<IntermediateType>(x) * static_cast<IntermediateType>(y); + *validity = DstRangeRelationToSrcRange<T>(tmp); + return static_cast<T>(tmp); +} + +template <typename T> +typename std::enable_if<std::numeric_limits<T>::is_integer && std::numeric_limits<T>::is_signed && + (sizeof(T) * 2 > sizeof(uintmax_t)), + T>::type +CheckedMul(T x, T y, RangeConstraint *validity) +{ + // If either side is zero then the result will be zero. + if (!x || !y) + { + *validity = RANGE_VALID; + return static_cast<T>(0); + } + else if (x > 0) + { + if (y > 0) + *validity = x <= std::numeric_limits<T>::max() / y ? RANGE_VALID : RANGE_OVERFLOW; + else + *validity = y >= std::numeric_limits<T>::min() / x ? RANGE_VALID : RANGE_UNDERFLOW; + } + else + { + if (y > 0) + *validity = x >= std::numeric_limits<T>::min() / y ? RANGE_VALID : RANGE_UNDERFLOW; + else + *validity = y >= std::numeric_limits<T>::max() / x ? RANGE_VALID : RANGE_OVERFLOW; + } + + return static_cast<T>(x * y); +} + +template <typename T> +typename std::enable_if<std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed && + (sizeof(T) * 2 > sizeof(uintmax_t)), + T>::type +CheckedMul(T x, T y, RangeConstraint *validity) +{ + *validity = (y == 0 || x <= std::numeric_limits<T>::max() / y) ? RANGE_VALID : RANGE_OVERFLOW; + return static_cast<T>(x * y); +} + +// Division just requires a check for an invalid negation on signed min/-1. +template <typename T> +T CheckedDiv(T x, + T y, + RangeConstraint *validity, + typename std::enable_if<std::numeric_limits<T>::is_integer, int>::type = 0) +{ + if (std::numeric_limits<T>::is_signed && x == std::numeric_limits<T>::min() && + y == static_cast<T>(-1)) + { + *validity = RANGE_OVERFLOW; + return std::numeric_limits<T>::min(); + } + + *validity = RANGE_VALID; + return static_cast<T>(x / y); +} + +template <typename T> +typename std::enable_if<std::numeric_limits<T>::is_integer && std::numeric_limits<T>::is_signed, + T>::type +CheckedMod(T x, T y, RangeConstraint *validity) +{ + *validity = y > 0 ? RANGE_VALID : RANGE_INVALID; + return static_cast<T>(x % y); +} + +template <typename T> +typename std::enable_if<std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed, + T>::type +CheckedMod(T x, T y, RangeConstraint *validity) +{ + *validity = RANGE_VALID; + return static_cast<T>(x % y); +} + +template <typename T> +typename std::enable_if<std::numeric_limits<T>::is_integer && std::numeric_limits<T>::is_signed, + T>::type +CheckedNeg(T value, RangeConstraint *validity) +{ + *validity = value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW; + // The negation of signed min is min, so catch that one. + return static_cast<T>(-value); +} + +template <typename T> +typename std::enable_if<std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed, + T>::type +CheckedNeg(T value, RangeConstraint *validity) +{ + // The only legal unsigned negation is zero. + *validity = value ? RANGE_UNDERFLOW : RANGE_VALID; + return static_cast<T>(-static_cast<typename SignedIntegerForSize<T>::type>(value)); +} + +template <typename T> +typename std::enable_if<std::numeric_limits<T>::is_integer && std::numeric_limits<T>::is_signed, + T>::type +CheckedAbs(T value, RangeConstraint *validity) +{ + *validity = value != std::numeric_limits<T>::min() ? RANGE_VALID : RANGE_OVERFLOW; + return static_cast<T>(std::abs(value)); +} + +template <typename T> +typename std::enable_if<std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed, + T>::type +CheckedAbs(T value, RangeConstraint *validity) +{ + // T is unsigned, so |value| must already be positive. + *validity = RANGE_VALID; + return value; +} + +template <typename T> +typename std::enable_if<std::numeric_limits<T>::is_integer && std::numeric_limits<T>::is_signed, + typename UnsignedIntegerForSize<T>::type>::type +CheckedUnsignedAbs(T value) +{ + typedef typename UnsignedIntegerForSize<T>::type UnsignedT; + return value == std::numeric_limits<T>::min() + ? static_cast<UnsignedT>(std::numeric_limits<T>::max()) + 1 + : static_cast<UnsignedT>(std::abs(value)); +} + +template <typename T> +typename std::enable_if<std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed, + T>::type +CheckedUnsignedAbs(T value) +{ + // T is unsigned, so |value| must already be positive. + return static_cast<T>(value); +} + +// These are the floating point stubs that the compiler needs to see. Only the +// negation operation is ever called. +#define BASE_FLOAT_ARITHMETIC_STUBS(NAME) \ + template <typename T> \ + typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type Checked##NAME( \ + T, T, RangeConstraint *) \ + { \ + NOTREACHED(); \ + return static_cast<T>(0); \ + } + +BASE_FLOAT_ARITHMETIC_STUBS(Add) +BASE_FLOAT_ARITHMETIC_STUBS(Sub) +BASE_FLOAT_ARITHMETIC_STUBS(Mul) +BASE_FLOAT_ARITHMETIC_STUBS(Div) +BASE_FLOAT_ARITHMETIC_STUBS(Mod) + +#undef BASE_FLOAT_ARITHMETIC_STUBS + +template <typename T> +typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedNeg(T value, + RangeConstraint *) +{ + return static_cast<T>(-value); +} + +template <typename T> +typename std::enable_if<std::numeric_limits<T>::is_iec559, T>::type CheckedAbs(T value, + RangeConstraint *) +{ + return static_cast<T>(std::abs(value)); +} + +// Floats carry around their validity state with them, but integers do not. So, +// we wrap the underlying value in a specialization in order to hide that detail +// and expose an interface via accessors. +enum NumericRepresentation +{ + NUMERIC_INTEGER, + NUMERIC_FLOATING, + NUMERIC_UNKNOWN +}; + +template <typename NumericType> +struct GetNumericRepresentation +{ + static const NumericRepresentation value = + std::numeric_limits<NumericType>::is_integer + ? NUMERIC_INTEGER + : (std::numeric_limits<NumericType>::is_iec559 ? NUMERIC_FLOATING : NUMERIC_UNKNOWN); +}; + +template <typename T, NumericRepresentation type = GetNumericRepresentation<T>::value> +class CheckedNumericState +{ +}; + +// Integrals require quite a bit of additional housekeeping to manage state. +template <typename T> +class CheckedNumericState<T, NUMERIC_INTEGER> +{ + private: + T value_; + RangeConstraint validity_ : CHAR_BIT; // Actually requires only two bits. + + public: + template <typename Src, NumericRepresentation type> + friend class CheckedNumericState; + + CheckedNumericState() : value_(0), validity_(RANGE_VALID) {} + + template <typename Src> + CheckedNumericState(Src value, RangeConstraint validity) + : value_(static_cast<T>(value)), + validity_(GetRangeConstraint(validity | DstRangeRelationToSrcRange<T>(value))) + { + static_assert(std::numeric_limits<Src>::is_specialized, "Argument must be numeric."); + } + + // Copy constructor. + template <typename Src> + CheckedNumericState(const CheckedNumericState<Src> &rhs) + : value_(static_cast<T>(rhs.value())), + validity_(GetRangeConstraint(rhs.validity() | DstRangeRelationToSrcRange<T>(rhs.value()))) + { + } + + template <typename Src> + explicit CheckedNumericState( + Src value, + typename std::enable_if<std::numeric_limits<Src>::is_specialized, int>::type = 0) + : value_(static_cast<T>(value)), validity_(DstRangeRelationToSrcRange<T>(value)) + { + } + + RangeConstraint validity() const { return validity_; } + T value() const { return value_; } +}; + +// Floating points maintain their own validity, but need translation wrappers. +template <typename T> +class CheckedNumericState<T, NUMERIC_FLOATING> +{ + private: + T value_; + + public: + template <typename Src, NumericRepresentation type> + friend class CheckedNumericState; + + CheckedNumericState() : value_(0.0) {} + + template <typename Src> + CheckedNumericState( + Src value, + RangeConstraint validity, + typename std::enable_if<std::numeric_limits<Src>::is_integer, int>::type = 0) + { + switch (DstRangeRelationToSrcRange<T>(value)) + { + case RANGE_VALID: + value_ = static_cast<T>(value); + break; + + case RANGE_UNDERFLOW: + value_ = -std::numeric_limits<T>::infinity(); + break; + + case RANGE_OVERFLOW: + value_ = std::numeric_limits<T>::infinity(); + break; + + case RANGE_INVALID: + value_ = std::numeric_limits<T>::quiet_NaN(); + break; + + default: + NOTREACHED(); + } + } + + template <typename Src> + explicit CheckedNumericState( + Src value, + typename std::enable_if<std::numeric_limits<Src>::is_specialized, int>::type = 0) + : value_(static_cast<T>(value)) + { + } + + // Copy constructor. + template <typename Src> + CheckedNumericState(const CheckedNumericState<Src> &rhs) : value_(static_cast<T>(rhs.value())) + { + } + + RangeConstraint validity() const + { + return GetRangeConstraint(value_ <= std::numeric_limits<T>::max(), + value_ >= -std::numeric_limits<T>::max()); + } + T value() const { return value_; } +}; + +// For integers less than 128-bit and floats 32-bit or larger, we have the type +// with the larger maximum exponent take precedence. +enum ArithmeticPromotionCategory +{ + LEFT_PROMOTION, + RIGHT_PROMOTION +}; + +template <typename Lhs, + typename Rhs = Lhs, + ArithmeticPromotionCategory Promotion = + (MaxExponent<Lhs>::value > MaxExponent<Rhs>::value) ? LEFT_PROMOTION + : RIGHT_PROMOTION> +struct ArithmeticPromotion; + +template <typename Lhs, typename Rhs> +struct ArithmeticPromotion<Lhs, Rhs, LEFT_PROMOTION> +{ + typedef Lhs type; +}; + +template <typename Lhs, typename Rhs> +struct ArithmeticPromotion<Lhs, Rhs, RIGHT_PROMOTION> +{ + typedef Rhs type; +}; + +// We can statically check if operations on the provided types can wrap, so we +// can skip the checked operations if they're not needed. So, for an integer we +// care if the destination type preserves the sign and is twice the width of +// the source. +template <typename T, typename Lhs, typename Rhs> +struct IsIntegerArithmeticSafe +{ + static const bool value = + !std::numeric_limits<T>::is_iec559 && + StaticDstRangeRelationToSrcRange<T, Lhs>::value == NUMERIC_RANGE_CONTAINED && + sizeof(T) >= (2 * sizeof(Lhs)) && + StaticDstRangeRelationToSrcRange<T, Rhs>::value != NUMERIC_RANGE_CONTAINED && + sizeof(T) >= (2 * sizeof(Rhs)); +}; + +} // namespace internal +} // namespace base + +#endif // BASE_NUMERICS_SAFE_MATH_IMPL_H_ diff --git a/gfx/angle/src/common/third_party/numerics/base/numerics/safe_numerics_unittest.cc b/gfx/angle/src/common/third_party/numerics/base/numerics/safe_numerics_unittest.cc new file mode 100755 index 000000000..052d85042 --- /dev/null +++ b/gfx/angle/src/common/third_party/numerics/base/numerics/safe_numerics_unittest.cc @@ -0,0 +1,771 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <stddef.h> +#include <stdint.h> + +#include <limits> +#include <type_traits> + +#include "base/compiler_specific.h" +#include "base/numerics/safe_conversions.h" +#include "base/numerics/safe_math.h" +#include "build/build_config.h" +#include "testing/gtest/include/gtest/gtest.h" + +#if defined(COMPILER_MSVC) && defined(ARCH_CPU_32_BITS) +#include <mmintrin.h> +#endif + +using std::numeric_limits; +using base::CheckedNumeric; +using base::checked_cast; +using base::IsValueInRangeForNumericType; +using base::IsValueNegative; +using base::SizeT; +using base::StrictNumeric; +using base::saturated_cast; +using base::strict_cast; +using base::internal::MaxExponent; +using base::internal::RANGE_VALID; +using base::internal::RANGE_INVALID; +using base::internal::RANGE_OVERFLOW; +using base::internal::RANGE_UNDERFLOW; +using base::internal::SignedIntegerForSize; + +// These tests deliberately cause arithmetic overflows. If the compiler is +// aggressive enough, it can const fold these overflows. Disable warnings about +// overflows for const expressions. +#if defined(OS_WIN) +#pragma warning(disable : 4756) +#endif + +// This is a helper function for finding the maximum value in Src that can be +// wholy represented as the destination floating-point type. +template <typename Dst, typename Src> +Dst GetMaxConvertibleToFloat() +{ + typedef numeric_limits<Dst> DstLimits; + typedef numeric_limits<Src> SrcLimits; + static_assert(SrcLimits::is_specialized, "Source must be numeric."); + static_assert(DstLimits::is_specialized, "Destination must be numeric."); + CHECK(DstLimits::is_iec559); + + if (SrcLimits::digits <= DstLimits::digits && + MaxExponent<Src>::value <= MaxExponent<Dst>::value) + return SrcLimits::max(); + Src max = SrcLimits::max() / 2 + (SrcLimits::is_integer ? 1 : 0); + while (max != static_cast<Src>(static_cast<Dst>(max))) + { + max /= 2; + } + return static_cast<Dst>(max); +} + +// Helper macros to wrap displaying the conversion types and line numbers. +#define TEST_EXPECTED_VALIDITY(expected, actual) \ + EXPECT_EQ(expected, CheckedNumeric<Dst>(actual).IsValid()) \ + << "Result test: Value " << +(actual).ValueUnsafe() << " as " << dst << " on line " \ + << line; + +#define TEST_EXPECTED_SUCCESS(actual) TEST_EXPECTED_VALIDITY(true, actual) +#define TEST_EXPECTED_FAILURE(actual) TEST_EXPECTED_VALIDITY(false, actual) + +#define TEST_EXPECTED_VALUE(expected, actual) \ + EXPECT_EQ(static_cast<Dst>(expected), CheckedNumeric<Dst>(actual).ValueUnsafe()) \ + << "Result test: Value " << +((actual).ValueUnsafe()) << " as " << dst << " on line " \ + << line; + +// Signed integer arithmetic. +template <typename Dst> +static void TestSpecializedArithmetic( + const char *dst, + int line, + typename std::enable_if<numeric_limits<Dst>::is_integer && numeric_limits<Dst>::is_signed, + int>::type = 0) +{ + typedef numeric_limits<Dst> DstLimits; + TEST_EXPECTED_FAILURE(-CheckedNumeric<Dst>(DstLimits::min())); + TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::min()).Abs()); + TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(-1).Abs()); + + TEST_EXPECTED_SUCCESS(CheckedNumeric<Dst>(DstLimits::max()) + -1); + TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::min()) + -1); + TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(-DstLimits::max()) + -DstLimits::max()); + + TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::min()) - 1); + TEST_EXPECTED_SUCCESS(CheckedNumeric<Dst>(DstLimits::min()) - -1); + TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::max()) - -DstLimits::max()); + TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(-DstLimits::max()) - DstLimits::max()); + + TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::min()) * 2); + + TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::min()) / -1); + TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(-1) / 2); + + // Modulus is legal only for integers. + TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>() % 1); + TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) % 1); + TEST_EXPECTED_VALUE(-1, CheckedNumeric<Dst>(-1) % 2); + TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(-1) % -2); + TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(DstLimits::min()) % 2); + TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(DstLimits::max()) % 2); + // Test all the different modulus combinations. + TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) % CheckedNumeric<Dst>(1)); + TEST_EXPECTED_VALUE(0, 1 % CheckedNumeric<Dst>(1)); + TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) % 1); + CheckedNumeric<Dst> checked_dst = 1; + TEST_EXPECTED_VALUE(0, checked_dst %= 1); +} + +// Unsigned integer arithmetic. +template <typename Dst> +static void TestSpecializedArithmetic( + const char *dst, + int line, + typename std::enable_if<numeric_limits<Dst>::is_integer && !numeric_limits<Dst>::is_signed, + int>::type = 0) +{ + typedef numeric_limits<Dst> DstLimits; + TEST_EXPECTED_SUCCESS(-CheckedNumeric<Dst>(DstLimits::min())); + TEST_EXPECTED_SUCCESS(CheckedNumeric<Dst>(DstLimits::min()).Abs()); + TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::min()) + -1); + TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::min()) - 1); + TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(DstLimits::min()) * 2); + TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) / 2); + TEST_EXPECTED_SUCCESS(CheckedNumeric<Dst>(DstLimits::min()).UnsignedAbs()); + TEST_EXPECTED_SUCCESS(CheckedNumeric<typename SignedIntegerForSize<Dst>::type>( + std::numeric_limits<typename SignedIntegerForSize<Dst>::type>::min()) + .UnsignedAbs()); + + // Modulus is legal only for integers. + TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>() % 1); + TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) % 1); + TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1) % 2); + TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(DstLimits::min()) % 2); + TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(DstLimits::max()) % 2); + // Test all the different modulus combinations. + TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) % CheckedNumeric<Dst>(1)); + TEST_EXPECTED_VALUE(0, 1 % CheckedNumeric<Dst>(1)); + TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) % 1); + CheckedNumeric<Dst> checked_dst = 1; + TEST_EXPECTED_VALUE(0, checked_dst %= 1); +} + +// Floating point arithmetic. +template <typename Dst> +void TestSpecializedArithmetic( + const char *dst, + int line, + typename std::enable_if<numeric_limits<Dst>::is_iec559, int>::type = 0) +{ + typedef numeric_limits<Dst> DstLimits; + TEST_EXPECTED_SUCCESS(-CheckedNumeric<Dst>(DstLimits::min())); + + TEST_EXPECTED_SUCCESS(CheckedNumeric<Dst>(DstLimits::min()).Abs()); + TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(-1).Abs()); + + TEST_EXPECTED_SUCCESS(CheckedNumeric<Dst>(DstLimits::min()) + -1); + TEST_EXPECTED_SUCCESS(CheckedNumeric<Dst>(DstLimits::max()) + 1); + TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(-DstLimits::max()) + -DstLimits::max()); + + TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::max()) - -DstLimits::max()); + TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(-DstLimits::max()) - DstLimits::max()); + + TEST_EXPECTED_SUCCESS(CheckedNumeric<Dst>(DstLimits::min()) * 2); + + TEST_EXPECTED_VALUE(-0.5, CheckedNumeric<Dst>(-1.0) / 2); + EXPECT_EQ(static_cast<Dst>(1.0), CheckedNumeric<Dst>(1.0).ValueFloating()); +} + +// Generic arithmetic tests. +template <typename Dst> +static void TestArithmetic(const char *dst, int line) +{ + typedef numeric_limits<Dst> DstLimits; + + EXPECT_EQ(true, CheckedNumeric<Dst>().IsValid()); + EXPECT_EQ( + false, + CheckedNumeric<Dst>(CheckedNumeric<Dst>(DstLimits::max()) * DstLimits::max()).IsValid()); + EXPECT_EQ(static_cast<Dst>(0), CheckedNumeric<Dst>().ValueOrDie()); + EXPECT_EQ(static_cast<Dst>(0), CheckedNumeric<Dst>().ValueOrDefault(1)); + EXPECT_EQ(static_cast<Dst>(1), + CheckedNumeric<Dst>(CheckedNumeric<Dst>(DstLimits::max()) * DstLimits::max()) + .ValueOrDefault(1)); + + // Test the operator combinations. + TEST_EXPECTED_VALUE(2, CheckedNumeric<Dst>(1) + CheckedNumeric<Dst>(1)); + TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) - CheckedNumeric<Dst>(1)); + TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1) * CheckedNumeric<Dst>(1)); + TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1) / CheckedNumeric<Dst>(1)); + TEST_EXPECTED_VALUE(2, 1 + CheckedNumeric<Dst>(1)); + TEST_EXPECTED_VALUE(0, 1 - CheckedNumeric<Dst>(1)); + TEST_EXPECTED_VALUE(1, 1 * CheckedNumeric<Dst>(1)); + TEST_EXPECTED_VALUE(1, 1 / CheckedNumeric<Dst>(1)); + TEST_EXPECTED_VALUE(2, CheckedNumeric<Dst>(1) + 1); + TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>(1) - 1); + TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1) * 1); + TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1) / 1); + CheckedNumeric<Dst> checked_dst = 1; + TEST_EXPECTED_VALUE(2, checked_dst += 1); + checked_dst = 1; + TEST_EXPECTED_VALUE(0, checked_dst -= 1); + checked_dst = 1; + TEST_EXPECTED_VALUE(1, checked_dst *= 1); + checked_dst = 1; + TEST_EXPECTED_VALUE(1, checked_dst /= 1); + + // Generic negation. + TEST_EXPECTED_VALUE(0, -CheckedNumeric<Dst>()); + TEST_EXPECTED_VALUE(-1, -CheckedNumeric<Dst>(1)); + TEST_EXPECTED_VALUE(1, -CheckedNumeric<Dst>(-1)); + TEST_EXPECTED_VALUE(static_cast<Dst>(DstLimits::max() * -1), + -CheckedNumeric<Dst>(DstLimits::max())); + + // Generic absolute value. + TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>().Abs()); + TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1).Abs()); + TEST_EXPECTED_VALUE(DstLimits::max(), CheckedNumeric<Dst>(DstLimits::max()).Abs()); + + // Generic addition. + TEST_EXPECTED_VALUE(1, (CheckedNumeric<Dst>() + 1)); + TEST_EXPECTED_VALUE(2, (CheckedNumeric<Dst>(1) + 1)); + TEST_EXPECTED_VALUE(0, (CheckedNumeric<Dst>(-1) + 1)); + TEST_EXPECTED_SUCCESS(CheckedNumeric<Dst>(DstLimits::min()) + 1); + TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::max()) + DstLimits::max()); + + // Generic subtraction. + TEST_EXPECTED_VALUE(-1, (CheckedNumeric<Dst>() - 1)); + TEST_EXPECTED_VALUE(0, (CheckedNumeric<Dst>(1) - 1)); + TEST_EXPECTED_VALUE(-2, (CheckedNumeric<Dst>(-1) - 1)); + TEST_EXPECTED_SUCCESS(CheckedNumeric<Dst>(DstLimits::max()) - 1); + + // Generic multiplication. + TEST_EXPECTED_VALUE(0, (CheckedNumeric<Dst>() * 1)); + TEST_EXPECTED_VALUE(1, (CheckedNumeric<Dst>(1) * 1)); + TEST_EXPECTED_VALUE(-2, (CheckedNumeric<Dst>(-1) * 2)); + TEST_EXPECTED_VALUE(0, (CheckedNumeric<Dst>(0) * 0)); + TEST_EXPECTED_VALUE(0, (CheckedNumeric<Dst>(-1) * 0)); + TEST_EXPECTED_VALUE(0, (CheckedNumeric<Dst>(0) * -1)); + TEST_EXPECTED_FAILURE(CheckedNumeric<Dst>(DstLimits::max()) * DstLimits::max()); + + // Generic division. + TEST_EXPECTED_VALUE(0, CheckedNumeric<Dst>() / 1); + TEST_EXPECTED_VALUE(1, CheckedNumeric<Dst>(1) / 1); + TEST_EXPECTED_VALUE(DstLimits::min() / 2, CheckedNumeric<Dst>(DstLimits::min()) / 2); + TEST_EXPECTED_VALUE(DstLimits::max() / 2, CheckedNumeric<Dst>(DstLimits::max()) / 2); + + TestSpecializedArithmetic<Dst>(dst, line); +} + +// Helper macro to wrap displaying the conversion types and line numbers. +#define TEST_ARITHMETIC(Dst) TestArithmetic<Dst>(#Dst, __LINE__) + +TEST(SafeNumerics, SignedIntegerMath) +{ + TEST_ARITHMETIC(int8_t); + TEST_ARITHMETIC(int); + TEST_ARITHMETIC(intptr_t); + TEST_ARITHMETIC(intmax_t); +} + +TEST(SafeNumerics, UnsignedIntegerMath) +{ + TEST_ARITHMETIC(uint8_t); + TEST_ARITHMETIC(unsigned int); + TEST_ARITHMETIC(uintptr_t); + TEST_ARITHMETIC(uintmax_t); +} + +TEST(SafeNumerics, FloatingPointMath) +{ + TEST_ARITHMETIC(float); + TEST_ARITHMETIC(double); +} + +// Enumerates the five different conversions types we need to test. +enum NumericConversionType +{ + SIGN_PRESERVING_VALUE_PRESERVING, + SIGN_PRESERVING_NARROW, + SIGN_TO_UNSIGN_WIDEN_OR_EQUAL, + SIGN_TO_UNSIGN_NARROW, + UNSIGN_TO_SIGN_NARROW_OR_EQUAL, +}; + +// Template covering the different conversion tests. +template <typename Dst, typename Src, NumericConversionType conversion> +struct TestNumericConversion +{ +}; + +// EXPECT_EQ wrappers providing specific detail on test failures. +#define TEST_EXPECTED_RANGE(expected, actual) \ + EXPECT_EQ(expected, base::internal::DstRangeRelationToSrcRange<Dst>(actual)) \ + << "Conversion test: " << src << " value " << actual << " to " << dst << " on line " \ + << line; + +template <typename Dst, typename Src> +struct TestNumericConversion<Dst, Src, SIGN_PRESERVING_VALUE_PRESERVING> +{ + static void Test(const char *dst, const char *src, int line) + { + typedef numeric_limits<Src> SrcLimits; + typedef numeric_limits<Dst> DstLimits; + // Integral to floating. + static_assert( + (DstLimits::is_iec559 && SrcLimits::is_integer) || + // Not floating to integral and... + (!(DstLimits::is_integer && SrcLimits::is_iec559) && + // Same sign, same numeric, source is narrower or same. + ((SrcLimits::is_signed == DstLimits::is_signed && sizeof(Dst) >= sizeof(Src)) || + // Or signed destination and source is smaller + (DstLimits::is_signed && sizeof(Dst) > sizeof(Src)))), + "Comparison must be sign preserving and value preserving"); + + const CheckedNumeric<Dst> checked_dst = SrcLimits::max(); + TEST_EXPECTED_SUCCESS(checked_dst); + if (MaxExponent<Dst>::value > MaxExponent<Src>::value) + { + if (MaxExponent<Dst>::value >= MaxExponent<Src>::value * 2 - 1) + { + // At least twice larger type. + TEST_EXPECTED_SUCCESS(SrcLimits::max() * checked_dst); + } + else + { // Larger, but not at least twice as large. + TEST_EXPECTED_FAILURE(SrcLimits::max() * checked_dst); + TEST_EXPECTED_SUCCESS(checked_dst + 1); + } + } + else + { // Same width type. + TEST_EXPECTED_FAILURE(checked_dst + 1); + } + + TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::max()); + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(1)); + if (SrcLimits::is_iec559) + { + TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::max() * static_cast<Src>(-1)); + TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::infinity()); + TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::infinity() * -1); + TEST_EXPECTED_RANGE(RANGE_INVALID, SrcLimits::quiet_NaN()); + } + else if (numeric_limits<Src>::is_signed) + { + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(-1)); + TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::min()); + } + } +}; + +template <typename Dst, typename Src> +struct TestNumericConversion<Dst, Src, SIGN_PRESERVING_NARROW> +{ + static void Test(const char *dst, const char *src, int line) + { + typedef numeric_limits<Src> SrcLimits; + typedef numeric_limits<Dst> DstLimits; + static_assert(SrcLimits::is_signed == DstLimits::is_signed, + "Destination and source sign must be the same"); + static_assert(sizeof(Dst) < sizeof(Src) || (DstLimits::is_integer && SrcLimits::is_iec559), + "Destination must be narrower than source"); + + const CheckedNumeric<Dst> checked_dst; + TEST_EXPECTED_FAILURE(checked_dst + SrcLimits::max()); + TEST_EXPECTED_VALUE(1, checked_dst + static_cast<Src>(1)); + TEST_EXPECTED_FAILURE(checked_dst - SrcLimits::max()); + + TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::max()); + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(1)); + if (SrcLimits::is_iec559) + { + TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::max() * -1); + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(-1)); + TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::infinity()); + TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::infinity() * -1); + TEST_EXPECTED_RANGE(RANGE_INVALID, SrcLimits::quiet_NaN()); + if (DstLimits::is_integer) + { + if (SrcLimits::digits < DstLimits::digits) + { + TEST_EXPECTED_RANGE(RANGE_OVERFLOW, static_cast<Src>(DstLimits::max())); + } + else + { + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(DstLimits::max())); + } + TEST_EXPECTED_RANGE(RANGE_VALID, + static_cast<Src>(GetMaxConvertibleToFloat<Src, Dst>())); + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(DstLimits::min())); + } + } + else if (SrcLimits::is_signed) + { + TEST_EXPECTED_VALUE(-1, checked_dst - static_cast<Src>(1)); + TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::min()); + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(-1)); + } + else + { + TEST_EXPECTED_FAILURE(checked_dst - static_cast<Src>(1)); + TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::min()); + } + } +}; + +template <typename Dst, typename Src> +struct TestNumericConversion<Dst, Src, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL> +{ + static void Test(const char *dst, const char *src, int line) + { + typedef numeric_limits<Src> SrcLimits; + typedef numeric_limits<Dst> DstLimits; + static_assert(sizeof(Dst) >= sizeof(Src), + "Destination must be equal or wider than source."); + static_assert(SrcLimits::is_signed, "Source must be signed"); + static_assert(!DstLimits::is_signed, "Destination must be unsigned"); + + const CheckedNumeric<Dst> checked_dst; + TEST_EXPECTED_VALUE(SrcLimits::max(), checked_dst + SrcLimits::max()); + TEST_EXPECTED_FAILURE(checked_dst + static_cast<Src>(-1)); + TEST_EXPECTED_FAILURE(checked_dst + -SrcLimits::max()); + + TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::min()); + TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::max()); + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(1)); + TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, static_cast<Src>(-1)); + } +}; + +template <typename Dst, typename Src> +struct TestNumericConversion<Dst, Src, SIGN_TO_UNSIGN_NARROW> +{ + static void Test(const char *dst, const char *src, int line) + { + typedef numeric_limits<Src> SrcLimits; + typedef numeric_limits<Dst> DstLimits; + static_assert( + (DstLimits::is_integer && SrcLimits::is_iec559) || (sizeof(Dst) < sizeof(Src)), + "Destination must be narrower than source."); + static_assert(SrcLimits::is_signed, "Source must be signed."); + static_assert(!DstLimits::is_signed, "Destination must be unsigned."); + + const CheckedNumeric<Dst> checked_dst; + TEST_EXPECTED_VALUE(1, checked_dst + static_cast<Src>(1)); + TEST_EXPECTED_FAILURE(checked_dst + SrcLimits::max()); + TEST_EXPECTED_FAILURE(checked_dst + static_cast<Src>(-1)); + TEST_EXPECTED_FAILURE(checked_dst + -SrcLimits::max()); + + TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::max()); + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(1)); + TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, static_cast<Src>(-1)); + if (SrcLimits::is_iec559) + { + TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::max() * -1); + TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::infinity()); + TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::infinity() * -1); + TEST_EXPECTED_RANGE(RANGE_INVALID, SrcLimits::quiet_NaN()); + if (DstLimits::is_integer) + { + if (SrcLimits::digits < DstLimits::digits) + { + TEST_EXPECTED_RANGE(RANGE_OVERFLOW, static_cast<Src>(DstLimits::max())); + } + else + { + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(DstLimits::max())); + } + TEST_EXPECTED_RANGE(RANGE_VALID, + static_cast<Src>(GetMaxConvertibleToFloat<Src, Dst>())); + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(DstLimits::min())); + } + } + else + { + TEST_EXPECTED_RANGE(RANGE_UNDERFLOW, SrcLimits::min()); + } + } +}; + +template <typename Dst, typename Src> +struct TestNumericConversion<Dst, Src, UNSIGN_TO_SIGN_NARROW_OR_EQUAL> +{ + static void Test(const char *dst, const char *src, int line) + { + typedef numeric_limits<Src> SrcLimits; + typedef numeric_limits<Dst> DstLimits; + static_assert(sizeof(Dst) <= sizeof(Src), + "Destination must be narrower or equal to source."); + static_assert(!SrcLimits::is_signed, "Source must be unsigned."); + static_assert(DstLimits::is_signed, "Destination must be signed."); + + const CheckedNumeric<Dst> checked_dst; + TEST_EXPECTED_VALUE(1, checked_dst + static_cast<Src>(1)); + TEST_EXPECTED_FAILURE(checked_dst + SrcLimits::max()); + TEST_EXPECTED_VALUE(SrcLimits::min(), checked_dst + SrcLimits::min()); + + TEST_EXPECTED_RANGE(RANGE_VALID, SrcLimits::min()); + TEST_EXPECTED_RANGE(RANGE_OVERFLOW, SrcLimits::max()); + TEST_EXPECTED_RANGE(RANGE_VALID, static_cast<Src>(1)); + } +}; + +// Helper macro to wrap displaying the conversion types and line numbers +#define TEST_NUMERIC_CONVERSION(d, s, t) TestNumericConversion<d, s, t>::Test(#d, #s, __LINE__) + +TEST(SafeNumerics, IntMinOperations) +{ + TEST_NUMERIC_CONVERSION(int8_t, int8_t, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(uint8_t, uint8_t, SIGN_PRESERVING_VALUE_PRESERVING); + + TEST_NUMERIC_CONVERSION(int8_t, int, SIGN_PRESERVING_NARROW); + TEST_NUMERIC_CONVERSION(uint8_t, unsigned int, SIGN_PRESERVING_NARROW); + TEST_NUMERIC_CONVERSION(int8_t, float, SIGN_PRESERVING_NARROW); + + TEST_NUMERIC_CONVERSION(uint8_t, int8_t, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL); + + TEST_NUMERIC_CONVERSION(uint8_t, int, SIGN_TO_UNSIGN_NARROW); + TEST_NUMERIC_CONVERSION(uint8_t, intmax_t, SIGN_TO_UNSIGN_NARROW); + TEST_NUMERIC_CONVERSION(uint8_t, float, SIGN_TO_UNSIGN_NARROW); + + TEST_NUMERIC_CONVERSION(int8_t, unsigned int, UNSIGN_TO_SIGN_NARROW_OR_EQUAL); + TEST_NUMERIC_CONVERSION(int8_t, uintmax_t, UNSIGN_TO_SIGN_NARROW_OR_EQUAL); +} + +TEST(SafeNumerics, IntOperations) +{ + TEST_NUMERIC_CONVERSION(int, int, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(unsigned int, unsigned int, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(int, int8_t, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(unsigned int, uint8_t, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(int, uint8_t, SIGN_PRESERVING_VALUE_PRESERVING); + + TEST_NUMERIC_CONVERSION(int, intmax_t, SIGN_PRESERVING_NARROW); + TEST_NUMERIC_CONVERSION(unsigned int, uintmax_t, SIGN_PRESERVING_NARROW); + TEST_NUMERIC_CONVERSION(int, float, SIGN_PRESERVING_NARROW); + TEST_NUMERIC_CONVERSION(int, double, SIGN_PRESERVING_NARROW); + + TEST_NUMERIC_CONVERSION(unsigned int, int, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL); + TEST_NUMERIC_CONVERSION(unsigned int, int8_t, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL); + + TEST_NUMERIC_CONVERSION(unsigned int, intmax_t, SIGN_TO_UNSIGN_NARROW); + TEST_NUMERIC_CONVERSION(unsigned int, float, SIGN_TO_UNSIGN_NARROW); + TEST_NUMERIC_CONVERSION(unsigned int, double, SIGN_TO_UNSIGN_NARROW); + + TEST_NUMERIC_CONVERSION(int, unsigned int, UNSIGN_TO_SIGN_NARROW_OR_EQUAL); + TEST_NUMERIC_CONVERSION(int, uintmax_t, UNSIGN_TO_SIGN_NARROW_OR_EQUAL); +} + +TEST(SafeNumerics, IntMaxOperations) +{ + TEST_NUMERIC_CONVERSION(intmax_t, intmax_t, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(uintmax_t, uintmax_t, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(intmax_t, int, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(uintmax_t, unsigned int, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(intmax_t, unsigned int, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(intmax_t, uint8_t, SIGN_PRESERVING_VALUE_PRESERVING); + + TEST_NUMERIC_CONVERSION(intmax_t, float, SIGN_PRESERVING_NARROW); + TEST_NUMERIC_CONVERSION(intmax_t, double, SIGN_PRESERVING_NARROW); + + TEST_NUMERIC_CONVERSION(uintmax_t, int, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL); + TEST_NUMERIC_CONVERSION(uintmax_t, int8_t, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL); + + TEST_NUMERIC_CONVERSION(uintmax_t, float, SIGN_TO_UNSIGN_NARROW); + TEST_NUMERIC_CONVERSION(uintmax_t, double, SIGN_TO_UNSIGN_NARROW); + + TEST_NUMERIC_CONVERSION(intmax_t, uintmax_t, UNSIGN_TO_SIGN_NARROW_OR_EQUAL); +} + +TEST(SafeNumerics, FloatOperations) +{ + TEST_NUMERIC_CONVERSION(float, intmax_t, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(float, uintmax_t, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(float, int, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(float, unsigned int, SIGN_PRESERVING_VALUE_PRESERVING); + + TEST_NUMERIC_CONVERSION(float, double, SIGN_PRESERVING_NARROW); +} + +TEST(SafeNumerics, DoubleOperations) +{ + TEST_NUMERIC_CONVERSION(double, intmax_t, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(double, uintmax_t, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(double, int, SIGN_PRESERVING_VALUE_PRESERVING); + TEST_NUMERIC_CONVERSION(double, unsigned int, SIGN_PRESERVING_VALUE_PRESERVING); +} + +TEST(SafeNumerics, SizeTOperations) +{ + TEST_NUMERIC_CONVERSION(size_t, int, SIGN_TO_UNSIGN_WIDEN_OR_EQUAL); + TEST_NUMERIC_CONVERSION(int, size_t, UNSIGN_TO_SIGN_NARROW_OR_EQUAL); +} + +TEST(SafeNumerics, CastTests) +{ +// MSVC catches and warns that we're forcing saturation in these tests. +// Since that's intentional, we need to shut this warning off. +#if defined(COMPILER_MSVC) +#pragma warning(disable : 4756) +#endif + + int small_positive = 1; + int small_negative = -1; + double double_small = 1.0; + double double_large = numeric_limits<double>::max(); + double double_infinity = numeric_limits<float>::infinity(); + double double_large_int = numeric_limits<int>::max(); + double double_small_int = numeric_limits<int>::min(); + + // Just test that the casts compile, since the other tests cover logic. + EXPECT_EQ(0, checked_cast<int>(static_cast<size_t>(0))); + EXPECT_EQ(0, strict_cast<int>(static_cast<char>(0))); + EXPECT_EQ(0, strict_cast<int>(static_cast<unsigned char>(0))); + EXPECT_EQ(0U, strict_cast<unsigned>(static_cast<unsigned char>(0))); + EXPECT_EQ(1ULL, static_cast<uint64_t>(StrictNumeric<size_t>(1U))); + EXPECT_EQ(1ULL, static_cast<uint64_t>(SizeT(1U))); + EXPECT_EQ(1U, static_cast<size_t>(StrictNumeric<unsigned>(1U))); + + EXPECT_TRUE(CheckedNumeric<uint64_t>(StrictNumeric<unsigned>(1U)).IsValid()); + EXPECT_TRUE(CheckedNumeric<int>(StrictNumeric<unsigned>(1U)).IsValid()); + EXPECT_FALSE(CheckedNumeric<unsigned>(StrictNumeric<int>(-1)).IsValid()); + + EXPECT_TRUE(IsValueNegative(-1)); + EXPECT_TRUE(IsValueNegative(numeric_limits<int>::min())); + EXPECT_FALSE(IsValueNegative(numeric_limits<unsigned>::min())); + EXPECT_TRUE(IsValueNegative(-numeric_limits<double>::max())); + EXPECT_FALSE(IsValueNegative(0)); + EXPECT_FALSE(IsValueNegative(1)); + EXPECT_FALSE(IsValueNegative(0u)); + EXPECT_FALSE(IsValueNegative(1u)); + EXPECT_FALSE(IsValueNegative(numeric_limits<int>::max())); + EXPECT_FALSE(IsValueNegative(numeric_limits<unsigned>::max())); + EXPECT_FALSE(IsValueNegative(numeric_limits<double>::max())); + + // These casts and coercions will fail to compile: + // EXPECT_EQ(0, strict_cast<int>(static_cast<size_t>(0))); + // EXPECT_EQ(0, strict_cast<size_t>(static_cast<int>(0))); + // EXPECT_EQ(1ULL, StrictNumeric<size_t>(1)); + // EXPECT_EQ(1, StrictNumeric<size_t>(1U)); + + // Test various saturation corner cases. + EXPECT_EQ(saturated_cast<int>(small_negative), static_cast<int>(small_negative)); + EXPECT_EQ(saturated_cast<int>(small_positive), static_cast<int>(small_positive)); + EXPECT_EQ(saturated_cast<unsigned>(small_negative), static_cast<unsigned>(0)); + EXPECT_EQ(saturated_cast<int>(double_small), static_cast<int>(double_small)); + EXPECT_EQ(saturated_cast<int>(double_large), numeric_limits<int>::max()); + EXPECT_EQ(saturated_cast<float>(double_large), double_infinity); + EXPECT_EQ(saturated_cast<float>(-double_large), -double_infinity); + EXPECT_EQ(numeric_limits<int>::min(), saturated_cast<int>(double_small_int)); + EXPECT_EQ(numeric_limits<int>::max(), saturated_cast<int>(double_large_int)); + + float not_a_number = + std::numeric_limits<float>::infinity() - std::numeric_limits<float>::infinity(); + EXPECT_TRUE(std::isnan(not_a_number)); + EXPECT_EQ(0, saturated_cast<int>(not_a_number)); +} + +#if GTEST_HAS_DEATH_TEST + +TEST(SafeNumerics, SaturatedCastChecks) +{ + float not_a_number = + std::numeric_limits<float>::infinity() - std::numeric_limits<float>::infinity(); + EXPECT_TRUE(std::isnan(not_a_number)); + EXPECT_DEATH((saturated_cast<int, base::SaturatedCastNaNBehaviorCheck>(not_a_number)), ""); +} + +#endif // GTEST_HAS_DEATH_TEST + +TEST(SafeNumerics, IsValueInRangeForNumericType) +{ + EXPECT_TRUE(IsValueInRangeForNumericType<uint32_t>(0)); + EXPECT_TRUE(IsValueInRangeForNumericType<uint32_t>(1)); + EXPECT_TRUE(IsValueInRangeForNumericType<uint32_t>(2)); + EXPECT_FALSE(IsValueInRangeForNumericType<uint32_t>(-1)); + EXPECT_TRUE(IsValueInRangeForNumericType<uint32_t>(0xffffffffu)); + EXPECT_TRUE(IsValueInRangeForNumericType<uint32_t>(UINT64_C(0xffffffff))); + EXPECT_FALSE(IsValueInRangeForNumericType<uint32_t>(UINT64_C(0x100000000))); + EXPECT_FALSE(IsValueInRangeForNumericType<uint32_t>(UINT64_C(0x100000001))); + EXPECT_FALSE(IsValueInRangeForNumericType<uint32_t>(std::numeric_limits<int32_t>::min())); + EXPECT_FALSE(IsValueInRangeForNumericType<uint32_t>(std::numeric_limits<int64_t>::min())); + + EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(0)); + EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(1)); + EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(2)); + EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(-1)); + EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(0x7fffffff)); + EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(0x7fffffffu)); + EXPECT_FALSE(IsValueInRangeForNumericType<int32_t>(0x80000000u)); + EXPECT_FALSE(IsValueInRangeForNumericType<int32_t>(0xffffffffu)); + EXPECT_FALSE(IsValueInRangeForNumericType<int32_t>(INT64_C(0x80000000))); + EXPECT_FALSE(IsValueInRangeForNumericType<int32_t>(INT64_C(0xffffffff))); + EXPECT_FALSE(IsValueInRangeForNumericType<int32_t>(INT64_C(0x100000000))); + EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>(std::numeric_limits<int32_t>::min())); + EXPECT_TRUE(IsValueInRangeForNumericType<int32_t>( + static_cast<int64_t>(std::numeric_limits<int32_t>::min()))); + EXPECT_FALSE(IsValueInRangeForNumericType<int32_t>( + static_cast<int64_t>(std::numeric_limits<int32_t>::min()) - 1)); + EXPECT_FALSE(IsValueInRangeForNumericType<int32_t>(std::numeric_limits<int64_t>::min())); + + EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(0)); + EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(1)); + EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(2)); + EXPECT_FALSE(IsValueInRangeForNumericType<uint64_t>(-1)); + EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(0xffffffffu)); + EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(UINT64_C(0xffffffff))); + EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(UINT64_C(0x100000000))); + EXPECT_TRUE(IsValueInRangeForNumericType<uint64_t>(UINT64_C(0x100000001))); + EXPECT_FALSE(IsValueInRangeForNumericType<uint64_t>(std::numeric_limits<int32_t>::min())); + EXPECT_FALSE(IsValueInRangeForNumericType<uint64_t>(INT64_C(-1))); + EXPECT_FALSE(IsValueInRangeForNumericType<uint64_t>(std::numeric_limits<int64_t>::min())); + + EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(0)); + EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(1)); + EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(2)); + EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(-1)); + EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(0x7fffffff)); + EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(0x7fffffffu)); + EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(0x80000000u)); + EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(0xffffffffu)); + EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(INT64_C(0x80000000))); + EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(INT64_C(0xffffffff))); + EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(INT64_C(0x100000000))); + EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(INT64_C(0x7fffffffffffffff))); + EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(UINT64_C(0x7fffffffffffffff))); + EXPECT_FALSE(IsValueInRangeForNumericType<int64_t>(UINT64_C(0x8000000000000000))); + EXPECT_FALSE(IsValueInRangeForNumericType<int64_t>(UINT64_C(0xffffffffffffffff))); + EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(std::numeric_limits<int32_t>::min())); + EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>( + static_cast<int64_t>(std::numeric_limits<int32_t>::min()))); + EXPECT_TRUE(IsValueInRangeForNumericType<int64_t>(std::numeric_limits<int64_t>::min())); +} + +TEST(SafeNumerics, CompoundNumericOperations) +{ + CheckedNumeric<int> a = 1; + CheckedNumeric<int> b = 2; + CheckedNumeric<int> c = 3; + CheckedNumeric<int> d = 4; + a += b; + EXPECT_EQ(3, a.ValueOrDie()); + a -= c; + EXPECT_EQ(0, a.ValueOrDie()); + d /= b; + EXPECT_EQ(2, d.ValueOrDie()); + d *= d; + EXPECT_EQ(4, d.ValueOrDie()); + + CheckedNumeric<int> too_large = std::numeric_limits<int>::max(); + EXPECT_TRUE(too_large.IsValid()); + too_large += d; + EXPECT_FALSE(too_large.IsValid()); + too_large -= d; + EXPECT_FALSE(too_large.IsValid()); + too_large /= d; + EXPECT_FALSE(too_large.IsValid()); +} diff --git a/gfx/angle/src/common/tls.cpp b/gfx/angle/src/common/tls.cpp new file mode 100755 index 000000000..cb1b32d32 --- /dev/null +++ b/gfx/angle/src/common/tls.cpp @@ -0,0 +1,156 @@ +// +// Copyright (c) 2014 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. +// + +// tls.cpp: Simple cross-platform interface for thread local storage. + +#include "common/tls.h" + +#include <assert.h> + +#ifdef ANGLE_ENABLE_WINDOWS_STORE +#include <vector> +#include <set> +#include <map> +#include <mutex> + +#include <wrl/client.h> +#include <wrl/async.h> +#include <Windows.System.Threading.h> + +using namespace std; +using namespace Windows::Foundation; +using namespace ABI::Windows::System::Threading; + +// Thread local storage for Windows Store support +typedef vector<void*> ThreadLocalData; + +static __declspec(thread) ThreadLocalData* currentThreadData = nullptr; +static set<ThreadLocalData*> allThreadData; +static DWORD nextTlsIndex = 0; +static vector<DWORD> freeTlsIndices; + +#endif + +TLSIndex CreateTLSIndex() +{ + TLSIndex index; + +#ifdef ANGLE_PLATFORM_WINDOWS +#ifdef ANGLE_ENABLE_WINDOWS_STORE + if (!freeTlsIndices.empty()) + { + DWORD result = freeTlsIndices.back(); + freeTlsIndices.pop_back(); + index = result; + } + else + { + index = nextTlsIndex++; + } +#else + index = TlsAlloc(); +#endif + +#elif defined(ANGLE_PLATFORM_POSIX) + // Create global pool key + if ((pthread_key_create(&index, NULL)) != 0) + { + index = TLS_INVALID_INDEX; + } +#endif + + assert(index != TLS_INVALID_INDEX && "CreateTLSIndex(): Unable to allocate Thread Local Storage"); + return index; +} + +bool DestroyTLSIndex(TLSIndex index) +{ + assert(index != TLS_INVALID_INDEX && "DestroyTLSIndex(): Invalid TLS Index"); + if (index == TLS_INVALID_INDEX) + { + return false; + } + +#ifdef ANGLE_PLATFORM_WINDOWS +#ifdef ANGLE_ENABLE_WINDOWS_STORE + assert(index < nextTlsIndex); + assert(find(freeTlsIndices.begin(), freeTlsIndices.end(), index) == freeTlsIndices.end()); + + freeTlsIndices.push_back(index); + for (auto threadData : allThreadData) + { + if (threadData->size() > index) + { + threadData->at(index) = nullptr; + } + } + return true; +#else + return (TlsFree(index) == TRUE); +#endif +#elif defined(ANGLE_PLATFORM_POSIX) + return (pthread_key_delete(index) == 0); +#endif +} + +bool SetTLSValue(TLSIndex index, void *value) +{ + assert(index != TLS_INVALID_INDEX && "SetTLSValue(): Invalid TLS Index"); + if (index == TLS_INVALID_INDEX) + { + return false; + } + +#ifdef ANGLE_PLATFORM_WINDOWS +#ifdef ANGLE_ENABLE_WINDOWS_STORE + ThreadLocalData* threadData = currentThreadData; + if (!threadData) + { + threadData = new ThreadLocalData(index + 1, nullptr); + allThreadData.insert(threadData); + currentThreadData = threadData; + } + else if (threadData->size() <= index) + { + threadData->resize(index + 1, nullptr); + } + + threadData->at(index) = value; + return true; +#else + return (TlsSetValue(index, value) == TRUE); +#endif +#elif defined(ANGLE_PLATFORM_POSIX) + return (pthread_setspecific(index, value) == 0); +#endif +} + +void *GetTLSValue(TLSIndex index) +{ + assert(index != TLS_INVALID_INDEX && "GetTLSValue(): Invalid TLS Index"); + if (index == TLS_INVALID_INDEX) + { + return NULL; + } + +#ifdef ANGLE_PLATFORM_WINDOWS +#ifdef ANGLE_ENABLE_WINDOWS_STORE + ThreadLocalData* threadData = currentThreadData; + if (threadData && threadData->size() > index) + { + return threadData->at(index); + } + else + { + return nullptr; + } +#else + return TlsGetValue(index); +#endif +#elif defined(ANGLE_PLATFORM_POSIX) + return pthread_getspecific(index); +#endif +} diff --git a/gfx/angle/src/common/tls.h b/gfx/angle/src/common/tls.h new file mode 100755 index 000000000..ca9e07ab7 --- /dev/null +++ b/gfx/angle/src/common/tls.h @@ -0,0 +1,46 @@ +// +// Copyright (c) 2014 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. +// + +// tls.h: Simple cross-platform interface for thread local storage. + +#ifndef COMMON_TLS_H_ +#define COMMON_TLS_H_ + +#include "common/platform.h" + +#ifdef ANGLE_PLATFORM_WINDOWS + +// TLS does not exist for Windows Store and needs to be emulated +# ifdef ANGLE_ENABLE_WINDOWS_STORE +# ifndef TLS_OUT_OF_INDEXES +# define TLS_OUT_OF_INDEXES static_cast<DWORD>(0xFFFFFFFF) +# endif +# ifndef CREATE_SUSPENDED +# define CREATE_SUSPENDED 0x00000004 +# endif +# endif + typedef DWORD TLSIndex; +# define TLS_INVALID_INDEX (TLS_OUT_OF_INDEXES) +#elif defined(ANGLE_PLATFORM_POSIX) +# include <pthread.h> +# include <semaphore.h> +# include <errno.h> + typedef pthread_key_t TLSIndex; +# define TLS_INVALID_INDEX (static_cast<TLSIndex>(-1)) +#else +# error Unsupported platform. +#endif + +// TODO(kbr): for POSIX platforms this will have to be changed to take +// in a destructor function pointer, to allow the thread-local storage +// to be properly deallocated upon thread exit. +TLSIndex CreateTLSIndex(); +bool DestroyTLSIndex(TLSIndex index); + +bool SetTLSValue(TLSIndex index, void *value); +void *GetTLSValue(TLSIndex index); + +#endif // COMMON_TLS_H_ diff --git a/gfx/angle/src/common/utilities.cpp b/gfx/angle/src/common/utilities.cpp new file mode 100755 index 000000000..89e383405 --- /dev/null +++ b/gfx/angle/src/common/utilities.cpp @@ -0,0 +1,843 @@ +// +// Copyright (c) 2002-2013 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. +// + +// utilities.cpp: Conversion functions and other utility routines. + +#include "common/utilities.h" +#include "common/mathutil.h" +#include "common/platform.h" + +#include <set> + +#if defined(ANGLE_ENABLE_WINDOWS_STORE) +# include <wrl.h> +# include <wrl/wrappers/corewrappers.h> +# include <windows.applicationmodel.core.h> +# include <windows.graphics.display.h> +#endif + +namespace +{ + +template <class IndexType> +gl::IndexRange ComputeTypedIndexRange(const IndexType *indices, + size_t count, + bool primitiveRestartEnabled, + GLuint primitiveRestartIndex) +{ + ASSERT(count > 0); + + IndexType minIndex = 0; + IndexType maxIndex = 0; + size_t nonPrimitiveRestartIndices = 0; + + if (primitiveRestartEnabled) + { + // Find the first non-primitive restart index to initialize the min and max values + size_t i = 0; + for (; i < count; i++) + { + if (indices[i] != primitiveRestartIndex) + { + minIndex = indices[i]; + maxIndex = indices[i]; + nonPrimitiveRestartIndices++; + break; + } + } + + // Loop over the rest of the indices + for (; i < count; i++) + { + if (indices[i] != primitiveRestartIndex) + { + if (minIndex > indices[i]) + { + minIndex = indices[i]; + } + if (maxIndex < indices[i]) + { + maxIndex = indices[i]; + } + nonPrimitiveRestartIndices++; + } + } + } + else + { + minIndex = indices[0]; + maxIndex = indices[0]; + nonPrimitiveRestartIndices = count; + + for (size_t i = 1; i < count; i++) + { + if (minIndex > indices[i]) + { + minIndex = indices[i]; + } + if (maxIndex < indices[i]) + { + maxIndex = indices[i]; + } + } + } + + return gl::IndexRange(static_cast<size_t>(minIndex), static_cast<size_t>(maxIndex), + nonPrimitiveRestartIndices); +} + +} // anonymous namespace + +namespace gl +{ + +int VariableComponentCount(GLenum type) +{ + return VariableRowCount(type) * VariableColumnCount(type); +} + +GLenum VariableComponentType(GLenum type) +{ + switch(type) + { + case GL_BOOL: + case GL_BOOL_VEC2: + case GL_BOOL_VEC3: + case GL_BOOL_VEC4: + return GL_BOOL; + case GL_FLOAT: + case GL_FLOAT_VEC2: + case GL_FLOAT_VEC3: + case GL_FLOAT_VEC4: + case GL_FLOAT_MAT2: + case GL_FLOAT_MAT3: + case GL_FLOAT_MAT4: + case GL_FLOAT_MAT2x3: + case GL_FLOAT_MAT3x2: + case GL_FLOAT_MAT2x4: + case GL_FLOAT_MAT4x2: + case GL_FLOAT_MAT3x4: + case GL_FLOAT_MAT4x3: + return GL_FLOAT; + case GL_INT: + case GL_SAMPLER_2D: + case GL_SAMPLER_3D: + case GL_SAMPLER_CUBE: + case GL_SAMPLER_2D_ARRAY: + case GL_SAMPLER_EXTERNAL_OES: + case GL_INT_SAMPLER_2D: + case GL_INT_SAMPLER_3D: + case GL_INT_SAMPLER_CUBE: + case GL_INT_SAMPLER_2D_ARRAY: + case GL_UNSIGNED_INT_SAMPLER_2D: + case GL_UNSIGNED_INT_SAMPLER_3D: + case GL_UNSIGNED_INT_SAMPLER_CUBE: + case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: + case GL_SAMPLER_2D_SHADOW: + case GL_SAMPLER_CUBE_SHADOW: + case GL_SAMPLER_2D_ARRAY_SHADOW: + case GL_INT_VEC2: + case GL_INT_VEC3: + case GL_INT_VEC4: + return GL_INT; + case GL_UNSIGNED_INT: + case GL_UNSIGNED_INT_VEC2: + case GL_UNSIGNED_INT_VEC3: + case GL_UNSIGNED_INT_VEC4: + return GL_UNSIGNED_INT; + default: + UNREACHABLE(); + } + + return GL_NONE; +} + +size_t VariableComponentSize(GLenum type) +{ + switch(type) + { + case GL_BOOL: return sizeof(GLint); + case GL_FLOAT: return sizeof(GLfloat); + case GL_INT: return sizeof(GLint); + case GL_UNSIGNED_INT: return sizeof(GLuint); + default: UNREACHABLE(); + } + + return 0; +} + +size_t VariableInternalSize(GLenum type) +{ + // Expanded to 4-element vectors + return VariableComponentSize(VariableComponentType(type)) * VariableRowCount(type) * 4; +} + +size_t VariableExternalSize(GLenum type) +{ + return VariableComponentSize(VariableComponentType(type)) * VariableComponentCount(type); +} + +GLenum VariableBoolVectorType(GLenum type) +{ + switch (type) + { + case GL_FLOAT: + case GL_INT: + case GL_UNSIGNED_INT: + return GL_BOOL; + case GL_FLOAT_VEC2: + case GL_INT_VEC2: + case GL_UNSIGNED_INT_VEC2: + return GL_BOOL_VEC2; + case GL_FLOAT_VEC3: + case GL_INT_VEC3: + case GL_UNSIGNED_INT_VEC3: + return GL_BOOL_VEC3; + case GL_FLOAT_VEC4: + case GL_INT_VEC4: + case GL_UNSIGNED_INT_VEC4: + return GL_BOOL_VEC4; + + default: + UNREACHABLE(); + return GL_NONE; + } +} + +int VariableRowCount(GLenum type) +{ + switch (type) + { + case GL_NONE: + case GL_STRUCT_ANGLEX: + return 0; + case GL_BOOL: + case GL_FLOAT: + case GL_INT: + case GL_UNSIGNED_INT: + case GL_BOOL_VEC2: + case GL_FLOAT_VEC2: + case GL_INT_VEC2: + case GL_UNSIGNED_INT_VEC2: + case GL_BOOL_VEC3: + case GL_FLOAT_VEC3: + case GL_INT_VEC3: + case GL_UNSIGNED_INT_VEC3: + case GL_BOOL_VEC4: + case GL_FLOAT_VEC4: + case GL_INT_VEC4: + case GL_UNSIGNED_INT_VEC4: + case GL_SAMPLER_2D: + case GL_SAMPLER_3D: + case GL_SAMPLER_CUBE: + case GL_SAMPLER_2D_ARRAY: + case GL_SAMPLER_EXTERNAL_OES: + case GL_SAMPLER_2D_RECT_ARB: + case GL_INT_SAMPLER_2D: + case GL_INT_SAMPLER_3D: + case GL_INT_SAMPLER_CUBE: + case GL_INT_SAMPLER_2D_ARRAY: + case GL_UNSIGNED_INT_SAMPLER_2D: + case GL_UNSIGNED_INT_SAMPLER_3D: + case GL_UNSIGNED_INT_SAMPLER_CUBE: + case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: + case GL_SAMPLER_2D_SHADOW: + case GL_SAMPLER_CUBE_SHADOW: + case GL_SAMPLER_2D_ARRAY_SHADOW: + case GL_IMAGE_2D: + case GL_INT_IMAGE_2D: + case GL_UNSIGNED_INT_IMAGE_2D: + case GL_IMAGE_2D_ARRAY: + case GL_INT_IMAGE_2D_ARRAY: + case GL_UNSIGNED_INT_IMAGE_2D_ARRAY: + case GL_IMAGE_3D: + case GL_INT_IMAGE_3D: + case GL_UNSIGNED_INT_IMAGE_3D: + case GL_IMAGE_CUBE: + case GL_INT_IMAGE_CUBE: + case GL_UNSIGNED_INT_IMAGE_CUBE: + return 1; + case GL_FLOAT_MAT2: + case GL_FLOAT_MAT3x2: + case GL_FLOAT_MAT4x2: + return 2; + case GL_FLOAT_MAT3: + case GL_FLOAT_MAT2x3: + case GL_FLOAT_MAT4x3: + return 3; + case GL_FLOAT_MAT4: + case GL_FLOAT_MAT2x4: + case GL_FLOAT_MAT3x4: + return 4; + default: + UNREACHABLE(); + } + + return 0; +} + +int VariableColumnCount(GLenum type) +{ + switch (type) + { + case GL_NONE: + case GL_STRUCT_ANGLEX: + return 0; + case GL_BOOL: + case GL_FLOAT: + case GL_INT: + case GL_UNSIGNED_INT: + case GL_SAMPLER_2D: + case GL_SAMPLER_3D: + case GL_SAMPLER_CUBE: + case GL_SAMPLER_2D_ARRAY: + case GL_INT_SAMPLER_2D: + case GL_INT_SAMPLER_3D: + case GL_INT_SAMPLER_CUBE: + case GL_INT_SAMPLER_2D_ARRAY: + case GL_SAMPLER_EXTERNAL_OES: + case GL_SAMPLER_2D_RECT_ARB: + case GL_UNSIGNED_INT_SAMPLER_2D: + case GL_UNSIGNED_INT_SAMPLER_3D: + case GL_UNSIGNED_INT_SAMPLER_CUBE: + case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: + case GL_SAMPLER_2D_SHADOW: + case GL_SAMPLER_CUBE_SHADOW: + case GL_SAMPLER_2D_ARRAY_SHADOW: + return 1; + case GL_BOOL_VEC2: + case GL_FLOAT_VEC2: + case GL_INT_VEC2: + case GL_UNSIGNED_INT_VEC2: + case GL_FLOAT_MAT2: + case GL_FLOAT_MAT2x3: + case GL_FLOAT_MAT2x4: + return 2; + case GL_BOOL_VEC3: + case GL_FLOAT_VEC3: + case GL_INT_VEC3: + case GL_UNSIGNED_INT_VEC3: + case GL_FLOAT_MAT3: + case GL_FLOAT_MAT3x2: + case GL_FLOAT_MAT3x4: + return 3; + case GL_BOOL_VEC4: + case GL_FLOAT_VEC4: + case GL_INT_VEC4: + case GL_UNSIGNED_INT_VEC4: + case GL_FLOAT_MAT4: + case GL_FLOAT_MAT4x2: + case GL_FLOAT_MAT4x3: + return 4; + default: + UNREACHABLE(); + } + + return 0; +} + +bool IsSamplerType(GLenum type) +{ + switch (type) + { + case GL_SAMPLER_2D: + case GL_SAMPLER_3D: + case GL_SAMPLER_CUBE: + case GL_SAMPLER_2D_ARRAY: + case GL_SAMPLER_EXTERNAL_OES: + case GL_INT_SAMPLER_2D: + case GL_INT_SAMPLER_3D: + case GL_INT_SAMPLER_CUBE: + case GL_INT_SAMPLER_2D_ARRAY: + case GL_UNSIGNED_INT_SAMPLER_2D: + case GL_UNSIGNED_INT_SAMPLER_3D: + case GL_UNSIGNED_INT_SAMPLER_CUBE: + case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: + case GL_SAMPLER_2D_SHADOW: + case GL_SAMPLER_CUBE_SHADOW: + case GL_SAMPLER_2D_ARRAY_SHADOW: + return true; + } + + return false; +} + +GLenum SamplerTypeToTextureType(GLenum samplerType) +{ + switch (samplerType) + { + case GL_SAMPLER_2D: + case GL_INT_SAMPLER_2D: + case GL_UNSIGNED_INT_SAMPLER_2D: + case GL_SAMPLER_2D_SHADOW: + return GL_TEXTURE_2D; + + case GL_SAMPLER_EXTERNAL_OES: + return GL_TEXTURE_EXTERNAL_OES; + + case GL_SAMPLER_CUBE: + case GL_INT_SAMPLER_CUBE: + case GL_UNSIGNED_INT_SAMPLER_CUBE: + case GL_SAMPLER_CUBE_SHADOW: + return GL_TEXTURE_CUBE_MAP; + + case GL_SAMPLER_2D_ARRAY: + case GL_INT_SAMPLER_2D_ARRAY: + case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: + case GL_SAMPLER_2D_ARRAY_SHADOW: + return GL_TEXTURE_2D_ARRAY; + + case GL_SAMPLER_3D: + case GL_INT_SAMPLER_3D: + case GL_UNSIGNED_INT_SAMPLER_3D: + return GL_TEXTURE_3D; + + default: + UNREACHABLE(); + return 0; + } +} + +bool IsMatrixType(GLenum type) +{ + return VariableRowCount(type) > 1; +} + +GLenum TransposeMatrixType(GLenum type) +{ + if (!IsMatrixType(type)) + { + return type; + } + + switch (type) + { + case GL_FLOAT_MAT2: return GL_FLOAT_MAT2; + case GL_FLOAT_MAT3: return GL_FLOAT_MAT3; + case GL_FLOAT_MAT4: return GL_FLOAT_MAT4; + case GL_FLOAT_MAT2x3: return GL_FLOAT_MAT3x2; + case GL_FLOAT_MAT3x2: return GL_FLOAT_MAT2x3; + case GL_FLOAT_MAT2x4: return GL_FLOAT_MAT4x2; + case GL_FLOAT_MAT4x2: return GL_FLOAT_MAT2x4; + case GL_FLOAT_MAT3x4: return GL_FLOAT_MAT4x3; + case GL_FLOAT_MAT4x3: return GL_FLOAT_MAT3x4; + default: UNREACHABLE(); return GL_NONE; + } +} + +int MatrixRegisterCount(GLenum type, bool isRowMajorMatrix) +{ + ASSERT(IsMatrixType(type)); + return isRowMajorMatrix ? VariableRowCount(type) : VariableColumnCount(type); +} + +int MatrixComponentCount(GLenum type, bool isRowMajorMatrix) +{ + ASSERT(IsMatrixType(type)); + return isRowMajorMatrix ? VariableColumnCount(type) : VariableRowCount(type); +} + +int VariableRegisterCount(GLenum type) +{ + return IsMatrixType(type) ? VariableColumnCount(type) : 1; +} + +int AllocateFirstFreeBits(unsigned int *bits, unsigned int allocationSize, unsigned int bitsSize) +{ + ASSERT(allocationSize <= bitsSize); + + unsigned int mask = std::numeric_limits<unsigned int>::max() >> (std::numeric_limits<unsigned int>::digits - allocationSize); + + for (unsigned int i = 0; i < bitsSize - allocationSize + 1; i++) + { + if ((*bits & mask) == 0) + { + *bits |= mask; + return i; + } + + mask <<= 1; + } + + return -1; +} + +static_assert(GL_TEXTURE_CUBE_MAP_NEGATIVE_X - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 1, "Unexpected GL cube map enum value."); +static_assert(GL_TEXTURE_CUBE_MAP_POSITIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 2, "Unexpected GL cube map enum value."); +static_assert(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 3, "Unexpected GL cube map enum value."); +static_assert(GL_TEXTURE_CUBE_MAP_POSITIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 4, "Unexpected GL cube map enum value."); +static_assert(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - GL_TEXTURE_CUBE_MAP_POSITIVE_X == 5, "Unexpected GL cube map enum value."); + +bool IsCubeMapTextureTarget(GLenum target) +{ + return (target >= FirstCubeMapTextureTarget && target <= LastCubeMapTextureTarget); +} + +size_t CubeMapTextureTargetToLayerIndex(GLenum target) +{ + ASSERT(IsCubeMapTextureTarget(target)); + return target - static_cast<size_t>(FirstCubeMapTextureTarget); +} + +GLenum LayerIndexToCubeMapTextureTarget(size_t index) +{ + ASSERT(index <= (LastCubeMapTextureTarget - FirstCubeMapTextureTarget)); + return FirstCubeMapTextureTarget + static_cast<GLenum>(index); +} + +IndexRange ComputeIndexRange(GLenum indexType, + const GLvoid *indices, + size_t count, + bool primitiveRestartEnabled) +{ + switch (indexType) + { + case GL_UNSIGNED_BYTE: + return ComputeTypedIndexRange(static_cast<const GLubyte *>(indices), count, + primitiveRestartEnabled, + GetPrimitiveRestartIndex(indexType)); + case GL_UNSIGNED_SHORT: + return ComputeTypedIndexRange(static_cast<const GLushort *>(indices), count, + primitiveRestartEnabled, + GetPrimitiveRestartIndex(indexType)); + case GL_UNSIGNED_INT: + return ComputeTypedIndexRange(static_cast<const GLuint *>(indices), count, + primitiveRestartEnabled, + GetPrimitiveRestartIndex(indexType)); + default: + UNREACHABLE(); + return IndexRange(); + } +} + +GLuint GetPrimitiveRestartIndex(GLenum indexType) +{ + switch (indexType) + { + case GL_UNSIGNED_BYTE: + return 0xFF; + case GL_UNSIGNED_SHORT: + return 0xFFFF; + case GL_UNSIGNED_INT: + return 0xFFFFFFFF; + default: + UNREACHABLE(); + return 0; + } +} + +bool IsTriangleMode(GLenum drawMode) +{ + switch (drawMode) + { + case GL_TRIANGLES: + case GL_TRIANGLE_FAN: + case GL_TRIANGLE_STRIP: + return true; + case GL_POINTS: + case GL_LINES: + case GL_LINE_LOOP: + case GL_LINE_STRIP: + return false; + default: UNREACHABLE(); + } + + return false; +} + +// [OpenGL ES SL 3.00.4] Section 11 p. 120 +// Vertex Outs/Fragment Ins packing priorities +int VariableSortOrder(GLenum type) +{ + switch (type) + { + // 1. Arrays of mat4 and mat4 + // Non-square matrices of type matCxR consume the same space as a square + // matrix of type matN where N is the greater of C and R + case GL_FLOAT_MAT4: + case GL_FLOAT_MAT2x4: + case GL_FLOAT_MAT3x4: + case GL_FLOAT_MAT4x2: + case GL_FLOAT_MAT4x3: + return 0; + + // 2. Arrays of mat2 and mat2 (since they occupy full rows) + case GL_FLOAT_MAT2: + return 1; + + // 3. Arrays of vec4 and vec4 + case GL_FLOAT_VEC4: + case GL_INT_VEC4: + case GL_BOOL_VEC4: + case GL_UNSIGNED_INT_VEC4: + return 2; + + // 4. Arrays of mat3 and mat3 + case GL_FLOAT_MAT3: + case GL_FLOAT_MAT2x3: + case GL_FLOAT_MAT3x2: + return 3; + + // 5. Arrays of vec3 and vec3 + case GL_FLOAT_VEC3: + case GL_INT_VEC3: + case GL_BOOL_VEC3: + case GL_UNSIGNED_INT_VEC3: + return 4; + + // 6. Arrays of vec2 and vec2 + case GL_FLOAT_VEC2: + case GL_INT_VEC2: + case GL_BOOL_VEC2: + case GL_UNSIGNED_INT_VEC2: + return 5; + + // 7. Single component types + case GL_FLOAT: + case GL_INT: + case GL_BOOL: + case GL_UNSIGNED_INT: + case GL_SAMPLER_2D: + case GL_SAMPLER_CUBE: + case GL_SAMPLER_EXTERNAL_OES: + case GL_SAMPLER_2D_RECT_ARB: + case GL_SAMPLER_2D_ARRAY: + case GL_SAMPLER_3D: + case GL_INT_SAMPLER_2D: + case GL_INT_SAMPLER_3D: + case GL_INT_SAMPLER_CUBE: + case GL_INT_SAMPLER_2D_ARRAY: + case GL_UNSIGNED_INT_SAMPLER_2D: + case GL_UNSIGNED_INT_SAMPLER_3D: + case GL_UNSIGNED_INT_SAMPLER_CUBE: + case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: + case GL_SAMPLER_2D_SHADOW: + case GL_SAMPLER_2D_ARRAY_SHADOW: + case GL_SAMPLER_CUBE_SHADOW: + return 6; + + default: + UNREACHABLE(); + return 0; + } +} + +std::string ParseUniformName(const std::string &name, size_t *outSubscript) +{ + // Strip any trailing array operator and retrieve the subscript + size_t open = name.find_last_of('['); + size_t close = name.find_last_of(']'); + bool hasIndex = (open != std::string::npos) && (close == name.length() - 1); + if (!hasIndex) + { + if (outSubscript) + { + *outSubscript = GL_INVALID_INDEX; + } + return name; + } + + if (outSubscript) + { + int index = atoi(name.substr(open + 1).c_str()); + if (index >= 0) + { + *outSubscript = index; + } + else + { + *outSubscript = GL_INVALID_INDEX; + } + } + + return name.substr(0, open); +} + +template <> +GLuint ConvertToGLuint(GLfloat param) +{ + return uiround<GLuint>(param); +} + +template <> +GLint ConvertToGLint(GLfloat param) +{ + return iround<GLint>(param); +} + +template <> +GLint ConvertFromGLfloat(GLfloat param) +{ + return iround<GLint>(param); +} +template <> +GLuint ConvertFromGLfloat(GLfloat param) +{ + return uiround<GLuint>(param); +} + +unsigned int ParseAndStripArrayIndex(std::string *name) +{ + unsigned int subscript = GL_INVALID_INDEX; + + // Strip any trailing array operator and retrieve the subscript + size_t open = name->find_last_of('['); + size_t close = name->find_last_of(']'); + if (open != std::string::npos && close == name->length() - 1) + { + subscript = atoi(name->c_str() + open + 1); + name->erase(open); + } + + return subscript; +} + +} // namespace gl + +namespace egl +{ +static_assert(EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR - EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR == 1, + "Unexpected EGL cube map enum value."); +static_assert(EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR - EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR == 2, + "Unexpected EGL cube map enum value."); +static_assert(EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR - EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR == 3, + "Unexpected EGL cube map enum value."); +static_assert(EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR - EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR == 4, + "Unexpected EGL cube map enum value."); +static_assert(EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR - EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR == 5, + "Unexpected EGL cube map enum value."); + +bool IsCubeMapTextureTarget(EGLenum target) +{ + return (target >= FirstCubeMapTextureTarget && target <= LastCubeMapTextureTarget); +} + +size_t CubeMapTextureTargetToLayerIndex(EGLenum target) +{ + ASSERT(IsCubeMapTextureTarget(target)); + return target - static_cast<size_t>(FirstCubeMapTextureTarget); +} + +EGLenum LayerIndexToCubeMapTextureTarget(size_t index) +{ + ASSERT(index <= (LastCubeMapTextureTarget - FirstCubeMapTextureTarget)); + return FirstCubeMapTextureTarget + static_cast<GLenum>(index); +} + +bool IsTextureTarget(EGLenum target) +{ + switch (target) + { + case EGL_GL_TEXTURE_2D_KHR: + case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR: + case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR: + case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR: + case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR: + case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR: + case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR: + case EGL_GL_TEXTURE_3D_KHR: + return true; + + default: + return false; + } +} + +bool IsRenderbufferTarget(EGLenum target) +{ + return target == EGL_GL_RENDERBUFFER_KHR; +} +} // namespace egl + +namespace egl_gl +{ +GLenum EGLCubeMapTargetToGLCubeMapTarget(EGLenum eglTarget) +{ + ASSERT(egl::IsCubeMapTextureTarget(eglTarget)); + return gl::LayerIndexToCubeMapTextureTarget(egl::CubeMapTextureTargetToLayerIndex(eglTarget)); +} + +GLenum EGLImageTargetToGLTextureTarget(EGLenum eglTarget) +{ + switch (eglTarget) + { + case EGL_GL_TEXTURE_2D_KHR: + return GL_TEXTURE_2D; + + case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR: + case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR: + case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR: + case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR: + case EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR: + case EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR: + return EGLCubeMapTargetToGLCubeMapTarget(eglTarget); + + case EGL_GL_TEXTURE_3D_KHR: + return GL_TEXTURE_3D; + + default: + UNREACHABLE(); + return GL_NONE; + } +} + +GLuint EGLClientBufferToGLObjectHandle(EGLClientBuffer buffer) +{ + return static_cast<GLuint>(reinterpret_cast<uintptr_t>(buffer)); +} +} // namespace egl_gl + +#if !defined(ANGLE_ENABLE_WINDOWS_STORE) +std::string getTempPath() +{ +#ifdef ANGLE_PLATFORM_WINDOWS + char path[MAX_PATH]; + DWORD pathLen = GetTempPathA(sizeof(path) / sizeof(path[0]), path); + if (pathLen == 0) + { + UNREACHABLE(); + return std::string(); + } + + UINT unique = GetTempFileNameA(path, "sh", 0, path); + if (unique == 0) + { + UNREACHABLE(); + return std::string(); + } + + return path; +#else + UNIMPLEMENTED(); + return ""; +#endif +} + +void writeFile(const char* path, const void* content, size_t size) +{ + FILE* file = fopen(path, "w"); + if (!file) + { + UNREACHABLE(); + return; + } + + fwrite(content, sizeof(char), size, file); + fclose(file); +} +#endif // !ANGLE_ENABLE_WINDOWS_STORE + +#if defined (ANGLE_PLATFORM_WINDOWS) + +// Causes the thread to relinquish the remainder of its time slice to any +// other thread that is ready to run.If there are no other threads ready +// to run, the function returns immediately, and the thread continues execution. +void ScheduleYield() +{ + Sleep(0); +} + +#endif diff --git a/gfx/angle/src/common/utilities.h b/gfx/angle/src/common/utilities.h new file mode 100755 index 000000000..16d6560a7 --- /dev/null +++ b/gfx/angle/src/common/utilities.h @@ -0,0 +1,172 @@ +// +// Copyright (c) 2002-2013 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. +// + +// utilities.h: Conversion functions and other utility routines. + +#ifndef COMMON_UTILITIES_H_ +#define COMMON_UTILITIES_H_ + +#include <EGL/egl.h> +#include <EGL/eglext.h> + +#include "angle_gl.h" +#include <string> +#include <math.h> + +#include "common/mathutil.h" + +namespace gl +{ + +int VariableComponentCount(GLenum type); +GLenum VariableComponentType(GLenum type); +size_t VariableComponentSize(GLenum type); +size_t VariableInternalSize(GLenum type); +size_t VariableExternalSize(GLenum type); +GLenum VariableBoolVectorType(GLenum type); +int VariableRowCount(GLenum type); +int VariableColumnCount(GLenum type); +bool IsSamplerType(GLenum type); +GLenum SamplerTypeToTextureType(GLenum samplerType); +bool IsMatrixType(GLenum type); +GLenum TransposeMatrixType(GLenum type); +int VariableRegisterCount(GLenum type); +int MatrixRegisterCount(GLenum type, bool isRowMajorMatrix); +int MatrixComponentCount(GLenum type, bool isRowMajorMatrix); +int VariableSortOrder(GLenum type); + +int AllocateFirstFreeBits(unsigned int *bits, unsigned int allocationSize, unsigned int bitsSize); + +static const GLenum FirstCubeMapTextureTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X; +static const GLenum LastCubeMapTextureTarget = GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; +bool IsCubeMapTextureTarget(GLenum target); +size_t CubeMapTextureTargetToLayerIndex(GLenum target); +GLenum LayerIndexToCubeMapTextureTarget(size_t index); + +// Parse the base uniform name and array index. Returns the base name of the uniform. outSubscript is +// set to GL_INVALID_INDEX if the provided name is not an array or the array index is invalid. +std::string ParseUniformName(const std::string &name, size_t *outSubscript); + +// Find the range of index values in the provided indices pointer. Primitive restart indices are +// only counted in the range if primitive restart is disabled. +IndexRange ComputeIndexRange(GLenum indexType, + const GLvoid *indices, + size_t count, + bool primitiveRestartEnabled); + +// Get the primitive restart index value for the given index type. +GLuint GetPrimitiveRestartIndex(GLenum indexType); + +bool IsTriangleMode(GLenum drawMode); + +// [OpenGL ES 3.0.2] Section 2.3.1 page 14 +// Data Conversion For State-Setting Commands +// Floating-point values are rounded to the nearest integer, instead of truncated, as done by static_cast. +template <typename outT> outT iround(GLfloat value) { return static_cast<outT>(value > 0.0f ? floor(value + 0.5f) : ceil(value - 0.5f)); } +template <typename outT> outT uiround(GLfloat value) { return static_cast<outT>(value + 0.5f); } + +// Helper for converting arbitrary GL types to other GL types used in queries and state setting +template <typename ParamType> +GLuint ConvertToGLuint(ParamType param) +{ + return static_cast<GLuint>(param); +} +template <> +GLuint ConvertToGLuint(GLfloat param); + +template <typename ParamType> +GLint ConvertToGLint(ParamType param) +{ + return static_cast<GLint>(param); +} +template <> +GLint ConvertToGLint(GLfloat param); + +// Same conversion as uint +template <typename ParamType> +GLenum ConvertToGLenum(ParamType param) +{ + return static_cast<GLenum>(ConvertToGLuint(param)); +} + +template <typename ParamType> +GLfloat ConvertToGLfloat(ParamType param) +{ + return static_cast<GLfloat>(param); +} + +template <typename ParamType> +ParamType ConvertFromGLfloat(GLfloat param) +{ + return static_cast<ParamType>(param); +} +template <> +GLint ConvertFromGLfloat(GLfloat param); +template <> +GLuint ConvertFromGLfloat(GLfloat param); + +template <typename ParamType> +ParamType ConvertFromGLenum(GLenum param) +{ + return static_cast<ParamType>(param); +} + +template <typename ParamType> +ParamType ConvertFromGLuint(GLuint param) +{ + return static_cast<ParamType>(param); +} + +template <typename ParamType> +ParamType ConvertFromGLint(GLint param) +{ + return static_cast<ParamType>(param); +} + +template <typename ParamType> +ParamType ConvertFromGLboolean(GLboolean param) +{ + return static_cast<ParamType>(param ? GL_TRUE : GL_FALSE); +} + +template <typename ParamType> +ParamType ConvertFromGLint64(GLint64 param) +{ + return clampCast<ParamType>(param); +} + +unsigned int ParseAndStripArrayIndex(std::string *name); + +} // namespace gl + +namespace egl +{ +static const EGLenum FirstCubeMapTextureTarget = EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR; +static const EGLenum LastCubeMapTextureTarget = EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR; +bool IsCubeMapTextureTarget(EGLenum target); +size_t CubeMapTextureTargetToLayerIndex(EGLenum target); +EGLenum LayerIndexToCubeMapTextureTarget(size_t index); +bool IsTextureTarget(EGLenum target); +bool IsRenderbufferTarget(EGLenum target); +} + +namespace egl_gl +{ +GLenum EGLCubeMapTargetToGLCubeMapTarget(EGLenum eglTarget); +GLenum EGLImageTargetToGLTextureTarget(EGLenum eglTarget); +GLuint EGLClientBufferToGLObjectHandle(EGLClientBuffer buffer); +} + +#if !defined(ANGLE_ENABLE_WINDOWS_STORE) +std::string getTempPath(); +void writeFile(const char* path, const void* data, size_t size); +#endif + +#if defined (ANGLE_PLATFORM_WINDOWS) +void ScheduleYield(); +#endif + +#endif // COMMON_UTILITIES_H_ diff --git a/gfx/angle/src/common/utilities_unittest.cpp b/gfx/angle/src/common/utilities_unittest.cpp new file mode 100755 index 000000000..447bfc6eb --- /dev/null +++ b/gfx/angle/src/common/utilities_unittest.cpp @@ -0,0 +1,55 @@ +// +// Copyright (c) 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. + +// utilities_unittest.cpp: Unit tests for ANGLE's GL utility functions + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +#include "common/utilities.h" + +namespace +{ + +TEST(ParseUniformName, ArrayIndex) +{ + size_t index; + EXPECT_EQ("foo", gl::ParseUniformName("foo[123]", &index)); + EXPECT_EQ(123u, index); + + EXPECT_EQ("bar", gl::ParseUniformName("bar[0]", &index)); + EXPECT_EQ(0u, index); +} + +TEST(ParseUniformName, NegativeArrayIndex) +{ + size_t index; + EXPECT_EQ("foo", gl::ParseUniformName("foo[-1]", &index)); + EXPECT_EQ(GL_INVALID_INDEX, index); +} + +TEST(ParseUniformName, NoArrayIndex) +{ + size_t index; + EXPECT_EQ("foo", gl::ParseUniformName("foo", &index)); + EXPECT_EQ(GL_INVALID_INDEX, index); +} + +TEST(ParseUniformName, NULLArrayIndex) +{ + EXPECT_EQ("foo", gl::ParseUniformName("foo[10]", nullptr)); +} + +TEST(ParseUniformName, TrailingWhitespace) +{ + size_t index; + EXPECT_EQ("foo ", gl::ParseUniformName("foo ", &index)); + EXPECT_EQ(GL_INVALID_INDEX, index); + + EXPECT_EQ("foo[10] ", gl::ParseUniformName("foo[10] ", &index)); + EXPECT_EQ(GL_INVALID_INDEX, index); +} + +} diff --git a/gfx/angle/src/common/version.h b/gfx/angle/src/common/version.h new file mode 100755 index 000000000..b653ae39c --- /dev/null +++ b/gfx/angle/src/common/version.h @@ -0,0 +1,28 @@ +// +// Copyright (c) 2014 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. +// + +#ifndef COMMON_VERSION_H_ +#define COMMON_VERSION_H_ + +#include "commit.h" + +#define ANGLE_MAJOR_VERSION 2 +#define ANGLE_MINOR_VERSION 1 + +#ifndef ANGLE_REVISION +#define ANGLE_REVISION 0 +#endif + +#define ANGLE_STRINGIFY(x) #x +#define ANGLE_MACRO_STRINGIFY(x) ANGLE_STRINGIFY(x) + +#define ANGLE_VERSION_STRING \ + ANGLE_MACRO_STRINGIFY(ANGLE_MAJOR_VERSION) "." \ + ANGLE_MACRO_STRINGIFY(ANGLE_MINOR_VERSION) "." \ + ANGLE_MACRO_STRINGIFY(ANGLE_REVISION) "." \ + ANGLE_COMMIT_HASH + +#endif // COMMON_VERSION_H_ |