Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright 2008 The Android Open Source Project
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "SkMathPriv.h"
      9 #include "SkFloatBits.h"
     10 #include "SkFloatingPoint.h"
     11 #include "SkScalar.h"
     12 
     13 const uint32_t gIEEENotANumber = 0x7FFFFFFF;
     14 const uint32_t gIEEEInfinity = 0x7F800000;
     15 const uint32_t gIEEENegativeInfinity = 0xFF800000;
     16 
     17 #define sub_shift(zeros, x, n)  \
     18     zeros -= n;                 \
     19     x >>= n
     20 
     21 int SkCLZ_portable(uint32_t x) {
     22     if (x == 0) {
     23         return 32;
     24     }
     25 
     26     int zeros = 31;
     27     if (x & 0xFFFF0000) {
     28         sub_shift(zeros, x, 16);
     29     }
     30     if (x & 0xFF00) {
     31         sub_shift(zeros, x, 8);
     32     }
     33     if (x & 0xF0) {
     34         sub_shift(zeros, x, 4);
     35     }
     36     if (x & 0xC) {
     37         sub_shift(zeros, x, 2);
     38     }
     39     if (x & 0x2) {
     40         sub_shift(zeros, x, 1);
     41     }
     42 
     43     return zeros;
     44 }
     45 
     46 SkFixed SkFixedMul_portable(SkFixed a, SkFixed b) {
     47 #if defined(SkLONGLONG)
     48     return static_cast<SkFixed>((int64_t)a * b >> 16);
     49 #else
     50     int sa = SkExtractSign(a);
     51     int sb = SkExtractSign(b);
     52     // now make them positive
     53     a = SkApplySign(a, sa);
     54     b = SkApplySign(b, sb);
     55 
     56     uint32_t    ah = a >> 16;
     57     uint32_t    al = a & 0xFFFF;
     58     uint32_t bh = b >> 16;
     59     uint32_t bl = b & 0xFFFF;
     60 
     61     uint32_t R = ah * b + al * bh + (al * bl >> 16);
     62 
     63     return SkApplySign(R, sa ^ sb);
     64 #endif
     65 }
     66 
     67 ///////////////////////////////////////////////////////////////////////////////
     68 
     69 #define DIVBITS_ITER(n)                                 \
     70     case n:                                             \
     71         if ((numer = (numer << 1) - denom) >= 0)        \
     72             result |= 1 << (n - 1); else numer += denom
     73 
     74 int32_t SkDivBits(int32_t numer, int32_t denom, int shift_bias) {
     75     SkASSERT(denom != 0);
     76     if (numer == 0) {
     77         return 0;
     78     }
     79 
     80     // make numer and denom positive, and sign hold the resulting sign
     81     int32_t sign = SkExtractSign(numer ^ denom);
     82     numer = SkAbs32(numer);
     83     denom = SkAbs32(denom);
     84 
     85     int nbits = SkCLZ(numer) - 1;
     86     int dbits = SkCLZ(denom) - 1;
     87     int bits = shift_bias - nbits + dbits;
     88 
     89     if (bits < 0) {  // answer will underflow
     90         return 0;
     91     }
     92     if (bits > 31) {  // answer will overflow
     93         return SkApplySign(SK_MaxS32, sign);
     94     }
     95 
     96     denom <<= dbits;
     97     numer <<= nbits;
     98 
     99     SkFixed result = 0;
    100 
    101     // do the first one
    102     if ((numer -= denom) >= 0) {
    103         result = 1;
    104     } else {
    105         numer += denom;
    106     }
    107 
    108     // Now fall into our switch statement if there are more bits to compute
    109     if (bits > 0) {
    110         // make room for the rest of the answer bits
    111         result <<= bits;
    112         switch (bits) {
    113             DIVBITS_ITER(31); DIVBITS_ITER(30); DIVBITS_ITER(29);
    114             DIVBITS_ITER(28); DIVBITS_ITER(27); DIVBITS_ITER(26);
    115             DIVBITS_ITER(25); DIVBITS_ITER(24); DIVBITS_ITER(23);
    116             DIVBITS_ITER(22); DIVBITS_ITER(21); DIVBITS_ITER(20);
    117             DIVBITS_ITER(19); DIVBITS_ITER(18); DIVBITS_ITER(17);
    118             DIVBITS_ITER(16); DIVBITS_ITER(15); DIVBITS_ITER(14);
    119             DIVBITS_ITER(13); DIVBITS_ITER(12); DIVBITS_ITER(11);
    120             DIVBITS_ITER(10); DIVBITS_ITER( 9); DIVBITS_ITER( 8);
    121             DIVBITS_ITER( 7); DIVBITS_ITER( 6); DIVBITS_ITER( 5);
    122             DIVBITS_ITER( 4); DIVBITS_ITER( 3); DIVBITS_ITER( 2);
    123             // we merge these last two together, makes GCC make better ARM
    124             default:
    125             DIVBITS_ITER( 1);
    126         }
    127     }
    128 
    129     if (result < 0) {
    130         result = SK_MaxS32;
    131     }
    132     return SkApplySign(result, sign);
    133 }
    134 
    135 /* www.worldserver.com/turk/computergraphics/FixedSqrt.pdf
    136 */
    137 int32_t SkSqrtBits(int32_t x, int count) {
    138     SkASSERT(x >= 0 && count > 0 && (unsigned)count <= 30);
    139 
    140     uint32_t    root = 0;
    141     uint32_t    remHi = 0;
    142     uint32_t    remLo = x;
    143 
    144     do {
    145         root <<= 1;
    146 
    147         remHi = (remHi<<2) | (remLo>>30);
    148         remLo <<= 2;
    149 
    150         uint32_t testDiv = (root << 1) + 1;
    151         if (remHi >= testDiv) {
    152             remHi -= testDiv;
    153             root++;
    154         }
    155     } while (--count >= 0);
    156 
    157     return root;
    158 }
    159 
    160 ///////////////////////////////////////////////////////////////////////////////
    161 
    162 float SkScalarSinCos(float radians, float* cosValue) {
    163     float sinValue = sk_float_sin(radians);
    164 
    165     if (cosValue) {
    166         *cosValue = sk_float_cos(radians);
    167         if (SkScalarNearlyZero(*cosValue)) {
    168             *cosValue = 0;
    169         }
    170     }
    171 
    172     if (SkScalarNearlyZero(sinValue)) {
    173         sinValue = 0;
    174     }
    175     return sinValue;
    176 }
    177 
    178 #define INTERP_SINTABLE
    179 #define BUILD_TABLE_AT_RUNTIMEx
    180 
    181 #define kTableSize  256
    182 
    183 #ifdef BUILD_TABLE_AT_RUNTIME
    184     static uint16_t gSkSinTable[kTableSize];
    185 
    186     static void build_sintable(uint16_t table[]) {
    187         for (int i = 0; i < kTableSize; i++) {
    188             double  rad = i * 3.141592653589793 / (2*kTableSize);
    189             double  val = sin(rad);
    190             int     ival = (int)(val * SK_Fixed1);
    191             table[i] = SkToU16(ival);
    192         }
    193     }
    194 #else
    195     #include "SkSinTable.h"
    196 #endif
    197 
    198 #define SK_Fract1024SizeOver2PI     0x28BE60    /* floatToFract(1024 / 2PI) */
    199 
    200 #ifdef INTERP_SINTABLE
    201 static SkFixed interp_table(const uint16_t table[], int index, int partial255) {
    202     SkASSERT((unsigned)index < kTableSize);
    203     SkASSERT((unsigned)partial255 <= 255);
    204 
    205     SkFixed lower = table[index];
    206     SkFixed upper = (index == kTableSize - 1) ? SK_Fixed1 : table[index + 1];
    207 
    208     SkASSERT(lower < upper);
    209     SkASSERT(lower >= 0);
    210     SkASSERT(upper <= SK_Fixed1);
    211 
    212     partial255 += (partial255 >> 7);
    213     return lower + ((upper - lower) * partial255 >> 8);
    214 }
    215 #endif
    216 
    217 SkFixed SkFixedSinCos(SkFixed radians, SkFixed* cosValuePtr) {
    218     SkASSERT(SK_ARRAY_COUNT(gSkSinTable) == kTableSize);
    219 
    220 #ifdef BUILD_TABLE_AT_RUNTIME
    221     static bool gFirstTime = true;
    222     if (gFirstTime) {
    223         build_sintable(gSinTable);
    224         gFirstTime = false;
    225     }
    226 #endif
    227 
    228     // make radians positive
    229     SkFixed sinValue, cosValue;
    230     int32_t cosSign = 0;
    231     int32_t sinSign = SkExtractSign(radians);
    232     radians = SkApplySign(radians, sinSign);
    233     // scale it to 0...1023 ...
    234 
    235 #ifdef INTERP_SINTABLE
    236     radians = SkMulDiv(radians, 2 * kTableSize * 256, SK_FixedPI);
    237     int findex = radians & (kTableSize * 256 - 1);
    238     int index = findex >> 8;
    239     int partial = findex & 255;
    240     sinValue = interp_table(gSkSinTable, index, partial);
    241 
    242     findex = kTableSize * 256 - findex - 1;
    243     index = findex >> 8;
    244     partial = findex & 255;
    245     cosValue = interp_table(gSkSinTable, index, partial);
    246 
    247     int quad = ((unsigned)radians / (kTableSize * 256)) & 3;
    248 #else
    249     radians = SkMulDiv(radians, 2 * kTableSize, SK_FixedPI);
    250     int     index = radians & (kTableSize - 1);
    251 
    252     if (index == 0) {
    253         sinValue = 0;
    254         cosValue = SK_Fixed1;
    255     } else {
    256         sinValue = gSkSinTable[index];
    257         cosValue = gSkSinTable[kTableSize - index];
    258     }
    259     int quad = ((unsigned)radians / kTableSize) & 3;
    260 #endif
    261 
    262     if (quad & 1) {
    263         SkTSwap<SkFixed>(sinValue, cosValue);
    264     }
    265     if (quad & 2) {
    266         sinSign = ~sinSign;
    267     }
    268     if (((quad - 1) & 2) == 0) {
    269         cosSign = ~cosSign;
    270     }
    271 
    272     // restore the sign for negative angles
    273     sinValue = SkApplySign(sinValue, sinSign);
    274     cosValue = SkApplySign(cosValue, cosSign);
    275 
    276 #ifdef SK_DEBUG
    277     if (1) {
    278         SkFixed sin2 = SkFixedMul(sinValue, sinValue);
    279         SkFixed cos2 = SkFixedMul(cosValue, cosValue);
    280         int diff = cos2 + sin2 - SK_Fixed1;
    281         SkASSERT(SkAbs32(diff) <= 7);
    282     }
    283 #endif
    284 
    285     if (cosValuePtr) {
    286         *cosValuePtr = cosValue;
    287     }
    288     return sinValue;
    289 }
    290