Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright 2006 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 
      9 #ifndef SkFDot6_DEFINED
     10 #define SkFDot6_DEFINED
     11 
     12 #include "SkFixed.h"
     13 #include "SkScalar.h"
     14 #include "SkMath.h"
     15 
     16 typedef int32_t SkFDot6;
     17 
     18 /* This uses the magic number approach suggested here:
     19  * http://stereopsis.com/sree/fpu2006.html and used in
     20  * _cairo_fixed_from_double. It does banker's rounding
     21  * (i.e. round to nearest even)
     22  */
     23 inline SkFDot6 SkScalarRoundToFDot6(SkScalar x, int shift = 0)
     24 {
     25     union {
     26         double  fDouble;
     27         int32_t fBits[2];
     28     } tmp;
     29     int fractionalBits = 6 + shift;
     30     double magic = (1LL << (52 - (fractionalBits))) * 1.5;
     31 
     32     tmp.fDouble = SkScalarToDouble(x) + magic;
     33 #ifdef SK_CPU_BENDIAN
     34     return tmp.fBits[1];
     35 #else
     36     return tmp.fBits[0];
     37 #endif
     38 }
     39 
     40 #define SK_FDot6One         (64)
     41 #define SK_FDot6Half        (32)
     42 
     43 #ifdef SK_DEBUG
     44     inline SkFDot6 SkIntToFDot6(S16CPU x) {
     45         SkASSERT(SkToS16(x) == x);
     46         return x << 6;
     47     }
     48 #else
     49     #define SkIntToFDot6(x) ((x) << 6)
     50 #endif
     51 
     52 #define SkFDot6Floor(x)     ((x) >> 6)
     53 #define SkFDot6Ceil(x)      (((x) + 63) >> 6)
     54 #define SkFDot6Round(x)     (((x) + 32) >> 6)
     55 
     56 #define SkFixedToFDot6(x)   ((x) >> 10)
     57 
     58 inline SkFixed SkFDot6ToFixed(SkFDot6 x) {
     59     SkASSERT((SkLeftShift(x, 10) >> 10) == x);
     60 
     61     return SkLeftShift(x, 10);
     62 }
     63 
     64 #define SkScalarToFDot6(x)  (SkFDot6)((x) * 64)
     65 #define SkFDot6ToScalar(x)  ((SkScalar)(x) * 0.015625f)
     66 #define SkFDot6ToFloat      SkFDot6ToScalar
     67 
     68 inline SkFixed SkFDot6Div(SkFDot6 a, SkFDot6 b) {
     69     SkASSERT(b != 0);
     70 
     71     if (a == (int16_t)a) {
     72         return SkLeftShift(a, 16) / b;
     73     } else {
     74         return SkFixedDiv(a, b);
     75     }
     76 }
     77 
     78 #include "SkFDot6Constants.h"
     79 
     80 class QuickFDot6Inverse {
     81 public:
     82     inline static SkFixed Lookup(SkFDot6 x) {
     83         SkASSERT(SkAbs32(x) < kInverseTableSize);
     84         return gFDot6INVERSE[kInverseTableSize + x];
     85     }
     86 };
     87 
     88 static inline SkFixed QuickSkFDot6Div(SkFDot6 a, SkFDot6 b) {
     89     const int kMinBits = 3;  // abs(b) should be at least (1 << kMinBits) for quick division
     90     const int kMaxBits = 31; // Number of bits available in signed int
     91     // Given abs(b) <= (1 << kMinBits), the inverse of abs(b) is at most 1 << (22 - kMinBits) in
     92     // SkFixed format. Hence abs(a) should be less than kMaxAbsA
     93     const int kMaxAbsA = 1 << (kMaxBits - (22 - kMinBits));
     94     SkFDot6 abs_a = SkAbs32(a);
     95     SkFDot6 abs_b = SkAbs32(b);
     96     if (abs_b >= (1 << kMinBits) && abs_b < kInverseTableSize && abs_a < kMaxAbsA) {
     97         SkASSERT((int64_t)a * QuickFDot6Inverse::Lookup(b) <= SK_MaxS32
     98                 && (int64_t)a * QuickFDot6Inverse::Lookup(b) >= SK_MinS32);
     99         SkFixed ourAnswer = (a * QuickFDot6Inverse::Lookup(b)) >> 6;
    100         #ifdef SK_DEBUG
    101         SkFixed directAnswer = SkFDot6Div(a, b);
    102         SkASSERT(
    103             (directAnswer == 0 && ourAnswer == 0) ||
    104             SkFixedDiv(SkAbs32(directAnswer - ourAnswer), SkAbs32(directAnswer)) <= 1 << 10
    105         );
    106         #endif
    107         return ourAnswer;
    108     } else {
    109         return SkFDot6Div(a, b);
    110     }
    111 }
    112 
    113 #endif
    114