X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fcompiler%2Fnir%2Fnir_lower_io_to_temporaries.c;h=301ba658921837467edae5906fffba2af5dbc0a9;hb=fc1d1dbe81e16041ec0d84811d171f7d42975eea;hp=4b4363b8cdec8005d51610583e1d2055bbe2d90e;hpb=595f9d5476764ba29272549bac7ccd0000f459fe;p=mesa.git diff --git a/src/compiler/nir/nir_lower_io_to_temporaries.c b/src/compiler/nir/nir_lower_io_to_temporaries.c index 4b4363b8cde..301ba658921 100644 --- a/src/compiler/nir/nir_lower_io_to_temporaries.c +++ b/src/compiler/nir/nir_lower_io_to_temporaries.c @@ -22,17 +22,21 @@ */ /* - * Implements a pass that lowers output variables to a temporary plus an - * output variable with a single copy at each exit point of the shader. - * This way the output variable is only ever written. + * Implements a pass that lowers output and/or input variables to a + * temporary plus an output variable with a single copy at each exit + * point of the shader and/or an input variable with a single copy + * at the entrance point of the shader. This way the output variable + * is only ever written once and/or input is only read once, and there + * are no indirect outut/input accesses. */ #include "nir.h" struct lower_io_state { nir_shader *shader; - nir_function *entrypoint; + nir_function_impl *entrypoint; struct exec_list old_outputs; + struct exec_list old_inputs; }; static void @@ -45,6 +49,21 @@ emit_copies(nir_cursor cursor, nir_shader *shader, struct exec_list *new_vars, nir_variable *newv = exec_node_data(nir_variable, new_node, node); nir_variable *temp = exec_node_data(nir_variable, old_node, node); + /* No need to copy the contents of a non-fb_fetch_output output variable + * to the temporary allocated for it, since its initial value is + * undefined. + */ + if (temp->data.mode == nir_var_shader_out && + !temp->data.fb_fetch_output) + continue; + + /* Can't copy the contents of the temporary back to a read-only + * interface variable. The value of the temporary won't have been + * modified by the shader anyway. + */ + if (newv->data.read_only) + continue; + nir_intrinsic_instr *copy = nir_intrinsic_instr_create(shader, nir_intrinsic_copy_var); copy->variables[0] = nir_deref_var_create(copy, newv); @@ -57,7 +76,7 @@ emit_copies(nir_cursor cursor, nir_shader *shader, struct exec_list *new_vars, static void emit_output_copies_impl(struct lower_io_state *state, nir_function_impl *impl) { - if (state->shader->stage == MESA_SHADER_GEOMETRY) { + if (state->shader->info.stage == MESA_SHADER_GEOMETRY) { /* For geometry shaders, we have to emit the output copies right * before each EmitVertex call. */ @@ -74,7 +93,11 @@ emit_output_copies_impl(struct lower_io_state *state, nir_function_impl *impl) } } } - } else if (impl->function == state->entrypoint) { + } else if (impl == state->entrypoint) { + nir_cursor cursor = nir_before_block(nir_start_block(impl)); + emit_copies(cursor, state->shader, &state->old_outputs, + &state->shader->outputs); + /* For all other shader types, we need to do the copies right before * the jumps to the end block. */ @@ -88,6 +111,16 @@ emit_output_copies_impl(struct lower_io_state *state, nir_function_impl *impl) } } +static void +emit_input_copies_impl(struct lower_io_state *state, nir_function_impl *impl) +{ + if (impl == state->entrypoint) { + nir_cursor cursor = nir_before_block(nir_start_block(impl)); + emit_copies(cursor, state->shader, &state->old_inputs, + &state->shader->inputs); + } +} + static nir_variable * create_shadow_temp(struct lower_io_state *state, nir_variable *var) { @@ -100,29 +133,40 @@ create_shadow_temp(struct lower_io_state *state, nir_variable *var) /* Reparent the name to the new variable */ ralloc_steal(nvar, nvar->name); - /* Reparent the constant initializer (if any) */ - ralloc_steal(nvar, nvar->constant_initializer); + assert(nvar->constant_initializer == NULL); - /* Give the output a new name with @out-temp appended */ - const char *mode = "out"; + /* Give the original a new name with @-temp appended */ + const char *mode = (temp->data.mode == nir_var_shader_in) ? "in" : "out"; temp->name = ralloc_asprintf(var, "%s@%s-temp", mode, nvar->name); temp->data.mode = nir_var_global; - temp->constant_initializer = NULL; + temp->data.read_only = false; + temp->data.fb_fetch_output = false; + temp->data.compact = false; return nvar; } void -nir_lower_io_to_temporaries(nir_shader *shader, nir_function *entrypoint) +nir_lower_io_to_temporaries(nir_shader *shader, nir_function_impl *entrypoint, + bool outputs, bool inputs) { struct lower_io_state state; - if (shader->stage == MESA_SHADER_TESS_CTRL) + if (shader->info.stage == MESA_SHADER_TESS_CTRL) return; state.shader = shader; state.entrypoint = entrypoint; - exec_list_move_nodes_to(&shader->outputs, &state.old_outputs); + + if (inputs) + exec_list_move_nodes_to(&shader->inputs, &state.old_inputs); + else + exec_list_make_empty(&state.old_inputs); + + if (outputs) + exec_list_move_nodes_to(&shader->outputs, &state.old_outputs); + else + exec_list_make_empty(&state.old_outputs); /* Walk over all of the outputs turn each output into a temporary and * make a new variable for the actual output. @@ -132,15 +176,26 @@ nir_lower_io_to_temporaries(nir_shader *shader, nir_function *entrypoint) exec_list_push_tail(&shader->outputs, &output->node); } + /* and same for inputs: */ + nir_foreach_variable(var, &state.old_inputs) { + nir_variable *input = create_shadow_temp(&state, var); + exec_list_push_tail(&shader->inputs, &input->node); + } + nir_foreach_function(function, shader) { if (function->impl == NULL) continue; - emit_output_copies_impl(&state, function->impl); + if (inputs) + emit_input_copies_impl(&state, function->impl); + + if (outputs) + emit_output_copies_impl(&state, function->impl); nir_metadata_preserve(function->impl, nir_metadata_block_index | nir_metadata_dominance); } + exec_list_append(&shader->globals, &state.old_inputs); exec_list_append(&shader->globals, &state.old_outputs); }