Use NaN-friendly behaviour for all mins and maxs in SPIR-V

* This matches the explicitly documented behaviour for D3D so it likely matches
  what GPUs do, and since SPIR-V leaves it undefined it's OK to do what we want.
  This does mean that there might be false negatives of cases where the GPU gets
  bad results and the simulation 'works', but this is preferable and less likely
  than false positives of the simulation going (legally) wrong when the GPU
  result is correct.
This commit is contained in:
baldurk
2020-07-15 14:49:51 +01:00
parent c3c95ece79
commit ddba7ef996
@@ -306,6 +306,58 @@ static T GLSLMin(T x, T y)
return y < x ? y : x;
}
template <>
static float GLSLMax(float x, float y)
{
const bool xnan = RDCISNAN(x);
const bool ynan = RDCISNAN(y);
if(xnan && !ynan)
return y;
else if(!xnan && ynan)
return x;
else
return x < y ? y : x;
}
template <>
static float GLSLMin(float x, float y)
{
const bool xnan = RDCISNAN(x);
const bool ynan = RDCISNAN(y);
if(xnan && !ynan)
return y;
else if(!xnan && ynan)
return x;
else
return y < x ? y : x;
}
template <>
static double GLSLMax(double x, double y)
{
const bool xnan = RDCISNAN(x);
const bool ynan = RDCISNAN(y);
if(xnan && !ynan)
return y;
else if(!xnan && ynan)
return x;
else
return x < y ? y : x;
}
template <>
static double GLSLMin(double x, double y)
{
const bool xnan = RDCISNAN(x);
const bool ynan = RDCISNAN(y);
if(xnan && !ynan)
return y;
else if(!xnan && ynan)
return x;
else
return y < x ? y : x;
}
ShaderVariable FMax(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(2);
@@ -852,30 +904,6 @@ ShaderVariable FindUMsb(ThreadState &state, uint32_t, const rdcarray<Id> &params
return x;
}
static float GLSLNMax(float x, float y)
{
const bool xnan = RDCISNAN(x);
const bool ynan = RDCISNAN(y);
if(xnan && !ynan)
return y;
else if(!xnan && ynan)
return x;
else
return x < y ? y : x;
}
static float GLSLNMin(float x, float y)
{
const bool xnan = RDCISNAN(x);
const bool ynan = RDCISNAN(y);
if(xnan && !ynan)
return y;
else if(!xnan && ynan)
return x;
else
return y < x ? y : x;
}
ShaderVariable NMin(ThreadState &state, uint32_t, const rdcarray<Id> &params)
{
CHECK_PARAMS(2);
@@ -884,7 +912,7 @@ ShaderVariable NMin(ThreadState &state, uint32_t, const rdcarray<Id> &params)
ShaderVariable y = state.GetSrc(params[1]);
for(uint32_t c = 0; c < var.columns; c++)
var.value.fv[c] = GLSLNMin(var.value.fv[c], y.value.fv[c]);
var.value.fv[c] = GLSLMin(var.value.fv[c], y.value.fv[c]);
return var;
}
@@ -897,7 +925,7 @@ ShaderVariable NMax(ThreadState &state, uint32_t, const rdcarray<Id> &params)
ShaderVariable y = state.GetSrc(params[1]);
for(uint32_t c = 0; c < var.columns; c++)
var.value.fv[c] = GLSLNMax(var.value.fv[c], y.value.fv[c]);
var.value.fv[c] = GLSLMax(var.value.fv[c], y.value.fv[c]);
return var;
}
@@ -911,7 +939,7 @@ ShaderVariable NClamp(ThreadState &state, uint32_t, const rdcarray<Id> &params)
ShaderVariable maxVal = state.GetSrc(params[2]);
for(uint32_t c = 0; c < var.columns; c++)
var.value.fv[c] = GLSLNMin(GLSLNMax(var.value.fv[c], minVal.value.fv[c]), maxVal.value.fv[c]);
var.value.fv[c] = GLSLMin(GLSLMax(var.value.fv[c], minVal.value.fv[c]), maxVal.value.fv[c]);
return var;
}