[Mesa-dev] [PATCH v2 15/29] nir: fix denorms in unpack_half_1x16()

Samuel Iglesias Gonsálvez siglesias at igalia.com
Tue Dec 18 10:34:10 UTC 2018


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 <siglesias at 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



More information about the mesa-dev mailing list