That is, evaluate constant expressions of the following functions: packSnorm2x16 unpackSnorm2x16 packUnorm2x16 unpackUnorm2x16 packHalf2x16 unpackHalf2x16
Signed-off-by: Chad Versace <chad.vers...@linux.intel.com> --- src/glsl/ir_constant_expression.cpp | 362 ++++++++++++++++++++++++++++++++++++ 1 file changed, 362 insertions(+) diff --git a/src/glsl/ir_constant_expression.cpp b/src/glsl/ir_constant_expression.cpp index 17b54b9..2038498 100644 --- a/src/glsl/ir_constant_expression.cpp +++ b/src/glsl/ir_constant_expression.cpp @@ -94,6 +94,332 @@ bitcast_f2u(float f) return u; } +/** + * Evaluate one component of a floating-poing 2x16 unpacking function. + */ +typedef uint16_t +(*pack_1x16_func_t)(float); + +/** + * Evaluate one component of a floating-poing 2x16 unpacking function. + */ +typedef void +(*unpack_1x16_func_t)(uint16_t, float*); + +/** + * Evaluate a 2x16 floating-point packing function. + */ +static uint32_t +pack_2x16(pack_1x16_func_t pack_1x16, + float x, float y) +{ + /* From section 8.4 of the GLSL ES 3.00 spec: + * + * packSnorm2x16 + * ------------- + * The first component of the vector will be written to the least + * significant bits of the output; the last component will be written to + * the most significant bits. + * + * The specifications for the other packing functions contain similar + * language. + */ + uint32_t u = 0; + u |= ((uint32_t) pack_1x16(x) << 0); + u |= ((uint32_t) pack_1x16(y) << 16); + return u; +} + +/** + * Evaluate a 2x16 floating-point unpacking function. + */ +static void +unpack_2x16(unpack_1x16_func_t unpack_1x16, + uint32_t u, + float *x, float *y) +{ + /* From section 8.4 of the GLSL ES 3.00 spec: + * + * unpackSnorm2x16 + * --------------- + * The first component of the returned vector will be extracted from + * the least significant bits of the input; the last component will be + * extracted from the most significant bits. + * + * The specifications for the other unpacking functions contain similar + * language. + */ + unpack_1x16((uint16_t) (u & 0xffff), x); + unpack_1x16((uint16_t) (u >> 16), y); +} + +/** + * Evaluate one component of packSnorm2x16. + */ +static uint16_t +pack_snorm_1x16(float x) +{ + /* From section 8.4 of the GLSL ES 3.00 spec: + * + * packSnorm2x16 + * --------------- + * The conversion for component c of v to fixed point is done as + * follows: + * + * packSnorm2x16: round(clamp(c, -1, +1) * 32767.0) + */ + return (uint16_t) round_to_even(CLAMP(x, -1.0f, +1.0f) * 32767.0f); +} + +/** + * Evaluate one component of unpackSnorm2x16. + */ +static void +unpack_snorm_1x16(uint16_t u, float *f) +{ + /* From section 8.4 of the GLSL ES 3.00 spec: + * + * unpackSnorm2x16 + * --------------- + * The conversion for unpacked fixed-point value f to floating point is + * done as follows: + * + * unpackSnorm2x16: clamp(f / 32767.0, -1,+1) + */ + *f = CLAMP((int16_t) u / 32767.0f, -1.0f, +1.0f); +} + +/** + * Evaluate one component packUnorm2x16. + */ +static uint16_t +pack_unorm_1x16(float x) +{ + /* From section 8.4 of the GLSL ES 3.00 spec: + * + * packUnorm2x16 + * --------------- + * The conversion for component c of v to fixed point is done as + * follows: + * + * packUnorm2x16: round(clamp(c, 0, +1) * 65535.0) + */ + return (uint16_t) round_to_even(CLAMP(x, 0.0f, 1.0f) * 65535.0f); +} + + +/** + * Evaluate one component of unpackUnorm2x16. + */ +static void +unpack_unorm_1x16(uint16_t u, float *f) +{ + /* From section 8.4 of the GLSL ES 3.00 spec: + * + * unpackUnorm2x16 + * --------------- + * The conversion for unpacked fixed-point value f to floating point is + * done as follows: + * + * unpackUnorm2x16: f / 65535.0 + */ + *f = (float) u / 65535.0f; +} + + +/** + * Evaluate one component of packHalf2x16. + */ +static uint16_t +pack_half_1x16(float x) +{ + /* The bit layout of a float16 is: + * sign: 15 + * exponent: 10:14 + * mantissa: 0:9 + * + * The sign, exponent, and mantissa of a float16 determine its value thus: + * + * if e = 0 and m = 0, then zero: (-1)^s * 0 + * if e = 0 and m != 0, then subnormal: (-1)^s * 2^(e - 14) * (m / 2^10) + * if 0 < e < 31, then normal: (-1)^s * 2^(e - 15) * (1 + m / 2^10) + * if e = 31 and m = 0, then inf: (-1)^s * inf + * if e = 31 and m != 0, then NaN + * + * where 0 <= m < 2^10 . + */ + + /* Calculate the resultant float16's sign, exponent, and mantissa + * bits. + */ + const int s = (copysign(1.0f, x) < 0) ? 1 : 0; + int e; + int m; + + switch (fpclassify(x)) { + case FP_NAN: + /* Any representation with e = 31 and m != 0 suffices. */ + return 0xffffu; + case FP_INFINITE: + e = 31; + m = 0; + break; + case FP_SUBNORMAL: + case FP_ZERO: + /* Subnormal float32 values are too small to be represented as + * a float16. + */ + e = 0; + m = 0; + break; + case FP_NORMAL: { + /* Represent the absolute value of the float32 input in the form + * + * 2^E * F, where 0.5 <= F < 1 . + */ + int E; + float F; + F = frexpf(fabs(x), &E); + + /* Some key boundary values of float16 are: + * + * min_subnormal = 2^(-14) * (1 / 2^10) + * max_subnormal = 2^(-14) * (1023 / 2^10) + * min_normal = 2^(1 - 15) * (1 + 1 / 2^10) + * max_normal = 2^(30 - 15) * (1 + 1023 / 2^10) + * + * Representing the same boundary values in the form returned + * by frexpf(), + * + * 2^e * f where 0.5 <= f < 1, + * + * gives + * + * min_subnormal = 2^(-14) * (1 / 2^10) + * = 2^(-23) * (1 / 2) + * = 2^(-23) * 0.5 + * + * max_subnormal = 2^(-14) * (1023 / 2^10) + * = 2^(-14) * 0.9990234375 + * + * min_normal = 2^(1 - 15) * (1 + 0 / 2^10) + * = 2^(-14) + * = 2^(-13) * 0.5 + * + * max_normal = 2^(30 - 15) * (1 + 1023 / 2^10) + * = 2^15 * (2^10 + 1023) / 2^10 + * = 2^16 * (2^10 + 1023) / 2^11 + * = 2^16 * 0.99951171875 + * + * Now calculate the results's exponent and mantissa by comparing the + * float32 input against the boundary values above. + */ + if (E == -23 && F < 0.5f) { + /* The float32 input is too small to be represented as a float16. The + * result is zero. + */ + e = 0; + m = 0; + } else if (E < -13 || (E == -13 && F < 0.5f)) { + /* The resultant float16 value is subnormal. Calculate m: + * + * 2^E * F = 2^(14) * (m / 2^10) + * = 2^(-24) * m + * m = 2^(E + 24) * F + */ + e = 0; + m = powf(2, E + 24) * F; + } else if (E < 16 || (E == 16 && F <= 0.99951171875f)) { + /* The resultant float16 is normal. Calculate e and m: + * + * 2^E * F = 2^(e - 15) * (1 + m / 2^10) (1) + * = 2^(e - 15) * (2^10 + m) / 2^10 (2) + * = 2^(e - 14) * (2^10 + m) / 2^11 (3) + * + * Substituting + * + * e1 := E (4) + * f1 := F (5) + * e2 := e - 14 (6) + * f2 := (2^10 + m) / 2^11 (7) + * + * transforms the equation to + * + * 2^e1 * f1 = 2^e2 * f2 (8) + * + * By definition, f1 lies in the range [0.5, 1). By equation 7, f2 + * lies there also. This observation combined with equation 8 implies + * f1 = f2, which in turn implies e1 = e2. Therefore + * + * e = E + 14 + * m = 2^11 * F - 2^10 + */ + e = E + 14; + m = powf(2, 11) * F - powf(2, 10); + } else { + /* The float32 input is too large to represent as a float16. The + * result is infinite. + */ + e = 31; + m = 0; + } + break; + } + default: + assert(0); + break; + } + + assert(s == 0 || s == 1); + assert(0 <= e && e <= 31); + assert(0 <= m && m <= 1023); + + return (s << 15) | (e << 10) | m; +} + +/** + * Evaluate one component of unpackHalf2x16. + */ +static void +unpack_half_1x16(uint16_t u, float *f) +{ + /* The bit layout of a float16 is: + * sign: 15 + * exponent: 10:14 + * mantissa: 0:9 + * + * The sign, exponent, and mantissa of a float16 determine its value thus: + * + * if e = 0 and m = 0, then zero: (-1)^s * 0 + * if e = 0 and m != 0, then subnormal: (-1)^s * 2^(e - 14) * (m / 2^10) + * if 0 < e < 31, then normal: (-1)^s * 2^(e - 15) * (1 + m / 2^10) + * if e = 31 and m = 0, then inf: (-1)^s * inf + * if e = 31 and m != 0, then NaN + * + * where 0 <= m < 2^10 . + */ + + int s = (u >> 15) & 0x1; + int e = (u >> 10) & 0x1f; + int m = u & 0x3ff; + + float sign = s ? -1 : 1; + + if (e == 0) { + /* The float16 is zero or subnormal. */ + *f = sign * pow(2, -24) * m; + } else if (1 <= e && e <= 30) { + /* The float16 is normal. */ + *f = sign * pow(2, e - 15) * (1.0 + m / 1024.0); + } else if (e == 31 && m == 0) { + *f = sign * INFINITY; + } else if (e == 31 && m != 0) { + *f = NAN; + } else { + assert(0); + } +} + ir_constant * ir_rvalue::constant_expression_value(struct hash_table *variable_context) { @@ -459,6 +785,42 @@ ir_expression::constant_expression_value(struct hash_table *variable_context) } break; + case ir_unop_pack_snorm_2x16: + assert(op[0]->type == glsl_type::vec2_type); + data.u[0] = pack_2x16(pack_snorm_1x16, + op[0]->value.f[0], + op[0]->value.f[1]); + break; + case ir_unop_unpack_snorm_2x16: + assert(op[0]->type == glsl_type::uint_type); + unpack_2x16(unpack_snorm_1x16, + op[0]->value.u[0], + &data.f[0], &data.f[1]); + break; + case ir_unop_pack_unorm_2x16: + assert(op[0]->type == glsl_type::vec2_type); + data.u[0] = pack_2x16(pack_unorm_1x16, + op[0]->value.f[0], + op[0]->value.f[1]); + break; + case ir_unop_unpack_unorm_2x16: + assert(op[0]->type == glsl_type::uint_type); + unpack_2x16(unpack_unorm_1x16, + op[0]->value.u[0], + &data.f[0], &data.f[1]); + break; + case ir_unop_pack_half_2x16: + assert(op[0]->type == glsl_type::vec2_type); + data.u[0] = pack_2x16(pack_half_1x16, + op[0]->value.f[0], + op[0]->value.f[1]); + break; + case ir_unop_unpack_half_2x16: + assert(op[0]->type == glsl_type::uint_type); + unpack_2x16(unpack_half_1x16, + op[0]->value.u[0], + &data.f[0], &data.f[1]); + break; case ir_binop_pow: assert(op[0]->type->base_type == GLSL_TYPE_FLOAT); for (unsigned c = 0; c < op[0]->type->components(); c++) { -- 1.8.1 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev