From be1d2bfdeab5781b6546b704b566aa214e79da06 Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Fri, 11 Jun 2010 14:01:44 -0700 Subject: [PATCH] Matrix and vector constructors with a single constant scalar are constant --- ast_function.cpp | 123 +++++++++++++++++++++++++++++++++++++++++++++-- ir.h | 18 ++++--- 2 files changed, 131 insertions(+), 10 deletions(-) diff --git a/ast_function.cpp b/ast_function.cpp index aba43749e06..d89266b9cc7 100644 --- a/ast_function.cpp +++ b/ast_function.cpp @@ -338,6 +338,100 @@ constant_record_constructor(const glsl_type *constructor_type, } +/** + * Generate data for a constant matrix constructor w/a single scalar parameter + * + * Matrix constructors in GLSL can be passed a single scalar of the + * approriate type. In these cases, the resulting matrix is the identity + * matrix multipled by the specified scalar. This function generates data for + * that matrix. + * + * \param type Type of the desired matrix. + * \param initializer Scalar value used to initialize the matrix diagonal. + * \param data Location to store the resulting matrix. + */ +void +generate_constructor_matrix(const glsl_type *type, ir_constant *initializer, + ir_constant_data *data) +{ + switch (type->base_type) { + case GLSL_TYPE_UINT: + case GLSL_TYPE_INT: + for (unsigned i = 0; i < type->components(); i++) + data->u[i] = 0; + + for (unsigned i = 0; i < type->matrix_columns; i++) { + /* The array offset of the ith row and column of the matrix. + */ + const unsigned idx = (i * type->vector_elements) + i; + + data->u[idx] = initializer->value.u[0]; + } + break; + + case GLSL_TYPE_FLOAT: + for (unsigned i = 0; i < type->components(); i++) + data->f[i] = 0; + + for (unsigned i = 0; i < type->matrix_columns; i++) { + /* The array offset of the ith row and column of the matrix. + */ + const unsigned idx = (i * type->vector_elements) + i; + + data->f[idx] = initializer->value.f[0]; + } + + break; + + default: + assert(!"Should not get here."); + break; + } +} + + +/** + * Generate data for a constant vector constructor w/a single scalar parameter + * + * Vector constructors in GLSL can be passed a single scalar of the + * approriate type. In these cases, the resulting vector contains the specified + * value in all components. This function generates data for that vector. + * + * \param type Type of the desired vector. + * \param initializer Scalar value used to initialize the vector. + * \param data Location to store the resulting vector data. + */ +void +generate_constructor_vector(const glsl_type *type, ir_constant *initializer, + ir_constant_data *data) +{ + switch (type->base_type) { + case GLSL_TYPE_UINT: + case GLSL_TYPE_INT: + for (unsigned i = 0; i < type->components(); i++) + data->u[i] = initializer->value.u[0]; + + break; + + case GLSL_TYPE_FLOAT: + for (unsigned i = 0; i < type->components(); i++) + data->f[i] = initializer->value.f[0]; + + break; + + case GLSL_TYPE_BOOL: + for (unsigned i = 0; i < type->components(); i++) + data->b[i] = initializer->value.b[0]; + + break; + + default: + assert(!"Should not get here."); + break; + } +} + + ir_rvalue * ast_function_expression::hir(exec_list *instructions, struct _mesa_glsl_parse_state *state) @@ -547,10 +641,31 @@ ast_function_expression::hir(exec_list *instructions, /* If all of the parameters are trivially constant, create a * constant representing the complete collection of parameters. */ - if (all_parameters_are_constant - && (components_used >= type_components)) - return new ir_constant(sig->return_type, & actual_parameters); - else + if (all_parameters_are_constant) { + if (components_used >= type_components) + return new ir_constant(sig->return_type, & actual_parameters); + + assert(sig->return_type->is_vector() + || sig->return_type->is_matrix()); + + /* Constructors with exactly one component are special for + * vectors and matrices. For vectors it causes all elements of + * the vector to be filled with the value. For matrices it + * causes the matrix to be filled with 0 and the diagonal to be + * filled with the value. + */ + ir_constant_data data; + ir_constant *const initializer = + (ir_constant *) actual_parameters.head; + if (sig->return_type->is_matrix()) + generate_constructor_matrix(sig->return_type, initializer, + &data); + else + generate_constructor_vector(sig->return_type, initializer, + &data); + + return new ir_constant(sig->return_type, &data); + } else return new ir_call(sig, & actual_parameters); } else { /* FINISHME: Log a better error message here. G++ will show the diff --git a/ir.h b/ir.h index 718c495fb30..1fdd125d8ac 100644 --- a/ir.h +++ b/ir.h @@ -1018,6 +1018,17 @@ public: }; +/** + * Data stored in an ir_constant + */ +union ir_constant_data { + unsigned u[16]; + int i[16]; + float f[16]; + bool b[16]; +}; + + class ir_constant : public ir_rvalue { public: ir_constant(const struct glsl_type *type, const void *data); @@ -1080,12 +1091,7 @@ public: * by the type associated with the \c ir_instruction. Constants may be * scalars, vectors, or matrices. */ - union { - unsigned u[16]; - int i[16]; - float f[16]; - bool b[16]; - } value; + union ir_constant_data value; exec_list components; -- 2.30.2