diff options
author | Eric Anholt <[email protected]> | 2010-08-28 23:31:09 -0700 |
---|---|---|
committer | Eric Anholt <[email protected]> | 2010-08-30 10:26:05 -0700 |
commit | 1fcb5a9858b7513c5130006933edc224b69be82d (patch) | |
tree | 607f57f4d475aea94b06dc3cfda2595be6c44971 /src | |
parent | 352dff62f8005add9e71e6b5ba3b3321cb953d73 (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.cpp | 86 |
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 fd65ab2fa77..34c5d5262fb 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: |