blob: 7684c3473748f92162fcafb1ad1233e3eeee23e0 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
2 * Copyright 2011 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
tfarina@chromium.orge4fafb12013-12-12 21:11:12 +00007
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "include/core/SkPoint.h"
9#include "include/private/SkColorData.h"
10#include "include/private/SkFixed.h"
11#include "include/private/SkHalf.h"
12#include "include/private/SkTo.h"
13#include "include/utils/SkRandom.h"
14#include "src/core/SkEndian.h"
15#include "src/core/SkFDot6.h"
16#include "src/core/SkMathPriv.h"
17#include "tests/Test.h"
reed@android.comed673312009-02-27 16:24:51 +000018
Adlai Holler684838f2020-05-12 10:41:04 -040019#include <cinttypes>
20
reed@google.comc21f86f2013-04-29 14:18:23 +000021static void test_clz(skiatest::Reporter* reporter) {
22 REPORTER_ASSERT(reporter, 32 == SkCLZ(0));
23 REPORTER_ASSERT(reporter, 31 == SkCLZ(1));
24 REPORTER_ASSERT(reporter, 1 == SkCLZ(1 << 30));
Ben Wagnere2a94432020-05-04 17:42:34 -040025 REPORTER_ASSERT(reporter, 1 == SkCLZ((1 << 30) | (1 << 24) | 1));
reed@google.com7729534d2013-04-29 14:43:50 +000026 REPORTER_ASSERT(reporter, 0 == SkCLZ(~0U));
skia.committer@gmail.com81521132013-04-30 07:01:03 +000027
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +000028 SkRandom rand;
reed@google.comc21f86f2013-04-29 14:18:23 +000029 for (int i = 0; i < 1000; ++i) {
30 uint32_t mask = rand.nextU();
reed@google.combc57a292013-04-29 15:27:42 +000031 // need to get some zeros for testing, but in some obscure way so the
32 // compiler won't "see" that, and work-around calling the functions.
33 mask >>= (mask & 31);
reed@google.comc21f86f2013-04-29 14:18:23 +000034 int intri = SkCLZ(mask);
35 int porta = SkCLZ_portable(mask);
Ben Wagnere2a94432020-05-04 17:42:34 -040036 REPORTER_ASSERT(reporter, intri == porta, "mask:%d intri:%d porta:%d", mask, intri, porta);
37 }
38}
39
40static void test_ctz(skiatest::Reporter* reporter) {
41 REPORTER_ASSERT(reporter, 32 == SkCTZ(0));
42 REPORTER_ASSERT(reporter, 0 == SkCTZ(1));
43 REPORTER_ASSERT(reporter, 30 == SkCTZ(1 << 30));
44 REPORTER_ASSERT(reporter, 2 == SkCTZ((1 << 30) | (1 << 24) | (1 << 2)));
45 REPORTER_ASSERT(reporter, 0 == SkCTZ(~0U));
46
47 SkRandom rand;
48 for (int i = 0; i < 1000; ++i) {
49 uint32_t mask = rand.nextU();
50 // need to get some zeros for testing, but in some obscure way so the
51 // compiler won't "see" that, and work-around calling the functions.
52 mask >>= (mask & 31);
53 int intri = SkCTZ(mask);
54 int porta = SkCTZ_portable(mask);
55 REPORTER_ASSERT(reporter, intri == porta, "mask:%d intri:%d porta:%d", mask, intri, porta);
reed@google.comc21f86f2013-04-29 14:18:23 +000056 }
57}
58
59///////////////////////////////////////////////////////////////////////////////
60
reed@google.coma7d74612012-05-30 12:30:09 +000061static float sk_fsel(float pred, float result_ge, float result_lt) {
62 return pred >= 0 ? result_ge : result_lt;
63}
64
65static float fast_floor(float x) {
reed@google.comc20bc252012-05-30 13:48:14 +000066// float big = sk_fsel(x, 0x1.0p+23, -0x1.0p+23);
67 float big = sk_fsel(x, (float)(1 << 23), -(float)(1 << 23));
robertphillips@google.com00bf06a2012-05-30 15:19:17 +000068 return (float)(x + big) - big;
reed@google.coma7d74612012-05-30 12:30:09 +000069}
70
71static float std_floor(float x) {
72 return sk_float_floor(x);
73}
74
75static void test_floor_value(skiatest::Reporter* reporter, float value) {
76 float fast = fast_floor(value);
77 float std = std_floor(value);
halcanary7d571242016-02-24 17:59:16 -080078 if (std != fast) {
79 ERRORF(reporter, "fast_floor(%.9g) == %.9g != %.9g == std_floor(%.9g)",
80 value, fast, std, value);
81 }
reed@google.coma7d74612012-05-30 12:30:09 +000082}
83
84static void test_floor(skiatest::Reporter* reporter) {
85 static const float gVals[] = {
86 0, 1, 1.1f, 1.01f, 1.001f, 1.0001f, 1.00001f, 1.000001f, 1.0000001f
87 };
rmistry@google.comd6176b02012-08-23 18:14:13 +000088
reed@google.coma7d74612012-05-30 12:30:09 +000089 for (size_t i = 0; i < SK_ARRAY_COUNT(gVals); ++i) {
90 test_floor_value(reporter, gVals[i]);
91// test_floor_value(reporter, -gVals[i]);
92 }
93}
94
95///////////////////////////////////////////////////////////////////////////////
96
reed@google.comea774d22013-04-22 20:21:56 +000097// test that SkMul16ShiftRound and SkMulDiv255Round return the same result
98static void test_muldivround(skiatest::Reporter* reporter) {
99#if 0
100 // this "complete" test is too slow, so we test a random sampling of it
101
102 for (int a = 0; a <= 32767; ++a) {
103 for (int b = 0; b <= 32767; ++b) {
104 unsigned prod0 = SkMul16ShiftRound(a, b, 8);
105 unsigned prod1 = SkMulDiv255Round(a, b);
106 SkASSERT(prod0 == prod1);
107 }
108 }
109#endif
110
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000111 SkRandom rand;
reed@google.comea774d22013-04-22 20:21:56 +0000112 for (int i = 0; i < 10000; ++i) {
113 unsigned a = rand.nextU() & 0x7FFF;
114 unsigned b = rand.nextU() & 0x7FFF;
115
116 unsigned prod0 = SkMul16ShiftRound(a, b, 8);
117 unsigned prod1 = SkMulDiv255Round(a, b);
118
119 REPORTER_ASSERT(reporter, prod0 == prod1);
120 }
121}
122
reed@google.com0abb4992011-10-06 20:04:36 +0000123static float float_blend(int src, int dst, float unit) {
124 return dst + (src - dst) * unit;
reed@google.com772813a2011-03-30 22:34:45 +0000125}
126
reed@google.com8d7e39c2011-11-09 17:12:08 +0000127static int blend31(int src, int dst, int a31) {
128 return dst + ((src - dst) * a31 * 2114 >> 16);
129 // return dst + ((src - dst) * a31 * 33 >> 10);
130}
131
132static int blend31_slow(int src, int dst, int a31) {
133 int prod = src * a31 + (31 - a31) * dst + 16;
134 prod = (prod + (prod >> 5)) >> 5;
135 return prod;
136}
137
138static int blend31_round(int src, int dst, int a31) {
139 int prod = (src - dst) * a31 + 16;
140 prod = (prod + (prod >> 5)) >> 5;
141 return dst + prod;
142}
143
144static int blend31_old(int src, int dst, int a31) {
145 a31 += a31 >> 4;
146 return dst + ((src - dst) * a31 >> 5);
147}
148
caryclark@google.com42639cd2012-06-06 12:03:39 +0000149// suppress unused code warning
150static int (*blend_functions[])(int, int, int) = {
151 blend31,
152 blend31_slow,
153 blend31_round,
154 blend31_old
155};
156
reed@google.com8d7e39c2011-11-09 17:12:08 +0000157static void test_blend31() {
158 int failed = 0;
159 int death = 0;
caryclark@google.com42639cd2012-06-06 12:03:39 +0000160 if (false) { // avoid bit rot, suppress warning
161 failed = (*blend_functions[0])(0,0,0);
162 }
reed@google.com8d7e39c2011-11-09 17:12:08 +0000163 for (int src = 0; src <= 255; src++) {
164 for (int dst = 0; dst <= 255; dst++) {
165 for (int a = 0; a <= 31; a++) {
166// int r0 = blend31(src, dst, a);
167// int r0 = blend31_round(src, dst, a);
168// int r0 = blend31_old(src, dst, a);
169 int r0 = blend31_slow(src, dst, a);
170
171 float f = float_blend(src, dst, a / 31.f);
172 int r1 = (int)f;
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000173 int r2 = SkScalarRoundToInt(f);
reed@google.com8d7e39c2011-11-09 17:12:08 +0000174
175 if (r0 != r1 && r0 != r2) {
bungeman@google.comfab44db2013-10-11 18:50:45 +0000176 SkDebugf("src:%d dst:%d a:%d result:%d float:%g\n",
halcanary7d571242016-02-24 17:59:16 -0800177 src, dst, a, r0, f);
reed@google.com8d7e39c2011-11-09 17:12:08 +0000178 failed += 1;
179 }
180 if (r0 > 255) {
181 death += 1;
bungeman@google.comfab44db2013-10-11 18:50:45 +0000182 SkDebugf("death src:%d dst:%d a:%d result:%d float:%g\n",
183 src, dst, a, r0, f);
reed@google.com8d7e39c2011-11-09 17:12:08 +0000184 }
185 }
186 }
187 }
188 SkDebugf("---- failed %d death %d\n", failed, death);
189}
190
reed@android.comed673312009-02-27 16:24:51 +0000191static void check_length(skiatest::Reporter* reporter,
192 const SkPoint& p, SkScalar targetLen) {
reed@android.comed673312009-02-27 16:24:51 +0000193 float x = SkScalarToFloat(p.fX);
194 float y = SkScalarToFloat(p.fY);
195 float len = sk_float_sqrt(x*x + y*y);
reed@android.com80e39a72009-04-02 16:59:40 +0000196
reed@android.comed673312009-02-27 16:24:51 +0000197 len /= SkScalarToFloat(targetLen);
reed@android.com80e39a72009-04-02 16:59:40 +0000198
reed@android.comed673312009-02-27 16:24:51 +0000199 REPORTER_ASSERT(reporter, len > 0.999f && len < 1.001f);
reed@android.comed673312009-02-27 16:24:51 +0000200}
201
reed@google.com077910e2011-02-08 21:56:39 +0000202static void unittest_isfinite(skiatest::Reporter* reporter) {
epoger@google.combf083a92011-06-08 18:26:08 +0000203 float nan = sk_float_asin(2);
Mike Reed026d20f2018-05-14 16:51:32 -0400204 float inf = SK_ScalarInfinity;
tomhudson@google.com75589252012-04-10 17:42:21 +0000205 float big = 3.40282e+038f;
reed@google.com077910e2011-02-08 21:56:39 +0000206
reed@google.com077910e2011-02-08 21:56:39 +0000207 REPORTER_ASSERT(reporter, !SkScalarIsNaN(inf));
reed@android.comd4134452011-02-09 02:24:26 +0000208 REPORTER_ASSERT(reporter, !SkScalarIsNaN(-inf));
209 REPORTER_ASSERT(reporter, !SkScalarIsFinite(inf));
210 REPORTER_ASSERT(reporter, !SkScalarIsFinite(-inf));
reed@android.comd4134452011-02-09 02:24:26 +0000211
212 REPORTER_ASSERT(reporter, SkScalarIsNaN(nan));
reed@google.com077910e2011-02-08 21:56:39 +0000213 REPORTER_ASSERT(reporter, !SkScalarIsNaN(big));
214 REPORTER_ASSERT(reporter, !SkScalarIsNaN(-big));
215 REPORTER_ASSERT(reporter, !SkScalarIsNaN(0));
rmistry@google.comd6176b02012-08-23 18:14:13 +0000216
reed@google.com077910e2011-02-08 21:56:39 +0000217 REPORTER_ASSERT(reporter, !SkScalarIsFinite(nan));
reed@google.com077910e2011-02-08 21:56:39 +0000218 REPORTER_ASSERT(reporter, SkScalarIsFinite(big));
219 REPORTER_ASSERT(reporter, SkScalarIsFinite(-big));
220 REPORTER_ASSERT(reporter, SkScalarIsFinite(0));
reed@google.com077910e2011-02-08 21:56:39 +0000221}
222
jvanverth93679922014-11-26 13:15:59 -0800223static void unittest_half(skiatest::Reporter* reporter) {
224 static const float gFloats[] = {
225 0.f, 1.f, 0.5f, 0.499999f, 0.5000001f, 1.f/3,
226 -0.f, -1.f, -0.5f, -0.499999f, -0.5000001f, -1.f/3
227 };
228
229 for (size_t i = 0; i < SK_ARRAY_COUNT(gFloats); ++i) {
230 SkHalf h = SkFloatToHalf(gFloats[i]);
231 float f = SkHalfToFloat(h);
232 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(f, gFloats[i]));
233 }
234
235 // check some special values
236 union FloatUnion {
237 uint32_t fU;
238 float fF;
239 };
240
241 static const FloatUnion largestPositiveHalf = { ((142 << 23) | (1023 << 13)) };
242 SkHalf h = SkFloatToHalf(largestPositiveHalf.fF);
243 float f = SkHalfToFloat(h);
244 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(f, largestPositiveHalf.fF));
245
246 static const FloatUnion largestNegativeHalf = { (1u << 31) | (142u << 23) | (1023u << 13) };
247 h = SkFloatToHalf(largestNegativeHalf.fF);
248 f = SkHalfToFloat(h);
249 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(f, largestNegativeHalf.fF));
250
251 static const FloatUnion smallestPositiveHalf = { 102 << 23 };
252 h = SkFloatToHalf(smallestPositiveHalf.fF);
253 f = SkHalfToFloat(h);
254 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(f, smallestPositiveHalf.fF));
255
256 static const FloatUnion overflowHalf = { ((143 << 23) | (1023 << 13)) };
257 h = SkFloatToHalf(overflowHalf.fF);
258 f = SkHalfToFloat(h);
259 REPORTER_ASSERT(reporter, !SkScalarIsFinite(f) );
260
261 static const FloatUnion underflowHalf = { 101 << 23 };
262 h = SkFloatToHalf(underflowHalf.fF);
263 f = SkHalfToFloat(h);
264 REPORTER_ASSERT(reporter, f == 0.0f );
265
266 static const FloatUnion inf32 = { 255 << 23 };
267 h = SkFloatToHalf(inf32.fF);
268 f = SkHalfToFloat(h);
269 REPORTER_ASSERT(reporter, !SkScalarIsFinite(f) );
270
271 static const FloatUnion nan32 = { 255 << 23 | 1 };
272 h = SkFloatToHalf(nan32.fF);
273 f = SkHalfToFloat(h);
274 REPORTER_ASSERT(reporter, SkScalarIsNaN(f) );
275
276}
277
mtkleina766ca82016-01-26 07:40:30 -0800278template <typename RSqrtFn>
279static void test_rsqrt(skiatest::Reporter* reporter, RSqrtFn rsqrt) {
jvanverth29c69792015-07-23 11:14:29 -0700280 const float maxRelativeError = 6.50196699e-4f;
281
282 // test close to 0 up to 1
283 float input = 0.000001f;
284 for (int i = 0; i < 1000; ++i) {
285 float exact = 1.0f/sk_float_sqrt(input);
mtkleina766ca82016-01-26 07:40:30 -0800286 float estimate = rsqrt(input);
jvanverth29c69792015-07-23 11:14:29 -0700287 float relativeError = sk_float_abs(exact - estimate)/exact;
288 REPORTER_ASSERT(reporter, relativeError <= maxRelativeError);
289 input += 0.001f;
290 }
291
292 // test 1 to ~100
293 input = 1.0f;
294 for (int i = 0; i < 1000; ++i) {
295 float exact = 1.0f/sk_float_sqrt(input);
mtkleina766ca82016-01-26 07:40:30 -0800296 float estimate = rsqrt(input);
jvanverth29c69792015-07-23 11:14:29 -0700297 float relativeError = sk_float_abs(exact - estimate)/exact;
298 REPORTER_ASSERT(reporter, relativeError <= maxRelativeError);
299 input += 0.01f;
300 }
301
302 // test some big numbers
303 input = 1000000.0f;
304 for (int i = 0; i < 100; ++i) {
305 float exact = 1.0f/sk_float_sqrt(input);
mtkleina766ca82016-01-26 07:40:30 -0800306 float estimate = rsqrt(input);
jvanverth29c69792015-07-23 11:14:29 -0700307 float relativeError = sk_float_abs(exact - estimate)/exact;
308 REPORTER_ASSERT(reporter, relativeError <= maxRelativeError);
309 input += 754326.f;
310 }
311}
312
reed@android.comed673312009-02-27 16:24:51 +0000313static void test_muldiv255(skiatest::Reporter* reporter) {
reed@android.comed673312009-02-27 16:24:51 +0000314 for (int a = 0; a <= 255; a++) {
315 for (int b = 0; b <= 255; b++) {
316 int ab = a * b;
317 float s = ab / 255.0f;
318 int round = (int)floorf(s + 0.5f);
319 int trunc = (int)floorf(s);
reed@android.com80e39a72009-04-02 16:59:40 +0000320
reed@android.comed673312009-02-27 16:24:51 +0000321 int iround = SkMulDiv255Round(a, b);
322 int itrunc = SkMulDiv255Trunc(a, b);
reed@android.com80e39a72009-04-02 16:59:40 +0000323
reed@android.comed673312009-02-27 16:24:51 +0000324 REPORTER_ASSERT(reporter, iround == round);
325 REPORTER_ASSERT(reporter, itrunc == trunc);
reed@android.com80e39a72009-04-02 16:59:40 +0000326
reed@android.comed673312009-02-27 16:24:51 +0000327 REPORTER_ASSERT(reporter, itrunc <= iround);
328 REPORTER_ASSERT(reporter, iround <= a);
329 REPORTER_ASSERT(reporter, iround <= b);
330 }
331 }
reed@android.comed673312009-02-27 16:24:51 +0000332}
333
senorblanco@chromium.orgec7a30c2010-12-07 21:07:56 +0000334static void test_muldiv255ceiling(skiatest::Reporter* reporter) {
335 for (int c = 0; c <= 255; c++) {
336 for (int a = 0; a <= 255; a++) {
337 int product = (c * a + 255);
338 int expected_ceiling = (product + (product >> 8)) >> 8;
339 int webkit_ceiling = (c * a + 254) / 255;
340 REPORTER_ASSERT(reporter, expected_ceiling == webkit_ceiling);
341 int skia_ceiling = SkMulDiv255Ceiling(c, a);
342 REPORTER_ASSERT(reporter, skia_ceiling == webkit_ceiling);
343 }
344 }
345}
346
reed@android.comf0ad0862010-02-09 19:18:38 +0000347static void test_copysign(skiatest::Reporter* reporter) {
348 static const int32_t gTriples[] = {
349 // x, y, expected result
350 0, 0, 0,
351 0, 1, 0,
352 0, -1, 0,
353 1, 0, 1,
354 1, 1, 1,
355 1, -1, -1,
356 -1, 0, 1,
357 -1, 1, 1,
358 -1, -1, -1,
359 };
360 for (size_t i = 0; i < SK_ARRAY_COUNT(gTriples); i += 3) {
361 REPORTER_ASSERT(reporter,
362 SkCopySign32(gTriples[i], gTriples[i+1]) == gTriples[i+2]);
reed@android.comf0ad0862010-02-09 19:18:38 +0000363 float x = (float)gTriples[i];
364 float y = (float)gTriples[i+1];
365 float expected = (float)gTriples[i+2];
366 REPORTER_ASSERT(reporter, sk_float_copysign(x, y) == expected);
reed@android.comf0ad0862010-02-09 19:18:38 +0000367 }
368
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000369 SkRandom rand;
reed@android.comf0ad0862010-02-09 19:18:38 +0000370 for (int j = 0; j < 1000; j++) {
371 int ix = rand.nextS();
372 REPORTER_ASSERT(reporter, SkCopySign32(ix, ix) == ix);
373 REPORTER_ASSERT(reporter, SkCopySign32(ix, -ix) == -ix);
374 REPORTER_ASSERT(reporter, SkCopySign32(-ix, ix) == ix);
375 REPORTER_ASSERT(reporter, SkCopySign32(-ix, -ix) == -ix);
376
377 SkScalar sx = rand.nextSScalar1();
378 REPORTER_ASSERT(reporter, SkScalarCopySign(sx, sx) == sx);
379 REPORTER_ASSERT(reporter, SkScalarCopySign(sx, -sx) == -sx);
380 REPORTER_ASSERT(reporter, SkScalarCopySign(-sx, sx) == sx);
381 REPORTER_ASSERT(reporter, SkScalarCopySign(-sx, -sx) == -sx);
382 }
383}
384
Mike Reed026d20f2018-05-14 16:51:32 -0400385static void huge_vector_normalize(skiatest::Reporter* reporter) {
386 // these values should fail (overflow/underflow) trying to normalize
387 const SkVector fail[] = {
388 { 0, 0 },
389 { SK_ScalarInfinity, 0 }, { 0, SK_ScalarInfinity },
390 { 0, SK_ScalarNaN }, { SK_ScalarNaN, 0 },
391 };
392 for (SkVector v : fail) {
393 SkVector v2 = v;
394 if (v2.setLength(1.0f)) {
395 REPORTER_ASSERT(reporter, !v.setLength(1.0f));
396 }
397 }
398}
399
tfarina@chromium.orge4fafb12013-12-12 21:11:12 +0000400DEF_TEST(Math, reporter) {
reed@android.comed673312009-02-27 16:24:51 +0000401 int i;
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000402 SkRandom rand;
reed@android.com80e39a72009-04-02 16:59:40 +0000403
reed@android.comed673312009-02-27 16:24:51 +0000404 // these should assert
405#if 0
406 SkToS8(128);
407 SkToS8(-129);
408 SkToU8(256);
409 SkToU8(-5);
reed@android.com80e39a72009-04-02 16:59:40 +0000410
reed@android.comed673312009-02-27 16:24:51 +0000411 SkToS16(32768);
412 SkToS16(-32769);
413 SkToU16(65536);
414 SkToU16(-5);
reed@android.com80e39a72009-04-02 16:59:40 +0000415
reed@android.comed673312009-02-27 16:24:51 +0000416 if (sizeof(size_t) > 4) {
417 SkToS32(4*1024*1024);
418 SkToS32(-4*1024*1024);
419 SkToU32(5*1024*1024);
420 SkToU32(-5);
421 }
422#endif
reed@android.com80e39a72009-04-02 16:59:40 +0000423
reed@android.comed673312009-02-27 16:24:51 +0000424 test_muldiv255(reporter);
senorblanco@chromium.orgec7a30c2010-12-07 21:07:56 +0000425 test_muldiv255ceiling(reporter);
reed@android.comf0ad0862010-02-09 19:18:38 +0000426 test_copysign(reporter);
reed@android.com80e39a72009-04-02 16:59:40 +0000427
reed@android.comed673312009-02-27 16:24:51 +0000428 {
429 SkScalar x = SK_ScalarNaN;
430 REPORTER_ASSERT(reporter, SkScalarIsNaN(x));
431 }
reed@android.com80e39a72009-04-02 16:59:40 +0000432
reed@android.come72fee52009-11-16 14:52:01 +0000433 for (i = 0; i < 10000; i++) {
reed@android.comed673312009-02-27 16:24:51 +0000434 SkPoint p;
reed@android.com80e39a72009-04-02 16:59:40 +0000435
tomhudson@google.com75589252012-04-10 17:42:21 +0000436 // These random values are being treated as 32-bit-patterns, not as
437 // ints; calling SkIntToScalar() here produces crashes.
robertphillips@google.com4debcac2012-05-14 16:33:36 +0000438 p.setLength((SkScalar) rand.nextS(),
rmistry@google.comd6176b02012-08-23 18:14:13 +0000439 (SkScalar) rand.nextS(),
robertphillips@google.com4debcac2012-05-14 16:33:36 +0000440 SK_Scalar1);
reed@android.comed673312009-02-27 16:24:51 +0000441 check_length(reporter, p, SK_Scalar1);
robertphillips@google.com4debcac2012-05-14 16:33:36 +0000442 p.setLength((SkScalar) (rand.nextS() >> 13),
rmistry@google.comd6176b02012-08-23 18:14:13 +0000443 (SkScalar) (rand.nextS() >> 13),
robertphillips@google.com4debcac2012-05-14 16:33:36 +0000444 SK_Scalar1);
reed@android.comed673312009-02-27 16:24:51 +0000445 check_length(reporter, p, SK_Scalar1);
446 }
reed@android.com80e39a72009-04-02 16:59:40 +0000447
reed@android.comed673312009-02-27 16:24:51 +0000448 {
449 SkFixed result = SkFixedDiv(100, 100);
450 REPORTER_ASSERT(reporter, result == SK_Fixed1);
451 result = SkFixedDiv(1, SK_Fixed1);
452 REPORTER_ASSERT(reporter, result == 1);
liyuqian0d2c2342016-07-13 13:34:46 -0700453 result = SkFixedDiv(10 - 1, SK_Fixed1 * 3);
454 REPORTER_ASSERT(reporter, result == 3);
reed@android.comed673312009-02-27 16:24:51 +0000455 }
reed@android.com80e39a72009-04-02 16:59:40 +0000456
liyuqian3f490cc2016-10-20 11:23:09 -0700457 {
458 REPORTER_ASSERT(reporter, (SkFixedRoundToFixed(-SK_Fixed1 * 10) >> 1) == -SK_Fixed1 * 5);
459 REPORTER_ASSERT(reporter, (SkFixedFloorToFixed(-SK_Fixed1 * 10) >> 1) == -SK_Fixed1 * 5);
460 REPORTER_ASSERT(reporter, (SkFixedCeilToFixed(-SK_Fixed1 * 10) >> 1) == -SK_Fixed1 * 5);
461 }
462
Mike Reed026d20f2018-05-14 16:51:32 -0400463 huge_vector_normalize(reporter);
reed@google.com077910e2011-02-08 21:56:39 +0000464 unittest_isfinite(reporter);
jvanverth93679922014-11-26 13:15:59 -0800465 unittest_half(reporter);
mtkleina766ca82016-01-26 07:40:30 -0800466 test_rsqrt(reporter, sk_float_rsqrt);
467 test_rsqrt(reporter, sk_float_rsqrt_portable);
reed@android.com80e39a72009-04-02 16:59:40 +0000468
reed@android.come72fee52009-11-16 14:52:01 +0000469 for (i = 0; i < 10000; i++) {
reed@android.comed673312009-02-27 16:24:51 +0000470 SkFixed numer = rand.nextS();
471 SkFixed denom = rand.nextS();
472 SkFixed result = SkFixedDiv(numer, denom);
caryclark3127c992015-12-09 12:02:30 -0800473 int64_t check = SkLeftShift((int64_t)numer, 16) / denom;
reed@android.com80e39a72009-04-02 16:59:40 +0000474
reed@android.comed673312009-02-27 16:24:51 +0000475 (void)SkCLZ(numer);
476 (void)SkCLZ(denom);
reed@android.com80e39a72009-04-02 16:59:40 +0000477
reed@android.comed673312009-02-27 16:24:51 +0000478 REPORTER_ASSERT(reporter, result != (SkFixed)SK_NaN32);
479 if (check > SK_MaxS32) {
480 check = SK_MaxS32;
481 } else if (check < -SK_MaxS32) {
482 check = SK_MinS32;
483 }
mtklein97ca98d2015-03-18 11:32:21 -0700484 if (result != (int32_t)check) {
Adlai Holler684838f2020-05-12 10:41:04 -0400485 ERRORF(reporter, "\nFixed Divide: %8x / %8x -> %8x %8" PRIx64 "\n", numer, denom,
486 result, check);
mtklein97ca98d2015-03-18 11:32:21 -0700487 }
reed@android.comed673312009-02-27 16:24:51 +0000488 REPORTER_ASSERT(reporter, result == (int32_t)check);
reed@android.comed673312009-02-27 16:24:51 +0000489 }
reed@android.com80e39a72009-04-02 16:59:40 +0000490
humper@google.com05af1af2013-01-07 16:47:43 +0000491 if (false) test_floor(reporter);
reed@google.coma7d74612012-05-30 12:30:09 +0000492
reed@google.com8d7e39c2011-11-09 17:12:08 +0000493 // disable for now
caryclark@google.com42639cd2012-06-06 12:03:39 +0000494 if (false) test_blend31(); // avoid bit rot, suppress warning
reed@google.comea774d22013-04-22 20:21:56 +0000495
496 test_muldivround(reporter);
reed@google.comc21f86f2013-04-29 14:18:23 +0000497 test_clz(reporter);
Ben Wagnere2a94432020-05-04 17:42:34 -0400498 test_ctz(reporter);
reed@android.comed673312009-02-27 16:24:51 +0000499}
500
reed@google.comc9f81662013-05-03 18:06:31 +0000501template <typename T> struct PairRec {
502 T fYin;
503 T fYang;
504};
505
tfarina@chromium.orge4fafb12013-12-12 21:11:12 +0000506DEF_TEST(TestEndian, reporter) {
reed@google.comc9f81662013-05-03 18:06:31 +0000507 static const PairRec<uint16_t> g16[] = {
508 { 0x0, 0x0 },
509 { 0xFFFF, 0xFFFF },
510 { 0x1122, 0x2211 },
511 };
512 static const PairRec<uint32_t> g32[] = {
513 { 0x0, 0x0 },
514 { 0xFFFFFFFF, 0xFFFFFFFF },
515 { 0x11223344, 0x44332211 },
516 };
517 static const PairRec<uint64_t> g64[] = {
518 { 0x0, 0x0 },
519 { 0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL },
520 { 0x1122334455667788ULL, 0x8877665544332211ULL },
521 };
522
523 REPORTER_ASSERT(reporter, 0x1122 == SkTEndianSwap16<0x2211>::value);
524 REPORTER_ASSERT(reporter, 0x11223344 == SkTEndianSwap32<0x44332211>::value);
525 REPORTER_ASSERT(reporter, 0x1122334455667788ULL == SkTEndianSwap64<0x8877665544332211ULL>::value);
526
527 for (size_t i = 0; i < SK_ARRAY_COUNT(g16); ++i) {
528 REPORTER_ASSERT(reporter, g16[i].fYang == SkEndianSwap16(g16[i].fYin));
529 }
530 for (size_t i = 0; i < SK_ARRAY_COUNT(g32); ++i) {
531 REPORTER_ASSERT(reporter, g32[i].fYang == SkEndianSwap32(g32[i].fYin));
532 }
533 for (size_t i = 0; i < SK_ARRAY_COUNT(g64); ++i) {
534 REPORTER_ASSERT(reporter, g64[i].fYang == SkEndianSwap64(g64[i].fYin));
535 }
536}
537
commit-bot@chromium.org2c86fbb2013-09-26 19:22:54 +0000538template <typename T>
539static void test_divmod(skiatest::Reporter* r) {
Brian Osman50ea3c02019-02-04 10:01:53 -0500540#if !defined(__MSVC_RUNTIME_CHECKS)
commit-bot@chromium.org2c86fbb2013-09-26 19:22:54 +0000541 const struct {
542 T numer;
543 T denom;
544 } kEdgeCases[] = {
545 {(T)17, (T)17},
546 {(T)17, (T)4},
547 {(T)0, (T)17},
548 // For unsigned T these negatives are just some large numbers. Doesn't hurt to test them.
549 {(T)-17, (T)-17},
550 {(T)-17, (T)4},
551 {(T)17, (T)-4},
552 {(T)-17, (T)-4},
553 };
554
555 for (size_t i = 0; i < SK_ARRAY_COUNT(kEdgeCases); i++) {
556 const T numer = kEdgeCases[i].numer;
557 const T denom = kEdgeCases[i].denom;
558 T div, mod;
559 SkTDivMod(numer, denom, &div, &mod);
560 REPORTER_ASSERT(r, numer/denom == div);
561 REPORTER_ASSERT(r, numer%denom == mod);
562 }
563
564 SkRandom rand;
565 for (size_t i = 0; i < 10000; i++) {
566 const T numer = (T)rand.nextS();
567 T denom = 0;
568 while (0 == denom) {
569 denom = (T)rand.nextS();
570 }
571 T div, mod;
572 SkTDivMod(numer, denom, &div, &mod);
573 REPORTER_ASSERT(r, numer/denom == div);
574 REPORTER_ASSERT(r, numer%denom == mod);
575 }
Brian Osman50ea3c02019-02-04 10:01:53 -0500576#endif
commit-bot@chromium.org2c86fbb2013-09-26 19:22:54 +0000577}
578
579DEF_TEST(divmod_u8, r) {
580 test_divmod<uint8_t>(r);
581}
582
583DEF_TEST(divmod_u16, r) {
584 test_divmod<uint16_t>(r);
585}
586
587DEF_TEST(divmod_u32, r) {
588 test_divmod<uint32_t>(r);
589}
590
591DEF_TEST(divmod_u64, r) {
592 test_divmod<uint64_t>(r);
593}
594
595DEF_TEST(divmod_s8, r) {
596 test_divmod<int8_t>(r);
597}
598
599DEF_TEST(divmod_s16, r) {
600 test_divmod<int16_t>(r);
601}
602
603DEF_TEST(divmod_s32, r) {
604 test_divmod<int32_t>(r);
605}
606
607DEF_TEST(divmod_s64, r) {
608 test_divmod<int64_t>(r);
609}
Robert Phillips9e380472016-10-28 12:15:03 -0400610
611static void test_nextsizepow2(skiatest::Reporter* r, size_t test, size_t expectedAns) {
612 size_t ans = GrNextSizePow2(test);
613
614 REPORTER_ASSERT(r, ans == expectedAns);
615 //SkDebugf("0x%zx -> 0x%zx (0x%zx)\n", test, ans, expectedAns);
616}
617
618DEF_TEST(GrNextSizePow2, reporter) {
619 constexpr int kNumSizeTBits = 8 * sizeof(size_t);
620
621 size_t test = 0, expectedAns = 1;
622
623 test_nextsizepow2(reporter, test, expectedAns);
624
625 test = 1; expectedAns = 1;
626
627 for (int i = 1; i < kNumSizeTBits; ++i) {
628 test_nextsizepow2(reporter, test, expectedAns);
629
630 test++;
631 expectedAns <<= 1;
632
633 test_nextsizepow2(reporter, test, expectedAns);
634
635 test = expectedAns;
636 }
637
638 // For the remaining three tests there is no higher power (of 2)
639 test = 0x1;
640 test <<= kNumSizeTBits-1;
641 test_nextsizepow2(reporter, test, test);
642
643 test++;
644 test_nextsizepow2(reporter, test, test);
645
646 test_nextsizepow2(reporter, SIZE_MAX, SIZE_MAX);
647}
Mike Reed828f1d52017-08-09 11:06:53 -0400648
Mike Reed3d5a6b52018-01-31 15:55:47 -0500649DEF_TEST(FloatSaturate32, reporter) {
Mike Reed828f1d52017-08-09 11:06:53 -0400650 const struct {
651 float fFloat;
652 int fExpectedInt;
653 } recs[] = {
654 { 0, 0 },
655 { 100.5f, 100 },
656 { (float)SK_MaxS32, SK_MaxS32FitsInFloat },
657 { (float)SK_MinS32, SK_MinS32FitsInFloat },
658 { SK_MaxS32 * 100.0f, SK_MaxS32FitsInFloat },
659 { SK_MinS32 * 100.0f, SK_MinS32FitsInFloat },
660 { SK_ScalarInfinity, SK_MaxS32FitsInFloat },
661 { SK_ScalarNegativeInfinity, SK_MinS32FitsInFloat },
662 { SK_ScalarNaN, SK_MaxS32FitsInFloat },
663 };
664
665 for (auto r : recs) {
666 int i = sk_float_saturate2int(r.fFloat);
667 REPORTER_ASSERT(reporter, r.fExpectedInt == i);
Mike Reedf6188422018-03-05 11:49:51 -0500668
Brian Osman788b9162020-02-07 10:36:46 -0500669 // Ensure that SkTPin bounds even non-finite values (including NaN)
Mike Reedf6188422018-03-05 11:49:51 -0500670 SkScalar p = SkTPin<SkScalar>(r.fFloat, 0, 100);
671 REPORTER_ASSERT(reporter, p >= 0 && p <= 100);
Mike Reed828f1d52017-08-09 11:06:53 -0400672 }
673}
Mike Reede0762232017-10-10 14:49:35 -0400674
Mike Reed3d5a6b52018-01-31 15:55:47 -0500675DEF_TEST(FloatSaturate64, reporter) {
676 const struct {
677 float fFloat;
678 int64_t fExpected64;
679 } recs[] = {
680 { 0, 0 },
681 { 100.5f, 100 },
682 { (float)SK_MaxS64, SK_MaxS64FitsInFloat },
683 { (float)SK_MinS64, SK_MinS64FitsInFloat },
684 { SK_MaxS64 * 100.0f, SK_MaxS64FitsInFloat },
685 { SK_MinS64 * 100.0f, SK_MinS64FitsInFloat },
686 { SK_ScalarInfinity, SK_MaxS64FitsInFloat },
687 { SK_ScalarNegativeInfinity, SK_MinS64FitsInFloat },
688 { SK_ScalarNaN, SK_MaxS64FitsInFloat },
689 };
690
691 for (auto r : recs) {
692 int64_t i = sk_float_saturate2int64(r.fFloat);
693 REPORTER_ASSERT(reporter, r.fExpected64 == i);
694 }
695}
696
697DEF_TEST(DoubleSaturate32, reporter) {
Mike Reede0762232017-10-10 14:49:35 -0400698 const struct {
699 double fDouble;
700 int fExpectedInt;
701 } recs[] = {
702 { 0, 0 },
703 { 100.5, 100 },
704 { SK_MaxS32, SK_MaxS32 },
705 { SK_MinS32, SK_MinS32 },
706 { SK_MaxS32 - 1, SK_MaxS32 - 1 },
707 { SK_MinS32 + 1, SK_MinS32 + 1 },
708 { SK_MaxS32 * 100.0, SK_MaxS32 },
709 { SK_MinS32 * 100.0, SK_MinS32 },
710 { SK_ScalarInfinity, SK_MaxS32 },
711 { SK_ScalarNegativeInfinity, SK_MinS32 },
712 { SK_ScalarNaN, SK_MaxS32 },
713 };
714
715 for (auto r : recs) {
716 int i = sk_double_saturate2int(r.fDouble);
717 REPORTER_ASSERT(reporter, r.fExpectedInt == i);
718 }
719}
Mike Kleind8853ec2018-03-10 11:34:53 -0500720
721#if defined(__ARM_NEON)
722 #include <arm_neon.h>
723
724 DEF_TEST(NeonU16Div255, r) {
725
726 for (int v = 0; v <= 255*255; v++) {
727 int want = (v + 127)/255;
728
729 uint16x8_t V = vdupq_n_u16(v);
730 int got = vrshrq_n_u16(vrsraq_n_u16(V, V, 8), 8)[0];
731
732 if (got != want) {
733 SkDebugf("%d -> %d, want %d\n", v, got, want);
734 }
735 REPORTER_ASSERT(r, got == want);
736 }
737 }
738
739#endif
Mike Reed31cc6d72019-02-27 16:14:37 -0500740
741DEF_TEST(unit_floats, r) {
742 // pick a non-trivial, non-pow-2 value, to test the loop
743 float v[13];
744 constexpr int N = SK_ARRAY_COUNT(v);
745
746 // empty array reports true
747 REPORTER_ASSERT(r, sk_floats_are_unit(v, 0));
748
749 SkRandom rand;
750 for (int outer = 0; outer < 1000; ++outer) {
751 // check some good values
752 for (int i = 0; i < N; ++i) {
753 v[i] = rand.nextUScalar1();
754 }
755 const int index = rand.nextU() % N;
756
757 REPORTER_ASSERT(r, sk_floats_are_unit(v, N));
758 v[index] = -0.f;
759 REPORTER_ASSERT(r, sk_floats_are_unit(v, N));
760 v[index] = 1.0f;
761 REPORTER_ASSERT(r, sk_floats_are_unit(v, N));
762
763 // check some bad values
764 const float non_norms[] = {
765 1.0000001f, 2, SK_ScalarInfinity, SK_ScalarNaN
766 };
767 for (float bad : non_norms) {
768 v[index] = bad;
769 REPORTER_ASSERT(r, !sk_floats_are_unit(v, N));
770 v[index] = -bad;
771 REPORTER_ASSERT(r, !sk_floats_are_unit(v, N));
772 }
773 }
774}