summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoland Scheidegger <sroland@vmware.com>2013-07-16 01:52:29 +0200
committerRoland Scheidegger <sroland@vmware.com>2013-07-16 01:54:51 +0200
commitdc1cc928edc09b3e804702d299f1c71aef014354 (patch)
tree7cf01823f5b41e56729f7ffad4dd6c055f57a8b5
parenta882067d74840ab87e35018bca53081f8deb460b (diff)
llvmpipe: support sRGB framebuffers
Just use the new conversion functions to do the work. The way it's plugged in into the blend code is quite hacktastic but follows all the same hacks as used by packed float format already. Only support 4x8bit srgb formats (rgba/rgbx plus swizzle), 24bit formats never worked anyway in the blend code and are thus disabled, and I don't think anyone is interested in L8/L8A8. Would need even more hacks otherwise. Unless I'm missing something, this is the last feature except MSAA needed for OpenGL 3.0, and for OpenGL 3.1 as well I believe. v2: prettify a bit, use separate function for packing. Reviewed-by: Jose Fonseca <jfonseca@vmware.com>
-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
@@ -161,5 +161,6 @@ lp_build_rgb9e5_to_float(struct gallivm_state *gallivm,
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);
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
@@ -149,3 +149,3 @@ lp_build_srgb_to_linear(struct gallivm_state *gallivm,
*/
-LLVMValueRef
+static LLVMValueRef
lp_build_linear_to_srgb(struct gallivm_state *gallivm,
@@ -295 +295,50 @@ 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).
+ *
+ * @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
@@ -330,3 +330,7 @@ llvmpipe_is_format_supported( struct pipe_screen *_screen,
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;
@@ -336,2 +340,3 @@ llvmpipe_is_format_supported( struct pipe_screen *_screen,
return FALSE;
+
assert(format_desc->block.width == 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
@@ -755,2 +755,18 @@ 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
@@ -766,3 +782,3 @@ lp_mem_type_from_format_desc(const struct util_format_description *format_desc,
- if (format_desc->format == PIPE_FORMAT_R11G11B10_FLOAT) {
+ if (format_expands_to_float_soa(format_desc)) {
/* just make this a 32bit uint */
@@ -814,3 +830,3 @@ lp_blend_type_from_format_desc(const struct util_format_description *format_desc
- if (format_desc->format == PIPE_FORMAT_R11G11B10_FLOAT) {
+ if (format_expands_to_float_soa(format_desc)) {
/* always use ordinary floats for blending */
@@ -940,6 +956,8 @@ convert_to_blend_type(struct gallivm_state *gallivm,
/*
- * 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];
@@ -977,3 +995,8 @@ convert_to_blend_type(struct gallivm_state *gallivm,
}
- 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]);
@@ -1091,6 +1114,8 @@ convert_from_blend_type(struct gallivm_state *gallivm,
/*
- * 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)) {
/*
@@ -1108,3 +1133,12 @@ convert_from_blend_type(struct gallivm_state *gallivm,
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) {
@@ -1455,4 +1489,8 @@ 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 */
@@ -1718,3 +1756,3 @@ generate_unswizzled_blend(struct gallivm_state *gallivm,
- if (out_format == PIPE_FORMAT_R11G11B10_FLOAT) {
+ if (format_expands_to_float_soa(out_format_desc)) {
/*