softpipe: fix seamless cube filtering
[mesa.git] / src / glsl / opt_algebraic.cpp
index 3c9af85f312bd17b2ab3143d7dee4c9f9dbf8251..d706a6ad13c44092b5e5498e93f58b2ce6cbd2db 100644 (file)
@@ -34,6 +34,8 @@
 #include "ir_optimization.h"
 #include "glsl_types.h"
 
+namespace {
+
 /**
  * Visitor class for replacing expressions with ir_constant values.
  */
@@ -68,6 +70,8 @@ public:
    bool progress;
 };
 
+} /* unnamed namespace */
+
 static inline bool
 is_vec_zero(ir_constant *ir)
 {
@@ -80,6 +84,12 @@ is_vec_one(ir_constant *ir)
    return (ir == NULL) ? false : ir->is_one();
 }
 
+static inline bool
+is_vec_basis(ir_constant *ir)
+{
+   return (ir == NULL) ? false : ir->is_basis();
+}
+
 static void
 update_type(ir_expression *ir)
 {
@@ -123,8 +133,8 @@ ir_algebraic_visitor::reassociate_constant(ir_expression *ir1, int const_index,
 
    /* Don't want to even think about matrices. */
    if (ir1->operands[0]->type->is_matrix() ||
-       ir1->operands[0]->type->is_matrix() ||
-       ir2->operands[1]->type->is_matrix() ||
+       ir1->operands[1]->type->is_matrix() ||
+       ir2->operands[0]->type->is_matrix() ||
        ir2->operands[1]->type->is_matrix())
       return false;
 
@@ -176,12 +186,12 @@ ir_algebraic_visitor::swizzle_if_required(ir_expression *expr,
 ir_rvalue *
 ir_algebraic_visitor::handle_expression(ir_expression *ir)
 {
-   ir_constant *op_const[2] = {NULL, NULL};
-   ir_expression *op_expr[2] = {NULL, NULL};
+   ir_constant *op_const[4] = {NULL, NULL, NULL, NULL};
+   ir_expression *op_expr[4] = {NULL, NULL, NULL, NULL};
    ir_expression *temp;
    unsigned int i;
 
-   assert(ir->get_num_operands() <= 2);
+   assert(ir->get_num_operands() <= 4);
    for (i = 0; i < ir->get_num_operands(); i++) {
       if (ir->operands[i]->type->is_matrix())
         return ir;
@@ -191,7 +201,7 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir)
    }
 
    if (this->mem_ctx == NULL)
-      this->mem_ctx = talloc_parent(ir);
+      this->mem_ctx = ralloc_parent(ir);
 
    switch (ir->operation) {
    case ir_unop_logic_not: {
@@ -305,6 +315,31 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir)
       }
       break;
 
+   case ir_binop_dot:
+      if (is_vec_zero(op_const[0]) || is_vec_zero(op_const[1])) {
+        this->progress = true;
+        return ir_constant::zero(mem_ctx, ir->type);
+      }
+      if (is_vec_basis(op_const[0])) {
+        this->progress = true;
+        unsigned component = 0;
+        for (unsigned c = 0; c < op_const[0]->type->vector_elements; c++) {
+           if (op_const[0]->value.f[c] == 1.0)
+              component = c;
+        }
+        return new(mem_ctx) ir_swizzle(ir->operands[1], component, 0, 0, 0, 1);
+      }
+      if (is_vec_basis(op_const[1])) {
+        this->progress = true;
+        unsigned component = 0;
+        for (unsigned c = 0; c < op_const[1]->type->vector_elements; c++) {
+           if (op_const[1]->value.f[c] == 1.0)
+              component = c;
+        }
+        return new(mem_ctx) ir_swizzle(ir->operands[0], component, 0, 0, 0, 1);
+      }
+      break;
+
    case ir_binop_logic_and:
       /* FINISHME: Also simplify (a && a) to (a). */
       if (is_vec_one(op_const[0])) {
@@ -380,6 +415,17 @@ ir_algebraic_visitor::handle_expression(ir_expression *ir)
 
       break;
 
+   case ir_triop_lrp:
+      /* Operands are (x, y, a). */
+      if (is_vec_zero(op_const[2])) {
+         this->progress = true;
+         return swizzle_if_required(ir, ir->operands[0]);
+      } else if (is_vec_one(op_const[2])) {
+         this->progress = true;
+         return swizzle_if_required(ir, ir->operands[1]);
+      }
+      break;
+
    default:
       break;
    }