reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 1 | /* |
epoger@google.com | ec3ed6a | 2011-07-28 14:26:00 +0000 | [diff] [blame] | 2 | * Copyright 2006 The Android Open Source Project |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 3 | * |
epoger@google.com | ec3ed6a | 2011-07-28 14:26:00 +0000 | [diff] [blame] | 4 | * Use of this source code is governed by a BSD-style license that can be |
| 5 | * found in the LICENSE file. |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 6 | */ |
| 7 | |
| 8 | #ifndef SkFixed_DEFINED |
| 9 | #define SkFixed_DEFINED |
| 10 | |
benjaminwagner | 6c71e0a | 2016-04-07 08:49:31 -0700 | [diff] [blame] | 11 | #include "SkScalar.h" |
Mike Klein | e9f78b4 | 2016-11-22 08:57:45 -0500 | [diff] [blame] | 12 | #include "SkSafe_math.h" |
benjaminwagner | 70f1a6c | 2016-04-07 09:23:11 -0700 | [diff] [blame] | 13 | |
tomhudson@google.com | 889bd8b | 2011-09-27 17:38:17 +0000 | [diff] [blame] | 14 | #include "SkTypes.h" |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 15 | |
| 16 | /** \file SkFixed.h |
| 17 | |
| 18 | Types and macros for 16.16 fixed point |
| 19 | */ |
| 20 | |
| 21 | /** 32 bit signed integer used to represent fractions values with 16 bits to the right of the decimal point |
| 22 | */ |
| 23 | typedef int32_t SkFixed; |
| 24 | #define SK_Fixed1 (1 << 16) |
| 25 | #define SK_FixedHalf (1 << 15) |
| 26 | #define SK_FixedMax (0x7FFFFFFF) |
bsalomon@google.com | ee9aa30 | 2011-05-09 22:32:52 +0000 | [diff] [blame] | 27 | #define SK_FixedMin (-SK_FixedMax) |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 28 | #define SK_FixedPI (0x3243F) |
| 29 | #define SK_FixedSqrt2 (92682) |
| 30 | #define SK_FixedTanPIOver8 (0x6A0A) |
| 31 | #define SK_FixedRoot2Over2 (0xB505) |
| 32 | |
bungeman | f4fddfc | 2015-04-17 10:05:43 -0700 | [diff] [blame] | 33 | #define SkFixedToFloat(x) ((x) * 1.52587890625e-5f) |
fmalita | e736506 | 2016-04-07 19:27:45 -0700 | [diff] [blame] | 34 | #define SkFloatToFixed(x) ((SkFixed)((x) * SK_Fixed1)) |
benjaminwagner | 70f1a6c | 2016-04-07 09:23:11 -0700 | [diff] [blame] | 35 | |
fmalita | e736506 | 2016-04-07 19:27:45 -0700 | [diff] [blame] | 36 | #ifdef SK_DEBUG |
| 37 | static inline SkFixed SkFloatToFixed_Check(float x) { |
| 38 | int64_t n64 = (int64_t)(x * SK_Fixed1); |
| 39 | SkFixed n32 = (SkFixed)n64; |
| 40 | SkASSERT(n64 == n32); |
| 41 | return n32; |
| 42 | } |
| 43 | #else |
| 44 | #define SkFloatToFixed_Check(x) SkFloatToFixed(x) |
| 45 | #endif |
reed@google.com | c9af5d8 | 2012-08-03 12:45:14 +0000 | [diff] [blame] | 46 | |
fmalita | e736506 | 2016-04-07 19:27:45 -0700 | [diff] [blame] | 47 | #define SkFixedToDouble(x) ((x) * 1.52587890625e-5) |
| 48 | #define SkDoubleToFixed(x) ((SkFixed)((x) * SK_Fixed1)) |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 49 | |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 50 | /** Converts an integer to a SkFixed, asserting that the result does not overflow |
| 51 | a 32 bit signed integer |
| 52 | */ |
| 53 | #ifdef SK_DEBUG |
| 54 | inline SkFixed SkIntToFixed(int n) |
| 55 | { |
| 56 | SkASSERT(n >= -32768 && n <= 32767); |
benjaminwagner | 0b2a189 | 2015-11-11 08:46:34 -0800 | [diff] [blame] | 57 | // Left shifting a negative value has undefined behavior in C, so we cast to unsigned before |
| 58 | // shifting. |
| 59 | return (unsigned)n << 16; |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 60 | } |
| 61 | #else |
benjaminwagner | 0b2a189 | 2015-11-11 08:46:34 -0800 | [diff] [blame] | 62 | // Left shifting a negative value has undefined behavior in C, so we cast to unsigned before |
| 63 | // shifting. Then we force the cast to SkFixed to ensure that the answer is signed (like the |
| 64 | // debug version). |
| 65 | #define SkIntToFixed(n) (SkFixed)((unsigned)(n) << 16) |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 66 | #endif |
| 67 | |
reed@google.com | 1b20280 | 2011-08-01 20:49:45 +0000 | [diff] [blame] | 68 | #define SkFixedRoundToInt(x) (((x) + SK_FixedHalf) >> 16) |
| 69 | #define SkFixedCeilToInt(x) (((x) + SK_Fixed1 - 1) >> 16) |
| 70 | #define SkFixedFloorToInt(x) ((x) >> 16) |
| 71 | |
liyuqian | 3f490cc | 2016-10-20 11:23:09 -0700 | [diff] [blame] | 72 | static inline SkFixed SkFixedRoundToFixed(SkFixed x) { |
| 73 | return (x + SK_FixedHalf) & 0xFFFF0000; |
| 74 | } |
| 75 | static inline SkFixed SkFixedCeilToFixed(SkFixed x) { |
| 76 | return (x + SK_Fixed1 - 1) & 0xFFFF0000; |
| 77 | } |
| 78 | static inline SkFixed SkFixedFloorToFixed(SkFixed x) { |
| 79 | return x & 0xFFFF0000; |
| 80 | } |
reed@google.com | 1b20280 | 2011-08-01 20:49:45 +0000 | [diff] [blame] | 81 | |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 82 | #define SkFixedAbs(x) SkAbs32(x) |
| 83 | #define SkFixedAve(a, b) (((a) + (b)) >> 1) |
| 84 | |
reed | 1541130 | 2016-04-27 18:45:36 -0700 | [diff] [blame] | 85 | // The divide may exceed 32 bits. Clamp to a signed 32 bit result. |
| 86 | #define SkFixedDiv(numer, denom) \ |
liyuqian | 0d2c234 | 2016-07-13 13:34:46 -0700 | [diff] [blame] | 87 | SkToS32(SkTPin<int64_t>((SkLeftShift((int64_t)(numer), 16) / (denom)), SK_MinS32, SK_MaxS32)) |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 88 | |
fmalita | e736506 | 2016-04-07 19:27:45 -0700 | [diff] [blame] | 89 | ////////////////////////////////////////////////////////////////////////////////////////////////////// |
| 90 | // Now look for ASM overrides for our portable versions (should consider putting this in its own file) |
| 91 | |
| 92 | inline SkFixed SkFixedMul_longlong(SkFixed a, SkFixed b) { |
| 93 | return (SkFixed)((int64_t)a * b >> 16); |
| 94 | } |
| 95 | #define SkFixedMul(a,b) SkFixedMul_longlong(a,b) |
| 96 | |
| 97 | |
| 98 | #if defined(SK_CPU_ARM32) |
| 99 | /* This guy does not handle NaN or other obscurities, but is faster than |
| 100 | than (int)(x*65536). When built on Android with -Os, needs forcing |
| 101 | to inline or we lose the speed benefit. |
| 102 | */ |
| 103 | SK_ALWAYS_INLINE SkFixed SkFloatToFixed_arm(float x) |
| 104 | { |
Amaury Le Leyzour | ac0e705 | 2017-03-07 16:58:08 -0800 | [diff] [blame] | 105 | int32_t y; |
| 106 | asm("vcvt.s32.f32 %0, %0, #16": "+w"(x)); |
| 107 | memcpy(&y, &x, sizeof(y)); |
fmalita | e736506 | 2016-04-07 19:27:45 -0700 | [diff] [blame] | 108 | return y; |
| 109 | } |
| 110 | inline SkFixed SkFixedMul_arm(SkFixed x, SkFixed y) |
| 111 | { |
| 112 | int32_t t; |
| 113 | asm("smull %0, %2, %1, %3 \n" |
| 114 | "mov %0, %0, lsr #16 \n" |
| 115 | "orr %0, %0, %2, lsl #16 \n" |
| 116 | : "=r"(x), "=&r"(y), "=r"(t) |
| 117 | : "r"(x), "1"(y) |
| 118 | : |
| 119 | ); |
| 120 | return x; |
| 121 | } |
| 122 | #undef SkFixedMul |
| 123 | #define SkFixedMul(x, y) SkFixedMul_arm(x, y) |
| 124 | |
| 125 | #undef SkFloatToFixed |
| 126 | #define SkFloatToFixed(x) SkFloatToFixed_arm(x) |
| 127 | #endif |
| 128 | |
reed@google.com | 4bc0a9d | 2012-03-07 21:47:41 +0000 | [diff] [blame] | 129 | /////////////////////////////////////////////////////////////////////////////// |
| 130 | |
benjaminwagner | 6c71e0a | 2016-04-07 08:49:31 -0700 | [diff] [blame] | 131 | #define SkFixedToScalar(x) SkFixedToFloat(x) |
| 132 | #define SkScalarToFixed(x) SkFloatToFixed(x) |
| 133 | |
benjaminwagner | 6c71e0a | 2016-04-07 08:49:31 -0700 | [diff] [blame] | 134 | /////////////////////////////////////////////////////////////////////////////// |
| 135 | |
mtklein | 1794651 | 2014-11-21 12:10:33 -0800 | [diff] [blame] | 136 | typedef int64_t SkFixed3232; // 32.32 |
reed@google.com | 4bc0a9d | 2012-03-07 21:47:41 +0000 | [diff] [blame] | 137 | |
Florin Malita | 63b6156 | 2017-02-10 10:42:49 -0500 | [diff] [blame] | 138 | #define SkFixed3232Max (0x7FFFFFFFFFFFFFFFLL) |
| 139 | #define SkFixed3232Min (-SkFixed3232Max) |
| 140 | |
fmalita | e736506 | 2016-04-07 19:27:45 -0700 | [diff] [blame] | 141 | #define SkIntToFixed3232(x) (SkLeftShift((SkFixed3232)(x), 32)) |
| 142 | #define SkFixed3232ToInt(x) ((int)((x) >> 32)) |
| 143 | #define SkFixedToFixed3232(x) (SkLeftShift((SkFixed3232)(x), 16)) |
| 144 | #define SkFixed3232ToFixed(x) ((SkFixed)((x) >> 16)) |
| 145 | #define SkFloatToFixed3232(x) ((SkFixed3232)((x) * (65536.0f * 65536.0f))) |
Florin Malita | 63b6156 | 2017-02-10 10:42:49 -0500 | [diff] [blame] | 146 | #define SkFixed3232ToFloat(x) (x * (1 / (65536.0f * 65536.0f))) |
reed@google.com | 4bc0a9d | 2012-03-07 21:47:41 +0000 | [diff] [blame] | 147 | |
mtklein | 1794651 | 2014-11-21 12:10:33 -0800 | [diff] [blame] | 148 | #define SkScalarToFixed3232(x) SkFloatToFixed3232(x) |
reed@google.com | 4bc0a9d | 2012-03-07 21:47:41 +0000 | [diff] [blame] | 149 | |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 150 | #endif |