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; int i;
drawSurf_t *drawSurf; drawSurf_t *drawSurf;
int oldSort; int oldSort;
float originalTime; double originalTime;
// save original time for entity shader offsets // save original time for entity shader offsets
originalTime = backEnd.refdef.floatTime; originalTime = backEnd.refdef.floatTime;
@ -562,7 +562,10 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) {
if ( entityNum != REFENTITYNUM_WORLD ) { if ( entityNum != REFENTITYNUM_WORLD ) {
backEnd.currentEntity = &backEnd.refdef.entities[entityNum]; 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 // we have to reset the shaderTime as well otherwise image animations start
// from the wrong frame // from the wrong frame
tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset; tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset;
@ -713,7 +716,7 @@ void RB_SetGL2D (void) {
// set time for 2D shaders // set time for 2D shaders
backEnd.refdef.time = ri.Milliseconds(); 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 { typedef struct {
genFunc_t func; genFunc_t func;
float base; double base;
float amplitude; double amplitude;
float phase; double phase;
float frequency; double frequency;
} waveForm_t; } waveForm_t;
#define TR_MAX_TEXMODS 4 #define TR_MAX_TEXMODS 4
@ -252,7 +252,7 @@ typedef struct {
typedef struct { typedef struct {
image_t *image[MAX_IMAGE_ANIMATIONS]; image_t *image[MAX_IMAGE_ANIMATIONS];
int numImageAnimations; int numImageAnimations;
float imageAnimationSpeed; double imageAnimationSpeed;
texCoordGen_t tcGen; texCoordGen_t tcGen;
vec3_t tcGenVectors[2]; vec3_t tcGenVectors[2];
@ -362,8 +362,8 @@ typedef struct shader_s {
void (*optimalStageIteratorFunc)( void ); void (*optimalStageIteratorFunc)( void );
float clampTime; // time this shader is clamped to double clampTime; // time this shader is clamped to
float timeOffset; // current time offset for this shader double timeOffset; // current time offset for this shader
struct shader_s *remappedShader; // current shader this one is remapped too struct shader_s *remappedShader; // current shader this one is remapped too
@ -388,7 +388,7 @@ typedef struct {
byte areamask[MAX_MAP_AREA_BYTES]; byte areamask[MAX_MAP_AREA_BYTES];
qboolean areamaskModified; // qtrue if areamask changed since last scene 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 // text messages for deform text shaders
char text[MAX_RENDER_STRINGS][MAX_RENDER_STRING_LENGTH]; 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); color4ub_t constantColor255[SHADER_MAX_VERTEXES] QALIGN(16);
shader_t *shader; shader_t *shader;
float shaderTime; double shaderTime;
int fogNum; int fogNum;
int dlightBits; // or together of all vertexDlightBits int dlightBits; // or together of all vertexDlightBits

View File

@ -218,7 +218,8 @@ R_BindAnimatedImage
================= =================
*/ */
static void R_BindAnimatedImage( textureBundle_t *bundle ) { static void R_BindAnimatedImage( textureBundle_t *bundle ) {
int index; int64_t index;
double v;
if ( bundle->isVideoMap ) { if ( bundle->isVideoMap ) {
ri.CIN_RunCinematic(bundle->videoMapHandle); 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 // it is necessary to do this messy calc to make sure animations line up
// exactly with waveforms of the same frequency // exactly with waveforms of the same frequency
index = ri.ftol(tess.shaderTime * bundle->imageAnimationSpeed * FUNCTABLE_SIZE); //index = ri.ftol(tess.shaderTime * bundle->imageAnimationSpeed * FUNCTABLE_SIZE);
index >>= FUNCTABLE_SIZE2; //index >>= FUNCTABLE_SIZE2;
v = tess.shaderTime * bundle->imageAnimationSpeed;
index = v;
if ( index < 0 ) { if ( index < 0 ) {
index = 0; // may happen with shader time offsets 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 #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 ) static float *TableForFunc( genFunc_t func )
{ {
@ -920,7 +920,7 @@ void RB_CalcEnvironmentTexCoords( float *st )
void RB_CalcTurbulentTexCoords( const waveForm_t *wf, float *st ) void RB_CalcTurbulentTexCoords( const waveForm_t *wf, float *st )
{ {
int i; int i;
float now; double now;
now = ( wf->phase + tess.shaderTime * wf->frequency ); 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 ) void RB_CalcScrollTexCoords( const float scrollSpeed[2], float *st )
{ {
int i; int i;
float timeScale = tess.shaderTime; double timeScale;
float adjustedScrollS, adjustedScrollT; double adjustedScrollS, adjustedScrollT;
adjustedScrollS = scrollSpeed[0] * timeScale; timeScale = tess.shaderTime;
adjustedScrollT = scrollSpeed[1] * timeScale;
adjustedScrollS = (double)scrollSpeed[0] * timeScale;
adjustedScrollT = (double)scrollSpeed[1] * timeScale;
// clamp so coordinates don't continuously get larger, causing problems // clamp so coordinates don't continuously get larger, causing problems
// with hardware limits // with hardware limits
@ -994,9 +996,9 @@ void RB_CalcTransformTexCoords( const texModInfo_t *tmi, float *st )
*/ */
void RB_CalcRotateTexCoords( float degsPerSecond, float *st ) void RB_CalcRotateTexCoords( float degsPerSecond, float *st )
{ {
float timeScale = tess.shaderTime; double timeScale = tess.shaderTime;
float degs; double degs;
int index; int64_t index;
float sinValue, cosValue; float sinValue, cosValue;
texModInfo_t tmi; texModInfo_t tmi;

View File

@ -433,7 +433,7 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) {
int i; int i;
drawSurf_t *drawSurf; drawSurf_t *drawSurf;
int oldSort; int oldSort;
float originalTime; double originalTime;
FBO_t* fbo = NULL; FBO_t* fbo = NULL;
qboolean inQuery = qfalse; qboolean inQuery = qfalse;
@ -498,7 +498,10 @@ void RB_RenderDrawSurfList( drawSurf_t *drawSurfs, int numDrawSurfs ) {
if ( entityNum != REFENTITYNUM_WORLD ) { if ( entityNum != REFENTITYNUM_WORLD ) {
backEnd.currentEntity = &backEnd.refdef.entities[entityNum]; 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 // we have to reset the shaderTime as well otherwise image animations start
// from the wrong frame // from the wrong frame
tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset; tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset;
@ -658,7 +661,7 @@ void RB_SetGL2D (void) {
// set time for 2D shaders // set time for 2D shaders
backEnd.refdef.time = ri.Milliseconds(); 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 { typedef struct {
genFunc_t func; genFunc_t func;
float base; double base;
float amplitude; double amplitude;
float phase; double phase;
float frequency; double frequency;
} waveForm_t; } waveForm_t;
#define TR_MAX_TEXMODS 4 #define TR_MAX_TEXMODS 4
@ -331,7 +331,7 @@ typedef struct {
typedef struct { typedef struct {
image_t *image[MAX_IMAGE_ANIMATIONS]; image_t *image[MAX_IMAGE_ANIMATIONS];
int numImageAnimations; int numImageAnimations;
float imageAnimationSpeed; double imageAnimationSpeed;
texCoordGen_t tcGen; texCoordGen_t tcGen;
vec3_t tcGenVectors[2]; vec3_t tcGenVectors[2];
@ -471,8 +471,8 @@ typedef struct shader_s {
void (*optimalStageIteratorFunc)( void ); void (*optimalStageIteratorFunc)( void );
float clampTime; // time this shader is clamped to double clampTime; // time this shader is clamped to
float timeOffset; // current time offset for this shader double timeOffset; // current time offset for this shader
struct shader_s *remappedShader; // current shader this one is remapped too struct shader_s *remappedShader; // current shader this one is remapped too
@ -733,7 +733,7 @@ typedef struct {
byte areamask[MAX_MAP_AREA_BYTES]; byte areamask[MAX_MAP_AREA_BYTES];
qboolean areamaskModified; // qtrue if areamask changed since last scene 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; float blurFactor;
@ -1978,7 +1978,7 @@ typedef struct shaderCommands_s
//color4ub_t constantColor255[SHADER_MAX_VERTEXES] QALIGN(16); //color4ub_t constantColor255[SHADER_MAX_VERTEXES] QALIGN(16);
shader_t *shader; shader_t *shader;
float shaderTime; double shaderTime;
int fogNum; int fogNum;
int cubemapIndex; int cubemapIndex;

View File

@ -65,7 +65,8 @@ R_BindAnimatedImageToTMU
================= =================
*/ */
static void R_BindAnimatedImageToTMU( textureBundle_t *bundle, int tmu ) { static void R_BindAnimatedImageToTMU( textureBundle_t *bundle, int tmu ) {
int index; int64_t index;
double v;
if ( bundle->isVideoMap ) { if ( bundle->isVideoMap ) {
ri.CIN_RunCinematic(bundle->videoMapHandle); 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 // it is necessary to do this messy calc to make sure animations line up
// exactly with waveforms of the same frequency // exactly with waveforms of the same frequency
index = ri.ftol(tess.shaderTime * bundle->imageAnimationSpeed * FUNCTABLE_SIZE); //index = ri.ftol(tess.shaderTime * bundle->imageAnimationSpeed * FUNCTABLE_SIZE);
index >>= FUNCTABLE_SIZE2; //index >>= FUNCTABLE_SIZE2;
v = tess.shaderTime * bundle->imageAnimationSpeed;
index = v;
if ( index < 0 ) { if ( index < 0 ) {
index = 0; // may happen with shader time offsets 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 #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 ) 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 ) void RB_CalcScrollTexMatrix( const float scrollSpeed[2], float *matrix )
{ {
float timeScale = tess.shaderTime; double timeScale;
float adjustedScrollS, adjustedScrollT; double adjustedScrollS, adjustedScrollT;
timeScale = tess.shaderTime;
adjustedScrollS = scrollSpeed[0] * timeScale; adjustedScrollS = scrollSpeed[0] * timeScale;
adjustedScrollT = scrollSpeed[1] * timeScale; adjustedScrollT = scrollSpeed[1] * timeScale;
// clamp so coordinates don't continuously get larger, causing problems // clamp so coordinates don't continuously get larger, causing problems
// with hardware limits // with hardware limits
adjustedScrollS = adjustedScrollS - floor( adjustedScrollS ); adjustedScrollS = (double)adjustedScrollS - floor( adjustedScrollS );
adjustedScrollT = adjustedScrollT - floor( adjustedScrollT ); adjustedScrollT = (double)adjustedScrollT - floor( adjustedScrollT );
matrix[0] = 1.0f; matrix[2] = 0.0f; matrix[4] = adjustedScrollS; matrix[0] = 1.0f; matrix[2] = 0.0f; matrix[4] = adjustedScrollS;
matrix[1] = 0.0f; matrix[3] = 1.0f; matrix[5] = adjustedScrollT; 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 ) void RB_CalcRotateTexMatrix( float degsPerSecond, float *matrix )
{ {
float timeScale = tess.shaderTime; double timeScale = tess.shaderTime;
float degs; double degs;
int index; int64_t index;
float sinValue, cosValue; float sinValue, cosValue;
degs = -degsPerSecond * timeScale; degs = -degsPerSecond * timeScale;