From: Samuel Iglesias Gonsálvez Date: Mon, 9 Jul 2018 07:46:59 +0000 (+0200) Subject: nir: fix denorms in unpack_half_1x16() X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=1e0e3ed15a8cfb98a182714bcb3e55cfab5c3df7;p=mesa.git nir: fix denorms in unpack_half_1x16() According to VK_KHR_shader_float_controls: "Denormalized values obtained via unpacking an integer into a vector of values with smaller bit width and interpreting those values as floating-point numbers must: be flushed to zero, unless the entry point is declared with the code:DenormPreserve execution mode." v2: - Add nir_op_unpack_half_2x16_flush_to_zero opcode (Connor). v3: - Adapt to use the new NIR lowering framework (Andres). v4: - Updated to renamed shader info member and enum values (Andres). v5: - Simplify flags logic operations (Caio). Signed-off-by: Samuel Iglesias Gonsálvez Signed-off-by: Andres Gomez Reviewed-by: Connor Abbott [v2] --- diff --git a/src/compiler/nir/nir_constant_expressions.py b/src/compiler/nir/nir_constant_expressions.py index 377f54d6521..267a2615964 100644 --- a/src/compiler/nir/nir_constant_expressions.py +++ b/src/compiler/nir/nir_constant_expressions.py @@ -254,6 +254,17 @@ pack_half_1x16(float x) return _mesa_float_to_half(x); } +/** + * Evaluate one component of unpackHalf2x16. + */ +static float +unpack_half_1x16_flush_to_zero(uint16_t u) +{ + if (0 == (u & 0x7c00)) + u &= 0x8000; + return _mesa_half_to_float(u); +} + /** * Evaluate one component of unpackHalf2x16. */ diff --git a/src/compiler/nir/nir_lower_alu_to_scalar.c b/src/compiler/nir/nir_lower_alu_to_scalar.c index bcd92908253..c0b7cc604ef 100644 --- a/src/compiler/nir/nir_lower_alu_to_scalar.c +++ b/src/compiler/nir/nir_lower_alu_to_scalar.c @@ -145,13 +145,23 @@ lower_alu_instr_scalar(nir_builder *b, nir_instr *instr, void *_data) */ return NULL; + case nir_op_unpack_half_2x16_flush_to_zero: case nir_op_unpack_half_2x16: { if (!b->shader->options->lower_unpack_half_2x16) return NULL; nir_ssa_def *packed = nir_ssa_for_alu_src(b, alu, 0); - return nir_vec2(b, nir_unpack_half_2x16_split_x(b, packed), - nir_unpack_half_2x16_split_y(b, packed)); + if (alu->op == nir_op_unpack_half_2x16_flush_to_zero) { + return nir_vec2(b, + nir_unpack_half_2x16_split_x_flush_to_zero(b, + packed), + nir_unpack_half_2x16_split_y_flush_to_zero(b, + packed)); + } else { + return nir_vec2(b, + nir_unpack_half_2x16_split_x(b, packed), + nir_unpack_half_2x16_split_y(b, packed)); + } } case nir_op_pack_uvec2_to_uint: { diff --git a/src/compiler/nir/nir_opcodes.py b/src/compiler/nir/nir_opcodes.py index d4d1f295eee..3325376c81c 100644 --- a/src/compiler/nir/nir_opcodes.py +++ b/src/compiler/nir/nir_opcodes.py @@ -362,14 +362,23 @@ unop_horiz("unpack_64_4x16", 4, tuint16, 1, tuint64, unop_horiz("unpack_32_2x16", 2, tuint16, 1, tuint32, "dst.x = src0.x; dst.y = src0.x >> 16;") -# Lowered floating point unpacking operations. +unop_horiz("unpack_half_2x16_flush_to_zero", 2, tfloat32, 1, tuint32, """ +dst.x = unpack_half_1x16_flush_to_zero((uint16_t)(src0.x & 0xffff)); +dst.y = unpack_half_1x16_flush_to_zero((uint16_t)(src0.x << 16)); +""") +# Lowered floating point unpacking operations. unop_convert("unpack_half_2x16_split_x", tfloat32, tuint32, "unpack_half_1x16((uint16_t)(src0 & 0xffff))") unop_convert("unpack_half_2x16_split_y", tfloat32, tuint32, "unpack_half_1x16((uint16_t)(src0 >> 16))") +unop_convert("unpack_half_2x16_split_x_flush_to_zero", tfloat32, tuint32, + "unpack_half_1x16_flush_to_zero((uint16_t)(src0 & 0xffff))") +unop_convert("unpack_half_2x16_split_y_flush_to_zero", tfloat32, tuint32, + "unpack_half_1x16_flush_to_zero((uint16_t)(src0 >> 16))") + unop_convert("unpack_32_2x16_split_x", tuint16, tuint32, "src0") unop_convert("unpack_32_2x16_split_y", tuint16, tuint32, "src0 >> 16") diff --git a/src/compiler/spirv/vtn_glsl450.c b/src/compiler/spirv/vtn_glsl450.c index 753e74cf73c..dd72a86e21c 100644 --- a/src/compiler/spirv/vtn_glsl450.c +++ b/src/compiler/spirv/vtn_glsl450.c @@ -387,7 +387,8 @@ build_atan2(nir_builder *b, nir_ssa_def *y, nir_ssa_def *x) static nir_op vtn_nir_alu_op_for_spirv_glsl_opcode(struct vtn_builder *b, - enum GLSLstd450 opcode) + enum GLSLstd450 opcode, + unsigned execution_mode) { switch (opcode) { case GLSLstd450Round: return nir_op_fround_even; @@ -433,7 +434,11 @@ vtn_nir_alu_op_for_spirv_glsl_opcode(struct vtn_builder *b, case GLSLstd450UnpackUnorm4x8: return nir_op_unpack_unorm_4x8; case GLSLstd450UnpackSnorm2x16: return nir_op_unpack_snorm_2x16; case GLSLstd450UnpackUnorm2x16: return nir_op_unpack_unorm_2x16; - case GLSLstd450UnpackHalf2x16: return nir_op_unpack_half_2x16; + case GLSLstd450UnpackHalf2x16: + if (execution_mode & FLOAT_CONTROLS_DENORM_FLUSH_TO_ZERO_FP16) + return nir_op_unpack_half_2x16_flush_to_zero; + else + return nir_op_unpack_half_2x16; case GLSLstd450UnpackDouble2x32: return nir_op_unpack_64_2x32; default: @@ -678,13 +683,16 @@ handle_glsl450_alu(struct vtn_builder *b, enum GLSLstd450 entrypoint, return; } - default: + default: { + unsigned execution_mode = + b->shader->info.float_controls_execution_mode; val->ssa->def = nir_build_alu(&b->nb, - vtn_nir_alu_op_for_spirv_glsl_opcode(b, entrypoint), + vtn_nir_alu_op_for_spirv_glsl_opcode(b, entrypoint, execution_mode), src[0], src[1], src[2], NULL); return; } + } } static void