summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/gallium/auxiliary/gallivm/lp_bld_format.h1
-rw-r--r--src/gallium/auxiliary/gallivm/lp_bld_format_soa.c3
-rw-r--r--src/gallium/auxiliary/gallivm/lp_bld_format_srgb.c26
-rw-r--r--src/gallium/drivers/llvmpipe/lp_screen.c1
-rw-r--r--src/gallium/drivers/llvmpipe/lp_state_fs.c39
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 a7a4ba0a48c..1177fb224dd 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 81cd2b0f7c6..ff2887ee8fa 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 6645151f514..e4849fe043f 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 c8e95fe329e..fe06e34f675 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 2f9f907edd6..5e28f0ec4ea 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;
}