glsl: Change built-in constant expression evaluation to run the IR.
This removes code duplication with ir_expression::constant_expression_value and builtins/ir/*. Signed-off-by: Olivier Galibert <galibert@pobox.com> Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
This commit is contained in:

committed by
Kenneth Graunke

parent
2ff7b121ca
commit
363c14ae0c
@@ -1128,6 +1128,115 @@ ir_call::constant_expression_value(struct hash_table *variable_context)
|
||||
}
|
||||
|
||||
|
||||
bool ir_function_signature::constant_expression_evaluate_expression_list(const struct exec_list &body,
|
||||
struct hash_table *variable_context,
|
||||
ir_constant **result)
|
||||
{
|
||||
foreach_list(n, &body) {
|
||||
ir_instruction *inst = (ir_instruction *)n;
|
||||
switch(inst->ir_type) {
|
||||
|
||||
/* (declare () type symbol) */
|
||||
case ir_type_variable: {
|
||||
ir_variable *var = inst->as_variable();
|
||||
hash_table_insert(variable_context, ir_constant::zero(this, var->type), var);
|
||||
break;
|
||||
}
|
||||
|
||||
/* (assign [condition] (write-mask) (ref) (value)) */
|
||||
case ir_type_assignment: {
|
||||
ir_assignment *asg = inst->as_assignment();
|
||||
if (asg->condition) {
|
||||
ir_constant *cond = asg->condition->constant_expression_value(variable_context);
|
||||
if (!cond)
|
||||
return false;
|
||||
if (!cond->get_bool_component(0))
|
||||
break;
|
||||
}
|
||||
|
||||
ir_constant *store = NULL;
|
||||
int offset = 0;
|
||||
asg->lhs->constant_referenced(variable_context, store, offset);
|
||||
|
||||
if (!store)
|
||||
return false;
|
||||
|
||||
ir_constant *value = asg->rhs->constant_expression_value(variable_context);
|
||||
|
||||
if (!value)
|
||||
return false;
|
||||
|
||||
store->copy_masked_offset(value, offset, asg->write_mask);
|
||||
break;
|
||||
}
|
||||
|
||||
/* (return (expression)) */
|
||||
case ir_type_return:
|
||||
assert (result);
|
||||
*result = inst->as_return()->value->constant_expression_value(variable_context);
|
||||
return *result != NULL;
|
||||
|
||||
/* (call name (ref) (params))*/
|
||||
case ir_type_call: {
|
||||
ir_call *call = inst->as_call();
|
||||
|
||||
/* Just say no to void functions in constant expressions. We
|
||||
* don't need them at that point.
|
||||
*/
|
||||
|
||||
if (!call->return_deref)
|
||||
return false;
|
||||
|
||||
ir_constant *store = NULL;
|
||||
int offset = 0;
|
||||
call->return_deref->constant_referenced(variable_context, store, offset);
|
||||
|
||||
if (!store)
|
||||
return false;
|
||||
|
||||
ir_constant *value = call->constant_expression_value(variable_context);
|
||||
|
||||
if(!value)
|
||||
return false;
|
||||
|
||||
store->copy_offset(value, offset);
|
||||
break;
|
||||
}
|
||||
|
||||
/* (if condition (then-instructions) (else-instructions)) */
|
||||
case ir_type_if: {
|
||||
ir_if *iif = inst->as_if();
|
||||
|
||||
ir_constant *cond = iif->condition->constant_expression_value(variable_context);
|
||||
if (!cond || !cond->type->is_boolean())
|
||||
return false;
|
||||
|
||||
exec_list &branch = cond->get_bool_component(0) ? iif->then_instructions : iif->else_instructions;
|
||||
|
||||
*result = NULL;
|
||||
if (!constant_expression_evaluate_expression_list(branch, variable_context, result))
|
||||
return false;
|
||||
|
||||
/* If there was a return in the branch chosen, drop out now. */
|
||||
if (*result)
|
||||
return true;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* Every other expression type, we drop out. */
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Reaching the end of the block is not an error condition */
|
||||
if (result)
|
||||
*result = NULL;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ir_constant *
|
||||
ir_function_signature::constant_expression_value(exec_list *actual_parameters, struct hash_table *variable_context)
|
||||
{
|
||||
@@ -1142,396 +1251,48 @@ ir_function_signature::constant_expression_value(exec_list *actual_parameters, s
|
||||
if (!this->is_builtin)
|
||||
return NULL;
|
||||
|
||||
unsigned num_parameters = 0;
|
||||
/*
|
||||
* Of the builtin functions, only the texture lookups and the noise
|
||||
* ones must not be used in constant expressions. They all include
|
||||
* specific opcodes so they don't need to be special-cased at this
|
||||
* point.
|
||||
*/
|
||||
|
||||
/* Initialize the table of dereferencable names with the function
|
||||
* parameters. Verify their const-ness on the way.
|
||||
*
|
||||
* We expect the correctness of the number of parameters to have
|
||||
* been checked earlier.
|
||||
*/
|
||||
hash_table *deref_hash = hash_table_ctor(8, hash_table_pointer_hash,
|
||||
hash_table_pointer_compare);
|
||||
|
||||
/* If "origin" is non-NULL, then the function body is there. So we
|
||||
* have to use the variable objects from the object with the body,
|
||||
* but the parameter instanciation on the current object.
|
||||
*/
|
||||
const exec_node *parameter_info = origin ? origin->parameters.head : parameters.head;
|
||||
|
||||
/* Check if all parameters are constant */
|
||||
ir_constant *op[3];
|
||||
foreach_list(n, actual_parameters) {
|
||||
ir_constant *constant = ((ir_rvalue *) n)->constant_expression_value(variable_context);
|
||||
if (constant == NULL)
|
||||
return NULL;
|
||||
|
||||
op[num_parameters] = constant;
|
||||
ir_variable *var = (ir_variable *)parameter_info;
|
||||
hash_table_insert(deref_hash, constant, var);
|
||||
|
||||
assert(num_parameters < 3);
|
||||
num_parameters++;
|
||||
parameter_info = parameter_info->next;
|
||||
}
|
||||
|
||||
/* Individual cases below can either:
|
||||
* - Assign "expr" a new ir_expression to evaluate (for basic opcodes)
|
||||
* - Fill "data" with appopriate constant data
|
||||
* - Return an ir_constant directly.
|
||||
ir_constant *result = NULL;
|
||||
|
||||
/* Now run the builtin function until something non-constant
|
||||
* happens or we get the result.
|
||||
*/
|
||||
void *mem_ctx = ralloc_parent(this);
|
||||
ir_expression *expr = NULL;
|
||||
if (constant_expression_evaluate_expression_list(origin ? origin->body : body, deref_hash, &result) && result)
|
||||
result = result->clone(ralloc_parent(this), NULL);
|
||||
|
||||
ir_constant_data data;
|
||||
memset(&data, 0, sizeof(data));
|
||||
hash_table_dtor(deref_hash);
|
||||
|
||||
const char *callee = this->function_name();
|
||||
if (strcmp(callee, "abs") == 0) {
|
||||
expr = new(mem_ctx) ir_expression(ir_unop_abs, type, op[0], NULL);
|
||||
} else if (strcmp(callee, "all") == 0) {
|
||||
assert(op[0]->type->is_boolean());
|
||||
for (unsigned c = 0; c < op[0]->type->components(); c++) {
|
||||
if (!op[0]->value.b[c])
|
||||
return new(mem_ctx) ir_constant(false);
|
||||
}
|
||||
return new(mem_ctx) ir_constant(true);
|
||||
} else if (strcmp(callee, "any") == 0) {
|
||||
assert(op[0]->type->is_boolean());
|
||||
for (unsigned c = 0; c < op[0]->type->components(); c++) {
|
||||
if (op[0]->value.b[c])
|
||||
return new(mem_ctx) ir_constant(true);
|
||||
}
|
||||
return new(mem_ctx) ir_constant(false);
|
||||
} else if (strcmp(callee, "acos") == 0) {
|
||||
assert(op[0]->type->is_float());
|
||||
for (unsigned c = 0; c < op[0]->type->components(); c++)
|
||||
data.f[c] = acosf(op[0]->value.f[c]);
|
||||
} else if (strcmp(callee, "acosh") == 0) {
|
||||
assert(op[0]->type->is_float());
|
||||
for (unsigned c = 0; c < op[0]->type->components(); c++)
|
||||
data.f[c] = acoshf(op[0]->value.f[c]);
|
||||
} else if (strcmp(callee, "asin") == 0) {
|
||||
assert(op[0]->type->is_float());
|
||||
for (unsigned c = 0; c < op[0]->type->components(); c++)
|
||||
data.f[c] = asinf(op[0]->value.f[c]);
|
||||
} else if (strcmp(callee, "asinh") == 0) {
|
||||
assert(op[0]->type->is_float());
|
||||
for (unsigned c = 0; c < op[0]->type->components(); c++)
|
||||
data.f[c] = asinhf(op[0]->value.f[c]);
|
||||
} else if (strcmp(callee, "atan") == 0) {
|
||||
assert(op[0]->type->is_float());
|
||||
if (num_parameters == 2) {
|
||||
assert(op[1]->type->is_float());
|
||||
for (unsigned c = 0; c < op[0]->type->components(); c++)
|
||||
data.f[c] = atan2f(op[0]->value.f[c], op[1]->value.f[c]);
|
||||
} else {
|
||||
for (unsigned c = 0; c < op[0]->type->components(); c++)
|
||||
data.f[c] = atanf(op[0]->value.f[c]);
|
||||
}
|
||||
} else if (strcmp(callee, "atanh") == 0) {
|
||||
assert(op[0]->type->is_float());
|
||||
for (unsigned c = 0; c < op[0]->type->components(); c++)
|
||||
data.f[c] = atanhf(op[0]->value.f[c]);
|
||||
} else if (strcmp(callee, "dFdx") == 0 || strcmp(callee, "dFdy") == 0) {
|
||||
return ir_constant::zero(mem_ctx, type);
|
||||
} else if (strcmp(callee, "ceil") == 0) {
|
||||
expr = new(mem_ctx) ir_expression(ir_unop_ceil, type, op[0], NULL);
|
||||
} else if (strcmp(callee, "clamp") == 0) {
|
||||
assert(num_parameters == 3);
|
||||
unsigned c1_inc = op[1]->type->is_scalar() ? 0 : 1;
|
||||
unsigned c2_inc = op[2]->type->is_scalar() ? 0 : 1;
|
||||
for (unsigned c = 0, c1 = 0, c2 = 0;
|
||||
c < op[0]->type->components();
|
||||
c1 += c1_inc, c2 += c2_inc, c++) {
|
||||
|
||||
switch (op[0]->type->base_type) {
|
||||
case GLSL_TYPE_UINT:
|
||||
data.u[c] = CLAMP(op[0]->value.u[c], op[1]->value.u[c1],
|
||||
op[2]->value.u[c2]);
|
||||
break;
|
||||
case GLSL_TYPE_INT:
|
||||
data.i[c] = CLAMP(op[0]->value.i[c], op[1]->value.i[c1],
|
||||
op[2]->value.i[c2]);
|
||||
break;
|
||||
case GLSL_TYPE_FLOAT:
|
||||
data.f[c] = CLAMP(op[0]->value.f[c], op[1]->value.f[c1],
|
||||
op[2]->value.f[c2]);
|
||||
break;
|
||||
default:
|
||||
assert(!"Should not get here.");
|
||||
}
|
||||
}
|
||||
} else if (strcmp(callee, "cos") == 0) {
|
||||
expr = new(mem_ctx) ir_expression(ir_unop_cos, type, op[0], NULL);
|
||||
} else if (strcmp(callee, "cosh") == 0) {
|
||||
assert(op[0]->type->is_float());
|
||||
for (unsigned c = 0; c < op[0]->type->components(); c++)
|
||||
data.f[c] = coshf(op[0]->value.f[c]);
|
||||
} else if (strcmp(callee, "cross") == 0) {
|
||||
assert(op[0]->type == glsl_type::vec3_type);
|
||||
assert(op[1]->type == glsl_type::vec3_type);
|
||||
data.f[0] = (op[0]->value.f[1] * op[1]->value.f[2] -
|
||||
op[1]->value.f[1] * op[0]->value.f[2]);
|
||||
data.f[1] = (op[0]->value.f[2] * op[1]->value.f[0] -
|
||||
op[1]->value.f[2] * op[0]->value.f[0]);
|
||||
data.f[2] = (op[0]->value.f[0] * op[1]->value.f[1] -
|
||||
op[1]->value.f[0] * op[0]->value.f[1]);
|
||||
} else if (strcmp(callee, "degrees") == 0) {
|
||||
assert(op[0]->type->is_float());
|
||||
for (unsigned c = 0; c < op[0]->type->components(); c++)
|
||||
data.f[c] = 180.0F / M_PI * op[0]->value.f[c];
|
||||
} else if (strcmp(callee, "distance") == 0) {
|
||||
assert(op[0]->type->is_float() && op[1]->type->is_float());
|
||||
float length_squared = 0.0;
|
||||
for (unsigned c = 0; c < op[0]->type->components(); c++) {
|
||||
float t = op[0]->value.f[c] - op[1]->value.f[c];
|
||||
length_squared += t * t;
|
||||
}
|
||||
return new(mem_ctx) ir_constant(sqrtf(length_squared));
|
||||
} else if (strcmp(callee, "dot") == 0) {
|
||||
return new(mem_ctx) ir_constant(dot(op[0], op[1]));
|
||||
} else if (strcmp(callee, "equal") == 0) {
|
||||
assert(op[0]->type->is_vector() && op[1] && op[1]->type->is_vector());
|
||||
for (unsigned c = 0; c < op[0]->type->components(); c++) {
|
||||
switch (op[0]->type->base_type) {
|
||||
case GLSL_TYPE_UINT:
|
||||
data.b[c] = op[0]->value.u[c] == op[1]->value.u[c];
|
||||
break;
|
||||
case GLSL_TYPE_INT:
|
||||
data.b[c] = op[0]->value.i[c] == op[1]->value.i[c];
|
||||
break;
|
||||
case GLSL_TYPE_FLOAT:
|
||||
data.b[c] = op[0]->value.f[c] == op[1]->value.f[c];
|
||||
break;
|
||||
case GLSL_TYPE_BOOL:
|
||||
data.b[c] = op[0]->value.b[c] == op[1]->value.b[c];
|
||||
break;
|
||||
default:
|
||||
assert(!"Should not get here.");
|
||||
}
|
||||
}
|
||||
} else if (strcmp(callee, "exp") == 0) {
|
||||
expr = new(mem_ctx) ir_expression(ir_unop_exp, type, op[0], NULL);
|
||||
} else if (strcmp(callee, "exp2") == 0) {
|
||||
expr = new(mem_ctx) ir_expression(ir_unop_exp2, type, op[0], NULL);
|
||||
} else if (strcmp(callee, "faceforward") == 0) {
|
||||
if (dot(op[2], op[1]) < 0)
|
||||
return op[0];
|
||||
for (unsigned c = 0; c < op[0]->type->components(); c++)
|
||||
data.f[c] = -op[0]->value.f[c];
|
||||
} else if (strcmp(callee, "floor") == 0) {
|
||||
expr = new(mem_ctx) ir_expression(ir_unop_floor, type, op[0], NULL);
|
||||
} else if (strcmp(callee, "fract") == 0) {
|
||||
expr = new(mem_ctx) ir_expression(ir_unop_fract, type, op[0], NULL);
|
||||
} else if (strcmp(callee, "fwidth") == 0) {
|
||||
return ir_constant::zero(mem_ctx, type);
|
||||
} else if (strcmp(callee, "greaterThan") == 0) {
|
||||
assert(op[0]->type->is_vector() && op[1] && op[1]->type->is_vector());
|
||||
for (unsigned c = 0; c < op[0]->type->components(); c++) {
|
||||
switch (op[0]->type->base_type) {
|
||||
case GLSL_TYPE_UINT:
|
||||
data.b[c] = op[0]->value.u[c] > op[1]->value.u[c];
|
||||
break;
|
||||
case GLSL_TYPE_INT:
|
||||
data.b[c] = op[0]->value.i[c] > op[1]->value.i[c];
|
||||
break;
|
||||
case GLSL_TYPE_FLOAT:
|
||||
data.b[c] = op[0]->value.f[c] > op[1]->value.f[c];
|
||||
break;
|
||||
default:
|
||||
assert(!"Should not get here.");
|
||||
}
|
||||
}
|
||||
} else if (strcmp(callee, "greaterThanEqual") == 0) {
|
||||
assert(op[0]->type->is_vector() && op[1] && op[1]->type->is_vector());
|
||||
for (unsigned c = 0; c < op[0]->type->components(); c++) {
|
||||
switch (op[0]->type->base_type) {
|
||||
case GLSL_TYPE_UINT:
|
||||
data.b[c] = op[0]->value.u[c] >= op[1]->value.u[c];
|
||||
break;
|
||||
case GLSL_TYPE_INT:
|
||||
data.b[c] = op[0]->value.i[c] >= op[1]->value.i[c];
|
||||
break;
|
||||
case GLSL_TYPE_FLOAT:
|
||||
data.b[c] = op[0]->value.f[c] >= op[1]->value.f[c];
|
||||
break;
|
||||
default:
|
||||
assert(!"Should not get here.");
|
||||
}
|
||||
}
|
||||
} else if (strcmp(callee, "inversesqrt") == 0) {
|
||||
expr = new(mem_ctx) ir_expression(ir_unop_rsq, type, op[0], NULL);
|
||||
} else if (strcmp(callee, "length") == 0) {
|
||||
return new(mem_ctx) ir_constant(sqrtf(dot(op[0], op[0])));
|
||||
} else if (strcmp(callee, "lessThan") == 0) {
|
||||
assert(op[0]->type->is_vector() && op[1] && op[1]->type->is_vector());
|
||||
for (unsigned c = 0; c < op[0]->type->components(); c++) {
|
||||
switch (op[0]->type->base_type) {
|
||||
case GLSL_TYPE_UINT:
|
||||
data.b[c] = op[0]->value.u[c] < op[1]->value.u[c];
|
||||
break;
|
||||
case GLSL_TYPE_INT:
|
||||
data.b[c] = op[0]->value.i[c] < op[1]->value.i[c];
|
||||
break;
|
||||
case GLSL_TYPE_FLOAT:
|
||||
data.b[c] = op[0]->value.f[c] < op[1]->value.f[c];
|
||||
break;
|
||||
default:
|
||||
assert(!"Should not get here.");
|
||||
}
|
||||
}
|
||||
} else if (strcmp(callee, "lessThanEqual") == 0) {
|
||||
assert(op[0]->type->is_vector() && op[1] && op[1]->type->is_vector());
|
||||
for (unsigned c = 0; c < op[0]->type->components(); c++) {
|
||||
switch (op[0]->type->base_type) {
|
||||
case GLSL_TYPE_UINT:
|
||||
data.b[c] = op[0]->value.u[c] <= op[1]->value.u[c];
|
||||
break;
|
||||
case GLSL_TYPE_INT:
|
||||
data.b[c] = op[0]->value.i[c] <= op[1]->value.i[c];
|
||||
break;
|
||||
case GLSL_TYPE_FLOAT:
|
||||
data.b[c] = op[0]->value.f[c] <= op[1]->value.f[c];
|
||||
break;
|
||||
default:
|
||||
assert(!"Should not get here.");
|
||||
}
|
||||
}
|
||||
} else if (strcmp(callee, "log") == 0) {
|
||||
expr = new(mem_ctx) ir_expression(ir_unop_log, type, op[0], NULL);
|
||||
} else if (strcmp(callee, "log2") == 0) {
|
||||
expr = new(mem_ctx) ir_expression(ir_unop_log2, type, op[0], NULL);
|
||||
} else if (strcmp(callee, "matrixCompMult") == 0) {
|
||||
assert(op[0]->type->is_float() && op[1]->type->is_float());
|
||||
for (unsigned c = 0; c < op[0]->type->components(); c++)
|
||||
data.f[c] = op[0]->value.f[c] * op[1]->value.f[c];
|
||||
} else if (strcmp(callee, "max") == 0) {
|
||||
expr = new(mem_ctx) ir_expression(ir_binop_max, type, op[0], op[1]);
|
||||
} else if (strcmp(callee, "min") == 0) {
|
||||
expr = new(mem_ctx) ir_expression(ir_binop_min, type, op[0], op[1]);
|
||||
} else if (strcmp(callee, "mix") == 0) {
|
||||
assert(op[0]->type->is_float() && op[1]->type->is_float());
|
||||
if (op[2]->type->is_float()) {
|
||||
unsigned c2_inc = op[2]->type->is_scalar() ? 0 : 1;
|
||||
unsigned components = op[0]->type->components();
|
||||
for (unsigned c = 0, c2 = 0; c < components; c2 += c2_inc, c++) {
|
||||
data.f[c] = op[0]->value.f[c] * (1 - op[2]->value.f[c2]) +
|
||||
op[1]->value.f[c] * op[2]->value.f[c2];
|
||||
}
|
||||
} else {
|
||||
assert(op[2]->type->is_boolean());
|
||||
for (unsigned c = 0; c < op[0]->type->components(); c++)
|
||||
data.f[c] = op[op[2]->value.b[c] ? 1 : 0]->value.f[c];
|
||||
}
|
||||
} else if (strcmp(callee, "mod") == 0) {
|
||||
expr = new(mem_ctx) ir_expression(ir_binop_mod, type, op[0], op[1]);
|
||||
} else if (strcmp(callee, "normalize") == 0) {
|
||||
assert(op[0]->type->is_float());
|
||||
float length = sqrtf(dot(op[0], op[0]));
|
||||
|
||||
if (length == 0)
|
||||
return ir_constant::zero(mem_ctx, type);
|
||||
|
||||
for (unsigned c = 0; c < op[0]->type->components(); c++)
|
||||
data.f[c] = op[0]->value.f[c] / length;
|
||||
} else if (strcmp(callee, "not") == 0) {
|
||||
expr = new(mem_ctx) ir_expression(ir_unop_logic_not, type, op[0], NULL);
|
||||
} else if (strcmp(callee, "notEqual") == 0) {
|
||||
assert(op[0]->type->is_vector() && op[1] && op[1]->type->is_vector());
|
||||
for (unsigned c = 0; c < op[0]->type->components(); c++) {
|
||||
switch (op[0]->type->base_type) {
|
||||
case GLSL_TYPE_UINT:
|
||||
data.b[c] = op[0]->value.u[c] != op[1]->value.u[c];
|
||||
break;
|
||||
case GLSL_TYPE_INT:
|
||||
data.b[c] = op[0]->value.i[c] != op[1]->value.i[c];
|
||||
break;
|
||||
case GLSL_TYPE_FLOAT:
|
||||
data.b[c] = op[0]->value.f[c] != op[1]->value.f[c];
|
||||
break;
|
||||
case GLSL_TYPE_BOOL:
|
||||
data.b[c] = op[0]->value.b[c] != op[1]->value.b[c];
|
||||
break;
|
||||
default:
|
||||
assert(!"Should not get here.");
|
||||
}
|
||||
}
|
||||
} else if (strcmp(callee, "outerProduct") == 0) {
|
||||
assert(op[0]->type->is_vector() && op[1]->type->is_vector());
|
||||
const unsigned m = op[0]->type->vector_elements;
|
||||
const unsigned n = op[1]->type->vector_elements;
|
||||
for (unsigned j = 0; j < n; j++) {
|
||||
for (unsigned i = 0; i < m; i++) {
|
||||
data.f[i+m*j] = op[0]->value.f[i] * op[1]->value.f[j];
|
||||
}
|
||||
}
|
||||
} else if (strcmp(callee, "pow") == 0) {
|
||||
expr = new(mem_ctx) ir_expression(ir_binop_pow, type, op[0], op[1]);
|
||||
} else if (strcmp(callee, "radians") == 0) {
|
||||
assert(op[0]->type->is_float());
|
||||
for (unsigned c = 0; c < op[0]->type->components(); c++)
|
||||
data.f[c] = M_PI / 180.0F * op[0]->value.f[c];
|
||||
} else if (strcmp(callee, "reflect") == 0) {
|
||||
assert(op[0]->type->is_float());
|
||||
float dot_NI = dot(op[1], op[0]);
|
||||
for (unsigned c = 0; c < op[0]->type->components(); c++)
|
||||
data.f[c] = op[0]->value.f[c] - 2 * dot_NI * op[1]->value.f[c];
|
||||
} else if (strcmp(callee, "refract") == 0) {
|
||||
const float eta = op[2]->value.f[0];
|
||||
const float dot_NI = dot(op[1], op[0]);
|
||||
const float k = 1.0F - eta * eta * (1.0F - dot_NI * dot_NI);
|
||||
if (k < 0.0) {
|
||||
return ir_constant::zero(mem_ctx, type);
|
||||
} else {
|
||||
for (unsigned c = 0; c < type->components(); c++) {
|
||||
data.f[c] = eta * op[0]->value.f[c] - (eta * dot_NI + sqrtf(k))
|
||||
* op[1]->value.f[c];
|
||||
}
|
||||
}
|
||||
} else if (strcmp(callee, "round") == 0 ||
|
||||
strcmp(callee, "roundEven") == 0) {
|
||||
expr = new(mem_ctx) ir_expression(ir_unop_round_even, op[0]);
|
||||
} else if (strcmp(callee, "sign") == 0) {
|
||||
expr = new(mem_ctx) ir_expression(ir_unop_sign, type, op[0], NULL);
|
||||
} else if (strcmp(callee, "sin") == 0) {
|
||||
expr = new(mem_ctx) ir_expression(ir_unop_sin, type, op[0], NULL);
|
||||
} else if (strcmp(callee, "sinh") == 0) {
|
||||
assert(op[0]->type->is_float());
|
||||
for (unsigned c = 0; c < op[0]->type->components(); c++)
|
||||
data.f[c] = sinhf(op[0]->value.f[c]);
|
||||
} else if (strcmp(callee, "smoothstep") == 0) {
|
||||
assert(num_parameters == 3);
|
||||
assert(op[1]->type == op[0]->type);
|
||||
unsigned edge_inc = op[0]->type->is_scalar() ? 0 : 1;
|
||||
for (unsigned c = 0, e = 0; c < type->components(); e += edge_inc, c++) {
|
||||
const float edge0 = op[0]->value.f[e];
|
||||
const float edge1 = op[1]->value.f[e];
|
||||
if (edge0 == edge1) {
|
||||
data.f[c] = 0.0; /* Avoid a crash - results are undefined anyway */
|
||||
} else {
|
||||
const float numerator = op[2]->value.f[c] - edge0;
|
||||
const float denominator = edge1 - edge0;
|
||||
const float t = CLAMP(numerator/denominator, 0, 1);
|
||||
data.f[c] = t * t * (3 - 2 * t);
|
||||
}
|
||||
}
|
||||
} else if (strcmp(callee, "sqrt") == 0) {
|
||||
expr = new(mem_ctx) ir_expression(ir_unop_sqrt, type, op[0], NULL);
|
||||
} else if (strcmp(callee, "step") == 0) {
|
||||
assert(op[0]->type->is_float() && op[1]->type->is_float());
|
||||
/* op[0] (edge) may be either a scalar or a vector */
|
||||
const unsigned c0_inc = op[0]->type->is_scalar() ? 0 : 1;
|
||||
for (unsigned c = 0, c0 = 0; c < type->components(); c0 += c0_inc, c++)
|
||||
data.f[c] = (op[1]->value.f[c] < op[0]->value.f[c0]) ? 0.0F : 1.0F;
|
||||
} else if (strcmp(callee, "tan") == 0) {
|
||||
assert(op[0]->type->is_float());
|
||||
for (unsigned c = 0; c < op[0]->type->components(); c++)
|
||||
data.f[c] = tanf(op[0]->value.f[c]);
|
||||
} else if (strcmp(callee, "tanh") == 0) {
|
||||
assert(op[0]->type->is_float());
|
||||
for (unsigned c = 0; c < op[0]->type->components(); c++)
|
||||
data.f[c] = tanhf(op[0]->value.f[c]);
|
||||
} else if (strcmp(callee, "transpose") == 0) {
|
||||
assert(op[0]->type->is_matrix());
|
||||
const unsigned n = op[0]->type->vector_elements;
|
||||
const unsigned m = op[0]->type->matrix_columns;
|
||||
for (unsigned j = 0; j < m; j++) {
|
||||
for (unsigned i = 0; i < n; i++) {
|
||||
data.f[m*i+j] += op[0]->value.f[i+n*j];
|
||||
}
|
||||
}
|
||||
} else if (strcmp(callee, "trunc") == 0) {
|
||||
expr = new(mem_ctx) ir_expression(ir_unop_trunc, op[0]);
|
||||
} else {
|
||||
/* Unsupported builtin - some are not allowed in constant expressions. */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (expr != NULL)
|
||||
return expr->constant_expression_value();
|
||||
|
||||
return new(mem_ctx) ir_constant(type, &data);
|
||||
return result;
|
||||
}
|
||||
|
Reference in New Issue
Block a user