Home | History | Annotate | Download | only in pixelflinger
      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 
     45 GGLfixed gglIntToFixed(GGLfixed i) {
     46     return i<<FIXED_BITS;
     47 }
     48 GGLfixed gglFixedToIntRound(GGLfixed f) {
     49     return (f + FIXED_HALF)>>FIXED_BITS;
     50 }
     51 GGLfixed gglFixedToIntFloor(GGLfixed f) {
     52     return f>>FIXED_BITS;
     53 }
     54 GGLfixed gglFixedToIntCeil(GGLfixed f) {
     55     return (f + ((1<<FIXED_BITS) - 1))>>FIXED_BITS;
     56 }
     57 
     58 GGLfixed gglFracx(GGLfixed v) {
     59     return v & ((1<<FIXED_BITS)-1);
     60 }
     61 GGLfixed gglFloorx(GGLfixed v) {
     62     return gglFixedToIntFloor(v)<<FIXED_BITS;
     63 }
     64 GGLfixed gglCeilx(GGLfixed v) {
     65     return gglFixedToIntCeil(v)<<FIXED_BITS;
     66 }
     67 GGLfixed gglCenterx(GGLfixed v) {
     68     return gglFloorx(v + FIXED_HALF) | FIXED_HALF;
     69 }
     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;
     96 inline GGLfixed gglRecip(GGLfixed x) {
     97     return gglRecipQ(x, 16);
     98 }
     99 
    100 inline GGLfixed gglRecip28(GGLfixed x) CONST;
    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;
    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;
    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;
    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;
    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;
    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;
    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;
    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;
    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;
    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;
    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;
    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;
    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;
    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;
    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;
    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;
    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