Matrix and vector constructors with a single constant scalar are constant
authorIan Romanick <ian.d.romanick@intel.com>
Fri, 11 Jun 2010 21:01:44 +0000 (14:01 -0700)
committerIan Romanick <ian.d.romanick@intel.com>
Fri, 11 Jun 2010 22:48:26 +0000 (15:48 -0700)
ast_function.cpp
ir.h

index aba43749e06084220e57b0cba2fbe8c032ab0577..d89266b9cc7a519ec80a8961e151e6ef392678b1 100644 (file)
@@ -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 718c495fb3089da3c54ff1061953704f5efc3d77..1fdd125d8ace8c9237788e41b09e95ac9ad1c4ef 100644 (file)
--- 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;