Mesa (main): nir/linker: support uniform when optimizing varying
GitLab Mirror
gitlab-mirror at kemper.freedesktop.org
Wed Oct 13 05:12:05 UTC 2021
Module: Mesa
Branch: main
Commit: 260462504372a0b398af8b41bd790a1a557abec9
URL: http://cgit.freedesktop.org/mesa/mesa/commit/?id=260462504372a0b398af8b41bd790a1a557abec9
Author: Qiang Yu <yuq825 at gmail.com>
Date: Mon Aug 30 15:51:50 2021 +0800
nir/linker: support uniform when optimizing varying
Varying assigned from uniform won't change after interpolation,
so move uniform load to fragment shader to eliminate the varying.
Acked-by: Pierre-Eric Pelloux-Prayer <pierre-eric.pelloux-prayer at amd.com>
Acked-by: Marek Olšák <marek.olsak at amd.com>
Signed-off-by: Qiang Yu <yuq825 at gmail.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/12613>
---
src/compiler/nir/nir_linking_helpers.c | 162 ++++++++++++++++++++++++++++++++-
1 file changed, 158 insertions(+), 4 deletions(-)
diff --git a/src/compiler/nir/nir_linking_helpers.c b/src/compiler/nir/nir_linking_helpers.c
index 129ac48312c..b32fee2ced3 100644
--- a/src/compiler/nir/nir_linking_helpers.c
+++ b/src/compiler/nir/nir_linking_helpers.c
@@ -1100,6 +1100,156 @@ replace_duplicate_input(nir_shader *shader, nir_variable *input_var,
return progress;
}
+static bool
+is_direct_uniform_load(nir_ssa_def *def, nir_ssa_scalar *s)
+{
+ /* def is sure to be scalar as can_replace_varying() filter out vector case. */
+ assert(def->num_components == 1);
+
+ /* Uniform load may hide behind some move instruction for converting
+ * vector to scalar:
+ *
+ * vec1 32 ssa_1 = deref_var &color (uniform vec3)
+ * vec3 32 ssa_2 = intrinsic load_deref (ssa_1) (0)
+ * vec1 32 ssa_3 = mov ssa_2.x
+ * vec1 32 ssa_4 = deref_var &color_out (shader_out float)
+ * intrinsic store_deref (ssa_4, ssa_3) (1, 0)
+ */
+ *s = nir_ssa_scalar_resolved(def, 0);
+
+ nir_ssa_def *ssa = s->def;
+ if (ssa->parent_instr->type != nir_instr_type_intrinsic)
+ return false;
+
+ nir_intrinsic_instr *intr = nir_instr_as_intrinsic(ssa->parent_instr);
+ if (intr->intrinsic != nir_intrinsic_load_deref)
+ return false;
+
+ nir_deref_instr *deref = nir_src_as_deref(intr->src[0]);
+ /* TODO: support nir_var_mem_ubo. */
+ if (!nir_deref_mode_is(deref, nir_var_uniform))
+ return false;
+
+ /* Does not support indirect uniform load. */
+ return !nir_deref_instr_has_indirect(deref);
+}
+
+static nir_variable *
+get_uniform_var_in_consumer(nir_shader *consumer,
+ nir_variable *var_in_producer)
+{
+ /* Find if uniform already exists in consumer. */
+ nir_variable *new_var = NULL;
+ nir_foreach_uniform_variable(v, consumer) {
+ if (!strcmp(var_in_producer->name, v->name)) {
+ new_var = v;
+ break;
+ }
+ }
+
+ /* Create a variable if not exist. */
+ if (!new_var) {
+ new_var = nir_variable_clone(var_in_producer, consumer);
+ nir_shader_add_variable(consumer, new_var);
+ }
+
+ return new_var;
+}
+
+static nir_deref_instr *
+clone_deref_instr(nir_builder *b, nir_variable *var, nir_deref_instr *deref)
+{
+ if (deref->deref_type == nir_deref_type_var)
+ return nir_build_deref_var(b, var);
+
+ nir_deref_instr *parent_deref = nir_deref_instr_parent(deref);
+ nir_deref_instr *parent = clone_deref_instr(b, var, parent_deref);
+
+ /* Build array and struct deref instruction.
+ * "deref" instr is sure to be direct (see is_direct_uniform_load()).
+ */
+ switch (deref->deref_type) {
+ case nir_deref_type_array: {
+ nir_load_const_instr *index =
+ nir_instr_as_load_const(deref->arr.index.ssa->parent_instr);
+ return nir_build_deref_array_imm(b, parent, index->value->i64);
+ }
+ case nir_deref_type_ptr_as_array: {
+ nir_load_const_instr *index =
+ nir_instr_as_load_const(deref->arr.index.ssa->parent_instr);
+ nir_ssa_def *ssa = nir_imm_intN_t(b, index->value->i64,
+ parent->dest.ssa.bit_size);
+ return nir_build_deref_ptr_as_array(b, parent, ssa);
+ }
+ case nir_deref_type_struct:
+ return nir_build_deref_struct(b, parent, deref->strct.index);
+ default:
+ unreachable("invalid type");
+ return NULL;
+ }
+}
+
+static bool
+replace_varying_input_by_uniform_load(nir_shader *shader,
+ nir_intrinsic_instr *store_intr,
+ nir_ssa_scalar *scalar)
+{
+ nir_function_impl *impl = nir_shader_get_entrypoint(shader);
+
+ nir_builder b;
+ nir_builder_init(&b, impl);
+
+ nir_variable *out_var =
+ nir_deref_instr_get_variable(nir_src_as_deref(store_intr->src[0]));
+
+ nir_intrinsic_instr *load = nir_instr_as_intrinsic(scalar->def->parent_instr);
+ nir_deref_instr *deref = nir_src_as_deref(load->src[0]);
+ nir_variable *uni_var = nir_deref_instr_get_variable(deref);
+ uni_var = get_uniform_var_in_consumer(shader, uni_var);
+
+ bool progress = false;
+ nir_foreach_block(block, impl) {
+ nir_foreach_instr(instr, block) {
+ if (instr->type != nir_instr_type_intrinsic)
+ continue;
+
+ nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr);
+ if (intr->intrinsic != nir_intrinsic_load_deref)
+ continue;
+
+ nir_deref_instr *in_deref = nir_src_as_deref(intr->src[0]);
+ if (!nir_deref_mode_is(in_deref, nir_var_shader_in))
+ continue;
+
+ nir_variable *in_var = nir_deref_instr_get_variable(in_deref);
+
+ if (!does_varying_match(out_var, in_var))
+ continue;
+
+ b.cursor = nir_before_instr(instr);
+
+ /* Clone instructions start from deref load to variable deref. */
+ nir_deref_instr *uni_deref = clone_deref_instr(&b, uni_var, deref);
+ nir_ssa_def *uni_def = nir_load_deref(&b, uni_deref);
+
+ /* Add a vector to scalar move if uniform is a vector. */
+ if (uni_def->num_components > 1) {
+ nir_alu_src src = {0};
+ src.src = nir_src_for_ssa(uni_def);
+ src.swizzle[0] = scalar->comp;
+ uni_def = nir_mov_alu(&b, src, 1);
+ }
+
+ /* Replace load input with load uniform. */
+ nir_ssa_def_rewrite_uses(&intr->dest.ssa, uni_def);
+
+ progress = true;
+ }
+ }
+
+ return progress;
+}
+
/* The GLSL ES 3.20 spec says:
*
* "The precision of a vertex output does not need to match the precision of
@@ -1201,11 +1351,16 @@ nir_link_opt_varyings(nir_shader *producer, nir_shader *consumer)
if (!can_replace_varying(out_var))
continue;
- if (intr->src[1].ssa->parent_instr->type == nir_instr_type_load_const) {
+ nir_ssa_scalar uni_scalar;
+ nir_ssa_def *ssa = intr->src[1].ssa;
+ if (ssa->parent_instr->type == nir_instr_type_load_const) {
progress |= replace_constant_input(consumer, intr);
+ } else if (is_direct_uniform_load(ssa, &uni_scalar)) {
+ progress |= replace_varying_input_by_uniform_load(consumer, intr,
+ &uni_scalar);
} else {
struct hash_entry *entry =
- _mesa_hash_table_search(varying_values, intr->src[1].ssa);
+ _mesa_hash_table_search(varying_values, ssa);
if (entry) {
progress |= replace_duplicate_input(consumer,
(nir_variable *) entry->data,
@@ -1213,8 +1368,7 @@ nir_link_opt_varyings(nir_shader *producer, nir_shader *consumer)
} else {
nir_variable *in_var = get_matching_input_var(consumer, out_var);
if (in_var) {
- _mesa_hash_table_insert(varying_values, intr->src[1].ssa,
- in_var);
+ _mesa_hash_table_insert(varying_values, ssa, in_var);
}
}
}
More information about the mesa-commit
mailing list