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) Signed-off-by: Samuel Iglesias Gonsálvez <sigles...@igalia.com> --- src/compiler/nir/nir_constant_expressions.py | 13 +++++++++++++ src/compiler/nir/nir_lower_alu_to_scalar.c | 11 +++++++++-- src/compiler/nir/nir_opcodes.py | 11 ++++++++++- src/compiler/spirv/vtn_glsl450.c | 15 +++++++++++---- 4 files changed, 43 insertions(+), 7 deletions(-) diff --git a/src/compiler/nir/nir_constant_expressions.py b/src/compiler/nir/nir_constant_expressions.py index 84cf819e921..83837457b63 100644 --- a/src/compiler/nir/nir_constant_expressions.py +++ b/src/compiler/nir/nir_constant_expressions.py @@ -261,6 +261,19 @@ 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 (u < 0x0400) + u = 0; + if (u & 0x8000 && !(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 9b175878c15..e0b650014a4 100644 --- a/src/compiler/nir/nir_lower_alu_to_scalar.c +++ b/src/compiler/nir/nir_lower_alu_to_scalar.c @@ -126,6 +126,7 @@ lower_alu_instr_scalar(nir_alu_instr *instr, nir_builder *b) */ return false; + case nir_op_unpack_half_2x16_flush_to_zero: case nir_op_unpack_half_2x16: { if (!b->shader->options->lower_unpack_half_2x16) return false; @@ -133,8 +134,14 @@ lower_alu_instr_scalar(nir_alu_instr *instr, nir_builder *b) nir_ssa_def *packed = nir_ssa_for_alu_src(b, instr, 0); nir_ssa_def *comps[2]; - comps[0] = nir_unpack_half_2x16_split_x(b, packed); - comps[1] = nir_unpack_half_2x16_split_y(b, packed); + + if (instr->op == nir_op_unpack_half_2x16_flush_to_zero) { + comps[0] = nir_unpack_half_2x16_split_x_flush_to_zero(b, packed); + comps[1] = nir_unpack_half_2x16_split_y_flush_to_zero(b, packed); + } else { + comps[0] = nir_unpack_half_2x16_split_x(b, packed); + comps[1] = nir_unpack_half_2x16_split_y(b, packed); + } nir_ssa_def *vec = nir_vec(b, comps, 2); nir_ssa_def_rewrite_uses(&instr->dest.dest.ssa, nir_src_for_ssa(vec)); diff --git a/src/compiler/nir/nir_opcodes.py b/src/compiler/nir/nir_opcodes.py index 21a3847d2ce..de10fd4d510 100644 --- a/src/compiler/nir/nir_opcodes.py +++ b/src/compiler/nir/nir_opcodes.py @@ -330,14 +330,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 c40594290a3..38ecafae21f 100644 --- a/src/compiler/spirv/vtn_glsl450.c +++ b/src/compiler/spirv/vtn_glsl450.c @@ -513,7 +513,8 @@ build_frexp64(nir_builder *b, nir_ssa_def *x, nir_ssa_def **exponent) static nir_op vtn_nir_alu_op_for_spirv_glsl_opcode(struct vtn_builder *b, - enum GLSLstd450 opcode) + enum GLSLstd450 opcode, + nir_rounding_mode rounding_mode) { switch (opcode) { case GLSLstd450Round: return nir_op_fround_even; @@ -559,7 +560,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 (rounding_mode & SHADER_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: @@ -821,11 +826,13 @@ handle_glsl450_alu(struct vtn_builder *b, enum GLSLstd450 entrypoint, return; } - default: + default: { + nir_rounding_mode rounding_mode = b->shader->info.shader_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, rounding_mode), src[0], src[1], src[2], NULL); + } return; } } -- 2.19.1 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/mesa-dev