diff options
-rw-r--r-- | src/glsl/ir_constant_expression.cpp | 18 | ||||
-rw-r--r-- | src/glsl/nir/nir_constant_expressions.py | 15 | ||||
-rw-r--r-- | src/glsl/nir/nir_opcodes.py | 2 | ||||
-rw-r--r-- | src/mesa/main/imports.c | 25 | ||||
-rw-r--r-- | src/mesa/main/imports.h | 3 | ||||
-rw-r--r-- | src/util/Makefile.sources | 1 | ||||
-rw-r--r-- | src/util/rounding.h | 58 |
7 files changed, 82 insertions, 40 deletions
diff --git a/src/glsl/ir_constant_expression.cpp b/src/glsl/ir_constant_expression.cpp index 388c4c28683..ecebc3cdc3b 100644 --- a/src/glsl/ir_constant_expression.cpp +++ b/src/glsl/ir_constant_expression.cpp @@ -35,6 +35,7 @@ #include <math.h> #include "main/core.h" /* for MAX2, MIN2, CLAMP */ +#include "util/rounding.h" /* for _mesa_roundeven */ #include "ir.h" #include "glsl_types.h" #include "program/hash_table.h" @@ -245,8 +246,8 @@ pack_snorm_1x8(float x) * We must first cast the float to an int, because casting a negative * float to a uint is undefined. */ - return (uint8_t) (int8_t) - _mesa_round_to_even(CLAMP(x, -1.0f, +1.0f) * 127.0f); + return (uint8_t) (int) + _mesa_roundevenf(CLAMP(x, -1.0f, +1.0f) * 127.0f); } /** @@ -267,8 +268,8 @@ pack_snorm_1x16(float x) * We must first cast the float to an int, because casting a negative * float to a uint is undefined. */ - return (uint16_t) (int16_t) - _mesa_round_to_even(CLAMP(x, -1.0f, +1.0f) * 32767.0f); + return (uint16_t) (int) + _mesa_roundevenf(CLAMP(x, -1.0f, +1.0f) * 32767.0f); } /** @@ -322,7 +323,7 @@ pack_unorm_1x8(float x) * * packUnorm4x8: round(clamp(c, 0, +1) * 255.0) */ - return (uint8_t) _mesa_round_to_even(CLAMP(x, 0.0f, 1.0f) * 255.0f); + return (uint8_t) (int) _mesa_roundevenf(CLAMP(x, 0.0f, 1.0f) * 255.0f); } /** @@ -340,7 +341,8 @@ pack_unorm_1x16(float x) * * packUnorm2x16: round(clamp(c, 0, +1) * 65535.0) */ - return (uint16_t) _mesa_round_to_even(CLAMP(x, 0.0f, 1.0f) * 65535.0f); + return (uint16_t) (int) + _mesa_roundevenf(CLAMP(x, 0.0f, 1.0f) * 65535.0f); } /** @@ -733,9 +735,9 @@ ir_expression::constant_expression_value(struct hash_table *variable_context) case ir_unop_round_even: for (unsigned c = 0; c < op[0]->type->components(); c++) { if (op[0]->type->base_type == GLSL_TYPE_DOUBLE) - data.d[c] = _mesa_round_to_even(op[0]->value.d[c]); + data.d[c] = _mesa_roundeven(op[0]->value.d[c]); else - data.f[c] = _mesa_round_to_even(op[0]->value.f[c]); + data.f[c] = _mesa_roundevenf(op[0]->value.f[c]); } break; diff --git a/src/glsl/nir/nir_constant_expressions.py b/src/glsl/nir/nir_constant_expressions.py index 22bc4f09583..bf82fe533d6 100644 --- a/src/glsl/nir/nir_constant_expressions.py +++ b/src/glsl/nir/nir_constant_expressions.py @@ -28,6 +28,7 @@ template = """\ #include <math.h> #include "main/core.h" +#include "util/rounding.h" /* for _mesa_roundeven */ #include "nir_constant_expressions.h" #if defined(_MSC_VER) && (_MSC_VER < 1800) @@ -68,8 +69,8 @@ pack_snorm_1x8(float x) * We must first cast the float to an int, because casting a negative * float to a uint is undefined. */ - return (uint8_t) (int8_t) - _mesa_round_to_even(CLAMP(x, -1.0f, +1.0f) * 127.0f); + return (uint8_t) (int) + _mesa_roundevenf(CLAMP(x, -1.0f, +1.0f) * 127.0f); } /** @@ -90,8 +91,8 @@ pack_snorm_1x16(float x) * We must first cast the float to an int, because casting a negative * float to a uint is undefined. */ - return (uint16_t) (int16_t) - _mesa_round_to_even(CLAMP(x, -1.0f, +1.0f) * 32767.0f); + return (uint16_t) (int) + _mesa_roundevenf(CLAMP(x, -1.0f, +1.0f) * 32767.0f); } /** @@ -145,7 +146,8 @@ pack_unorm_1x8(float x) * * packUnorm4x8: round(clamp(c, 0, +1) * 255.0) */ - return (uint8_t) _mesa_round_to_even(CLAMP(x, 0.0f, 1.0f) * 255.0f); + return (uint8_t) (int) + _mesa_roundevenf(CLAMP(x, 0.0f, 1.0f) * 255.0f); } /** @@ -163,7 +165,8 @@ pack_unorm_1x16(float x) * * packUnorm2x16: round(clamp(c, 0, +1) * 65535.0) */ - return (uint16_t) _mesa_round_to_even(CLAMP(x, 0.0f, 1.0f) * 65535.0f); + return (uint16_t) (int) + _mesa_roundevenf(CLAMP(x, 0.0f, 1.0f) * 65535.0f); } /** diff --git a/src/glsl/nir/nir_opcodes.py b/src/glsl/nir/nir_opcodes.py index 77f3bb8266d..062cd628b8d 100644 --- a/src/glsl/nir/nir_opcodes.py +++ b/src/glsl/nir/nir_opcodes.py @@ -183,7 +183,7 @@ unop("ftrunc", tfloat, "truncf(src0)") unop("fceil", tfloat, "ceilf(src0)") unop("ffloor", tfloat, "floorf(src0)") unop("ffract", tfloat, "src0 - floorf(src0)") -unop("fround_even", tfloat, "_mesa_round_to_even(src0)") +unop("fround_even", tfloat, "_mesa_roundevenf(src0)") # Trigonometric operations. diff --git a/src/mesa/main/imports.c b/src/mesa/main/imports.c index ac8deeb97c9..68c7316575c 100644 --- a/src/mesa/main/imports.c +++ b/src/mesa/main/imports.c @@ -45,6 +45,7 @@ #include <stdio.h> #include <stdarg.h> #include "c99_math.h" +#include "util/rounding.h" /* for _mesa_roundeven */ #include "imports.h" #include "context.h" #include "mtypes.h" @@ -307,26 +308,6 @@ _mesa_bitcount_64(uint64_t n) #endif -/* Using C99 rounding functions for roundToEven() implementation is - * difficult, because round(), rint, and nearbyint() are affected by - * fesetenv(), which the application may have done for its own - * purposes. Mesa's IROUND macro is close to what we want, but it - * rounds away from 0 on n + 0.5. - */ -int -_mesa_round_to_even(float val) -{ - int rounded = IROUND(val); - - if (val - floor(val) == 0.5) { - if (rounded % 2 != 0) - rounded += val > 0 ? -1 : 1; - } - - return rounded; -} - - /** * Convert a 4-byte float to a 2-byte half float. * @@ -388,7 +369,7 @@ _mesa_float_to_half(float val) * or normal. */ e = 0; - m = _mesa_round_to_even((1 << 24) * fabsf(fi.f)); + m = (int) _mesa_roundevenf((1 << 24) * fabsf(fi.f)); } else if (new_exp > 15) { /* map this value to infinity */ @@ -402,7 +383,7 @@ _mesa_float_to_half(float val) * either normal or infinite. */ e = new_exp + 15; - m = _mesa_round_to_even(flt_m / (float) (1 << 13)); + m = (int) _mesa_roundevenf(flt_m / (float) (1 << 13)); } } diff --git a/src/mesa/main/imports.h b/src/mesa/main/imports.h index ee6b39945a3..29f249980a0 100644 --- a/src/mesa/main/imports.h +++ b/src/mesa/main/imports.h @@ -433,9 +433,6 @@ _mesa_fls(unsigned int n) #endif } -extern int -_mesa_round_to_even(float val); - extern GLhalfARB _mesa_float_to_half(float f); diff --git a/src/util/Makefile.sources b/src/util/Makefile.sources index 560ea836aa1..3e0d02bad1e 100644 --- a/src/util/Makefile.sources +++ b/src/util/Makefile.sources @@ -14,6 +14,7 @@ MESA_UTIL_FILES := \ register_allocate.h \ rgtc.c \ rgtc.h \ + rounding.h \ set.c \ set.h \ simple_list.h \ diff --git a/src/util/rounding.h b/src/util/rounding.h new file mode 100644 index 00000000000..c8be45057b6 --- /dev/null +++ b/src/util/rounding.h @@ -0,0 +1,58 @@ +/* + * Copyright © 2015 Intel Corporation + * + * 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. + */ + +#include <math.h> + +/* The C standard library has functions round()/rint()/nearbyint() that round + * their arguments according to the rounding mode set in the floating-point + * control register. While there are trunc()/ceil()/floor() functions that do + * a specific operation without modifying the rounding mode, there is no + * roundeven() in any version of C. + * + * Technical Specification 18661 (ISO/IEC TS 18661-1:2014) adds roundeven(), + * but it's unfortunately not implemented by glibc. + * + * This implementation differs in that it does not raise the inexact exception. + * + * We use rint() to implement these functions, with the assumption that the + * floating-point rounding mode has not been changed from the default Round + * to Nearest. + */ + +/** + * \brief Rounds \c x to the nearest integer, with ties to the even integer. + */ +static inline float +_mesa_roundevenf(float x) +{ + return rintf(x); +} + +/** + * \brief Rounds \c x to the nearest integer, with ties to the even integer. + */ +static inline double +_mesa_roundeven(double x) +{ + return rint(x); +} |