ggl_fixed.h revision dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0
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
28const GGLfixed FIXED_BITS = 16;
29const GGLfixed FIXED_EPSILON  = 1;
30const GGLfixed FIXED_ONE  = 1L<<FIXED_BITS;
31const GGLfixed FIXED_HALF = 1L<<(FIXED_BITS-1);
32const GGLfixed FIXED_MIN  = 0x80000000L;
33const GGLfixed FIXED_MAX  = 0x7FFFFFFFL;
34
35inline GGLfixed gglIntToFixed(GGLfixed i)       ALWAYS_INLINE ;
36inline GGLfixed gglFixedToIntRound(GGLfixed f)  ALWAYS_INLINE ;
37inline GGLfixed gglFixedToIntFloor(GGLfixed f)  ALWAYS_INLINE ;
38inline GGLfixed gglFixedToIntCeil(GGLfixed f)   ALWAYS_INLINE ;
39inline GGLfixed gglFracx(GGLfixed v)            ALWAYS_INLINE ;
40inline GGLfixed gglFloorx(GGLfixed v)           ALWAYS_INLINE ;
41inline GGLfixed gglCeilx(GGLfixed v)            ALWAYS_INLINE ;
42inline GGLfixed gglCenterx(GGLfixed v)          ALWAYS_INLINE ;
43inline GGLfixed gglRoundx(GGLfixed v)           ALWAYS_INLINE ;
44
45GGLfixed gglIntToFixed(GGLfixed i) {
46    return i<<FIXED_BITS;
47}
48GGLfixed gglFixedToIntRound(GGLfixed f) {
49    return (f + FIXED_HALF)>>FIXED_BITS;
50}
51GGLfixed gglFixedToIntFloor(GGLfixed f) {
52    return f>>FIXED_BITS;
53}
54GGLfixed gglFixedToIntCeil(GGLfixed f) {
55    return (f + ((1<<FIXED_BITS) - 1))>>FIXED_BITS;
56}
57
58GGLfixed gglFracx(GGLfixed v) {
59    return v & ((1<<FIXED_BITS)-1);
60}
61GGLfixed gglFloorx(GGLfixed v) {
62    return gglFixedToIntFloor(v)<<FIXED_BITS;
63}
64GGLfixed gglCeilx(GGLfixed v) {
65    return gglFixedToIntCeil(v)<<FIXED_BITS;
66}
67GGLfixed gglCenterx(GGLfixed v) {
68    return gglFloorx(v + FIXED_HALF) | FIXED_HALF;
69}
70GGLfixed 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
86GGLfixed gglPowx(GGLfixed x, GGLfixed y) CONST;
87GGLfixed gglSqrtx(GGLfixed a) CONST;
88GGLfixed gglSqrtRecipx(GGLfixed x) CONST;
89GGLfixed gglFastDivx(GGLfixed n, GGLfixed d) CONST;
90int32_t gglMulDivi(int32_t a, int32_t b, int32_t c);
91
92int32_t gglRecipQNormalized(int32_t x, int* exponent);
93int32_t gglRecipQ(GGLfixed x, int q) CONST;
94
95inline GGLfixed gglRecip(GGLfixed x) CONST;
96inline GGLfixed gglRecip(GGLfixed x) {
97    return gglRecipQ(x, 16);
98}
99
100inline GGLfixed gglRecip28(GGLfixed x) CONST;
101int32_t gglRecip28(GGLfixed x) {
102    return gglRecipQ(x, 28);
103}
104
105// ----------------------------------------------------------------------------
106
107#if defined(__arm__) && !defined(__thumb__)
108
109// inline ARM implementations
110inline GGLfixed gglMulx(GGLfixed x, GGLfixed y, int shift) CONST;
111inline 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
133inline GGLfixed gglMulAddx(GGLfixed x, GGLfixed y, GGLfixed a, int shift) CONST;
134inline 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
154inline GGLfixed gglMulSubx(GGLfixed x, GGLfixed y, GGLfixed a, int shift) CONST;
155inline 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
175inline int64_t gglMulii(int32_t x, int32_t y) CONST;
176inline 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
196inline GGLfixed gglMulx(GGLfixed a, GGLfixed b, int shift) CONST;
197inline GGLfixed gglMulx(GGLfixed a, GGLfixed b, int shift) {
198    return GGLfixed((int64_t(a)*b + (1<<(shift-1)))>>shift);
199}
200inline GGLfixed gglMulAddx(GGLfixed a, GGLfixed b, GGLfixed c, int shift) CONST;
201inline GGLfixed gglMulAddx(GGLfixed a, GGLfixed b, GGLfixed c, int shift) {
202    return GGLfixed((int64_t(a)*b)>>shift) + c;
203}
204inline GGLfixed gglMulSubx(GGLfixed a, GGLfixed b, GGLfixed c, int shift) CONST;
205inline GGLfixed gglMulSubx(GGLfixed a, GGLfixed b, GGLfixed c, int shift) {
206    return GGLfixed((int64_t(a)*b)>>shift) - c;
207}
208inline int64_t gglMulii(int32_t a, int32_t b) CONST;
209inline int64_t gglMulii(int32_t a, int32_t b) {
210    return int64_t(a)*b;
211}
212
213#endif
214
215// ------------------------------------------------------------------------
216
217inline GGLfixed gglMulx(GGLfixed a, GGLfixed b) CONST;
218inline GGLfixed gglMulx(GGLfixed a, GGLfixed b) {
219    return gglMulx(a, b, 16);
220}
221inline GGLfixed gglMulAddx(GGLfixed a, GGLfixed b, GGLfixed c) CONST;
222inline GGLfixed gglMulAddx(GGLfixed a, GGLfixed b, GGLfixed c) {
223    return gglMulAddx(a, b, c, 16);
224}
225inline GGLfixed gglMulSubx(GGLfixed a, GGLfixed b, GGLfixed c) CONST;
226inline GGLfixed gglMulSubx(GGLfixed a, GGLfixed b, GGLfixed c) {
227    return gglMulSubx(a, b, c, 16);
228}
229
230// ------------------------------------------------------------------------
231
232inline int32_t gglClz(int32_t x) CONST;
233inline 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
251int32_t gglDivQ(GGLfixed n, GGLfixed d, int32_t i) CONST;
252
253inline int32_t gglDivQ16(GGLfixed n, GGLfixed d) CONST;
254inline int32_t gglDivQ16(GGLfixed n, GGLfixed d) {
255    return gglDivQ(n, d, 16);
256}
257
258inline int32_t gglDivx(GGLfixed n, GGLfixed d) CONST;
259inline int32_t gglDivx(GGLfixed n, GGLfixed d) {
260    return gglDivQ(n, d, 16);
261}
262
263// ------------------------------------------------------------------------
264
265inline GGLfixed gglRecipFast(GGLfixed x) CONST;
266inline 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
278inline GGLfixed gglClampx(GGLfixed c) CONST;
279inline 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