Added few more stubs so that control reaches to DestroyDevice().
[mesa.git] / src / util / half_float.c
index 4df64c2ccf9383ebfff77506ab16d47d976f497b..aae690a56a6fad2e03636517397305f9713af537 100644 (file)
@@ -2,6 +2,9 @@
  * Mesa 3-D graphics library
  *
  * Copyright (C) 1999-2007  Brian Paul   All Rights Reserved.
+ * Copyright 2015 Philip Taylor <philip@zaynar.co.uk>
+ * Copyright 2018 Advanced Micro Devices, Inc.
+ * Copyright (C) 2018-2019 Intel Corporation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
 #include <math.h>
 #include <assert.h>
 #include "half_float.h"
+#include "util/u_half.h"
 #include "rounding.h"
+#include "softfloat.h"
+#include "macros.h"
 
 typedef union { float f; int32_t i; uint32_t u; } fi_type;
 
@@ -122,6 +128,11 @@ _mesa_float_to_half(float val)
    return result;
 }
 
+uint16_t
+_mesa_float_to_float16_rtz(float val)
+{
+    return _mesa_float_to_half_rtz(val);
+}
 
 /**
  * Convert a 2-byte half float to a 4-byte float.
@@ -131,47 +142,72 @@ _mesa_float_to_half(float val)
 float
 _mesa_half_to_float(uint16_t val)
 {
-   /* XXX could also use a 64K-entry lookup table */
+   return util_half_to_float(val);
+}
+
+/**
+  * Convert 0.0 to 0x00, 1.0 to 0xff.
+  * Values outside the range [0.0, 1.0] will give undefined results.
+  */
+uint8_t _mesa_half_to_unorm8(uint16_t val)
+{
    const int m = val & 0x3ff;
    const int e = (val >> 10) & 0x1f;
-   const int s = (val >> 15) & 0x1;
-   int flt_m, flt_e, flt_s;
-   fi_type fi;
-   float result;
+   ASSERTED const int s = (val >> 15) & 0x1;
 
-   /* sign bit */
-   flt_s = s;
+   /* v = round_to_nearest(1.mmmmmmmmmm * 2^(e-15) * 255)
+    *   = round_to_nearest((1.mmmmmmmmmm * 255) * 2^(e-15))
+    *   = round_to_nearest((1mmmmmmmmmm * 255) * 2^(e-25))
+    *   = round_to_zero((1mmmmmmmmmm * 255) * 2^(e-25) + 0.5)
+    *   = round_to_zero(((1mmmmmmmmmm * 255) * 2^(e-24) + 1) / 2)
+    *
+    * This happens to give the correct answer for zero/subnormals too
+    */
+   assert(s == 0 && val <= FP16_ONE); /* check 0 <= this <= 1 */
+   /* (implies e <= 15, which means the bit-shifts below are safe) */
 
-   /* handle special cases */
-   if ((e == 0) && (m == 0)) {
-      /* zero */
-      flt_m = 0;
-      flt_e = 0;
-   }
-   else if ((e == 0) && (m != 0)) {
-      /* denorm -- denorm half will fit in non-denorm single */
-      const float half_denorm = 1.0f / 16384.0f; /* 2^-14 */
-      float mantissa = ((float) (m)) / 1024.0f;
-      float sign = s ? -1.0f : 1.0f;
-      return sign * mantissa * half_denorm;
-   }
-   else if ((e == 31) && (m == 0)) {
-      /* infinity */
-      flt_e = 0xff;
-      flt_m = 0;
-   }
-   else if ((e == 31) && (m != 0)) {
-      /* NaN */
-      flt_e = 0xff;
-      flt_m = 1;
-   }
-   else {
-      /* regular */
-      flt_e = e + 112;
-      flt_m = m << 13;
+   uint32_t v = ((1 << 10) | m) * 255;
+   v = ((v >> (24 - e)) + 1) >> 1;
+   return v;
+}
+
+/**
+  * Takes a uint16_t, divides by 65536, converts the infinite-precision
+  * result to fp16 with round-to-zero. Used by the ASTC decoder.
+  */
+uint16_t _mesa_uint16_div_64k_to_half(uint16_t v)
+{
+   /* Zero or subnormal. Set the mantissa to (v << 8) and return. */
+   if (v < 4)
+      return v << 8;
+
+   /* Count the leading 0s in the uint16_t */
+#ifdef HAVE___BUILTIN_CLZ
+   int n = __builtin_clz(v) - 16;
+#else
+   int n = 16;
+   for (int i = 15; i >= 0; i--) {
+      if (v & (1 << i)) {
+         n = 15 - i;
+         break;
+      }
    }
+#endif
 
-   fi.i = (flt_s << 31) | (flt_e << 23) | flt_m;
-   result = fi.f;
-   return result;
+   /* Shift the mantissa up so bit 16 is the hidden 1 bit,
+    * mask it off, then shift back down to 10 bits
+    */
+   int m = ( ((uint32_t)v << (n + 1)) & 0xffff ) >> 6;
+
+   /*  (0{n} 1 X{15-n}) * 2^-16
+    * = 1.X * 2^(15-n-16)
+    * = 1.X * 2^(14-n - 15)
+    * which is the FP16 form with e = 14 - n
+    */
+   int e = 14 - n;
+
+   assert(e >= 1 && e <= 30);
+   assert(m >= 0 && m < 0x400);
+
+   return (e << 10) | m;
 }