summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Romanick <ian.d.romanick@intel.com>2010-06-11 14:01:44 -0700
committerIan Romanick <ian.d.romanick@intel.com>2010-06-11 15:48:26 -0700
commitbe1d2bfdeab5781b6546b704b566aa214e79da06 (patch)
tree5cda7f5d256b3911d5876f436e2fc9572f2c5266
parent39d6dd3537ce436806dbb5e7f6fa7c5477babb8e (diff)
Matrix and vector constructors with a single constant scalar are constant
-rw-r--r--ast_function.cpp123
-rw-r--r--ir.h18
2 files changed, 131 insertions, 10 deletions
diff --git a/ast_function.cpp b/ast_function.cpp
index aba4374..d89266b 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 718c495..1fdd125 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;