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" |
benjaminwagner | 70f1a6c | 2016-04-07 09:23:11 -0700 | [diff] [blame] | 12 | #include "math.h" |
| 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 | |
| 72 | #define SkFixedRoundToFixed(x) (((x) + SK_FixedHalf) & 0xFFFF0000) |
| 73 | #define SkFixedCeilToFixed(x) (((x) + SK_Fixed1 - 1) & 0xFFFF0000) |
| 74 | #define SkFixedFloorToFixed(x) ((x) & 0xFFFF0000) |
| 75 | |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 76 | #define SkFixedAbs(x) SkAbs32(x) |
| 77 | #define SkFixedAve(a, b) (((a) + (b)) >> 1) |
| 78 | |
reed | 1541130 | 2016-04-27 18:45:36 -0700 | [diff] [blame] | 79 | // The divide may exceed 32 bits. Clamp to a signed 32 bit result. |
| 80 | #define SkFixedDiv(numer, denom) \ |
| 81 | 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] | 82 | |
fmalita | e736506 | 2016-04-07 19:27:45 -0700 | [diff] [blame] | 83 | ////////////////////////////////////////////////////////////////////////////////////////////////////// |
| 84 | // Now look for ASM overrides for our portable versions (should consider putting this in its own file) |
| 85 | |
| 86 | inline SkFixed SkFixedMul_longlong(SkFixed a, SkFixed b) { |
| 87 | return (SkFixed)((int64_t)a * b >> 16); |
| 88 | } |
| 89 | #define SkFixedMul(a,b) SkFixedMul_longlong(a,b) |
| 90 | |
| 91 | |
| 92 | #if defined(SK_CPU_ARM32) |
| 93 | /* This guy does not handle NaN or other obscurities, but is faster than |
| 94 | than (int)(x*65536). When built on Android with -Os, needs forcing |
| 95 | to inline or we lose the speed benefit. |
| 96 | */ |
| 97 | SK_ALWAYS_INLINE SkFixed SkFloatToFixed_arm(float x) |
| 98 | { |
| 99 | int32_t y, z; |
| 100 | asm("movs %1, %3, lsl #1 \n" |
| 101 | "mov %2, #0x8E \n" |
| 102 | "sub %1, %2, %1, lsr #24 \n" |
| 103 | "mov %2, %3, lsl #8 \n" |
| 104 | "orr %2, %2, #0x80000000 \n" |
| 105 | "mov %1, %2, lsr %1 \n" |
| 106 | "it cs \n" |
| 107 | "rsbcs %1, %1, #0 \n" |
| 108 | : "=r"(x), "=&r"(y), "=&r"(z) |
| 109 | : "r"(x) |
| 110 | : "cc" |
| 111 | ); |
| 112 | return y; |
| 113 | } |
| 114 | inline SkFixed SkFixedMul_arm(SkFixed x, SkFixed y) |
| 115 | { |
| 116 | int32_t t; |
| 117 | asm("smull %0, %2, %1, %3 \n" |
| 118 | "mov %0, %0, lsr #16 \n" |
| 119 | "orr %0, %0, %2, lsl #16 \n" |
| 120 | : "=r"(x), "=&r"(y), "=r"(t) |
| 121 | : "r"(x), "1"(y) |
| 122 | : |
| 123 | ); |
| 124 | return x; |
| 125 | } |
| 126 | #undef SkFixedMul |
| 127 | #define SkFixedMul(x, y) SkFixedMul_arm(x, y) |
| 128 | |
| 129 | #undef SkFloatToFixed |
| 130 | #define SkFloatToFixed(x) SkFloatToFixed_arm(x) |
| 131 | #endif |
| 132 | |
reed@google.com | 4bc0a9d | 2012-03-07 21:47:41 +0000 | [diff] [blame] | 133 | /////////////////////////////////////////////////////////////////////////////// |
| 134 | |
benjaminwagner | 6c71e0a | 2016-04-07 08:49:31 -0700 | [diff] [blame] | 135 | #if SK_SCALAR_IS_FLOAT |
| 136 | |
| 137 | #define SkFixedToScalar(x) SkFixedToFloat(x) |
| 138 | #define SkScalarToFixed(x) SkFloatToFixed(x) |
| 139 | |
| 140 | #else // SK_SCALAR_IS_DOUBLE |
| 141 | |
| 142 | #define SkFixedToScalar(x) SkFixedToDouble(x) |
| 143 | #define SkScalarToFixed(x) SkDoubleToFixed(x) |
| 144 | |
| 145 | #endif |
| 146 | |
| 147 | /////////////////////////////////////////////////////////////////////////////// |
| 148 | |
mtklein | 1794651 | 2014-11-21 12:10:33 -0800 | [diff] [blame] | 149 | typedef int64_t SkFixed3232; // 32.32 |
reed@google.com | 4bc0a9d | 2012-03-07 21:47:41 +0000 | [diff] [blame] | 150 | |
fmalita | e736506 | 2016-04-07 19:27:45 -0700 | [diff] [blame] | 151 | #define SkIntToFixed3232(x) (SkLeftShift((SkFixed3232)(x), 32)) |
| 152 | #define SkFixed3232ToInt(x) ((int)((x) >> 32)) |
| 153 | #define SkFixedToFixed3232(x) (SkLeftShift((SkFixed3232)(x), 16)) |
| 154 | #define SkFixed3232ToFixed(x) ((SkFixed)((x) >> 16)) |
| 155 | #define SkFloatToFixed3232(x) ((SkFixed3232)((x) * (65536.0f * 65536.0f))) |
reed@google.com | 4bc0a9d | 2012-03-07 21:47:41 +0000 | [diff] [blame] | 156 | |
mtklein | 1794651 | 2014-11-21 12:10:33 -0800 | [diff] [blame] | 157 | #define SkScalarToFixed3232(x) SkFloatToFixed3232(x) |
reed@google.com | 4bc0a9d | 2012-03-07 21:47:41 +0000 | [diff] [blame] | 158 | |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 159 | #endif |