epoger@google.com | ec3ed6a | 2011-07-28 14:26:00 +0000 | [diff] [blame] | 1 | |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 2 | /* |
epoger@google.com | ec3ed6a | 2011-07-28 14:26:00 +0000 | [diff] [blame] | 3 | * Copyright 2006 The Android Open Source Project |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 4 | * |
epoger@google.com | ec3ed6a | 2011-07-28 14:26:00 +0000 | [diff] [blame] | 5 | * Use of this source code is governed by a BSD-style license that can be |
| 6 | * found in the LICENSE file. |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 7 | */ |
| 8 | |
epoger@google.com | ec3ed6a | 2011-07-28 14:26:00 +0000 | [diff] [blame] | 9 | |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 10 | #ifndef SkFixed_DEFINED |
| 11 | #define SkFixed_DEFINED |
| 12 | |
tomhudson@google.com | 889bd8b | 2011-09-27 17:38:17 +0000 | [diff] [blame] | 13 | #include "SkTypes.h" |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 14 | |
| 15 | /** \file SkFixed.h |
| 16 | |
| 17 | Types and macros for 16.16 fixed point |
| 18 | */ |
| 19 | |
| 20 | /** 32 bit signed integer used to represent fractions values with 16 bits to the right of the decimal point |
| 21 | */ |
| 22 | typedef int32_t SkFixed; |
| 23 | #define SK_Fixed1 (1 << 16) |
| 24 | #define SK_FixedHalf (1 << 15) |
| 25 | #define SK_FixedMax (0x7FFFFFFF) |
bsalomon@google.com | ee9aa30 | 2011-05-09 22:32:52 +0000 | [diff] [blame] | 26 | #define SK_FixedMin (-SK_FixedMax) |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 27 | #define SK_FixedNaN ((int) 0x80000000) |
| 28 | #define SK_FixedPI (0x3243F) |
| 29 | #define SK_FixedSqrt2 (92682) |
| 30 | #define SK_FixedTanPIOver8 (0x6A0A) |
| 31 | #define SK_FixedRoot2Over2 (0xB505) |
| 32 | |
reed@google.com | 7886ad3 | 2012-06-11 21:21:26 +0000 | [diff] [blame] | 33 | #define SkFixedToFloat(x) ((x) * 1.5258789e-5f) |
reed@google.com | 4b22602 | 2011-01-11 18:32:13 +0000 | [diff] [blame] | 34 | #if 1 |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 35 | #define SkFloatToFixed(x) ((SkFixed)((x) * SK_Fixed1)) |
reed@google.com | 4b22602 | 2011-01-11 18:32:13 +0000 | [diff] [blame] | 36 | #else |
| 37 | // pins over/under flows to max/min int32 (slower than just a cast) |
| 38 | static inline SkFixed SkFloatToFixed(float x) { |
| 39 | int64_t n = x * SK_Fixed1; |
| 40 | return (SkFixed)n; |
| 41 | } |
| 42 | #endif |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 43 | |
reed@google.com | c9af5d8 | 2012-08-03 12:45:14 +0000 | [diff] [blame] | 44 | #ifdef SK_DEBUG |
| 45 | static inline SkFixed SkFloatToFixed_Check(float x) { |
reed@google.com | dea8e25 | 2012-08-03 13:55:37 +0000 | [diff] [blame] | 46 | int64_t n64 = (int64_t)(x * SK_Fixed1); |
reed@google.com | c9af5d8 | 2012-08-03 12:45:14 +0000 | [diff] [blame] | 47 | SkFixed n32 = (SkFixed)n64; |
| 48 | SkASSERT(n64 == n32); |
| 49 | return n32; |
| 50 | } |
| 51 | #else |
| 52 | #define SkFloatToFixed_Check(x) SkFloatToFixed(x) |
| 53 | #endif |
| 54 | |
reed@google.com | 7886ad3 | 2012-06-11 21:21:26 +0000 | [diff] [blame] | 55 | #define SkFixedToDouble(x) ((x) * 1.5258789e-5) |
| 56 | #define SkDoubleToFixed(x) ((SkFixed)((x) * SK_Fixed1)) |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 57 | |
| 58 | /** 32 bit signed integer used to represent fractions values with 30 bits to the right of the decimal point |
| 59 | */ |
| 60 | typedef int32_t SkFract; |
| 61 | #define SK_Fract1 (1 << 30) |
| 62 | #define Sk_FracHalf (1 << 29) |
| 63 | #define SK_FractPIOver180 (0x11DF46A) |
| 64 | |
reed@google.com | 7886ad3 | 2012-06-11 21:21:26 +0000 | [diff] [blame] | 65 | #define SkFractToFloat(x) ((float)(x) * 0.00000000093132257f) |
| 66 | #define SkFloatToFract(x) ((SkFract)((x) * SK_Fract1)) |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 67 | |
| 68 | /** Converts an integer to a SkFixed, asserting that the result does not overflow |
| 69 | a 32 bit signed integer |
| 70 | */ |
| 71 | #ifdef SK_DEBUG |
| 72 | inline SkFixed SkIntToFixed(int n) |
| 73 | { |
| 74 | SkASSERT(n >= -32768 && n <= 32767); |
| 75 | return n << 16; |
| 76 | } |
| 77 | #else |
| 78 | // force the cast to SkFixed to ensure that the answer is signed (like the debug version) |
| 79 | #define SkIntToFixed(n) (SkFixed)((n) << 16) |
| 80 | #endif |
| 81 | |
| 82 | /** Converts a SkFixed to a SkFract, asserting that the result does not overflow |
| 83 | a 32 bit signed integer |
| 84 | */ |
| 85 | #ifdef SK_DEBUG |
| 86 | inline SkFract SkFixedToFract(SkFixed x) |
| 87 | { |
| 88 | SkASSERT(x >= (-2 << 16) && x <= (2 << 16) - 1); |
| 89 | return x << 14; |
| 90 | } |
| 91 | #else |
| 92 | #define SkFixedToFract(x) ((x) << 14) |
| 93 | #endif |
| 94 | |
| 95 | /** Returns the signed fraction of a SkFixed |
| 96 | */ |
| 97 | inline SkFixed SkFixedFraction(SkFixed x) |
| 98 | { |
| 99 | SkFixed mask = x >> 31 << 16; |
| 100 | return (x & 0xFFFF) | mask; |
| 101 | } |
| 102 | |
| 103 | /** Converts a SkFract to a SkFixed |
| 104 | */ |
| 105 | #define SkFractToFixed(x) ((x) >> 14) |
reed@google.com | 1b20280 | 2011-08-01 20:49:45 +0000 | [diff] [blame] | 106 | |
| 107 | #define SkFixedRoundToInt(x) (((x) + SK_FixedHalf) >> 16) |
| 108 | #define SkFixedCeilToInt(x) (((x) + SK_Fixed1 - 1) >> 16) |
| 109 | #define SkFixedFloorToInt(x) ((x) >> 16) |
| 110 | |
| 111 | #define SkFixedRoundToFixed(x) (((x) + SK_FixedHalf) & 0xFFFF0000) |
| 112 | #define SkFixedCeilToFixed(x) (((x) + SK_Fixed1 - 1) & 0xFFFF0000) |
| 113 | #define SkFixedFloorToFixed(x) ((x) & 0xFFFF0000) |
| 114 | |
| 115 | // DEPRECATED |
| 116 | #define SkFixedFloor(x) SkFixedFloorToInt(x) |
| 117 | #define SkFixedCeil(x) SkFixedCeilToInt(x) |
| 118 | #define SkFixedRound(x) SkFixedRoundToInt(x) |
| 119 | |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 120 | #define SkFixedAbs(x) SkAbs32(x) |
| 121 | #define SkFixedAve(a, b) (((a) + (b)) >> 1) |
| 122 | |
robertphillips@google.com | 0e6e8cc | 2013-08-15 13:43:23 +0000 | [diff] [blame] | 123 | SkFixed SkFixedMul_portable(SkFixed, SkFixed); |
| 124 | SkFract SkFractMul_portable(SkFract, SkFract); |
| 125 | inline SkFixed SkFixedSquare_portable(SkFixed value) |
| 126 | { |
| 127 | uint32_t a = SkAbs32(value); |
| 128 | uint32_t ah = a >> 16; |
| 129 | uint32_t al = a & 0xFFFF; |
| 130 | SkFixed result = ah * a + al * ah + (al * al >> 16); |
| 131 | if (result >= 0) |
| 132 | return result; |
| 133 | else // Overflow. |
| 134 | return SK_FixedMax; |
| 135 | } |
| 136 | |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 137 | #define SkFixedDiv(numer, denom) SkDivBits(numer, denom, 16) |
| 138 | SkFixed SkFixedDivInt(int32_t numer, int32_t denom); |
| 139 | SkFixed SkFixedMod(SkFixed numer, SkFixed denom); |
| 140 | #define SkFixedInvert(n) SkDivBits(SK_Fixed1, n, 16) |
| 141 | SkFixed SkFixedFastInvert(SkFixed n); |
| 142 | #define SkFixedSqrt(n) SkSqrtBits(n, 23) |
| 143 | SkFixed SkFixedMean(SkFixed a, SkFixed b); //*< returns sqrt(x*y) |
| 144 | int SkFixedMulCommon(SkFixed, int , int bias); // internal used by SkFixedMulFloor, SkFixedMulCeil, SkFixedMulRound |
| 145 | |
| 146 | #define SkFractDiv(numer, denom) SkDivBits(numer, denom, 30) |
| 147 | #define SkFractSqrt(n) SkSqrtBits(n, 30) |
| 148 | |
| 149 | SkFixed SkFixedSinCos(SkFixed radians, SkFixed* cosValueOrNull); |
| 150 | #define SkFixedSin(radians) SkFixedSinCos(radians, NULL) |
| 151 | inline SkFixed SkFixedCos(SkFixed radians) |
| 152 | { |
| 153 | SkFixed cosValue; |
| 154 | (void)SkFixedSinCos(radians, &cosValue); |
| 155 | return cosValue; |
| 156 | } |
| 157 | SkFixed SkFixedTan(SkFixed radians); |
| 158 | SkFixed SkFixedASin(SkFixed); |
| 159 | SkFixed SkFixedACos(SkFixed); |
| 160 | SkFixed SkFixedATan2(SkFixed y, SkFixed x); |
| 161 | SkFixed SkFixedExp(SkFixed); |
| 162 | SkFixed SkFixedLog(SkFixed); |
| 163 | |
| 164 | #define SK_FixedNearlyZero (SK_Fixed1 >> 12) |
| 165 | |
| 166 | inline bool SkFixedNearlyZero(SkFixed x, SkFixed tolerance = SK_FixedNearlyZero) |
| 167 | { |
| 168 | SkASSERT(tolerance > 0); |
| 169 | return SkAbs32(x) < tolerance; |
| 170 | } |
| 171 | |
| 172 | ////////////////////////////////////////////////////////////////////////////////////////////////////// |
| 173 | // Now look for ASM overrides for our portable versions (should consider putting this in its own file) |
| 174 | |
robertphillips@google.com | 0e6e8cc | 2013-08-15 13:43:23 +0000 | [diff] [blame] | 175 | #ifdef SkLONGLONG |
| 176 | inline SkFixed SkFixedMul_longlong(SkFixed a, SkFixed b) |
| 177 | { |
| 178 | return (SkFixed)((SkLONGLONG)a * b >> 16); |
| 179 | } |
| 180 | inline SkFract SkFractMul_longlong(SkFract a, SkFract b) |
| 181 | { |
| 182 | return (SkFract)((SkLONGLONG)a * b >> 30); |
| 183 | } |
| 184 | inline SkFixed SkFixedSquare_longlong(SkFixed value) |
| 185 | { |
| 186 | return (SkFixed)((SkLONGLONG)value * value >> 16); |
| 187 | } |
| 188 | #define SkFixedMul(a,b) SkFixedMul_longlong(a,b) |
| 189 | #define SkFractMul(a,b) SkFractMul_longlong(a,b) |
| 190 | #define SkFixedSquare(a) SkFixedSquare_longlong(a) |
| 191 | #endif |
| 192 | |
mtklein@google.com | 069aea7 | 2013-07-29 19:30:00 +0000 | [diff] [blame] | 193 | #if defined(SK_CPU_ARM) |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 194 | /* This guy does not handle NaN or other obscurities, but is faster than |
djsollen@google.com | 25a11e4 | 2013-07-18 19:11:30 +0000 | [diff] [blame] | 195 | than (int)(x*65536) |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 196 | */ |
| 197 | inline SkFixed SkFloatToFixed_arm(float x) |
| 198 | { |
commit-bot@chromium.org | 46ec815 | 2013-12-16 23:51:11 +0000 | [diff] [blame] | 199 | int32_t y, z; |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 200 | asm("movs %1, %3, lsl #1 \n" |
| 201 | "mov %2, #0x8E \n" |
| 202 | "sub %1, %2, %1, lsr #24 \n" |
| 203 | "mov %2, %3, lsl #8 \n" |
| 204 | "orr %2, %2, #0x80000000 \n" |
| 205 | "mov %1, %2, lsr %1 \n" |
mtklein@google.com | 069aea7 | 2013-07-29 19:30:00 +0000 | [diff] [blame] | 206 | "it cs \n" |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 207 | "rsbcs %1, %1, #0 \n" |
| 208 | : "=r"(x), "=&r"(y), "=&r"(z) |
| 209 | : "r"(x) |
| 210 | : "cc" |
| 211 | ); |
| 212 | return y; |
| 213 | } |
| 214 | inline SkFixed SkFixedMul_arm(SkFixed x, SkFixed y) |
| 215 | { |
commit-bot@chromium.org | 46ec815 | 2013-12-16 23:51:11 +0000 | [diff] [blame] | 216 | int32_t t; |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 217 | asm("smull %0, %2, %1, %3 \n" |
| 218 | "mov %0, %0, lsr #16 \n" |
| 219 | "orr %0, %0, %2, lsl #16 \n" |
| 220 | : "=r"(x), "=&r"(y), "=r"(t) |
| 221 | : "r"(x), "1"(y) |
| 222 | : |
| 223 | ); |
| 224 | return x; |
| 225 | } |
| 226 | inline SkFixed SkFixedMulAdd_arm(SkFixed x, SkFixed y, SkFixed a) |
| 227 | { |
commit-bot@chromium.org | 46ec815 | 2013-12-16 23:51:11 +0000 | [diff] [blame] | 228 | int32_t t; |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 229 | asm("smull %0, %3, %1, %4 \n" |
| 230 | "add %0, %2, %0, lsr #16 \n" |
| 231 | "add %0, %0, %3, lsl #16 \n" |
| 232 | : "=r"(x), "=&r"(y), "=&r"(a), "=r"(t) |
| 233 | : "%r"(x), "1"(y), "2"(a) |
| 234 | : |
| 235 | ); |
| 236 | return x; |
| 237 | } |
| 238 | inline SkFixed SkFractMul_arm(SkFixed x, SkFixed y) |
| 239 | { |
commit-bot@chromium.org | 46ec815 | 2013-12-16 23:51:11 +0000 | [diff] [blame] | 240 | int32_t t; |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 241 | asm("smull %0, %2, %1, %3 \n" |
| 242 | "mov %0, %0, lsr #30 \n" |
| 243 | "orr %0, %0, %2, lsl #2 \n" |
| 244 | : "=r"(x), "=&r"(y), "=r"(t) |
| 245 | : "r"(x), "1"(y) |
| 246 | : |
| 247 | ); |
| 248 | return x; |
| 249 | } |
| 250 | #undef SkFixedMul |
| 251 | #undef SkFractMul |
| 252 | #define SkFixedMul(x, y) SkFixedMul_arm(x, y) |
| 253 | #define SkFractMul(x, y) SkFractMul_arm(x, y) |
| 254 | #define SkFixedMulAdd(x, y, a) SkFixedMulAdd_arm(x, y, a) |
| 255 | |
| 256 | #undef SkFloatToFixed |
| 257 | #define SkFloatToFixed(x) SkFloatToFixed_arm(x) |
| 258 | #endif |
| 259 | |
| 260 | /////////////////////// Now define our macros to the portable versions if they weren't overridden |
| 261 | |
| 262 | #ifndef SkFixedSquare |
| 263 | #define SkFixedSquare(x) SkFixedSquare_portable(x) |
| 264 | #endif |
robertphillips@google.com | 0e6e8cc | 2013-08-15 13:43:23 +0000 | [diff] [blame] | 265 | #ifndef SkFixedMul |
| 266 | #define SkFixedMul(x, y) SkFixedMul_portable(x, y) |
| 267 | #endif |
| 268 | #ifndef SkFractMul |
| 269 | #define SkFractMul(x, y) SkFractMul_portable(x, y) |
| 270 | #endif |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 271 | #ifndef SkFixedMulAdd |
| 272 | #define SkFixedMulAdd(x, y, a) (SkFixedMul(x, y) + (a)) |
| 273 | #endif |
| 274 | |
reed@google.com | 4bc0a9d | 2012-03-07 21:47:41 +0000 | [diff] [blame] | 275 | /////////////////////////////////////////////////////////////////////////////// |
| 276 | |
| 277 | typedef int64_t SkFixed48; |
| 278 | |
| 279 | #define SkIntToFixed48(x) ((SkFixed48)(x) << 48) |
| 280 | #define SkFixed48ToInt(x) ((int)((x) >> 48)) |
| 281 | #define SkFixedToFixed48(x) ((SkFixed48)(x) << 32) |
| 282 | #define SkFixed48ToFixed(x) ((SkFixed)((x) >> 32)) |
| 283 | #define SkFloatToFixed48(x) ((SkFixed48)((x) * (65536.0f * 65536.0f * 65536.0f))) |
| 284 | |
reed@google.com | 8f4d230 | 2013-12-17 16:44:46 +0000 | [diff] [blame^] | 285 | #define SkScalarToFixed48(x) SkFloatToFixed48(x) |
reed@google.com | 4bc0a9d | 2012-03-07 21:47:41 +0000 | [diff] [blame] | 286 | |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 287 | #endif |