2 * Copyright © 2015 Intel Corporation
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
25 * Implements a pass that lowers output variables to a temporary plus an
26 * output variable with a single copy at each exit point of the shader.
27 * This way the output variable is only ever written.
29 * Because valid NIR requires that output variables are never read, this
30 * pass is more of a helper for NIR producers and must be run before the
31 * shader is ever validated.
36 struct lower_outputs_state
{
38 struct exec_list old_outputs
;
42 emit_output_copies(nir_cursor cursor
, struct lower_outputs_state
*state
)
44 assert(exec_list_length(&state
->shader
->outputs
) ==
45 exec_list_length(&state
->old_outputs
));
47 foreach_two_lists(out_node
, &state
->shader
->outputs
,
48 temp_node
, &state
->old_outputs
) {
49 nir_variable
*output
= exec_node_data(nir_variable
, out_node
, node
);
50 nir_variable
*temp
= exec_node_data(nir_variable
, temp_node
, node
);
52 nir_intrinsic_instr
*copy
=
53 nir_intrinsic_instr_create(state
->shader
, nir_intrinsic_copy_var
);
54 copy
->variables
[0] = nir_deref_var_create(copy
, output
);
55 copy
->variables
[1] = nir_deref_var_create(copy
, temp
);
57 nir_instr_insert(cursor
, ©
->instr
);
62 emit_output_copies_block(nir_block
*block
, void *state
)
64 nir_foreach_instr(block
, instr
) {
65 if (instr
->type
!= nir_instr_type_intrinsic
)
68 nir_intrinsic_instr
*intrin
= nir_instr_as_intrinsic(instr
);
69 if (intrin
->intrinsic
== nir_intrinsic_emit_vertex
)
70 emit_output_copies(nir_before_instr(&intrin
->instr
), state
);
77 nir_lower_outputs_to_temporaries(nir_shader
*shader
)
79 struct lower_outputs_state state
;
81 if (shader
->stage
== MESA_SHADER_TESS_CTRL
)
84 state
.shader
= shader
;
85 exec_list_move_nodes_to(&shader
->outputs
, &state
.old_outputs
);
87 /* Walk over all of the outputs turn each output into a temporary and
88 * make a new variable for the actual output.
90 nir_foreach_variable(var
, &state
.old_outputs
) {
91 nir_variable
*output
= ralloc(shader
, nir_variable
);
92 memcpy(output
, var
, sizeof *output
);
94 /* The orignal is now the temporary */
95 nir_variable
*temp
= var
;
97 /* Reparent the name to the new variable */
98 ralloc_steal(output
, output
->name
);
100 /* Give the output a new name with @out-temp appended */
101 temp
->name
= ralloc_asprintf(var
, "%s@out-temp", output
->name
);
102 temp
->data
.mode
= nir_var_global
;
103 temp
->constant_initializer
= NULL
;
105 exec_list_push_tail(&shader
->outputs
, &output
->node
);
108 nir_foreach_function(shader
, function
) {
109 if (function
->impl
== NULL
)
112 if (shader
->stage
== MESA_SHADER_GEOMETRY
) {
113 /* For geometry shaders, we have to emit the output copies right
114 * before each EmitVertex call.
116 nir_foreach_block(function
->impl
, emit_output_copies_block
, &state
);
117 } else if (strcmp(function
->name
, "main") == 0) {
118 /* For all other shader types, we need to do the copies right before
119 * the jumps to the end block.
121 struct set_entry
*block_entry
;
122 set_foreach(function
->impl
->end_block
->predecessors
, block_entry
) {
123 struct nir_block
*block
= (void *)block_entry
->key
;
124 emit_output_copies(nir_after_block_before_jump(block
), &state
);
128 nir_metadata_preserve(function
->impl
, nir_metadata_block_index
|
129 nir_metadata_dominance
);
132 exec_list_append(&shader
->globals
, &state
.old_outputs
);