[Mesa-dev,2/2] i965/vec4: fix precision of f2b

Submitted by Iago Toral Quiroga on Feb. 25, 2016, 10:15 a.m.

Details

Message ID 1456395349-8923-2-git-send-email-itoral@igalia.com
State New
Headers show
Series "Series without cover letter" ( rev: 1 ) in Mesa

Not browsing as part of any series.

Commit Message

Iago Toral Quiroga Feb. 25, 2016, 10:15 a.m.
From the OpenGL 4.2 spec:

"When a constructor is used to convert any integer or floating-point type to a
 bool, 0 and 0.0 are converted to false, and non-zero values are converted to
 true."

Thus, even the smallest non-zero floating value should be translated to true.
This behavior has been verified also with proprietary NVIDIA drivers.

Currently, we implement this conversion as a cmp.nz operation with floats,
subject to floating-point precision limitations, and as a result, relatively
small non-zero floating point numbers return false instead of true.

This patch fixes the problem by getting rid of the sign bit (to cover the case
of -0.0) and testing the result against 0u using an integer comparison instead.
---
 src/mesa/drivers/dri/i965/brw_vec4_nir.cpp | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)

Patch hide | download patch | download mbox

diff --git a/src/mesa/drivers/dri/i965/brw_vec4_nir.cpp b/src/mesa/drivers/dri/i965/brw_vec4_nir.cpp
index 74ec4f0..d2e12fb 100644
--- a/src/mesa/drivers/dri/i965/brw_vec4_nir.cpp
+++ b/src/mesa/drivers/dri/i965/brw_vec4_nir.cpp
@@ -1288,9 +1288,17 @@  vec4_visitor::nir_emit_alu(nir_alu_instr *instr)
       emit(MOV(dst, negate(op[0])));
       break;
 
-   case nir_op_f2b:
-      emit(CMP(dst, op[0], brw_imm_f(0.0f), BRW_CONDITIONAL_NZ));
-      break;
+   case nir_op_f2b: {
+      /* Because comparing to 0.0f is subject to precision limitations, do the
+       * comparison using integers (we need to get rid of the sign bit for that)
+       */
+      if (devinfo->gen >= 8)
+         op[0] = resolve_source_modifiers(op[0]);
+      op[0] = retype(op[0], BRW_REGISTER_TYPE_UD);
+      emit(AND(dst_reg(op[0]), op[0], brw_imm_ud(0x7FFFFFFFu)));
+      emit(CMP(dst, op[0], brw_imm_ud(0u), BRW_CONDITIONAL_NZ));
+       break;
+   }
 
    case nir_op_i2b:
       emit(CMP(dst, op[0], brw_imm_d(0), BRW_CONDITIONAL_NZ));