• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2005 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 ANDROID_GGL_FIXED_H
18 #define ANDROID_GGL_FIXED_H
19 
20 #include <math.h>
21 #include <pixelflinger/pixelflinger.h>
22 
23 // ----------------------------------------------------------------------------
24 
25 #define CONST           __attribute__((const))
26 #define ALWAYS_INLINE   __attribute__((always_inline))
27 
28 const GGLfixed FIXED_BITS = 16;
29 const GGLfixed FIXED_EPSILON  = 1;
30 const GGLfixed FIXED_ONE  = 1L<<FIXED_BITS;
31 const GGLfixed FIXED_HALF = 1L<<(FIXED_BITS-1);
32 const GGLfixed FIXED_MIN  = 0x80000000L;
33 const GGLfixed FIXED_MAX  = 0x7FFFFFFFL;
34 
35 inline GGLfixed gglIntToFixed(GGLfixed i)       ALWAYS_INLINE ;
36 inline GGLfixed gglFixedToIntRound(GGLfixed f)  ALWAYS_INLINE ;
37 inline GGLfixed gglFixedToIntFloor(GGLfixed f)  ALWAYS_INLINE ;
38 inline GGLfixed gglFixedToIntCeil(GGLfixed f)   ALWAYS_INLINE ;
39 inline GGLfixed gglFracx(GGLfixed v)            ALWAYS_INLINE ;
40 inline GGLfixed gglFloorx(GGLfixed v)           ALWAYS_INLINE ;
41 inline GGLfixed gglCeilx(GGLfixed v)            ALWAYS_INLINE ;
42 inline GGLfixed gglCenterx(GGLfixed v)          ALWAYS_INLINE ;
43 inline GGLfixed gglRoundx(GGLfixed v)           ALWAYS_INLINE ;
44 
gglIntToFixed(GGLfixed i)45 GGLfixed gglIntToFixed(GGLfixed i) {
46     return i<<FIXED_BITS;
47 }
gglFixedToIntRound(GGLfixed f)48 GGLfixed gglFixedToIntRound(GGLfixed f) {
49     return (f + FIXED_HALF)>>FIXED_BITS;
50 }
gglFixedToIntFloor(GGLfixed f)51 GGLfixed gglFixedToIntFloor(GGLfixed f) {
52     return f>>FIXED_BITS;
53 }
gglFixedToIntCeil(GGLfixed f)54 GGLfixed gglFixedToIntCeil(GGLfixed f) {
55     return (f + ((1<<FIXED_BITS) - 1))>>FIXED_BITS;
56 }
57 
gglFracx(GGLfixed v)58 GGLfixed gglFracx(GGLfixed v) {
59     return v & ((1<<FIXED_BITS)-1);
60 }
gglFloorx(GGLfixed v)61 GGLfixed gglFloorx(GGLfixed v) {
62     return gglFixedToIntFloor(v)<<FIXED_BITS;
63 }
gglCeilx(GGLfixed v)64 GGLfixed gglCeilx(GGLfixed v) {
65     return gglFixedToIntCeil(v)<<FIXED_BITS;
66 }
gglCenterx(GGLfixed v)67 GGLfixed gglCenterx(GGLfixed v) {
68     return gglFloorx(v + FIXED_HALF) | FIXED_HALF;
69 }
gglRoundx(GGLfixed v)70 GGLfixed gglRoundx(GGLfixed v) {
71     return gglFixedToIntRound(v)<<FIXED_BITS;
72 }
73 
74 // conversion from (unsigned) int, short, byte to fixed...
75 #define GGL_B_TO_X(_x)      GGLfixed( ((int32_t(_x)+1)>>1)<<10 )
76 #define GGL_S_TO_X(_x)      GGLfixed( ((int32_t(_x)+1)>>1)<<2 )
77 #define GGL_I_TO_X(_x)      GGLfixed( ((int32_t(_x)>>1)+1)>>14 )
78 #define GGL_UB_TO_X(_x)     GGLfixed(   uint32_t(_x) +      \
79                                         (uint32_t(_x)<<8) + \
80                                         (uint32_t(_x)>>7) )
81 #define GGL_US_TO_X(_x)     GGLfixed( (_x) + ((_x)>>15) )
82 #define GGL_UI_TO_X(_x)     GGLfixed( (((_x)>>1)+1)>>15 )
83 
84 // ----------------------------------------------------------------------------
85 
86 GGLfixed gglPowx(GGLfixed x, GGLfixed y) CONST;
87 GGLfixed gglSqrtx(GGLfixed a) CONST;
88 GGLfixed gglSqrtRecipx(GGLfixed x) CONST;
89 GGLfixed gglFastDivx(GGLfixed n, GGLfixed d) CONST;
90 int32_t gglMulDivi(int32_t a, int32_t b, int32_t c);
91 
92 int32_t gglRecipQNormalized(int32_t x, int* exponent);
93 int32_t gglRecipQ(GGLfixed x, int q) CONST;
94 
95 inline GGLfixed gglRecip(GGLfixed x) CONST;
gglRecip(GGLfixed x)96 inline GGLfixed gglRecip(GGLfixed x) {
97     return gglRecipQ(x, 16);
98 }
99 
100 inline GGLfixed gglRecip28(GGLfixed x) CONST;
gglRecip28(GGLfixed x)101 int32_t gglRecip28(GGLfixed x) {
102     return gglRecipQ(x, 28);
103 }
104 
105 // ----------------------------------------------------------------------------
106 
107 #if defined(__arm__) && !defined(__thumb__)
108 
109 // inline ARM implementations
110 inline GGLfixed gglMulx(GGLfixed x, GGLfixed y, int shift) CONST;
gglMulx(GGLfixed x,GGLfixed y,int shift)111 inline GGLfixed gglMulx(GGLfixed x, GGLfixed y, int shift) {
112     GGLfixed result, t;
113     if (__builtin_constant_p(shift)) {
114     asm("smull  %[lo], %[hi], %[x], %[y]            \n"
115         "movs   %[lo], %[lo], lsr %[rshift]         \n"
116         "adc    %[lo], %[lo], %[hi], lsl %[lshift]  \n"
117         : [lo]"=r"(result), [hi]"=r"(t), [x]"=r"(x)
118         : "%[x]"(x), [y]"r"(y), [lshift] "I"(32-shift), [rshift] "I"(shift)
119         : "cc"
120         );
121     } else {
122     asm("smull  %[lo], %[hi], %[x], %[y]            \n"
123         "movs   %[lo], %[lo], lsr %[rshift]         \n"
124         "adc    %[lo], %[lo], %[hi], lsl %[lshift]  \n"
125         : [lo]"=&r"(result), [hi]"=&r"(t), [x]"=&r"(x)
126         : "%[x]"(x), [y]"r"(y), [lshift] "r"(32-shift), [rshift] "r"(shift)
127         : "cc"
128         );
129     }
130     return result;
131 }
132 
133 inline GGLfixed gglMulAddx(GGLfixed x, GGLfixed y, GGLfixed a, int shift) CONST;
gglMulAddx(GGLfixed x,GGLfixed y,GGLfixed a,int shift)134 inline GGLfixed gglMulAddx(GGLfixed x, GGLfixed y, GGLfixed a, int shift) {
135     GGLfixed result, t;
136     if (__builtin_constant_p(shift)) {
137     asm("smull  %[lo], %[hi], %[x], %[y]            \n"
138         "add    %[lo], %[a],  %[lo], lsr %[rshift]  \n"
139         "add    %[lo], %[lo], %[hi], lsl %[lshift]  \n"
140         : [lo]"=&r"(result), [hi]"=&r"(t), [x]"=&r"(x)
141         : "%[x]"(x), [y]"r"(y), [a]"r"(a), [lshift] "I"(32-shift), [rshift] "I"(shift)
142         );
143     } else {
144     asm("smull  %[lo], %[hi], %[x], %[y]            \n"
145         "add    %[lo], %[a],  %[lo], lsr %[rshift]  \n"
146         "add    %[lo], %[lo], %[hi], lsl %[lshift]  \n"
147         : [lo]"=&r"(result), [hi]"=&r"(t), [x]"=&r"(x)
148         : "%[x]"(x), [y]"r"(y), [a]"r"(a), [lshift] "r"(32-shift), [rshift] "r"(shift)
149         );
150     }
151     return result;
152 }
153 
154 inline GGLfixed gglMulSubx(GGLfixed x, GGLfixed y, GGLfixed a, int shift) CONST;
gglMulSubx(GGLfixed x,GGLfixed y,GGLfixed a,int shift)155 inline GGLfixed gglMulSubx(GGLfixed x, GGLfixed y, GGLfixed a, int shift) {
156     GGLfixed result, t;
157     if (__builtin_constant_p(shift)) {
158     asm("smull  %[lo], %[hi], %[x], %[y]            \n"
159         "rsb    %[lo], %[a],  %[lo], lsr %[rshift]  \n"
160         "add    %[lo], %[lo], %[hi], lsl %[lshift]  \n"
161         : [lo]"=&r"(result), [hi]"=&r"(t), [x]"=&r"(x)
162         : "%[x]"(x), [y]"r"(y), [a]"r"(a), [lshift] "I"(32-shift), [rshift] "I"(shift)
163         );
164     } else {
165     asm("smull  %[lo], %[hi], %[x], %[y]            \n"
166         "rsb    %[lo], %[a],  %[lo], lsr %[rshift]  \n"
167         "add    %[lo], %[lo], %[hi], lsl %[lshift]  \n"
168         : [lo]"=&r"(result), [hi]"=&r"(t), [x]"=&r"(x)
169         : "%[x]"(x), [y]"r"(y), [a]"r"(a), [lshift] "r"(32-shift), [rshift] "r"(shift)
170         );
171     }
172     return result;
173 }
174 
175 inline int64_t gglMulii(int32_t x, int32_t y) CONST;
gglMulii(int32_t x,int32_t y)176 inline int64_t gglMulii(int32_t x, int32_t y)
177 {
178     // 64-bits result: r0=low, r1=high
179     union {
180         struct {
181             int32_t lo;
182             int32_t hi;
183         } s;
184         int64_t res;
185     };
186     asm("smull %0, %1, %2, %3   \n"
187         : "=r"(s.lo), "=&r"(s.hi)
188         : "%r"(x), "r"(y)
189         :
190         );
191     return res;
192 }
193 
194 #else // ----------------------------------------------------------------------
195 
196 inline GGLfixed gglMulx(GGLfixed a, GGLfixed b, int shift) CONST;
gglMulx(GGLfixed a,GGLfixed b,int shift)197 inline GGLfixed gglMulx(GGLfixed a, GGLfixed b, int shift) {
198     return GGLfixed((int64_t(a)*b + (1<<(shift-1)))>>shift);
199 }
200 inline GGLfixed gglMulAddx(GGLfixed a, GGLfixed b, GGLfixed c, int shift) CONST;
gglMulAddx(GGLfixed a,GGLfixed b,GGLfixed c,int shift)201 inline GGLfixed gglMulAddx(GGLfixed a, GGLfixed b, GGLfixed c, int shift) {
202     return GGLfixed((int64_t(a)*b)>>shift) + c;
203 }
204 inline GGLfixed gglMulSubx(GGLfixed a, GGLfixed b, GGLfixed c, int shift) CONST;
gglMulSubx(GGLfixed a,GGLfixed b,GGLfixed c,int shift)205 inline GGLfixed gglMulSubx(GGLfixed a, GGLfixed b, GGLfixed c, int shift) {
206     return GGLfixed((int64_t(a)*b)>>shift) - c;
207 }
208 inline int64_t gglMulii(int32_t a, int32_t b) CONST;
gglMulii(int32_t a,int32_t b)209 inline int64_t gglMulii(int32_t a, int32_t b) {
210     return int64_t(a)*b;
211 }
212 
213 #endif
214 
215 // ------------------------------------------------------------------------
216 
217 inline GGLfixed gglMulx(GGLfixed a, GGLfixed b) CONST;
gglMulx(GGLfixed a,GGLfixed b)218 inline GGLfixed gglMulx(GGLfixed a, GGLfixed b) {
219     return gglMulx(a, b, 16);
220 }
221 inline GGLfixed gglMulAddx(GGLfixed a, GGLfixed b, GGLfixed c) CONST;
gglMulAddx(GGLfixed a,GGLfixed b,GGLfixed c)222 inline GGLfixed gglMulAddx(GGLfixed a, GGLfixed b, GGLfixed c) {
223     return gglMulAddx(a, b, c, 16);
224 }
225 inline GGLfixed gglMulSubx(GGLfixed a, GGLfixed b, GGLfixed c) CONST;
gglMulSubx(GGLfixed a,GGLfixed b,GGLfixed c)226 inline GGLfixed gglMulSubx(GGLfixed a, GGLfixed b, GGLfixed c) {
227     return gglMulSubx(a, b, c, 16);
228 }
229 
230 // ------------------------------------------------------------------------
231 
232 inline int32_t gglClz(int32_t x) CONST;
gglClz(int32_t x)233 inline int32_t gglClz(int32_t x)
234 {
235 #if defined(__arm__) && !defined(__thumb__)
236     return __builtin_clz(x);
237 #else
238     if (!x) return 32;
239     int32_t exp = 31;
240     if (x & 0xFFFF0000) { exp -=16; x >>= 16; }
241     if (x & 0x0000ff00) { exp -= 8; x >>= 8; }
242     if (x & 0x000000f0) { exp -= 4; x >>= 4; }
243     if (x & 0x0000000c) { exp -= 2; x >>= 2; }
244     if (x & 0x00000002) { exp -= 1; }
245     return exp;
246 #endif
247 }
248 
249 // ------------------------------------------------------------------------
250 
251 int32_t gglDivQ(GGLfixed n, GGLfixed d, int32_t i) CONST;
252 
253 inline int32_t gglDivQ16(GGLfixed n, GGLfixed d) CONST;
gglDivQ16(GGLfixed n,GGLfixed d)254 inline int32_t gglDivQ16(GGLfixed n, GGLfixed d) {
255     return gglDivQ(n, d, 16);
256 }
257 
258 inline int32_t gglDivx(GGLfixed n, GGLfixed d) CONST;
gglDivx(GGLfixed n,GGLfixed d)259 inline int32_t gglDivx(GGLfixed n, GGLfixed d) {
260     return gglDivQ(n, d, 16);
261 }
262 
263 // ------------------------------------------------------------------------
264 
265 inline GGLfixed gglRecipFast(GGLfixed x) CONST;
gglRecipFast(GGLfixed x)266 inline GGLfixed gglRecipFast(GGLfixed x)
267 {
268     // This is a really bad approximation of 1/x, but it's also
269     // very fast. x must be strictly positive.
270     // if x between [0.5, 1[ , then 1/x = 3-2*x
271     // (we use 2.30 fixed-point)
272     const int32_t lz = gglClz(x);
273     return (0xC0000000 - (x << (lz - 1))) >> (30-lz);
274 }
275 
276 // ------------------------------------------------------------------------
277 
278 inline GGLfixed gglClampx(GGLfixed c) CONST;
gglClampx(GGLfixed c)279 inline GGLfixed gglClampx(GGLfixed c)
280 {
281 #if defined(__thumb__)
282     // clamp without branches
283     c &= ~(c>>31);  c = FIXED_ONE - c;
284     c &= ~(c>>31);  c = FIXED_ONE - c;
285 #else
286 #if defined(__arm__)
287     // I don't know why gcc thinks its smarter than me! The code below
288     // clamps to zero in one instruction, but gcc won't generate it and
289     // replace it by a cmp + movlt (it's quite amazing actually).
290     asm("bic %0, %1, %1, asr #31\n" : "=r"(c) : "r"(c));
291 #else
292     c &= ~(c>>31);
293 #endif
294     if (c>FIXED_ONE)
295         c = FIXED_ONE;
296 #endif
297     return c;
298 }
299 
300 // ------------------------------------------------------------------------
301 
302 #endif // ANDROID_GGL_FIXED_H
303