summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorEric Anholt <eric@anholt.net>2010-11-30 11:23:28 -0800
committerEric Anholt <eric@anholt.net>2010-11-30 11:42:42 -0800
commitff79633d9f930e396933a0ad9564824ec73ea4dc (patch)
treedfb739086ec04a08b8c4fedcb9dd12a666951bfc /src
parent6b937465d4aeab72fabcfe5250d477cf6790a521 (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')
-rw-r--r--src/glsl/ast_to_hir.cpp72
1 files changed, 70 insertions, 2 deletions
diff --git a/src/glsl/ast_to_hir.cpp b/src/glsl/ast_to_hir.cpp
index fd9ed556806..0978100acd9 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);