Mesa (glsl2): glsl2: Add matrix multiplication to ir_mat_op_to_vec.

Eric Anholt anholt at kemper.freedesktop.org
Tue Jul 13 02:55:42 UTC 2010


Module: Mesa
Branch: glsl2
Commit: 15ded6327966fa5824e34f7291e624994457f9b5
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=15ded6327966fa5824e34f7291e624994457f9b5

Author: Eric Anholt <eric at anholt.net>
Date:   Mon Jul 12 17:34:17 2010 -0700

glsl2: Add matrix multiplication to ir_mat_op_to_vec.

---

 src/glsl/ir_mat_op_to_vec.cpp |  197 +++++++++++++++++++++++++++++++++++++++--
 1 files changed, 188 insertions(+), 9 deletions(-)

diff --git a/src/glsl/ir_mat_op_to_vec.cpp b/src/glsl/ir_mat_op_to_vec.cpp
index 828c63c..7bdb905 100644
--- a/src/glsl/ir_mat_op_to_vec.cpp
+++ b/src/glsl/ir_mat_op_to_vec.cpp
@@ -44,7 +44,17 @@ public:
 
    ir_visitor_status visit_leave(ir_assignment *);
 
-   ir_rvalue *get_column(ir_variable *var, int i);
+   ir_rvalue *get_column(ir_variable *var, int col);
+   ir_rvalue *get_element(ir_variable *var, int col, int row);
+
+   void do_mul_mat_mat(ir_variable *result_var,
+		       ir_variable *a_var, ir_variable *b_var);
+   void do_mul_mat_vec(ir_variable *result_var,
+		       ir_variable *a_var, ir_variable *b_var);
+   void do_mul_vec_mat(ir_variable *result_var,
+		       ir_variable *a_var, ir_variable *b_var);
+   void do_mul_mat_scalar(ir_variable *result_var,
+			  ir_variable *a_var, ir_variable *b_var);
 
    bool made_progress;
 };
@@ -83,7 +93,24 @@ do_mat_op_to_vec(exec_list *instructions)
 }
 
 ir_rvalue *
-ir_mat_op_to_vec_visitor::get_column(ir_variable *var, int i)
+ir_mat_op_to_vec_visitor::get_element(ir_variable *var, int col, int row)
+{
+   ir_dereference *deref;
+
+   deref = new(base_ir) ir_dereference_variable(var);
+
+   if (var->type->is_matrix()) {
+      deref = new(base_ir) ir_dereference_array(var,
+						new(base_ir) ir_constant(col));
+   } else {
+      assert(col == 0);
+   }
+
+   return new(base_ir) ir_swizzle(deref, row, 0, 0, 0, 1);
+}
+
+ir_rvalue *
+ir_mat_op_to_vec_visitor::get_column(ir_variable *var, int row)
 {
    ir_dereference *deref;
 
@@ -92,12 +119,152 @@ ir_mat_op_to_vec_visitor::get_column(ir_variable *var, int i)
    } else {
       deref = new(base_ir) ir_dereference_variable(var);
       deref = new(base_ir) ir_dereference_array(deref,
-						new(base_ir) ir_constant(i));
+						new(base_ir) ir_constant(row));
    }
 
    return deref;
 }
 
