|
|
|
@@ -0,0 +1,199 @@ |
|
|
|
/* |
|
|
|
* Copyright (c) 2013 Intel Corporation |
|
|
|
* |
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a |
|
|
|
* copy of this software and associated documentation files (the "Software"), |
|
|
|
* to deal in the Software without restriction, including without limitation |
|
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
|
|
|
* and/or sell copies of the Software, and to permit persons to whom the |
|
|
|
* Software is furnished to do so, subject to the following conditions: |
|
|
|
* |
|
|
|
* The above copyright notice and this permission notice (including the next |
|
|
|
* paragraph) shall be included in all copies or substantial portions of the |
|
|
|
* Software. |
|
|
|
* |
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
|
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
|
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
|
|
|
* DEALINGS IN THE SOFTWARE. |
|
|
|
*/ |
|
|
|
|
|
|
|
/** |
|
|
|
* \file lower_named_interface_blocks.cpp |
|
|
|
* |
|
|
|
* This lowering pass converts all interface blocks with instance names |
|
|
|
* into interface blocks without an instance name. |
|
|
|
* |
|
|
|
* For example, the following shader: |
|
|
|
* |
|
|
|
* out block { |
|
|
|
* float block_var; |
|
|
|
* } inst_name; |
|
|
|
* |
|
|
|
* main() |
|
|
|
* { |
|
|
|
* inst_name.block_var = 0.0; |
|
|
|
* } |
|
|
|
* |
|
|
|
* Is rewritten to: |
|
|
|
* |
|
|
|
* out block { |
|
|
|
* float block_var; |
|
|
|
* }; |
|
|
|
* |
|
|
|
* main() |
|
|
|
* { |
|
|
|
* block_var = 0.0; |
|
|
|
* } |
|
|
|
* |
|
|
|
* This takes place after the shader code has already been verified with |
|
|
|
* the interface name in place. |
|
|
|
* |
|
|
|
* The linking phase will use the interface block name rather than the |
|
|
|
* interface's instance name when linking interfaces. |
|
|
|
* |
|
|
|
* This modification to the ir allows our currently existing dead code |
|
|
|
* elimination to work with interface blocks without changes. |
|
|
|
*/ |
|
|
|
|
|
|
|
#include "glsl_symbol_table.h" |
|
|
|
#include "ir.h" |
|
|
|
#include "ir_optimization.h" |
|
|
|
#include "ir_rvalue_visitor.h" |
|
|
|
#include "program/hash_table.h" |
|
|
|
|
|
|
|
class flatten_named_interface_blocks_declarations : public ir_rvalue_visitor |
|
|
|
{ |
|
|
|
public: |
|
|
|
void * const mem_ctx; |
|
|
|
hash_table *interface_namespace; |
|
|
|
|
|
|
|
flatten_named_interface_blocks_declarations(void *mem_ctx) |
|
|
|
: mem_ctx(mem_ctx) |
|
|
|
{ |
|
|
|
} |
|
|
|
|
|
|
|
void run(exec_list *instructions); |
|
|
|
|
|
|
|
virtual ir_visitor_status visit_leave(ir_assignment *); |
|
|
|
virtual void handle_rvalue(ir_rvalue **rvalue); |
|
|
|
}; |
|
|
|
|
|
|
|
void |
|
|
|
flatten_named_interface_blocks_declarations::run(exec_list *instructions) |
|
|
|
{ |
|
|
|
interface_namespace = hash_table_ctor(0, hash_table_string_hash, |
|
|
|
hash_table_string_compare); |
|
|
|
|
|
|
|
/* First pass: adjust instance block variables with an instance name |
|
|
|
* to not have an instance name. |
|
|
|
* |
|
|
|
* The interface block variables are stored in the interface_namespace |
|
|
|
* hash table so they can be used in the second pass. |
|
|
|
*/ |
|
|
|
foreach_list_safe(node, instructions) { |
|
|
|
ir_variable *var = ((ir_instruction *) node)->as_variable(); |
|
|
|
if (!var || !var->is_interface_instance()) |
|
|
|
continue; |
|
|
|
|
|
|
|
/* It should be possible to handle uniforms during this pass, |
|
|
|
* but, this will require changes to the other uniform block |
|
|
|
* support code. |
|
|
|
*/ |
|
|
|
if (var->mode == ir_var_uniform) |
|
|
|
continue; |
|
|
|
|
|
|
|
const glsl_type *const t = var->type; |
|
|
|
exec_node *insert_pos = var; |
|
|
|
char *iface_field_name; |
|
|
|
for (unsigned i = 0; i < t->length; i++) { |
|
|
|
iface_field_name = ralloc_asprintf(mem_ctx, "%s.%s", t->name, |
|
|
|
t->fields.structure[i].name); |
|
|
|
|
|
|
|
ir_variable *found_var = |
|
|
|
(ir_variable *) hash_table_find(interface_namespace, |
|
|
|
iface_field_name); |
|
|
|
if (!found_var) { |
|
|
|
ir_variable *new_var = |
|
|
|
new(mem_ctx) ir_variable(t->fields.structure[i].type, |
|
|
|
ralloc_strdup(mem_ctx, t->fields.structure[i].name), |
|
|
|
(ir_variable_mode) var->mode); |
|
|
|
new_var->interface_type = t; |
|
|
|
hash_table_insert(interface_namespace, new_var, |
|
|
|
iface_field_name); |
|
|
|
insert_pos->insert_after(new_var); |
|
|
|
insert_pos = new_var; |
|
|
|
} |
|
|
|
} |
|
|
|
var->remove(); |
|
|
|
} |
|
|
|
|
|
|
|
/* Second pass: visit all ir_dereference_record instances, and if they |
|
|
|
* reference an interface block, then flatten the refererence out. |
|
|
|
*/ |
|
|
|
visit_list_elements(this, instructions); |
|
|
|
hash_table_dtor(interface_namespace); |
|
|
|
interface_namespace = NULL; |
|
|
|
} |
|
|
|
|
|
|
|
ir_visitor_status |
|
|
|
flatten_named_interface_blocks_declarations::visit_leave(ir_assignment *ir) |
|
|
|
{ |
|
|
|
ir_dereference_record *lhs_rec = ir->lhs->as_dereference_record(); |
|
|
|
if (lhs_rec) { |
|
|
|
ir_rvalue *lhs_rec_tmp = lhs_rec; |
|
|
|
handle_rvalue(&lhs_rec_tmp); |
|
|
|
if (lhs_rec_tmp != lhs_rec) { |
|
|
|
ir->set_lhs(lhs_rec_tmp); |
|
|
|
} |
|
|
|
} |
|
|
|
return rvalue_visit(ir); |
|
|
|
} |
|
|
|
|
|
|
|
void |
|
|
|
flatten_named_interface_blocks_declarations::handle_rvalue(ir_rvalue **rvalue) |
|
|
|
{ |
|
|
|
if (*rvalue == NULL) |
|
|
|
return; |
|
|
|
|
|
|
|
ir_dereference_record *ir = (*rvalue)->as_dereference_record(); |
|
|
|
if (ir == NULL) |
|
|
|
return; |
|
|
|
|
|
|
|
ir_variable *var = ir->variable_referenced(); |
|
|
|
|
|
|
|
if (!var->is_interface_instance()) |
|
|
|
return; |
|
|
|
|
|
|
|
/* It should be possible to handle uniforms during this pass, |
|
|
|
* but, this will require changes to the other uniform block |
|
|
|
* support code. |
|
|
|
*/ |
|
|
|
if (var->mode == ir_var_uniform) |
|
|
|
return; |
|
|
|
|
|
|
|
if (var->interface_type != NULL) { |
|
|
|
char *iface_field_name = |
|
|
|
ralloc_asprintf(mem_ctx, "%s.%s", var->interface_type->name, |
|
|
|
ir->field); |
|
|
|
/* Find the variable in the set of flattened interface blocks */ |
|
|
|
ir_variable *found_var = |
|
|
|
(ir_variable *) hash_table_find(interface_namespace, |
|
|
|
iface_field_name); |
|
|
|
assert(found_var); |
|
|
|
ir_dereference_variable *deref_var = |
|
|
|
new(mem_ctx) ir_dereference_variable(found_var); |
|
|
|
*rvalue = deref_var; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void |
|
|
|
lower_named_interface_blocks(void *mem_ctx, gl_shader *shader) |
|
|
|
{ |
|
|
|
flatten_named_interface_blocks_declarations v_decl(mem_ctx); |
|
|
|
v_decl.run(shader->ir); |
|
|
|
} |
|
|
|
|