From ddba7ef996667a29ec88ac12b09fa42a5878ba86 Mon Sep 17 00:00:00 2001 From: baldurk Date: Wed, 15 Jul 2020 14:49:51 +0100 Subject: [PATCH] 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. --- .../shaders/spirv/spirv_debug_glsl450.cpp | 82 +++++++++++++------ 1 file changed, 55 insertions(+), 27 deletions(-) diff --git a/renderdoc/driver/shaders/spirv/spirv_debug_glsl450.cpp b/renderdoc/driver/shaders/spirv/spirv_debug_glsl450.cpp index 3c42985c3..a1e8200ae 100644 --- a/renderdoc/driver/shaders/spirv/spirv_debug_glsl450.cpp +++ b/renderdoc/driver/shaders/spirv/spirv_debug_glsl450.cpp @@ -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 ¶ms) { CHECK_PARAMS(2); @@ -852,30 +904,6 @@ ShaderVariable FindUMsb(ThreadState &state, uint32_t, const rdcarray ¶ms 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 ¶ms) { CHECK_PARAMS(2); @@ -884,7 +912,7 @@ ShaderVariable NMin(ThreadState &state, uint32_t, const rdcarray ¶ms) 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 ¶ms) 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 ¶ms) 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; }