diff options
author | Eric Anholt <eric@anholt.net> | 2010-11-30 11:23:28 -0800 |
---|---|---|
committer | Eric Anholt <eric@anholt.net> | 2010-11-30 11:42:42 -0800 |
commit | ff79633d9f930e396933a0ad9564824ec73ea4dc (patch) | |
tree | dfb739086ec04a08b8c4fedcb9dd12a666951bfc /src/glsl | |
parent | 6b937465d4aeab72fabcfe5250d477cf6790a521 (diff) |
glsl: Fix structure and array comparisions.
We were trying to emit a single ir_expression to compare the whole
thing. The backends (ir_to_mesa.cpp and brw_fs.cpp so far) expected
ir_binop_any_nequal or ir_binop_all_equal to apply to at most a vector
(with matrices broken down by the lowering pass). Break them down to
a bunch of ORed or ANDed any_nequals/all_equals.
Fixes:
glsl-array-compare
glsl-array-compare-02
glsl-fs-struct-equal
glsl-fs-struct-notequal
Bug #31909
Diffstat (limited to 'src/glsl')
-rw-r--r-- | src/glsl/ast_to_hir.cpp | 72 |
1 files changed, 70 insertions, 2 deletions
diff --git a/src/glsl/ast_to_hir.cpp b/src/glsl/ast_to_hir.cpp index fd9ed55680..0978100acd 100644 --- a/src/glsl/ast_to_hir.cpp +++ b/src/glsl/ast_to_hir.cpp @@ -745,6 +745,75 @@ ast_node::hir(exec_list *instructions, return NULL; } +static ir_rvalue * +do_comparison(void *mem_ctx, int operation, ir_rvalue *op0, ir_rvalue *op1) +{ + int join_op; + + if (operation == ir_binop_all_equal) + join_op = ir_binop_logic_and; + else + join_op = ir_binop_logic_or; + + switch (op0->type->base_type) { + case GLSL_TYPE_FLOAT: + case GLSL_TYPE_UINT: + case GLSL_TYPE_INT: + case GLSL_TYPE_BOOL: + return new(mem_ctx) ir_expression(operation, op0, op1); + + case GLSL_TYPE_ARRAY: { + ir_rvalue *last = NULL; + + for (unsigned int i = 0; i < op0->type->length; i++) { + ir_rvalue *e0, *e1, *result; + + e0 = new(mem_ctx) ir_dereference_array(op0->clone(mem_ctx, NULL), + new(mem_ctx) ir_constant(i)); + e1 = new(mem_ctx) ir_dereference_array(op1->clone(mem_ctx, NULL), + new(mem_ctx) ir_constant(i)); + result = do_comparison(mem_ctx, operation, e0, e1); + + if (last) { + last = new(mem_ctx) ir_expression(join_op, last, result); + } else { + last = result; + } + } + return last; + } + + case GLSL_TYPE_STRUCT: { + ir_rvalue *last = NULL; + + for (unsigned int i = 0; i < op0->type->length; i++) { + ir_rvalue *e0, *e1, *result; + const char *field_name = op0->type->fields.structure[i].name; + + e0 = new(mem_ctx) ir_dereference_record(op0->clone(mem_ctx, NULL), + field_name); + e1 = new(mem_ctx) ir_dereference_record(op1->clone(mem_ctx, NULL), + field_name); + result = do_comparison(mem_ctx, operation, e0, e1); + + if (last) { + last = new(mem_ctx) ir_expression(join_op, last, result); + } else { + last = result; + } + } + return last; + } + + case GLSL_TYPE_ERROR: + case GLSL_TYPE_VOID: + case GLSL_TYPE_SAMPLER: + /* I assume a comparison of a struct containing a sampler just + * ignores the sampler present in the type. + */ + return new(mem_ctx) ir_constant(true); + } +} ir_rvalue * ast_expression::hir(exec_list *instructions, @@ -941,8 +1010,7 @@ ast_expression::hir(exec_list *instructions, error_emitted = true; } - result = new(ctx) ir_expression(operations[this->oper], glsl_type::bool_type, - op[0], op[1]); + result = do_comparison(ctx, operations[this->oper], op[0], op[1]); type = glsl_type::bool_type; assert(result->type == glsl_type::bool_type); |