[Mesa-dev] [PATCH] llvmpipe: support sRGB framebuffers

sroland at vmware.com sroland at vmware.com
Sat Jul 13 09:41:14 PDT 2013


From: Roland Scheidegger <sroland at vmware.com>

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.
---
 src/gallium/drivers/llvmpipe/lp_screen.c   |    7 ++-
 src/gallium/drivers/llvmpipe/lp_state_fs.c |   83 +++++++++++++++++++++++-----
 2 files changed, 76 insertions(+), 14 deletions(-)

diff --git a/src/gallium/drivers/llvmpipe/lp_screen.c b/src/gallium/drivers/llvmpipe/lp_screen.c
index 1fed537..26aac32 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 6afd57a..50405ef 100644
--- a/src/gallium/drivers/llvmpipe/lp_state_fs.c
+++ b/src/gallium/drivers/llvmpipe/lp_state_fs.c
@@ -764,7 +764,8 @@ 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_desc->format == PIPE_FORMAT_R11G11B10_FLOAT ||
+         format_desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) {
       /* just make this a 32bit uint */
       type->floating = false;
       type->fixed = false;
@@ -812,7 +813,8 @@ 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_desc->format == PIPE_FORMAT_R11G11B10_FLOAT ||
+       format_desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) {
       /* always use ordinary floats for blending */
       type->floating = true;
       type->fixed = false;
@@ -938,10 +940,13 @@ 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 (src_fmt->format == PIPE_FORMAT_R11G11B10_FLOAT ||
+       src_fmt->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) {
       LLVMValueRef tmpsrc[4];
       /*
        * This is pretty suboptimal for this case blending in SoA would be much
@@ -975,7 +980,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 +1099,13 @@ 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 (src_fmt->format == PIPE_FORMAT_R11G11B10_FLOAT ||
+       src_fmt->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) {
       /*
        * 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 +1119,45 @@ 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 {
+            unsigned chan;
+            struct lp_build_context f32_bld;
+            struct lp_type int32_type = lp_int_type(src_type);
+            LLVMValueRef tmpsrgb[4], alpha;
+
+            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, tmpsoa[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, tmpsoa[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);
+
+            tmpdst = lp_build_zero(gallivm, int32_type);
+            for (chan = 0; chan < src_fmt->nr_channels; chan++) {
+               if (src_fmt->swizzle[chan] <= UTIL_FORMAT_SWIZZLE_W) {
+                  unsigned ls;
+                  LLVMValueRef shifted, shift_val;
+                  ls = src_fmt->channel[src_fmt->swizzle[chan]].shift;
+                  shift_val = lp_build_const_int_vec(gallivm, int32_type, ls);
+                  shifted = LLVMBuildShl(builder, tmpsrgb[chan], shift_val, "");
+                  tmpdst = LLVMBuildOr(builder, tmpdst, shifted, "");
+               }
+            }
+         }
+
          if (src_type.length == 8) {
             LLVMValueRef tmpaos, shuffles[8];
             unsigned j;
@@ -1453,8 +1504,13 @@ generate_unswizzled_blend(struct gallivm_state *gallivm,
       }
    }
 
-   if (out_format == PIPE_FORMAT_R11G11B10_FLOAT) {
-      /* the code above can't work for layout_other */
+   if (out_format == PIPE_FORMAT_R11G11B10_FLOAT ||
+       out_format_desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) {
+      /*
+       * 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 +1772,8 @@ generate_unswizzled_blend(struct gallivm_state *gallivm,
 
    dst_type.length *= block_size / dst_count;
 
-   if (out_format == PIPE_FORMAT_R11G11B10_FLOAT) {
+   if (out_format == PIPE_FORMAT_R11G11B10_FLOAT ||
+       out_format_desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) {
       /*
        * we need multiple values at once for the conversion, so can as well
        * load them vectorized here too instead of concatenating later.
-- 
1.7.9.5


More information about the mesa-dev mailing list