nir/lower-tex: add srgb->linear lowering
authorRob Clark <robclark@freedesktop.org>
Tue, 19 Apr 2016 12:28:22 +0000 (08:28 -0400)
committerRob Clark <robclark@freedesktop.org>
Tue, 19 Apr 2016 21:13:50 +0000 (17:13 -0400)
Signed-off-by: Rob Clark <robclark@freedesktop.org>
Reviewed-by: Eric Anholt <eric@anholt.net>
Reviewed-by: Jason Ekstrand <jason@jlekstrand.net>
src/compiler/nir/nir.h
src/compiler/nir/nir_lower_tex.c

index bbbc2089db3f21960f49440fa014be07475afd53..3b82cfac1b52c23025caf609200441c47a44774a 100644 (file)
@@ -2301,6 +2301,13 @@ typedef struct nir_lower_tex_options {
     * while 4 and 5 represent 0 and 1 respectively.
     */
    uint8_t swizzles[32][4];
+
+   /**
+    * Bitmap of textures that need srgb to linear conversion.  If
+    * (lower_srgb & (1 << texture_index)) then the rgb (xyz) components
+    * of the texture are lowered to linear.
+    */
+   unsigned lower_srgb;
 } nir_lower_tex_options;
 
 bool nir_lower_tex(nir_shader *shader,
index 7740e588790af08795958e5c6b2ca196cbd3fdcc..4cc18228d1d6cd691717c660d18347bb559356e3 100644 (file)
@@ -275,6 +275,45 @@ swizzle_result(nir_builder *b, nir_tex_instr *tex, const uint8_t swizzle[4])
                                   swizzled->parent_instr);
 }
 
+static void
+linearize_srgb_result(nir_builder *b, nir_tex_instr *tex)
+{
+   assert(tex->dest.is_ssa);
+   assert(nir_tex_instr_dest_size(tex) == 4);
+   assert(nir_alu_type_get_base_type(tex->dest_type) == nir_type_float);
+
+   b->cursor = nir_after_instr(&tex->instr);
+
+   static const unsigned swiz[4] = {0, 1, 2, 0};
+   nir_ssa_def *comp = nir_swizzle(b, &tex->dest.ssa, swiz, 3, true);
+
+   /* Formula is:
+    *    (comp <= 0.04045) ?
+    *          (comp / 12.92) :
+    *          pow((comp + 0.055) / 1.055, 2.4)
+    */
+   nir_ssa_def *low  = nir_fmul(b, comp, nir_imm_float(b, 1.0 / 12.92));
+   nir_ssa_def *high = nir_fpow(b,
+                                nir_fmul(b,
+                                         nir_fadd(b,
+                                                  comp,
+                                                  nir_imm_float(b, 0.055)),
+                                         nir_imm_float(b, 1.0 / 1.055)),
+                                nir_imm_float(b, 2.4));
+   nir_ssa_def *cond = nir_fge(b, nir_imm_float(b, 0.04045), comp);
+   nir_ssa_def *rgb  = nir_bcsel(b, cond, low, high);
+
+   /* alpha is untouched: */
+   nir_ssa_def *result = nir_vec4(b,
+                                  nir_channel(b, rgb, 0),
+                                  nir_channel(b, rgb, 1),
+                                  nir_channel(b, rgb, 2),
+                                  nir_channel(b, &tex->dest.ssa, 3));
+
+   nir_ssa_def_rewrite_uses_after(&tex->dest.ssa, nir_src_for_ssa(result),
+                                  result->parent_instr);
+}
+
 static bool
 nir_lower_tex_block(nir_block *block, void *void_state)
 {
@@ -323,6 +362,13 @@ nir_lower_tex_block(nir_block *block, void *void_state)
          swizzle_result(b, tex, options->swizzles[tex->texture_index]);
          state->progress = true;
       }
+
+      /* should be after swizzle so we know which channels are rgb: */
+      if (((1 << tex->texture_index) & options->lower_srgb) &&
+          !nir_tex_instr_is_query(tex) && !tex->is_shadow) {
+         linearize_srgb_result(b, tex);
+         state->progress = true;
+      }
    }
 
    return true;