diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/glsl/ir_function_inlining.cpp | 143 |
1 files changed, 138 insertions, 5 deletions
diff --git a/src/glsl/ir_function_inlining.cpp b/src/glsl/ir_function_inlining.cpp index 973813774e2..35eb2b38ea9 100644 --- a/src/glsl/ir_function_inlining.cpp +++ b/src/glsl/ir_function_inlining.cpp @@ -35,6 +35,11 @@ #include "glsl_types.h" #include "program/hash_table.h" +static void +do_sampler_replacement(exec_list *instructions, + ir_variable *sampler, + ir_dereference *deref); + class ir_function_inlining_visitor : public ir_hierarchical_visitor { public: ir_function_inlining_visitor() @@ -96,7 +101,7 @@ replace_return_with_assignment(ir_instruction *ir, void *data) /* un-valued return has to be the last return, or we shouldn't * have reached here. (see can_inline()). */ - assert(!ret->next->is_tail_sentinel()); + assert(ret->next->is_tail_sentinel()); ret->remove(); } } @@ -142,10 +147,9 @@ ir_call::generate_inline(ir_instruction *next_ir) /* For samplers, we want the inlined sampler references * referencing the passed in sampler variable, since that * will have the location information, which an assignment of - * a sampler wouldn't. + * a sampler wouldn't. Fix it up below. */ parameters[i] = NULL; - hash_table_insert(ht, param->variable_referenced(), sig_param); } else { parameters[i] = sig_param->clone(ctx, ht); parameters[i]->mode = ir_var_auto; @@ -166,15 +170,40 @@ ir_call::generate_inline(ir_instruction *next_ir) param_iter.next(); } - /* Generate the inlined body of the function. */ + exec_list new_instructions; + + /* Generate the inlined body of the function to a new list */ foreach_iter(exec_list_iterator, iter, callee->body) { ir_instruction *ir = (ir_instruction *)iter.get(); ir_instruction *new_ir = ir->clone(ctx, ht); - next_ir->insert_before(new_ir); + new_instructions.push_tail(new_ir); visit_tree(new_ir, replace_return_with_assignment, retval); } + /* If any samplers were passed in, replace any deref of the sampler + * with a deref of the sampler argument. + */ + param_iter = this->actual_parameters.iterator(); + sig_param_iter = this->callee->parameters.iterator(); + for (i = 0; i < num_parameters; i++) { + ir_instruction *const param = (ir_instruction *) param_iter.get(); + ir_variable *sig_param = (ir_variable *) sig_param_iter.get(); + + if (sig_param->type->base_type == GLSL_TYPE_SAMPLER) { + ir_dereference *deref = param->as_dereference(); + + assert(deref); + do_sampler_replacement(&new_instructions, sig_param, deref); + } + } + + /* Now push those new instructions in. */ + foreach_iter(exec_list_iterator, iter, new_instructions) { + ir_instruction *ir = (ir_instruction *)iter.get(); + next_ir->insert_before(ir); + } + /* Copy back the value of any 'out' parameters from the function body * variables to our own. */ @@ -280,3 +309,107 @@ ir_function_inlining_visitor::visit_enter(ir_assignment *ir) return visit_continue; } + +/** + * Replaces references to the "sampler" variable with a clone of "deref." + * + * From the spec, samplers can appear in the tree as function + * (non-out) parameters and as the result of array indexing and + * structure field selection. In our builtin implementation, they + * also appear in the sampler field of an ir_tex instruction. + */ + +class ir_sampler_replacement_visitor : public ir_hierarchical_visitor { +public: + ir_sampler_replacement_visitor(ir_variable *sampler, ir_dereference *deref) + { + this->sampler = sampler; + this->deref = deref; + } + + virtual ~ir_sampler_replacement_visitor() + { + } + + virtual ir_visitor_status visit_leave(ir_call *); + virtual ir_visitor_status visit_leave(ir_dereference_array *); + virtual ir_visitor_status visit_leave(ir_dereference_record *); + virtual ir_visitor_status visit_leave(ir_texture *); + + void replace_deref(ir_dereference **deref); + void replace_rvalue(ir_rvalue **rvalue); + + ir_variable *sampler; + ir_dereference *deref; +}; + +void +ir_sampler_replacement_visitor::replace_deref(ir_dereference **deref) +{ + ir_dereference_variable *deref_var = (*deref)->as_dereference_variable(); + if (deref_var && deref_var->var == this->sampler) { + *deref = this->deref->clone(talloc_parent(*deref), NULL); + } +} + +void +ir_sampler_replacement_visitor::replace_rvalue(ir_rvalue **rvalue) +{ + if (!*rvalue) + return; + + ir_dereference *deref = (*rvalue)->as_dereference(); + + if (!deref) + return; + + replace_deref(&deref); + *rvalue = deref; +} + +ir_visitor_status +ir_sampler_replacement_visitor::visit_leave(ir_texture *ir) +{ + replace_deref(&ir->sampler); + + return visit_continue; +} + +ir_visitor_status +ir_sampler_replacement_visitor::visit_leave(ir_dereference_array *ir) +{ + replace_rvalue(&ir->array); + return visit_continue; +} + +ir_visitor_status +ir_sampler_replacement_visitor::visit_leave(ir_dereference_record *ir) +{ + replace_rvalue(&ir->record); + return visit_continue; +} + +ir_visitor_status +ir_sampler_replacement_visitor::visit_leave(ir_call *ir) +{ + foreach_iter(exec_list_iterator, iter, *ir) { + ir_rvalue *param = (ir_rvalue *)iter.get(); + ir_rvalue *new_param = param; + replace_rvalue(&new_param); + + if (new_param != param) { + param->replace_with(new_param); + } + } + return visit_continue; +} + +static void +do_sampler_replacement(exec_list *instructions, + ir_variable *sampler, + ir_dereference *deref) +{ + ir_sampler_replacement_visitor v(sampler, deref); + + visit_list_elements(&v, instructions); +} |