2 * Copyright © 2016 Red Hat
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 FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 #include "nir_builder.h"
27 /* Lower complex (struct/array/mat) input and output vars to primitive types
28 * (vec4) for linking. All indirect input/output access should already be
29 * lowered (ie. nir_lower_io_to_temporaries).
32 struct lower_io_types_state
{
34 struct exec_list new_ins
;
35 struct exec_list new_outs
;
39 get_new_var(struct lower_io_types_state
*state
, nir_variable
*var
,
40 const struct glsl_type
*deref_type
, unsigned off
)
42 struct exec_list
*list
;
44 if (var
->data
.mode
== nir_var_shader_in
) {
45 list
= &state
->new_ins
;
47 assert(var
->data
.mode
== nir_var_shader_out
);
48 list
= &state
->new_outs
;
51 nir_foreach_variable(nvar
, list
) {
52 if (nvar
->data
.location
== (var
->data
.location
+ off
))
56 /* doesn't already exist, so we need to create a new one: */
57 /* TODO figure out if scalar vs vec, and if float/int/uint/(double?)
58 * do we need to fixup interpolation mode for int vs float components
61 const struct glsl_type
*ntype
=
62 glsl_vector_type(glsl_get_base_type(deref_type
),
63 glsl_get_vector_elements(deref_type
));
64 nir_variable
*nvar
= nir_variable_create(state
->shader
, var
->data
.mode
,
67 nvar
->name
= ralloc_asprintf(nvar
, "%s@%u", var
->name
, off
);
68 nvar
->data
= var
->data
;
69 nvar
->data
.location
+= off
;
71 /* nir_variable_create is too clever for its own good: */
72 exec_node_remove(&nvar
->node
);
73 exec_node_self_link(&nvar
->node
); /* no delinit() :-( */
75 exec_list_push_tail(list
, &nvar
->node
);
77 /* remove existing var from input/output list: */
78 exec_node_remove(&var
->node
);
79 exec_node_self_link(&var
->node
);
85 get_deref_offset(struct lower_io_types_state
*state
, nir_deref
*tail
, bool vs_in
)
89 while (tail
->child
!= NULL
) {
90 const struct glsl_type
*parent_type
= tail
->type
;
93 if (tail
->deref_type
== nir_deref_type_array
) {
94 nir_deref_array
*deref_array
= nir_deref_as_array(tail
);
96 /* indirect inputs/outputs should already be lowered! */
97 assert(deref_array
->deref_array_type
== nir_deref_array_type_direct
);
99 unsigned size
= glsl_count_attribute_slots(tail
->type
, vs_in
);
101 offset
+= size
* deref_array
->base_offset
;
102 } else if (tail
->deref_type
== nir_deref_type_struct
) {
103 nir_deref_struct
*deref_struct
= nir_deref_as_struct(tail
);
105 for (unsigned i
= 0; i
< deref_struct
->index
; i
++) {
106 const struct glsl_type
*ft
= glsl_get_struct_field(parent_type
, i
);
107 offset
+= glsl_count_attribute_slots(ft
, vs_in
);
116 lower_io_types_block(struct lower_io_types_state
*state
, nir_block
*block
)
118 nir_foreach_instr(instr
, block
) {
119 if (instr
->type
!= nir_instr_type_intrinsic
)
122 nir_intrinsic_instr
*intr
= nir_instr_as_intrinsic(instr
);
124 if ((intr
->intrinsic
!= nir_intrinsic_load_var
) &&
125 (intr
->intrinsic
!= nir_intrinsic_store_var
))
128 nir_variable
*var
= intr
->variables
[0]->var
;
130 if ((var
->data
.mode
!= nir_var_shader_in
) &&
131 (var
->data
.mode
!= nir_var_shader_out
))
134 bool vs_in
= (state
->shader
->stage
== MESA_SHADER_VERTEX
) &&
135 (var
->data
.mode
== nir_var_shader_in
);
136 if (glsl_count_attribute_slots(var
->type
, vs_in
) == 1)
139 unsigned off
= get_deref_offset(state
, &intr
->variables
[0]->deref
, vs_in
);
140 const struct glsl_type
*deref_type
=
141 nir_deref_tail(&intr
->variables
[0]->deref
)->type
;
142 nir_variable
*nvar
= get_new_var(state
, var
, deref_type
, off
);
144 /* and then re-write the load/store_var deref: */
145 intr
->variables
[0] = nir_deref_var_create(intr
, nvar
);
152 lower_io_types_impl(nir_function_impl
*impl
, struct lower_io_types_state
*state
)
154 nir_foreach_block(block
, impl
) {
155 lower_io_types_block(state
, block
);
158 nir_metadata_preserve(impl
, nir_metadata_block_index
|
159 nir_metadata_dominance
);
164 nir_lower_io_types(nir_shader
*shader
)
166 struct lower_io_types_state state
;
168 state
.shader
= shader
;
169 exec_list_make_empty(&state
.new_ins
);
170 exec_list_make_empty(&state
.new_outs
);
172 nir_foreach_function(function
, shader
) {
174 lower_io_types_impl(function
->impl
, &state
);
177 /* move new in/out vars to shader's lists: */
178 exec_list_append(&shader
->inputs
, &state
.new_ins
);
179 exec_list_append(&shader
->outputs
, &state
.new_outs
);