summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/gallium/auxiliary/gallivm/lp_bld_format.h7
-rw-r--r--src/gallium/auxiliary/gallivm/lp_bld_format_srgb.c51
-rw-r--r--src/gallium/drivers/llvmpipe/lp_screen.c7
-rw-r--r--src/gallium/drivers/llvmpipe/lp_state_fs.c64
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.