blob: f1ba3a3a0c8baafc02c1cc60472523815ba1643b [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2008 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00006 */
7
reed@google.com4b163ed2012-08-07 21:35:13 +00008#include "SkMathPriv.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +00009#include "SkCordic.h"
10#include "SkFloatBits.h"
11#include "SkFloatingPoint.h"
12#include "Sk64.h"
13#include "SkScalar.h"
14
reed@google.com8f4d2302013-12-17 16:44:46 +000015const uint32_t gIEEENotANumber = 0x7FFFFFFF;
16const uint32_t gIEEEInfinity = 0x7F800000;
17const uint32_t gIEEENegativeInfinity = 0xFF800000;
reed@android.com8a1c16f2008-12-17 15:59:43 +000018
19#define sub_shift(zeros, x, n) \
20 zeros -= n; \
21 x >>= n
rmistry@google.comfbfcd562012-08-23 18:09:54 +000022
reed@android.com8a1c16f2008-12-17 15:59:43 +000023int SkCLZ_portable(uint32_t x) {
24 if (x == 0) {
25 return 32;
26 }
27
reed@android.com8a1c16f2008-12-17 15:59:43 +000028 int zeros = 31;
29 if (x & 0xFFFF0000) {
30 sub_shift(zeros, x, 16);
31 }
32 if (x & 0xFF00) {
33 sub_shift(zeros, x, 8);
34 }
35 if (x & 0xF0) {
36 sub_shift(zeros, x, 4);
37 }
38 if (x & 0xC) {
39 sub_shift(zeros, x, 2);
40 }
41 if (x & 0x2) {
42 sub_shift(zeros, x, 1);
43 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000044
45 return zeros;
46}
47
48int32_t SkMulDiv(int32_t numer1, int32_t numer2, int32_t denom) {
49 SkASSERT(denom);
50
51 Sk64 tmp;
52 tmp.setMul(numer1, numer2);
53 tmp.div(denom, Sk64::kTrunc_DivOption);
54 return tmp.get32();
55}
56
57int32_t SkMulShift(int32_t a, int32_t b, unsigned shift) {
58 int sign = SkExtractSign(a ^ b);
59
60 if (shift > 63) {
61 return sign;
62 }
63
64 a = SkAbs32(a);
65 b = SkAbs32(b);
66
67 uint32_t ah = a >> 16;
68 uint32_t al = a & 0xFFFF;
69 uint32_t bh = b >> 16;
70 uint32_t bl = b & 0xFFFF;
71
72 uint32_t A = ah * bh;
73 uint32_t B = ah * bl + al * bh;
74 uint32_t C = al * bl;
75
76 /* [ A ]
77 [ B ]
78 [ C ]
79 */
80 uint32_t lo = C + (B << 16);
81 int32_t hi = A + (B >> 16) + (lo < C);
82
83 if (sign < 0) {
84 hi = -hi - Sk32ToBool(lo);
85 lo = 0 - lo;
86 }
87
88 if (shift == 0) {
89#ifdef SK_DEBUGx
90 SkASSERT(((int32_t)lo >> 31) == hi);
91#endif
92 return lo;
93 } else if (shift >= 32) {
94 return hi >> (shift - 32);
95 } else {
96#ifdef SK_DEBUGx
97 int32_t tmp = hi >> shift;
98 SkASSERT(tmp == 0 || tmp == -1);
99#endif
100 // we want (hi << (32 - shift)) | (lo >> shift) but rounded
101 int roundBit = (lo >> (shift - 1)) & 1;
102 return ((hi << (32 - shift)) | (lo >> shift)) + roundBit;
103 }
104}
105
robertphillips@google.com0e6e8cc2013-08-15 13:43:23 +0000106SkFixed SkFixedMul_portable(SkFixed a, SkFixed b) {
107#if 0
108 Sk64 tmp;
109
110 tmp.setMul(a, b);
111 tmp.shiftRight(16);
112 return tmp.fLo;
113#elif defined(SkLONGLONG)
114 return static_cast<SkFixed>((SkLONGLONG)a * b >> 16);
115#else
116 int sa = SkExtractSign(a);
117 int sb = SkExtractSign(b);
118 // now make them positive
119 a = SkApplySign(a, sa);
120 b = SkApplySign(b, sb);
121
122 uint32_t ah = a >> 16;
123 uint32_t al = a & 0xFFFF;
124 uint32_t bh = b >> 16;
125 uint32_t bl = b & 0xFFFF;
126
127 uint32_t R = ah * b + al * bh + (al * bl >> 16);
128
129 return SkApplySign(R, sa ^ sb);
130#endif
131}
132
133SkFract SkFractMul_portable(SkFract a, SkFract b) {
134#if 0
135 Sk64 tmp;
136 tmp.setMul(a, b);
137 return tmp.getFract();
138#elif defined(SkLONGLONG)
139 return static_cast<SkFract>((SkLONGLONG)a * b >> 30);
140#else
141 int sa = SkExtractSign(a);
142 int sb = SkExtractSign(b);
143 // now make them positive
144 a = SkApplySign(a, sa);
145 b = SkApplySign(b, sb);
146
147 uint32_t ah = a >> 16;
148 uint32_t al = a & 0xFFFF;
149 uint32_t bh = b >> 16;
150 uint32_t bl = b & 0xFFFF;
151
152 uint32_t A = ah * bh;
153 uint32_t B = ah * bl + al * bh;
154 uint32_t C = al * bl;
155
156 /* [ A ]
157 [ B ]
158 [ C ]
159 */
160 uint32_t Lo = C + (B << 16);
161 uint32_t Hi = A + (B >>16) + (Lo < C);
162
163 SkASSERT((Hi >> 29) == 0); // else overflow
164
165 int32_t R = (Hi << 2) + (Lo >> 30);
166
167 return SkApplySign(R, sa ^ sb);
168#endif
169}
170
reed@android.com8a1c16f2008-12-17 15:59:43 +0000171int SkFixedMulCommon(SkFixed a, int b, int bias) {
172 // this function only works if b is 16bits
173 SkASSERT(b == (int16_t)b);
174 SkASSERT(b >= 0);
175
176 int sa = SkExtractSign(a);
177 a = SkApplySign(a, sa);
178 uint32_t ah = a >> 16;
179 uint32_t al = a & 0xFFFF;
180 uint32_t R = ah * b + ((al * b + bias) >> 16);
181 return SkApplySign(R, sa);
182}
183
184#ifdef SK_DEBUGx
185 #define TEST_FASTINVERT
186#endif
187
188SkFixed SkFixedFastInvert(SkFixed x) {
189/* Adapted (stolen) from gglRecip()
190*/
191
192 if (x == SK_Fixed1) {
193 return SK_Fixed1;
194 }
195
196 int sign = SkExtractSign(x);
197 uint32_t a = SkApplySign(x, sign);
198
199 if (a <= 2) {
200 return SkApplySign(SK_MaxS32, sign);
201 }
202
203#ifdef TEST_FASTINVERT
204 SkFixed orig = a;
205 uint32_t slow = SkFixedDiv(SK_Fixed1, a);
206#endif
207
208 // normalize a
209 int lz = SkCLZ(a);
210 a = a << lz >> 16;
211
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000212 // compute 1/a approximation (0.5 <= a < 1.0)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000213 uint32_t r = 0x17400 - a; // (2.90625 (~2.914) - 2*a) >> 1
214
215 // Newton-Raphson iteration:
216 // x = r*(2 - a*r) = ((r/2)*(1 - a*r/2))*4
217 r = ( (0x10000 - ((a*r)>>16)) * r ) >> 15;
218 r = ( (0x10000 - ((a*r)>>16)) * r ) >> (30 - lz);
219
220#ifdef TEST_FASTINVERT
221 SkDebugf("SkFixedFastInvert(%x %g) = %x %g Slow[%x %g]\n",
222 orig, orig/65536.,
223 r, r/65536.,
224 slow, slow/65536.);
225#endif
226
227 return SkApplySign(r, sign);
228}
229
230///////////////////////////////////////////////////////////////////////////////
231
232#define DIVBITS_ITER(n) \
233 case n: \
234 if ((numer = (numer << 1) - denom) >= 0) \
235 result |= 1 << (n - 1); else numer += denom
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000236
reed@android.com8a1c16f2008-12-17 15:59:43 +0000237int32_t SkDivBits(int32_t numer, int32_t denom, int shift_bias) {
238 SkASSERT(denom != 0);
239 if (numer == 0) {
240 return 0;
241 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000242
reed@android.com8a1c16f2008-12-17 15:59:43 +0000243 // make numer and denom positive, and sign hold the resulting sign
244 int32_t sign = SkExtractSign(numer ^ denom);
245 numer = SkAbs32(numer);
246 denom = SkAbs32(denom);
247
248 int nbits = SkCLZ(numer) - 1;
249 int dbits = SkCLZ(denom) - 1;
250 int bits = shift_bias - nbits + dbits;
251
252 if (bits < 0) { // answer will underflow
253 return 0;
254 }
255 if (bits > 31) { // answer will overflow
256 return SkApplySign(SK_MaxS32, sign);
257 }
258
259 denom <<= dbits;
260 numer <<= nbits;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000261
reed@android.com8a1c16f2008-12-17 15:59:43 +0000262 SkFixed result = 0;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000263
reed@android.com8a1c16f2008-12-17 15:59:43 +0000264 // do the first one
265 if ((numer -= denom) >= 0) {
266 result = 1;
267 } else {
268 numer += denom;
269 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000270
reed@android.com8a1c16f2008-12-17 15:59:43 +0000271 // Now fall into our switch statement if there are more bits to compute
272 if (bits > 0) {
273 // make room for the rest of the answer bits
274 result <<= bits;
275 switch (bits) {
276 DIVBITS_ITER(31); DIVBITS_ITER(30); DIVBITS_ITER(29);
277 DIVBITS_ITER(28); DIVBITS_ITER(27); DIVBITS_ITER(26);
278 DIVBITS_ITER(25); DIVBITS_ITER(24); DIVBITS_ITER(23);
279 DIVBITS_ITER(22); DIVBITS_ITER(21); DIVBITS_ITER(20);
280 DIVBITS_ITER(19); DIVBITS_ITER(18); DIVBITS_ITER(17);
281 DIVBITS_ITER(16); DIVBITS_ITER(15); DIVBITS_ITER(14);
282 DIVBITS_ITER(13); DIVBITS_ITER(12); DIVBITS_ITER(11);
283 DIVBITS_ITER(10); DIVBITS_ITER( 9); DIVBITS_ITER( 8);
284 DIVBITS_ITER( 7); DIVBITS_ITER( 6); DIVBITS_ITER( 5);
285 DIVBITS_ITER( 4); DIVBITS_ITER( 3); DIVBITS_ITER( 2);
286 // we merge these last two together, makes GCC make better ARM
287 default:
288 DIVBITS_ITER( 1);
289 }
290 }
291
292 if (result < 0) {
293 result = SK_MaxS32;
294 }
295 return SkApplySign(result, sign);
296}
297
298/* mod(float numer, float denom) seems to always return the sign
299 of the numer, so that's what we do too
300*/
301SkFixed SkFixedMod(SkFixed numer, SkFixed denom) {
302 int sn = SkExtractSign(numer);
303 int sd = SkExtractSign(denom);
304
305 numer = SkApplySign(numer, sn);
306 denom = SkApplySign(denom, sd);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000307
reed@android.com8a1c16f2008-12-17 15:59:43 +0000308 if (numer < denom) {
309 return SkApplySign(numer, sn);
310 } else if (numer == denom) {
311 return 0;
312 } else {
313 SkFixed div = SkFixedDiv(numer, denom);
314 return SkApplySign(SkFixedMul(denom, div & 0xFFFF), sn);
315 }
316}
317
318/* www.worldserver.com/turk/computergraphics/FixedSqrt.pdf
319*/
320int32_t SkSqrtBits(int32_t x, int count) {
321 SkASSERT(x >= 0 && count > 0 && (unsigned)count <= 30);
322
323 uint32_t root = 0;
324 uint32_t remHi = 0;
325 uint32_t remLo = x;
326
327 do {
328 root <<= 1;
329
330 remHi = (remHi<<2) | (remLo>>30);
331 remLo <<= 2;
332
333 uint32_t testDiv = (root << 1) + 1;
334 if (remHi >= testDiv) {
335 remHi -= testDiv;
336 root++;
337 }
338 } while (--count >= 0);
339
340 return root;
341}
342
343int32_t SkCubeRootBits(int32_t value, int bits) {
344 SkASSERT(bits > 0);
345
346 int sign = SkExtractSign(value);
347 value = SkApplySign(value, sign);
348
349 uint32_t root = 0;
350 uint32_t curr = (uint32_t)value >> 30;
351 value <<= 2;
352
353 do {
354 root <<= 1;
355 uint32_t guess = root * root + root;
356 guess = (guess << 1) + guess; // guess *= 3
357 if (guess < curr) {
358 curr -= guess + 1;
359 root |= 1;
360 }
361 curr = (curr << 3) | ((uint32_t)value >> 29);
362 value <<= 3;
363 } while (--bits);
364
365 return SkApplySign(root, sign);
366}
367
368SkFixed SkFixedMean(SkFixed a, SkFixed b) {
369 Sk64 tmp;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000370
reed@android.com8a1c16f2008-12-17 15:59:43 +0000371 tmp.setMul(a, b);
372 return tmp.getSqrt();
373}
374
375///////////////////////////////////////////////////////////////////////////////
376
reed@android.com8a1c16f2008-12-17 15:59:43 +0000377float SkScalarSinCos(float radians, float* cosValue) {
378 float sinValue = sk_float_sin(radians);
379
380 if (cosValue) {
381 *cosValue = sk_float_cos(radians);
382 if (SkScalarNearlyZero(*cosValue)) {
383 *cosValue = 0;
384 }
385 }
386
387 if (SkScalarNearlyZero(sinValue)) {
388 sinValue = 0;
389 }
390 return sinValue;
391}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000392
393#define INTERP_SINTABLE
394#define BUILD_TABLE_AT_RUNTIMEx
395
396#define kTableSize 256
397
398#ifdef BUILD_TABLE_AT_RUNTIME
399 static uint16_t gSkSinTable[kTableSize];
400
401 static void build_sintable(uint16_t table[]) {
402 for (int i = 0; i < kTableSize; i++) {
403 double rad = i * 3.141592653589793 / (2*kTableSize);
404 double val = sin(rad);
405 int ival = (int)(val * SK_Fixed1);
406 table[i] = SkToU16(ival);
407 }
408 }
409#else
410 #include "SkSinTable.h"
411#endif
412
413#define SK_Fract1024SizeOver2PI 0x28BE60 /* floatToFract(1024 / 2PI) */
414
415#ifdef INTERP_SINTABLE
416static SkFixed interp_table(const uint16_t table[], int index, int partial255) {
417 SkASSERT((unsigned)index < kTableSize);
418 SkASSERT((unsigned)partial255 <= 255);
419
420 SkFixed lower = table[index];
421 SkFixed upper = (index == kTableSize - 1) ? SK_Fixed1 : table[index + 1];
422
423 SkASSERT(lower < upper);
424 SkASSERT(lower >= 0);
425 SkASSERT(upper <= SK_Fixed1);
426
427 partial255 += (partial255 >> 7);
428 return lower + ((upper - lower) * partial255 >> 8);
429}
430#endif
431
432SkFixed SkFixedSinCos(SkFixed radians, SkFixed* cosValuePtr) {
433 SkASSERT(SK_ARRAY_COUNT(gSkSinTable) == kTableSize);
434
435#ifdef BUILD_TABLE_AT_RUNTIME
436 static bool gFirstTime = true;
437 if (gFirstTime) {
438 build_sintable(gSinTable);
439 gFirstTime = false;
440 }
441#endif
442
443 // make radians positive
444 SkFixed sinValue, cosValue;
445 int32_t cosSign = 0;
446 int32_t sinSign = SkExtractSign(radians);
447 radians = SkApplySign(radians, sinSign);
448 // scale it to 0...1023 ...
449
450#ifdef INTERP_SINTABLE
451 radians = SkMulDiv(radians, 2 * kTableSize * 256, SK_FixedPI);
452 int findex = radians & (kTableSize * 256 - 1);
453 int index = findex >> 8;
454 int partial = findex & 255;
455 sinValue = interp_table(gSkSinTable, index, partial);
456
457 findex = kTableSize * 256 - findex - 1;
458 index = findex >> 8;
459 partial = findex & 255;
460 cosValue = interp_table(gSkSinTable, index, partial);
461
462 int quad = ((unsigned)radians / (kTableSize * 256)) & 3;
463#else
464 radians = SkMulDiv(radians, 2 * kTableSize, SK_FixedPI);
465 int index = radians & (kTableSize - 1);
466
467 if (index == 0) {
468 sinValue = 0;
469 cosValue = SK_Fixed1;
470 } else {
471 sinValue = gSkSinTable[index];
472 cosValue = gSkSinTable[kTableSize - index];
473 }
474 int quad = ((unsigned)radians / kTableSize) & 3;
475#endif
476
477 if (quad & 1) {
478 SkTSwap<SkFixed>(sinValue, cosValue);
479 }
480 if (quad & 2) {
481 sinSign = ~sinSign;
482 }
483 if (((quad - 1) & 2) == 0) {
484 cosSign = ~cosSign;
485 }
486
487 // restore the sign for negative angles
488 sinValue = SkApplySign(sinValue, sinSign);
489 cosValue = SkApplySign(cosValue, cosSign);
490
491#ifdef SK_DEBUG
492 if (1) {
493 SkFixed sin2 = SkFixedMul(sinValue, sinValue);
494 SkFixed cos2 = SkFixedMul(cosValue, cosValue);
495 int diff = cos2 + sin2 - SK_Fixed1;
496 SkASSERT(SkAbs32(diff) <= 7);
497 }
498#endif
499
500 if (cosValuePtr) {
501 *cosValuePtr = cosValue;
502 }
503 return sinValue;
504}
505
506///////////////////////////////////////////////////////////////////////////////
507
508SkFixed SkFixedTan(SkFixed radians) { return SkCordicTan(radians); }
509SkFixed SkFixedASin(SkFixed x) { return SkCordicASin(x); }
510SkFixed SkFixedACos(SkFixed x) { return SkCordicACos(x); }
511SkFixed SkFixedATan2(SkFixed y, SkFixed x) { return SkCordicATan2(y, x); }
512SkFixed SkFixedExp(SkFixed x) { return SkCordicExp(x); }
513SkFixed SkFixedLog(SkFixed x) { return SkCordicLog(x); }