diff options
Diffstat (limited to 'src/compiler/nir/nir_linking_helpers.c')
-rw-r--r-- | src/compiler/nir/nir_linking_helpers.c | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/src/compiler/nir/nir_linking_helpers.c b/src/compiler/nir/nir_linking_helpers.c index de6f2481def..b07bb40894e 100644 --- a/src/compiler/nir/nir_linking_helpers.c +++ b/src/compiler/nir/nir_linking_helpers.c @@ -22,6 +22,7 @@ */ #include "nir.h" +#include "nir_builder.h" #include "util/set.h" #include "util/hash_table.h" @@ -556,3 +557,112 @@ nir_link_xfb_varyings(nir_shader *producer, nir_shader *consumer) } } } + +static bool +try_replace_constant_input(nir_shader *shader, + nir_intrinsic_instr *store_intr) +{ + nir_variable *out_var = + nir_deref_instr_get_variable(nir_src_as_deref(store_intr->src[0])); + + if (out_var->data.mode != nir_var_shader_out) + return false; + + /* Skip types that require more complex handling. + * TODO: add support for these types. + */ + if (glsl_type_is_array(out_var->type) || + glsl_type_is_dual_slot(out_var->type) || + glsl_type_is_matrix(out_var->type) || + glsl_type_is_struct(out_var->type)) + return false; + + /* Limit this pass to scalars for now to keep things simple. Most varyings + * should have been lowered to scalars at this point anyway. + */ + if (store_intr->num_components != 1) + return false; + + if (out_var->data.location < VARYING_SLOT_VAR0 || + out_var->data.location - VARYING_SLOT_VAR0 >= MAX_VARYING) + return false; + + nir_function_impl *impl = nir_shader_get_entrypoint(shader); + + nir_builder b; + nir_builder_init(&b, impl); + + 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_variable *in_var = + nir_deref_instr_get_variable(nir_src_as_deref(intr->src[0])); + + if (in_var->data.mode != nir_var_shader_in) + continue; + + if (in_var->data.location != out_var->data.location || + in_var->data.location_frac != out_var->data.location_frac) + continue; + + b.cursor = nir_before_instr(instr); + + nir_load_const_instr *out_const = + nir_instr_as_load_const(store_intr->src[1].ssa->parent_instr); + + /* Add new const to replace the input */ + nir_ssa_def *nconst = nir_build_imm(&b, store_intr->num_components, + intr->dest.ssa.bit_size, + out_const->value); + + nir_ssa_def_rewrite_uses(&intr->dest.ssa, nir_src_for_ssa(nconst)); + + progress = true; + } + } + + return progress; +} + +bool +nir_link_constant_varyings(nir_shader *producer, nir_shader *consumer) +{ + /* TODO: Add support for more shader stage combinations */ + if (consumer->info.stage != MESA_SHADER_FRAGMENT || + (producer->info.stage != MESA_SHADER_VERTEX && + producer->info.stage != MESA_SHADER_TESS_EVAL)) + return false; + + bool progress = false; + + nir_function_impl *impl = nir_shader_get_entrypoint(producer); + + /* If we find a store in the last block of the producer we can be sure this + * is the only possible value for this output. + */ + nir_block *last_block = nir_impl_last_block(impl); + nir_foreach_instr_reverse(instr, last_block) { + if (instr->type != nir_instr_type_intrinsic) + continue; + + nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr); + + if (intr->intrinsic != nir_intrinsic_store_deref) + continue; + + if (intr->src[1].ssa->parent_instr->type != nir_instr_type_load_const) { + continue; + } + + progress |= try_replace_constant_input(consumer, intr); + } + + return progress; +} |