diff options
Diffstat (limited to 'src/gallium/drivers/r600')
-rw-r--r-- | src/gallium/drivers/r600/Makefile | 1 | ||||
-rw-r--r-- | src/gallium/drivers/r600/eg_asm.c | 27 | ||||
-rw-r--r-- | src/gallium/drivers/r600/r600_asm.c | 1147 | ||||
-rw-r--r-- | src/gallium/drivers/r600/r600_asm.h | 5 | ||||
-rw-r--r-- | src/gallium/drivers/r600/r600_pipe.c | 2 | ||||
-rw-r--r-- | src/gallium/drivers/r600/r600_shader.c | 20 | ||||
-rw-r--r-- | src/gallium/drivers/r600/r600_state.c | 11 | ||||
-rw-r--r-- | src/gallium/drivers/r600/r600_state_inlines.h | 16 | ||||
-rw-r--r-- | src/gallium/drivers/r600/r600_texture.c | 96 | ||||
-rw-r--r-- | src/gallium/drivers/r600/r600_video_context.c | 21 | ||||
-rw-r--r-- | src/gallium/drivers/r600/r600_video_context.h | 11 |
11 files changed, 1121 insertions, 236 deletions
diff --git a/src/gallium/drivers/r600/Makefile b/src/gallium/drivers/r600/Makefile index b476b9af3b8..a690b671e49 100644 --- a/src/gallium/drivers/r600/Makefile +++ b/src/gallium/drivers/r600/Makefile @@ -17,6 +17,7 @@ C_SOURCES = \ r600_shader.c \ r600_state.c \ r600_texture.c \ + r600_video_context.c \ r700_asm.c \ evergreen_state.c \ eg_asm.c \ diff --git a/src/gallium/drivers/r600/eg_asm.c b/src/gallium/drivers/r600/eg_asm.c index 67d742b3760..4f86e3b4c38 100644 --- a/src/gallium/drivers/r600/eg_asm.c +++ b/src/gallium/drivers/r600/eg_asm.c @@ -32,12 +32,14 @@ int eg_bc_cf_build(struct r600_bc *bc, struct r600_bc_cf *cf) { unsigned id = cf->id; + unsigned end_of_program = bc->cf.prev == &cf->list; switch (cf->inst) { case (EG_V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU << 3): case (EG_V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_POP_AFTER << 3): case (EG_V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_POP2_AFTER << 3): case (EG_V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_PUSH_BEFORE << 3): + assert(!end_of_program); bc->bytecode[id++] = S_SQ_CF_ALU_WORD0_ADDR(cf->addr >> 1) | S_SQ_CF_ALU_WORD0_KCACHE_MODE0(cf->kcache[0].mode) | S_SQ_CF_ALU_WORD0_KCACHE_BANK0(cf->kcache[0].bank) | @@ -46,15 +48,16 @@ int eg_bc_cf_build(struct r600_bc *bc, struct r600_bc_cf *cf) S_SQ_CF_ALU_WORD1_KCACHE_MODE1(cf->kcache[1].mode) | S_SQ_CF_ALU_WORD1_KCACHE_ADDR0(cf->kcache[0].addr) | S_SQ_CF_ALU_WORD1_KCACHE_ADDR1(cf->kcache[1].addr) | - S_SQ_CF_ALU_WORD1_BARRIER(1) | - S_SQ_CF_ALU_WORD1_COUNT((cf->ndw / 2) - 1); + S_SQ_CF_ALU_WORD1_BARRIER(cf->barrier) | + S_SQ_CF_ALU_WORD1_COUNT((cf->ndw / 2) - 1); break; case EG_V_SQ_CF_WORD1_SQ_CF_INST_TEX: case EG_V_SQ_CF_WORD1_SQ_CF_INST_VTX: bc->bytecode[id++] = S_SQ_CF_WORD0_ADDR(cf->addr >> 1); bc->bytecode[id++] = S_SQ_CF_WORD1_CF_INST(cf->inst) | - S_SQ_CF_WORD1_BARRIER(1) | - S_SQ_CF_WORD1_COUNT((cf->ndw / 4) - 1); + S_SQ_CF_WORD1_BARRIER(cf->barrier) | + S_SQ_CF_WORD1_COUNT((cf->ndw / 4) - 1) | + S_SQ_CF_WORD1_END_OF_PROGRAM(end_of_program); break; case EG_V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT: case EG_V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT_DONE: @@ -62,13 +65,14 @@ int eg_bc_cf_build(struct r600_bc *bc, struct r600_bc_cf *cf) S_SQ_CF_ALLOC_EXPORT_WORD0_ELEM_SIZE(cf->output.elem_size) | S_SQ_CF_ALLOC_EXPORT_WORD0_ARRAY_BASE(cf->output.array_base) | S_SQ_CF_ALLOC_EXPORT_WORD0_TYPE(cf->output.type); - bc->bytecode[id++] = S_SQ_CF_ALLOC_EXPORT_WORD1_SWIZ_SEL_X(cf->output.swizzle_x) | + bc->bytecode[id++] = S_SQ_CF_ALLOC_EXPORT_WORD1_BURST_COUNT(cf->output.burst_count - 1) | + S_SQ_CF_ALLOC_EXPORT_WORD1_SWIZ_SEL_X(cf->output.swizzle_x) | S_SQ_CF_ALLOC_EXPORT_WORD1_SWIZ_SEL_Y(cf->output.swizzle_y) | S_SQ_CF_ALLOC_EXPORT_WORD1_SWIZ_SEL_Z(cf->output.swizzle_z) | S_SQ_CF_ALLOC_EXPORT_WORD1_SWIZ_SEL_W(cf->output.swizzle_w) | - S_SQ_CF_ALLOC_EXPORT_WORD1_BARRIER(cf->output.barrier) | - S_SQ_CF_ALLOC_EXPORT_WORD1_CF_INST(cf->output.inst) | - S_SQ_CF_ALLOC_EXPORT_WORD1_END_OF_PROGRAM(cf->output.end_of_program); + S_SQ_CF_ALLOC_EXPORT_WORD1_BARRIER(cf->barrier) | + S_SQ_CF_ALLOC_EXPORT_WORD1_CF_INST(cf->inst) | + S_SQ_CF_ALLOC_EXPORT_WORD1_END_OF_PROGRAM(end_of_program); break; case EG_V_SQ_CF_WORD1_SQ_CF_INST_JUMP: case EG_V_SQ_CF_WORD1_SQ_CF_INST_ELSE: @@ -81,9 +85,10 @@ int eg_bc_cf_build(struct r600_bc *bc, struct r600_bc_cf *cf) case EG_V_SQ_CF_WORD1_SQ_CF_INST_RETURN: bc->bytecode[id++] = S_SQ_CF_WORD0_ADDR(cf->cf_addr >> 1); bc->bytecode[id++] = S_SQ_CF_WORD1_CF_INST(cf->inst) | - S_SQ_CF_WORD1_BARRIER(1) | - S_SQ_CF_WORD1_COND(cf->cond) | - S_SQ_CF_WORD1_POP_COUNT(cf->pop_count); + S_SQ_CF_WORD1_BARRIER(cf->barrier) | + S_SQ_CF_WORD1_COND(cf->cond) | + S_SQ_CF_WORD1_POP_COUNT(cf->pop_count) | + S_SQ_CF_WORD1_END_OF_PROGRAM(end_of_program); break; default: diff --git a/src/gallium/drivers/r600/r600_asm.c b/src/gallium/drivers/r600/r600_asm.c index a473fb29c4d..61de24b31ae 100644 --- a/src/gallium/drivers/r600/r600_asm.c +++ b/src/gallium/drivers/r600/r600_asm.c @@ -35,6 +35,9 @@ #define NUM_OF_CYCLES 3 #define NUM_OF_COMPONENTS 4 +#define PREV_ALU(alu) LIST_ENTRY(struct r600_bc_alu, alu->list.prev, list) +#define NEXT_ALU(alu) LIST_ENTRY(struct r600_bc_alu, alu->list.next, list) + static inline unsigned int r600_bc_get_num_operands(struct r600_bc *bc, struct r600_bc_alu *alu) { if(alu->is_op3) @@ -154,6 +157,7 @@ static struct r600_bc_cf *r600_bc_cf(void) LIST_INITHEAD(&cf->alu); LIST_INITHEAD(&cf->vtx); LIST_INITHEAD(&cf->tex); + cf->barrier = 1; return cf; } @@ -242,6 +246,44 @@ static int r600_bc_add_cf(struct r600_bc *bc) return 0; } +static void r600_bc_remove_cf(struct r600_bc *bc, struct r600_bc_cf *cf) +{ + struct r600_bc_cf *other; + LIST_FOR_EACH_ENTRY(other, &bc->cf, list) { + if (other->id > cf->id) + other->id -= 2; + if (other->cf_addr > cf->id) + other->cf_addr -= 2; + } + LIST_DEL(&cf->list); + free(cf); +} + +static void r600_bc_move_cf(struct r600_bc *bc, struct r600_bc_cf *cf, struct r600_bc_cf *next) +{ + struct r600_bc_cf *prev = LIST_ENTRY(struct r600_bc_cf, next->list.prev, list); + unsigned old_id = cf->id; + unsigned new_id = prev->id + 2; + struct r600_bc_cf *other; + + if (prev == cf) + return; /* position hasn't changed */ + + LIST_DEL(&cf->list); + LIST_FOR_EACH_ENTRY(other, &bc->cf, list) { + if (other->id > old_id) + other->id -= 2; + if (other->id >= new_id) + other->id += 2; + if (other->cf_addr > old_id) + other->cf_addr -= 2; + if (other->cf_addr > new_id) + other->cf_addr += 2; + } + cf->id = new_id; + LIST_ADD(&cf->list, &prev->list); +} + int r600_bc_add_output(struct r600_bc *bc, const struct r600_bc_output *output) { int r; @@ -249,28 +291,19 @@ int r600_bc_add_output(struct r600_bc *bc, const struct r600_bc_output *output) r = r600_bc_add_cf(bc); if (r) return r; - bc->cf_last->inst = output->inst; + bc->cf_last->inst = BC_INST(bc, V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT); memcpy(&bc->cf_last->output, output, sizeof(struct r600_bc_output)); + bc->cf_last->output.burst_count = 1; return 0; } -/* alu instructions that can ony exits once per group */ -static int is_alu_once_inst(struct r600_bc *bc, struct r600_bc_alu *alu) +/* alu predicate instructions */ +static int is_alu_pred_inst(struct r600_bc *bc, struct r600_bc_alu *alu) { switch (bc->chiprev) { case CHIPREV_R600: case CHIPREV_R700: return !alu->is_op3 && ( - alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLE || - alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLGT || - alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLGE || - alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLNE || - alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLGT_UINT || - alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLGE_UINT || - alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLE_INT || - alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLGT_INT || - alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLGE_INT || - alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLNE_INT || alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETGT_UINT || alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETGE_UINT || alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETE || @@ -298,16 +331,6 @@ static int is_alu_once_inst(struct r600_bc *bc, struct r600_bc_alu *alu) case CHIPREV_EVERGREEN: default: return !alu->is_op3 && ( - alu->inst == EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLE || - alu->inst == EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLGT || - alu->inst == EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLGE || - alu->inst == EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLNE || - alu->inst == EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLGT_UINT || - alu->inst == EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLGE_UINT || - alu->inst == EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLE_INT || - alu->inst == EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLGT_INT || - alu->inst == EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLGE_INT || - alu->inst == EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLNE_INT || alu->inst == EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETGT_UINT || alu->inst == EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETGE_UINT || alu->inst == EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETE || @@ -335,6 +358,46 @@ static int is_alu_once_inst(struct r600_bc *bc, struct r600_bc_alu *alu) } } +/* alu kill instructions */ +static int is_alu_kill_inst(struct r600_bc *bc, struct r600_bc_alu *alu) +{ + switch (bc->chiprev) { + case CHIPREV_R600: + case CHIPREV_R700: + return !alu->is_op3 && ( + alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLE || + alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLGT || + alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLGE || + alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLNE || + alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLGT_UINT || + alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLGE_UINT || + alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLE_INT || + alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLGT_INT || + alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLGE_INT || + alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLNE_INT); + case CHIPREV_EVERGREEN: + default: + return !alu->is_op3 && ( + alu->inst == EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLE || + alu->inst == EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLGT || + alu->inst == EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLGE || + alu->inst == EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLNE || + alu->inst == EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLGT_UINT || + alu->inst == EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLGE_UINT || + alu->inst == EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLE_INT || + alu->inst == EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLGT_INT || + alu->inst == EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLGE_INT || + alu->inst == EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLNE_INT); + } +} + +/* alu instructions that can ony exits once per group */ +static int is_alu_once_inst(struct r600_bc *bc, struct r600_bc_alu *alu) +{ + return is_alu_kill_inst(bc, alu) || + is_alu_pred_inst(bc, alu); +} + static int is_alu_reduction_inst(struct r600_bc *bc, struct r600_bc_alu *alu) { switch (bc->chiprev) { @@ -527,7 +590,7 @@ static void init_bank_swizzle(struct alu_bank_swizzle *bs) for (i = 0; i < 4; i++) bs->hw_cfile_elem[i] = -1; } - + static int reserve_gpr(struct alu_bank_swizzle *bs, unsigned sel, unsigned chan, unsigned cycle) { if (bs->hw_gpr[cycle][chan] == -1) @@ -538,7 +601,7 @@ static int reserve_gpr(struct alu_bank_swizzle *bs, unsigned sel, unsigned chan, } return 0; } - + static int reserve_cfile(struct alu_bank_swizzle *bs, unsigned sel, unsigned chan) { int res, resmatch = -1, resempty = -1; @@ -558,9 +621,9 @@ static int reserve_cfile(struct alu_bank_swizzle *bs, unsigned sel, unsigned cha // All cfile read ports are used, cannot reference vector element return -1; } - return 0; + return 0; } - + static int is_gpr(unsigned sel) { return (sel >= 0 && sel <= 127); @@ -575,19 +638,19 @@ static int is_cfile(unsigned sel) (sel > 511 && sel < 4607) || // Kcache before translate (sel > 127 && sel < 192); // Kcache after translate } - + static int is_const(int sel) { return is_cfile(sel) || - (sel >= V_SQ_ALU_SRC_0 && + (sel >= V_SQ_ALU_SRC_0 && sel <= V_SQ_ALU_SRC_LITERAL); } - + static int check_vector(struct r600_bc *bc, struct r600_bc_alu *alu, struct alu_bank_swizzle *bs, int bank_swizzle) { int r, src, num_src, sel, elem, cycle; - + num_src = r600_bc_get_num_operands(bc, alu); for (src = 0; src < num_src; src++) { sel = alu->src[src].sel; @@ -595,7 +658,7 @@ static int check_vector(struct r600_bc *bc, struct r600_bc_alu *alu, if (is_gpr(sel)) { cycle = cycle_for_bank_swizzle_vec[bank_swizzle][src]; if (src == 1 && sel == alu->src[0].sel && elem == alu->src[0].chan) - // Nothing to do; special-case optimization, + // Nothing to do; special-case optimization, // second source uses first source’s reservation continue; else { @@ -612,12 +675,12 @@ static int check_vector(struct r600_bc *bc, struct r600_bc_alu *alu, } return 0; } - + static int check_scalar(struct r600_bc *bc, struct r600_bc_alu *alu, struct alu_bank_swizzle *bs, int bank_swizzle) { int r, src, num_src, const_count, sel, elem, cycle; - + num_src = r600_bc_get_num_operands(bc, alu); for (const_count = 0, src = 0; src < num_src; ++src) { sel = alu->src[src].sel; @@ -626,7 +689,7 @@ static int check_scalar(struct r600_bc *bc, struct r600_bc_alu *alu, if (const_count >= 2) // More than two references to a constant in // transcendental operation. - return -1; + return -1; else const_count++; } @@ -661,7 +724,7 @@ static int check_and_set_bank_swizzle(struct r600_bc *bc, struct alu_bank_swizzle bs; int bank_swizzle[5]; int i, r = 0, forced = 0; - + for (i = 0; i < 5; i++) if (slots[i] && slots[i]->bank_swizzle_force) { slots[i]->bank_swizzle = slots[i]->bank_swizzle_force; @@ -846,7 +909,7 @@ static int merge_inst_groups(struct r600_bc *bc, struct r600_bc_alu *slots[5], { struct r600_bc_alu *prev[5]; struct r600_bc_alu *result[5] = { NULL }; - + uint32_t literal[4], prev_literal[4]; unsigned nliteral = 0, prev_nliteral = 0; @@ -890,7 +953,7 @@ static int merge_inst_groups(struct r600_bc *bc, struct r600_bc_alu *slots[5], return 0; } else if(!slots[i]) { continue; - } else + } else result[i] = slots[i]; // let's check source gprs @@ -1115,19 +1178,21 @@ int r600_bc_add_alu_type(struct r600_bc *bc, const struct r600_bc_alu *alu, int if (!bc->cf_last->curr_bs_head) { bc->cf_last->curr_bs_head = nalu; } - /* number of gpr == the last gpr used in any alu */ + /* replace special constants */ for (i = 0; i < 3; i++) { - if (nalu->src[i].sel >= bc->ngpr && nalu->src[i].sel < 128) { - bc->ngpr = nalu->src[i].sel + 1; - } if (nalu->src[i].sel == V_SQ_ALU_SRC_LITERAL) r600_bc_special_constants( - nalu->src[i].value[nalu->src[i].chan], + nalu->src[i].value[nalu->src[i].chan], &nalu->src[i].sel, &nalu->src[i].neg); + + if (nalu->src[i].sel >= bc->ngpr && nalu->src[i].sel < 128) { + bc->ngpr = nalu->src[i].sel + 1; + } } if (nalu->dst.sel >= bc->ngpr) { bc->ngpr = nalu->dst.sel + 1; } + LIST_ADDTAIL(&nalu->list, &bc->cf_last->alu); /* each alu use 2 dwords */ bc->cf_last->ndw += 2; @@ -1185,6 +1250,16 @@ int r600_bc_add_alu(struct r600_bc *bc, const struct r600_bc_alu *alu) return r600_bc_add_alu_type(bc, alu, BC_INST(bc, V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU)); } +static void r600_bc_remove_alu(struct r600_bc_cf *cf, struct r600_bc_alu *alu) +{ + if (alu->last && alu->list.prev != &cf->alu) { + PREV_ALU(alu)->last = 1; + } + LIST_DEL(&alu->list); + free(alu); + cf->ndw -= 2; +} + int r600_bc_add_vtx(struct r600_bc *bc, const struct r600_bc_vtx *vtx) { struct r600_bc_vtx *nvtx = r600_bc_vtx(); @@ -1380,16 +1455,61 @@ static int r600_bc_alu_build(struct r600_bc *bc, struct r600_bc_alu *alu, unsign return 0; } -/* common for r600/r700 - eg in eg_asm.c */ -static int r600_bc_cf_build(struct r600_bc *bc, struct r600_bc_cf *cf) +enum cf_class { - unsigned id = cf->id; + CF_CLASS_ALU, + CF_CLASS_TEXTURE, + CF_CLASS_VERTEX, + CF_CLASS_EXPORT, + CF_CLASS_OTHER +}; +static enum cf_class get_cf_class(struct r600_bc_cf *cf) +{ switch (cf->inst) { case (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU << 3): - case (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_PUSH_BEFORE << 3): case (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_POP_AFTER << 3): case (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_POP2_AFTER << 3): + case (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_PUSH_BEFORE << 3): + return CF_CLASS_ALU; + + case V_SQ_CF_WORD1_SQ_CF_INST_TEX: + return CF_CLASS_TEXTURE; + + case V_SQ_CF_WORD1_SQ_CF_INST_VTX: + case V_SQ_CF_WORD1_SQ_CF_INST_VTX_TC: + return CF_CLASS_VERTEX; + + case V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT: + case V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT_DONE: + return CF_CLASS_EXPORT; + + case V_SQ_CF_WORD1_SQ_CF_INST_JUMP: + case V_SQ_CF_WORD1_SQ_CF_INST_ELSE: + case V_SQ_CF_WORD1_SQ_CF_INST_POP: + case V_SQ_CF_WORD1_SQ_CF_INST_LOOP_START_NO_AL: + case V_SQ_CF_WORD1_SQ_CF_INST_LOOP_END: + case V_SQ_CF_WORD1_SQ_CF_INST_LOOP_CONTINUE: + case V_SQ_CF_WORD1_SQ_CF_INST_LOOP_BREAK: + case V_SQ_CF_WORD1_SQ_CF_INST_CALL_FS: + case V_SQ_CF_WORD1_SQ_CF_INST_RETURN: + return CF_CLASS_OTHER; + + default: + R600_ERR("unsupported CF instruction (0x%X)\n", cf->inst); + return -EINVAL; + } +} + +/* common for r600/r700 - eg in eg_asm.c */ +static int r600_bc_cf_build(struct r600_bc *bc, struct r600_bc_cf *cf) +{ + unsigned id = cf->id; + unsigned end_of_program = bc->cf.prev == &cf->list; + + switch (get_cf_class(cf)) { + case CF_CLASS_ALU: + assert(!end_of_program); bc->bytecode[id++] = S_SQ_CF_ALU_WORD0_ADDR(cf->addr >> 1) | S_SQ_CF_ALU_WORD0_KCACHE_MODE0(cf->kcache[0].mode) | S_SQ_CF_ALU_WORD0_KCACHE_BANK0(cf->kcache[0].bank) | @@ -1399,46 +1519,39 @@ static int r600_bc_cf_build(struct r600_bc *bc, struct r600_bc_cf *cf) S_SQ_CF_ALU_WORD1_KCACHE_MODE1(cf->kcache[1].mode) | S_SQ_CF_ALU_WORD1_KCACHE_ADDR0(cf->kcache[0].addr) | S_SQ_CF_ALU_WORD1_KCACHE_ADDR1(cf->kcache[1].addr) | - S_SQ_CF_ALU_WORD1_BARRIER(1) | - S_SQ_CF_ALU_WORD1_USES_WATERFALL(bc->chiprev == CHIPREV_R600 ? cf->r6xx_uses_waterfall : 0) | - S_SQ_CF_ALU_WORD1_COUNT((cf->ndw / 2) - 1); + S_SQ_CF_ALU_WORD1_BARRIER(cf->barrier) | + S_SQ_CF_ALU_WORD1_USES_WATERFALL(bc->chiprev == CHIPREV_R600 ? cf->r6xx_uses_waterfall : 0) | + S_SQ_CF_ALU_WORD1_COUNT((cf->ndw / 2) - 1); break; - case V_SQ_CF_WORD1_SQ_CF_INST_TEX: - case V_SQ_CF_WORD1_SQ_CF_INST_VTX: - case V_SQ_CF_WORD1_SQ_CF_INST_VTX_TC: + case CF_CLASS_TEXTURE: + case CF_CLASS_VERTEX: bc->bytecode[id++] = S_SQ_CF_WORD0_ADDR(cf->addr >> 1); bc->bytecode[id++] = S_SQ_CF_WORD1_CF_INST(cf->inst) | - S_SQ_CF_WORD1_BARRIER(1) | - S_SQ_CF_WORD1_COUNT((cf->ndw / 4) - 1); + S_SQ_CF_WORD1_BARRIER(cf->barrier) | + S_SQ_CF_WORD1_COUNT((cf->ndw / 4) - 1) | + S_SQ_CF_WORD1_END_OF_PROGRAM(end_of_program); break; - case V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT: - case V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT_DONE: + case CF_CLASS_EXPORT: bc->bytecode[id++] = S_SQ_CF_ALLOC_EXPORT_WORD0_RW_GPR(cf->output.gpr) | S_SQ_CF_ALLOC_EXPORT_WORD0_ELEM_SIZE(cf->output.elem_size) | S_SQ_CF_ALLOC_EXPORT_WORD0_ARRAY_BASE(cf->output.array_base) | S_SQ_CF_ALLOC_EXPORT_WORD0_TYPE(cf->output.type); - bc->bytecode[id++] = S_SQ_CF_ALLOC_EXPORT_WORD1_SWIZ_SEL_X(cf->output.swizzle_x) | + bc->bytecode[id++] = S_SQ_CF_ALLOC_EXPORT_WORD1_BURST_COUNT(cf->output.burst_count - 1) | + S_SQ_CF_ALLOC_EXPORT_WORD1_SWIZ_SEL_X(cf->output.swizzle_x) | S_SQ_CF_ALLOC_EXPORT_WORD1_SWIZ_SEL_Y(cf->output.swizzle_y) | S_SQ_CF_ALLOC_EXPORT_WORD1_SWIZ_SEL_Z(cf->output.swizzle_z) | S_SQ_CF_ALLOC_EXPORT_WORD1_SWIZ_SEL_W(cf->output.swizzle_w) | - S_SQ_CF_ALLOC_EXPORT_WORD1_BARRIER(cf->output.barrier) | - S_SQ_CF_ALLOC_EXPORT_WORD1_CF_INST(cf->output.inst) | - S_SQ_CF_ALLOC_EXPORT_WORD1_END_OF_PROGRAM(cf->output.end_of_program); + S_SQ_CF_ALLOC_EXPORT_WORD1_BARRIER(cf->barrier) | + S_SQ_CF_ALLOC_EXPORT_WORD1_CF_INST(cf->inst) | + S_SQ_CF_ALLOC_EXPORT_WORD1_END_OF_PROGRAM(end_of_program); break; - case V_SQ_CF_WORD1_SQ_CF_INST_JUMP: - case V_SQ_CF_WORD1_SQ_CF_INST_ELSE: - case V_SQ_CF_WORD1_SQ_CF_INST_POP: - case V_SQ_CF_WORD1_SQ_CF_INST_LOOP_START_NO_AL: - case V_SQ_CF_WORD1_SQ_CF_INST_LOOP_END: - case V_SQ_CF_WORD1_SQ_CF_INST_LOOP_CONTINUE: - case V_SQ_CF_WORD1_SQ_CF_INST_LOOP_BREAK: - case V_SQ_CF_WORD1_SQ_CF_INST_CALL_FS: - case V_SQ_CF_WORD1_SQ_CF_INST_RETURN: + case CF_CLASS_OTHER: bc->bytecode[id++] = S_SQ_CF_WORD0_ADDR(cf->cf_addr >> 1); bc->bytecode[id++] = S_SQ_CF_WORD1_CF_INST(cf->inst) | - S_SQ_CF_WORD1_BARRIER(1) | - S_SQ_CF_WORD1_COND(cf->cond) | - S_SQ_CF_WORD1_POP_COUNT(cf->pop_count); + S_SQ_CF_WORD1_BARRIER(cf->barrier) | + S_SQ_CF_WORD1_COND(cf->cond) | + S_SQ_CF_WORD1_POP_COUNT(cf->pop_count) | + S_SQ_CF_WORD1_END_OF_PROGRAM(end_of_program); break; default: @@ -1448,12 +1561,773 @@ static int r600_bc_cf_build(struct r600_bc *bc, struct r600_bc_cf *cf) return 0; } +struct gpr_usage_range { + int replacement; + int32_t start; + int32_t end; +}; + +struct gpr_usage { + unsigned channels:4; + int32_t first_write; + int32_t last_write[4]; + unsigned nranges; + struct gpr_usage_range *ranges; +}; + +static struct gpr_usage_range* add_gpr_usage_range(struct gpr_usage *usage) +{ + usage->nranges++; + usage->ranges = realloc(usage->ranges, usage->nranges * sizeof(struct gpr_usage_range)); + if (!usage->ranges) + return NULL; + return &usage->ranges[usage->nranges-1]; +} + +static void notice_gpr_read(struct gpr_usage *usage, int32_t id, unsigned chan) +{ + usage->channels |= 1 << chan; + usage->first_write = -1; + if (!usage->nranges) { + struct gpr_usage_range* range = add_gpr_usage_range(usage); + range->replacement = -1; + range->start = -1; + range->end = -1; + } + if (usage->ranges[usage->nranges-1].end < id) + usage->ranges[usage->nranges-1].end = id; +} + +static void notice_gpr_rel_read(struct gpr_usage usage[128], int32_t id, unsigned chan) +{ + unsigned i; + for (i = 0; i < 128; ++i) + notice_gpr_read(&usage[i], id, chan); +} + +static void notice_gpr_last_write(struct gpr_usage *usage, int32_t id, unsigned chan) +{ + usage->last_write[chan] = id; +} + +static void notice_gpr_write(struct gpr_usage *usage, int32_t id, unsigned chan, + int predicate, int prefered_replacement) +{ + int32_t start = usage->first_write != -1 ? usage->first_write : id; + usage->channels &= ~(1 << chan); + if (usage->channels) { + if (usage->first_write == -1) + usage->first_write = id; + } else if (!usage->nranges || (usage->ranges[usage->nranges-1].start != start && !predicate)) { + usage->first_write = start; + struct gpr_usage_range* range = add_gpr_usage_range(usage); + range->replacement = prefered_replacement; + range->start = start; + range->end = -1; + } else if (usage->ranges[usage->nranges-1].start == start && prefered_replacement != -1) { + usage->ranges[usage->nranges-1].replacement = prefered_replacement; + } + notice_gpr_last_write(usage, id, chan); +} + +static void notice_gpr_rel_last_write(struct gpr_usage usage[128], int32_t id, unsigned chan) +{ + unsigned i; + for (i = 0; i < 128; ++i) + notice_gpr_last_write(&usage[i], id, chan); +} + +static void notice_gpr_rel_write(struct gpr_usage usage[128], int32_t id, unsigned chan) +{ + unsigned i; + for (i = 0; i < 128; ++i) + notice_gpr_write(&usage[i], id, chan, 1, -1); +} + +static void notice_alu_src_gprs(struct r600_bc *bc, struct r600_bc_alu *alu, + struct gpr_usage usage[128], int32_t id) +{ + unsigned src, num_src; + + num_src = r600_bc_get_num_operands(bc, alu); + for (src = 0; src < num_src; ++src) { + // constants doesn't matter + if (!is_gpr(alu->src[src].sel)) + continue; + + if (alu->src[src].rel) + notice_gpr_rel_read(usage, id, alu->src[src].chan); + else + notice_gpr_read(&usage[alu->src[src].sel], id, alu->src[src].chan); + } +} + +static void notice_alu_dst_gprs(struct r600_bc_alu *alu_first, struct gpr_usage usage[128], + int32_t id, int predicate) +{ + struct r600_bc_alu *alu; + for (alu = alu_first; alu; alu = LIST_ENTRY(struct r600_bc_alu, alu->list.next, list)) { + if (alu->dst.write) { + if (alu->dst.rel) + notice_gpr_rel_write(usage, id, alu->dst.chan); + else if (alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MOV && is_gpr(alu->src[0].sel)) + notice_gpr_write(&usage[alu->dst.sel], id, alu->dst.chan, + predicate, alu->src[0].sel); + else + notice_gpr_write(&usage[alu->dst.sel], id, alu->dst.chan, predicate, -1); + } + + if (alu->last) + break; + } +} + +static void notice_tex_gprs(struct r600_bc_tex *tex, struct gpr_usage usage[128], + int32_t id, int predicate) +{ + if (tex->src_rel) { + if (tex->src_sel_x < 4) + notice_gpr_rel_read(usage, id, tex->src_sel_x); + if (tex->src_sel_y < 4) + notice_gpr_rel_read(usage, id, tex->src_sel_y); + if (tex->src_sel_z < 4) + notice_gpr_rel_read(usage, id, tex->src_sel_z); + if (tex->src_sel_w < 4) + notice_gpr_rel_read(usage, id, tex->src_sel_w); + } else { + if (tex->src_sel_x < 4) + notice_gpr_read(&usage[tex->src_gpr], id, tex->src_sel_x); + if (tex->src_sel_y < 4) + notice_gpr_read(&usage[tex->src_gpr], id, tex->src_sel_y); + if (tex->src_sel_z < 4) + notice_gpr_read(&usage[tex->src_gpr], id, tex->src_sel_z); + if (tex->src_sel_w < 4) + notice_gpr_read(&usage[tex->src_gpr], id, tex->src_sel_w); + } + if (tex->dst_rel) { + if (tex->dst_sel_x != 7) + notice_gpr_rel_write(usage, id, 0); + if (tex->dst_sel_y != 7) + notice_gpr_rel_write(usage, id, 1); + if (tex->dst_sel_z != 7) + notice_gpr_rel_write(usage, id, 2); + if (tex->dst_sel_w != 7) + notice_gpr_rel_write(usage, id, 3); + } else { + if (tex->dst_sel_x != 7) + notice_gpr_write(&usage[tex->dst_gpr], id, 0, predicate, -1); + if (tex->dst_sel_y != 7) + notice_gpr_write(&usage[tex->dst_gpr], id, 1, predicate, -1); + if (tex->dst_sel_z != 7) + notice_gpr_write(&usage[tex->dst_gpr], id, 2, predicate, -1); + if (tex->dst_sel_w != 7) + notice_gpr_write(&usage[tex->dst_gpr], id, 3, predicate, -1); + } +} + +static void notice_vtx_gprs(struct r600_bc_vtx *vtx, struct gpr_usage usage[128], + int32_t id, int predicate) +{ + notice_gpr_read(&usage[vtx->src_gpr], id, vtx->src_sel_x); + + if (vtx->dst_sel_x != 7) + notice_gpr_write(&usage[vtx->dst_gpr], id, 0, predicate, -1); + if (vtx->dst_sel_y != 7) + notice_gpr_write(&usage[vtx->dst_gpr], id, 1, predicate, -1); + if (vtx->dst_sel_z != 7) + notice_gpr_write(&usage[vtx->dst_gpr], id, 2, predicate, -1); + if (vtx->dst_sel_w != 7) + notice_gpr_write(&usage[vtx->dst_gpr], id, 3, predicate, -1); +} + +static void notice_export_gprs(struct r600_bc_cf *cf, struct gpr_usage usage[128], + struct r600_bc_cf *export_cf[128], int32_t export_remap[128]) +{ + //TODO handle other memory operations + struct gpr_usage *output = &usage[cf->output.gpr]; + int32_t id = (output->last_write[0] + 0x100) & ~0xFF; + + export_cf[cf->output.gpr] = cf; + export_remap[cf->output.gpr] = id; + if (cf->output.swizzle_x < 4) + notice_gpr_read(output, id, cf->output.swizzle_x); + if (cf->output.swizzle_y < 4) + notice_gpr_read(output, id, cf->output.swizzle_y); + if (cf->output.swizzle_z < 4) + notice_gpr_read(output, id, cf->output.swizzle_z); + if (cf->output.swizzle_w < 4) + notice_gpr_read(output, id, cf->output.swizzle_w); +} + +static struct gpr_usage_range *find_src_range(struct gpr_usage *usage, int32_t id) +{ + unsigned i; + for (i = 0; i < usage->nranges; ++i) { + struct gpr_usage_range* range = &usage->ranges[i]; + + if (range->start < id && id <= range->end) + return range; + } + return NULL; +} + +static struct gpr_usage_range *find_dst_range(struct gpr_usage *usage, int32_t id) +{ + unsigned i; + for (i = 0; i < usage->nranges; ++i) { + struct gpr_usage_range* range = &usage->ranges[i]; + int32_t end = range->end; + + if (range->start <= id && (id < end || end == -1)) + return range; + } + assert(0); /* should not happen */ + return NULL; +} + +static int is_barrier_needed(struct gpr_usage *usage, int32_t id, unsigned chan, int32_t last_barrier) +{ + if (usage->last_write[chan] != (id & ~0xFF)) + return usage->last_write[chan] >= last_barrier; + else + return 0; +} + +static int is_intersection(struct gpr_usage_range* a, struct gpr_usage_range* b) +{ + return a->start <= b->end && b->start < a->end; +} + +static int rate_replacement(struct gpr_usage *usage, struct gpr_usage_range* range) +{ + unsigned i; + int32_t best_start = 0x3FFFFFFF, best_end = 0x3FFFFFFF; + + for (i = 0; i < usage->nranges; ++i) { + if (usage->ranges[i].replacement != -1) + continue; /* ignore already remapped ranges */ + + if (is_intersection(&usage->ranges[i], range)) + return -1; /* forget it if usages overlap */ + + if (range->start >= usage->ranges[i].end) + best_start = MIN2(best_start, range->start - usage->ranges[i].end); + + if (range->end != -1 && range->end <= usage->ranges[i].start) + best_end = MIN2(best_end, usage->ranges[i].start - range->end); + } + return best_start + best_end; +} + +static void find_replacement(struct gpr_usage usage[128], unsigned current, + struct gpr_usage_range *range, int is_export) +{ + unsigned i; + int best_gpr = -1, best_rate = 0x7FFFFFFF; + + if (range->replacement != -1 && range->replacement <= current) { + struct gpr_usage_range *other = find_src_range(&usage[range->replacement], range->start); + if (other && other->replacement != -1) + range->replacement = other->replacement; + } + + if (range->replacement != -1 && range->replacement < current) { + int rate = rate_replacement(&usage[range->replacement], range); + + /* check if prefered replacement can be used */ + if (rate != -1) { + best_rate = rate; + best_gpr = range->replacement; + } + } + + if (best_gpr == -1 && (range->start & ~0xFF) == (range->end & ~0xFF)) { + /* register is just used inside one ALU clause */ + /* try to use clause temporaryis for it */ + for (i = 127; i > 123; --i) { + int rate = rate_replacement(&usage[i], range); + + if (rate == -1) /* can't be used because ranges overlap */ + continue; + + if (rate < best_rate) { + best_rate = rate; + best_gpr = i; + + /* can't get better than this */ + if (rate == 0 || is_export) + break; + } + } + } + + if (best_gpr == -1) { + for (i = 0; i < current; ++i) { + int rate = rate_replacement(&usage[i], range); + + if (rate == -1) /* can't be used because ranges overlap */ + continue; + + if (rate < best_rate) { + best_rate = rate; + best_gpr = i; + + /* can't get better than this */ + if (rate == 0) + break; + } + } + } + + range->replacement = best_gpr; + if (best_gpr != -1) { + struct gpr_usage_range *reservation = add_gpr_usage_range(&usage[best_gpr]); + reservation->replacement = -1; + reservation->start = range->start; + reservation->end = range->end; + } +} + +static void find_export_replacement(struct gpr_usage usage[128], + struct gpr_usage_range *range, struct r600_bc_cf *current, + struct r600_bc_cf *next, int32_t next_id) +{ + if (!next || next_id <= range->start || next_id > range->end) + return; + + if (current->output.type != next->output.type) + return; + + if ((current->output.array_base + 1) != next->output.array_base) + return; + + find_src_range(&usage[next->output.gpr], next_id)->replacement = range->replacement + 1; +} + +static void replace_alu_gprs(struct r600_bc *bc, struct r600_bc_alu *alu, struct gpr_usage usage[128], + int32_t id, int32_t last_barrier, unsigned *barrier) +{ + struct gpr_usage *cur_usage; + struct gpr_usage_range *range; + unsigned src, num_src; + + num_src = r600_bc_get_num_operands(bc, alu); + for (src = 0; src < num_src; ++src) { + // constants doesn't matter + if (!is_gpr(alu->src[src].sel)) + continue; + + cur_usage = &usage[alu->src[src].sel]; + range = find_src_range(cur_usage, id); + if (range->replacement != -1) + alu->src[src].sel = range->replacement; + + *barrier |= is_barrier_needed(cur_usage, id, alu->src[src].chan, last_barrier); + } + + if (alu->dst.write) { + cur_usage = &usage[alu->dst.sel]; + range = find_dst_range(cur_usage, id); + if (range->replacement == alu->dst.sel) { + if (!alu->is_op3) + alu->dst.write = 0; + else + /*TODO: really check that register 123 is useable */ + alu->dst.sel = 123; + } else if (range->replacement != -1) { + alu->dst.sel = range->replacement; + } + if (alu->dst.rel) + notice_gpr_rel_last_write(usage, id, alu->dst.chan); + else + notice_gpr_last_write(cur_usage, id, alu->dst.chan); + } +} + +static void replace_tex_gprs(struct r600_bc_tex *tex, struct gpr_usage usage[128], + int32_t id, int32_t last_barrier, unsigned *barrier) +{ + struct gpr_usage *cur_usage = &usage[tex->src_gpr]; + struct gpr_usage_range *range = find_src_range(cur_usage, id); + + if (tex->src_rel) { + *barrier = 1; + } else { + if (tex->src_sel_x < 4) + *barrier |= is_barrier_needed(cur_usage, id, tex->src_sel_x, last_barrier); + if (tex->src_sel_y < 4) + *barrier |= is_barrier_needed(cur_usage, id, tex->src_sel_y, last_barrier); + if (tex->src_sel_z < 4) + *barrier |= is_barrier_needed(cur_usage, id, tex->src_sel_z, last_barrier); + if (tex->src_sel_w < 4) + *barrier |= is_barrier_needed(cur_usage, id, tex->src_sel_w, last_barrier); + } + + if (range->replacement != -1) + tex->src_gpr = range->replacement; + + cur_usage = &usage[tex->dst_gpr]; + range = find_dst_range(cur_usage, id); + if (range->replacement != -1) + tex->dst_gpr = range->replacement; + + if (tex->dst_rel) { + if (tex->dst_sel_x != 7) + notice_gpr_rel_last_write(usage, id, tex->dst_sel_x); + if (tex->dst_sel_y != 7) + notice_gpr_rel_last_write(usage, id, tex->dst_sel_y); + if (tex->dst_sel_z != 7) + notice_gpr_rel_last_write(usage, id, tex->dst_sel_z); + if (tex->dst_sel_w != 7) + notice_gpr_rel_last_write(usage, id, tex->dst_sel_w); + } else { + if (tex->dst_sel_x != 7) + notice_gpr_last_write(cur_usage, id, tex->dst_sel_x); + if (tex->dst_sel_y != 7) + notice_gpr_last_write(cur_usage, id, tex->dst_sel_y); + if (tex->dst_sel_z != 7) + notice_gpr_last_write(cur_usage, id, tex->dst_sel_z); + if (tex->dst_sel_w != 7) + notice_gpr_last_write(cur_usage, id, tex->dst_sel_w); + } +} + +static void replace_vtx_gprs(struct r600_bc_vtx *vtx, struct gpr_usage usage[128], + int32_t id, int32_t last_barrier, unsigned *barrier) +{ + struct gpr_usage *cur_usage = &usage[vtx->src_gpr]; + struct gpr_usage_range *range = find_src_range(cur_usage, id); + + *barrier |= is_barrier_needed(cur_usage, id, vtx->src_sel_x, last_barrier); + + if (range->replacement != -1) + vtx->src_gpr = range->replacement; + + cur_usage = &usage[vtx->dst_gpr]; + range = find_dst_range(cur_usage, id); + if (range->replacement != -1) + vtx->dst_gpr = range->replacement; + + if (vtx->dst_sel_x != 7) + notice_gpr_last_write(cur_usage, id, vtx->dst_sel_x); + if (vtx->dst_sel_y != 7) + notice_gpr_last_write(cur_usage, id, vtx->dst_sel_y); + if (vtx->dst_sel_z != 7) + notice_gpr_last_write(cur_usage, id, vtx->dst_sel_z); + if (vtx->dst_sel_w != 7) + notice_gpr_last_write(cur_usage, id, vtx->dst_sel_w); +} + +static void replace_export_gprs(struct r600_bc_cf *cf, struct gpr_usage usage[128], + int32_t id, int32_t last_barrier) +{ + //TODO handle other memory operations + struct gpr_usage *cur_usage = &usage[cf->output.gpr]; + struct gpr_usage_range *range = find_src_range(cur_usage, id); + + cf->barrier = 0; + if (cf->output.swizzle_x < 4) + cf->barrier |= is_barrier_needed(cur_usage, -1, cf->output.swizzle_x, last_barrier); + if (cf->output.swizzle_y < 4) + cf->barrier |= is_barrier_needed(cur_usage, -1, cf->output.swizzle_y, last_barrier); + if (cf->output.swizzle_z < 4) + cf->barrier |= is_barrier_needed(cur_usage, -1, cf->output.swizzle_z, last_barrier); + if (cf->output.swizzle_w < 4) + cf->barrier |= is_barrier_needed(cur_usage, -1, cf->output.swizzle_w, last_barrier); + + if (range->replacement != -1) + cf->output.gpr = range->replacement; +} + +static void optimize_alu_inst(struct r600_bc *bc, struct r600_bc_cf *cf, struct r600_bc_alu *alu) +{ + struct r600_bc_alu *alu_next; + unsigned chan; + unsigned src, num_src; + + /* check if a MOV could be optimized away */ + if (alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MOV) { + + /* destination equals source? */ + if (alu->dst.sel != alu->src[0].sel || + alu->dst.chan != alu->src[0].chan) + return; + + /* any special handling for the source? */ + if (alu->src[0].rel || alu->src[0].neg || alu->src[0].abs) + return; + + /* any special handling for destination? */ + if (alu->dst.rel || alu->dst.clamp) + return; + + /* ok find next instruction group and check if ps/pv is used */ + for (alu_next = alu; !alu_next->last; alu_next = NEXT_ALU(alu_next)); + + if (alu_next->list.next != &cf->alu) { + chan = is_alu_reduction_inst(bc, alu) ? 0 : alu->dst.chan; + for (alu_next = NEXT_ALU(alu_next); alu_next; alu_next = NEXT_ALU(alu_next)) { + num_src = r600_bc_get_num_operands(bc, alu_next); + for (src = 0; src < num_src; ++src) { + if (alu_next->src[src].sel == V_SQ_ALU_SRC_PV && + alu_next->src[src].chan == chan) + return; + + if (alu_next->src[src].sel == V_SQ_ALU_SRC_PS) + return; + } + + if (alu_next->last) + break; + } + } + + r600_bc_remove_alu(cf, alu); + } +} + +static void optimize_export_inst(struct r600_bc *bc, struct r600_bc_cf *cf) +{ + struct r600_bc_cf *prev = LIST_ENTRY(struct r600_bc_cf, cf->list.prev, list); + if (&prev->list == &bc->cf || + prev->inst != cf->inst || + prev->output.type != cf->output.type || + prev->output.elem_size != cf->output.elem_size || + prev->output.swizzle_x != cf->output.swizzle_x || + prev->output.swizzle_y != cf->output.swizzle_y || + prev->output.swizzle_z != cf->output.swizzle_z || + prev->output.swizzle_w != cf->output.swizzle_w) + return; + + if ((prev->output.burst_count + cf->output.burst_count) > 16) + return; + + if ((prev->output.gpr + prev->output.burst_count) == cf->output.gpr && + (prev->output.array_base + prev->output.burst_count) == cf->output.array_base) { + + prev->output.burst_count += cf->output.burst_count; + r600_bc_remove_cf(bc, cf); + + } else if (prev->output.gpr == (cf->output.gpr + cf->output.burst_count) && + prev->output.array_base == (cf->output.array_base + cf->output.burst_count)) { + + cf->output.burst_count += prev->output.burst_count; + r600_bc_remove_cf(bc, prev); + } +} + +static void r600_bc_optimize(struct r600_bc *bc) +{ + struct r600_bc_cf *cf, *next_cf; + struct r600_bc_alu *first, *next_alu; + struct r600_bc_alu *alu; + struct r600_bc_vtx *vtx; + struct r600_bc_tex *tex; + struct gpr_usage usage[128]; + + /* assume that each gpr is exported only once */ + struct r600_bc_cf *export_cf[128] = { NULL }; + int32_t export_remap[128]; + + int32_t id, barrier[bc->nstack]; + unsigned i, j, stack, predicate, old_stack; + + memset(&usage, 0, sizeof(usage)); + for (i = 0; i < 128; ++i) { + usage[i].first_write = -1; + usage[i].last_write[0] = -1; + usage[i].last_write[1] = -1; + usage[i].last_write[2] = -1; + usage[i].last_write[3] = -1; + } + + /* first gather some informations about the gpr usage */ + id = 0; stack = 0; + LIST_FOR_EACH_ENTRY(cf, &bc->cf, list) { + switch (get_cf_class(cf)) { + case CF_CLASS_ALU: + predicate = 0; + first = NULL; + LIST_FOR_EACH_ENTRY(alu, &cf->alu, list) { + if (!first) + first = alu; + notice_alu_src_gprs(bc, alu, usage, id); + if (alu->last) { + notice_alu_dst_gprs(first, usage, id, predicate || stack > 0); + first = NULL; + ++id; + } + if (is_alu_pred_inst(bc, alu)) + predicate++; + } + if (cf->inst == V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_PUSH_BEFORE << 3) + stack += predicate; + else if (cf->inst == V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_POP_AFTER << 3) + stack -= 1; + else if (cf->inst == V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_POP2_AFTER << 3) + stack -= 2; + break; + case CF_CLASS_TEXTURE: + LIST_FOR_EACH_ENTRY(tex, &cf->tex, list) { + notice_tex_gprs(tex, usage, id++, stack > 0); + } + break; + case CF_CLASS_VERTEX: + LIST_FOR_EACH_ENTRY(vtx, &cf->vtx, list) { + notice_vtx_gprs(vtx, usage, id++, stack > 0); + } + break; + case CF_CLASS_EXPORT: + notice_export_gprs(cf, usage, export_cf, export_remap); + continue; // don't increment id + case CF_CLASS_OTHER: + switch (cf->inst) { + case V_SQ_CF_WORD1_SQ_CF_INST_JUMP: + case V_SQ_CF_WORD1_SQ_CF_INST_ELSE: + case V_SQ_CF_WORD1_SQ_CF_INST_CALL_FS: + break; + + case V_SQ_CF_WORD1_SQ_CF_INST_POP: + stack -= cf->pop_count; + break; + + default: + // TODO implement loop handling + goto out; + } + } + id += 0x100; + id &= ~0xFF; + } + assert(stack == 0); + + /* try to optimize gpr usage */ + for (i = 0; i < 124; ++i) { + for (j = 0; j < usage[i].nranges; ++j) { + struct gpr_usage_range *range = &usage[i].ranges[j]; + int is_export = export_cf[i] && export_cf[i + 1] && + range->start < export_remap[i] && + export_remap[i] <= range->end; + + if (range->start == -1) + range->replacement = -1; + else if (range->end == -1) + range->replacement = i; + else + find_replacement(usage, i, range, is_export); + + if (range->replacement == -1) + bc->ngpr = i; + else if (range->replacement < i && range->replacement > bc->ngpr) + bc->ngpr = range->replacement; + + if (is_export && range->replacement != -1) { + find_export_replacement(usage, range, export_cf[i], + export_cf[i + 1], export_remap[i + 1]); + } + } + } + bc->ngpr++; + + /* apply the changes */ + for (i = 0; i < 128; ++i) { + usage[i].last_write[0] = -1; + usage[i].last_write[1] = -1; + usage[i].last_write[2] = -1; + usage[i].last_write[3] = -1; + } + barrier[0] = 0; + id = 0; stack = 0; + LIST_FOR_EACH_ENTRY_SAFE(cf, next_cf, &bc->cf, list) { + old_stack = stack; + switch (get_cf_class(cf)) { + case CF_CLASS_ALU: + predicate = 0; + first = NULL; + cf->barrier = 0; + LIST_FOR_EACH_ENTRY_SAFE(alu, next_alu, &cf->alu, list) { + replace_alu_gprs(bc, alu, usage, id, barrier[stack], &cf->barrier); + if (alu->last) + ++id; + + if (is_alu_pred_inst(bc, alu)) + predicate++; + + if (cf->inst == V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU << 3) + optimize_alu_inst(bc, cf, alu); + } + if (cf->inst == V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_PUSH_BEFORE << 3) + stack += predicate; + else if (cf->inst == V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_POP_AFTER << 3) + stack -= 1; + else if (cf->inst == V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_POP2_AFTER << 3) + stack -= 2; + if (LIST_IS_EMPTY(&cf->alu)) { + r600_bc_remove_cf(bc, cf); + cf = NULL; + } + break; + case CF_CLASS_TEXTURE: + cf->barrier = 0; + LIST_FOR_EACH_ENTRY(tex, &cf->tex, list) { + replace_tex_gprs(tex, usage, id++, barrier[stack], &cf->barrier); + } + break; + case CF_CLASS_VERTEX: + cf->barrier = 0; + LIST_FOR_EACH_ENTRY(vtx, &cf->vtx, list) { + replace_vtx_gprs(vtx, usage, id++, barrier[stack], &cf->barrier); + } + break; + case CF_CLASS_EXPORT: + continue; // don't increment id + case CF_CLASS_OTHER: + if (cf->inst == V_SQ_CF_WORD1_SQ_CF_INST_POP) { + cf->barrier = 0; + stack -= cf->pop_count; + } + break; + } + + id &= ~0xFF; + if (cf && cf->barrier) + barrier[old_stack] = id; + + for (i = old_stack + 1; i <= stack; ++i) + barrier[i] = barrier[old_stack]; + + id += 0x100; + if (stack != 0) /* ensue exports are placed outside of conditional blocks */ + continue; + + for (i = 0; i < 128; ++i) { + if (!export_cf[i] || id < export_remap[i]) + continue; + + r600_bc_move_cf(bc, export_cf[i], next_cf); + replace_export_gprs(export_cf[i], usage, export_remap[i], barrier[stack]); + if (export_cf[i]->barrier) + barrier[stack] = id - 1; + next_cf = LIST_ENTRY(struct r600_bc_cf, export_cf[i]->list.next, list); + optimize_export_inst(bc, export_cf[i]); + export_cf[i] = NULL; + } + } + assert(stack == 0); + +out: + for (i = 0; i < 128; ++i) { + free(usage[i].ranges); + } +} + int r600_bc_build(struct r600_bc *bc) { struct r600_bc_cf *cf; struct r600_bc_alu *alu; struct r600_bc_vtx *vtx; struct r600_bc_tex *tex; + struct r600_bc_cf *exports[4] = { NULL }; uint32_t literal[4]; unsigned nliteral; unsigned addr; @@ -1465,37 +2339,27 @@ int r600_bc_build(struct r600_bc *bc) bc->nstack = 1; } + r600_bc_optimize(bc); + /* first path compute addr of each CF block */ /* addr start after all the CF instructions */ - addr = bc->cf_last->id + 2; + addr = LIST_ENTRY(struct r600_bc_cf, bc->cf.prev, list)->id + 2; LIST_FOR_EACH_ENTRY(cf, &bc->cf, list) { - switch (cf->inst) { - case (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU << 3): - case (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_POP_AFTER << 3): - case (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_POP2_AFTER << 3): - case (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_PUSH_BEFORE << 3): + switch (get_cf_class(cf)) { + case CF_CLASS_ALU: break; - case V_SQ_CF_WORD1_SQ_CF_INST_TEX: - case V_SQ_CF_WORD1_SQ_CF_INST_VTX: - case V_SQ_CF_WORD1_SQ_CF_INST_VTX_TC: + case CF_CLASS_TEXTURE: + case CF_CLASS_VERTEX: /* fetch node need to be 16 bytes aligned*/ addr += 3; addr &= 0xFFFFFFFCUL; break; - case V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT: - case V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT_DONE: - case EG_V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT: - case EG_V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT_DONE: break; - case V_SQ_CF_WORD1_SQ_CF_INST_JUMP: - case V_SQ_CF_WORD1_SQ_CF_INST_ELSE: - case V_SQ_CF_WORD1_SQ_CF_INST_POP: - case V_SQ_CF_WORD1_SQ_CF_INST_LOOP_START_NO_AL: - case V_SQ_CF_WORD1_SQ_CF_INST_LOOP_END: - case V_SQ_CF_WORD1_SQ_CF_INST_LOOP_CONTINUE: - case V_SQ_CF_WORD1_SQ_CF_INST_LOOP_BREAK: - case V_SQ_CF_WORD1_SQ_CF_INST_CALL_FS: - case V_SQ_CF_WORD1_SQ_CF_INST_RETURN: + case CF_CLASS_EXPORT: + if (cf->inst == BC_INST(bc, V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT)) + exports[cf->output.type] = cf; + break; + case CF_CLASS_OTHER: break; default: R600_ERR("unsupported CF instruction (0x%X)\n", cf->inst); @@ -1505,6 +2369,14 @@ int r600_bc_build(struct r600_bc *bc) addr += cf->ndw; bc->ndw = cf->addr + cf->ndw; } + + /* set export done on last export of each type */ + for (i = 0; i < 4; ++i) { + if (exports[i]) { + exports[i]->inst = BC_INST(bc, V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT_DONE); + } + } + free(bc->bytecode); bc->bytecode = calloc(1, bc->ndw * 4); if (bc->bytecode == NULL) @@ -1517,11 +2389,8 @@ int r600_bc_build(struct r600_bc *bc) r = r600_bc_cf_build(bc, cf); if (r) return r; - switch (cf->inst) { - case (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU << 3): - case (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_POP_AFTER << 3): - case (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_POP2_AFTER << 3): - case (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_PUSH_BEFORE << 3): + switch (get_cf_class(cf)) { + case CF_CLASS_ALU: nliteral = 0; memset(literal, 0, sizeof(literal)); LIST_FOR_EACH_ENTRY(alu, &cf->alu, list) { @@ -1553,8 +2422,7 @@ int r600_bc_build(struct r600_bc *bc) } } break; - case V_SQ_CF_WORD1_SQ_CF_INST_VTX: - case V_SQ_CF_WORD1_SQ_CF_INST_VTX_TC: + case CF_CLASS_VERTEX: LIST_FOR_EACH_ENTRY(vtx, &cf->vtx, list) { r = r600_bc_vtx_build(bc, vtx, addr); if (r) @@ -1562,7 +2430,7 @@ int r600_bc_build(struct r600_bc *bc) addr += 4; } break; - case V_SQ_CF_WORD1_SQ_CF_INST_TEX: + case CF_CLASS_TEXTURE: LIST_FOR_EACH_ENTRY(tex, &cf->tex, list) { r = r600_bc_tex_build(bc, tex, addr); if (r) @@ -1570,19 +2438,8 @@ int r600_bc_build(struct r600_bc *bc) addr += 4; } break; - case V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT: - case V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT_DONE: - case EG_V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT: - case EG_V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT_DONE: - case V_SQ_CF_WORD1_SQ_CF_INST_LOOP_START_NO_AL: - case V_SQ_CF_WORD1_SQ_CF_INST_LOOP_END: - case V_SQ_CF_WORD1_SQ_CF_INST_LOOP_CONTINUE: - case V_SQ_CF_WORD1_SQ_CF_INST_LOOP_BREAK: - case V_SQ_CF_WORD1_SQ_CF_INST_JUMP: - case V_SQ_CF_WORD1_SQ_CF_INST_ELSE: - case V_SQ_CF_WORD1_SQ_CF_INST_POP: - case V_SQ_CF_WORD1_SQ_CF_INST_CALL_FS: - case V_SQ_CF_WORD1_SQ_CF_INST_RETURN: + case CF_CLASS_EXPORT: + case CF_CLASS_OTHER: break; default: R600_ERR("unsupported CF instruction (0x%X)\n", cf->inst); @@ -1658,13 +2515,10 @@ void r600_bc_dump(struct r600_bc *bc) LIST_FOR_EACH_ENTRY(cf, &bc->cf, list) { id = cf->id; - switch (cf->inst) { - case (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU << 3): - case (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_POP_AFTER << 3): - case (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_POP2_AFTER << 3): - case (V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU_PUSH_BEFORE << 3): + switch (get_cf_class(cf)) { + case CF_CLASS_ALU: fprintf(stderr, "%04d %08X ALU ", id, bc->bytecode[id]); - fprintf(stderr, "ADDR:%d ", cf->addr); + fprintf(stderr, "ADDR:%04d ", cf->addr); fprintf(stderr, "KCACHE_MODE0:%X ", cf->kcache[0].mode); fprintf(stderr, "KCACHE_BANK0:%X ", cf->kcache[0].bank); fprintf(stderr, "KCACHE_BANK1:%X\n", cf->kcache[1].bank); @@ -1674,22 +2528,22 @@ void r600_bc_dump(struct r600_bc *bc) fprintf(stderr, "KCACHE_MODE1:%X ", cf->kcache[1].mode); fprintf(stderr, "KCACHE_ADDR0:%X ", cf->kcache[0].addr); fprintf(stderr, "KCACHE_ADDR1:%X ", cf->kcache[1].addr); + fprintf(stderr, "BARRIER:%d ", cf->barrier); fprintf(stderr, "COUNT:%d\n", cf->ndw / 2); break; - case V_SQ_CF_WORD1_SQ_CF_INST_TEX: - case V_SQ_CF_WORD1_SQ_CF_INST_VTX: - case V_SQ_CF_WORD1_SQ_CF_INST_VTX_TC: + case CF_CLASS_TEXTURE: + case CF_CLASS_VERTEX: fprintf(stderr, "%04d %08X TEX/VTX ", id, bc->bytecode[id]); - fprintf(stderr, "ADDR:%d\n", cf->addr); + fprintf(stderr, "ADDR:%04d\n", cf->addr); id++; fprintf(stderr, "%04d %08X TEX/VTX ", id, bc->bytecode[id]); fprintf(stderr, "INST:%d ", cf->inst); + fprintf(stderr, "BARRIER:%d ", cf->barrier); fprintf(stderr, "COUNT:%d\n", cf->ndw / 4); break; - case V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT: - case V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT_DONE: + case CF_CLASS_EXPORT: fprintf(stderr, "%04d %08X EXPORT ", id, bc->bytecode[id]); - fprintf(stderr, "GPR:%X ", cf->output.gpr); + fprintf(stderr, "GPR:%d ", cf->output.gpr); fprintf(stderr, "ELEM_SIZE:%X ", cf->output.elem_size); fprintf(stderr, "ARRAY_BASE:%X ", cf->output.array_base); fprintf(stderr, "TYPE:%X\n", cf->output.type); @@ -1700,25 +2554,18 @@ void r600_bc_dump(struct r600_bc *bc) fprintf(stderr, "SWIZ_Z:%X ", cf->output.swizzle_z); fprintf(stderr, "SWIZ_W:%X ", cf->output.swizzle_w); fprintf(stderr, "SWIZ_W:%X ", cf->output.swizzle_w); - fprintf(stderr, "BARRIER:%X ", cf->output.barrier); - fprintf(stderr, "INST:%d ", cf->output.inst); - fprintf(stderr, "EOP:%X\n", cf->output.end_of_program); + fprintf(stderr, "BARRIER:%d ", cf->barrier); + fprintf(stderr, "INST:%d ", cf->inst); + fprintf(stderr, "BURST_COUNT:%d\n", cf->output.burst_count); break; - case V_SQ_CF_WORD1_SQ_CF_INST_JUMP: - case V_SQ_CF_WORD1_SQ_CF_INST_ELSE: - case V_SQ_CF_WORD1_SQ_CF_INST_POP: - case V_SQ_CF_WORD1_SQ_CF_INST_LOOP_START_NO_AL: - case V_SQ_CF_WORD1_SQ_CF_INST_LOOP_END: - case V_SQ_CF_WORD1_SQ_CF_INST_LOOP_CONTINUE: - case V_SQ_CF_WORD1_SQ_CF_INST_LOOP_BREAK: - case V_SQ_CF_WORD1_SQ_CF_INST_CALL_FS: - case V_SQ_CF_WORD1_SQ_CF_INST_RETURN: + case CF_CLASS_OTHER: fprintf(stderr, "%04d %08X CF ", id, bc->bytecode[id]); - fprintf(stderr, "ADDR:%d\n", cf->cf_addr); + fprintf(stderr, "ADDR:%04d\n", cf->cf_addr); id++; fprintf(stderr, "%04d %08X CF ", id, bc->bytecode[id]); fprintf(stderr, "INST:%d ", cf->inst); fprintf(stderr, "COND:%X ", cf->cond); + fprintf(stderr, "BARRIER:%d ", cf->barrier); fprintf(stderr, "POP_COUNT:%X\n", cf->pop_count); break; } @@ -1791,21 +2638,21 @@ void r600_cf_vtx(struct r600_vertex_element *ve, u32 *bytecode, unsigned count) if (count > 8) { bytecode[i++] = S_SQ_CF_WORD0_ADDR(8 >> 1); bytecode[i++] = S_SQ_CF_WORD1_CF_INST(V_SQ_CF_WORD1_SQ_CF_INST_VTX) | - S_SQ_CF_WORD1_BARRIER(1) | + S_SQ_CF_WORD1_BARRIER(0) | S_SQ_CF_WORD1_COUNT(8 - 1); bytecode[i++] = S_SQ_CF_WORD0_ADDR(40 >> 1); bytecode[i++] = S_SQ_CF_WORD1_CF_INST(V_SQ_CF_WORD1_SQ_CF_INST_VTX) | - S_SQ_CF_WORD1_BARRIER(1) | + S_SQ_CF_WORD1_BARRIER(0) | S_SQ_CF_WORD1_COUNT(count - 8 - 1); } else { bytecode[i++] = S_SQ_CF_WORD0_ADDR(8 >> 1); bytecode[i++] = S_SQ_CF_WORD1_CF_INST(V_SQ_CF_WORD1_SQ_CF_INST_VTX) | - S_SQ_CF_WORD1_BARRIER(1) | + S_SQ_CF_WORD1_BARRIER(0) | S_SQ_CF_WORD1_COUNT(count - 1); } bytecode[i++] = S_SQ_CF_WORD0_ADDR(0); bytecode[i++] = S_SQ_CF_WORD1_CF_INST(V_SQ_CF_WORD1_SQ_CF_INST_RETURN) | - S_SQ_CF_WORD1_BARRIER(1); + S_SQ_CF_WORD1_BARRIER(0); rstate = &ve->rstate; rstate->id = R600_PIPE_STATE_FETCH_SHADER; @@ -1827,21 +2674,21 @@ void r600_cf_vtx_tc(struct r600_vertex_element *ve, u32 *bytecode, unsigned coun if (count > 8) { bytecode[i++] = S_SQ_CF_WORD0_ADDR(8 >> 1); bytecode[i++] = S_SQ_CF_WORD1_CF_INST(V_SQ_CF_WORD1_SQ_CF_INST_VTX_TC) | - S_SQ_CF_WORD1_BARRIER(1) | + S_SQ_CF_WORD1_BARRIER(0) | S_SQ_CF_WORD1_COUNT(8 - 1); bytecode[i++] = S_SQ_CF_WORD0_ADDR(40 >> 1); bytecode[i++] = S_SQ_CF_WORD1_CF_INST(V_SQ_CF_WORD1_SQ_CF_INST_VTX_TC) | - S_SQ_CF_WORD1_BARRIER(1) | + S_SQ_CF_WORD1_BARRIER(0) | S_SQ_CF_WORD1_COUNT((count - 8) - 1); } else { bytecode[i++] = S_SQ_CF_WORD0_ADDR(8 >> 1); bytecode[i++] = S_SQ_CF_WORD1_CF_INST(V_SQ_CF_WORD1_SQ_CF_INST_VTX_TC) | - S_SQ_CF_WORD1_BARRIER(1) | + S_SQ_CF_WORD1_BARRIER(0) | S_SQ_CF_WORD1_COUNT(count - 1); } bytecode[i++] = S_SQ_CF_WORD0_ADDR(0); bytecode[i++] = S_SQ_CF_WORD1_CF_INST(V_SQ_CF_WORD1_SQ_CF_INST_RETURN) | - S_SQ_CF_WORD1_BARRIER(1); + S_SQ_CF_WORD1_BARRIER(0); rstate = &ve->rstate; rstate->id = R600_PIPE_STATE_FETCH_SHADER; diff --git a/src/gallium/drivers/r600/r600_asm.h b/src/gallium/drivers/r600/r600_asm.h index 278b4466cb0..519245f3af2 100644 --- a/src/gallium/drivers/r600/r600_asm.h +++ b/src/gallium/drivers/r600/r600_asm.h @@ -108,15 +108,13 @@ struct r600_bc_vtx { struct r600_bc_output { unsigned array_base; unsigned type; - unsigned end_of_program; - unsigned inst; unsigned elem_size; unsigned gpr; unsigned swizzle_x; unsigned swizzle_y; unsigned swizzle_z; unsigned swizzle_w; - unsigned barrier; + unsigned burst_count; }; struct r600_bc_kcache { @@ -134,6 +132,7 @@ struct r600_bc_cf { unsigned cond; unsigned pop_count; unsigned cf_addr; /* control flow addr */ + unsigned barrier; struct r600_bc_kcache kcache[2]; unsigned r6xx_uses_waterfall; struct list_head alu; diff --git a/src/gallium/drivers/r600/r600_pipe.c b/src/gallium/drivers/r600/r600_pipe.c index 20838e4d98f..ad14dbe14f4 100644 --- a/src/gallium/drivers/r600/r600_pipe.c +++ b/src/gallium/drivers/r600/r600_pipe.c @@ -42,6 +42,7 @@ #include "r600_shader.h" #include "r600_pipe.h" #include "r600_state_inlines.h" +#include "r600_video_context.h" /* * pipe_context @@ -483,6 +484,7 @@ struct pipe_screen *r600_screen_create(struct radeon *radeon) rscreen->screen.get_paramf = r600_get_paramf; rscreen->screen.is_format_supported = r600_is_format_supported; rscreen->screen.context_create = r600_create_context; + rscreen->screen.video_context_create = r600_video_create; r600_init_screen_resource_functions(&rscreen->screen); rscreen->tiling_info = r600_get_tiling_info(radeon); diff --git a/src/gallium/drivers/r600/r600_shader.c b/src/gallium/drivers/r600/r600_shader.c index 5d952a0cae7..106852c1082 100644 --- a/src/gallium/drivers/r600/r600_shader.c +++ b/src/gallium/drivers/r600/r600_shader.c @@ -497,7 +497,7 @@ int r600_shader_from_tgsi(const struct tgsi_token *tokens, struct r600_shader *s struct tgsi_full_immediate *immediate; struct r600_shader_ctx ctx; struct r600_bc_output output[32]; - unsigned output_done, noutput; + unsigned noutput; unsigned opcode; int i, r = 0, pos0; @@ -619,10 +619,8 @@ int r600_shader_from_tgsi(const struct tgsi_token *tokens, struct r600_shader *s output[i].swizzle_y = 1; output[i].swizzle_z = 2; output[i].swizzle_w = 3; - output[i].barrier = 1; output[i].type = V_SQ_CF_ALLOC_EXPORT_WORD0_SQ_EXPORT_PARAM; output[i].array_base = i - pos0; - output[i].inst = BC_INST(ctx.bc, V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT); switch (ctx.type) { case TGSI_PROCESSOR_VERTEX: if (shader->output[i].name == TGSI_SEMANTIC_POSITION) { @@ -682,10 +680,8 @@ int r600_shader_from_tgsi(const struct tgsi_token *tokens, struct r600_shader *s output[i].swizzle_y = 1; output[i].swizzle_z = 2; output[i].swizzle_w = 3; - output[i].barrier = 1; output[i].type = V_SQ_CF_ALLOC_EXPORT_WORD0_SQ_EXPORT_PARAM; output[i].array_base = 0; - output[i].inst = BC_INST(ctx.bc, V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT); noutput++; } } @@ -698,22 +694,10 @@ int r600_shader_from_tgsi(const struct tgsi_token *tokens, struct r600_shader *s output[0].swizzle_y = 7; output[0].swizzle_z = 7; output[0].swizzle_w = 7; - output[0].barrier = 1; output[0].type = V_SQ_CF_ALLOC_EXPORT_WORD0_SQ_EXPORT_PIXEL; output[0].array_base = 0; - output[0].inst = BC_INST(ctx.bc, V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT); noutput++; } - /* set export done on last export of each type */ - for (i = noutput - 1, output_done = 0; i >= 0; i--) { - if (i == (noutput - 1)) { - output[i].end_of_program = 1; - } - if (!(output_done & (1 << output[i].type))) { - output_done |= (1 << output[i].type); - output[i].inst = BC_INST(ctx.bc, V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT_DONE); - } - } /* add output to bytecode */ for (i = 0; i < noutput; i++) { r = r600_bc_add_output(ctx.bc, &output[i]); @@ -747,7 +731,7 @@ static int tgsi_src(struct r600_shader_ctx *ctx, memset(r600_src, 0, sizeof(struct r600_bc_alu_src)); r600_src->neg = tgsi_src->Register.Negate; r600_src->abs = tgsi_src->Register.Absolute; - if (tgsi_src->Register.File == TGSI_FILE_IMMEDIATE) { + if (tgsi_src->Register.File == TGSI_FILE_IMMEDIATE) { int index; if((tgsi_src->Register.SwizzleX == tgsi_src->Register.SwizzleY) && (tgsi_src->Register.SwizzleX == tgsi_src->Register.SwizzleZ) && diff --git a/src/gallium/drivers/r600/r600_state.c b/src/gallium/drivers/r600/r600_state.c index d678f42ad67..de2668cee16 100644 --- a/src/gallium/drivers/r600/r600_state.c +++ b/src/gallium/drivers/r600/r600_state.c @@ -925,6 +925,17 @@ static void r600_cb(struct r600_pipe_context *rctx, struct r600_pipe_state *rsta desc = util_format_description(rtex->resource.base.b.format); if (desc->colorspace == UTIL_FORMAT_COLORSPACE_SRGB) ntype = V_0280A0_NUMBER_SRGB; + else if (desc->layout == UTIL_FORMAT_LAYOUT_PLAIN) { + switch(desc->channel[0].type) { + case UTIL_FORMAT_TYPE_UNSIGNED: + ntype = V_0280A0_NUMBER_UNORM; + break; + + case UTIL_FORMAT_TYPE_SIGNED: + ntype = V_0280A0_NUMBER_SNORM; + break; + } + } format = r600_translate_colorformat(rtex->resource.base.b.format); swap = r600_translate_colorswap(rtex->resource.base.b.format); diff --git a/src/gallium/drivers/r600/r600_state_inlines.h b/src/gallium/drivers/r600/r600_state_inlines.h index d5dabdc69b6..a0ec493fc85 100644 --- a/src/gallium/drivers/r600/r600_state_inlines.h +++ b/src/gallium/drivers/r600/r600_state_inlines.h @@ -310,6 +310,7 @@ static inline uint32_t r600_translate_colorswap(enum pipe_format format) return V_0280A0_SWAP_STD; case PIPE_FORMAT_R16_UNORM: + case PIPE_FORMAT_R16_SNORM: return V_0280A0_SWAP_STD; /* 32-bit buffers. */ @@ -360,7 +361,7 @@ static inline uint32_t r600_translate_colorswap(enum pipe_format format) // return FMT_16_16_16_16_FLOAT; /* 128-bit buffers. */ - case PIPE_FORMAT_R32G32B32A32_FLOAT: + //case PIPE_FORMAT_R32G32B32A32_FLOAT: // return FMT_32_32_32_32_FLOAT; return 0; default: @@ -401,6 +402,7 @@ static INLINE uint32_t r600_translate_colorformat(enum pipe_format format) return V_0280A0_COLOR_8_8; case PIPE_FORMAT_R16_UNORM: + case PIPE_FORMAT_R16_SNORM: return V_0280A0_COLOR_16; /* 32-bit buffers. */ @@ -433,8 +435,8 @@ static INLINE uint32_t r600_translate_colorformat(enum pipe_format format) case PIPE_FORMAT_S8_USCALED_Z24_UNORM: return V_0280A0_COLOR_24_8; - case PIPE_FORMAT_R32_FLOAT: - return V_0280A0_COLOR_32_FLOAT; + //case PIPE_FORMAT_R32_FLOAT: + // return V_0280A0_COLOR_32_FLOAT; case PIPE_FORMAT_R16G16_FLOAT: return V_0280A0_COLOR_16_16_FLOAT; @@ -465,10 +467,10 @@ static INLINE uint32_t r600_translate_colorformat(enum pipe_format format) return V_0280A0_COLOR_32_32; /* 128-bit buffers. */ - case PIPE_FORMAT_R32G32B32_FLOAT: - return V_0280A0_COLOR_32_32_32_FLOAT; - case PIPE_FORMAT_R32G32B32A32_FLOAT: - return V_0280A0_COLOR_32_32_32_32_FLOAT; + //case PIPE_FORMAT_R32G32B32_FLOAT: + // return V_0280A0_COLOR_32_32_32_FLOAT; + //case PIPE_FORMAT_R32G32B32A32_FLOAT: + // return V_0280A0_COLOR_32_32_32_32_FLOAT; /* YUV buffers. */ case PIPE_FORMAT_UYVY: diff --git a/src/gallium/drivers/r600/r600_texture.c b/src/gallium/drivers/r600/r600_texture.c index e2745624575..1f4f453c091 100644 --- a/src/gallium/drivers/r600/r600_texture.c +++ b/src/gallium/drivers/r600/r600_texture.c @@ -321,6 +321,48 @@ r600_texture_create_object(struct pipe_screen *screen, return rtex; } +/* Figure out whether u_blitter will fallback to a transfer operation. + * If so, don't use a staging resource. + */ +static boolean permit_hardware_blit(struct pipe_screen *screen, + const struct pipe_resource *res) +{ + unsigned bind; + + if (util_format_is_depth_or_stencil(res->format)) + bind = PIPE_BIND_DEPTH_STENCIL; + else + bind = PIPE_BIND_RENDER_TARGET; + + /* See r600_resource_copy_region: there is something wrong + * with depth resource copies at the moment so avoid them for + * now. + */ + if (util_format_get_component_bits(res->format, + UTIL_FORMAT_COLORSPACE_ZS, + 0) != 0) + return FALSE; + + if (!screen->is_format_supported(screen, + res->format, + res->target, + res->nr_samples, + bind, 0)) + return FALSE; + + if (!screen->is_format_supported(screen, + res->format, + res->target, + res->nr_samples, + PIPE_BIND_SAMPLER_VIEW, 0)) + return FALSE; + + if (res->usage == PIPE_USAGE_STREAM) + return FALSE; + + return TRUE; +} + struct pipe_resource *r600_texture_create(struct pipe_screen *screen, const struct pipe_resource *templ) { @@ -332,7 +374,7 @@ struct pipe_resource *r600_texture_create(struct pipe_screen *screen, if (force_tiling == -1) force_tiling = debug_get_bool_option("R600_FORCE_TILING", FALSE); - if (force_tiling) { + if (force_tiling && permit_hardware_blit(screen, templ)) { if (!(templ->flags & R600_RESOURCE_FLAG_TRANSFER) && !(templ->bind & PIPE_BIND_SCANOUT)) { array_mode = V_038000_ARRAY_2D_TILED_THIN1; @@ -485,46 +527,6 @@ static INLINE unsigned u_box_volume( const struct pipe_box *box ) return box->width * box->depth * box->height; }; - -/* Figure out whether u_blitter will fallback to a transfer operation. - * If so, don't use a staging resource. - */ -static boolean permit_hardware_blit(struct pipe_screen *screen, - struct pipe_resource *res) -{ - unsigned bind; - - if (util_format_is_depth_or_stencil(res->format)) - bind = PIPE_BIND_DEPTH_STENCIL; - else - bind = PIPE_BIND_RENDER_TARGET; - - /* See r600_resource_copy_region: there is something wrong - * with depth resource copies at the moment so avoid them for - * now. - */ - if (util_format_get_component_bits(res->format, - UTIL_FORMAT_COLORSPACE_ZS, - 0) != 0) - return FALSE; - - if (!screen->is_format_supported(screen, - res->format, - res->target, - res->nr_samples, - bind, 0)) - return FALSE; - - if (!screen->is_format_supported(screen, - res->format, - res->target, - res->nr_samples, - PIPE_BIND_SAMPLER_VIEW, 0)) - return FALSE; - - return TRUE; -} - struct pipe_transfer* r600_texture_get_transfer(struct pipe_context *ctx, struct pipe_resource *texture, unsigned level, @@ -794,7 +796,7 @@ static unsigned r600_get_swizzle_combined(const unsigned char *swizzle_format, /* texture format translate */ uint32_t r600_translate_texformat(enum pipe_format format, - const unsigned char *swizzle_view, + const unsigned char *swizzle_view, uint32_t *word4_p, uint32_t *yuv_format_p) { uint32_t result = 0, word4 = 0, yuv_format = 0; @@ -848,7 +850,7 @@ uint32_t r600_translate_texformat(enum pipe_format format, break; } goto out_unknown; /* TODO */ - + case UTIL_FORMAT_COLORSPACE_SRGB: word4 |= S_038010_FORCE_DEGAMMA(1); if (format == PIPE_FORMAT_L8A8_SRGB || format == PIPE_FORMAT_L8_SRGB) @@ -864,7 +866,7 @@ uint32_t r600_translate_texformat(enum pipe_format format, static int r600_enable_s3tc = -1; if (r600_enable_s3tc == -1) - r600_enable_s3tc = + r600_enable_s3tc = debug_get_bool_option("R600_ENABLE_S3TC", FALSE); if (!r600_enable_s3tc) @@ -887,7 +889,7 @@ uint32_t r600_translate_texformat(enum pipe_format format, } - for (i = 0; i < desc->nr_channels; i++) { + for (i = 0; i < desc->nr_channels; i++) { if (desc->channel[i].type == UTIL_FORMAT_TYPE_SIGNED) { word4 |= sign_bit[i]; } @@ -901,7 +903,7 @@ uint32_t r600_translate_texformat(enum pipe_format format, for (i = 1; i < desc->nr_channels; i++) { uniform = uniform && desc->channel[0].size == desc->channel[i].size; } - + /* Non-uniform formats. */ if (!uniform) { switch(desc->nr_channels) { @@ -1019,7 +1021,7 @@ uint32_t r600_translate_texformat(enum pipe_format format, goto out_word4; } } - + } out_word4: if (word4_p) diff --git a/src/gallium/drivers/r600/r600_video_context.c b/src/gallium/drivers/r600/r600_video_context.c new file mode 100644 index 00000000000..b3885db0f55 --- /dev/null +++ b/src/gallium/drivers/r600/r600_video_context.c @@ -0,0 +1,21 @@ +#include "r600_video_context.h" +#include <softpipe/sp_video_context.h> + +struct pipe_video_context * +r600_video_create(struct pipe_screen *screen, enum pipe_video_profile profile, + enum pipe_video_chroma_format chroma_format, + unsigned width, unsigned height, void *priv) +{ + struct pipe_context *pipe; + + assert(screen); + + pipe = screen->context_create(screen, priv); + if (!pipe) + return NULL; + + return sp_video_create_ex(pipe, profile, chroma_format, width, height, + VL_MPEG12_MC_RENDERER_BUFFER_PICTURE, + true, + PIPE_FORMAT_VUYX); +} diff --git a/src/gallium/drivers/r600/r600_video_context.h b/src/gallium/drivers/r600/r600_video_context.h new file mode 100644 index 00000000000..bda33a00d44 --- /dev/null +++ b/src/gallium/drivers/r600/r600_video_context.h @@ -0,0 +1,11 @@ +#ifndef __R600_VIDEO_CONTEXT_H__ +#define __R600_VIDEO_CONTEXT_H__ + +#include <pipe/p_video_context.h> + +struct pipe_video_context * +r600_video_create(struct pipe_screen *screen, enum pipe_video_profile profile, + enum pipe_video_chroma_format chroma_format, + unsigned width, unsigned height, void *priv); + +#endif |