[Mesa-dev] [PATCH 3/6] glsl: move half<->float convertion to util
Matt Turner
mattst88 at gmail.com
Sat Oct 10 12:09:11 PDT 2015
On Sat, Oct 10, 2015 at 11:47 AM, Rob Clark <robdclark at gmail.com> wrote:
> From: Rob Clark <robclark at freedesktop.org>
>
> Needed in NIR too, so move out of mesa/main/imports.c
>
> Signed-off-by: Rob Clark <robclark at freedesktop.org>
> ---
> src/glsl/Makefile.am | 1 +
> src/mesa/main/imports.c | 148 --------------------------------------
> src/mesa/main/imports.h | 38 ++++++++--
> src/util/Makefile.sources | 2 +
> src/util/convert.c | 179 ++++++++++++++++++++++++++++++++++++++++++++++
> src/util/convert.h | 43 +++++++++++
> 6 files changed, 259 insertions(+), 152 deletions(-)
> create mode 100644 src/util/convert.c
> create mode 100644 src/util/convert.h
>
> diff --git a/src/glsl/Makefile.am b/src/glsl/Makefile.am
> index 3265391..347919b 100644
> --- a/src/glsl/Makefile.am
> +++ b/src/glsl/Makefile.am
> @@ -160,6 +160,7 @@ glsl_compiler_SOURCES = \
> glsl_compiler_LDADD = \
> libglsl.la \
> $(top_builddir)/src/libglsl_util.la \
> + $(top_builddir)/src/util/libmesautil.la \
> $(PTHREAD_LIBS)
>
> glsl_test_SOURCES = \
> diff --git a/src/mesa/main/imports.c b/src/mesa/main/imports.c
> index 350e675..230ebbc 100644
> --- a/src/mesa/main/imports.c
> +++ b/src/mesa/main/imports.c
> @@ -307,154 +307,6 @@ _mesa_bitcount_64(uint64_t n)
> }
> #endif
>
> -
> -/**
> - * Convert a 4-byte float to a 2-byte half float.
> - *
> - * Not all float32 values can be represented exactly as a float16 value. We
> - * round such intermediate float32 values to the nearest float16. When the
> - * float32 lies exactly between to float16 values, we round to the one with
> - * an even mantissa.
> - *
> - * This rounding behavior has several benefits:
> - * - It has no sign bias.
> - *
> - * - It reproduces the behavior of real hardware: opcode F32TO16 in Intel's
> - * GPU ISA.
> - *
> - * - By reproducing the behavior of the GPU (at least on Intel hardware),
> - * compile-time evaluation of constant packHalf2x16 GLSL expressions will
> - * result in the same value as if the expression were executed on the GPU.
> - */
> -GLhalfARB
> -_mesa_float_to_half(float val)
> -{
> - const fi_type fi = {val};
> - const int flt_m = fi.i & 0x7fffff;
> - const int flt_e = (fi.i >> 23) & 0xff;
> - const int flt_s = (fi.i >> 31) & 0x1;
> - int s, e, m = 0;
> - GLhalfARB result;
> -
> - /* sign bit */
> - s = flt_s;
> -
> - /* handle special cases */
> - if ((flt_e == 0) && (flt_m == 0)) {
> - /* zero */
> - /* m = 0; - already set */
> - e = 0;
> - }
> - else if ((flt_e == 0) && (flt_m != 0)) {
> - /* denorm -- denorm float maps to 0 half */
> - /* m = 0; - already set */
> - e = 0;
> - }
> - else if ((flt_e == 0xff) && (flt_m == 0)) {
> - /* infinity */
> - /* m = 0; - already set */
> - e = 31;
> - }
> - else if ((flt_e == 0xff) && (flt_m != 0)) {
> - /* NaN */
> - m = 1;
> - e = 31;
> - }
> - else {
> - /* regular number */
> - const int new_exp = flt_e - 127;
> - if (new_exp < -14) {
> - /* The float32 lies in the range (0.0, min_normal16) and is rounded
> - * to a nearby float16 value. The result will be either zero, subnormal,
> - * or normal.
> - */
> - e = 0;
> - m = _mesa_lroundevenf((1 << 24) * fabsf(fi.f));
> - }
> - else if (new_exp > 15) {
> - /* map this value to infinity */
> - /* m = 0; - already set */
> - e = 31;
> - }
> - else {
> - /* The float32 lies in the range
> - * [min_normal16, max_normal16 + max_step16)
> - * and is rounded to a nearby float16 value. The result will be
> - * either normal or infinite.
> - */
> - e = new_exp + 15;
> - m = _mesa_lroundevenf(flt_m / (float) (1 << 13));
> - }
> - }
> -
> - assert(0 <= m && m <= 1024);
> - if (m == 1024) {
> - /* The float32 was rounded upwards into the range of the next exponent,
> - * so bump the exponent. This correctly handles the case where f32
> - * should be rounded up to float16 infinity.
> - */
> - ++e;
> - m = 0;
> - }
> -
> - result = (s << 15) | (e << 10) | m;
> - return result;
> -}
> -
> -
> -/**
> - * Convert a 2-byte half float to a 4-byte float.
> - * Based on code from:
> - * http://www.opengl.org/discussion_boards/ubb/Forum3/HTML/008786.html
> - */
> -float
> -_mesa_half_to_float(GLhalfARB val)
> -{
> - /* XXX could also use a 64K-entry lookup table */
> - 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;
> -
> - /* sign bit */
> - flt_s = s;
> -
> - /* 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;
> - }
> -
> - fi.i = (flt_s << 31) | (flt_e << 23) | flt_m;
> - result = fi.f;
> - return result;
> -}
> -
> /*@}*/
>
>
> diff --git a/src/mesa/main/imports.h b/src/mesa/main/imports.h
> index 9024758..3a09304 100644
> --- a/src/mesa/main/imports.h
> +++ b/src/mesa/main/imports.h
> @@ -42,6 +42,7 @@
> #include "compiler.h"
> #include "glheader.h"
> #include "errors.h"
> +#include "util/convert.h"
>
> #ifdef __cplusplus
> extern "C" {
> @@ -396,12 +397,41 @@ _mesa_flsll(uint64_t n)
> #endif
> }
>
> +/**
> + * Convert a 4-byte float to a 2-byte half float.
> + *
> + * Not all float32 values can be represented exactly as a float16 value. We
> + * round such intermediate float32 values to the nearest float16. When the
> + * float32 lies exactly between to float16 values, we round to the one with
> + * an even mantissa.
> + *
> + * This rounding behavior has several benefits:
> + * - It has no sign bias.
> + *
> + * - It reproduces the behavior of real hardware: opcode F32TO16 in Intel's
> + * GPU ISA.
> + *
> + * - By reproducing the behavior of the GPU (at least on Intel hardware),
> + * compile-time evaluation of constant packHalf2x16 GLSL expressions will
> + * result in the same value as if the expression were executed on the GPU.
> + */
> +static inline GLhalfARB
> +_mesa_float_to_half(float val)
> +{
> + return float_to_half(val);
> +}
>
> -extern GLhalfARB
> -_mesa_float_to_half(float f);
>
> -extern float
> -_mesa_half_to_float(GLhalfARB h);
> +/**
> + * Convert a 2-byte half float to a 4-byte float.
> + * Based on code from:
> + * http://www.opengl.org/discussion_boards/ubb/Forum3/HTML/008786.html
> + */
> +static inline float
> +_mesa_half_to_float(GLhalfARB val)
> +{
> + return half_to_float(val);
> +}
>
> static inline bool
> _mesa_half_is_negative(GLhalfARB h)
> diff --git a/src/util/Makefile.sources b/src/util/Makefile.sources
> index e45431d..71b2a25 100644
> --- a/src/util/Makefile.sources
> +++ b/src/util/Makefile.sources
> @@ -1,5 +1,7 @@
> MESA_UTIL_FILES := \
> bitset.h \
> + convert.c \
> + convert.h \
> debug.c \
> debug.h \
> format_srgb.h \
> diff --git a/src/util/convert.c b/src/util/convert.c
> new file mode 100644
> index 0000000..e86e322
> --- /dev/null
> +++ b/src/util/convert.c
half-float.c seems like a better name.
> @@ -0,0 +1,179 @@
> +/*
> + * Copyright © 2015 Red Hat
What the?
No. This code was written by Brian (commit 7eb3e9b) and Chad (commit
529b6d1). Its copyright belongs to VMware and Intel (and probably
"gking" from [1])
[1] https://web.archive.org/web/20030303115125/http://www.opengl.org/discussion_boards/ubb/Forum3/HTML/008786.html
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> + * IN THE SOFTWARE.
> + *
> + * Authors:
> + * Rob Clark <robclark at freedesktop.org>
We're trying to stop with author lists generally, but listing yourself
as an author on some code you copied from somewhere else is not okay.
> + */
> +
> +#include <math.h>
> +#include <assert.h>
> +#include "convert.h"
> +#include "rounding.h"
> +
> +typedef union { float f; int32_t i; uint32_t u; } fi_type;
> +
> +/**
> + * Convert a 4-byte float to a 2-byte half float.
> + *
> + * Not all float32 values can be represented exactly as a float16 value. We
> + * round such intermediate float32 values to the nearest float16. When the
> + * float32 lies exactly between to float16 values, we round to the one with
> + * an even mantissa.
> + *
> + * This rounding behavior has several benefits:
> + * - It has no sign bias.
> + *
> + * - It reproduces the behavior of real hardware: opcode F32TO16 in Intel's
> + * GPU ISA.
> + *
> + * - By reproducing the behavior of the GPU (at least on Intel hardware),
> + * compile-time evaluation of constant packHalf2x16 GLSL expressions will
> + * result in the same value as if the expression were executed on the GPU.
> + */
> +uint16_t
> +float_to_half(float val)
> +{
> + const fi_type fi = {val};
> + const int flt_m = fi.i & 0x7fffff;
> + const int flt_e = (fi.i >> 23) & 0xff;
> + const int flt_s = (fi.i >> 31) & 0x1;
> + int s, e, m = 0;
> + uint16_t result;
> +
> + /* sign bit */
> + s = flt_s;
> +
> + /* handle special cases */
> + if ((flt_e == 0) && (flt_m == 0)) {
> + /* zero */
> + /* m = 0; - already set */
> + e = 0;
> + }
> + else if ((flt_e == 0) && (flt_m != 0)) {
> + /* denorm -- denorm float maps to 0 half */
> + /* m = 0; - already set */
> + e = 0;
> + }
> + else if ((flt_e == 0xff) && (flt_m == 0)) {
> + /* infinity */
> + /* m = 0; - already set */
> + e = 31;
> + }
> + else if ((flt_e == 0xff) && (flt_m != 0)) {
> + /* NaN */
> + m = 1;
> + e = 31;
> + }
> + else {
> + /* regular number */
> + const int new_exp = flt_e - 127;
> + if (new_exp < -14) {
> + /* The float32 lies in the range (0.0, min_normal16) and is rounded
> + * to a nearby float16 value. The result will be either zero, subnormal,
> + * or normal.
> + */
> + e = 0;
> + m = _mesa_lroundevenf((1 << 24) * fabsf(fi.f));
> + }
> + else if (new_exp > 15) {
> + /* map this value to infinity */
> + /* m = 0; - already set */
> + e = 31;
> + }
> + else {
> + /* The float32 lies in the range
> + * [min_normal16, max_normal16 + max_step16)
> + * and is rounded to a nearby float16 value. The result will be
> + * either normal or infinite.
> + */
> + e = new_exp + 15;
> + m = _mesa_lroundevenf(flt_m / (float) (1 << 13));
> + }
> + }
> +
> + assert(0 <= m && m <= 1024);
> + if (m == 1024) {
> + /* The float32 was rounded upwards into the range of the next exponent,
> + * so bump the exponent. This correctly handles the case where f32
> + * should be rounded up to float16 infinity.
> + */
> + ++e;
> + m = 0;
> + }
> +
> + result = (s << 15) | (e << 10) | m;
> + return result;
> +}
> +
> +
> +/**
> + * Convert a 2-byte half float to a 4-byte float.
> + * Based on code from:
> + * http://www.opengl.org/discussion_boards/ubb/Forum3/HTML/008786.html
> + */
> +float
> +half_to_float(uint16_t val)
> +{
> + /* XXX could also use a 64K-entry lookup table */
> + 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;
> +
> + /* sign bit */
> + flt_s = s;
> +
> + /* 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;
> + }
> +
> + fi.i = (flt_s << 31) | (flt_e << 23) | flt_m;
> + result = fi.f;
> + return result;
> +}
> diff --git a/src/util/convert.h b/src/util/convert.h
> new file mode 100644
> index 0000000..30d36a1
> --- /dev/null
> +++ b/src/util/convert.h
> @@ -0,0 +1,43 @@
> +/*
> + * Copyright © 2015 Red Hat
Seems fishy.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> + * IN THE SOFTWARE.
> + *
> + * Authors:
> + * Rob Clark <robclark at freedesktop.org>
Again, no author list.
> + */
> +
> +#ifndef _MATH_H_
> +#define _MATH_H_
Wrong name.
> +
> +#include <stdint.h>
> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif
> +
> +uint16_t float_to_half(float val);
> +float half_to_float(uint16_t val);
I think these functions need to be prefixed with something -- util_*
or something or just leave them as _mesa_*.
> +
> +#ifdef __cplusplus
> +} /* extern C */
> +#endif
> +
> +#endif /* _MATH_H_ */
More information about the mesa-dev
mailing list