diff options
-rw-r--r-- | src/glsl/ast_function.cpp | 101 |
1 files changed, 100 insertions, 1 deletions
diff --git a/src/glsl/ast_function.cpp b/src/glsl/ast_function.cpp index f431d1d0156..f1ab6f0c5a1 100644 --- a/src/glsl/ast_function.cpp +++ b/src/glsl/ast_function.cpp @@ -444,6 +444,98 @@ generate_constructor_vector(const glsl_type *type, ir_constant *initializer, } +/** + * Determine if a list consists of a single scalar r-value + */ +bool +single_scalar_parameter(exec_list *parameters) +{ + const ir_rvalue *const p = (ir_rvalue *) parameters->head; + assert(((ir_rvalue *)p)->as_rvalue() != NULL); + + return (p->type->is_scalar() && p->next->is_tail_sentinal()); +} + + +/** + * Generate inline code for a vector constructor + * + * The generated constructor code will consist of a temporary variable + * declaration of the same type as the constructor. A sequence of assignments + * from constructor parameters to the temporary will follow. + * + * \return + * An \c ir_dereference_variable of the temprorary generated in the constructor + * body. + */ +ir_rvalue * +emit_inline_vector_constructor(const glsl_type *type, + exec_list *instructions, + exec_list *parameters, + void *ctx) +{ + assert(!parameters->is_empty()); + + ir_variable *var = new(ctx) ir_variable(type, strdup("vec_ctor")); + instructions->push_tail(var); + + /* There are two kinds of vector constructors. + * + * - Construct a vector from a single scalar by replicating that scalar to + * all components of the vector. + * + * - Construct a vector from an arbirary combination of vectors and + * scalars. The components of the constructor parameters are assigned + * to the vector in order until the vector is full. + */ + const unsigned lhs_components = type->components(); + if (single_scalar_parameter(parameters)) { + ir_rvalue *first_param = (ir_rvalue *)parameters->head; + ir_rvalue *rhs = new(ctx) ir_swizzle(first_param, 0, 0, 0, 0, + lhs_components); + ir_dereference_variable *lhs = new(ctx) ir_dereference_variable(var); + + assert(rhs->type == lhs->type); + + ir_instruction *inst = new(ctx) ir_assignment(lhs, rhs, NULL); + instructions->push_tail(inst); + } else { + unsigned base_component = 0; + foreach_list(node, parameters) { + ir_rvalue *rhs = (ir_rvalue *) node; + unsigned rhs_components = rhs->type->components(); + + /* Do not try to assign more components to the vector than it has! + */ + if ((rhs_components + base_component) > lhs_components) { + rhs_components = lhs_components - base_component; + } + + /* Emit an assignment of the constructor parameter to the next set of + * components in the temporary variable. + */ + unsigned mask[4] = { 0, 0, 0, 0 }; + for (unsigned i = 0; i < rhs_components; i++) { + mask[i] = i + base_component; + } + + + ir_rvalue *lhs_ref = new(ctx) ir_dereference_variable(var); + ir_swizzle *lhs = new(ctx) ir_swizzle(lhs_ref, mask, rhs_components); + + ir_instruction *inst = new(ctx) ir_assignment(lhs, rhs, NULL); + instructions->push_tail(inst); + + /* Advance the component index by the number of components that were + * just assigned. + */ + base_component += rhs_components; + } + } + return new(ctx) ir_dereference_variable(var); +} + + ir_rvalue * ast_function_expression::hir(exec_list *instructions, struct _mesa_glsl_parse_state *state) @@ -708,8 +800,15 @@ ast_function_expression::hir(exec_list *instructions, &data); return new(ctx) ir_constant(sig->return_type, &data); - } else + } else if (constructor_type->is_vector()) { + return emit_inline_vector_constructor(constructor_type, + instructions, + &actual_parameters, + ctx); + } else { + assert(constructor_type->is_matrix()); return new(ctx) ir_call(sig, & actual_parameters); + } } else { /* FINISHME: Log a better error message here. G++ will show the * FINSIHME: types of the actual parameters and the set of |