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 | |
Brian Osman | ff50008 | 2017-12-18 10:14:12 -0500 | [diff] [blame] | 33 | // NOTE: SkFixedToFloat is exact. SkFloatToFixed seems to lack a rounding step. For all fixed-point |
| 34 | // values, this version is as accurate as possible for (fixed -> float -> fixed). Rounding reduces |
| 35 | // accuracy if the intermediate floats are in the range that only holds integers (adding 0.5f to an |
| 36 | // odd integer then snaps to nearest even). Using double for the rounding math gives maximum |
| 37 | // accuracy for (float -> fixed -> float), but that's usually overkill. |
bungeman | f4fddfc | 2015-04-17 10:05:43 -0700 | [diff] [blame] | 38 | #define SkFixedToFloat(x) ((x) * 1.52587890625e-5f) |
Mike Reed | 56536c4 | 2017-11-27 10:11:47 -0500 | [diff] [blame] | 39 | #define SkFloatToFixed(x) sk_float_saturate2int((x) * SK_Fixed1) |
benjaminwagner | 70f1a6c | 2016-04-07 09:23:11 -0700 | [diff] [blame] | 40 | |
fmalita | e736506 | 2016-04-07 19:27:45 -0700 | [diff] [blame] | 41 | #ifdef SK_DEBUG |
| 42 | static inline SkFixed SkFloatToFixed_Check(float x) { |
| 43 | int64_t n64 = (int64_t)(x * SK_Fixed1); |
| 44 | SkFixed n32 = (SkFixed)n64; |
| 45 | SkASSERT(n64 == n32); |
| 46 | return n32; |
| 47 | } |
| 48 | #else |
| 49 | #define SkFloatToFixed_Check(x) SkFloatToFixed(x) |
| 50 | #endif |
reed@google.com | c9af5d8 | 2012-08-03 12:45:14 +0000 | [diff] [blame] | 51 | |
fmalita | e736506 | 2016-04-07 19:27:45 -0700 | [diff] [blame] | 52 | #define SkFixedToDouble(x) ((x) * 1.52587890625e-5) |
| 53 | #define SkDoubleToFixed(x) ((SkFixed)((x) * SK_Fixed1)) |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 54 | |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 55 | /** Converts an integer to a SkFixed, asserting that the result does not overflow |
| 56 | a 32 bit signed integer |
| 57 | */ |
| 58 | #ifdef SK_DEBUG |
| 59 | inline SkFixed SkIntToFixed(int n) |
| 60 | { |
| 61 | SkASSERT(n >= -32768 && n <= 32767); |
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. |
| 64 | return (unsigned)n << 16; |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 65 | } |
| 66 | #else |
benjaminwagner | 0b2a189 | 2015-11-11 08:46:34 -0800 | [diff] [blame] | 67 | // Left shifting a negative value has undefined behavior in C, so we cast to unsigned before |
| 68 | // shifting. Then we force the cast to SkFixed to ensure that the answer is signed (like the |
| 69 | // debug version). |
| 70 | #define SkIntToFixed(n) (SkFixed)((unsigned)(n) << 16) |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 71 | #endif |
| 72 | |
reed@google.com | 1b20280 | 2011-08-01 20:49:45 +0000 | [diff] [blame] | 73 | #define SkFixedRoundToInt(x) (((x) + SK_FixedHalf) >> 16) |
| 74 | #define SkFixedCeilToInt(x) (((x) + SK_Fixed1 - 1) >> 16) |
| 75 | #define SkFixedFloorToInt(x) ((x) >> 16) |
| 76 | |
liyuqian | 3f490cc | 2016-10-20 11:23:09 -0700 | [diff] [blame] | 77 | static inline SkFixed SkFixedRoundToFixed(SkFixed x) { |
| 78 | return (x + SK_FixedHalf) & 0xFFFF0000; |
| 79 | } |
| 80 | static inline SkFixed SkFixedCeilToFixed(SkFixed x) { |
| 81 | return (x + SK_Fixed1 - 1) & 0xFFFF0000; |
| 82 | } |
| 83 | static inline SkFixed SkFixedFloorToFixed(SkFixed x) { |
| 84 | return x & 0xFFFF0000; |
| 85 | } |
reed@google.com | 1b20280 | 2011-08-01 20:49:45 +0000 | [diff] [blame] | 86 | |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 87 | #define SkFixedAbs(x) SkAbs32(x) |
| 88 | #define SkFixedAve(a, b) (((a) + (b)) >> 1) |
| 89 | |
reed | 1541130 | 2016-04-27 18:45:36 -0700 | [diff] [blame] | 90 | // The divide may exceed 32 bits. Clamp to a signed 32 bit result. |
| 91 | #define SkFixedDiv(numer, denom) \ |
liyuqian | 0d2c234 | 2016-07-13 13:34:46 -0700 | [diff] [blame] | 92 | 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] | 93 | |
Mike Klein | ea000ff | 2017-11-09 12:55:32 -0500 | [diff] [blame] | 94 | static inline SkFixed SkFixedMul(SkFixed a, SkFixed b) { |
fmalita | e736506 | 2016-04-07 19:27:45 -0700 | [diff] [blame] | 95 | return (SkFixed)((int64_t)a * b >> 16); |
| 96 | } |
Mike Klein | ea000ff | 2017-11-09 12:55:32 -0500 | [diff] [blame] | 97 | |
| 98 | /////////////////////////////////////////////////////////////////////////////// |
| 99 | // Platform-specific alternatives to our portable versions. |
fmalita | e736506 | 2016-04-07 19:27:45 -0700 | [diff] [blame] | 100 | |
Ben Wagner | 3136687 | 2017-11-09 12:18:09 -0500 | [diff] [blame] | 101 | // The VCVT float-to-fixed instruction is part of the VFPv3 instruction set. |
| 102 | #if defined(__ARM_VFPV3__) |
fmalita | e736506 | 2016-04-07 19:27:45 -0700 | [diff] [blame] | 103 | /* This guy does not handle NaN or other obscurities, but is faster than |
| 104 | than (int)(x*65536). When built on Android with -Os, needs forcing |
| 105 | to inline or we lose the speed benefit. |
| 106 | */ |
| 107 | SK_ALWAYS_INLINE SkFixed SkFloatToFixed_arm(float x) |
| 108 | { |
Amaury Le Leyzour | ac0e705 | 2017-03-07 16:58:08 -0800 | [diff] [blame] | 109 | int32_t y; |
| 110 | asm("vcvt.s32.f32 %0, %0, #16": "+w"(x)); |
| 111 | memcpy(&y, &x, sizeof(y)); |
fmalita | e736506 | 2016-04-07 19:27:45 -0700 | [diff] [blame] | 112 | return y; |
| 113 | } |
Ben Wagner | 3136687 | 2017-11-09 12:18:09 -0500 | [diff] [blame] | 114 | #undef SkFloatToFixed |
| 115 | #define SkFloatToFixed(x) SkFloatToFixed_arm(x) |
| 116 | #endif |
| 117 | |
reed@google.com | 4bc0a9d | 2012-03-07 21:47:41 +0000 | [diff] [blame] | 118 | /////////////////////////////////////////////////////////////////////////////// |
| 119 | |
benjaminwagner | 6c71e0a | 2016-04-07 08:49:31 -0700 | [diff] [blame] | 120 | #define SkFixedToScalar(x) SkFixedToFloat(x) |
| 121 | #define SkScalarToFixed(x) SkFloatToFixed(x) |
| 122 | |
benjaminwagner | 6c71e0a | 2016-04-07 08:49:31 -0700 | [diff] [blame] | 123 | /////////////////////////////////////////////////////////////////////////////// |
| 124 | |
mtklein | 1794651 | 2014-11-21 12:10:33 -0800 | [diff] [blame] | 125 | typedef int64_t SkFixed3232; // 32.32 |
reed@google.com | 4bc0a9d | 2012-03-07 21:47:41 +0000 | [diff] [blame] | 126 | |
Mike Reed | 3d5a6b5 | 2018-01-31 15:55:47 -0500 | [diff] [blame] | 127 | #define SkFixed3232Max SK_MaxS64 |
Florin Malita | 63b6156 | 2017-02-10 10:42:49 -0500 | [diff] [blame] | 128 | #define SkFixed3232Min (-SkFixed3232Max) |
| 129 | |
fmalita | e736506 | 2016-04-07 19:27:45 -0700 | [diff] [blame] | 130 | #define SkIntToFixed3232(x) (SkLeftShift((SkFixed3232)(x), 32)) |
| 131 | #define SkFixed3232ToInt(x) ((int)((x) >> 32)) |
| 132 | #define SkFixedToFixed3232(x) (SkLeftShift((SkFixed3232)(x), 16)) |
| 133 | #define SkFixed3232ToFixed(x) ((SkFixed)((x) >> 16)) |
Mike Reed | 3d5a6b5 | 2018-01-31 15:55:47 -0500 | [diff] [blame] | 134 | #define SkFloatToFixed3232(x) sk_float_saturate2int64((x) * (65536.0f * 65536.0f)) |
Florin Malita | 63b6156 | 2017-02-10 10:42:49 -0500 | [diff] [blame] | 135 | #define SkFixed3232ToFloat(x) (x * (1 / (65536.0f * 65536.0f))) |
reed@google.com | 4bc0a9d | 2012-03-07 21:47:41 +0000 | [diff] [blame] | 136 | |
mtklein | 1794651 | 2014-11-21 12:10:33 -0800 | [diff] [blame] | 137 | #define SkScalarToFixed3232(x) SkFloatToFixed3232(x) |
reed@google.com | 4bc0a9d | 2012-03-07 21:47:41 +0000 | [diff] [blame] | 138 | |
reed@android.com | 8a1c16f | 2008-12-17 15:59:43 +0000 | [diff] [blame] | 139 | #endif |