blob: 89e25b05e6410e091420847427891f7b562e49fd [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
Cary Clarka4083c92017-09-15 11:59:23 -04008#include "SkColorData.h"
tfarina@chromium.orge4fafb12013-12-12 21:11:12 +00009#include "SkEndian.h"
Yuqian Lice1d2932016-11-18 10:18:15 -050010#include "SkFDot6.h"
benjaminwagner6c71e0a2016-04-07 08:49:31 -070011#include "SkFixed.h"
jvanverth93679922014-11-26 13:15:59 -080012#include "SkHalf.h"
reed@google.com4b163ed2012-08-07 21:35:13 +000013#include "SkMathPriv.h"
reed@android.comed673312009-02-27 16:24:51 +000014#include "SkPoint.h"
15#include "SkRandom.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040016#include "SkTo.h"
tfarina@chromium.org8f6884a2014-01-24 20:56:26 +000017#include "Test.h"
reed@android.comed673312009-02-27 16:24:51 +000018
reed@google.comc21f86f2013-04-29 14:18:23 +000019static void test_clz(skiatest::Reporter* reporter) {
20 REPORTER_ASSERT(reporter, 32 == SkCLZ(0));
21 REPORTER_ASSERT(reporter, 31 == SkCLZ(1));
22 REPORTER_ASSERT(reporter, 1 == SkCLZ(1 << 30));
reed@google.com7729534d2013-04-29 14:43:50 +000023 REPORTER_ASSERT(reporter, 0 == SkCLZ(~0U));
skia.committer@gmail.com81521132013-04-30 07:01:03 +000024
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +000025 SkRandom rand;
reed@google.comc21f86f2013-04-29 14:18:23 +000026 for (int i = 0; i < 1000; ++i) {
27 uint32_t mask = rand.nextU();
reed@google.combc57a292013-04-29 15:27:42 +000028 // need to get some zeros for testing, but in some obscure way so the
29 // compiler won't "see" that, and work-around calling the functions.
30 mask >>= (mask & 31);
reed@google.comc21f86f2013-04-29 14:18:23 +000031 int intri = SkCLZ(mask);
32 int porta = SkCLZ_portable(mask);
33 REPORTER_ASSERT(reporter, intri == porta);
34 }
35}
36
37///////////////////////////////////////////////////////////////////////////////
38
reed@google.coma7d74612012-05-30 12:30:09 +000039static float sk_fsel(float pred, float result_ge, float result_lt) {
40 return pred >= 0 ? result_ge : result_lt;
41}
42
43static float fast_floor(float x) {
reed@google.comc20bc252012-05-30 13:48:14 +000044// float big = sk_fsel(x, 0x1.0p+23, -0x1.0p+23);
45 float big = sk_fsel(x, (float)(1 << 23), -(float)(1 << 23));
robertphillips@google.com00bf06a2012-05-30 15:19:17 +000046 return (float)(x + big) - big;
reed@google.coma7d74612012-05-30 12:30:09 +000047}
48
49static float std_floor(float x) {
50 return sk_float_floor(x);
51}
52
53static void test_floor_value(skiatest::Reporter* reporter, float value) {
54 float fast = fast_floor(value);
55 float std = std_floor(value);
halcanary7d571242016-02-24 17:59:16 -080056 if (std != fast) {
57 ERRORF(reporter, "fast_floor(%.9g) == %.9g != %.9g == std_floor(%.9g)",
58 value, fast, std, value);
59 }
reed@google.coma7d74612012-05-30 12:30:09 +000060}
61
62static void test_floor(skiatest::Reporter* reporter) {
63 static const float gVals[] = {
64 0, 1, 1.1f, 1.01f, 1.001f, 1.0001f, 1.00001f, 1.000001f, 1.0000001f
65 };
rmistry@google.comd6176b02012-08-23 18:14:13 +000066
reed@google.coma7d74612012-05-30 12:30:09 +000067 for (size_t i = 0; i < SK_ARRAY_COUNT(gVals); ++i) {
68 test_floor_value(reporter, gVals[i]);
69// test_floor_value(reporter, -gVals[i]);
70 }
71}
72
73///////////////////////////////////////////////////////////////////////////////
74
reed@google.comea774d22013-04-22 20:21:56 +000075// test that SkMul16ShiftRound and SkMulDiv255Round return the same result
76static void test_muldivround(skiatest::Reporter* reporter) {
77#if 0
78 // this "complete" test is too slow, so we test a random sampling of it
79
80 for (int a = 0; a <= 32767; ++a) {
81 for (int b = 0; b <= 32767; ++b) {
82 unsigned prod0 = SkMul16ShiftRound(a, b, 8);
83 unsigned prod1 = SkMulDiv255Round(a, b);
84 SkASSERT(prod0 == prod1);
85 }
86 }
87#endif
88
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +000089 SkRandom rand;
reed@google.comea774d22013-04-22 20:21:56 +000090 for (int i = 0; i < 10000; ++i) {
91 unsigned a = rand.nextU() & 0x7FFF;
92 unsigned b = rand.nextU() & 0x7FFF;
93
94 unsigned prod0 = SkMul16ShiftRound(a, b, 8);
95 unsigned prod1 = SkMulDiv255Round(a, b);
96
97 REPORTER_ASSERT(reporter, prod0 == prod1);
98 }
99}
100
reed@google.com0abb4992011-10-06 20:04:36 +0000101static float float_blend(int src, int dst, float unit) {
102 return dst + (src - dst) * unit;
reed@google.com772813a2011-03-30 22:34:45 +0000103}
104
reed@google.com8d7e39c2011-11-09 17:12:08 +0000105static int blend31(int src, int dst, int a31) {
106 return dst + ((src - dst) * a31 * 2114 >> 16);
107 // return dst + ((src - dst) * a31 * 33 >> 10);
108}
109
110static int blend31_slow(int src, int dst, int a31) {
111 int prod = src * a31 + (31 - a31) * dst + 16;
112 prod = (prod + (prod >> 5)) >> 5;
113 return prod;
114}
115
116static int blend31_round(int src, int dst, int a31) {
117 int prod = (src - dst) * a31 + 16;
118 prod = (prod + (prod >> 5)) >> 5;
119 return dst + prod;
120}
121
122static int blend31_old(int src, int dst, int a31) {
123 a31 += a31 >> 4;
124 return dst + ((src - dst) * a31 >> 5);
125}
126
caryclark@google.com42639cd2012-06-06 12:03:39 +0000127// suppress unused code warning
128static int (*blend_functions[])(int, int, int) = {
129 blend31,
130 blend31_slow,
131 blend31_round,
132 blend31_old
133};
134
reed@google.com8d7e39c2011-11-09 17:12:08 +0000135static void test_blend31() {
136 int failed = 0;
137 int death = 0;
caryclark@google.com42639cd2012-06-06 12:03:39 +0000138 if (false) { // avoid bit rot, suppress warning
139 failed = (*blend_functions[0])(0,0,0);
140 }
reed@google.com8d7e39c2011-11-09 17:12:08 +0000141 for (int src = 0; src <= 255; src++) {
142 for (int dst = 0; dst <= 255; dst++) {
143 for (int a = 0; a <= 31; a++) {
144// int r0 = blend31(src, dst, a);
145// int r0 = blend31_round(src, dst, a);
146// int r0 = blend31_old(src, dst, a);
147 int r0 = blend31_slow(src, dst, a);
148
149 float f = float_blend(src, dst, a / 31.f);
150 int r1 = (int)f;
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000151 int r2 = SkScalarRoundToInt(f);
reed@google.com8d7e39c2011-11-09 17:12:08 +0000152
153 if (r0 != r1 && r0 != r2) {
bungeman@google.comfab44db2013-10-11 18:50:45 +0000154 SkDebugf("src:%d dst:%d a:%d result:%d float:%g\n",
halcanary7d571242016-02-24 17:59:16 -0800155 src, dst, a, r0, f);
reed@google.com8d7e39c2011-11-09 17:12:08 +0000156 failed += 1;
157 }
158 if (r0 > 255) {
159 death += 1;
bungeman@google.comfab44db2013-10-11 18:50:45 +0000160 SkDebugf("death src:%d dst:%d a:%d result:%d float:%g\n",
161 src, dst, a, r0, f);
reed@google.com8d7e39c2011-11-09 17:12:08 +0000162 }
163 }
164 }
165 }
166 SkDebugf("---- failed %d death %d\n", failed, death);
167}
168
reed@android.comed673312009-02-27 16:24:51 +0000169static void check_length(skiatest::Reporter* reporter,
170 const SkPoint& p, SkScalar targetLen) {
reed@android.comed673312009-02-27 16:24:51 +0000171 float x = SkScalarToFloat(p.fX);
172 float y = SkScalarToFloat(p.fY);
173 float len = sk_float_sqrt(x*x + y*y);
reed@android.com80e39a72009-04-02 16:59:40 +0000174
reed@android.comed673312009-02-27 16:24:51 +0000175 len /= SkScalarToFloat(targetLen);
reed@android.com80e39a72009-04-02 16:59:40 +0000176
reed@android.comed673312009-02-27 16:24:51 +0000177 REPORTER_ASSERT(reporter, len > 0.999f && len < 1.001f);
reed@android.comed673312009-02-27 16:24:51 +0000178}
179
reed@google.com077910e2011-02-08 21:56:39 +0000180static void unittest_isfinite(skiatest::Reporter* reporter) {
epoger@google.combf083a92011-06-08 18:26:08 +0000181 float nan = sk_float_asin(2);
Mike Reed026d20f2018-05-14 16:51:32 -0400182 float inf = SK_ScalarInfinity;
tomhudson@google.com75589252012-04-10 17:42:21 +0000183 float big = 3.40282e+038f;
reed@google.com077910e2011-02-08 21:56:39 +0000184
reed@google.com077910e2011-02-08 21:56:39 +0000185 REPORTER_ASSERT(reporter, !SkScalarIsNaN(inf));
reed@android.comd4134452011-02-09 02:24:26 +0000186 REPORTER_ASSERT(reporter, !SkScalarIsNaN(-inf));
187 REPORTER_ASSERT(reporter, !SkScalarIsFinite(inf));
188 REPORTER_ASSERT(reporter, !SkScalarIsFinite(-inf));
reed@android.comd4134452011-02-09 02:24:26 +0000189
190 REPORTER_ASSERT(reporter, SkScalarIsNaN(nan));
reed@google.com077910e2011-02-08 21:56:39 +0000191 REPORTER_ASSERT(reporter, !SkScalarIsNaN(big));
192 REPORTER_ASSERT(reporter, !SkScalarIsNaN(-big));
193 REPORTER_ASSERT(reporter, !SkScalarIsNaN(0));
rmistry@google.comd6176b02012-08-23 18:14:13 +0000194
reed@google.com077910e2011-02-08 21:56:39 +0000195 REPORTER_ASSERT(reporter, !SkScalarIsFinite(nan));
reed@google.com077910e2011-02-08 21:56:39 +0000196 REPORTER_ASSERT(reporter, SkScalarIsFinite(big));
197 REPORTER_ASSERT(reporter, SkScalarIsFinite(-big));
198 REPORTER_ASSERT(reporter, SkScalarIsFinite(0));
reed@google.com077910e2011-02-08 21:56:39 +0000199}
200
jvanverth93679922014-11-26 13:15:59 -0800201static void unittest_half(skiatest::Reporter* reporter) {
202 static const float gFloats[] = {
203 0.f, 1.f, 0.5f, 0.499999f, 0.5000001f, 1.f/3,
204 -0.f, -1.f, -0.5f, -0.499999f, -0.5000001f, -1.f/3
205 };
206
207 for (size_t i = 0; i < SK_ARRAY_COUNT(gFloats); ++i) {
208 SkHalf h = SkFloatToHalf(gFloats[i]);
209 float f = SkHalfToFloat(h);
210 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(f, gFloats[i]));
211 }
212
213 // check some special values
214 union FloatUnion {
215 uint32_t fU;
216 float fF;
217 };
218
219 static const FloatUnion largestPositiveHalf = { ((142 << 23) | (1023 << 13)) };
220 SkHalf h = SkFloatToHalf(largestPositiveHalf.fF);
221 float f = SkHalfToFloat(h);
222 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(f, largestPositiveHalf.fF));
223
224 static const FloatUnion largestNegativeHalf = { (1u << 31) | (142u << 23) | (1023u << 13) };
225 h = SkFloatToHalf(largestNegativeHalf.fF);
226 f = SkHalfToFloat(h);
227 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(f, largestNegativeHalf.fF));
228
229 static const FloatUnion smallestPositiveHalf = { 102 << 23 };
230 h = SkFloatToHalf(smallestPositiveHalf.fF);
231 f = SkHalfToFloat(h);
232 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(f, smallestPositiveHalf.fF));
233
234 static const FloatUnion overflowHalf = { ((143 << 23) | (1023 << 13)) };
235 h = SkFloatToHalf(overflowHalf.fF);
236 f = SkHalfToFloat(h);
237 REPORTER_ASSERT(reporter, !SkScalarIsFinite(f) );
238
239 static const FloatUnion underflowHalf = { 101 << 23 };
240 h = SkFloatToHalf(underflowHalf.fF);
241 f = SkHalfToFloat(h);
242 REPORTER_ASSERT(reporter, f == 0.0f );
243
244 static const FloatUnion inf32 = { 255 << 23 };
245 h = SkFloatToHalf(inf32.fF);
246 f = SkHalfToFloat(h);
247 REPORTER_ASSERT(reporter, !SkScalarIsFinite(f) );
248
249 static const FloatUnion nan32 = { 255 << 23 | 1 };
250 h = SkFloatToHalf(nan32.fF);
251 f = SkHalfToFloat(h);
252 REPORTER_ASSERT(reporter, SkScalarIsNaN(f) );
253
254}
255
mtkleina766ca82016-01-26 07:40:30 -0800256template <typename RSqrtFn>
257static void test_rsqrt(skiatest::Reporter* reporter, RSqrtFn rsqrt) {
jvanverth29c69792015-07-23 11:14:29 -0700258 const float maxRelativeError = 6.50196699e-4f;
259
260 // test close to 0 up to 1
261 float input = 0.000001f;
262 for (int i = 0; i < 1000; ++i) {
263 float exact = 1.0f/sk_float_sqrt(input);
mtkleina766ca82016-01-26 07:40:30 -0800264 float estimate = rsqrt(input);
jvanverth29c69792015-07-23 11:14:29 -0700265 float relativeError = sk_float_abs(exact - estimate)/exact;
266 REPORTER_ASSERT(reporter, relativeError <= maxRelativeError);
267 input += 0.001f;
268 }
269
270 // test 1 to ~100
271 input = 1.0f;
272 for (int i = 0; i < 1000; ++i) {
273 float exact = 1.0f/sk_float_sqrt(input);
mtkleina766ca82016-01-26 07:40:30 -0800274 float estimate = rsqrt(input);
jvanverth29c69792015-07-23 11:14:29 -0700275 float relativeError = sk_float_abs(exact - estimate)/exact;
276 REPORTER_ASSERT(reporter, relativeError <= maxRelativeError);
277 input += 0.01f;
278 }
279
280 // test some big numbers
281 input = 1000000.0f;
282 for (int i = 0; i < 100; ++i) {
283 float exact = 1.0f/sk_float_sqrt(input);
mtkleina766ca82016-01-26 07:40:30 -0800284 float estimate = rsqrt(input);
jvanverth29c69792015-07-23 11:14:29 -0700285 float relativeError = sk_float_abs(exact - estimate)/exact;
286 REPORTER_ASSERT(reporter, relativeError <= maxRelativeError);
287 input += 754326.f;
288 }
289}
290
reed@android.comed673312009-02-27 16:24:51 +0000291static void test_muldiv255(skiatest::Reporter* reporter) {
reed@android.comed673312009-02-27 16:24:51 +0000292 for (int a = 0; a <= 255; a++) {
293 for (int b = 0; b <= 255; b++) {
294 int ab = a * b;
295 float s = ab / 255.0f;
296 int round = (int)floorf(s + 0.5f);
297 int trunc = (int)floorf(s);
reed@android.com80e39a72009-04-02 16:59:40 +0000298
reed@android.comed673312009-02-27 16:24:51 +0000299 int iround = SkMulDiv255Round(a, b);
300 int itrunc = SkMulDiv255Trunc(a, b);
reed@android.com80e39a72009-04-02 16:59:40 +0000301
reed@android.comed673312009-02-27 16:24:51 +0000302 REPORTER_ASSERT(reporter, iround == round);
303 REPORTER_ASSERT(reporter, itrunc == trunc);
reed@android.com80e39a72009-04-02 16:59:40 +0000304
reed@android.comed673312009-02-27 16:24:51 +0000305 REPORTER_ASSERT(reporter, itrunc <= iround);
306 REPORTER_ASSERT(reporter, iround <= a);
307 REPORTER_ASSERT(reporter, iround <= b);
308 }
309 }
reed@android.comed673312009-02-27 16:24:51 +0000310}
311
senorblanco@chromium.orgec7a30c2010-12-07 21:07:56 +0000312static void test_muldiv255ceiling(skiatest::Reporter* reporter) {
313 for (int c = 0; c <= 255; c++) {
314 for (int a = 0; a <= 255; a++) {
315 int product = (c * a + 255);
316 int expected_ceiling = (product + (product >> 8)) >> 8;
317 int webkit_ceiling = (c * a + 254) / 255;
318 REPORTER_ASSERT(reporter, expected_ceiling == webkit_ceiling);
319 int skia_ceiling = SkMulDiv255Ceiling(c, a);
320 REPORTER_ASSERT(reporter, skia_ceiling == webkit_ceiling);
321 }
322 }
323}
324
reed@android.comf0ad0862010-02-09 19:18:38 +0000325static void test_copysign(skiatest::Reporter* reporter) {
326 static const int32_t gTriples[] = {
327 // x, y, expected result
328 0, 0, 0,
329 0, 1, 0,
330 0, -1, 0,
331 1, 0, 1,
332 1, 1, 1,
333 1, -1, -1,
334 -1, 0, 1,
335 -1, 1, 1,
336 -1, -1, -1,
337 };
338 for (size_t i = 0; i < SK_ARRAY_COUNT(gTriples); i += 3) {
339 REPORTER_ASSERT(reporter,
340 SkCopySign32(gTriples[i], gTriples[i+1]) == gTriples[i+2]);
reed@android.comf0ad0862010-02-09 19:18:38 +0000341 float x = (float)gTriples[i];
342 float y = (float)gTriples[i+1];
343 float expected = (float)gTriples[i+2];
344 REPORTER_ASSERT(reporter, sk_float_copysign(x, y) == expected);
reed@android.comf0ad0862010-02-09 19:18:38 +0000345 }
346
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000347 SkRandom rand;
reed@android.comf0ad0862010-02-09 19:18:38 +0000348 for (int j = 0; j < 1000; j++) {
349 int ix = rand.nextS();
350 REPORTER_ASSERT(reporter, SkCopySign32(ix, ix) == ix);
351 REPORTER_ASSERT(reporter, SkCopySign32(ix, -ix) == -ix);
352 REPORTER_ASSERT(reporter, SkCopySign32(-ix, ix) == ix);
353 REPORTER_ASSERT(reporter, SkCopySign32(-ix, -ix) == -ix);
354
355 SkScalar sx = rand.nextSScalar1();
356 REPORTER_ASSERT(reporter, SkScalarCopySign(sx, sx) == sx);
357 REPORTER_ASSERT(reporter, SkScalarCopySign(sx, -sx) == -sx);
358 REPORTER_ASSERT(reporter, SkScalarCopySign(-sx, sx) == sx);
359 REPORTER_ASSERT(reporter, SkScalarCopySign(-sx, -sx) == -sx);
360 }
361}
362
Mike Reed026d20f2018-05-14 16:51:32 -0400363static void huge_vector_normalize(skiatest::Reporter* reporter) {
364 // these values should fail (overflow/underflow) trying to normalize
365 const SkVector fail[] = {
366 { 0, 0 },
367 { SK_ScalarInfinity, 0 }, { 0, SK_ScalarInfinity },
368 { 0, SK_ScalarNaN }, { SK_ScalarNaN, 0 },
369 };
370 for (SkVector v : fail) {
371 SkVector v2 = v;
372 if (v2.setLength(1.0f)) {
373 REPORTER_ASSERT(reporter, !v.setLength(1.0f));
374 }
375 }
376}
377
tfarina@chromium.orge4fafb12013-12-12 21:11:12 +0000378DEF_TEST(Math, reporter) {
reed@android.comed673312009-02-27 16:24:51 +0000379 int i;
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000380 SkRandom rand;
reed@android.com80e39a72009-04-02 16:59:40 +0000381
reed@android.comed673312009-02-27 16:24:51 +0000382 // these should assert
383#if 0
384 SkToS8(128);
385 SkToS8(-129);
386 SkToU8(256);
387 SkToU8(-5);
reed@android.com80e39a72009-04-02 16:59:40 +0000388
reed@android.comed673312009-02-27 16:24:51 +0000389 SkToS16(32768);
390 SkToS16(-32769);
391 SkToU16(65536);
392 SkToU16(-5);
reed@android.com80e39a72009-04-02 16:59:40 +0000393
reed@android.comed673312009-02-27 16:24:51 +0000394 if (sizeof(size_t) > 4) {
395 SkToS32(4*1024*1024);
396 SkToS32(-4*1024*1024);
397 SkToU32(5*1024*1024);
398 SkToU32(-5);
399 }
400#endif
reed@android.com80e39a72009-04-02 16:59:40 +0000401
reed@android.comed673312009-02-27 16:24:51 +0000402 test_muldiv255(reporter);
senorblanco@chromium.orgec7a30c2010-12-07 21:07:56 +0000403 test_muldiv255ceiling(reporter);
reed@android.comf0ad0862010-02-09 19:18:38 +0000404 test_copysign(reporter);
reed@android.com80e39a72009-04-02 16:59:40 +0000405
reed@android.comed673312009-02-27 16:24:51 +0000406 {
407 SkScalar x = SK_ScalarNaN;
408 REPORTER_ASSERT(reporter, SkScalarIsNaN(x));
409 }
reed@android.com80e39a72009-04-02 16:59:40 +0000410
reed@android.comed673312009-02-27 16:24:51 +0000411 for (i = 0; i < 1000; i++) {
Mike Klein5595f6e2018-09-05 10:51:00 -0400412 int value = rand.nextS() >> 16;
413 int max = rand.nextU() >> 16;
reed@android.com80e39a72009-04-02 16:59:40 +0000414
reed@android.comed673312009-02-27 16:24:51 +0000415 int clamp = SkClampMax(value, max);
416 int clamp2 = value < 0 ? 0 : (value > max ? max : value);
417 REPORTER_ASSERT(reporter, clamp == clamp2);
418 }
reed@android.com80e39a72009-04-02 16:59:40 +0000419
reed@android.come72fee52009-11-16 14:52:01 +0000420 for (i = 0; i < 10000; i++) {
reed@android.comed673312009-02-27 16:24:51 +0000421 SkPoint p;
reed@android.com80e39a72009-04-02 16:59:40 +0000422
tomhudson@google.com75589252012-04-10 17:42:21 +0000423 // These random values are being treated as 32-bit-patterns, not as
424 // ints; calling SkIntToScalar() here produces crashes.
robertphillips@google.com4debcac2012-05-14 16:33:36 +0000425 p.setLength((SkScalar) rand.nextS(),
rmistry@google.comd6176b02012-08-23 18:14:13 +0000426 (SkScalar) rand.nextS(),
robertphillips@google.com4debcac2012-05-14 16:33:36 +0000427 SK_Scalar1);
reed@android.comed673312009-02-27 16:24:51 +0000428 check_length(reporter, p, SK_Scalar1);
robertphillips@google.com4debcac2012-05-14 16:33:36 +0000429 p.setLength((SkScalar) (rand.nextS() >> 13),
rmistry@google.comd6176b02012-08-23 18:14:13 +0000430 (SkScalar) (rand.nextS() >> 13),
robertphillips@google.com4debcac2012-05-14 16:33:36 +0000431 SK_Scalar1);
reed@android.comed673312009-02-27 16:24:51 +0000432 check_length(reporter, p, SK_Scalar1);
433 }
reed@android.com80e39a72009-04-02 16:59:40 +0000434
reed@android.comed673312009-02-27 16:24:51 +0000435 {
436 SkFixed result = SkFixedDiv(100, 100);
437 REPORTER_ASSERT(reporter, result == SK_Fixed1);
438 result = SkFixedDiv(1, SK_Fixed1);
439 REPORTER_ASSERT(reporter, result == 1);
liyuqian0d2c2342016-07-13 13:34:46 -0700440 result = SkFixedDiv(10 - 1, SK_Fixed1 * 3);
441 REPORTER_ASSERT(reporter, result == 3);
reed@android.comed673312009-02-27 16:24:51 +0000442 }
reed@android.com80e39a72009-04-02 16:59:40 +0000443
liyuqian3f490cc2016-10-20 11:23:09 -0700444 {
445 REPORTER_ASSERT(reporter, (SkFixedRoundToFixed(-SK_Fixed1 * 10) >> 1) == -SK_Fixed1 * 5);
446 REPORTER_ASSERT(reporter, (SkFixedFloorToFixed(-SK_Fixed1 * 10) >> 1) == -SK_Fixed1 * 5);
447 REPORTER_ASSERT(reporter, (SkFixedCeilToFixed(-SK_Fixed1 * 10) >> 1) == -SK_Fixed1 * 5);
448 }
449
Mike Reed026d20f2018-05-14 16:51:32 -0400450 huge_vector_normalize(reporter);
reed@google.com077910e2011-02-08 21:56:39 +0000451 unittest_isfinite(reporter);
jvanverth93679922014-11-26 13:15:59 -0800452 unittest_half(reporter);
mtkleina766ca82016-01-26 07:40:30 -0800453 test_rsqrt(reporter, sk_float_rsqrt);
454 test_rsqrt(reporter, sk_float_rsqrt_portable);
reed@android.com80e39a72009-04-02 16:59:40 +0000455
reed@android.come72fee52009-11-16 14:52:01 +0000456 for (i = 0; i < 10000; i++) {
reed@android.comed673312009-02-27 16:24:51 +0000457 SkFixed numer = rand.nextS();
458 SkFixed denom = rand.nextS();
459 SkFixed result = SkFixedDiv(numer, denom);
caryclark3127c992015-12-09 12:02:30 -0800460 int64_t check = SkLeftShift((int64_t)numer, 16) / denom;
reed@android.com80e39a72009-04-02 16:59:40 +0000461
reed@android.comed673312009-02-27 16:24:51 +0000462 (void)SkCLZ(numer);
463 (void)SkCLZ(denom);
reed@android.com80e39a72009-04-02 16:59:40 +0000464
reed@android.comed673312009-02-27 16:24:51 +0000465 REPORTER_ASSERT(reporter, result != (SkFixed)SK_NaN32);
466 if (check > SK_MaxS32) {
467 check = SK_MaxS32;
468 } else if (check < -SK_MaxS32) {
469 check = SK_MinS32;
470 }
mtklein97ca98d2015-03-18 11:32:21 -0700471 if (result != (int32_t)check) {
472 ERRORF(reporter, "\nFixed Divide: %8x / %8x -> %8x %8x\n", numer, denom, result, check);
473 }
reed@android.comed673312009-02-27 16:24:51 +0000474 REPORTER_ASSERT(reporter, result == (int32_t)check);
reed@android.comed673312009-02-27 16:24:51 +0000475 }
reed@android.com80e39a72009-04-02 16:59:40 +0000476
humper@google.com05af1af2013-01-07 16:47:43 +0000477 if (false) test_floor(reporter);
reed@google.coma7d74612012-05-30 12:30:09 +0000478
reed@google.com8d7e39c2011-11-09 17:12:08 +0000479 // disable for now
caryclark@google.com42639cd2012-06-06 12:03:39 +0000480 if (false) test_blend31(); // avoid bit rot, suppress warning
reed@google.comea774d22013-04-22 20:21:56 +0000481
482 test_muldivround(reporter);
reed@google.comc21f86f2013-04-29 14:18:23 +0000483 test_clz(reporter);
reed@android.comed673312009-02-27 16:24:51 +0000484}
485
reed@google.comc9f81662013-05-03 18:06:31 +0000486template <typename T> struct PairRec {
487 T fYin;
488 T fYang;
489};
490
tfarina@chromium.orge4fafb12013-12-12 21:11:12 +0000491DEF_TEST(TestEndian, reporter) {
reed@google.comc9f81662013-05-03 18:06:31 +0000492 static const PairRec<uint16_t> g16[] = {
493 { 0x0, 0x0 },
494 { 0xFFFF, 0xFFFF },
495 { 0x1122, 0x2211 },
496 };
497 static const PairRec<uint32_t> g32[] = {
498 { 0x0, 0x0 },
499 { 0xFFFFFFFF, 0xFFFFFFFF },
500 { 0x11223344, 0x44332211 },
501 };
502 static const PairRec<uint64_t> g64[] = {
503 { 0x0, 0x0 },
504 { 0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL },
505 { 0x1122334455667788ULL, 0x8877665544332211ULL },
506 };
507
508 REPORTER_ASSERT(reporter, 0x1122 == SkTEndianSwap16<0x2211>::value);
509 REPORTER_ASSERT(reporter, 0x11223344 == SkTEndianSwap32<0x44332211>::value);
510 REPORTER_ASSERT(reporter, 0x1122334455667788ULL == SkTEndianSwap64<0x8877665544332211ULL>::value);
511
512 for (size_t i = 0; i < SK_ARRAY_COUNT(g16); ++i) {
513 REPORTER_ASSERT(reporter, g16[i].fYang == SkEndianSwap16(g16[i].fYin));
514 }
515 for (size_t i = 0; i < SK_ARRAY_COUNT(g32); ++i) {
516 REPORTER_ASSERT(reporter, g32[i].fYang == SkEndianSwap32(g32[i].fYin));
517 }
518 for (size_t i = 0; i < SK_ARRAY_COUNT(g64); ++i) {
519 REPORTER_ASSERT(reporter, g64[i].fYang == SkEndianSwap64(g64[i].fYin));
520 }
521}
522
commit-bot@chromium.org2c86fbb2013-09-26 19:22:54 +0000523template <typename T>
524static void test_divmod(skiatest::Reporter* r) {
Brian Osman50ea3c02019-02-04 10:01:53 -0500525#if !defined(__MSVC_RUNTIME_CHECKS)
commit-bot@chromium.org2c86fbb2013-09-26 19:22:54 +0000526 const struct {
527 T numer;
528 T denom;
529 } kEdgeCases[] = {
530 {(T)17, (T)17},
531 {(T)17, (T)4},
532 {(T)0, (T)17},
533 // For unsigned T these negatives are just some large numbers. Doesn't hurt to test them.
534 {(T)-17, (T)-17},
535 {(T)-17, (T)4},
536 {(T)17, (T)-4},
537 {(T)-17, (T)-4},
538 };
539
540 for (size_t i = 0; i < SK_ARRAY_COUNT(kEdgeCases); i++) {
541 const T numer = kEdgeCases[i].numer;
542 const T denom = kEdgeCases[i].denom;
543 T div, mod;
544 SkTDivMod(numer, denom, &div, &mod);
545 REPORTER_ASSERT(r, numer/denom == div);
546 REPORTER_ASSERT(r, numer%denom == mod);
547 }
548
549 SkRandom rand;
550 for (size_t i = 0; i < 10000; i++) {
551 const T numer = (T)rand.nextS();
552 T denom = 0;
553 while (0 == denom) {
554 denom = (T)rand.nextS();
555 }
556 T div, mod;
557 SkTDivMod(numer, denom, &div, &mod);
558 REPORTER_ASSERT(r, numer/denom == div);
559 REPORTER_ASSERT(r, numer%denom == mod);
560 }
Brian Osman50ea3c02019-02-04 10:01:53 -0500561#endif
commit-bot@chromium.org2c86fbb2013-09-26 19:22:54 +0000562}
563
564DEF_TEST(divmod_u8, r) {
565 test_divmod<uint8_t>(r);
566}
567
568DEF_TEST(divmod_u16, r) {
569 test_divmod<uint16_t>(r);
570}
571
572DEF_TEST(divmod_u32, r) {
573 test_divmod<uint32_t>(r);
574}
575
576DEF_TEST(divmod_u64, r) {
577 test_divmod<uint64_t>(r);
578}
579
580DEF_TEST(divmod_s8, r) {
581 test_divmod<int8_t>(r);
582}
583
584DEF_TEST(divmod_s16, r) {
585 test_divmod<int16_t>(r);
586}
587
588DEF_TEST(divmod_s32, r) {
589 test_divmod<int32_t>(r);
590}
591
592DEF_TEST(divmod_s64, r) {
593 test_divmod<int64_t>(r);
594}
Robert Phillips9e380472016-10-28 12:15:03 -0400595
596static void test_nextsizepow2(skiatest::Reporter* r, size_t test, size_t expectedAns) {
597 size_t ans = GrNextSizePow2(test);
598
599 REPORTER_ASSERT(r, ans == expectedAns);
600 //SkDebugf("0x%zx -> 0x%zx (0x%zx)\n", test, ans, expectedAns);
601}
602
603DEF_TEST(GrNextSizePow2, reporter) {
604 constexpr int kNumSizeTBits = 8 * sizeof(size_t);
605
606 size_t test = 0, expectedAns = 1;
607
608 test_nextsizepow2(reporter, test, expectedAns);
609
610 test = 1; expectedAns = 1;
611
612 for (int i = 1; i < kNumSizeTBits; ++i) {
613 test_nextsizepow2(reporter, test, expectedAns);
614
615 test++;
616 expectedAns <<= 1;
617
618 test_nextsizepow2(reporter, test, expectedAns);
619
620 test = expectedAns;
621 }
622
623 // For the remaining three tests there is no higher power (of 2)
624 test = 0x1;
625 test <<= kNumSizeTBits-1;
626 test_nextsizepow2(reporter, test, test);
627
628 test++;
629 test_nextsizepow2(reporter, test, test);
630
631 test_nextsizepow2(reporter, SIZE_MAX, SIZE_MAX);
632}
Mike Reed828f1d52017-08-09 11:06:53 -0400633
Mike Reed3d5a6b52018-01-31 15:55:47 -0500634DEF_TEST(FloatSaturate32, reporter) {
Mike Reed828f1d52017-08-09 11:06:53 -0400635 const struct {
636 float fFloat;
637 int fExpectedInt;
638 } recs[] = {
639 { 0, 0 },
640 { 100.5f, 100 },
641 { (float)SK_MaxS32, SK_MaxS32FitsInFloat },
642 { (float)SK_MinS32, SK_MinS32FitsInFloat },
643 { SK_MaxS32 * 100.0f, SK_MaxS32FitsInFloat },
644 { SK_MinS32 * 100.0f, SK_MinS32FitsInFloat },
645 { SK_ScalarInfinity, SK_MaxS32FitsInFloat },
646 { SK_ScalarNegativeInfinity, SK_MinS32FitsInFloat },
647 { SK_ScalarNaN, SK_MaxS32FitsInFloat },
648 };
649
650 for (auto r : recs) {
651 int i = sk_float_saturate2int(r.fFloat);
652 REPORTER_ASSERT(reporter, r.fExpectedInt == i);
Mike Reedf6188422018-03-05 11:49:51 -0500653
654 // ensure that these bound even non-finite values (including NaN)
655
656 SkScalar mx = SkTMax<SkScalar>(r.fFloat, 50);
657 REPORTER_ASSERT(reporter, mx >= 50);
658
659 SkScalar mn = SkTMin<SkScalar>(r.fFloat, 50);
660 REPORTER_ASSERT(reporter, mn <= 50);
661
662 SkScalar p = SkTPin<SkScalar>(r.fFloat, 0, 100);
663 REPORTER_ASSERT(reporter, p >= 0 && p <= 100);
Mike Reed828f1d52017-08-09 11:06:53 -0400664 }
665}
Mike Reede0762232017-10-10 14:49:35 -0400666
Mike Reed3d5a6b52018-01-31 15:55:47 -0500667DEF_TEST(FloatSaturate64, reporter) {
668 const struct {
669 float fFloat;
670 int64_t fExpected64;
671 } recs[] = {
672 { 0, 0 },
673 { 100.5f, 100 },
674 { (float)SK_MaxS64, SK_MaxS64FitsInFloat },
675 { (float)SK_MinS64, SK_MinS64FitsInFloat },
676 { SK_MaxS64 * 100.0f, SK_MaxS64FitsInFloat },
677 { SK_MinS64 * 100.0f, SK_MinS64FitsInFloat },
678 { SK_ScalarInfinity, SK_MaxS64FitsInFloat },
679 { SK_ScalarNegativeInfinity, SK_MinS64FitsInFloat },
680 { SK_ScalarNaN, SK_MaxS64FitsInFloat },
681 };
682
683 for (auto r : recs) {
684 int64_t i = sk_float_saturate2int64(r.fFloat);
685 REPORTER_ASSERT(reporter, r.fExpected64 == i);
686 }
687}
688
689DEF_TEST(DoubleSaturate32, reporter) {
Mike Reede0762232017-10-10 14:49:35 -0400690 const struct {
691 double fDouble;
692 int fExpectedInt;
693 } recs[] = {
694 { 0, 0 },
695 { 100.5, 100 },
696 { SK_MaxS32, SK_MaxS32 },
697 { SK_MinS32, SK_MinS32 },
698 { SK_MaxS32 - 1, SK_MaxS32 - 1 },
699 { SK_MinS32 + 1, SK_MinS32 + 1 },
700 { SK_MaxS32 * 100.0, SK_MaxS32 },
701 { SK_MinS32 * 100.0, SK_MinS32 },
702 { SK_ScalarInfinity, SK_MaxS32 },
703 { SK_ScalarNegativeInfinity, SK_MinS32 },
704 { SK_ScalarNaN, SK_MaxS32 },
705 };
706
707 for (auto r : recs) {
708 int i = sk_double_saturate2int(r.fDouble);
709 REPORTER_ASSERT(reporter, r.fExpectedInt == i);
710 }
711}
Mike Kleind8853ec2018-03-10 11:34:53 -0500712
713#if defined(__ARM_NEON)
714 #include <arm_neon.h>
715
716 DEF_TEST(NeonU16Div255, r) {
717
718 for (int v = 0; v <= 255*255; v++) {
719 int want = (v + 127)/255;
720
721 uint16x8_t V = vdupq_n_u16(v);
722 int got = vrshrq_n_u16(vrsraq_n_u16(V, V, 8), 8)[0];
723
724 if (got != want) {
725 SkDebugf("%d -> %d, want %d\n", v, got, want);
726 }
727 REPORTER_ASSERT(r, got == want);
728 }
729 }
730
731#endif
Mike Reed31cc6d72019-02-27 16:14:37 -0500732
733DEF_TEST(unit_floats, r) {
734 // pick a non-trivial, non-pow-2 value, to test the loop
735 float v[13];
736 constexpr int N = SK_ARRAY_COUNT(v);
737
738 // empty array reports true
739 REPORTER_ASSERT(r, sk_floats_are_unit(v, 0));
740
741 SkRandom rand;
742 for (int outer = 0; outer < 1000; ++outer) {
743 // check some good values
744 for (int i = 0; i < N; ++i) {
745 v[i] = rand.nextUScalar1();
746 }
747 const int index = rand.nextU() % N;
748
749 REPORTER_ASSERT(r, sk_floats_are_unit(v, N));
750 v[index] = -0.f;
751 REPORTER_ASSERT(r, sk_floats_are_unit(v, N));
752 v[index] = 1.0f;
753 REPORTER_ASSERT(r, sk_floats_are_unit(v, N));
754
755 // check some bad values
756 const float non_norms[] = {
757 1.0000001f, 2, SK_ScalarInfinity, SK_ScalarNaN
758 };
759 for (float bad : non_norms) {
760 v[index] = bad;
761 REPORTER_ASSERT(r, !sk_floats_are_unit(v, N));
762 v[index] = -bad;
763 REPORTER_ASSERT(r, !sk_floats_are_unit(v, N));
764 }
765 }
766}