From 50f19e3a668b1b589bf00613d33c7c7c4e6a4954 Mon Sep 17 00:00:00 2001
From: Roland Scheidegger <sroland@vmware.com>
Date: Mon, 11 Nov 2013 15:11:59 +0000
Subject: draw,llvmpipe: use exponent manipulation instead of exp2 for polygon
 offset

Since we explicitly require a integer input we should avoid using exp2 math
(even if we were using optimized versions), which turns the exp2 into a int
sub (plus some casts).

v2: fix bogus uint (needs to be int) math spotted by Matthew, fix comments

Reviewed-by: Jose Fonseca <jfonseca@vmware.com>
---
 src/gallium/auxiliary/draw/draw_pipe_offset.c | 21 +++++++++++++--------
 src/gallium/drivers/llvmpipe/lp_state_setup.c | 26 +++++++++++++++-----------
 2 files changed, 28 insertions(+), 19 deletions(-)

diff --git a/src/gallium/auxiliary/draw/draw_pipe_offset.c b/src/gallium/auxiliary/draw/draw_pipe_offset.c
index 8071bc77b80..34114035ac8 100644
--- a/src/gallium/auxiliary/draw/draw_pipe_offset.c
+++ b/src/gallium/auxiliary/draw/draw_pipe_offset.c
@@ -90,18 +90,23 @@ static void do_offset_tri( struct draw_stage *stage,
    float dzdx = fabsf(a * inv_det);
    float dzdy = fabsf(b * inv_det);
 
-   float zoffset, maxz, bias, mult;
+   float zoffset, mult;
 
    mult = MAX2(dzdx, dzdy) * offset->scale;
 
    if (stage->draw->floating_point_depth) {
-      maxz = MAX3(v0[2], v1[2], v2[2]);
-
-      /**
-       * XXX: TODO optimize this to quickly resolve a pow2 number through
-       *      an exponent only operation.
-       */
-      bias = offset->units * util_fast_exp2(util_get_float32_exponent(maxz) - 23);
+      float bias;
+      union fi maxz;
+      maxz.f = MAX3(v0[2], v1[2], v2[2]);
+      /* just do the math directly on shifted number */
+      maxz.ui &= 0xff << 23;
+      maxz.i -= 23 << 23;
+      /* Clamping to zero means mrd will be zero for very small numbers,
+       * but specs do not indicate this should be prevented by clamping
+       * mrd to smallest normal number instead. */
+      maxz.i = MAX2(maxz.i, 0);
+
+      bias = offset->units * maxz.f;
       zoffset = bias + mult;
    } else {
       zoffset = offset->units + mult;
diff --git a/src/gallium/drivers/llvmpipe/lp_state_setup.c b/src/gallium/drivers/llvmpipe/lp_state_setup.c
index ccc9fb902f3..1685ddce5ab 100644
--- a/src/gallium/drivers/llvmpipe/lp_state_setup.c
+++ b/src/gallium/drivers/llvmpipe/lp_state_setup.c
@@ -31,6 +31,7 @@
 #include "util/u_simple_list.h"
 #include "os/os_time.h"
 #include "gallivm/lp_bld_arit.h"
+#include "gallivm/lp_bld_bitarit.h"
 #include "gallivm/lp_bld_const.h"
 #include "gallivm/lp_bld_debug.h"
 #include "gallivm/lp_bld_init.h"
@@ -268,8 +269,6 @@ lp_do_offset_tri(struct gallivm_state *gallivm,
    LLVMValueRef zeroi = lp_build_const_int32(gallivm, 0);
    LLVMValueRef twoi = lp_build_const_int32(gallivm, 2);
    LLVMValueRef threei  = lp_build_const_int32(gallivm, 3);
-   LLVMValueRef mantissa_bits, exp, bias;
-   LLVMValueRef maxz_value, maxz0z1_value;
 
    /* (res12) = cross(e,f).xy */
    shuffles[0] = twoi;
@@ -319,9 +318,13 @@ lp_do_offset_tri(struct gallivm_state *gallivm,
        *
        * NOTE: Assumes IEEE float32.
        */
+      LLVMValueRef c23_shifted, exp_mask, bias, exp;
+      LLVMValueRef maxz_value, maxz0z1_value;
+
       lp_build_context_init(&int_scalar_bld, gallivm, lp_type_int_vec(32, 32));
 
-      mantissa_bits = lp_build_const_int32(gallivm, 23);
+      c23_shifted = lp_build_const_int32(gallivm, 23 << 23);
+      exp_mask = lp_build_const_int32(gallivm, 0xff << 23);
 
       maxz0z1_value = lp_build_max(&flt_scalar_bld,
                          LLVMBuildExtractElement(b, attribv[0], twoi, ""),
@@ -331,15 +334,16 @@ lp_do_offset_tri(struct gallivm_state *gallivm,
                       LLVMBuildExtractElement(b, attribv[2], twoi, ""),
                       maxz0z1_value);
 
-      /**
-       * XXX: TODO optimize this to quickly resolve a pow2 number through
-       *      an exponent only operation.
-       */
-      exp = lp_build_extract_exponent(&flt_scalar_bld, maxz_value, 0);
-      exp = lp_build_sub(&int_scalar_bld, exp, mantissa_bits);
-      exp = lp_build_int_to_float(&flt_scalar_bld, exp);
+      exp = LLVMBuildBitCast(b, maxz_value, int_scalar_bld.vec_type, "");
+      exp = lp_build_and(&int_scalar_bld, exp, exp_mask);
+      exp = lp_build_sub(&int_scalar_bld, exp, c23_shifted);
+      /* Clamping to zero means mrd will be zero for very small numbers,
+       * but specs do not indicate this should be prevented by clamping
+       * mrd to smallest normal number instead. */
+      exp = lp_build_max(&int_scalar_bld, exp, int_scalar_bld.zero);
+      exp = LLVMBuildBitCast(b, exp, flt_scalar_bld.vec_type, "");
 
-      bias = LLVMBuildFMul(b, lp_build_exp2(&flt_scalar_bld, exp),
+      bias = LLVMBuildFMul(b, exp,
                            lp_build_const_float(gallivm, key->pgon_offset_units),
                            "bias");
 
-- 
cgit v1.2.3