diff options
Diffstat (limited to 'src/util/half_float.c')
-rw-r--r-- | src/util/half_float.c | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/src/util/half_float.c b/src/util/half_float.c index 4df64c2ccf9..588f050d924 100644 --- a/src/util/half_float.c +++ b/src/util/half_float.c @@ -2,6 +2,8 @@ * Mesa 3-D graphics library * * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. + * Copyright 2015 Philip Taylor <[email protected]> + * Copyright 2018 Advanced Micro Devices, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -175,3 +177,60 @@ _mesa_half_to_float(uint16_t val) result = fi.f; return result; } + +/** + * 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; + + /* 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) */ + + 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 */ + int n = __builtin_clz(v) - (sizeof(unsigned int) - sizeof(uint16_t)) * 8; + + /* 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; +} |