blob: fbdc97b837d51485cda8bab745c52eb2ecb3d308 [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"
Mike Klein8aa0edf2020-10-16 11:04:18 -050012#include "include/private/SkTPin.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050013#include "include/private/SkTo.h"
14#include "include/utils/SkRandom.h"
15#include "src/core/SkEndian.h"
16#include "src/core/SkFDot6.h"
17#include "src/core/SkMathPriv.h"
18#include "tests/Test.h"
reed@android.comed673312009-02-27 16:24:51 +000019
Mike Kleina0c67312020-10-16 09:49:07 -050020#include <algorithm>
Adlai Holler684838f2020-05-12 10:41:04 -040021#include <cinttypes>
22
reed@google.comc21f86f2013-04-29 14:18:23 +000023static void test_clz(skiatest::Reporter* reporter) {
24 REPORTER_ASSERT(reporter, 32 == SkCLZ(0));
25 REPORTER_ASSERT(reporter, 31 == SkCLZ(1));
26 REPORTER_ASSERT(reporter, 1 == SkCLZ(1 << 30));
Ben Wagnere2a94432020-05-04 17:42:34 -040027 REPORTER_ASSERT(reporter, 1 == SkCLZ((1 << 30) | (1 << 24) | 1));
reed@google.com7729534d2013-04-29 14:43:50 +000028 REPORTER_ASSERT(reporter, 0 == SkCLZ(~0U));
skia.committer@gmail.com81521132013-04-30 07:01:03 +000029
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +000030 SkRandom rand;
reed@google.comc21f86f2013-04-29 14:18:23 +000031 for (int i = 0; i < 1000; ++i) {
32 uint32_t mask = rand.nextU();
reed@google.combc57a292013-04-29 15:27:42 +000033 // need to get some zeros for testing, but in some obscure way so the
34 // compiler won't "see" that, and work-around calling the functions.
35 mask >>= (mask & 31);
reed@google.comc21f86f2013-04-29 14:18:23 +000036 int intri = SkCLZ(mask);
37 int porta = SkCLZ_portable(mask);
Ben Wagnere2a94432020-05-04 17:42:34 -040038 REPORTER_ASSERT(reporter, intri == porta, "mask:%d intri:%d porta:%d", mask, intri, porta);
39 }
40}
41
42static void test_ctz(skiatest::Reporter* reporter) {
43 REPORTER_ASSERT(reporter, 32 == SkCTZ(0));
44 REPORTER_ASSERT(reporter, 0 == SkCTZ(1));
45 REPORTER_ASSERT(reporter, 30 == SkCTZ(1 << 30));
46 REPORTER_ASSERT(reporter, 2 == SkCTZ((1 << 30) | (1 << 24) | (1 << 2)));
47 REPORTER_ASSERT(reporter, 0 == SkCTZ(~0U));
48
49 SkRandom rand;
50 for (int i = 0; i < 1000; ++i) {
51 uint32_t mask = rand.nextU();
52 // need to get some zeros for testing, but in some obscure way so the
53 // compiler won't "see" that, and work-around calling the functions.
54 mask >>= (mask & 31);
55 int intri = SkCTZ(mask);
56 int porta = SkCTZ_portable(mask);
57 REPORTER_ASSERT(reporter, intri == porta, "mask:%d intri:%d porta:%d", mask, intri, porta);
reed@google.comc21f86f2013-04-29 14:18:23 +000058 }
59}
60
61///////////////////////////////////////////////////////////////////////////////
62
reed@google.coma7d74612012-05-30 12:30:09 +000063static float sk_fsel(float pred, float result_ge, float result_lt) {
64 return pred >= 0 ? result_ge : result_lt;
65}
66
67static float fast_floor(float x) {
reed@google.comc20bc252012-05-30 13:48:14 +000068// float big = sk_fsel(x, 0x1.0p+23, -0x1.0p+23);
69 float big = sk_fsel(x, (float)(1 << 23), -(float)(1 << 23));
robertphillips@google.com00bf06a2012-05-30 15:19:17 +000070 return (float)(x + big) - big;
reed@google.coma7d74612012-05-30 12:30:09 +000071}
72
73static float std_floor(float x) {
74 return sk_float_floor(x);
75}
76
77static void test_floor_value(skiatest::Reporter* reporter, float value) {
78 float fast = fast_floor(value);
79 float std = std_floor(value);
halcanary7d571242016-02-24 17:59:16 -080080 if (std != fast) {
81 ERRORF(reporter, "fast_floor(%.9g) == %.9g != %.9g == std_floor(%.9g)",
82 value, fast, std, value);
83 }
reed@google.coma7d74612012-05-30 12:30:09 +000084}
85
86static void test_floor(skiatest::Reporter* reporter) {
87 static const float gVals[] = {
88 0, 1, 1.1f, 1.01f, 1.001f, 1.0001f, 1.00001f, 1.000001f, 1.0000001f
89 };
rmistry@google.comd6176b02012-08-23 18:14:13 +000090
reed@google.coma7d74612012-05-30 12:30:09 +000091 for (size_t i = 0; i < SK_ARRAY_COUNT(gVals); ++i) {
92 test_floor_value(reporter, gVals[i]);
93// test_floor_value(reporter, -gVals[i]);
94 }
95}
96
97///////////////////////////////////////////////////////////////////////////////
98
reed@google.com0abb4992011-10-06 20:04:36 +000099static float float_blend(int src, int dst, float unit) {
100 return dst + (src - dst) * unit;
reed@google.com772813a2011-03-30 22:34:45 +0000101}
102
reed@google.com8d7e39c2011-11-09 17:12:08 +0000103static int blend31(int src, int dst, int a31) {
104 return dst + ((src - dst) * a31 * 2114 >> 16);
105 // return dst + ((src - dst) * a31 * 33 >> 10);
106}
107
108static int blend31_slow(int src, int dst, int a31) {
109 int prod = src * a31 + (31 - a31) * dst + 16;
110 prod = (prod + (prod >> 5)) >> 5;
111 return prod;
112}
113
114static int blend31_round(int src, int dst, int a31) {
115 int prod = (src - dst) * a31 + 16;
116 prod = (prod + (prod >> 5)) >> 5;
117 return dst + prod;
118}
119
120static int blend31_old(int src, int dst, int a31) {
121 a31 += a31 >> 4;
122 return dst + ((src - dst) * a31 >> 5);
123}
124
caryclark@google.com42639cd2012-06-06 12:03:39 +0000125// suppress unused code warning
126static int (*blend_functions[])(int, int, int) = {
127 blend31,
128 blend31_slow,
129 blend31_round,
130 blend31_old
131};
132
reed@google.com8d7e39c2011-11-09 17:12:08 +0000133static void test_blend31() {
134 int failed = 0;
135 int death = 0;
caryclark@google.com42639cd2012-06-06 12:03:39 +0000136 if (false) { // avoid bit rot, suppress warning
137 failed = (*blend_functions[0])(0,0,0);
138 }
reed@google.com8d7e39c2011-11-09 17:12:08 +0000139 for (int src = 0; src <= 255; src++) {
140 for (int dst = 0; dst <= 255; dst++) {
141 for (int a = 0; a <= 31; a++) {
142// int r0 = blend31(src, dst, a);
143// int r0 = blend31_round(src, dst, a);
144// int r0 = blend31_old(src, dst, a);
145 int r0 = blend31_slow(src, dst, a);
146
147 float f = float_blend(src, dst, a / 31.f);
148 int r1 = (int)f;
commit-bot@chromium.org4b413c82013-11-25 19:44:07 +0000149 int r2 = SkScalarRoundToInt(f);
reed@google.com8d7e39c2011-11-09 17:12:08 +0000150
151 if (r0 != r1 && r0 != r2) {
bungeman@google.comfab44db2013-10-11 18:50:45 +0000152 SkDebugf("src:%d dst:%d a:%d result:%d float:%g\n",
halcanary7d571242016-02-24 17:59:16 -0800153 src, dst, a, r0, f);
reed@google.com8d7e39c2011-11-09 17:12:08 +0000154 failed += 1;
155 }
156 if (r0 > 255) {
157 death += 1;
bungeman@google.comfab44db2013-10-11 18:50:45 +0000158 SkDebugf("death src:%d dst:%d a:%d result:%d float:%g\n",
159 src, dst, a, r0, f);
reed@google.com8d7e39c2011-11-09 17:12:08 +0000160 }
161 }
162 }
163 }
164 SkDebugf("---- failed %d death %d\n", failed, death);
165}
166
reed@android.comed673312009-02-27 16:24:51 +0000167static void check_length(skiatest::Reporter* reporter,
168 const SkPoint& p, SkScalar targetLen) {
reed@android.comed673312009-02-27 16:24:51 +0000169 float x = SkScalarToFloat(p.fX);
170 float y = SkScalarToFloat(p.fY);
171 float len = sk_float_sqrt(x*x + y*y);
reed@android.com80e39a72009-04-02 16:59:40 +0000172
reed@android.comed673312009-02-27 16:24:51 +0000173 len /= SkScalarToFloat(targetLen);
reed@android.com80e39a72009-04-02 16:59:40 +0000174
reed@android.comed673312009-02-27 16:24:51 +0000175 REPORTER_ASSERT(reporter, len > 0.999f && len < 1.001f);
reed@android.comed673312009-02-27 16:24:51 +0000176}
177
reed@google.com077910e2011-02-08 21:56:39 +0000178static void unittest_isfinite(skiatest::Reporter* reporter) {
epoger@google.combf083a92011-06-08 18:26:08 +0000179 float nan = sk_float_asin(2);
Mike Reed026d20f2018-05-14 16:51:32 -0400180 float inf = SK_ScalarInfinity;
tomhudson@google.com75589252012-04-10 17:42:21 +0000181 float big = 3.40282e+038f;
reed@google.com077910e2011-02-08 21:56:39 +0000182
reed@google.com077910e2011-02-08 21:56:39 +0000183 REPORTER_ASSERT(reporter, !SkScalarIsNaN(inf));
reed@android.comd4134452011-02-09 02:24:26 +0000184 REPORTER_ASSERT(reporter, !SkScalarIsNaN(-inf));
185 REPORTER_ASSERT(reporter, !SkScalarIsFinite(inf));
186 REPORTER_ASSERT(reporter, !SkScalarIsFinite(-inf));
reed@android.comd4134452011-02-09 02:24:26 +0000187
188 REPORTER_ASSERT(reporter, SkScalarIsNaN(nan));
reed@google.com077910e2011-02-08 21:56:39 +0000189 REPORTER_ASSERT(reporter, !SkScalarIsNaN(big));
190 REPORTER_ASSERT(reporter, !SkScalarIsNaN(-big));
191 REPORTER_ASSERT(reporter, !SkScalarIsNaN(0));
rmistry@google.comd6176b02012-08-23 18:14:13 +0000192
reed@google.com077910e2011-02-08 21:56:39 +0000193 REPORTER_ASSERT(reporter, !SkScalarIsFinite(nan));
reed@google.com077910e2011-02-08 21:56:39 +0000194 REPORTER_ASSERT(reporter, SkScalarIsFinite(big));
195 REPORTER_ASSERT(reporter, SkScalarIsFinite(-big));
196 REPORTER_ASSERT(reporter, SkScalarIsFinite(0));
reed@google.com077910e2011-02-08 21:56:39 +0000197}
198
jvanverth93679922014-11-26 13:15:59 -0800199static void unittest_half(skiatest::Reporter* reporter) {
200 static const float gFloats[] = {
201 0.f, 1.f, 0.5f, 0.499999f, 0.5000001f, 1.f/3,
202 -0.f, -1.f, -0.5f, -0.499999f, -0.5000001f, -1.f/3
203 };
204
205 for (size_t i = 0; i < SK_ARRAY_COUNT(gFloats); ++i) {
206 SkHalf h = SkFloatToHalf(gFloats[i]);
207 float f = SkHalfToFloat(h);
208 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(f, gFloats[i]));
209 }
210
211 // check some special values
212 union FloatUnion {
213 uint32_t fU;
214 float fF;
215 };
216
217 static const FloatUnion largestPositiveHalf = { ((142 << 23) | (1023 << 13)) };
218 SkHalf h = SkFloatToHalf(largestPositiveHalf.fF);
219 float f = SkHalfToFloat(h);
220 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(f, largestPositiveHalf.fF));
221
222 static const FloatUnion largestNegativeHalf = { (1u << 31) | (142u << 23) | (1023u << 13) };
223 h = SkFloatToHalf(largestNegativeHalf.fF);
224 f = SkHalfToFloat(h);
225 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(f, largestNegativeHalf.fF));
226
227 static const FloatUnion smallestPositiveHalf = { 102 << 23 };
228 h = SkFloatToHalf(smallestPositiveHalf.fF);
229 f = SkHalfToFloat(h);
230 REPORTER_ASSERT(reporter, SkScalarNearlyEqual(f, smallestPositiveHalf.fF));
231
232 static const FloatUnion overflowHalf = { ((143 << 23) | (1023 << 13)) };
233 h = SkFloatToHalf(overflowHalf.fF);
234 f = SkHalfToFloat(h);
235 REPORTER_ASSERT(reporter, !SkScalarIsFinite(f) );
236
237 static const FloatUnion underflowHalf = { 101 << 23 };
238 h = SkFloatToHalf(underflowHalf.fF);
239 f = SkHalfToFloat(h);
240 REPORTER_ASSERT(reporter, f == 0.0f );
241
242 static const FloatUnion inf32 = { 255 << 23 };
243 h = SkFloatToHalf(inf32.fF);
244 f = SkHalfToFloat(h);
245 REPORTER_ASSERT(reporter, !SkScalarIsFinite(f) );
246
247 static const FloatUnion nan32 = { 255 << 23 | 1 };
248 h = SkFloatToHalf(nan32.fF);
249 f = SkHalfToFloat(h);
250 REPORTER_ASSERT(reporter, SkScalarIsNaN(f) );
251
252}
253
mtkleina766ca82016-01-26 07:40:30 -0800254template <typename RSqrtFn>
255static void test_rsqrt(skiatest::Reporter* reporter, RSqrtFn rsqrt) {
jvanverth29c69792015-07-23 11:14:29 -0700256 const float maxRelativeError = 6.50196699e-4f;
257
258 // test close to 0 up to 1
259 float input = 0.000001f;
260 for (int i = 0; i < 1000; ++i) {
261 float exact = 1.0f/sk_float_sqrt(input);
mtkleina766ca82016-01-26 07:40:30 -0800262 float estimate = rsqrt(input);
jvanverth29c69792015-07-23 11:14:29 -0700263 float relativeError = sk_float_abs(exact - estimate)/exact;
264 REPORTER_ASSERT(reporter, relativeError <= maxRelativeError);
265 input += 0.001f;
266 }
267
268 // test 1 to ~100
269 input = 1.0f;
270 for (int i = 0; i < 1000; ++i) {
271 float exact = 1.0f/sk_float_sqrt(input);
mtkleina766ca82016-01-26 07:40:30 -0800272 float estimate = rsqrt(input);
jvanverth29c69792015-07-23 11:14:29 -0700273 float relativeError = sk_float_abs(exact - estimate)/exact;
274 REPORTER_ASSERT(reporter, relativeError <= maxRelativeError);
275 input += 0.01f;
276 }
277
278 // test some big numbers
279 input = 1000000.0f;
280 for (int i = 0; i < 100; ++i) {
281 float exact = 1.0f/sk_float_sqrt(input);
mtkleina766ca82016-01-26 07:40:30 -0800282 float estimate = rsqrt(input);
jvanverth29c69792015-07-23 11:14:29 -0700283 float relativeError = sk_float_abs(exact - estimate)/exact;
284 REPORTER_ASSERT(reporter, relativeError <= maxRelativeError);
285 input += 754326.f;
286 }
287}
288
Chris Dalton6b3c2f62020-08-19 16:26:13 -0600289static void test_nextlog2(skiatest::Reporter* r) {
290 REPORTER_ASSERT(r, sk_float_nextlog2(-std::numeric_limits<float>::infinity()) == 0);
291 REPORTER_ASSERT(r, sk_float_nextlog2(-std::numeric_limits<float>::max()) == 0);
292 REPORTER_ASSERT(r, sk_float_nextlog2(-1000.0f) == 0);
293 REPORTER_ASSERT(r, sk_float_nextlog2(-0.1f) == 0);
294 REPORTER_ASSERT(r, sk_float_nextlog2(-std::numeric_limits<float>::min()) == 0);
295 REPORTER_ASSERT(r, sk_float_nextlog2(-std::numeric_limits<float>::denorm_min()) == 0);
296 REPORTER_ASSERT(r, sk_float_nextlog2(0.0f) == 0);
297 REPORTER_ASSERT(r, sk_float_nextlog2(std::numeric_limits<float>::denorm_min()) == 0);
298 REPORTER_ASSERT(r, sk_float_nextlog2(std::numeric_limits<float>::min()) == 0);
299 REPORTER_ASSERT(r, sk_float_nextlog2(0.1f) == 0);
300 REPORTER_ASSERT(r, sk_float_nextlog2(1.0f) == 0);
301 REPORTER_ASSERT(r, sk_float_nextlog2(1.1f) == 1);
302 REPORTER_ASSERT(r, sk_float_nextlog2(2.0f) == 1);
303 REPORTER_ASSERT(r, sk_float_nextlog2(2.1f) == 2);
304 REPORTER_ASSERT(r, sk_float_nextlog2(3.0f) == 2);
305 REPORTER_ASSERT(r, sk_float_nextlog2(3.1f) == 2);
306 REPORTER_ASSERT(r, sk_float_nextlog2(4.0f) == 2);
307 REPORTER_ASSERT(r, sk_float_nextlog2(4.1f) == 3);
308 REPORTER_ASSERT(r, sk_float_nextlog2(5.0f) == 3);
309 REPORTER_ASSERT(r, sk_float_nextlog2(5.1f) == 3);
310 REPORTER_ASSERT(r, sk_float_nextlog2(6.0f) == 3);
311 REPORTER_ASSERT(r, sk_float_nextlog2(6.1f) == 3);
312 REPORTER_ASSERT(r, sk_float_nextlog2(7.0f) == 3);
313 REPORTER_ASSERT(r, sk_float_nextlog2(7.1f) == 3);
314 REPORTER_ASSERT(r, sk_float_nextlog2(8.0f) == 3);
315 REPORTER_ASSERT(r, sk_float_nextlog2(8.1f) == 4);
316 REPORTER_ASSERT(r, sk_float_nextlog2(9.0f) == 4);
317 REPORTER_ASSERT(r, sk_float_nextlog2(9.1f) == 4);
318 REPORTER_ASSERT(r, sk_float_nextlog2(std::numeric_limits<float>::max()) == 128);
319 REPORTER_ASSERT(r, sk_float_nextlog2(std::numeric_limits<float>::infinity()) > 0);
320 REPORTER_ASSERT(r, sk_float_nextlog2(std::numeric_limits<float>::quiet_NaN()) >= 0);
321
322 for (int i = 0; i < 100; ++i) {
323 float pow2 = std::ldexp(1, i);
324 float epsilon = std::ldexp(SK_ScalarNearlyZero, i);
325 REPORTER_ASSERT(r, sk_float_nextlog2(pow2) == i);
326 REPORTER_ASSERT(r, sk_float_nextlog2(pow2 + epsilon) == i + 1);
327 REPORTER_ASSERT(r, sk_float_nextlog2(pow2 - epsilon) == i);
328 }
329}
330
reed@android.comed673312009-02-27 16:24:51 +0000331static void test_muldiv255(skiatest::Reporter* reporter) {
reed@android.comed673312009-02-27 16:24:51 +0000332 for (int a = 0; a <= 255; a++) {
333 for (int b = 0; b <= 255; b++) {
334 int ab = a * b;
335 float s = ab / 255.0f;
336 int round = (int)floorf(s + 0.5f);
337 int trunc = (int)floorf(s);
reed@android.com80e39a72009-04-02 16:59:40 +0000338
reed@android.comed673312009-02-27 16:24:51 +0000339 int iround = SkMulDiv255Round(a, b);
340 int itrunc = SkMulDiv255Trunc(a, b);
reed@android.com80e39a72009-04-02 16:59:40 +0000341
reed@android.comed673312009-02-27 16:24:51 +0000342 REPORTER_ASSERT(reporter, iround == round);
343 REPORTER_ASSERT(reporter, itrunc == trunc);
reed@android.com80e39a72009-04-02 16:59:40 +0000344
reed@android.comed673312009-02-27 16:24:51 +0000345 REPORTER_ASSERT(reporter, itrunc <= iround);
346 REPORTER_ASSERT(reporter, iround <= a);
347 REPORTER_ASSERT(reporter, iround <= b);
348 }
349 }
reed@android.comed673312009-02-27 16:24:51 +0000350}
351
senorblanco@chromium.orgec7a30c2010-12-07 21:07:56 +0000352static void test_muldiv255ceiling(skiatest::Reporter* reporter) {
353 for (int c = 0; c <= 255; c++) {
354 for (int a = 0; a <= 255; a++) {
355 int product = (c * a + 255);
356 int expected_ceiling = (product + (product >> 8)) >> 8;
357 int webkit_ceiling = (c * a + 254) / 255;
358 REPORTER_ASSERT(reporter, expected_ceiling == webkit_ceiling);
359 int skia_ceiling = SkMulDiv255Ceiling(c, a);
360 REPORTER_ASSERT(reporter, skia_ceiling == webkit_ceiling);
361 }
362 }
363}
364
reed@android.comf0ad0862010-02-09 19:18:38 +0000365static void test_copysign(skiatest::Reporter* reporter) {
366 static const int32_t gTriples[] = {
367 // x, y, expected result
368 0, 0, 0,
369 0, 1, 0,
370 0, -1, 0,
371 1, 0, 1,
372 1, 1, 1,
373 1, -1, -1,
374 -1, 0, 1,
375 -1, 1, 1,
376 -1, -1, -1,
377 };
378 for (size_t i = 0; i < SK_ARRAY_COUNT(gTriples); i += 3) {
379 REPORTER_ASSERT(reporter,
380 SkCopySign32(gTriples[i], gTriples[i+1]) == gTriples[i+2]);
reed@android.comf0ad0862010-02-09 19:18:38 +0000381 float x = (float)gTriples[i];
382 float y = (float)gTriples[i+1];
383 float expected = (float)gTriples[i+2];
384 REPORTER_ASSERT(reporter, sk_float_copysign(x, y) == expected);
reed@android.comf0ad0862010-02-09 19:18:38 +0000385 }
386
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000387 SkRandom rand;
reed@android.comf0ad0862010-02-09 19:18:38 +0000388 for (int j = 0; j < 1000; j++) {
389 int ix = rand.nextS();
390 REPORTER_ASSERT(reporter, SkCopySign32(ix, ix) == ix);
391 REPORTER_ASSERT(reporter, SkCopySign32(ix, -ix) == -ix);
392 REPORTER_ASSERT(reporter, SkCopySign32(-ix, ix) == ix);
393 REPORTER_ASSERT(reporter, SkCopySign32(-ix, -ix) == -ix);
394
395 SkScalar sx = rand.nextSScalar1();
396 REPORTER_ASSERT(reporter, SkScalarCopySign(sx, sx) == sx);
397 REPORTER_ASSERT(reporter, SkScalarCopySign(sx, -sx) == -sx);
398 REPORTER_ASSERT(reporter, SkScalarCopySign(-sx, sx) == sx);
399 REPORTER_ASSERT(reporter, SkScalarCopySign(-sx, -sx) == -sx);
400 }
401}
402
Mike Reed026d20f2018-05-14 16:51:32 -0400403static void huge_vector_normalize(skiatest::Reporter* reporter) {
404 // these values should fail (overflow/underflow) trying to normalize
405 const SkVector fail[] = {
406 { 0, 0 },
407 { SK_ScalarInfinity, 0 }, { 0, SK_ScalarInfinity },
408 { 0, SK_ScalarNaN }, { SK_ScalarNaN, 0 },
409 };
410 for (SkVector v : fail) {
411 SkVector v2 = v;
412 if (v2.setLength(1.0f)) {
413 REPORTER_ASSERT(reporter, !v.setLength(1.0f));
414 }
415 }
416}
417
tfarina@chromium.orge4fafb12013-12-12 21:11:12 +0000418DEF_TEST(Math, reporter) {
reed@android.comed673312009-02-27 16:24:51 +0000419 int i;
commit-bot@chromium.orge0e7cfe2013-09-09 20:09:12 +0000420 SkRandom rand;
reed@android.com80e39a72009-04-02 16:59:40 +0000421
reed@android.comed673312009-02-27 16:24:51 +0000422 // these should assert
423#if 0
424 SkToS8(128);
425 SkToS8(-129);
426 SkToU8(256);
427 SkToU8(-5);
reed@android.com80e39a72009-04-02 16:59:40 +0000428
reed@android.comed673312009-02-27 16:24:51 +0000429 SkToS16(32768);
430 SkToS16(-32769);
431 SkToU16(65536);
432 SkToU16(-5);
reed@android.com80e39a72009-04-02 16:59:40 +0000433
reed@android.comed673312009-02-27 16:24:51 +0000434 if (sizeof(size_t) > 4) {
435 SkToS32(4*1024*1024);
436 SkToS32(-4*1024*1024);
437 SkToU32(5*1024*1024);
438 SkToU32(-5);
439 }
440#endif
reed@android.com80e39a72009-04-02 16:59:40 +0000441
reed@android.comed673312009-02-27 16:24:51 +0000442 test_muldiv255(reporter);
senorblanco@chromium.orgec7a30c2010-12-07 21:07:56 +0000443 test_muldiv255ceiling(reporter);
reed@android.comf0ad0862010-02-09 19:18:38 +0000444 test_copysign(reporter);
reed@android.com80e39a72009-04-02 16:59:40 +0000445
reed@android.comed673312009-02-27 16:24:51 +0000446 {
447 SkScalar x = SK_ScalarNaN;
448 REPORTER_ASSERT(reporter, SkScalarIsNaN(x));
449 }
reed@android.com80e39a72009-04-02 16:59:40 +0000450
reed@android.come72fee52009-11-16 14:52:01 +0000451 for (i = 0; i < 10000; i++) {
reed@android.comed673312009-02-27 16:24:51 +0000452 SkPoint p;
reed@android.com80e39a72009-04-02 16:59:40 +0000453
tomhudson@google.com75589252012-04-10 17:42:21 +0000454 // These random values are being treated as 32-bit-patterns, not as
455 // ints; calling SkIntToScalar() here produces crashes.
robertphillips@google.com4debcac2012-05-14 16:33:36 +0000456 p.setLength((SkScalar) rand.nextS(),
rmistry@google.comd6176b02012-08-23 18:14:13 +0000457 (SkScalar) rand.nextS(),
robertphillips@google.com4debcac2012-05-14 16:33:36 +0000458 SK_Scalar1);
reed@android.comed673312009-02-27 16:24:51 +0000459 check_length(reporter, p, SK_Scalar1);
robertphillips@google.com4debcac2012-05-14 16:33:36 +0000460 p.setLength((SkScalar) (rand.nextS() >> 13),
rmistry@google.comd6176b02012-08-23 18:14:13 +0000461 (SkScalar) (rand.nextS() >> 13),
robertphillips@google.com4debcac2012-05-14 16:33:36 +0000462 SK_Scalar1);
reed@android.comed673312009-02-27 16:24:51 +0000463 check_length(reporter, p, SK_Scalar1);
464 }
reed@android.com80e39a72009-04-02 16:59:40 +0000465
reed@android.comed673312009-02-27 16:24:51 +0000466 {
467 SkFixed result = SkFixedDiv(100, 100);
468 REPORTER_ASSERT(reporter, result == SK_Fixed1);
469 result = SkFixedDiv(1, SK_Fixed1);
470 REPORTER_ASSERT(reporter, result == 1);
liyuqian0d2c2342016-07-13 13:34:46 -0700471 result = SkFixedDiv(10 - 1, SK_Fixed1 * 3);
472 REPORTER_ASSERT(reporter, result == 3);
reed@android.comed673312009-02-27 16:24:51 +0000473 }
reed@android.com80e39a72009-04-02 16:59:40 +0000474
liyuqian3f490cc2016-10-20 11:23:09 -0700475 {
476 REPORTER_ASSERT(reporter, (SkFixedRoundToFixed(-SK_Fixed1 * 10) >> 1) == -SK_Fixed1 * 5);
477 REPORTER_ASSERT(reporter, (SkFixedFloorToFixed(-SK_Fixed1 * 10) >> 1) == -SK_Fixed1 * 5);
478 REPORTER_ASSERT(reporter, (SkFixedCeilToFixed(-SK_Fixed1 * 10) >> 1) == -SK_Fixed1 * 5);
479 }
480
Mike Reed026d20f2018-05-14 16:51:32 -0400481 huge_vector_normalize(reporter);
reed@google.com077910e2011-02-08 21:56:39 +0000482 unittest_isfinite(reporter);
jvanverth93679922014-11-26 13:15:59 -0800483 unittest_half(reporter);
mtkleina766ca82016-01-26 07:40:30 -0800484 test_rsqrt(reporter, sk_float_rsqrt);
485 test_rsqrt(reporter, sk_float_rsqrt_portable);
Chris Dalton6b3c2f62020-08-19 16:26:13 -0600486 test_nextlog2(reporter);
reed@android.com80e39a72009-04-02 16:59:40 +0000487
reed@android.come72fee52009-11-16 14:52:01 +0000488 for (i = 0; i < 10000; i++) {
reed@android.comed673312009-02-27 16:24:51 +0000489 SkFixed numer = rand.nextS();
490 SkFixed denom = rand.nextS();
491 SkFixed result = SkFixedDiv(numer, denom);
caryclark3127c992015-12-09 12:02:30 -0800492 int64_t check = SkLeftShift((int64_t)numer, 16) / denom;
reed@android.com80e39a72009-04-02 16:59:40 +0000493
reed@android.comed673312009-02-27 16:24:51 +0000494 (void)SkCLZ(numer);
495 (void)SkCLZ(denom);
reed@android.com80e39a72009-04-02 16:59:40 +0000496
reed@android.comed673312009-02-27 16:24:51 +0000497 REPORTER_ASSERT(reporter, result != (SkFixed)SK_NaN32);
498 if (check > SK_MaxS32) {
499 check = SK_MaxS32;
500 } else if (check < -SK_MaxS32) {
501 check = SK_MinS32;
502 }
mtklein97ca98d2015-03-18 11:32:21 -0700503 if (result != (int32_t)check) {
Adlai Holler684838f2020-05-12 10:41:04 -0400504 ERRORF(reporter, "\nFixed Divide: %8x / %8x -> %8x %8" PRIx64 "\n", numer, denom,
505 result, check);
mtklein97ca98d2015-03-18 11:32:21 -0700506 }
reed@android.comed673312009-02-27 16:24:51 +0000507 REPORTER_ASSERT(reporter, result == (int32_t)check);
reed@android.comed673312009-02-27 16:24:51 +0000508 }
reed@android.com80e39a72009-04-02 16:59:40 +0000509
humper@google.com05af1af2013-01-07 16:47:43 +0000510 if (false) test_floor(reporter);
reed@google.coma7d74612012-05-30 12:30:09 +0000511
reed@google.com8d7e39c2011-11-09 17:12:08 +0000512 // disable for now
caryclark@google.com42639cd2012-06-06 12:03:39 +0000513 if (false) test_blend31(); // avoid bit rot, suppress warning
reed@google.comea774d22013-04-22 20:21:56 +0000514
reed@google.comc21f86f2013-04-29 14:18:23 +0000515 test_clz(reporter);
Ben Wagnere2a94432020-05-04 17:42:34 -0400516 test_ctz(reporter);
reed@android.comed673312009-02-27 16:24:51 +0000517}
518
reed@google.comc9f81662013-05-03 18:06:31 +0000519template <typename T> struct PairRec {
520 T fYin;
521 T fYang;
522};
523
tfarina@chromium.orge4fafb12013-12-12 21:11:12 +0000524DEF_TEST(TestEndian, reporter) {
reed@google.comc9f81662013-05-03 18:06:31 +0000525 static const PairRec<uint16_t> g16[] = {
526 { 0x0, 0x0 },
527 { 0xFFFF, 0xFFFF },
528 { 0x1122, 0x2211 },
529 };
530 static const PairRec<uint32_t> g32[] = {
531 { 0x0, 0x0 },
532 { 0xFFFFFFFF, 0xFFFFFFFF },
533 { 0x11223344, 0x44332211 },
534 };
535 static const PairRec<uint64_t> g64[] = {
536 { 0x0, 0x0 },
537 { 0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL },
538 { 0x1122334455667788ULL, 0x8877665544332211ULL },
539 };
540
541 REPORTER_ASSERT(reporter, 0x1122 == SkTEndianSwap16<0x2211>::value);
542 REPORTER_ASSERT(reporter, 0x11223344 == SkTEndianSwap32<0x44332211>::value);
543 REPORTER_ASSERT(reporter, 0x1122334455667788ULL == SkTEndianSwap64<0x8877665544332211ULL>::value);
544
545 for (size_t i = 0; i < SK_ARRAY_COUNT(g16); ++i) {
546 REPORTER_ASSERT(reporter, g16[i].fYang == SkEndianSwap16(g16[i].fYin));
547 }
548 for (size_t i = 0; i < SK_ARRAY_COUNT(g32); ++i) {
549 REPORTER_ASSERT(reporter, g32[i].fYang == SkEndianSwap32(g32[i].fYin));
550 }
551 for (size_t i = 0; i < SK_ARRAY_COUNT(g64); ++i) {
552 REPORTER_ASSERT(reporter, g64[i].fYang == SkEndianSwap64(g64[i].fYin));
553 }
554}
555
commit-bot@chromium.org2c86fbb2013-09-26 19:22:54 +0000556template <typename T>
557static void test_divmod(skiatest::Reporter* r) {
Brian Osman50ea3c02019-02-04 10:01:53 -0500558#if !defined(__MSVC_RUNTIME_CHECKS)
commit-bot@chromium.org2c86fbb2013-09-26 19:22:54 +0000559 const struct {
560 T numer;
561 T denom;
562 } kEdgeCases[] = {
563 {(T)17, (T)17},
564 {(T)17, (T)4},
565 {(T)0, (T)17},
566 // For unsigned T these negatives are just some large numbers. Doesn't hurt to test them.
567 {(T)-17, (T)-17},
568 {(T)-17, (T)4},
569 {(T)17, (T)-4},
570 {(T)-17, (T)-4},
571 };
572
573 for (size_t i = 0; i < SK_ARRAY_COUNT(kEdgeCases); i++) {
574 const T numer = kEdgeCases[i].numer;
575 const T denom = kEdgeCases[i].denom;
576 T div, mod;
577 SkTDivMod(numer, denom, &div, &mod);
578 REPORTER_ASSERT(r, numer/denom == div);
579 REPORTER_ASSERT(r, numer%denom == mod);
580 }
581
582 SkRandom rand;
583 for (size_t i = 0; i < 10000; i++) {
584 const T numer = (T)rand.nextS();
585 T denom = 0;
586 while (0 == denom) {
587 denom = (T)rand.nextS();
588 }
589 T div, mod;
590 SkTDivMod(numer, denom, &div, &mod);
591 REPORTER_ASSERT(r, numer/denom == div);
592 REPORTER_ASSERT(r, numer%denom == mod);
593 }
Brian Osman50ea3c02019-02-04 10:01:53 -0500594#endif
commit-bot@chromium.org2c86fbb2013-09-26 19:22:54 +0000595}
596
597DEF_TEST(divmod_u8, r) {
598 test_divmod<uint8_t>(r);
599}
600
601DEF_TEST(divmod_u16, r) {
602 test_divmod<uint16_t>(r);
603}
604
605DEF_TEST(divmod_u32, r) {
606 test_divmod<uint32_t>(r);
607}
608
609DEF_TEST(divmod_u64, r) {
610 test_divmod<uint64_t>(r);
611}
612
613DEF_TEST(divmod_s8, r) {
614 test_divmod<int8_t>(r);
615}
616
617DEF_TEST(divmod_s16, r) {
618 test_divmod<int16_t>(r);
619}
620
621DEF_TEST(divmod_s32, r) {
622 test_divmod<int32_t>(r);
623}
624
625DEF_TEST(divmod_s64, r) {
626 test_divmod<int64_t>(r);
627}
Robert Phillips9e380472016-10-28 12:15:03 -0400628
629static void test_nextsizepow2(skiatest::Reporter* r, size_t test, size_t expectedAns) {
630 size_t ans = GrNextSizePow2(test);
631
632 REPORTER_ASSERT(r, ans == expectedAns);
633 //SkDebugf("0x%zx -> 0x%zx (0x%zx)\n", test, ans, expectedAns);
634}
635
636DEF_TEST(GrNextSizePow2, reporter) {
637 constexpr int kNumSizeTBits = 8 * sizeof(size_t);
638
639 size_t test = 0, expectedAns = 1;
640
641 test_nextsizepow2(reporter, test, expectedAns);
642
643 test = 1; expectedAns = 1;
644
645 for (int i = 1; i < kNumSizeTBits; ++i) {
646 test_nextsizepow2(reporter, test, expectedAns);
647
648 test++;
649 expectedAns <<= 1;
650
651 test_nextsizepow2(reporter, test, expectedAns);
652
653 test = expectedAns;
654 }
655
656 // For the remaining three tests there is no higher power (of 2)
657 test = 0x1;
658 test <<= kNumSizeTBits-1;
659 test_nextsizepow2(reporter, test, test);
660
661 test++;
662 test_nextsizepow2(reporter, test, test);
663
664 test_nextsizepow2(reporter, SIZE_MAX, SIZE_MAX);
665}
Mike Reed828f1d52017-08-09 11:06:53 -0400666
Mike Reed3d5a6b52018-01-31 15:55:47 -0500667DEF_TEST(FloatSaturate32, reporter) {
Mike Reed828f1d52017-08-09 11:06:53 -0400668 const struct {
669 float fFloat;
670 int fExpectedInt;
671 } recs[] = {
672 { 0, 0 },
673 { 100.5f, 100 },
674 { (float)SK_MaxS32, SK_MaxS32FitsInFloat },
675 { (float)SK_MinS32, SK_MinS32FitsInFloat },
676 { SK_MaxS32 * 100.0f, SK_MaxS32FitsInFloat },
677 { SK_MinS32 * 100.0f, SK_MinS32FitsInFloat },
678 { SK_ScalarInfinity, SK_MaxS32FitsInFloat },
679 { SK_ScalarNegativeInfinity, SK_MinS32FitsInFloat },
680 { SK_ScalarNaN, SK_MaxS32FitsInFloat },
681 };
682
683 for (auto r : recs) {
684 int i = sk_float_saturate2int(r.fFloat);
685 REPORTER_ASSERT(reporter, r.fExpectedInt == i);
Mike Reedf6188422018-03-05 11:49:51 -0500686
Brian Osman788b9162020-02-07 10:36:46 -0500687 // Ensure that SkTPin bounds even non-finite values (including NaN)
Mike Reedf6188422018-03-05 11:49:51 -0500688 SkScalar p = SkTPin<SkScalar>(r.fFloat, 0, 100);
689 REPORTER_ASSERT(reporter, p >= 0 && p <= 100);
Mike Reed828f1d52017-08-09 11:06:53 -0400690 }
691}
Mike Reede0762232017-10-10 14:49:35 -0400692
Mike Reed3d5a6b52018-01-31 15:55:47 -0500693DEF_TEST(FloatSaturate64, reporter) {
694 const struct {
695 float fFloat;
696 int64_t fExpected64;
697 } recs[] = {
698 { 0, 0 },
699 { 100.5f, 100 },
700 { (float)SK_MaxS64, SK_MaxS64FitsInFloat },
701 { (float)SK_MinS64, SK_MinS64FitsInFloat },
702 { SK_MaxS64 * 100.0f, SK_MaxS64FitsInFloat },
703 { SK_MinS64 * 100.0f, SK_MinS64FitsInFloat },
704 { SK_ScalarInfinity, SK_MaxS64FitsInFloat },
705 { SK_ScalarNegativeInfinity, SK_MinS64FitsInFloat },
706 { SK_ScalarNaN, SK_MaxS64FitsInFloat },
707 };
708
709 for (auto r : recs) {
710 int64_t i = sk_float_saturate2int64(r.fFloat);
711 REPORTER_ASSERT(reporter, r.fExpected64 == i);
712 }
713}
714
715DEF_TEST(DoubleSaturate32, reporter) {
Mike Reede0762232017-10-10 14:49:35 -0400716 const struct {
717 double fDouble;
718 int fExpectedInt;
719 } recs[] = {
720 { 0, 0 },
721 { 100.5, 100 },
722 { SK_MaxS32, SK_MaxS32 },
723 { SK_MinS32, SK_MinS32 },
724 { SK_MaxS32 - 1, SK_MaxS32 - 1 },
725 { SK_MinS32 + 1, SK_MinS32 + 1 },
726 { SK_MaxS32 * 100.0, SK_MaxS32 },
727 { SK_MinS32 * 100.0, SK_MinS32 },
728 { SK_ScalarInfinity, SK_MaxS32 },
729 { SK_ScalarNegativeInfinity, SK_MinS32 },
730 { SK_ScalarNaN, SK_MaxS32 },
731 };
732
733 for (auto r : recs) {
734 int i = sk_double_saturate2int(r.fDouble);
735 REPORTER_ASSERT(reporter, r.fExpectedInt == i);
736 }
737}
Mike Kleind8853ec2018-03-10 11:34:53 -0500738
739#if defined(__ARM_NEON)
740 #include <arm_neon.h>
741
742 DEF_TEST(NeonU16Div255, r) {
743
744 for (int v = 0; v <= 255*255; v++) {
745 int want = (v + 127)/255;
746
747 uint16x8_t V = vdupq_n_u16(v);
748 int got = vrshrq_n_u16(vrsraq_n_u16(V, V, 8), 8)[0];
749
750 if (got != want) {
751 SkDebugf("%d -> %d, want %d\n", v, got, want);
752 }
753 REPORTER_ASSERT(r, got == want);
754 }
755 }
756
757#endif
Mike Reed31cc6d72019-02-27 16:14:37 -0500758
759DEF_TEST(unit_floats, r) {
760 // pick a non-trivial, non-pow-2 value, to test the loop
761 float v[13];
762 constexpr int N = SK_ARRAY_COUNT(v);
763
764 // empty array reports true
765 REPORTER_ASSERT(r, sk_floats_are_unit(v, 0));
766
767 SkRandom rand;
768 for (int outer = 0; outer < 1000; ++outer) {
769 // check some good values
770 for (int i = 0; i < N; ++i) {
771 v[i] = rand.nextUScalar1();
772 }
773 const int index = rand.nextU() % N;
774
775 REPORTER_ASSERT(r, sk_floats_are_unit(v, N));
776 v[index] = -0.f;
777 REPORTER_ASSERT(r, sk_floats_are_unit(v, N));
778 v[index] = 1.0f;
779 REPORTER_ASSERT(r, sk_floats_are_unit(v, N));
780
781 // check some bad values
782 const float non_norms[] = {
783 1.0000001f, 2, SK_ScalarInfinity, SK_ScalarNaN
784 };
785 for (float bad : non_norms) {
786 v[index] = bad;
787 REPORTER_ASSERT(r, !sk_floats_are_unit(v, N));
788 v[index] = -bad;
789 REPORTER_ASSERT(r, !sk_floats_are_unit(v, N));
790 }
791 }
792}