?? imports.c
字號:
/** * \file imports.c * Standard C library function wrappers. * * Imports are services which the device driver or window system or * operating system provides to the core renderer. The core renderer (Mesa) * will call these functions in order to do memory allocation, simple I/O, * etc. * * Some drivers will want to override/replace this file with something * specialized, but that'll be rare. * * Eventually, I want to move roll the glheader.h file into this. * * \todo Functions still needed: * - scanf * - qsort * - rand and RAND_MAX *//* * Mesa 3-D graphics library * Version: 7.1 * * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */#include "imports.h"#include "context.h"#include "version.h"#define MAXSTRING 4000 /* for vsnprintf() */#ifdef WIN32#define vsnprintf _vsnprintf#elif defined(__IBMC__) || defined(__IBMCPP__) || ( defined(__VMS) && __CRTL_VER < 70312000 )extern int vsnprintf(char *str, size_t count, const char *fmt, va_list arg);#ifdef __VMS#include "vsnprintf.c"#endif#endif/**********************************************************************//** \name Memory *//*@{*//** Wrapper around malloc() */void *_mesa_malloc(size_t bytes){ return malloc(bytes);}/** Wrapper around calloc() */void *_mesa_calloc(size_t bytes){ return calloc(1, bytes);}/** Wrapper around free() */void_mesa_free(void *ptr){ free(ptr);}/** * Allocate aligned memory. * * \param bytes number of bytes to allocate. * \param alignment alignment (must be greater than zero). * * Allocates extra memory to accommodate rounding up the address for * alignment and to record the real malloc address. * * \sa _mesa_align_free(). */void *_mesa_align_malloc(size_t bytes, unsigned long alignment){#if defined(HAVE_POSIX_MEMALIGN) void *mem; (void) posix_memalign(& mem, alignment, bytes); return mem;#elif defined(_WIN32) && defined(_MSC_VER) return _aligned_malloc(bytes, alignment);#else uintptr_t ptr, buf; ASSERT( alignment > 0 ); ptr = (uintptr_t) _mesa_malloc(bytes + alignment + sizeof(void *)); if (!ptr) return NULL; buf = (ptr + alignment + sizeof(void *)) & ~(uintptr_t)(alignment - 1); *(uintptr_t *)(buf - sizeof(void *)) = ptr;#ifdef DEBUG /* mark the non-aligned area */ while ( ptr < buf - sizeof(void *) ) { *(unsigned long *)ptr = 0xcdcdcdcd; ptr += sizeof(unsigned long); }#endif return (void *) buf;#endif /* defined(HAVE_POSIX_MEMALIGN) */}/** * Same as _mesa_align_malloc(), but using _mesa_calloc() instead of * _mesa_malloc() */void *_mesa_align_calloc(size_t bytes, unsigned long alignment){#if defined(HAVE_POSIX_MEMALIGN) void *mem; mem = _mesa_align_malloc(bytes, alignment); if (mem != NULL) { (void) memset(mem, 0, bytes); } return mem;#elif defined(_WIN32) && defined(_MSC_VER) void *mem; mem = _aligned_malloc(bytes, alignment); if (mem != NULL) { (void) memset(mem, 0, bytes); } return mem;#else uintptr_t ptr, buf; ASSERT( alignment > 0 ); ptr = (uintptr_t) _mesa_calloc(bytes + alignment + sizeof(void *)); if (!ptr) return NULL; buf = (ptr + alignment + sizeof(void *)) & ~(uintptr_t)(alignment - 1); *(uintptr_t *)(buf - sizeof(void *)) = ptr;#ifdef DEBUG /* mark the non-aligned area */ while ( ptr < buf - sizeof(void *) ) { *(unsigned long *)ptr = 0xcdcdcdcd; ptr += sizeof(unsigned long); }#endif return (void *)buf;#endif /* defined(HAVE_POSIX_MEMALIGN) */}/** * Free memory which was allocated with either _mesa_align_malloc() * or _mesa_align_calloc(). * \param ptr pointer to the memory to be freed. * The actual address to free is stored in the word immediately before the * address the client sees. */void_mesa_align_free(void *ptr){#if defined(HAVE_POSIX_MEMALIGN) free(ptr);#elif defined(_WIN32) && defined(_MSC_VER) _aligned_free(ptr);#else void **cubbyHole = (void **) ((char *) ptr - sizeof(void *)); void *realAddr = *cubbyHole; _mesa_free(realAddr);#endif /* defined(HAVE_POSIX_MEMALIGN) */}/** * Reallocate memory, with alignment. */void *_mesa_align_realloc(void *oldBuffer, size_t oldSize, size_t newSize, unsigned long alignment){#if defined(_WIN32) && defined(_MSC_VER) (void) oldSize; return _aligned_realloc(oldBuffer, newSize, alignment);#else const size_t copySize = (oldSize < newSize) ? oldSize : newSize; void *newBuf = _mesa_align_malloc(newSize, alignment); if (newBuf && oldBuffer && copySize > 0) { _mesa_memcpy(newBuf, oldBuffer, copySize); } if (oldBuffer) _mesa_align_free(oldBuffer); return newBuf;#endif}/** Reallocate memory */void *_mesa_realloc(void *oldBuffer, size_t oldSize, size_t newSize){ const size_t copySize = (oldSize < newSize) ? oldSize : newSize; void *newBuffer = _mesa_malloc(newSize); if (newBuffer && oldBuffer && copySize > 0) _mesa_memcpy(newBuffer, oldBuffer, copySize); if (oldBuffer) _mesa_free(oldBuffer); return newBuffer;}/** memcpy wrapper */void *_mesa_memcpy(void *dest, const void *src, size_t n){#if defined(SUNOS4) return memcpy((char *) dest, (char *) src, (int) n);#else return memcpy(dest, src, n);#endif}/** Wrapper around memset() */void_mesa_memset( void *dst, int val, size_t n ){#if defined(SUNOS4) memset( (char *) dst, (int) val, (int) n );#else memset(dst, val, n);#endif}/** * Fill memory with a constant 16bit word. * \param dst destination pointer. * \param val value. * \param n number of words. */void_mesa_memset16( unsigned short *dst, unsigned short val, size_t n ){ while (n-- > 0) *dst++ = val;}/** Wrapper around either memset() or bzero() */void_mesa_bzero( void *dst, size_t n ){#if defined(__FreeBSD__) bzero( dst, n );#else memset( dst, 0, n );#endif}/** Wrapper around memcmp() */int_mesa_memcmp( const void *s1, const void *s2, size_t n ){#if defined(SUNOS4) return memcmp( (char *) s1, (char *) s2, (int) n );#else return memcmp(s1, s2, n);#endif}/*@}*//**********************************************************************//** \name Math *//*@{*//** Wrapper around sin() */double_mesa_sin(double a){ return sin(a);}/** Single precision wrapper around sin() */float_mesa_sinf(float a){ return (float) sin((double) a);}/** Wrapper around cos() */double_mesa_cos(double a){ return cos(a);}/** Single precision wrapper around asin() */float_mesa_asinf(float x){ return (float) asin((double) x);}/** Single precision wrapper around atan() */float_mesa_atanf(float x){ return (float) atan((double) x);}/** Wrapper around sqrt() */double_mesa_sqrtd(double x){ return sqrt(x);}/* * A High Speed, Low Precision Square Root * by Paul Lalonde and Robert Dawson * from "Graphics Gems", Academic Press, 1990 * * SPARC implementation of a fast square root by table * lookup. * SPARC floating point format is as follows: * * BIT 31 30 23 22 0 * sign exponent mantissa */static short sqrttab[0x100]; /* declare table of square roots */void_mesa_init_sqrt_table(void){#if defined(USE_IEEE) && !defined(DEBUG) unsigned short i; fi_type fi; /* to access the bits of a float in C quickly */ /* we use a union defined in glheader.h */ for(i=0; i<= 0x7f; i++) { fi.i = 0; /* * Build a float with the bit pattern i as mantissa * and an exponent of 0, stored as 127 */ fi.i = (i << 16) | (127 << 23); fi.f = _mesa_sqrtd(fi.f); /* * Take the square root then strip the first 7 bits of * the mantissa into the table */ sqrttab[i] = (fi.i & 0x7fffff) >> 16; /* * Repeat the process, this time with an exponent of * 1, stored as 128 */ fi.i = 0; fi.i = (i << 16) | (128 << 23); fi.f = sqrt(fi.f); sqrttab[i+0x80] = (fi.i & 0x7fffff) >> 16; }#else (void) sqrttab; /* silence compiler warnings */#endif /*HAVE_FAST_MATH*/}/** * Single precision square root. */float_mesa_sqrtf( float x ){#if defined(USE_IEEE) && !defined(DEBUG) fi_type num; /* to access the bits of a float in C * we use a union from glheader.h */ short e; /* the exponent */ if (x == 0.0F) return 0.0F; /* check for square root of 0 */ num.f = x; e = (num.i >> 23) - 127; /* get the exponent - on a SPARC the */ /* exponent is stored with 127 added */ num.i &= 0x7fffff; /* leave only the mantissa */ if (e & 0x01) num.i |= 0x800000; /* the exponent is odd so we have to */ /* look it up in the second half of */ /* the lookup table, so we set the */ /* high bit */ e >>= 1; /* divide the exponent by two */ /* note that in C the shift */ /* operators are sign preserving */ /* for signed operands */ /* Do the table lookup, based on the quaternary mantissa, * then reconstruct the result back into a float */ num.i = ((sqrttab[num.i >> 16]) << 16) | ((e + 127) << 23); return num.f;#else return (float) _mesa_sqrtd((double) x);#endif}/** inv_sqrt - A single precision 1/sqrt routine for IEEE format floats. written by Josh Vanderhoof, based on newsgroup posts by James Van Buskirk and Vesa Karvonen.*/float_mesa_inv_sqrtf(float n){#if defined(USE_IEEE) && !defined(DEBUG) float r0, x0, y0; float r1, x1, y1; float r2, x2, y2;#if 0 /* not used, see below -BP */ float r3, x3, y3;#endif union { float f; unsigned int i; } u; unsigned int magic; /* Exponent part of the magic number - We want to: 1. subtract the bias from the exponent, 2. negate it 3. divide by two (rounding towards -inf) 4. add the bias back Which is the same as subtracting the exponent from 381 and dividing by 2. floor(-(x - 127) / 2) + 127 = floor((381 - x) / 2) */ magic = 381 << 23; /* Significand part of magic number - With the current magic number, "(magic - u.i) >> 1" will give you: for 1 <= u.f <= 2: 1.25 - u.f / 4 for 2 <= u.f <= 4: 1.00 - u.f / 8 This isn't a bad approximation of 1/sqrt. The maximum difference from 1/sqrt will be around .06. After three Newton-Raphson iterations, the maximum difference is less than 4.5e-8. (Which is actually close enough to make the following bias academic...) To get a better approximation you can add a bias to the magic number. For example, if you subtract 1/2 of the maximum difference in the first approximation (.03), you will get the following function: for 1 <= u.f <= 2: 1.22 - u.f / 4 for 2 <= u.f <= 3.76: 0.97 - u.f / 8 for 3.76 <= u.f <= 4: 0.72 - u.f / 16 (The 3.76 to 4 range is where the result is < .5.) This is the closest possible initial approximation, but with a maximum error of 8e-11 after three NR iterations, it is still not perfect. If you subtract 0.0332281 instead of .03, the maximum error will be 2.5e-11 after three NR iterations, which should be about as close as is possible. for 1 <= u.f <= 2: 1.2167719 - u.f / 4 for 2 <= u.f <= 3.73: 0.9667719 - u.f / 8 for 3.73 <= u.f <= 4: 0.7167719 - u.f / 16 */ magic -= (int)(0.0332281 * (1 << 25)); u.f = n; u.i = (magic - u.i) >> 1; /* Instead of Newton-Raphson, we use Goldschmidt's algorithm, which allows more parallelism. From what I understand, the parallelism comes at the cost of less precision, because it lets error accumulate across iterations. */ x0 = 1.0f; y0 = 0.5f * n; r0 = u.f; x1 = x0 * r0; y1 = y0 * r0 * r0; r1 = 1.5f - y1; x2 = x1 * r1; y2 = y1 * r1 * r1; r2 = 1.5f - y2;#if 1 return x2 * r2; /* we can stop here, and be conformant -BP */#else x3 = x2 * r2; y3 = y2 * r2 * r2; r3 = 1.5f - y3; return x3 * r3;#endif#else return (float) (1.0 / sqrt(n));#endif}/** Wrapper around pow() */double_mesa_pow(double x, double y){ return pow(x, y);}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -