[Mesa-dev] [PATCH 2/2] gallivm: fix float->SNORM conversion

Jose Fonseca jfonseca at vmware.com
Sat Jul 27 03:48:02 PDT 2013


Series looks alright AFAICT.

Jose

----- Original Message -----
> From: Roland Scheidegger <sroland at vmware.com>
> 
> Just like the UNORM case we need to use round to nearest, not trunc.
> (There's also another problem, we're using the formula for SNORM->float
> which will produce a value below -1.0 for the most negative value which
> according to both OpenGL and d3d10 would need clamping. However, no actual
> failures have been observed due to that hence keep cheating on that.)
> ---
>  src/gallium/auxiliary/gallivm/lp_bld_conv.c       |   52
>  ++++++++++++++++-----
>  src/gallium/auxiliary/gallivm/lp_bld_format_soa.c |    6 +++
>  2 files changed, 47 insertions(+), 11 deletions(-)
> 
> diff --git a/src/gallium/auxiliary/gallivm/lp_bld_conv.c
> b/src/gallium/auxiliary/gallivm/lp_bld_conv.c
> index cbea966..56c1581 100644
> --- a/src/gallium/auxiliary/gallivm/lp_bld_conv.c
> +++ b/src/gallium/auxiliary/gallivm/lp_bld_conv.c
> @@ -257,6 +257,7 @@ lp_build_clamped_float_to_unsigned_norm(struct
> gallivm_state *gallivm,
>        bias = (double)(1ULL << (mantissa - dst_width));
>  
>        res = LLVMBuildFMul(builder, src, lp_build_const_vec(gallivm,
>        src_type, scale), "");
> +      /* instead of fadd/and could (with sse2) just use lp_build_iround */
>        res = LLVMBuildFAdd(builder, res, lp_build_const_vec(gallivm,
>        src_type, bias), "");
>        res = LLVMBuildBitCast(builder, res, int_vec_type, "");
>        res = LLVMBuildAnd(builder, res,
> @@ -742,7 +743,6 @@ lp_build_conv(struct gallivm_state *gallivm,
>        }
>        else {
>           double dst_scale = lp_const_scale(dst_type);
> -         LLVMTypeRef tmp_vec_type;
>  
>           if (dst_scale != 1.0) {
>              LLVMValueRef scale = lp_build_const_vec(gallivm, tmp_type,
>              dst_scale);
> @@ -750,19 +750,37 @@ lp_build_conv(struct gallivm_state *gallivm,
>                 tmp[i] = LLVMBuildFMul(builder, tmp[i], scale, "");
>           }
>  
> -         /* Use an equally sized integer for intermediate computations */
> -         tmp_type.floating = FALSE;
> -         tmp_vec_type = lp_build_vec_type(gallivm, tmp_type);
> -         for(i = 0; i < num_tmps; ++i) {
> +         /*
> +          * these functions will use fptosi in some form which won't work
> +          * with 32bit uint dst.
> +          */
> +         assert(dst_type.sign || dst_type.width < 32);
> +
> +         if (dst_type.sign && dst_type.norm && !dst_type.fixed) {
> +            struct lp_build_context bld;
> +
> +            lp_build_context_init(&bld, gallivm, tmp_type);
> +            for(i = 0; i < num_tmps; ++i) {
> +               tmp[i] = lp_build_iround(&bld, tmp[i]);
> +            }
> +            tmp_type.floating = FALSE;
> +         }
> +         else {
> +            LLVMTypeRef tmp_vec_type;
> +
> +            tmp_type.floating = FALSE;
> +            tmp_vec_type = lp_build_vec_type(gallivm, tmp_type);
> +            for(i = 0; i < num_tmps; ++i) {
>  #if 0
> -            if(dst_type.sign)
> -               tmp[i] = LLVMBuildFPToSI(builder, tmp[i], tmp_vec_type, "");
> -            else
> -               tmp[i] = LLVMBuildFPToUI(builder, tmp[i], tmp_vec_type, "");
> +               if(dst_type.sign)
> +                  tmp[i] = LLVMBuildFPToSI(builder, tmp[i], tmp_vec_type,
> "");
> +               else
> +                  tmp[i] = LLVMBuildFPToUI(builder, tmp[i], tmp_vec_type,
> "");
>  #else
> -           /* FIXME: there is no SSE counterpart for LLVMBuildFPToUI */
> -            tmp[i] = LLVMBuildFPToSI(builder, tmp[i], tmp_vec_type, "");
> +              /* FIXME: there is no SSE counterpart for LLVMBuildFPToUI */
> +               tmp[i] = LLVMBuildFPToSI(builder, tmp[i], tmp_vec_type, "");
>  #endif
> +            }
>           }
>        }
>     }
> @@ -860,6 +878,18 @@ lp_build_conv(struct gallivm_state *gallivm,
>               for(i = 0; i < num_tmps; ++i)
>                  tmp[i] = LLVMBuildFMul(builder, tmp[i], scale, "");
>            }
> +
> +          /* the formula above will produce value below -1.0 for most
> negative
> +           * value but everything seems happy with that hence disable for
> now */
> +          if (0 && !src_type.fixed && src_type.norm && src_type.sign) {
> +             struct lp_build_context bld;
> +
> +             lp_build_context_init(&bld, gallivm, dst_type);
> +             for(i = 0; i < num_tmps; ++i) {
> +                tmp[i] = lp_build_max(&bld, tmp[i],
> +                                      lp_build_const_vec(gallivm, dst_type,
> -1.0f));
> +             }
> +          }
>        }
>      }
>      else {
> diff --git a/src/gallium/auxiliary/gallivm/lp_bld_format_soa.c
> b/src/gallium/auxiliary/gallivm/lp_bld_format_soa.c
> index 114ce03..81cd2b0 100644
> --- a/src/gallium/auxiliary/gallivm/lp_bld_format_soa.c
> +++ b/src/gallium/auxiliary/gallivm/lp_bld_format_soa.c
> @@ -39,6 +39,7 @@
>  #include "lp_bld_gather.h"
>  #include "lp_bld_debug.h"
>  #include "lp_bld_format.h"
> +#include "lp_bld_arit.h"
>  
>  
>  void
> @@ -221,6 +222,11 @@ lp_build_unpack_rgba_soa(struct gallivm_state *gallivm,
>                 double scale = 1.0 / ((1 << (format_desc->channel[chan].size
>                 - 1)) - 1);
>                 LLVMValueRef scale_val = lp_build_const_vec(gallivm, type,
>                 scale);
>                 input = LLVMBuildFMul(builder, input, scale_val, "");
> +               /* the formula above will produce value below -1.0 for most
> negative
> +                * value but everything seems happy with that hence disable
> for now */
> +               if (0)
> +                  input = lp_build_max(&bld, input,
> +                                       lp_build_const_vec(gallivm, type,
> -1.0f));
>              }
>           }
>           else if (format_desc->channel[chan].pure_integer) {
> --
> 1.7.9.5
> 


More information about the mesa-dev mailing list