summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Anholt <eric@anholt.net>2010-07-12 17:34:17 -0700
committerEric Anholt <eric@anholt.net>2010-07-12 19:50:49 -0700
commit15ded6327966fa5824e34f7291e624994457f9b5 (patch)
tree8fbd04cbf5ba3da84053707f67e748aec8e84c64
parent3f08989267d9cdd944787fcf7a300c6f1f84462c (diff)
glsl2: Add matrix multiplication to ir_mat_op_to_vec.
-rw-r--r--src/glsl/ir_mat_op_to_vec.cpp197
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 828c63c17a7..7bdb9057d82 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());