X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fgallium%2Fauxiliary%2Fgallivm%2Flp_bld_format_srgb.c;h=2b1fe643849324b8d631904bb1321bb1ec1a4616;hb=8c5283dc177ec8538d1154e71f915aac2066a093;hp=217aaa998383a58841cd2d802751c4f78236c8e6;hpb=6bcbb0dc82f9f72c747ef39ed80a4ee0d883ce8e;p=mesa.git diff --git a/src/gallium/auxiliary/gallivm/lp_bld_format_srgb.c b/src/gallium/auxiliary/gallivm/lp_bld_format_srgb.c index 217aaa99838..2b1fe643849 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_format_srgb.c +++ b/src/gallium/auxiliary/gallivm/lp_bld_format_srgb.c @@ -147,7 +147,7 @@ lp_build_srgb_to_linear(struct gallivm_state *gallivm, * * @param src float (vector) value(s) to convert. */ -LLVMValueRef +static LLVMValueRef lp_build_linear_to_srgb(struct gallivm_state *gallivm, struct lp_type src_type, LLVMValueRef src) @@ -170,6 +170,8 @@ lp_build_linear_to_srgb(struct gallivm_state *gallivm, */ float exp_f = 2.0f / 3.0f; + /* some compilers can't do exp2f, so this is exp2f(127.0f/exp_f - 127.0f) */ + float exp2f_c = 1.30438178253e+19f; float coeff_f = 0.62996f; LLVMValueRef pow_approx, coeff, x2, exponent, pow_1, pow_2; struct lp_type int_type = lp_int_type(src_type); @@ -179,8 +181,7 @@ lp_build_linear_to_srgb(struct gallivm_state *gallivm, */ exponent = lp_build_const_vec(gallivm, src_type, exp_f); coeff = lp_build_const_vec(gallivm, src_type, - exp2f(127.0f / exp_f - 127.0f) * - powf(coeff_f, 1.0f / exp_f)); + exp2f_c * powf(coeff_f, 1.0f / exp_f)); /* premultiply src */ tmp = lp_build_mul(&f32_bld, coeff, src); @@ -241,8 +242,10 @@ lp_build_linear_to_srgb(struct gallivm_state *gallivm, * error metric if you'd want to tweak them, they also MUST fit with * the crappy polynomial above for srgb->linear since it is required * that each srgb value maps back to the same value). - * This function has an error of max +-0.17 (and we'd only require +-0.6), - * for the approximated srgb->linear values the error is naturally larger + * This function has an error of max +-0.17. Not sure this is actually + * enough, we require +-0.6 but that may include the +-0.5 from integer + * conversion. Seems to pass all relevant tests though... + * For the approximated srgb->linear values the error is naturally larger * (+-0.42) but still accurate enough (required +-0.5 essentially). * All in all (including min/max clamp, conversion) 15 instructions. * FMA would help (minus 2 instructions). @@ -292,3 +295,52 @@ lp_build_linear_to_srgb(struct gallivm_state *gallivm, f32_bld.type.sign = 0; return lp_build_iround(&f32_bld, tmp); } + + +/** + * 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). + * + * @param src float SoA (vector) values to convert. + */ +LLVMValueRef +lp_build_float_to_srgb_packed(struct gallivm_state *gallivm, + const struct util_format_description *dst_fmt, + struct lp_type src_type, + LLVMValueRef *src) +{ + LLVMBuilderRef builder = gallivm->builder; + unsigned chan; + struct lp_build_context f32_bld; + struct lp_type int32_type = lp_int_type(src_type); + LLVMValueRef tmpsrgb[4], alpha, dst; + + lp_build_context_init(&f32_bld, gallivm, src_type); + + /* 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]); + } + /* + * can't use lp_build_conv since we want to keep values as 32bit + * here so we can interleave with rgb to go from SoA->AoS. + */ + alpha = lp_build_clamp(&f32_bld, src[3], f32_bld.zero, f32_bld.one); + alpha = lp_build_mul(&f32_bld, alpha, + lp_build_const_vec(gallivm, src_type, 255.0f)); + tmpsrgb[3] = lp_build_iround(&f32_bld, alpha); + + dst = lp_build_zero(gallivm, int32_type); + for (chan = 0; chan < dst_fmt->nr_channels; chan++) { + if (dst_fmt->swizzle[chan] <= UTIL_FORMAT_SWIZZLE_W) { + unsigned ls; + LLVMValueRef shifted, shift_val; + ls = dst_fmt->channel[dst_fmt->swizzle[chan]].shift; + shift_val = lp_build_const_int_vec(gallivm, int32_type, ls); + shifted = LLVMBuildShl(builder, tmpsrgb[chan], shift_val, ""); + dst = LLVMBuildOr(builder, dst, shifted, ""); + } + } + return dst; +}