• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2015 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // mathutil_unittest:
7 //   Unit tests for the utils defined in mathutil.h
8 //
9 
10 #include "mathutil.h"
11 
12 #include <gtest/gtest.h>
13 
14 using namespace gl;
15 
16 namespace
17 {
18 
19 // Test the correctness of packSnorm2x16 and unpackSnorm2x16 functions.
20 // For floats f1 and f2, unpackSnorm2x16(packSnorm2x16(f1, f2)) should be same as f1 and f2.
TEST(MathUtilTest,packAndUnpackSnorm2x16)21 TEST(MathUtilTest, packAndUnpackSnorm2x16)
22 {
23     const float input[8][2] = {
24         {0.0f, 0.0f},    {1.0f, 1.0f},          {-1.0f, 1.0f},           {-1.0f, -1.0f},
25         {0.875f, 0.75f}, {0.00392f, -0.99215f}, {-0.000675f, 0.004954f}, {-0.6937f, -0.02146f}};
26     const float floatFaultTolerance = 0.0001f;
27     float outputVal1, outputVal2;
28 
29     for (size_t i = 0; i < 8; i++)
30     {
31         unpackSnorm2x16(packSnorm2x16(input[i][0], input[i][1]), &outputVal1, &outputVal2);
32         EXPECT_NEAR(input[i][0], outputVal1, floatFaultTolerance);
33         EXPECT_NEAR(input[i][1], outputVal2, floatFaultTolerance);
34     }
35 }
36 
37 // Test the correctness of packSnorm2x16 and unpackSnorm2x16 functions with infinity values,
38 // result should be clamped to [-1, 1].
TEST(MathUtilTest,packAndUnpackSnorm2x16Infinity)39 TEST(MathUtilTest, packAndUnpackSnorm2x16Infinity)
40 {
41     const float floatFaultTolerance = 0.0001f;
42     float outputVal1, outputVal2;
43 
44     unpackSnorm2x16(packSnorm2x16(std::numeric_limits<float>::infinity(),
45                                   std::numeric_limits<float>::infinity()),
46                     &outputVal1, &outputVal2);
47     EXPECT_NEAR(1.0f, outputVal1, floatFaultTolerance);
48     EXPECT_NEAR(1.0f, outputVal2, floatFaultTolerance);
49 
50     unpackSnorm2x16(packSnorm2x16(std::numeric_limits<float>::infinity(),
51                                   -std::numeric_limits<float>::infinity()),
52                     &outputVal1, &outputVal2);
53     EXPECT_NEAR(1.0f, outputVal1, floatFaultTolerance);
54     EXPECT_NEAR(-1.0f, outputVal2, floatFaultTolerance);
55 
56     unpackSnorm2x16(packSnorm2x16(-std::numeric_limits<float>::infinity(),
57                                   -std::numeric_limits<float>::infinity()),
58                     &outputVal1, &outputVal2);
59     EXPECT_NEAR(-1.0f, outputVal1, floatFaultTolerance);
60     EXPECT_NEAR(-1.0f, outputVal2, floatFaultTolerance);
61 }
62 
63 // Test the correctness of packUnorm2x16 and unpackUnorm2x16 functions.
64 // For floats f1 and f2, unpackUnorm2x16(packUnorm2x16(f1, f2)) should be same as f1 and f2.
TEST(MathUtilTest,packAndUnpackUnorm2x16)65 TEST(MathUtilTest, packAndUnpackUnorm2x16)
66 {
67     const float input[8][2] = {
68         {0.0f, 0.0f},    {1.0f, 1.0f},          {-1.0f, 1.0f},           {-1.0f, -1.0f},
69         {0.875f, 0.75f}, {0.00392f, -0.99215f}, {-0.000675f, 0.004954f}, {-0.6937f, -0.02146f}};
70     const float floatFaultTolerance = 0.0001f;
71     float outputVal1, outputVal2;
72 
73     for (size_t i = 0; i < 8; i++)
74     {
75         unpackUnorm2x16(packUnorm2x16(input[i][0], input[i][1]), &outputVal1, &outputVal2);
76         float expected = input[i][0] < 0.0f ? 0.0f : input[i][0];
77         EXPECT_NEAR(expected, outputVal1, floatFaultTolerance);
78         expected = input[i][1] < 0.0f ? 0.0f : input[i][1];
79         EXPECT_NEAR(expected, outputVal2, floatFaultTolerance);
80     }
81 }
82 
83 // Test the correctness of packUnorm2x16 and unpackUnorm2x16 functions with infinity values,
84 // result should be clamped to [0, 1].
TEST(MathUtilTest,packAndUnpackUnorm2x16Infinity)85 TEST(MathUtilTest, packAndUnpackUnorm2x16Infinity)
86 {
87     const float floatFaultTolerance = 0.0001f;
88     float outputVal1, outputVal2;
89 
90     unpackUnorm2x16(packUnorm2x16(std::numeric_limits<float>::infinity(),
91                                   std::numeric_limits<float>::infinity()),
92                     &outputVal1, &outputVal2);
93     EXPECT_NEAR(1.0f, outputVal1, floatFaultTolerance);
94     EXPECT_NEAR(1.0f, outputVal2, floatFaultTolerance);
95 
96     unpackUnorm2x16(packUnorm2x16(std::numeric_limits<float>::infinity(),
97                                   -std::numeric_limits<float>::infinity()),
98                     &outputVal1, &outputVal2);
99     EXPECT_NEAR(1.0f, outputVal1, floatFaultTolerance);
100     EXPECT_NEAR(0.0f, outputVal2, floatFaultTolerance);
101 
102     unpackUnorm2x16(packUnorm2x16(-std::numeric_limits<float>::infinity(),
103                                   -std::numeric_limits<float>::infinity()),
104                     &outputVal1, &outputVal2);
105     EXPECT_NEAR(0.0f, outputVal1, floatFaultTolerance);
106     EXPECT_NEAR(0.0f, outputVal2, floatFaultTolerance);
107 }
108 
109 // Test the correctness of packHalf2x16 and unpackHalf2x16 functions.
110 // For floats f1 and f2, unpackHalf2x16(packHalf2x16(f1, f2)) should be same as f1 and f2.
TEST(MathUtilTest,packAndUnpackHalf2x16)111 TEST(MathUtilTest, packAndUnpackHalf2x16)
112 {
113     const float input[8][2] = {
114         {0.0f, 0.0f},    {1.0f, 1.0f},          {-1.0f, 1.0f},           {-1.0f, -1.0f},
115         {0.875f, 0.75f}, {0.00392f, -0.99215f}, {-0.000675f, 0.004954f}, {-0.6937f, -0.02146f},
116     };
117     const float floatFaultTolerance = 0.0005f;
118     float outputVal1, outputVal2;
119 
120     for (size_t i = 0; i < 8; i++)
121     {
122         unpackHalf2x16(packHalf2x16(input[i][0], input[i][1]), &outputVal1, &outputVal2);
123         EXPECT_NEAR(input[i][0], outputVal1, floatFaultTolerance);
124         EXPECT_NEAR(input[i][1], outputVal2, floatFaultTolerance);
125     }
126 }
127 
128 // Test the correctness of packUnorm4x8 and unpackUnorm4x8 functions.
129 // For floats f1 to f4, unpackUnorm4x8(packUnorm4x8(f1, f2, f3, f4)) should be same as f1 to f4.
TEST(MathUtilTest,packAndUnpackUnorm4x8)130 TEST(MathUtilTest, packAndUnpackUnorm4x8)
131 {
132     const float input[5][4] = {{0.0f, 0.0f, 0.0f, 0.0f},
133                                {1.0f, 1.0f, 1.0f, 1.0f},
134                                {-1.0f, 1.0f, -1.0f, 1.0f},
135                                {-1.0f, -1.0f, -1.0f, -1.0f},
136                                {64.0f / 255.0f, 128.0f / 255.0f, 32.0f / 255.0f, 16.0f / 255.0f}};
137 
138     const float floatFaultTolerance = 0.005f;
139     float outputVals[4];
140 
141     for (size_t i = 0; i < 5; i++)
142     {
143         UnpackUnorm4x8(PackUnorm4x8(input[i][0], input[i][1], input[i][2], input[i][3]),
144                        outputVals);
145         for (size_t j = 0; j < 4; j++)
146         {
147             float expected = input[i][j] < 0.0f ? 0.0f : input[i][j];
148             EXPECT_NEAR(expected, outputVals[j], floatFaultTolerance);
149         }
150     }
151 }
152 
153 // Test the correctness of packSnorm4x8 and unpackSnorm4x8 functions.
154 // For floats f1 to f4, unpackSnorm4x8(packSnorm4x8(f1, f2, f3, f4)) should be same as f1 to f4.
TEST(MathUtilTest,packAndUnpackSnorm4x8)155 TEST(MathUtilTest, packAndUnpackSnorm4x8)
156 {
157     const float input[5][4] = {{0.0f, 0.0f, 0.0f, 0.0f},
158                                {1.0f, 1.0f, 1.0f, 1.0f},
159                                {-1.0f, 1.0f, -1.0f, 1.0f},
160                                {-1.0f, -1.0f, -1.0f, -1.0f},
161                                {64.0f / 127.0f, -8.0f / 127.0f, 32.0f / 127.0f, 16.0f / 127.0f}};
162 
163     const float floatFaultTolerance = 0.01f;
164     float outputVals[4];
165 
166     for (size_t i = 0; i < 5; i++)
167     {
168         UnpackSnorm4x8(PackSnorm4x8(input[i][0], input[i][1], input[i][2], input[i][3]),
169                        outputVals);
170         for (size_t j = 0; j < 4; j++)
171         {
172             float expected = input[i][j];
173             EXPECT_NEAR(expected, outputVals[j], floatFaultTolerance);
174         }
175     }
176 }
177 
178 // Test the correctness of gl::isNaN function.
TEST(MathUtilTest,isNaN)179 TEST(MathUtilTest, isNaN)
180 {
181     EXPECT_TRUE(isNaN(bitCast<float>(0xffu << 23 | 1u)));
182     EXPECT_TRUE(isNaN(bitCast<float>(1u << 31 | 0xffu << 23 | 1u)));
183     EXPECT_TRUE(isNaN(bitCast<float>(1u << 31 | 0xffu << 23 | 0x400000u)));
184     EXPECT_TRUE(isNaN(bitCast<float>(1u << 31 | 0xffu << 23 | 0x7fffffu)));
185     EXPECT_FALSE(isNaN(0.0f));
186     EXPECT_FALSE(isNaN(bitCast<float>(1u << 31 | 0xffu << 23)));
187     EXPECT_FALSE(isNaN(bitCast<float>(0xffu << 23)));
188 }
189 
190 // Test the correctness of gl::isInf function.
TEST(MathUtilTest,isInf)191 TEST(MathUtilTest, isInf)
192 {
193     EXPECT_TRUE(isInf(bitCast<float>(0xffu << 23)));
194     EXPECT_TRUE(isInf(bitCast<float>(1u << 31 | 0xffu << 23)));
195     EXPECT_FALSE(isInf(0.0f));
196     EXPECT_FALSE(isInf(bitCast<float>(0xffu << 23 | 1u)));
197     EXPECT_FALSE(isInf(bitCast<float>(1u << 31 | 0xffu << 23 | 1u)));
198     EXPECT_FALSE(isInf(bitCast<float>(1u << 31 | 0xffu << 23 | 0x400000u)));
199     EXPECT_FALSE(isInf(bitCast<float>(1u << 31 | 0xffu << 23 | 0x7fffffu)));
200     EXPECT_FALSE(isInf(bitCast<float>(0xfeu << 23 | 0x7fffffu)));
201     EXPECT_FALSE(isInf(bitCast<float>(1u << 31 | 0xfeu << 23 | 0x7fffffu)));
202 }
203 
TEST(MathUtilTest,CountLeadingZeros)204 TEST(MathUtilTest, CountLeadingZeros)
205 {
206     for (unsigned int i = 0; i < 32u; ++i)
207     {
208         uint32_t iLeadingZeros = 1u << (31u - i);
209         EXPECT_EQ(i, CountLeadingZeros(iLeadingZeros));
210     }
211     EXPECT_EQ(32u, CountLeadingZeros(0));
212 }
213 
214 // Some basic tests. Tests that rounding up zero produces zero.
TEST(MathUtilTest,BasicRoundUp)215 TEST(MathUtilTest, BasicRoundUp)
216 {
217     EXPECT_EQ(0u, rx::roundUp(0u, 4u));
218     EXPECT_EQ(4u, rx::roundUp(1u, 4u));
219     EXPECT_EQ(4u, rx::roundUp(4u, 4u));
220 }
221 
222 // Test that rounding up zero produces zero for checked ints.
TEST(MathUtilTest,CheckedRoundUpZero)223 TEST(MathUtilTest, CheckedRoundUpZero)
224 {
225     auto checkedValue = rx::CheckedRoundUp(0u, 4u);
226     ASSERT_TRUE(checkedValue.IsValid());
227     ASSERT_EQ(0u, checkedValue.ValueOrDie());
228 }
229 
230 // Test out-of-bounds with CheckedRoundUp
TEST(MathUtilTest,CheckedRoundUpInvalid)231 TEST(MathUtilTest, CheckedRoundUpInvalid)
232 {
233     // The answer to this query is out of bounds.
234     auto limit        = std::numeric_limits<unsigned int>::max();
235     auto checkedValue = rx::CheckedRoundUp(limit, limit - 1);
236     ASSERT_FALSE(checkedValue.IsValid());
237 
238     // Our implementation can't handle this query, despite the parameters being in range.
239     auto checkedLimit = rx::CheckedRoundUp(limit - 1, limit);
240     ASSERT_FALSE(checkedLimit.IsValid());
241 }
242 
243 // Test BitfieldReverse which reverses the order of the bits in an integer.
TEST(MathUtilTest,BitfieldReverse)244 TEST(MathUtilTest, BitfieldReverse)
245 {
246     EXPECT_EQ(0u, gl::BitfieldReverse(0u));
247     EXPECT_EQ(0x80000000u, gl::BitfieldReverse(1u));
248     EXPECT_EQ(0x1u, gl::BitfieldReverse(0x80000000u));
249     uint32_t bits     = (1u << 4u) | (1u << 7u);
250     uint32_t reversed = (1u << (31u - 4u)) | (1u << (31u - 7u));
251     EXPECT_EQ(reversed, gl::BitfieldReverse(bits));
252 }
253 
254 // Test BitCount, which counts 1 bits in an integer.
TEST(MathUtilTest,BitCount)255 TEST(MathUtilTest, BitCount)
256 {
257     EXPECT_EQ(0, gl::BitCount(0u));
258     EXPECT_EQ(32, gl::BitCount(0xFFFFFFFFu));
259     EXPECT_EQ(10, gl::BitCount(0x17103121u));
260 
261     EXPECT_EQ(0, gl::BitCount(static_cast<uint64_t>(0ull)));
262     EXPECT_EQ(32, gl::BitCount(static_cast<uint64_t>(0xFFFFFFFFull)));
263     EXPECT_EQ(10, gl::BitCount(static_cast<uint64_t>(0x17103121ull)));
264 
265     EXPECT_EQ(33, gl::BitCount(static_cast<uint64_t>(0xFFFFFFFF80000000ull)));
266     EXPECT_EQ(11, gl::BitCount(static_cast<uint64_t>(0x1710312180000000ull)));
267 }
268 
269 // Test ScanForward, which scans for the least significant 1 bit from a non-zero integer.
TEST(MathUtilTest,ScanForward)270 TEST(MathUtilTest, ScanForward)
271 {
272     EXPECT_EQ(0ul, gl::ScanForward(1u));
273     EXPECT_EQ(16ul, gl::ScanForward(0x80010000u));
274     EXPECT_EQ(31ul, gl::ScanForward(0x80000000u));
275 
276     EXPECT_EQ(0ul, gl::ScanForward(static_cast<uint64_t>(1ull)));
277     EXPECT_EQ(16ul, gl::ScanForward(static_cast<uint64_t>(0x80010000ull)));
278     EXPECT_EQ(31ul, gl::ScanForward(static_cast<uint64_t>(0x80000000ull)));
279 
280     EXPECT_EQ(32ul, gl::ScanForward(static_cast<uint64_t>(0x100000000ull)));
281     EXPECT_EQ(48ul, gl::ScanForward(static_cast<uint64_t>(0x8001000000000000ull)));
282     EXPECT_EQ(63ul, gl::ScanForward(static_cast<uint64_t>(0x8000000000000000ull)));
283 }
284 
285 // Test ScanReverse, which scans for the most significant 1 bit from a non-zero integer.
TEST(MathUtilTest,ScanReverse)286 TEST(MathUtilTest, ScanReverse)
287 {
288     EXPECT_EQ(0ul, gl::ScanReverse(1ul));
289     EXPECT_EQ(16ul, gl::ScanReverse(0x00010030ul));
290     EXPECT_EQ(31ul, gl::ScanReverse(0x80000000ul));
291 }
292 
293 // Test FindLSB, which finds the least significant 1 bit.
TEST(MathUtilTest,FindLSB)294 TEST(MathUtilTest, FindLSB)
295 {
296     EXPECT_EQ(-1, gl::FindLSB(0u));
297     EXPECT_EQ(0, gl::FindLSB(1u));
298     EXPECT_EQ(16, gl::FindLSB(0x80010000u));
299     EXPECT_EQ(31, gl::FindLSB(0x80000000u));
300 }
301 
302 // Test FindMSB, which finds the most significant 1 bit.
TEST(MathUtilTest,FindMSB)303 TEST(MathUtilTest, FindMSB)
304 {
305     EXPECT_EQ(-1, gl::FindMSB(0u));
306     EXPECT_EQ(0, gl::FindMSB(1u));
307     EXPECT_EQ(16, gl::FindMSB(0x00010030u));
308     EXPECT_EQ(31, gl::FindMSB(0x80000000u));
309 }
310 
311 // Test Ldexp, which combines mantissa and exponent into a floating-point number.
TEST(MathUtilTest,Ldexp)312 TEST(MathUtilTest, Ldexp)
313 {
314     EXPECT_EQ(2.5f, Ldexp(0.625f, 2));
315     EXPECT_EQ(-5.0f, Ldexp(-0.625f, 3));
316     EXPECT_EQ(std::numeric_limits<float>::infinity(), Ldexp(0.625f, 129));
317     EXPECT_EQ(0.0f, Ldexp(1.0f, -129));
318 }
319 
320 // Test that Range::extend works as expected.
TEST(MathUtilTest,RangeExtend)321 TEST(MathUtilTest, RangeExtend)
322 {
323     RangeI range(0, 0);
324 
325     range.extend(5);
326     EXPECT_EQ(0, range.low());
327     EXPECT_EQ(6, range.high());
328     EXPECT_EQ(6, range.length());
329 
330     range.extend(-1);
331     EXPECT_EQ(-1, range.low());
332     EXPECT_EQ(6, range.high());
333     EXPECT_EQ(7, range.length());
334 
335     range.extend(10);
336     EXPECT_EQ(-1, range.low());
337     EXPECT_EQ(11, range.high());
338     EXPECT_EQ(12, range.length());
339 }
340 
341 // Test that Range iteration works as expected.
TEST(MathUtilTest,RangeIteration)342 TEST(MathUtilTest, RangeIteration)
343 {
344     RangeI range(0, 10);
345     int expected = 0;
346     for (int value : range)
347     {
348         EXPECT_EQ(expected, value);
349         expected++;
350     }
351     EXPECT_EQ(range.length(), expected);
352 }
353 
354 // Tests for float32 to float16 conversion
TEST(MathUtilTest,Float32ToFloat16)355 TEST(MathUtilTest, Float32ToFloat16)
356 {
357     ASSERT_EQ(float32ToFloat16(0.0f), 0x0000);
358     ASSERT_EQ(float32ToFloat16(-0.0f), 0x8000);
359 
360     float inf = std::numeric_limits<float>::infinity();
361 
362     ASSERT_EQ(float32ToFloat16(inf), 0x7C00);
363     ASSERT_EQ(float32ToFloat16(-inf), 0xFC00);
364 
365     // Check that NaN is converted to a value in one of the float16 NaN ranges
366     float nan      = std::numeric_limits<float>::quiet_NaN();
367     uint16_t nan16 = float32ToFloat16(nan);
368     ASSERT_TRUE(nan16 > 0xFC00 || (nan16 < 0x8000 && nan16 > 0x7C00));
369 
370     ASSERT_EQ(float32ToFloat16(1.0f), 0x3C00);
371 }
372 
373 }  // anonymous namespace
374