+void
+ir_mat_op_to_vec_visitor::do_mul_mat_mat(ir_variable *result_var,
+					 ir_variable *a_var,
+					 ir_variable *b_var)
+{
+   int b_col, i;
+   ir_assignment *assign;
+   ir_expression *expr;
+
+   for (b_col = 0; b_col < b_var->type->matrix_columns; b_col++) {
+      ir_rvalue *a = get_column(a_var, 0);
+      ir_rvalue *b = get_element(b_var, b_col, 0);
+
+      /* first column */
+      expr = new(base_ir) ir_expression(ir_binop_mul,
+					a->type,
+					a,
+					b);
+
+      /* following columns */
+      for (i = 1; i < a_var->type->matrix_columns; i++) {
+	 ir_expression *mul_expr;
+
+	 a = get_column(a_var, i);
+	 b = get_element(b_var, b_col, i);
+
+	 mul_expr = new(base_ir) ir_expression(ir_binop_mul,
+					       a->type,
+					       a,
+					       b);
+	 expr = new(base_ir) ir_expression(ir_binop_add,
+					   a->type,
+					   expr,
+					   mul_expr);
+      }
+
+      ir_rvalue *result = get_column(result_var, b_col);
+      assign = new(base_ir) ir_assignment(result,
+					  expr,
+					  NULL);
+      base_ir->insert_before(assign);
+   }
+}
+
+void
+ir_mat_op_to_vec_visitor::do_mul_mat_vec(ir_variable *result_var,
+					 ir_variable *a_var,
+					 ir_variable *b_var)
+{
+   int i;
+   ir_rvalue *a = get_column(a_var, 0);
+   ir_rvalue *b = get_element(b_var, 0, 0);
+   ir_assignment *assign;
+   ir_expression *expr;
+
+   /* first column */
+   expr = new(base_ir) ir_expression(ir_binop_mul,
+				     result_var->type,
+				     a,
+				     b);
+
+   /* following columns */
+   for (i = 1; i < a_var->type->matrix_columns; i++) {
+      ir_expression *mul_expr;
+
+      a = get_column(a_var, i);
+      b = get_element(b_var, 0, i);
+
+      mul_expr = new(base_ir) ir_expression(ir_binop_mul,
+					    result_var->type,
+					    a,
+					    b);
+      expr = new(base_ir) ir_expression(ir_binop_add,
+					result_var->type,
+					expr,
+					mul_expr);
+   }
+
+   ir_rvalue *result = new(base_ir) ir_dereference_variable(result_var);
+   assign = new(base_ir) ir_assignment(result,
+				       expr,
+				       NULL);
+   base_ir->insert_before(assign);
+}
+
+void
+ir_mat_op_to_vec_visitor::do_mul_vec_mat(ir_variable *result_var,
+					 ir_variable *a_var,
+					 ir_variable *b_var)
+{
+   int i;
+
+   for (i = 0; i < b_var->type->matrix_columns; i++) {
+      ir_rvalue *a = new(base_ir) ir_dereference_variable(a_var);
+      ir_rvalue *b = get_column(b_var, i);
+      ir_rvalue *result;
+      ir_expression *column_expr;
+      ir_assignment *column_assign;
+
+      result = new(base_ir) ir_dereference_variable(result_var);
+      result = new(base_ir) ir_swizzle(result, i, 0, 0, 0, 1);
+
+      column_expr = new(base_ir) ir_expression(ir_binop_dot,
+					       result->type,
+					       a,
+					       b);
+
+      column_assign = new(base_ir) ir_assignment(result,
+						 column_expr,
+						 NULL);
+      base_ir->insert_before(column_assign);
+   }
+}
+
+void
+ir_mat_op_to_vec_visitor::do_mul_mat_scalar(ir_variable *result_var,
+					    ir_variable *a_var,
+					    ir_variable *b_var)
+{
+   int i;
+
+   for (i = 0; i < a_var->type->matrix_columns; i++) {
+      ir_rvalue *a = get_column(a_var, i);
+      ir_rvalue *b = new(base_ir) ir_dereference_variable(b_var);
+      ir_rvalue *result = get_column(result_var, i);
+      ir_expression *column_expr;
+      ir_assignment *column_assign;
+
+      column_expr = new(base_ir) ir_expression(ir_binop_mul,
+					       result->type,
+					       a,
+					       b);
+
+      column_assign = new(base_ir) ir_assignment(result,
+						 column_expr,
+						 NULL);
+      base_ir->insert_before(column_assign);
+   }
+}
+
 ir_visitor_status
 ir_mat_op_to_vec_visitor::visit_leave(ir_assignment *assign)
 {
@@ -119,10 +286,6 @@ ir_mat_op_to_vec_visitor::visit_leave(ir_assignment *assign)
    if (!found_matrix)
       return visit_continue;
 
-   /* FINISHME: see below */
-   if (expr->operation == ir_binop_mul)
-      return visit_continue;
-
    ir_dereference_variable *lhs_deref = assign->lhs->as_dereference_variable();
    assert(lhs_deref);
 
@@ -174,8 +337,24 @@ ir_mat_op_to_vec_visitor::visit_leave(ir_assignment *assign)
       }
       break;
    case ir_binop_mul:
-      /* FINISHME */
-      return visit_continue;
+      if (op_var[0]->type->is_matrix()) {
+	 if (op_var[1]->type->is_matrix()) {
+	    do_mul_mat_mat(result_var, op_var[0], op_var[1]);
+	 } else if (op_var[1]->type->is_vector()) {
+	    do_mul_mat_vec(result_var, op_var[0], op_var[1]);
+	 } else {
+	    assert(op_var[1]->type->is_scalar());
+	    do_mul_mat_scalar(result_var, op_var[0], op_var[1]);
+	 }
+      } else {
+	 assert(op_var[1]->type->is_matrix());
+	 if (op_var[0]->type->is_vector()) {
+	    do_mul_vec_mat(result_var, op_var[0], op_var[1]);
+	 } else {
+	    assert(op_var[0]->type->is_scalar());
+	    do_mul_mat_scalar(result_var, op_var[1], op_var[0]);
+	 }
+      }
       break;
    default:
       printf("FINISHME: Handle matrix operation for %s\n", expr->operator_string());




More information about the mesa-commit mailing list