diff options
author | Marek Olšák <[email protected]> | 2018-02-13 16:02:14 +0100 |
---|---|---|
committer | Marek Olšák <[email protected]> | 2018-07-31 18:09:57 -0400 |
commit | 38ab39f6501f78ea7048e8a16a97fdb075b9d8c7 (patch) | |
tree | 8c1166d4d47c30d4e2a1316f62fa33e971c69bb6 /src/util | |
parent | 5be352b4303a759c8ebbbd047365e94f66a098f0 (diff) |
mesa: add ASTC 2D LDR decoder
Tested-by: Mike Lothian <[email protected]>
Tested-By: Gert Wollny <[email protected]>
Tested-by: Dieter Nützel <[email protected]>
Diffstat (limited to 'src/util')
-rw-r--r-- | src/util/half_float.c | 59 | ||||
-rw-r--r-- | src/util/half_float.h | 5 |
2 files changed, 64 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; +} diff --git a/src/util/half_float.h b/src/util/half_float.h index b3bc3f687ad..01557424735 100644 --- a/src/util/half_float.h +++ b/src/util/half_float.h @@ -32,8 +32,13 @@ extern "C" { #endif +#define FP16_ONE 0x3C00 +#define FP16_ZERO 0 + uint16_t _mesa_float_to_half(float val); float _mesa_half_to_float(uint16_t val); +uint8_t _mesa_half_to_unorm8(uint16_t v); +uint16_t _mesa_uint16_div_64k_to_half(uint16_t v); static inline bool _mesa_half_is_negative(uint16_t h) |