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