Edit

kc3-lang/angle/src/common/mathutil_unittest.cpp

Branch :

  • Show log

    Commit

  • Author : Olli Etuaho
    Date : 2017-01-21 10:51:27
    Hash : 9250cb24
    Message : Add ESSL 3.10 integer math built-ins This adds built-ins found in ESSL 3.10 section 8.8 Integer functions. This includes constant folding support for functions that may be constant folded, and support for both GLSL and HLSL output. In HLSL several of the functions need to be emulated. The precision qualification for the return value of some of these functions is determined by special rules, that are now part of type promotion for TIntermUnary nodes and determining the type of TIntermAggregate nodes. BUG=angleproject:1730 TEST=angle_unittests TEST=dEQP-GLES31.functional.shaders.builtin_functions.integer.* Change-Id: Ib0056c17671c42b6496c2f0ef059b99f8f25c122 Reviewed-on: https://chromium-review.googlesource.com/431310 Commit-Queue: Olli Etuaho <oetuaho@nvidia.com> Reviewed-by: Jamie Madill <jmadill@chromium.org>

  • src/common/mathutil_unittest.cpp
  • //
    // 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());
    }
    
    // Test BitfieldReverse which reverses the order of the bits in an integer.
    TEST(MathUtilTest, BitfieldReverse)
    {
        EXPECT_EQ(0u, gl::BitfieldReverse(0u));
        EXPECT_EQ(0x80000000u, gl::BitfieldReverse(1u));
        EXPECT_EQ(0x1u, gl::BitfieldReverse(0x80000000u));
        uint32_t bits     = (1u << 4u) | (1u << 7u);
        uint32_t reversed = (1u << (31u - 4u)) | (1u << (31u - 7u));
        EXPECT_EQ(reversed, gl::BitfieldReverse(bits));
    }
    
    // Test BitCount, which counts 1 bits in an integer.
    TEST(MathUtilTest, BitCount)
    {
        EXPECT_EQ(0, gl::BitCount(0u));
        EXPECT_EQ(32, gl::BitCount(0xFFFFFFFFu));
        EXPECT_EQ(10, gl::BitCount(0x17103121u));
    }
    
    // Test ScanForward, which scans for the least significant 1 bit from a non-zero integer.
    TEST(MathUtilTest, ScanForward)
    {
        EXPECT_EQ(0ul, gl::ScanForward(1ul));
        EXPECT_EQ(16ul, gl::ScanForward(0x80010000ul));
        EXPECT_EQ(31ul, gl::ScanForward(0x80000000ul));
    }
    
    // Test ScanReverse, which scans for the most significant 1 bit from a non-zero integer.
    TEST(MathUtilTest, ScanReverse)
    {
        EXPECT_EQ(0ul, gl::ScanReverse(1ul));
        EXPECT_EQ(16ul, gl::ScanReverse(0x00010030ul));
        EXPECT_EQ(31ul, gl::ScanReverse(0x80000000ul));
    }
    
    // Test FindLSB, which finds the least significant 1 bit.
    TEST(MathUtilTest, FindLSB)
    {
        EXPECT_EQ(-1, gl::FindLSB(0u));
        EXPECT_EQ(0, gl::FindLSB(1u));
        EXPECT_EQ(16, gl::FindLSB(0x80010000u));
        EXPECT_EQ(31, gl::FindLSB(0x80000000u));
    }
    
    // Test FindMSB, which finds the most significant 1 bit.
    TEST(MathUtilTest, FindMSB)
    {
        EXPECT_EQ(-1, gl::FindMSB(0u));
        EXPECT_EQ(0, gl::FindMSB(1u));
        EXPECT_EQ(16, gl::FindMSB(0x00010030u));
        EXPECT_EQ(31, gl::FindMSB(0x80000000u));
    }
    
    }  // anonymous namespace