diff options
-rw-r--r-- | src/gallium/auxiliary/gallivm/lp_bld_format.h | 7 | ||||
-rw-r--r-- | src/gallium/auxiliary/gallivm/lp_bld_format_srgb.c | 51 | ||||
-rw-r--r-- | src/gallium/drivers/llvmpipe/lp_screen.c | 7 | ||||
-rw-r--r-- | src/gallium/drivers/llvmpipe/lp_state_fs.c | 64 |
4 files changed, 111 insertions, 18 deletions
diff --git a/src/gallium/auxiliary/gallivm/lp_bld_format.h b/src/gallium/auxiliary/gallivm/lp_bld_format.h index 744d0028941..a7a4ba0a48c 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_format.h +++ b/src/gallium/auxiliary/gallivm/lp_bld_format.h @@ -159,9 +159,10 @@ lp_build_rgb9e5_to_float(struct gallivm_state *gallivm, LLVMValueRef *dst); LLVMValueRef -lp_build_linear_to_srgb(struct gallivm_state *gallivm, - struct lp_type src_type, - LLVMValueRef src); +lp_build_float_to_srgb_packed(struct gallivm_state *gallivm, + const struct util_format_description *dst_fmt, + struct lp_type src_type, + LLVMValueRef *src); LLVMValueRef lp_build_srgb_to_linear(struct gallivm_state *gallivm, diff --git a/src/gallium/auxiliary/gallivm/lp_bld_format_srgb.c b/src/gallium/auxiliary/gallivm/lp_bld_format_srgb.c index f949a8daff1..848d6f8121b 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) @@ -293,3 +293,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; +} diff --git a/src/gallium/drivers/llvmpipe/lp_screen.c b/src/gallium/drivers/llvmpipe/lp_screen.c index 1fed537899a..26aac329e67 100644 --- a/src/gallium/drivers/llvmpipe/lp_screen.c +++ b/src/gallium/drivers/llvmpipe/lp_screen.c @@ -328,12 +328,17 @@ llvmpipe_is_format_supported( struct pipe_screen *_screen, return FALSE; if (bind & PIPE_BIND_RENDER_TARGET) { - if (format_desc->colorspace != UTIL_FORMAT_COLORSPACE_RGB) + if (format_desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) { + if (format_desc->nr_channels < 3) + return FALSE; + } + else if (format_desc->colorspace != UTIL_FORMAT_COLORSPACE_RGB) return FALSE; if (format_desc->layout != UTIL_FORMAT_LAYOUT_PLAIN && format != PIPE_FORMAT_R11G11B10_FLOAT) return FALSE; + assert(format_desc->block.width == 1); assert(format_desc->block.height == 1); diff --git a/src/gallium/drivers/llvmpipe/lp_state_fs.c b/src/gallium/drivers/llvmpipe/lp_state_fs.c index 6afd57a6859..afd01e31725 100644 --- a/src/gallium/drivers/llvmpipe/lp_state_fs.c +++ b/src/gallium/drivers/llvmpipe/lp_state_fs.c @@ -753,6 +753,22 @@ is_arithmetic_format(const struct util_format_description *format_desc) /** + * Checks if this format requires special handling due to required expansion + * to floats for blending, and furthermore has "natural" packed AoS -> unpacked + * SoA conversion. + */ +static INLINE boolean +format_expands_to_float_soa(const struct util_format_description *format_desc) +{ + if (format_desc->format == PIPE_FORMAT_R11G11B10_FLOAT || + format_desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) { + return true; + } + return false; +} + + +/** * Retrieves the type representing the memory layout for a format * * e.g. RGBA16F = 4x half-float and R3G3B2 = 1x byte @@ -764,7 +780,7 @@ lp_mem_type_from_format_desc(const struct util_format_description *format_desc, unsigned i; unsigned chan; - if (format_desc->format == PIPE_FORMAT_R11G11B10_FLOAT) { + if (format_expands_to_float_soa(format_desc)) { /* just make this a 32bit uint */ type->floating = false; type->fixed = false; @@ -812,7 +828,7 @@ lp_blend_type_from_format_desc(const struct util_format_description *format_desc unsigned i; unsigned chan; - if (format_desc->format == PIPE_FORMAT_R11G11B10_FLOAT) { + if (format_expands_to_float_soa(format_desc)) { /* always use ordinary floats for blending */ type->floating = true; type->fixed = false; @@ -938,10 +954,12 @@ convert_to_blend_type(struct gallivm_state *gallivm, bool is_arith; /* - * full custom path for packed floats - none of the later functions would do - * anything useful, and given the lp_type representation they can't be fixed. + * full custom path for packed floats and srgb formats - none of the later + * functions would do anything useful, and given the lp_type representation they + * can't be fixed. Should really have some SoA blend path for these kind of + * formats rather than hacking them in here. */ - if (src_fmt->format == PIPE_FORMAT_R11G11B10_FLOAT) { + if (format_expands_to_float_soa(src_fmt)) { LLVMValueRef tmpsrc[4]; /* * This is pretty suboptimal for this case blending in SoA would be much @@ -975,7 +993,12 @@ convert_to_blend_type(struct gallivm_state *gallivm, tmps = LLVMBuildShuffleVector(builder, tmps, tmps, LLVMConstVector(shuffles, 8), ""); } - lp_build_r11g11b10_to_float(gallivm, tmps, tmpsoa); + if (src_fmt->format == PIPE_FORMAT_R11G11B10_FLOAT) { + lp_build_r11g11b10_to_float(gallivm, tmps, tmpsoa); + } + else { + lp_build_unpack_rgba_soa(gallivm, src_fmt, dst_type, tmps, tmpsoa); + } lp_build_transpose_aos(gallivm, dst_type, tmpsoa, &src[i * 4]); } return; @@ -1089,10 +1112,12 @@ convert_from_blend_type(struct gallivm_state *gallivm, bool is_arith; /* - * full custom path for packed floats - none of the later functions would do - * anything useful, and given the lp_type representation they can't be fixed. + * full custom path for packed floats and srgb formats - none of the later + * functions would do anything useful, and given the lp_type representation they + * can't be fixed. Should really have some SoA blend path for these kind of + * formats rather than hacking them in here. */ - if (src_fmt->format == PIPE_FORMAT_R11G11B10_FLOAT) { + if (format_expands_to_float_soa(src_fmt)) { /* * This is pretty suboptimal for this case blending in SoA would be much * better - we need to transpose the AoS values back to SoA values for @@ -1106,7 +1131,16 @@ convert_from_blend_type(struct gallivm_state *gallivm, for (i = 0; i < num_srcs / 4; i++) { LLVMValueRef tmpsoa[4], tmpdst; lp_build_transpose_aos(gallivm, src_type, &src[i * 4], tmpsoa); - tmpdst = lp_build_float_to_r11g11b10(gallivm, tmpsoa); + /* really really need SoA here */ + + if (src_fmt->format == PIPE_FORMAT_R11G11B10_FLOAT) { + tmpdst = lp_build_float_to_r11g11b10(gallivm, tmpsoa); + } + else { + tmpdst = lp_build_float_to_srgb_packed(gallivm, src_fmt, + src_type, tmpsoa); + } + if (src_type.length == 8) { LLVMValueRef tmpaos, shuffles[8]; unsigned j; @@ -1453,8 +1487,12 @@ generate_unswizzled_blend(struct gallivm_state *gallivm, } } - if (out_format == PIPE_FORMAT_R11G11B10_FLOAT) { - /* the code above can't work for layout_other */ + if (format_expands_to_float_soa(out_format_desc)) { + /* + * the code above can't work for layout_other + * for srgb it would sort of work but we short-circuit swizzles, etc. + * as that is done as part of unpack / pack. + */ dst_channels = 4; /* HACK: this is fake 4 really but need it due to transpose stuff later */ has_alpha = true; swizzle[0] = 0; @@ -1716,7 +1754,7 @@ generate_unswizzled_blend(struct gallivm_state *gallivm, dst_type.length *= block_size / dst_count; - if (out_format == PIPE_FORMAT_R11G11B10_FLOAT) { + if (format_expands_to_float_soa(out_format_desc)) { /* * we need multiple values at once for the conversion, so can as well * load them vectorized here too instead of concatenating later. |