[Mesa-dev] [PATCH 2/2] llvmpipe: add support for b5g6r5_srgb

Jose Fonseca jfonseca at vmware.com
Thu Mar 20 10:41:17 PDT 2014


Series looks good to me.

Jose

----- Original Message -----
> From: Roland Scheidegger <sroland at vmware.com>
> 
> The conversion code for srgb was tuned for n x 4x8bit AoS -> 4 x nxfloat SoA
> (and vice versa), fix this to handle also 16bit 565-style srgb formats.
> Still not really all that generic, things like r10g10b10a2_srgb or
> r4g4b4a4_srgb wouldn't work (the latter trivial to fix, the former would not
> require more work to not crash but near certainly need some higher precision
> calculation) but not needed right now.
> The code is not fully optimized for this (could use more direct calculation
> instead of expanding to 8-bit range first) but should be good enough.
> ---
>  src/gallium/auxiliary/gallivm/lp_bld_format.h      |    1 +
>  src/gallium/auxiliary/gallivm/lp_bld_format_soa.c  |    3 +-
>  src/gallium/auxiliary/gallivm/lp_bld_format_srgb.c |   26 +++++++++++--
>  src/gallium/drivers/llvmpipe/lp_screen.c           |    1 +
>  src/gallium/drivers/llvmpipe/lp_state_fs.c         |   39
>  ++++++++++++++++++--
>  5 files changed, 61 insertions(+), 9 deletions(-)
> 
> diff --git a/src/gallium/auxiliary/gallivm/lp_bld_format.h
> b/src/gallium/auxiliary/gallivm/lp_bld_format.h
> index a7a4ba0..1177fb2 100644
> --- a/src/gallium/auxiliary/gallivm/lp_bld_format.h
> +++ b/src/gallium/auxiliary/gallivm/lp_bld_format.h
> @@ -167,6 +167,7 @@ lp_build_float_to_srgb_packed(struct gallivm_state
> *gallivm,
>  LLVMValueRef
>  lp_build_srgb_to_linear(struct gallivm_state *gallivm,
>                          struct lp_type src_type,
> +                        unsigned chan_bits,
>                          LLVMValueRef src);
>  
>  
> diff --git a/src/gallium/auxiliary/gallivm/lp_bld_format_soa.c
> b/src/gallium/auxiliary/gallivm/lp_bld_format_soa.c
> index 81cd2b0..ff2887e 100644
> --- a/src/gallium/auxiliary/gallivm/lp_bld_format_soa.c
> +++ b/src/gallium/auxiliary/gallivm/lp_bld_format_soa.c
> @@ -165,13 +165,12 @@ lp_build_unpack_rgba_soa(struct gallivm_state *gallivm,
>  
>           if (type.floating) {
>              if (format_desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) {
> -               assert(width == 8);
>                 if (format_desc->swizzle[3] == chan) {
>                    input = lp_build_unsigned_norm_to_float(gallivm, width,
>                    type, input);
>                 }
>                 else {
>                    struct lp_type conv_type = lp_uint_type(type);
> -                  input = lp_build_srgb_to_linear(gallivm, conv_type,
> input);
> +                  input = lp_build_srgb_to_linear(gallivm, conv_type, width,
> input);
>                 }
>              }
>              else {
> diff --git a/src/gallium/auxiliary/gallivm/lp_bld_format_srgb.c
> b/src/gallium/auxiliary/gallivm/lp_bld_format_srgb.c
> index 6645151..e4849fe 100644
> --- a/src/gallium/auxiliary/gallivm/lp_bld_format_srgb.c
> +++ b/src/gallium/auxiliary/gallivm/lp_bld_format_srgb.c
> @@ -88,11 +88,12 @@
>   *   (3rd order polynomial is required for crappy but just sufficient
>   accuracy)
>   *
>   * @param src   integer (vector) value(s) to convert
> - *              (8 bit values unpacked to 32 bit already).
> + *              (chan_bits bit values unpacked to 32 bit already).
>   */
>  LLVMValueRef
>  lp_build_srgb_to_linear(struct gallivm_state *gallivm,
>                          struct lp_type src_type,
> +                        unsigned chan_bits,
>                          LLVMValueRef src)
>  {
>     struct lp_type f32_type = lp_type_float_vec(32, src_type.length * 32);
> @@ -105,6 +106,8 @@ lp_build_srgb_to_linear(struct gallivm_state *gallivm,
>     };
>  
>     assert(src_type.width == 32);
> +   /* Technically this would work with more bits too but would be
> inaccurate. */
> +   assert(chan_bits <= 8);
>  
>     lp_build_context_init(&f32_bld, gallivm, f32_type);
>  
> @@ -124,6 +127,12 @@ lp_build_srgb_to_linear(struct gallivm_state *gallivm,
>      */
>     /* doing the 1/255 mul as part of the approximation */
>     srcf = lp_build_int_to_float(&f32_bld, src);
> +   if (chan_bits != 8) {
> +      /* could adjust all the constants instead */
> +      LLVMValueRef rescale_const = lp_build_const_vec(gallivm, f32_type,
> +                                                      255.0f / ((1 <<
> chan_bits) - 1));
> +      srcf = lp_build_mul(&f32_bld, srcf, rescale_const);
> +   }
>     lin_const = lp_build_const_vec(gallivm, f32_type, 1.0f / (12.6f *
>     255.0f));
>     part_lin = lp_build_mul(&f32_bld, srcf, lin_const);
>  
> @@ -150,6 +159,7 @@ lp_build_srgb_to_linear(struct gallivm_state *gallivm,
>  static LLVMValueRef
>  lp_build_linear_to_srgb(struct gallivm_state *gallivm,
>                          struct lp_type src_type,
> +                        unsigned chan_bits,
>                          LLVMValueRef src)
>  {
>     LLVMBuilderRef builder = gallivm->builder;
> @@ -292,6 +302,13 @@ lp_build_linear_to_srgb(struct gallivm_state *gallivm,
>     is_linear = lp_build_compare(gallivm, src_type, PIPE_FUNC_LEQUAL, src,
>     lin_thresh);
>     tmp = lp_build_select(&f32_bld, is_linear, lin, pow_final);
>  
> +   if (chan_bits != 8) {
> +      /* could adjust all the constants instead */
> +      LLVMValueRef rescale_const = lp_build_const_vec(gallivm, src_type,
> +                                                      ((1 << chan_bits) - 1)
> / 255.0f);
> +      tmp = lp_build_mul(&f32_bld, tmp, rescale_const);
> +   }
> +
>     f32_bld.type.sign = 0;
>     return lp_build_iround(&f32_bld, tmp);
>  }
> @@ -300,7 +317,9 @@ lp_build_linear_to_srgb(struct gallivm_state *gallivm,
>  /**
>   * Convert linear float soa values to packed srgb AoS values.
>   * This only handles packed formats which are 4x8bit in size
> - * (rgba and rgbx plus swizzles).
> + * (rgba and rgbx plus swizzles), and 16bit 565-style formats
> + * with no alpha. (In the latter case the return values won't be
> + * fully packed, it will look like r5g6b5x16r5g6b5x16...)
>   *
>   * @param src   float SoA (vector) values to convert.
>   */
> @@ -320,7 +339,8 @@ lp_build_float_to_srgb_packed(struct gallivm_state
> *gallivm,
>  
>     /* rgb is subject to linear->srgb conversion, alpha is not */
>     for (chan = 0; chan < 3; chan++) {
> -      tmpsrgb[chan] = lp_build_linear_to_srgb(gallivm, src_type, src[chan]);
> +      unsigned chan_bits = dst_fmt->channel[dst_fmt->swizzle[chan]].size;
> +      tmpsrgb[chan] = lp_build_linear_to_srgb(gallivm, src_type, chan_bits,
> src[chan]);
>     }
>     /*
>      * can't use lp_build_conv since we want to keep values as 32bit
> diff --git a/src/gallium/drivers/llvmpipe/lp_screen.c
> b/src/gallium/drivers/llvmpipe/lp_screen.c
> index c8e95fe..fe06e34 100644
> --- a/src/gallium/drivers/llvmpipe/lp_screen.c
> +++ b/src/gallium/drivers/llvmpipe/lp_screen.c
> @@ -342,6 +342,7 @@ llvmpipe_is_format_supported( struct pipe_screen
> *_screen,
>  
>     if (bind & PIPE_BIND_RENDER_TARGET) {
>        if (format_desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) {
> +         /* this is a lie actually other formats COULD exist where we would
> fail */
>           if (format_desc->nr_channels < 3)
>              return FALSE;
>        }
> diff --git a/src/gallium/drivers/llvmpipe/lp_state_fs.c
> b/src/gallium/drivers/llvmpipe/lp_state_fs.c
> index 2f9f907..5e28f0e 100644
> --- a/src/gallium/drivers/llvmpipe/lp_state_fs.c
> +++ b/src/gallium/drivers/llvmpipe/lp_state_fs.c
> @@ -868,12 +868,12 @@ lp_mem_type_from_format_desc(const struct
> util_format_description *format_desc,
>     unsigned chan;
>  
>     if (format_expands_to_float_soa(format_desc)) {
> -      /* just make this a 32bit uint */
> +      /* just make this a uint with width of block */
>        type->floating = false;
>        type->fixed = false;
>        type->sign = false;
>        type->norm = false;
> -      type->width = 32;
> +      type->width = format_desc->block.bits;
>        type->length = 1;
>        return;
>     }
> @@ -1137,12 +1137,24 @@ convert_to_blend_type(struct gallivm_state *gallivm,
>         * This is pretty suboptimal for this case blending in SoA would be
>         much
>         * better, since conversion gets us SoA values so need to convert
>         back.
>         */
> -      assert(src_type.width == 32);
> +      assert(src_type.width == 32 || src_type.width == 16);
>        assert(dst_type.floating);
>        assert(dst_type.width == 32);
>        assert(dst_type.length % 4 == 0);
>        assert(num_srcs % 4 == 0);
>  
> +      if (src_type.width == 16) {
> +         /* expand 4x16bit values to 4x32bit */
> +         struct lp_type type32x4 = src_type;
> +         LLVMTypeRef ltype32x4;
> +         unsigned num_fetch = dst_type.length == 8 ? num_srcs / 2 : num_srcs
> / 4;
> +         type32x4.width = 32;
> +         ltype32x4 = lp_build_vec_type(gallivm, type32x4);
> +         for (i = 0; i < num_fetch; i++) {
> +            src[i] = LLVMBuildZExt(builder, src[i], ltype32x4, "");
> +         }
> +         src_type.width = 32;
> +      }
>        for (i = 0; i < 4; i++) {
>           tmpsrc[i] = src[i];
>        }
> @@ -1298,7 +1310,7 @@ convert_from_blend_type(struct gallivm_state *gallivm,
>        assert(src_type.floating);
>        assert(src_type.width == 32);
>        assert(src_type.length % 4 == 0);
> -      assert(dst_type.width == 32);
> +      assert(dst_type.width == 32 || dst_type.width == 16);
>  
>        for (i = 0; i < num_srcs / 4; i++) {
>           LLVMValueRef tmpsoa[4], tmpdst;
> @@ -1333,6 +1345,25 @@ convert_from_blend_type(struct gallivm_state *gallivm,
>              src[i] = tmpdst;
>           }
>        }
> +      if (dst_type.width == 16) {
> +         struct lp_type type16x8 = dst_type;
> +         struct lp_type type32x4 = dst_type;
> +         LLVMTypeRef ltype16x4, ltypei64, ltypei128;
> +         unsigned num_fetch = src_type.length == 8 ? num_srcs / 2 : num_srcs
> / 4;
> +         type16x8.length = 8;
> +         type32x4.width = 32;
> +         ltypei128 = LLVMIntTypeInContext(gallivm->context, 128);
> +         ltypei64 = LLVMIntTypeInContext(gallivm->context, 64);
> +         ltype16x4 = lp_build_vec_type(gallivm, dst_type);
> +         /* We could do vector truncation but it doesn't generate very good
> code */
> +         for (i = 0; i < num_fetch; i++) {
> +            src[i] = lp_build_pack2(gallivm, type32x4, type16x8,
> +                                    src[i], lp_build_zero(gallivm,
> type32x4));
> +            src[i] = LLVMBuildBitCast(builder, src[i], ltypei128, "");
> +            src[i] = LLVMBuildTrunc(builder, src[i], ltypei64, "");
> +            src[i] = LLVMBuildBitCast(builder, src[i], ltype16x4, "");
> +         }
> +      }
>        return;
>     }
>  
> --
> 1.7.9.5
> 


More information about the mesa-dev mailing list