1
2/*
3 * Copyright 2006 The Android Open Source Project
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9
10#ifndef SkFixed_DEFINED
11#define SkFixed_DEFINED
12
13#include "SkTypes.h"
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*/
22typedef int32_t             SkFixed;
23#define SK_Fixed1           (1 << 16)
24#define SK_FixedHalf        (1 << 15)
25#define SK_FixedMax         (0x7FFFFFFF)
26#define SK_FixedMin         (-SK_FixedMax)
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
33#define SkFixedToFloat(x)   ((x) * 1.5258789e-5f)
34#if 1
35    #define SkFloatToFixed(x)   ((SkFixed)((x) * SK_Fixed1))
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
43
44#ifdef SK_DEBUG
45    static inline SkFixed SkFloatToFixed_Check(float x) {
46        int64_t n64 = (int64_t)(x * SK_Fixed1);
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
55#define SkFixedToDouble(x)  ((x) * 1.5258789e-5)
56#define SkDoubleToFixed(x)  ((SkFixed)((x) * SK_Fixed1))
57
58/** 32 bit signed integer used to represent fractions values with 30 bits to the right of the decimal point
59*/
60typedef int32_t             SkFract;
61#define SK_Fract1           (1 << 30)
62#define Sk_FracHalf         (1 << 29)
63#define SK_FractPIOver180   (0x11DF46A)
64
65#define SkFractToFloat(x)   ((float)(x) * 0.00000000093132257f)
66#define SkFloatToFract(x)   ((SkFract)((x) * SK_Fract1))
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*/
97inline 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)
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
120#define SkFixedAbs(x)       SkAbs32(x)
121#define SkFixedAve(a, b)    (((a) + (b)) >> 1)
122
123SkFixed SkFixedMul_portable(SkFixed, SkFixed);
124SkFract SkFractMul_portable(SkFract, SkFract);
125inline 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
137#define SkFixedDiv(numer, denom)    SkDivBits(numer, denom, 16)
138SkFixed SkFixedDivInt(int32_t numer, int32_t denom);
139SkFixed SkFixedMod(SkFixed numer, SkFixed denom);
140#define SkFixedInvert(n)            SkDivBits(SK_Fixed1, n, 16)
141SkFixed SkFixedFastInvert(SkFixed n);
142#define SkFixedSqrt(n)              SkSqrtBits(n, 23)
143SkFixed SkFixedMean(SkFixed a, SkFixed b);  //*< returns sqrt(x*y)
144int 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
149SkFixed SkFixedSinCos(SkFixed radians, SkFixed* cosValueOrNull);
150#define SkFixedSin(radians)         SkFixedSinCos(radians, NULL)
151inline SkFixed SkFixedCos(SkFixed radians)
152{
153    SkFixed cosValue;
154    (void)SkFixedSinCos(radians, &cosValue);
155    return cosValue;
156}
157SkFixed SkFixedTan(SkFixed radians);
158SkFixed SkFixedASin(SkFixed);
159SkFixed SkFixedACos(SkFixed);
160SkFixed SkFixedATan2(SkFixed y, SkFixed x);
161SkFixed SkFixedExp(SkFixed);
162SkFixed SkFixedLog(SkFixed);
163
164#define SK_FixedNearlyZero          (SK_Fixed1 >> 12)
165
166inline 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
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
193#if defined(SK_CPU_ARM)
194    /* This guy does not handle NaN or other obscurities, but is faster than
195       than (int)(x*65536)
196    */
197    inline SkFixed SkFloatToFixed_arm(float x)
198    {
199        register int32_t y, z;
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"
206            "it cs                          \n"
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    {
216        register int32_t t;
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    {
228        register int32_t t;
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    {
240        register int32_t t;
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
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
271#ifndef SkFixedMulAdd
272    #define SkFixedMulAdd(x, y, a)  (SkFixedMul(x, y) + (a))
273#endif
274
275///////////////////////////////////////////////////////////////////////////////
276
277typedef 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
285#ifdef SK_SCALAR_IS_FLOAT
286    #define SkScalarToFixed48(x)    SkFloatToFixed48(x)
287#else
288    #define SkScalarToFixed48(x)    SkFixedToFixed48(x)
289#endif
290
291#endif
292