(declare (in) float arg0)
(declare (in) float arg1)
(declare (in) float arg2))
- ((return (expression float + (expression float * (var_ref arg0) (expression float - (constant float (1.000000)) (var_ref arg2))) (expression float * (var_ref arg1) (var_ref arg2))))))
+ ((return (expression float lrp (var_ref arg0) (var_ref arg1) (var_ref arg2)))))
(signature vec2
(parameters
(declare (in) vec2 arg0)
(declare (in) vec2 arg1)
(declare (in) vec2 arg2))
- ((return (expression vec2 + (expression vec2 * (var_ref arg0) (expression vec2 - (constant float (1.000000)) (var_ref arg2))) (expression vec2 * (var_ref arg1) (var_ref arg2))))))
+ ((return (expression vec2 lrp (var_ref arg0) (var_ref arg1) (var_ref arg2)))))
(signature vec3
(parameters
(declare (in) vec3 arg0)
(declare (in) vec3 arg1)
(declare (in) vec3 arg2))
- ((return (expression vec3 + (expression vec3 * (var_ref arg0) (expression vec3 - (constant float (1.000000)) (var_ref arg2))) (expression vec3 * (var_ref arg1) (var_ref arg2))))))
+ ((return (expression vec3 lrp (var_ref arg0) (var_ref arg1) (var_ref arg2)))))
(signature vec4
(parameters
(declare (in) vec4 arg0)
(declare (in) vec4 arg1)
(declare (in) vec4 arg2))
- ((return (expression vec4 + (expression vec4 * (var_ref arg0) (expression vec4 - (constant float (1.000000)) (var_ref arg2))) (expression vec4 * (var_ref arg1) (var_ref arg2))))))
+ ((return (expression vec4 lrp (var_ref arg0) (var_ref arg1) (var_ref arg2)))))
(signature vec2
(parameters
(declare (in) vec2 arg0)
(declare (in) vec2 arg1)
(declare (in) float arg2))
- ((return (expression vec2 + (expression vec2 * (var_ref arg0) (expression float - (constant float (1.000000)) (var_ref arg2))) (expression vec2 * (var_ref arg1) (var_ref arg2))))))
+ ((return (expression vec2 lrp (var_ref arg0) (var_ref arg1) (var_ref arg2)))))
(signature vec3
(parameters
(declare (in) vec3 arg0)
(declare (in) vec3 arg1)
(declare (in) float arg2))
- ((return (expression vec3 + (expression vec3 * (var_ref arg0) (expression float - (constant float (1.000000)) (var_ref arg2))) (expression vec3 * (var_ref arg1) (var_ref arg2))))))
+ ((return (expression vec3 lrp (var_ref arg0) (var_ref arg1) (var_ref arg2)))))
(signature vec4
(parameters
(declare (in) vec4 arg0)
(declare (in) vec4 arg1)
(declare (in) float arg2))
- ((return (expression vec4 + (expression vec4 * (var_ref arg0) (expression float - (constant float (1.000000)) (var_ref arg2))) (expression vec4 * (var_ref arg1) (var_ref arg2))))))
+ ((return (expression vec4 lrp (var_ref arg0) (var_ref arg1) (var_ref arg2)))))
(signature float
(parameters
if (op <= ir_last_binop)
return 2;
+ if (op <= ir_last_triop)
+ return 3;
+
if (op == ir_quadop_vector)
return 4;
"pow",
"packHalf2x16_split",
"ubo_load",
+ "lrp",
"vector",
};
*/
ir_last_binop = ir_binop_ubo_load,
+ ir_triop_lrp,
+
+ /**
+ * A sentinel marking the last of the ternary operations.
+ */
+ ir_last_triop = ir_triop_lrp,
+
ir_quadop_vector,
/**
}
break;
+ case ir_triop_lrp: {
+ assert(op[0]->type->base_type == GLSL_TYPE_FLOAT);
+ assert(op[1]->type->base_type == GLSL_TYPE_FLOAT);
+ assert(op[2]->type->base_type == GLSL_TYPE_FLOAT);
+
+ unsigned c2_inc = op[2]->type->is_scalar() ? 0 : 1;
+ for (unsigned c = 0, c2 = 0; c < components; c2 += c2_inc, c++) {
+ data.f[c] = op[0]->value.f[c] * (1.0f - op[2]->value.f[c2]) +
+ (op[1]->value.f[c] * op[2]->value.f[c2]);
+ }
+ break;
+ }
+
case ir_quadop_vector:
for (unsigned c = 0; c < this->type->vector_elements; c++) {
switch (this->type->base_type) {
#define LOG_TO_LOG2 0x10
#define MOD_TO_FRACT 0x20
#define INT_DIV_TO_MUL_RCP 0x40
+#define LRP_TO_ARITH 0x80
/**
* \see class lower_packing_builtins_visitor
assert(ir->operands[1]->type == glsl_type::uint_type);
break;
+ case ir_triop_lrp:
+ assert(ir->operands[0]->type->base_type == GLSL_TYPE_FLOAT);
+ assert(ir->operands[0]->type == ir->operands[1]->type);
+ assert(ir->operands[2]->type == ir->operands[0]->type || ir->operands[2]->type == glsl_type::float_type);
+ break;
+
case ir_quadop_vector:
/* The vector operator collects some number of scalars and generates a
* vector from them.
* - POW_TO_EXP2
* - LOG_TO_LOG2
* - MOD_TO_FRACT
+ * - LRP_TO_ARITH
*
* SUB_TO_ADD_NEG:
* ---------------
* Many GPUs don't have a MOD instruction (945 and 965 included), and
* if we have to break it down like this anyway, it gives an
* opportunity to do things like constant fold the (1.0 / op1) easily.
+ *
+ * LRP_TO_ARITH:
+ * -------------
+ * Converts ir_triop_lrp to (op0 * (1.0f - op2)) + (op1 * op2).
*/
#include "main/core.h" /* for M_LOG2E */
#include "glsl_types.h"
#include "ir.h"
+#include "ir_builder.h"
#include "ir_optimization.h"
+using namespace ir_builder;
+
class lower_instructions_visitor : public ir_hierarchical_visitor {
public:
lower_instructions_visitor(unsigned lower)
void exp_to_exp2(ir_expression *);
void pow_to_exp2(ir_expression *);
void log_to_log2(ir_expression *);
+ void lrp_to_arith(ir_expression *);
};
/**
this->progress = true;
}
+void
+lower_instructions_visitor::lrp_to_arith(ir_expression *ir)
+{
+ /* (lrp x y a) -> x*(1-a) + y*a */
+
+ /* Save op2 */
+ ir_variable *temp = new(ir) ir_variable(ir->operands[2]->type, "lrp_factor",
+ ir_var_temporary);
+ this->base_ir->insert_before(temp);
+ this->base_ir->insert_before(assign(temp, ir->operands[2]));
+
+ ir_constant *one = new(ir) ir_constant(1.0f);
+
+ ir->operation = ir_binop_add;
+ ir->operands[0] = mul(ir->operands[0], sub(one, temp));
+ ir->operands[1] = mul(ir->operands[1], temp);
+ ir->operands[2] = NULL;
+
+ this->progress = true;
+}
+
ir_visitor_status
lower_instructions_visitor::visit_leave(ir_expression *ir)
{
pow_to_exp2(ir);
break;
+ case ir_triop_lrp:
+ if (lowering(LRP_TO_ARITH))
+ lrp_to_arith(ir);
+ break;
+
default:
return visit_continue;
}
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[3] = {NULL, NULL, NULL};
+ ir_expression *op_expr[3] = {NULL, NULL, NULL};
ir_expression *temp;
unsigned int i;
- assert(ir->get_num_operands() <= 2);
+ assert(ir->get_num_operands() <= 3);
for (i = 0; i < ir->get_num_operands(); i++) {
if (ir->operands[i]->type->is_matrix())
return ir;
DIV_TO_MUL_RCP |
SUB_TO_ADD_NEG |
EXP_TO_EXP2 |
- LOG_TO_LOG2);
+ LOG_TO_LOG2 |
+ LRP_TO_ARITH);
/* Pre-gen6 HW can only nest if-statements 16 deep. Beyond this,
* if-statements need to be flattened.
assert(!"not supported");
break;
+ case ir_triop_lrp:
+ assert(!"ir_triop_lrp should have been lowered.");
+ break;
+
case ir_quadop_vector:
/* This operation should have already been handled.
*/
/* Lowering */
do_mat_op_to_vec(ir);
lower_instructions(ir, (MOD_TO_FRACT | DIV_TO_MUL_RCP | EXP_TO_EXP2
- | LOG_TO_LOG2 | INT_DIV_TO_MUL_RCP
+ | LOG_TO_LOG2 | INT_DIV_TO_MUL_RCP | LRP_TO_ARITH
| ((options->EmitNoPow) ? POW_TO_EXP2 : 0)));
progress = do_lower_jumps(ir, true, true, options->EmitNoMainReturn, options->EmitNoCont, options->EmitNoLoops) || progress;
DIV_TO_MUL_RCP |
EXP_TO_EXP2 |
LOG_TO_LOG2 |
+ LRP_TO_ARITH |
(options->EmitNoPow ? POW_TO_EXP2 : 0) |
(!ctx->Const.NativeIntegers ? INT_DIV_TO_MUL_RCP : 0));