OSDN Git Service

nir: fix denorms in unpack_half_1x16()
authorSamuel Iglesias Gonsálvez <siglesias@igalia.com>
Mon, 9 Jul 2018 07:46:59 +0000 (09:46 +0200)
committerAndres Gomez <agomez@igalia.com>
Tue, 17 Sep 2019 20:39:18 +0000 (23:39 +0300)
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 <siglesias@igalia.com>
Signed-off-by: Andres Gomez <agomez@igalia.com>
Reviewed-by: Connor Abbott <cwabbott0@gmail.com> [v2]
src/compiler/nir/nir_constant_expressions.py
src/compiler/nir/nir_lower_alu_to_scalar.c
src/compiler/nir/nir_opcodes.py
src/compiler/spirv/vtn_glsl450.c

index 377f54d..267a261 100644 (file)
@@ -258,6 +258,17 @@ pack_half_1x16(float 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.
+ */
+static float
 unpack_half_1x16(uint16_t u)
 {
    return _mesa_half_to_float(u);
index bcd9290..c0b7cc6 100644 (file)
@@ -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: {
index d4d1f29..3325376 100644 (file)
@@ -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")
 
index 753e74c..dd72a86 100644 (file)
@@ -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