llvmpipe: do additional checks in lp_state_fs_analysis.c for linear shaders
authorBrian Paul <brianp@vmware.com>
Tue, 14 Feb 2023 20:26:48 +0000 (13:26 -0700)
committerMarge Bot <emma+marge@anholt.net>
Sat, 18 Feb 2023 03:05:17 +0000 (03:05 +0000)
Check if the FS output color comes from an FS input.  If so, don't tag
the shader as linear.  See code comments for more details.

During testing I added extra counters to check the number of times
linear shaders were used to be sure we're not accidentally disallowing
too many shaders.  Things looked good with our in-house mksReplay test
suite.

This fixes some OpenGL CTS test failures with llvmpipe.

Signed-off-by: Brian Paul <brianp@vmware.com>
Closes: https://gitlab.freedesktop.org/mesa/mesa/-/issues/7489
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/21340>

src/gallium/drivers/llvmpipe/lp_state_fs_analysis.c

index ad24053..00a47f3 100644 (file)
@@ -175,6 +175,56 @@ finished:
 
 
 /*
+ * Check if the given nir_src comes directly from a FS input.
+ */
+static bool
+is_fs_input(const nir_src *src)
+{
+   if (!src->is_ssa) {
+      return false;
+   }
+
+   const nir_instr *parent = src->ssa[0].parent_instr;
+   if (!parent) {
+      return false;
+   }
+
+   if (parent->type == nir_instr_type_alu) {
+      const nir_alu_instr *alu = nir_instr_as_alu(parent);
+      if (alu->op == nir_op_vec2 ||
+          alu->op == nir_op_vec3 ||
+          alu->op == nir_op_vec4) {
+         /* Check if any of the components come from an FS input */
+         unsigned num_src = nir_op_infos[alu->op].num_inputs;
+         for (unsigned i = 0; i < num_src; i++) {
+            if (is_fs_input(&alu->src[i].src)) {
+               return true;
+            }
+         }
+      }
+   } else if (parent->type == nir_instr_type_intrinsic) {
+      const nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(parent);
+      /* loading from an FS input? */
+      if (intrin->intrinsic == nir_intrinsic_load_deref) {
+         if (is_fs_input(&intrin->src[0])) {
+            return true;
+         }
+      }
+   } else if (parent->type == nir_instr_type_deref) {
+      const nir_deref_instr *deref = nir_instr_as_deref(parent);
+      /* deref'ing an FS input? */
+      if (deref &&
+          deref->deref_type == nir_deref_type_var &&
+          deref->modes == nir_var_shader_in) {
+         return true;
+      }
+   }
+
+   return false;
+}
+
+
+/*
  * Determine whether the given alu src comes directly from an input
  * register.  If so, return true and the input register index and
  * component.  Return false otherwise.
@@ -305,6 +355,11 @@ check_load_const_in_zero_one(const nir_load_const_instr *load)
 
 /*
  * Examine the NIR shader to determine if it's "linear".
+ * For the linear path, we're optimizing the case of rendering a window-
+ * aligned, textured quad.  Basically, FS must get the output color from
+ * a texture lookup and, possibly, a constant color.  If the color comes
+ * from some other sort of computation or from a VS output (FS input), we
+ * can't use the linear path.
  */
 static bool
 llvmpipe_nir_fn_is_linear_compat(const struct nir_shader *shader,
@@ -337,6 +392,17 @@ llvmpipe_nir_fn_is_linear_compat(const struct nir_shader *shader,
                   nir_instr_as_load_const(intrin->src[0].ssa->parent_instr);
                if (load->value[0].u32 != 0)
                   return false;
+            } else if (intrin->intrinsic == nir_intrinsic_store_deref) {
+               /*
+                * Assume the store destination is the FS output color.
+                * Check if the store src comes directly from a FS input.
+                * If so, we cannot use the linear path since we don't have
+                * code to convert VS outputs / FS inputs to ubyte with the
+                * needed swizzling.
+                */
+               if (is_fs_input(&intrin->src[1])) {
+                  return false;
+               }
             }
             break;
          }
@@ -412,6 +478,9 @@ llvmpipe_nir_fn_is_linear_compat(const struct nir_shader *shader,
                      if (!check_load_const_in_zero_one(load)) {
                         return false;
                      }
+                  } else if (is_fs_input(&alu->src[s].src)) {
+                     /* we don't know if the fs inputs are in [0,1] */
+                     return false;
                   }
                }
                break;