101e04c3fSmrg/* 201e04c3fSmrg * Mesa 3-D graphics library 301e04c3fSmrg * 401e04c3fSmrg * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. 501e04c3fSmrg * Copyright 2015 Philip Taylor <philip@zaynar.co.uk> 601e04c3fSmrg * Copyright 2018 Advanced Micro Devices, Inc. 77ec681f3Smrg * Copyright (C) 2018-2019 Intel Corporation 801e04c3fSmrg * 901e04c3fSmrg * Permission is hereby granted, free of charge, to any person obtaining a 1001e04c3fSmrg * copy of this software and associated documentation files (the "Software"), 1101e04c3fSmrg * to deal in the Software without restriction, including without limitation 1201e04c3fSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 1301e04c3fSmrg * and/or sell copies of the Software, and to permit persons to whom the 1401e04c3fSmrg * Software is furnished to do so, subject to the following conditions: 1501e04c3fSmrg * 1601e04c3fSmrg * The above copyright notice and this permission notice shall be included 1701e04c3fSmrg * in all copies or substantial portions of the Software. 1801e04c3fSmrg * 1901e04c3fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 2001e04c3fSmrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 2101e04c3fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 2201e04c3fSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 2301e04c3fSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 2401e04c3fSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 2501e04c3fSmrg * OTHER DEALINGS IN THE SOFTWARE. 2601e04c3fSmrg */ 2701e04c3fSmrg 2801e04c3fSmrg#include <math.h> 2901e04c3fSmrg#include <assert.h> 3001e04c3fSmrg#include "half_float.h" 3101e04c3fSmrg#include "rounding.h" 327ec681f3Smrg#include "softfloat.h" 3301e04c3fSmrg#include "macros.h" 347ec681f3Smrg#include "u_math.h" 3501e04c3fSmrg 3601e04c3fSmrgtypedef union { float f; int32_t i; uint32_t u; } fi_type; 3701e04c3fSmrg 3801e04c3fSmrg/** 3901e04c3fSmrg * Convert a 4-byte float to a 2-byte half float. 4001e04c3fSmrg * 4101e04c3fSmrg * Not all float32 values can be represented exactly as a float16 value. We 4201e04c3fSmrg * round such intermediate float32 values to the nearest float16. When the 4301e04c3fSmrg * float32 lies exactly between to float16 values, we round to the one with 4401e04c3fSmrg * an even mantissa. 4501e04c3fSmrg * 4601e04c3fSmrg * This rounding behavior has several benefits: 4701e04c3fSmrg * - It has no sign bias. 4801e04c3fSmrg * 4901e04c3fSmrg * - It reproduces the behavior of real hardware: opcode F32TO16 in Intel's 5001e04c3fSmrg * GPU ISA. 5101e04c3fSmrg * 5201e04c3fSmrg * - By reproducing the behavior of the GPU (at least on Intel hardware), 5301e04c3fSmrg * compile-time evaluation of constant packHalf2x16 GLSL expressions will 5401e04c3fSmrg * result in the same value as if the expression were executed on the GPU. 5501e04c3fSmrg */ 5601e04c3fSmrguint16_t 577ec681f3Smrg_mesa_float_to_half_slow(float val) 5801e04c3fSmrg{ 5901e04c3fSmrg const fi_type fi = {val}; 6001e04c3fSmrg const int flt_m = fi.i & 0x7fffff; 6101e04c3fSmrg const int flt_e = (fi.i >> 23) & 0xff; 6201e04c3fSmrg const int flt_s = (fi.i >> 31) & 0x1; 6301e04c3fSmrg int s, e, m = 0; 6401e04c3fSmrg uint16_t result; 6501e04c3fSmrg 6601e04c3fSmrg /* sign bit */ 6701e04c3fSmrg s = flt_s; 6801e04c3fSmrg 6901e04c3fSmrg /* handle special cases */ 7001e04c3fSmrg if ((flt_e == 0) && (flt_m == 0)) { 7101e04c3fSmrg /* zero */ 7201e04c3fSmrg /* m = 0; - already set */ 7301e04c3fSmrg e = 0; 7401e04c3fSmrg } 7501e04c3fSmrg else if ((flt_e == 0) && (flt_m != 0)) { 7601e04c3fSmrg /* denorm -- denorm float maps to 0 half */ 7701e04c3fSmrg /* m = 0; - already set */ 7801e04c3fSmrg e = 0; 7901e04c3fSmrg } 8001e04c3fSmrg else if ((flt_e == 0xff) && (flt_m == 0)) { 8101e04c3fSmrg /* infinity */ 8201e04c3fSmrg /* m = 0; - already set */ 8301e04c3fSmrg e = 31; 8401e04c3fSmrg } 8501e04c3fSmrg else if ((flt_e == 0xff) && (flt_m != 0)) { 8601e04c3fSmrg /* NaN */ 8701e04c3fSmrg m = 1; 8801e04c3fSmrg e = 31; 8901e04c3fSmrg } 9001e04c3fSmrg else { 9101e04c3fSmrg /* regular number */ 9201e04c3fSmrg const int new_exp = flt_e - 127; 9301e04c3fSmrg if (new_exp < -14) { 9401e04c3fSmrg /* The float32 lies in the range (0.0, min_normal16) and is rounded 9501e04c3fSmrg * to a nearby float16 value. The result will be either zero, subnormal, 9601e04c3fSmrg * or normal. 9701e04c3fSmrg */ 9801e04c3fSmrg e = 0; 9901e04c3fSmrg m = _mesa_lroundevenf((1 << 24) * fabsf(fi.f)); 10001e04c3fSmrg } 10101e04c3fSmrg else if (new_exp > 15) { 10201e04c3fSmrg /* map this value to infinity */ 10301e04c3fSmrg /* m = 0; - already set */ 10401e04c3fSmrg e = 31; 10501e04c3fSmrg } 10601e04c3fSmrg else { 10701e04c3fSmrg /* The float32 lies in the range 10801e04c3fSmrg * [min_normal16, max_normal16 + max_step16) 10901e04c3fSmrg * and is rounded to a nearby float16 value. The result will be 11001e04c3fSmrg * either normal or infinite. 11101e04c3fSmrg */ 11201e04c3fSmrg e = new_exp + 15; 11301e04c3fSmrg m = _mesa_lroundevenf(flt_m / (float) (1 << 13)); 11401e04c3fSmrg } 11501e04c3fSmrg } 11601e04c3fSmrg 11701e04c3fSmrg assert(0 <= m && m <= 1024); 11801e04c3fSmrg if (m == 1024) { 11901e04c3fSmrg /* The float32 was rounded upwards into the range of the next exponent, 12001e04c3fSmrg * so bump the exponent. This correctly handles the case where f32 12101e04c3fSmrg * should be rounded up to float16 infinity. 12201e04c3fSmrg */ 12301e04c3fSmrg ++e; 12401e04c3fSmrg m = 0; 12501e04c3fSmrg } 12601e04c3fSmrg 12701e04c3fSmrg result = (s << 15) | (e << 10) | m; 12801e04c3fSmrg return result; 12901e04c3fSmrg} 13001e04c3fSmrg 1317ec681f3Smrguint16_t 1327ec681f3Smrg_mesa_float_to_float16_rtz_slow(float val) 1337ec681f3Smrg{ 1347ec681f3Smrg return _mesa_float_to_half_rtz_slow(val); 1357ec681f3Smrg} 13601e04c3fSmrg 13701e04c3fSmrg/** 13801e04c3fSmrg * Convert a 2-byte half float to a 4-byte float. 13901e04c3fSmrg * Based on code from: 14001e04c3fSmrg * http://www.opengl.org/discussion_boards/ubb/Forum3/HTML/008786.html 14101e04c3fSmrg */ 14201e04c3fSmrgfloat 1437ec681f3Smrg_mesa_half_to_float_slow(uint16_t val) 14401e04c3fSmrg{ 1457ec681f3Smrg union fi infnan; 1467ec681f3Smrg union fi magic; 1477ec681f3Smrg union fi f32; 14801e04c3fSmrg 1497ec681f3Smrg infnan.ui = 0x8f << 23; 1507ec681f3Smrg infnan.f = 65536.0f; 1517ec681f3Smrg magic.ui = 0xef << 23; 15201e04c3fSmrg 1537ec681f3Smrg /* Exponent / Mantissa */ 1547ec681f3Smrg f32.ui = (val & 0x7fff) << 13; 15501e04c3fSmrg 1567ec681f3Smrg /* Adjust */ 1577ec681f3Smrg f32.f *= magic.f; 1587ec681f3Smrg /* XXX: The magic mul relies on denorms being available */ 1597ec681f3Smrg 1607ec681f3Smrg /* Inf / NaN */ 1617ec681f3Smrg if (f32.f >= infnan.f) 1627ec681f3Smrg f32.ui |= 0xff << 23; 1637ec681f3Smrg 1647ec681f3Smrg /* Sign */ 1657ec681f3Smrg f32.ui |= (uint32_t)(val & 0x8000) << 16; 1667ec681f3Smrg 1677ec681f3Smrg return f32.f; 16801e04c3fSmrg} 16901e04c3fSmrg 17001e04c3fSmrg/** 17101e04c3fSmrg * Convert 0.0 to 0x00, 1.0 to 0xff. 17201e04c3fSmrg * Values outside the range [0.0, 1.0] will give undefined results. 17301e04c3fSmrg */ 17401e04c3fSmrguint8_t _mesa_half_to_unorm8(uint16_t val) 17501e04c3fSmrg{ 17601e04c3fSmrg const int m = val & 0x3ff; 17701e04c3fSmrg const int e = (val >> 10) & 0x1f; 1787ec681f3Smrg ASSERTED const int s = (val >> 15) & 0x1; 17901e04c3fSmrg 18001e04c3fSmrg /* v = round_to_nearest(1.mmmmmmmmmm * 2^(e-15) * 255) 18101e04c3fSmrg * = round_to_nearest((1.mmmmmmmmmm * 255) * 2^(e-15)) 18201e04c3fSmrg * = round_to_nearest((1mmmmmmmmmm * 255) * 2^(e-25)) 18301e04c3fSmrg * = round_to_zero((1mmmmmmmmmm * 255) * 2^(e-25) + 0.5) 18401e04c3fSmrg * = round_to_zero(((1mmmmmmmmmm * 255) * 2^(e-24) + 1) / 2) 18501e04c3fSmrg * 18601e04c3fSmrg * This happens to give the correct answer for zero/subnormals too 18701e04c3fSmrg */ 18801e04c3fSmrg assert(s == 0 && val <= FP16_ONE); /* check 0 <= this <= 1 */ 18901e04c3fSmrg /* (implies e <= 15, which means the bit-shifts below are safe) */ 19001e04c3fSmrg 19101e04c3fSmrg uint32_t v = ((1 << 10) | m) * 255; 19201e04c3fSmrg v = ((v >> (24 - e)) + 1) >> 1; 19301e04c3fSmrg return v; 19401e04c3fSmrg} 19501e04c3fSmrg 19601e04c3fSmrg/** 19701e04c3fSmrg * Takes a uint16_t, divides by 65536, converts the infinite-precision 19801e04c3fSmrg * result to fp16 with round-to-zero. Used by the ASTC decoder. 19901e04c3fSmrg */ 20001e04c3fSmrguint16_t _mesa_uint16_div_64k_to_half(uint16_t v) 20101e04c3fSmrg{ 20201e04c3fSmrg /* Zero or subnormal. Set the mantissa to (v << 8) and return. */ 20301e04c3fSmrg if (v < 4) 20401e04c3fSmrg return v << 8; 20501e04c3fSmrg 20601e04c3fSmrg /* Count the leading 0s in the uint16_t */ 20701e04c3fSmrg#ifdef HAVE___BUILTIN_CLZ 20801e04c3fSmrg int n = __builtin_clz(v) - 16; 20901e04c3fSmrg#else 21001e04c3fSmrg int n = 16; 21101e04c3fSmrg for (int i = 15; i >= 0; i--) { 21201e04c3fSmrg if (v & (1 << i)) { 21301e04c3fSmrg n = 15 - i; 21401e04c3fSmrg break; 21501e04c3fSmrg } 21601e04c3fSmrg } 21701e04c3fSmrg#endif 21801e04c3fSmrg 21901e04c3fSmrg /* Shift the mantissa up so bit 16 is the hidden 1 bit, 22001e04c3fSmrg * mask it off, then shift back down to 10 bits 22101e04c3fSmrg */ 22201e04c3fSmrg int m = ( ((uint32_t)v << (n + 1)) & 0xffff ) >> 6; 22301e04c3fSmrg 22401e04c3fSmrg /* (0{n} 1 X{15-n}) * 2^-16 22501e04c3fSmrg * = 1.X * 2^(15-n-16) 22601e04c3fSmrg * = 1.X * 2^(14-n - 15) 22701e04c3fSmrg * which is the FP16 form with e = 14 - n 22801e04c3fSmrg */ 22901e04c3fSmrg int e = 14 - n; 23001e04c3fSmrg 23101e04c3fSmrg assert(e >= 1 && e <= 30); 23201e04c3fSmrg assert(m >= 0 && m < 0x400); 23301e04c3fSmrg 23401e04c3fSmrg return (e << 10) | m; 23501e04c3fSmrg} 236