Fix floating point precision loss in renderer [part 1]

Patch for https://bugzilla.icculus.org/show_bug.cgi?id=5931 by
Eugene C. from 2013 plus recent fix for tcMod rotate.

I merged the changes into the OpenGL2 renderer though the fix for
tcMod turb doesn't translate.
This commit is contained in:
Zack Middleton 2017-08-02 22:39:27 -05:00
parent 9c4c363ccc
commit 30fdd88c9f
8 changed files with 63 additions and 47 deletions

View file

@ -509,7 +509,7 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) {
int i;
drawSurf_t *drawSurf;
int oldSort;
float originalTime;
double originalTime;
// save original time for entity shader offsets
originalTime = backEnd.refdef.floatTime;
@ -562,7 +562,10 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) {
if ( entityNum != REFENTITYNUM_WORLD ) {
backEnd.currentEntity = &backEnd.refdef.entities[entityNum];
backEnd.refdef.floatTime = originalTime - backEnd.currentEntity->e.shaderTime;
// FIXME: e.shaderTime must be passed as int to avoid fp-precision loss issues
backEnd.refdef.floatTime = originalTime - (double)backEnd.currentEntity->e.shaderTime;
// we have to reset the shaderTime as well otherwise image animations start
// from the wrong frame
tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset;
@ -713,7 +716,7 @@ void RB_SetGL2D (void) {
// set time for 2D shaders
backEnd.refdef.time = ri.Milliseconds();
backEnd.refdef.floatTime = backEnd.refdef.time * 0.001f;
backEnd.refdef.floatTime = (double)backEnd.refdef.time * 0.001f;
}

View file

@ -189,10 +189,10 @@ typedef enum {
typedef struct {
genFunc_t func;
float base;
float amplitude;
float phase;
float frequency;
double base;
double amplitude;
double phase;
double frequency;
} waveForm_t;
#define TR_MAX_TEXMODS 4
@ -252,7 +252,7 @@ typedef struct {
typedef struct {
image_t *image[MAX_IMAGE_ANIMATIONS];
int numImageAnimations;
float imageAnimationSpeed;
double imageAnimationSpeed;
texCoordGen_t tcGen;
vec3_t tcGenVectors[2];
@ -362,8 +362,8 @@ typedef struct shader_s {
void (*optimalStageIteratorFunc)( void );
float clampTime; // time this shader is clamped to
float timeOffset; // current time offset for this shader
double clampTime; // time this shader is clamped to
double timeOffset; // current time offset for this shader
struct shader_s *remappedShader; // current shader this one is remapped too
@ -388,7 +388,7 @@ typedef struct {
byte areamask[MAX_MAP_AREA_BYTES];
qboolean areamaskModified; // qtrue if areamask changed since last scene
float floatTime; // tr.refdef.time / 1000.0
double floatTime; // tr.refdef.time / 1000.0
// text messages for deform text shaders
char text[MAX_RENDER_STRINGS][MAX_RENDER_STRING_LENGTH];
@ -1217,7 +1217,7 @@ typedef struct shaderCommands_s
color4ub_t constantColor255[SHADER_MAX_VERTEXES] QALIGN(16);
shader_t *shader;
float shaderTime;
double shaderTime;
int fogNum;
int dlightBits; // or together of all vertexDlightBits

View file

@ -218,7 +218,8 @@ R_BindAnimatedImage
=================
*/
static void R_BindAnimatedImage( textureBundle_t *bundle ) {
int index;
int64_t index;
double v;
if ( bundle->isVideoMap ) {
ri.CIN_RunCinematic(bundle->videoMapHandle);
@ -233,8 +234,10 @@ static void R_BindAnimatedImage( textureBundle_t *bundle ) {
// it is necessary to do this messy calc to make sure animations line up
// exactly with waveforms of the same frequency
index = ri.ftol(tess.shaderTime * bundle->imageAnimationSpeed * FUNCTABLE_SIZE);
index >>= FUNCTABLE_SIZE2;
//index = ri.ftol(tess.shaderTime * bundle->imageAnimationSpeed * FUNCTABLE_SIZE);
//index >>= FUNCTABLE_SIZE2;
v = tess.shaderTime * bundle->imageAnimationSpeed;
index = v;
if ( index < 0 ) {
index = 0; // may happen with shader time offsets

View file

@ -27,7 +27,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#endif
#define WAVEVALUE( table, base, amplitude, phase, freq ) ((base) + table[ ri.ftol( ( ( (phase) + tess.shaderTime * (freq) ) * FUNCTABLE_SIZE ) ) & FUNCTABLE_MASK ] * (amplitude))
#define WAVEVALUE( table, base, amplitude, phase, freq ) ((base) + table[ (int)( ( ( (phase) + tess.shaderTime * (freq) ) * FUNCTABLE_SIZE ) ) & FUNCTABLE_MASK ] * (amplitude))
static float *TableForFunc( genFunc_t func )
{
@ -920,7 +920,7 @@ void RB_CalcEnvironmentTexCoords( float *st )
void RB_CalcTurbulentTexCoords( const waveForm_t *wf, float *st )
{
int i;
float now;
double now;
now = ( wf->phase + tess.shaderTime * wf->frequency );
@ -954,11 +954,13 @@ void RB_CalcScaleTexCoords( const float scale[2], float *st )
void RB_CalcScrollTexCoords( const float scrollSpeed[2], float *st )
{
int i;
float timeScale = tess.shaderTime;
float adjustedScrollS, adjustedScrollT;
double timeScale;
double adjustedScrollS, adjustedScrollT;
adjustedScrollS = scrollSpeed[0] * timeScale;
adjustedScrollT = scrollSpeed[1] * timeScale;
timeScale = tess.shaderTime;
adjustedScrollS = (double)scrollSpeed[0] * timeScale;
adjustedScrollT = (double)scrollSpeed[1] * timeScale;
// clamp so coordinates don't continuously get larger, causing problems
// with hardware limits
@ -994,9 +996,9 @@ void RB_CalcTransformTexCoords( const texModInfo_t *tmi, float *st )
*/
void RB_CalcRotateTexCoords( float degsPerSecond, float *st )
{
float timeScale = tess.shaderTime;
float degs;
int index;
double timeScale = tess.shaderTime;
double degs;
int64_t index;
float sinValue, cosValue;
texModInfo_t tmi;

View file

@ -433,7 +433,7 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) {
int i;
drawSurf_t *drawSurf;
int oldSort;
float originalTime;
double originalTime;
FBO_t* fbo = NULL;
qboolean inQuery = qfalse;
@ -498,7 +498,10 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) {
if ( entityNum != REFENTITYNUM_WORLD ) {
backEnd.currentEntity = &backEnd.refdef.entities[entityNum];
backEnd.refdef.floatTime = originalTime - backEnd.currentEntity->e.shaderTime;
// FIXME: e.shaderTime must be passed as int to avoid fp-precision loss issues
backEnd.refdef.floatTime = originalTime - (double)backEnd.currentEntity->e.shaderTime;
// we have to reset the shaderTime as well otherwise image animations start
// from the wrong frame
tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset;
@ -658,7 +661,7 @@ void RB_SetGL2D (void) {
// set time for 2D shaders
backEnd.refdef.time = ri.Milliseconds();
backEnd.refdef.floatTime = backEnd.refdef.time * 0.001f;
backEnd.refdef.floatTime = (double)backEnd.refdef.time * 0.001f;
}

View file

@ -268,10 +268,10 @@ typedef enum {
typedef struct {
genFunc_t func;
float base;
float amplitude;
float phase;
float frequency;
double base;
double amplitude;
double phase;
double frequency;
} waveForm_t;
#define TR_MAX_TEXMODS 4
@ -331,7 +331,7 @@ typedef struct {
typedef struct {
image_t *image[MAX_IMAGE_ANIMATIONS];
int numImageAnimations;
float imageAnimationSpeed;
double imageAnimationSpeed;
texCoordGen_t tcGen;
vec3_t tcGenVectors[2];
@ -471,8 +471,8 @@ typedef struct shader_s {
void (*optimalStageIteratorFunc)( void );
float clampTime; // time this shader is clamped to
float timeOffset; // current time offset for this shader
double clampTime; // time this shader is clamped to
double timeOffset; // current time offset for this shader
struct shader_s *remappedShader; // current shader this one is remapped too
@ -733,7 +733,7 @@ typedef struct {
byte areamask[MAX_MAP_AREA_BYTES];
qboolean areamaskModified; // qtrue if areamask changed since last scene
float floatTime; // tr.refdef.time / 1000.0
double floatTime; // tr.refdef.time / 1000.0
float blurFactor;
@ -1978,7 +1978,7 @@ typedef struct shaderCommands_s
//color4ub_t constantColor255[SHADER_MAX_VERTEXES] QALIGN(16);
shader_t *shader;
float shaderTime;
double shaderTime;
int fogNum;
int cubemapIndex;

View file

@ -65,7 +65,8 @@ R_BindAnimatedImageToTMU
=================
*/
static void R_BindAnimatedImageToTMU( textureBundle_t *bundle, int tmu ) {
int index;
int64_t index;
double v;
if ( bundle->isVideoMap ) {
ri.CIN_RunCinematic(bundle->videoMapHandle);
@ -81,8 +82,10 @@ static void R_BindAnimatedImageToTMU( textureBundle_t *bundle, int tmu ) {
// it is necessary to do this messy calc to make sure animations line up
// exactly with waveforms of the same frequency
index = ri.ftol(tess.shaderTime * bundle->imageAnimationSpeed * FUNCTABLE_SIZE);
index >>= FUNCTABLE_SIZE2;
//index = ri.ftol(tess.shaderTime * bundle->imageAnimationSpeed * FUNCTABLE_SIZE);
//index >>= FUNCTABLE_SIZE2;
v = tess.shaderTime * bundle->imageAnimationSpeed;
index = v;
if ( index < 0 ) {
index = 0; // may happen with shader time offsets

View file

@ -27,7 +27,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#endif
#define WAVEVALUE( table, base, amplitude, phase, freq ) ((base) + table[ ri.ftol( ( ( (phase) + tess.shaderTime * (freq) ) * FUNCTABLE_SIZE ) ) & FUNCTABLE_MASK ] * (amplitude))
#define WAVEVALUE( table, base, amplitude, phase, freq ) ((base) + table[ (int)( ( ( (phase) + tess.shaderTime * (freq) ) * FUNCTABLE_SIZE ) ) & FUNCTABLE_MASK ] * (amplitude))
static float *TableForFunc( genFunc_t func )
{
@ -776,16 +776,18 @@ void RB_CalcScaleTexMatrix( const float scale[2], float *matrix )
*/
void RB_CalcScrollTexMatrix( const float scrollSpeed[2], float *matrix )
{
float timeScale = tess.shaderTime;
float adjustedScrollS, adjustedScrollT;
double timeScale;
double adjustedScrollS, adjustedScrollT;
timeScale = tess.shaderTime;
adjustedScrollS = scrollSpeed[0] * timeScale;
adjustedScrollT = scrollSpeed[1] * timeScale;
// clamp so coordinates don't continuously get larger, causing problems
// with hardware limits
adjustedScrollS = adjustedScrollS - floor( adjustedScrollS );
adjustedScrollT = adjustedScrollT - floor( adjustedScrollT );
adjustedScrollS = (double)adjustedScrollS - floor( adjustedScrollS );
adjustedScrollT = (double)adjustedScrollT - floor( adjustedScrollT );
matrix[0] = 1.0f; matrix[2] = 0.0f; matrix[4] = adjustedScrollS;
matrix[1] = 0.0f; matrix[3] = 1.0f; matrix[5] = adjustedScrollT;
@ -805,9 +807,9 @@ void RB_CalcTransformTexMatrix( const texModInfo_t *tmi, float *matrix )
*/
void RB_CalcRotateTexMatrix( float degsPerSecond, float *matrix )
{
float timeScale = tess.shaderTime;
float degs;
int index;
double timeScale = tess.shaderTime;
double degs;
int64_t index;
float sinValue, cosValue;
degs = -degsPerSecond * timeScale;