util: treat denorm'ed floats like zero
[mesa.git] / src / gallium / auxiliary / util / u_math.c
index 2811475fa0017aeb721bcbe3e7a3ad0ab2c6184f..2487bc74b25ad9174331d55784f7f5b8bc20d7a8 100644 (file)
@@ -28,6 +28,7 @@
 
 
 #include "util/u_math.h"
+#include "util/u_cpu_detect.h"
 
 
 /** 2^x, for x in [-1.0, 1.0) */
@@ -70,4 +71,59 @@ util_init_math(void)
    }
 }
 
+/**
+ * Fetches the contents of the fpstate (mxcsr on x86) register.
+ *
+ * On platforms without support for it just returns 0.
+ */
+unsigned
+util_fpstate_get(void)
+{
+   unsigned mxcsr = 0;
+
+#if defined(PIPE_ARCH_X86) || defined(PIPE_ARCH_X86_64)
+   if (util_cpu_caps.has_sse) {
+      mxcsr = __builtin_ia32_stmxcsr();
+   }
+#endif
 
+   return mxcsr;
+}
+
+/**
+ * Make sure that the fp treats the denormalized floating
+ * point numbers as zero.
+ *
+ * This is the behavior required by D3D10. OpenGL doesn't care.
+ */
+unsigned
+util_fpstate_set_denorms_to_zero(unsigned current_mxcsr)
+{
+#if defined(PIPE_ARCH_X86) || defined(PIPE_ARCH_X86_64)
+#define MXCSR_DAZ (1 << 6)     /* Enable denormals are zero mode */
+#define MXCSR_FTZ (1 << 15)    /* Enable flush to zero mode */
+   if (util_cpu_caps.has_sse) {
+      current_mxcsr |= MXCSR_FTZ;
+      if (util_cpu_caps.has_sse3) {
+         current_mxcsr |= MXCSR_DAZ;
+      }
+      util_fpstate_set(current_mxcsr);
+   }
+#endif
+   return current_mxcsr;
+}
+
+/**
+ * Set the state of the fpstate (mxcsr on x86) register.
+ *
+ * On platforms without support for it's a noop.
+ */
+void
+util_fpstate_set(unsigned mxcsr)
+{
+#if defined(PIPE_ARCH_X86) || defined(PIPE_ARCH_X86_64)
+   if (util_cpu_caps.has_sse) {
+      __builtin_ia32_ldmxcsr(mxcsr);
+   }
+#endif
+}