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