summaryrefslogtreecommitdiffstats
path: root/src/gallium/auxiliary/util/u_half.h
diff options
context:
space:
mode:
authorLuca Barbieri <[email protected]>2010-03-24 18:12:45 +0100
committerMichal Krol <[email protected]>2010-04-01 13:33:07 +0200
commit3ff175d6de89ad92d167362355501f99d06f0f97 (patch)
tree6332294693fc3581785927a9df6013aecf9aca22 /src/gallium/auxiliary/util/u_half.h
parent110e039d0df08ae1642adf4bd20f07992b9ffe9c (diff)
gallium/util: add fast half float conversion functions
This adds a fast half float conversion facility to Gallium. Mesa already contains such a facility, but using a much worse algorithm. This one is an implementation of www.fox-toolkit.org/ftp/fasthalffloatconversion.pdf and uses a branch-less algorithm with some lookup tables small enough to fit in the L1 cache. Ideally, Mesa should start using these functions too, but I'm not sure how to arrange that with the current build system. A new "u_gctors.cpp" is added that defines a global C++ constructor allowing to initialize to conversion lookup tables at library init.
Diffstat (limited to 'src/gallium/auxiliary/util/u_half.h')
-rw-r--r--src/gallium/auxiliary/util/u_half.h55
1 files changed, 55 insertions, 0 deletions
diff --git a/src/gallium/auxiliary/util/u_half.h b/src/gallium/auxiliary/util/u_half.h
new file mode 100644
index 00000000000..464d43df8a0
--- /dev/null
+++ b/src/gallium/auxiliary/util/u_half.h
@@ -0,0 +1,55 @@
+#ifndef U_HALF_H
+#define U_HALF_H
+
+#include "pipe/p_compiler.h"
+
+extern uint32_t util_half_to_float_mantissa_table[2048];
+extern uint32_t util_half_to_float_exponent_table[64];
+extern uint32_t util_half_to_float_offset_table[64];
+extern uint16_t util_float_to_half_base_table[512];
+extern uint8_t util_float_to_half_shift_table[512];
+
+/*
+ * Note that if the half float is a signaling NaN, the x87 FPU will turn
+ * it into a quiet NaN immediately upon loading into a float.
+ *
+ * Additionally, denormals may be flushed to zero.
+ *
+ * To avoid this, use the floatui functions instead of the float ones
+ * when just doing conversion rather than computation on the resulting
+ * floats.
+ */
+
+static INLINE uint32_t
+util_half_to_floatui(half h)
+{
+ unsigned exp = h >> 10;
+ return util_half_to_float_mantissa_table[util_half_to_float_offset_table[exp] + (h & 0x3ff)]
+ + util_half_to_float_exponent_table[exp];
+}
+
+static INLINE float
+util_half_to_float(half h)
+{
+ union {float f; uint32_t v;} r;
+ r.v = util_half_to_floatui(h);
+ return r.f;
+}
+
+static INLINE half
+util_floatui_to_half(uint32_t v)
+{
+ unsigned signexp = v >> 23;
+ return util_float_to_half_base_table[signexp]
+ + ((v & 0x007fffff) >> util_float_to_half_shift_table[signexp]);
+}
+
+static INLINE half
+util_float_to_half(float f)
+{
+ union {float f; uint32_t v;} i;
+ i.f = f;
+ return util_floatui_to_half(i.v);
+}
+
+#endif /* U_HALF_H */