2 * Copyright (c) 2013 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
21 * DEALINGS IN THE SOFTWARE.
25 * \file lower_named_interface_blocks.cpp
27 * This lowering pass converts all interface blocks with instance names
28 * into interface blocks without an instance name.
30 * For example, the following shader:
38 * inst_name.block_var = 0.0;
52 * This takes place after the shader code has already been verified with
53 * the interface name in place.
55 * The linking phase will use the interface block name rather than the
56 * interface's instance name when linking interfaces.
58 * This modification to the ir allows our currently existing dead code
59 * elimination to work with interface blocks without changes.
62 #include "glsl_symbol_table.h"
64 #include "ir_optimization.h"
65 #include "ir_rvalue_visitor.h"
66 #include "util/hash_table.h"
67 #include "main/mtypes.h"
69 static const glsl_type
*
70 process_array_type(const glsl_type
*type
, unsigned idx
)
72 const glsl_type
*element_type
= type
->fields
.array
;
73 if (element_type
->is_array()) {
74 const glsl_type
*new_array_type
= process_array_type(element_type
, idx
);
75 return glsl_type::get_array_instance(new_array_type
, type
->length
);
77 return glsl_type::get_array_instance(
78 element_type
->fields
.structure
[idx
].type
, type
->length
);
83 process_array_ir(void * const mem_ctx
,
84 ir_dereference_array
*deref_array_prev
,
87 ir_dereference_array
*deref_array
=
88 deref_array_prev
->array
->as_dereference_array();
90 if (deref_array
== NULL
) {
91 return new(mem_ctx
) ir_dereference_array(deref_var
,
92 deref_array_prev
->array_index
);
94 deref_array
= (ir_dereference_array
*) process_array_ir(mem_ctx
,
97 return new(mem_ctx
) ir_dereference_array(deref_array
,
98 deref_array_prev
->array_index
);
104 class flatten_named_interface_blocks_declarations
: public ir_rvalue_visitor
107 void * const mem_ctx
;
108 hash_table
*interface_namespace
;
110 flatten_named_interface_blocks_declarations(void *mem_ctx
)
112 interface_namespace(NULL
)
116 void run(exec_list
*instructions
);
118 virtual ir_visitor_status
visit_leave(ir_assignment
*);
119 virtual ir_visitor_status
visit_leave(ir_expression
*);
120 virtual void handle_rvalue(ir_rvalue
**rvalue
);
123 } /* anonymous namespace */
126 flatten_named_interface_blocks_declarations::run(exec_list
*instructions
)
128 interface_namespace
= _mesa_hash_table_create(NULL
, _mesa_key_hash_string
,
129 _mesa_key_string_equal
);
131 /* First pass: adjust instance block variables with an instance name
132 * to not have an instance name.
134 * The interface block variables are stored in the interface_namespace
135 * hash table so they can be used in the second pass.
137 foreach_in_list_safe(ir_instruction
, node
, instructions
) {
138 ir_variable
*var
= node
->as_variable();
139 if (!var
|| !var
->is_interface_instance())
142 /* It should be possible to handle uniforms during this pass,
143 * but, this will require changes to the other uniform block
146 if (var
->data
.mode
== ir_var_uniform
||
147 var
->data
.mode
== ir_var_shader_storage
)
150 const glsl_type
* iface_t
= var
->type
->without_array();
151 exec_node
*insert_pos
= var
;
153 assert (iface_t
->is_interface());
155 for (unsigned i
= 0; i
< iface_t
->length
; i
++) {
156 const char * field_name
= iface_t
->fields
.structure
[i
].name
;
157 char *iface_field_name
=
158 ralloc_asprintf(mem_ctx
, "%s %s.%s.%s",
159 var
->data
.mode
== ir_var_shader_in
? "in" : "out",
160 iface_t
->name
, var
->name
, field_name
);
162 hash_entry
*entry
= _mesa_hash_table_search(interface_namespace
,
164 ir_variable
*found_var
= entry
? (ir_variable
*) entry
->data
: NULL
;
166 ir_variable
*new_var
;
168 ralloc_strdup(mem_ctx
, iface_t
->fields
.structure
[i
].name
);
169 if (!var
->type
->is_array()) {
171 new(mem_ctx
) ir_variable(iface_t
->fields
.structure
[i
].type
,
173 (ir_variable_mode
) var
->data
.mode
);
175 const glsl_type
*new_array_type
=
176 process_array_type(var
->type
, i
);
178 new(mem_ctx
) ir_variable(new_array_type
,
180 (ir_variable_mode
) var
->data
.mode
);
182 new_var
->data
.location
= iface_t
->fields
.structure
[i
].location
;
183 new_var
->data
.explicit_location
= (new_var
->data
.location
>= 0);
184 new_var
->data
.offset
= iface_t
->fields
.structure
[i
].offset
;
185 new_var
->data
.explicit_xfb_offset
=
186 (iface_t
->fields
.structure
[i
].offset
>= 0);
187 new_var
->data
.xfb_buffer
=
188 iface_t
->fields
.structure
[i
].xfb_buffer
;
189 new_var
->data
.explicit_xfb_buffer
=
190 iface_t
->fields
.structure
[i
].explicit_xfb_buffer
;
191 new_var
->data
.interpolation
=
192 iface_t
->fields
.structure
[i
].interpolation
;
193 new_var
->data
.centroid
= iface_t
->fields
.structure
[i
].centroid
;
194 new_var
->data
.sample
= iface_t
->fields
.structure
[i
].sample
;
195 new_var
->data
.patch
= iface_t
->fields
.structure
[i
].patch
;
196 new_var
->data
.stream
= var
->data
.stream
;
197 new_var
->data
.how_declared
= var
->data
.how_declared
;
198 new_var
->data
.from_named_ifc_block
= 1;
200 new_var
->init_interface_type(var
->type
);
201 _mesa_hash_table_insert(interface_namespace
, iface_field_name
,
203 insert_pos
->insert_after(new_var
);
204 insert_pos
= new_var
;
210 /* Second pass: visit all ir_dereference_record instances, and if they
211 * reference an interface block, then flatten the refererence out.
213 visit_list_elements(this, instructions
);
214 _mesa_hash_table_destroy(interface_namespace
, NULL
);
215 interface_namespace
= NULL
;
219 flatten_named_interface_blocks_declarations::visit_leave(ir_assignment
*ir
)
221 ir_dereference_record
*lhs_rec
= ir
->lhs
->as_dereference_record();
223 ir_variable
*lhs_var
= ir
->lhs
->variable_referenced();
224 if (lhs_var
&& lhs_var
->get_interface_type()) {
225 lhs_var
->data
.assigned
= 1;
229 ir_rvalue
*lhs_rec_tmp
= lhs_rec
;
230 handle_rvalue(&lhs_rec_tmp
);
231 if (lhs_rec_tmp
!= lhs_rec
) {
232 ir
->set_lhs(lhs_rec_tmp
);
235 ir_variable
*lhs_var
= lhs_rec_tmp
->variable_referenced();
237 lhs_var
->data
.assigned
= 1;
240 return rvalue_visit(ir
);
244 flatten_named_interface_blocks_declarations::visit_leave(ir_expression
*ir
)
246 ir_visitor_status status
= rvalue_visit(ir
);
248 if (ir
->operation
== ir_unop_interpolate_at_centroid
||
249 ir
->operation
== ir_binop_interpolate_at_offset
||
250 ir
->operation
== ir_binop_interpolate_at_sample
) {
251 const ir_rvalue
*val
= ir
->operands
[0];
253 /* This disables varying packing for this input. */
254 val
->variable_referenced()->data
.must_be_shader_input
= 1;
261 flatten_named_interface_blocks_declarations::handle_rvalue(ir_rvalue
**rvalue
)
266 ir_dereference_record
*ir
= (*rvalue
)->as_dereference_record();
270 ir_variable
*var
= ir
->variable_referenced();
274 if (!var
->is_interface_instance())
277 /* It should be possible to handle uniforms during this pass,
278 * but, this will require changes to the other uniform block
281 if (var
->data
.mode
== ir_var_uniform
|| var
->data
.mode
== ir_var_shader_storage
)
284 if (var
->get_interface_type() != NULL
) {
285 char *iface_field_name
=
286 ralloc_asprintf(mem_ctx
, "%s %s.%s.%s",
287 var
->data
.mode
== ir_var_shader_in
? "in" : "out",
288 var
->get_interface_type()->name
,
290 ir
->record
->type
->fields
.structure
[ir
->field_idx
].name
);
292 /* Find the variable in the set of flattened interface blocks */
293 hash_entry
*entry
= _mesa_hash_table_search(interface_namespace
,
296 ir_variable
*found_var
= (ir_variable
*) entry
->data
;
298 ir_dereference_variable
*deref_var
=
299 new(mem_ctx
) ir_dereference_variable(found_var
);
301 ir_dereference_array
*deref_array
=
302 ir
->record
->as_dereference_array();
303 if (deref_array
!= NULL
) {
304 *rvalue
= process_array_ir(mem_ctx
, deref_array
,
305 (ir_rvalue
*)deref_var
);
313 lower_named_interface_blocks(void *mem_ctx
, gl_linked_shader
*shader
)
315 flatten_named_interface_blocks_declarations
v_decl(mem_ctx
);
316 v_decl
.run(shader
->ir
);