GMISC invsqrt() function.

Fix a 64bit processor bug.
Add support for processors where the floating point and integer endianness don't match.
Add support for processors with a non-standard floating point format.
Update gdisp_streaming demo with extra comments to reflect the above changes.
This commit is contained in:
inmarket 2013-10-24 15:03:47 +10:00
parent 21afd2b8f1
commit e6f17baf61
5 changed files with 97 additions and 29 deletions

View File

@ -35,9 +35,11 @@
/* Builtin Fonts */
#define GDISP_INCLUDE_FONT_UI2 FALSE
#define GFX_USE_GMISC TRUE
#define GMISC_NEED_FIXEDTRIG FALSE
#define GMISC_NEED_FASTTRIG FALSE
#define GMISC_NEED_INVSQRT TRUE
#define GFX_USE_GMISC TRUE
#define GMISC_NEED_FIXEDTRIG FALSE
#define GMISC_NEED_FASTTRIG FALSE
#define GMISC_NEED_INVSQRT TRUE
//#define GDISP_INVSQRT_MIXED_ENDIAN TRUE
//#define GDISP_INVSQRT_REAL_SLOW TRUE
#endif /* _GFXCONF_H */

View File

@ -31,15 +31,29 @@
#include "gfx.h"
#include <math.h>
#define Lightgrey ()
#define Midgrey ()
#define Darkgrey (HTML2COLOR(0x303030))
#define BALLCOLOR1 Red
#define BALLCOLOR2 Yellow
#define WALLCOLOR HTML2COLOR(0x303030)
#define BACKCOLOR HTML2COLOR(0xC0C0C0)
#define FLOORCOLOR HTML2COLOR(0x606060)
/**
* NOTE:
*
* This demo uses floating point operations. Don't expect it to work with any
* speed unless your processor has an FPU.
*
* If you see garbage inside the ball as it is running rather than the red and yellow
* checkerboard pattern then the fast invsqrt() function in GMISC does not work on
* your processor.
*
* You can modify the implementation of invsqrt() by firstly defining
* #define GDISP_INVSQRT_MIXED_ENDIAN TRUE
* in your gfxconf.h file.
*
* If it still doesn't work then instead define
* #define GDISP_INVSQRT_REAL_SLOW TRUE
* in your gfxconf.h file. This should always work although it will probably be slow.
*/
#define BALLCOLOR1 Red
#define BALLCOLOR2 Yellow
#define WALLCOLOR HTML2COLOR(0x303030)
#define BACKCOLOR HTML2COLOR(0xC0C0C0)
#define FLOORCOLOR HTML2COLOR(0x606060)
#define SHADOWALPHA (255-255*0.2)
int main(void) {

View File

@ -181,11 +181,12 @@
#define GWIN_CONSOLE_USE_BASESTREAM FALSE
#define GWIN_CONSOLE_USE_FLOAT FALSE
#define GWIN_NEED_IMAGE_ANIMATION FALSE
#define GDISP_INVSQRT_MIXED_ENDIAN FALSE
#define GDISP_INVSQRT_REAL_SLOW FALSE
*/
/* Optional Low Level Driver Definitions */
/*
#define GDISP_USE_CUSTOM_BOARD FALSE
#define GDISP_SCREEN_WIDTH 320
#define GDISP_SCREEN_HEIGHT 240
#define GDISP_USE_FSMC

View File

@ -44,9 +44,34 @@
/**
* @}
*
* @name GMISC Optional Sizing Parameters
* @name GMISC Optional Parameters
* @{
*/
/**
* @brief Modifies the @p invsqrt() function to assume a different integer to floating point endianness.
* @note Normally the floating point format and the integer format have
* the same endianness. Unfortunately there are some strange
* processors that don't eg. some very early ARM devices.
* For those where the endianness doesn't match you can fix it by
* defining GDISP_INVSQRT_MIXED_ENDIAN.
* @note This still assumes the processor is using an ieee floating point format.
*
* If you have a software floating point that uses a non-standard
* floating point format (or very strange hardware) then define
* GDISP_INVSQRT_REAL_SLOW and it will do it the hard way.
*/
#ifndef GDISP_INVSQRT_MIXED_ENDIAN
#define GDISP_INVSQRT_MIXED_ENDIAN FALSE
#endif
/**
* @brief Modifies the @p invsqrt() function to do things the long slow way.
* @note This causes the @p invsqrt() function to work regardless of the
* processor floating point format.
* @note This makes the @p invsqrt() function very slow.
*/
#ifndef GDISP_INVSQRT_REAL_SLOW
#define GDISP_INVSQRT_REAL_SLOW FALSE
#endif
/** @} */
#endif /* _GMISC_OPTIONS_H */

View File

@ -143,21 +143,47 @@
#endif
#if GMISC_NEED_INVSQRT
// Algorithm based on Quake code
float invsqrt(float n) {
long i;
float x2, y;
const float threehalfs = 1.5F;
// Algorithm based on Quake code.
#if GDISP_INVSQRT_REAL_SLOW
#include <math.h>
float invsqrt(float n) {
return 1.0/sqrt(n);
}
#else
float invsqrt(float n) {
int32_t i;
float x2;
x2 = n * 0.5F;
y = n;
i = * ( long * ) &y; // evil floating point bit level hacking
i = 0x5f3759df - ( i >> 1 ); // what the?
y = * ( float * ) &i;
y = y * ( threehalfs - ( x2 * y * y ) ); // 1st iteration
//y = y * ( threehalfs - ( x2 * y * y ) ); // 2nd iteration for extra precision, this can be removed
return y;
}
x2 = n * 0.5F;
// Convert into an int32 (no binary format conversion)
#if GDISP_INVSQRT_MIXED_ENDIAN
((char *)&i)[0] = ((char *)&n)[3];
((char *)&i)[1] = ((char *)&n)[2];
((char *)&i)[2] = ((char *)&n)[1];
((char *)&i)[3] = ((char *)&n)[0];
#else
i = *(int32_t *)&n;
#endif
// evil floating point bit level hacking
i = 0x5F3759DF - (i >> 1);
// Convert back to a float (no binary format conversion)
#if GDISP_INVSQRT_MIXED_ENDIAN
((char *)&n)[0] = ((char *)&i)[3];
((char *)&n)[1] = ((char *)&i)[2];
((char *)&n)[2] = ((char *)&i)[1];
((char *)&n)[3] = ((char *)&i)[0];
#else
n = *(float *)&i;
#endif
n = n * (1.5F - (x2 * n * n)); // 1st iteration
//n = n * (1.5F - (x2 * n * n)); // 2nd iteration for extra precision, this can be removed
return n;
}
#endif
#endif
#endif /* GFX_USE_GMISC */