• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef SkFixed_DEFINED
18 #define SkFixed_DEFINED
19 
20 #include "SkMath.h"
21 
22 /** \file SkFixed.h
23 
24     Types and macros for 16.16 fixed point
25 */
26 
27 /** 32 bit signed integer used to represent fractions values with 16 bits to the right of the decimal point
28 */
29 typedef int32_t             SkFixed;
30 #define SK_Fixed1           (1 << 16)
31 #define SK_FixedHalf        (1 << 15)
32 #define SK_FixedMax         (0x7FFFFFFF)
33 #define SK_FixedMin         (-SK_FixedMax)
34 #define SK_FixedNaN         ((int) 0x80000000)
35 #define SK_FixedPI          (0x3243F)
36 #define SK_FixedSqrt2       (92682)
37 #define SK_FixedTanPIOver8  (0x6A0A)
38 #define SK_FixedRoot2Over2  (0xB505)
39 
40 #ifdef SK_CAN_USE_FLOAT
41     #define SkFixedToFloat(x)   ((x) * 1.5258789e-5f)
42 #if 1
43     #define SkFloatToFixed(x)   ((SkFixed)((x) * SK_Fixed1))
44 #else
45     // pins over/under flows to max/min int32 (slower than just a cast)
SkFloatToFixed(float x)46     static inline SkFixed SkFloatToFixed(float x) {
47         int64_t n = x * SK_Fixed1;
48         return (SkFixed)n;
49     }
50 #endif
51 
52     #define SkFixedToDouble(x)  ((x) * 1.5258789e-5)
53     #define SkDoubleToFixed(x)  ((SkFixed)((x) * SK_Fixed1))
54 #endif
55 
56 /** 32 bit signed integer used to represent fractions values with 30 bits to the right of the decimal point
57 */
58 typedef int32_t             SkFract;
59 #define SK_Fract1           (1 << 30)
60 #define Sk_FracHalf         (1 << 29)
61 #define SK_FractPIOver180   (0x11DF46A)
62 
63 #ifdef SK_CAN_USE_FLOAT
64     #define SkFractToFloat(x)   ((float)(x) * 0.00000000093132257f)
65     #define SkFloatToFract(x)   ((SkFract)((x) * SK_Fract1))
66 #endif
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
SkIntToFixed(int n)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
SkFixedToFract(SkFixed x)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 */
SkFixedFraction(SkFixed x)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)
106 /** Round a SkFixed to an integer
107 */
108 #define SkFixedRound(x)     (((x) + SK_FixedHalf) >> 16)
109 #define SkFixedCeil(x)      (((x) + SK_Fixed1 - 1) >> 16)
110 #define SkFixedFloor(x)     ((x) >> 16)
111 #define SkFixedAbs(x)       SkAbs32(x)
112 #define SkFixedAve(a, b)    (((a) + (b)) >> 1)
113 
114 // The same as SkIntToFixed(SkFixedFloor(x))
115 #define SkFixedFloorToFixed(x)  ((x) & ~0xFFFF)
116 
117 SkFixed SkFixedMul_portable(SkFixed, SkFixed);
118 SkFract SkFractMul_portable(SkFract, SkFract);
SkFixedSquare_portable(SkFixed value)119 inline SkFixed SkFixedSquare_portable(SkFixed value)
120 {
121     uint32_t a = SkAbs32(value);
122     uint32_t ah = a >> 16;
123     uint32_t al = a & 0xFFFF;
124     SkFixed result = ah * a + al * ah + (al * al >> 16);
125     if (result >= 0)
126         return result;
127     else // Overflow.
128         return SK_FixedMax;
129 }
130 
131 #define SkFixedDiv(numer, denom)    SkDivBits(numer, denom, 16)
132 SkFixed SkFixedDivInt(int32_t numer, int32_t denom);
133 SkFixed SkFixedMod(SkFixed numer, SkFixed denom);
134 #define SkFixedInvert(n)            SkDivBits(SK_Fixed1, n, 16)
135 SkFixed SkFixedFastInvert(SkFixed n);
136 #define SkFixedSqrt(n)              SkSqrtBits(n, 23)
137 SkFixed SkFixedMean(SkFixed a, SkFixed b);  //*< returns sqrt(x*y)
138 int SkFixedMulCommon(SkFixed, int , int bias);  // internal used by SkFixedMulFloor, SkFixedMulCeil, SkFixedMulRound
139 
140 #define SkFractDiv(numer, denom)    SkDivBits(numer, denom, 30)
141 #define SkFractSqrt(n)              SkSqrtBits(n, 30)
142 
143 SkFixed SkFixedSinCos(SkFixed radians, SkFixed* cosValueOrNull);
144 #define SkFixedSin(radians)         SkFixedSinCos(radians, NULL)
SkFixedCos(SkFixed radians)145 inline SkFixed SkFixedCos(SkFixed radians)
146 {
147     SkFixed cosValue;
148     (void)SkFixedSinCos(radians, &cosValue);
149     return cosValue;
150 }
151 SkFixed SkFixedTan(SkFixed radians);
152 SkFixed SkFixedASin(SkFixed);
153 SkFixed SkFixedACos(SkFixed);
154 SkFixed SkFixedATan2(SkFixed y, SkFixed x);
155 SkFixed SkFixedExp(SkFixed);
156 SkFixed SkFixedLog(SkFixed);
157 
158 #define SK_FixedNearlyZero          (SK_Fixed1 >> 12)
159 
160 inline bool SkFixedNearlyZero(SkFixed x, SkFixed tolerance = SK_FixedNearlyZero)
161 {
162     SkASSERT(tolerance > 0);
163     return SkAbs32(x) < tolerance;
164 }
165 
166 //////////////////////////////////////////////////////////////////////////////////////////////////////
167 // Now look for ASM overrides for our portable versions (should consider putting this in its own file)
168 
169 #ifdef SkLONGLONG
SkFixedMul_longlong(SkFixed a,SkFixed b)170     inline SkFixed SkFixedMul_longlong(SkFixed a, SkFixed b)
171     {
172         return (SkFixed)((SkLONGLONG)a * b >> 16);
173     }
SkFractMul_longlong(SkFract a,SkFract b)174     inline SkFract SkFractMul_longlong(SkFract a, SkFract b)
175     {
176         return (SkFixed)((SkLONGLONG)a * b >> 30);
177     }
SkFixedSquare_longlong(SkFixed value)178     inline SkFixed SkFixedSquare_longlong(SkFixed value)
179     {
180         return (SkFixed)((SkLONGLONG)value * value >> 16);
181     }
182     #define SkFixedMul(a,b)     SkFixedMul_longlong(a,b)
183     #define SkFractMul(a,b)     SkFractMul_longlong(a,b)
184     #define SkFixedSquare(a)    SkFixedSquare_longlong(a)
185 #endif
186 
187 #if defined(__arm__) && !defined(__thumb__)
188     /* This guy does not handle NaN or other obscurities, but is faster than
189        than (int)(x*65536) when we only have software floats
190     */
SkFloatToFixed_arm(float x)191     inline SkFixed SkFloatToFixed_arm(float x)
192     {
193         register int32_t y, z;
194         asm("movs    %1, %3, lsl #1         \n"
195             "mov     %2, #0x8E              \n"
196             "sub     %1, %2, %1, lsr #24    \n"
197             "mov     %2, %3, lsl #8         \n"
198             "orr     %2, %2, #0x80000000    \n"
199             "mov     %1, %2, lsr %1         \n"
200             "rsbcs   %1, %1, #0             \n"
201             : "=r"(x), "=&r"(y), "=&r"(z)
202             : "r"(x)
203             : "cc"
204             );
205         return y;
206     }
SkFixedMul_arm(SkFixed x,SkFixed y)207     inline SkFixed SkFixedMul_arm(SkFixed x, SkFixed y)
208     {
209         register int32_t t;
210         asm("smull  %0, %2, %1, %3          \n"
211             "mov    %0, %0, lsr #16         \n"
212             "orr    %0, %0, %2, lsl #16     \n"
213             : "=r"(x), "=&r"(y), "=r"(t)
214             : "r"(x), "1"(y)
215             :
216             );
217         return x;
218     }
SkFixedMulAdd_arm(SkFixed x,SkFixed y,SkFixed a)219     inline SkFixed SkFixedMulAdd_arm(SkFixed x, SkFixed y, SkFixed a)
220     {
221         register int32_t t;
222         asm("smull  %0, %3, %1, %4          \n"
223             "add    %0, %2, %0, lsr #16     \n"
224             "add    %0, %0, %3, lsl #16     \n"
225             : "=r"(x), "=&r"(y), "=&r"(a), "=r"(t)
226             : "%r"(x), "1"(y), "2"(a)
227             :
228             );
229         return x;
230     }
SkFractMul_arm(SkFixed x,SkFixed y)231     inline SkFixed SkFractMul_arm(SkFixed x, SkFixed y)
232     {
233         register int32_t t;
234         asm("smull  %0, %2, %1, %3          \n"
235             "mov    %0, %0, lsr #30         \n"
236             "orr    %0, %0, %2, lsl #2      \n"
237             : "=r"(x), "=&r"(y), "=r"(t)
238             : "r"(x), "1"(y)
239             :
240             );
241         return x;
242     }
243     #undef SkFixedMul
244     #undef SkFractMul
245     #define SkFixedMul(x, y)        SkFixedMul_arm(x, y)
246     #define SkFractMul(x, y)        SkFractMul_arm(x, y)
247     #define SkFixedMulAdd(x, y, a)  SkFixedMulAdd_arm(x, y, a)
248 
249     #undef SkFloatToFixed
250     #define SkFloatToFixed(x)  SkFloatToFixed_arm(x)
251 #endif
252 
253 /////////////////////// Now define our macros to the portable versions if they weren't overridden
254 
255 #ifndef SkFixedSquare
256     #define SkFixedSquare(x)    SkFixedSquare_portable(x)
257 #endif
258 #ifndef SkFixedMul
259     #define SkFixedMul(x, y)    SkFixedMul_portable(x, y)
260 #endif
261 #ifndef SkFractMul
262     #define SkFractMul(x, y)    SkFractMul_portable(x, y)
263 #endif
264 #ifndef SkFixedMulAdd
265     #define SkFixedMulAdd(x, y, a)  (SkFixedMul(x, y) + (a))
266 #endif
267 
268 #endif
269