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 "program/hash_table.h"
70 class flatten_named_interface_blocks_declarations
: public ir_rvalue_visitor
74 hash_table
*interface_namespace
;
76 flatten_named_interface_blocks_declarations(void *mem_ctx
)
78 interface_namespace(NULL
)
82 void run(exec_list
*instructions
);
84 virtual ir_visitor_status
visit_leave(ir_assignment
*);
85 virtual void handle_rvalue(ir_rvalue
**rvalue
);
88 } /* anonymous namespace */
91 flatten_named_interface_blocks_declarations::run(exec_list
*instructions
)
93 interface_namespace
= hash_table_ctor(0, hash_table_string_hash
,
94 hash_table_string_compare
);
96 /* First pass: adjust instance block variables with an instance name
97 * to not have an instance name.
99 * The interface block variables are stored in the interface_namespace
100 * hash table so they can be used in the second pass.
102 foreach_list_safe(node
, instructions
) {
103 ir_variable
*var
= ((ir_instruction
*) node
)->as_variable();
104 if (!var
|| !var
->is_interface_instance())
107 /* It should be possible to handle uniforms during this pass,
108 * but, this will require changes to the other uniform block
111 if (var
->mode
== ir_var_uniform
)
114 const glsl_type
* iface_t
= var
->type
;
115 const glsl_type
* array_t
= NULL
;
116 exec_node
*insert_pos
= var
;
118 if (iface_t
->is_array()) {
120 iface_t
= array_t
->fields
.array
;
123 assert (iface_t
->is_interface());
125 for (unsigned i
= 0; i
< iface_t
->length
; i
++) {
126 const char * field_name
= iface_t
->fields
.structure
[i
].name
;
127 char *iface_field_name
=
128 ralloc_asprintf(mem_ctx
, "%s.%s",
129 iface_t
->name
, field_name
);
131 ir_variable
*found_var
=
132 (ir_variable
*) hash_table_find(interface_namespace
,
135 ir_variable
*new_var
;
137 ralloc_strdup(mem_ctx
, iface_t
->fields
.structure
[i
].name
);
138 if (array_t
== NULL
) {
140 new(mem_ctx
) ir_variable(iface_t
->fields
.structure
[i
].type
,
142 (ir_variable_mode
) var
->mode
);
144 const glsl_type
*new_array_type
=
145 glsl_type::get_array_instance(
146 iface_t
->fields
.structure
[i
].type
,
149 new(mem_ctx
) ir_variable(new_array_type
,
151 (ir_variable_mode
) var
->mode
);
153 new_var
->location
= iface_t
->fields
.structure
[i
].location
;
154 new_var
->explicit_location
= (new_var
->location
>= 0);
156 new_var
->init_interface_type(iface_t
);
157 hash_table_insert(interface_namespace
, new_var
,
159 insert_pos
->insert_after(new_var
);
160 insert_pos
= new_var
;
166 /* Second pass: visit all ir_dereference_record instances, and if they
167 * reference an interface block, then flatten the refererence out.
169 visit_list_elements(this, instructions
);
170 hash_table_dtor(interface_namespace
);
171 interface_namespace
= NULL
;
175 flatten_named_interface_blocks_declarations::visit_leave(ir_assignment
*ir
)
177 ir_dereference_record
*lhs_rec
= ir
->lhs
->as_dereference_record();
179 ir_rvalue
*lhs_rec_tmp
= lhs_rec
;
180 handle_rvalue(&lhs_rec_tmp
);
181 if (lhs_rec_tmp
!= lhs_rec
) {
182 ir
->set_lhs(lhs_rec_tmp
);
185 return rvalue_visit(ir
);
189 flatten_named_interface_blocks_declarations::handle_rvalue(ir_rvalue
**rvalue
)
194 ir_dereference_record
*ir
= (*rvalue
)->as_dereference_record();
198 ir_variable
*var
= ir
->variable_referenced();
202 if (!var
->is_interface_instance())
205 /* It should be possible to handle uniforms during this pass,
206 * but, this will require changes to the other uniform block
209 if (var
->mode
== ir_var_uniform
)
212 if (var
->get_interface_type() != NULL
) {
213 char *iface_field_name
=
214 ralloc_asprintf(mem_ctx
, "%s.%s", var
->get_interface_type()->name
,
216 /* Find the variable in the set of flattened interface blocks */
217 ir_variable
*found_var
=
218 (ir_variable
*) hash_table_find(interface_namespace
,
222 ir_dereference_variable
*deref_var
=
223 new(mem_ctx
) ir_dereference_variable(found_var
);
225 ir_dereference_array
*deref_array
=
226 ir
->record
->as_dereference_array();
227 if (deref_array
!= NULL
) {
229 new(mem_ctx
) ir_dereference_array(deref_var
,
230 deref_array
->array_index
);
238 lower_named_interface_blocks(void *mem_ctx
, gl_shader
*shader
)
240 flatten_named_interface_blocks_declarations
v_decl(mem_ctx
);
241 v_decl
.run(shader
->ir
);