summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEric Anholt <eric@anholt.net>2010-08-28 23:31:09 -0700
committerEric Anholt <eric@anholt.net>2010-08-30 10:26:05 -0700
commit1fcb5a9858b7513c5130006933edc224b69be82d (patch)
tree607f57f4d475aea94b06dc3cfda2595be6c44971 /src
parent352dff62f8005add9e71e6b5ba3b3321cb953d73 (diff)
i965: Add support for loops to the new FS backend.
This includes a handy little safety check to prevent the loop from going "too long", as permitted by the spec. I haven't gone out of my way to test it, though… Fixes 20 more piglit tests.
Diffstat (limited to 'src')
-rw-r--r--src/mesa/drivers/dri/i965/brw_fs.cpp86
1 files changed, 82 insertions, 4 deletions
diff --git a/src/mesa/drivers/dri/i965/brw_fs.cpp b/src/mesa/drivers/dri/i965/brw_fs.cpp
index fd65ab2fa7..34c5d5262f 100644
--- a/src/mesa/drivers/dri/i965/brw_fs.cpp
+++ b/src/mesa/drivers/dri/i965/brw_fs.cpp
@@ -1071,13 +1071,48 @@ fs_visitor::visit(ir_if *ir)
void
fs_visitor::visit(ir_loop *ir)
{
- assert(!"FINISHME");
+ assert(!ir->from);
+ assert(!ir->to);
+ assert(!ir->increment);
+ assert(!ir->counter);
+
+ emit(fs_inst(BRW_OPCODE_DO));
+
+ /* Start a safety counter. If the user messed up their loop
+ * counting, we don't want to hang the GPU.
+ */
+ fs_reg max_iter = fs_reg(this, glsl_type::int_type);
+ emit(fs_inst(BRW_OPCODE_MOV, max_iter, fs_reg(10000)));
+
+ foreach_iter(exec_list_iterator, iter, ir->body_instructions) {
+ ir_instruction *ir = (ir_instruction *)iter.get();
+ fs_inst *inst;
+
+ this->base_ir = ir;
+ ir->accept(this);
+
+ /* Check the maximum loop iters counter. */
+ inst = emit(fs_inst(BRW_OPCODE_ADD, max_iter, max_iter, fs_reg(-1)));
+ inst->conditional_mod = BRW_CONDITIONAL_Z;
+
+ inst = emit(fs_inst(BRW_OPCODE_BREAK));
+ inst->predicated = true;
+ }
+
+ emit(fs_inst(BRW_OPCODE_WHILE));
}
void
fs_visitor::visit(ir_loop_jump *ir)
{
- assert(!"FINISHME");
+ switch (ir->mode) {
+ case ir_loop_jump::jump_break:
+ emit(fs_inst(BRW_OPCODE_BREAK));
+ break;
+ case ir_loop_jump::jump_continue:
+ emit(fs_inst(BRW_OPCODE_CONTINUE));
+ break;
+ }
}
void
@@ -1624,8 +1659,11 @@ fs_visitor::generate_code()
{
unsigned int annotation_len = 0;
int last_native_inst = 0;
- struct brw_instruction *if_stack[16];
- int if_stack_depth = 0;
+ struct brw_instruction *if_stack[16], *loop_stack[16];
+ int if_stack_depth = 0, loop_stack_depth = 0;
+ int if_depth_in_loop[16];
+
+ if_depth_in_loop[loop_stack_depth] = 0;
memset(&if_stack, 0, sizeof(if_stack));
foreach_iter(exec_list_iterator, iter, this->instructions) {
@@ -1691,6 +1729,46 @@ fs_visitor::generate_code()
if_stack_depth--;
brw_ENDIF(p , if_stack[if_stack_depth]);
break;
+
+ case BRW_OPCODE_DO:
+ loop_stack[loop_stack_depth++] = brw_DO(p, BRW_EXECUTE_8);
+ if_depth_in_loop[loop_stack_depth] = 0;
+ break;
+
+ case BRW_OPCODE_BREAK:
+ brw_BREAK(p, if_depth_in_loop[loop_stack_depth]);
+ brw_set_predicate_control(p, BRW_PREDICATE_NONE);
+ break;
+ case BRW_OPCODE_CONTINUE:
+ brw_CONT(p, if_depth_in_loop[loop_stack_depth]);
+ brw_set_predicate_control(p, BRW_PREDICATE_NONE);
+ break;
+
+ case BRW_OPCODE_WHILE: {
+ struct brw_instruction *inst0, *inst1;
+ GLuint br = 1;
+
+ if (intel->gen == 5)
+ br = 2;
+
+ assert(loop_stack_depth > 0);
+ loop_stack_depth--;
+ inst0 = inst1 = brw_WHILE(p, loop_stack[loop_stack_depth]);
+ /* patch all the BREAK/CONT instructions from last BGNLOOP */
+ while (inst0 > loop_stack[loop_stack_depth]) {
+ inst0--;
+ if (inst0->header.opcode == BRW_OPCODE_BREAK &&
+ inst0->bits3.if_else.jump_count == 0) {
+ inst0->bits3.if_else.jump_count = br * (inst1 - inst0 + 1);
+ }
+ else if (inst0->header.opcode == BRW_OPCODE_CONTINUE &&
+ inst0->bits3.if_else.jump_count == 0) {
+ inst0->bits3.if_else.jump_count = br * (inst1 - inst0);
+ }
+ }
+ }
+ break;
+
case FS_OPCODE_RCP:
case FS_OPCODE_RSQ:
case FS_OPCODE_SQRT: