diff options
Diffstat (limited to 'mesalib/src/glsl')
-rw-r--r-- | mesalib/src/glsl/TODO | 3 | ||||
-rw-r--r-- | mesalib/src/glsl/ir.cpp | 48 | ||||
-rw-r--r-- | mesalib/src/glsl/ir.h | 26 | ||||
-rw-r--r-- | mesalib/src/glsl/opt_algebraic.cpp | 31 |
4 files changed, 101 insertions, 7 deletions
diff --git a/mesalib/src/glsl/TODO b/mesalib/src/glsl/TODO index eb73fc2e8..bd077a856 100644 --- a/mesalib/src/glsl/TODO +++ b/mesalib/src/glsl/TODO @@ -6,9 +6,6 @@ constant index values. For others it is more complicated. Perhaps these cases should be silently converted to uniforms? -- Implement support for ir_binop_dot in opt_algebraic.cpp. Perform - transformations such as "dot(v, vec3(0.0, 1.0, 0.0))" -> v.y. - - Track source locations throughout the IR. There are currently several places where we cannot emit line numbers for errors (and currently emit 0:0) because we've "lost" the line number information. This is particularly diff --git a/mesalib/src/glsl/ir.cpp b/mesalib/src/glsl/ir.cpp index 69954998b..f81bfd1ab 100644 --- a/mesalib/src/glsl/ir.cpp +++ b/mesalib/src/glsl/ir.cpp @@ -46,6 +46,11 @@ bool ir_rvalue::is_negative_one() const return false; } +bool ir_rvalue::is_basis() const +{ + return false; +} + /** * Modify the swizzle make to move one component to another * @@ -1125,6 +1130,49 @@ ir_constant::is_negative_one() const return true; } +bool +ir_constant::is_basis() const +{ + if (!this->type->is_scalar() && !this->type->is_vector()) + return false; + + if (this->type->is_boolean()) + return false; + + unsigned ones = 0; + for (unsigned c = 0; c < this->type->vector_elements; c++) { + switch (this->type->base_type) { + case GLSL_TYPE_FLOAT: + if (this->value.f[c] == 1.0) + ones++; + else if (this->value.f[c] != 0.0) + return false; + break; + case GLSL_TYPE_INT: + if (this->value.i[c] == 1) + ones++; + else if (this->value.i[c] != 0) + return false; + break; + case GLSL_TYPE_UINT: + if (int(this->value.u[c]) == 1) + ones++; + else if (int(this->value.u[c]) != 0) + return false; + break; + default: + /* The only other base types are structures, arrays, samplers, and + * booleans. Samplers cannot be constants, and the others should + * have been filtered out above. + */ + assert(!"Should not get here."); + return false; + } + } + + return ones == 1; +} + ir_loop::ir_loop() { this->ir_type = ir_type_loop; diff --git a/mesalib/src/glsl/ir.h b/mesalib/src/glsl/ir.h index a3f9f0588..55535b2f5 100644 --- a/mesalib/src/glsl/ir.h +++ b/mesalib/src/glsl/ir.h @@ -201,7 +201,8 @@ public: * for vector and scalar types that have all elements set to the value * zero (or \c false for booleans). * - * \sa ir_constant::has_value, ir_rvalue::is_one, ir_rvalue::is_negative_one + * \sa ir_constant::has_value, ir_rvalue::is_one, ir_rvalue::is_negative_one, + * ir_constant::is_basis */ virtual bool is_zero() const; @@ -213,7 +214,8 @@ public: * for vector and scalar types that have all elements set to the value * one (or \c true for booleans). * - * \sa ir_constant::has_value, ir_rvalue::is_zero, ir_rvalue::is_negative_one + * \sa ir_constant::has_value, ir_rvalue::is_zero, ir_rvalue::is_negative_one, + * ir_constant::is_basis */ virtual bool is_one() const; @@ -223,12 +225,27 @@ public: * The base implementation of this function always returns \c false. The * \c ir_constant class over-rides this function to return \c true \b only * for vector and scalar types that have all elements set to the value - * negative one. For boolean times, the result is always \c false. + * negative one. For boolean types, the result is always \c false. * * \sa ir_constant::has_value, ir_rvalue::is_zero, ir_rvalue::is_one + * ir_constant::is_basis */ virtual bool is_negative_one() const; + /** + * Determine if an r-value is a basis vector + * + * The base implementation of this function always returns \c false. The + * \c ir_constant class over-rides this function to return \c true \b only + * for vector and scalar types that have one element set to the value one, + * and the other elements set to the value zero. For boolean types, the + * result is always \c false. + * + * \sa ir_constant::has_value, ir_rvalue::is_zero, ir_rvalue::is_one, + * is_constant::is_negative_one + */ + virtual bool is_basis() const; + /** * Return a generic value of error_type. @@ -1743,13 +1760,14 @@ public: * Determine whether a constant has the same value as another constant * * \sa ir_constant::is_zero, ir_constant::is_one, - * ir_constant::is_negative_one + * ir_constant::is_negative_one, ir_constant::is_basis */ bool has_value(const ir_constant *) const; virtual bool is_zero() const; virtual bool is_one() const; virtual bool is_negative_one() const; + virtual bool is_basis() const; /** * Value of the constant. diff --git a/mesalib/src/glsl/opt_algebraic.cpp b/mesalib/src/glsl/opt_algebraic.cpp index d39761260..75948db16 100644 --- a/mesalib/src/glsl/opt_algebraic.cpp +++ b/mesalib/src/glsl/opt_algebraic.cpp @@ -84,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) { @@ -309,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])) { |