Cell: fix small sampling error in sample_texture_bilinear()
[mesa.git] / src / mesa / pipe / p_util.h
1 /**************************************************************************
2 *
3 * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28 #ifndef P_UTIL_H
29 #define P_UTIL_H
30
31 #include "p_compiler.h"
32 #include <math.h>
33
34
35 #ifdef WIN32
36
37 #ifdef __cplusplus
38 extern "C"
39 {
40 #endif
41
42 void * __stdcall
43 EngAllocMem(
44 unsigned long Flags,
45 unsigned long MemSize,
46 unsigned long Tag );
47
48 void __stdcall
49 EngFreeMem(
50 void *Mem );
51
52 #ifdef __cplusplus
53 }
54 #endif
55
56 static INLINE void *
57 MALLOC( unsigned size )
58 {
59 return EngAllocMem( 0, size, 'D3AG' );
60 }
61
62 static INLINE void *
63 CALLOC( unsigned count, unsigned size )
64 {
65 void *ptr = MALLOC( count * size );
66 if( ptr ) {
67 memset( ptr, 0, count * size );
68 }
69 return ptr;
70 }
71
72 static INLINE void
73 FREE( void *ptr )
74 {
75 if( ptr ) {
76 EngFreeMem( ptr );
77 }
78 }
79
80 static INLINE void *
81 REALLOC( void *old_ptr, unsigned old_size, unsigned new_size )
82 {
83 void *new_ptr;
84 if( new_size <= old_size ) {
85 return old_ptr;
86 }
87 new_ptr = MALLOC( new_size );
88 if( new_ptr ) {
89 memcpy( new_ptr, old_ptr, old_size );
90 }
91 FREE( old_ptr );
92 return new_ptr;
93 }
94
95 #define GETENV( X ) NULL
96
97 #else /* WIN32 */
98
99 #define MALLOC( SIZE ) malloc( SIZE )
100
101 #define CALLOC( COUNT, SIZE ) calloc( COUNT, SIZE )
102
103 #define FREE( PTR ) free( PTR )
104
105 #define REALLOC( OLDPTR, OLDSIZE, NEWSIZE ) realloc( OLDPTR, NEWSIZE )
106
107 #define GETENV( X ) getenv( X )
108
109 #endif /* WIN32 */
110
111 #define MALLOC_STRUCT(T) (struct T *) MALLOC(sizeof(struct T))
112
113 #define CALLOC_STRUCT(T) (struct T *) CALLOC(1, sizeof(struct T))
114
115
116 /**
117 * Return a pointer aligned to next multiple of N bytes.
118 */
119 static INLINE void *
120 align_pointer( void *unaligned, uint alignment )
121 {
122 if (sizeof(void *) == 64) {
123 union {
124 void *p;
125 uint64 u;
126 } pu;
127 pu.p = unaligned;
128 pu.u = (pu.u + alignment - 1) & ~(uint64) (alignment - 1);
129 return pu.p;
130 }
131 else {
132 /* 32-bit pointers */
133 union {
134 void *p;
135 uint u;
136 } pu;
137 pu.p = unaligned;
138 pu.u = (pu.u + alignment - 1) & ~(alignment - 1);
139 return pu.p;
140 }
141 }
142
143 /**
144 * Return memory on given byte alignment
145 */
146 static INLINE void *
147 align_malloc(size_t bytes, uint alignment)
148 {
149 #if defined(HAVE_POSIX_MEMALIGN)
150 void *mem;
151 (void) posix_memalign(& mem, alignment, bytes);
152 return mem;
153 #else
154 char *ptr, *buf;
155
156 assert( alignment > 0 );
157
158 ptr = (char *) MALLOC(bytes + alignment + sizeof(void *));
159 if (!ptr)
160 return NULL;
161
162 buf = (char *) align_pointer( ptr + sizeof(void *), alignment );
163 *(char **)(buf - sizeof(void *)) = ptr;
164
165 return buf;
166 #endif /* defined(HAVE_POSIX_MEMALIGN) */
167 }
168
169 /**
170 * Free memory returned by align_malloc().
171 */
172 static INLINE void
173 align_free(void *ptr)
174 {
175 #if defined(HAVE_POSIX_MEMALIGN)
176 FREE(ptr);
177 #else
178 void **cubbyHole = (void **) ((char *) ptr - sizeof(void *));
179 void *realAddr = *cubbyHole;
180 FREE(realAddr);
181 #endif /* defined(HAVE_POSIX_MEMALIGN) */
182 }
183
184
185
186 #define CLAMP( X, MIN, MAX ) ( (X)<(MIN) ? (MIN) : ((X)>(MAX) ? (MAX) : (X)) )
187 #define MIN2( A, B ) ( (A)<(B) ? (A) : (B) )
188 #define MAX2( A, B ) ( (A)>(B) ? (A) : (B) )
189
190 #define Elements(x) sizeof(x)/sizeof(*(x))
191 #define Offset(TYPE, MEMBER) ((unsigned)&(((TYPE *)NULL)->MEMBER))
192
193 /**
194 * Return a pointer aligned to next multiple of 16 bytes.
195 */
196 static INLINE void *
197 align16( void *unaligned )
198 {
199 return align_pointer( unaligned, 16 );
200 }
201
202
203 static INLINE int align_int(int x, int align)
204 {
205 return (x + align - 1) & ~(align - 1);
206 }
207
208
209
210 #if defined(__MSC__) && defined(__WIN32__)
211 static INLINE unsigned ffs( unsigned u )
212 {
213 unsigned i;
214
215 if( u == 0 ) {
216 return 0;
217 }
218
219 __asm bsf eax, [u]
220 __asm inc eax
221 __asm mov [i], eax
222
223 return i;
224 }
225 #endif
226
227 union fi {
228 float f;
229 int i;
230 unsigned ui;
231 };
232
233 #define UBYTE_TO_FLOAT( ub ) ((float)(ub) / 255.0F)
234
235 #define IEEE_0996 0x3f7f0000 /* 0.996 or so */
236
237 /* This function/macro is sensitive to precision. Test very carefully
238 * if you change it!
239 */
240 #define UNCLAMPED_FLOAT_TO_UBYTE(UB, F) \
241 do { \
242 union fi __tmp; \
243 __tmp.f = (F); \
244 if (__tmp.i < 0) \
245 UB = (ubyte) 0; \
246 else if (__tmp.i >= IEEE_0996) \
247 UB = (ubyte) 255; \
248 else { \
249 __tmp.f = __tmp.f * (255.0f/256.0f) + 32768.0f; \
250 UB = (ubyte) __tmp.i; \
251 } \
252 } while (0)
253
254
255
256 static INLINE unsigned pack_ub4( unsigned char b0,
257 unsigned char b1,
258 unsigned char b2,
259 unsigned char b3 )
260 {
261 return ((((unsigned int)b0) << 0) |
262 (((unsigned int)b1) << 8) |
263 (((unsigned int)b2) << 16) |
264 (((unsigned int)b3) << 24));
265 }
266
267 static INLINE unsigned fui( float f )
268 {
269 union fi fi;
270 fi.f = f;
271 return fi.ui;
272 }
273
274 static INLINE unsigned char float_to_ubyte( float f )
275 {
276 unsigned char ub;
277 UNCLAMPED_FLOAT_TO_UBYTE(ub, f);
278 return ub;
279 }
280
281 static INLINE unsigned pack_ui32_float4( float a,
282 float b,
283 float c,
284 float d )
285 {
286 return pack_ub4( float_to_ubyte(a),
287 float_to_ubyte(b),
288 float_to_ubyte(c),
289 float_to_ubyte(d) );
290 }
291
292 #define COPY_4V( DST, SRC ) \
293 do { \
294 (DST)[0] = (SRC)[0]; \
295 (DST)[1] = (SRC)[1]; \
296 (DST)[2] = (SRC)[2]; \
297 (DST)[3] = (SRC)[3]; \
298 } while (0)
299
300
301 #define COPY_4FV( DST, SRC ) COPY_4V(DST, SRC)
302
303
304 #define ASSIGN_4V( DST, V0, V1, V2, V3 ) \
305 do { \
306 (DST)[0] = (V0); \
307 (DST)[1] = (V1); \
308 (DST)[2] = (V2); \
309 (DST)[3] = (V3); \
310 } while (0)
311
312
313 static INLINE int ifloor(float f)
314 {
315 int ai, bi;
316 double af, bf;
317 union fi u;
318
319 af = (3 << 22) + 0.5 + (double)f;
320 bf = (3 << 22) + 0.5 - (double)f;
321 u.f = (float) af; ai = u.i;
322 u.f = (float) bf; bi = u.i;
323 return (ai - bi) >> 1;
324 }
325
326
327 #if defined(__GNUC__) && defined(__i386__)
328 static INLINE int iround(float f)
329 {
330 int r;
331 __asm__ ("fistpl %0" : "=m" (r) : "t" (f) : "st");
332 return r;
333 }
334 #elif defined(__MSC__) && defined(__WIN32__)
335 static INLINE int iround(float f)
336 {
337 int r;
338 _asm {
339 fld f
340 fistp r
341 }
342 return r;
343 }
344 #else
345 #define IROUND(f) ((int) (((f) >= 0.0F) ? ((f) + 0.5F) : ((f) - 0.5F)))
346 #endif
347
348
349 /* Could maybe have an inline version of this?
350 */
351 #if defined(__GNUC__)
352 #define FABSF(x) fabsf(x)
353 #else
354 #define FABSF(x) ((float) fabs(x))
355 #endif
356
357 /* Pretty fast, and accurate.
358 * Based on code from http://www.flipcode.com/totd/
359 */
360 static INLINE float LOG2(float val)
361 {
362 union fi num;
363 int log_2;
364
365 num.f = val;
366 log_2 = ((num.i >> 23) & 255) - 128;
367 num.i &= ~(255 << 23);
368 num.i += 127 << 23;
369 num.f = ((-1.0f/3) * num.f + 2) * num.f - 2.0f/3;
370 return num.f + log_2;
371 }
372
373 #if defined(__GNUC__)
374 #define CEILF(x) ceilf(x)
375 #else
376 #define CEILF(x) ((float) ceil(x))
377 #endif
378
379 static INLINE int align(int value, int alignment)
380 {
381 return (value + alignment - 1) & ~(alignment - 1);
382 }
383
384 /* Convenient...
385 */
386 extern void _mesa_printf(const char *str, ...);
387
388
389 /* util/p_util.c
390 */
391 extern void pipe_copy_rect(ubyte * dst, unsigned cpp, unsigned dst_pitch,
392 unsigned dst_x, unsigned dst_y, unsigned width,
393 unsigned height, const ubyte * src,
394 unsigned src_pitch, unsigned src_x, unsigned src_y);
395
396
397 #endif