diff options
author | Dave Airlie <[email protected]> | 2010-09-08 14:09:40 +1000 |
---|---|---|
committer | Dave Airlie <[email protected]> | 2010-09-08 14:12:21 +1000 |
commit | bf346f065c65e15e5757d5b1a14dbc6638051860 (patch) | |
tree | eaa1e5bdec0cce3c5e38d4a7a218fa755a9ef8cb /src/gallium/drivers/r600 | |
parent | 48e789d71e01b0a7185555735b4a26b1a53d0825 (diff) |
r600g: add initial bank swizzle support.
this is ported from r600c mostly, bank swizzling is real messy and I don't think
I got enough sleep last night to fully understand it.
Diffstat (limited to 'src/gallium/drivers/r600')
-rw-r--r-- | src/gallium/drivers/r600/r600_asm.c | 276 | ||||
-rw-r--r-- | src/gallium/drivers/r600/r600_asm.h | 7 | ||||
-rw-r--r-- | src/gallium/drivers/r600/r600_sq.h | 12 | ||||
-rw-r--r-- | src/gallium/drivers/r600/r700_asm.c | 4 |
4 files changed, 295 insertions, 4 deletions
diff --git a/src/gallium/drivers/r600/r600_asm.c b/src/gallium/drivers/r600/r600_asm.c index 13a44c8d0e3..0ed177c66bd 100644 --- a/src/gallium/drivers/r600/r600_asm.c +++ b/src/gallium/drivers/r600/r600_asm.c @@ -28,6 +28,57 @@ #include <stdio.h> #include <errno.h> +static inline unsigned int r600_bc_get_num_operands(struct r600_bc_alu *alu) +{ + if(alu->is_op3) + return 3; + + switch (alu->inst) { + case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP: + return 0; + case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_ADD: + case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLE: + case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLGT: + case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLGE: + case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLNE: + case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MUL: + case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MAX: + case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MIN: + case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_SETE: + case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_SETNE: + case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_SETGT: + case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_SETGE: + case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETE: + case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETGT: + case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETGE: + case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETNE: + case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_DOT4: + case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_DOT4_IEEE: + case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_CUBE: + return 2; + + case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MOV: + case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MOVA_FLOOR: + case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_FRACT: + case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_FLOOR: + case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_TRUNC: + case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_EXP_IEEE: + case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_LOG_CLAMPED: + case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_LOG_IEEE: + case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_RECIP_IEEE: + case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_RECIPSQRT_IEEE: + case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_FLT_TO_INT: + case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_SIN: + case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_COS: + return 1; + + default: R600_ERR( + "Need instruction operand number for 0x%x.\n", alu->inst); + }; + + return 3; +} + int r700_bc_alu_build(struct r600_bc *bc, struct r600_bc_alu *alu, unsigned id); static struct r600_bc_cf *r600_bc_cf(void) @@ -50,6 +101,7 @@ static struct r600_bc_alu *r600_bc_alu(void) if (alu == NULL) return NULL; LIST_INITHEAD(&alu->list); + LIST_INITHEAD(&alu->bs_list); return alu; } @@ -129,10 +181,219 @@ int r600_bc_add_output(struct r600_bc *bc, const struct r600_bc_output *output) return 0; } +const unsigned bank_swizzle_vec[8] = {SQ_ALU_VEC_210, //000 + SQ_ALU_VEC_120, //001 + SQ_ALU_VEC_102, //010 + + SQ_ALU_VEC_201, //011 + SQ_ALU_VEC_012, //100 + SQ_ALU_VEC_021, //101 + + SQ_ALU_VEC_012, //110 + SQ_ALU_VEC_012}; //111 + +const unsigned bank_swizzle_scl[8] = {SQ_ALU_SCL_210, //000 + SQ_ALU_SCL_122, //001 + SQ_ALU_SCL_122, //010 + + SQ_ALU_SCL_221, //011 + SQ_ALU_SCL_212, //100 + SQ_ALU_SCL_122, //101 + + SQ_ALU_SCL_122, //110 + SQ_ALU_SCL_122}; //111 + +static int init_gpr(struct r600_bc_alu *alu) +{ + int cycle, component; + /* set up gpr use */ + for (cycle = 0; cycle < NUM_OF_CYCLES; cycle++) + for (component = 0; component < NUM_OF_COMPONENTS; component++) + alu->hw_gpr[cycle][component] = -1; + return 0; +} + +static int reserve_gpr(struct r600_bc_alu *alu, unsigned sel, unsigned chan, unsigned cycle) +{ + if (alu->hw_gpr[cycle][chan] < 0) + alu->hw_gpr[cycle][chan] = sel; + else if (alu->hw_gpr[cycle][chan] != (int)sel) { + R600_ERR("Another scalar operation has already used GPR read port for channel\n"); + return -1; + } + return 0; +} + +static int cycle_for_scalar_bank_swizzle(const int swiz, const int sel, unsigned *p_cycle) +{ + int table[3]; + int ret = 0; + switch (swiz) { + case SQ_ALU_SCL_210: + table[0] = 2; table[1] = 1; table[2] = 0; + *p_cycle = table[sel]; + break; + case SQ_ALU_SCL_122: + table[0] = 1; table[1] = 2; table[2] = 2; + *p_cycle = table[sel]; + break; + case SQ_ALU_SCL_212: + table[0] = 2; table[1] = 1; table[2] = 2; + *p_cycle = table[sel]; + break; + case SQ_ALU_SCL_221: + table[0] = 2; table[1] = 2; table[2] = 1; + *p_cycle = table[sel]; + break; + break; + default: + R600_ERR("bad scalar bank swizzle value\n"); + ret = -1; + break; + } + return ret; +} + +static int cycle_for_vector_bank_swizzle(const int swiz, const int sel, unsigned *p_cycle) +{ + int table[3]; + int ret; + + switch (swiz) { + case SQ_ALU_VEC_012: + table[0] = 0; table[1] = 1; table[2] = 2; + *p_cycle = table[sel]; + break; + case SQ_ALU_VEC_021: + table[0] = 0; table[1] = 2; table[2] = 1; + *p_cycle = table[sel]; + break; + case SQ_ALU_VEC_120: + table[0] = 1; table[1] = 2; table[2] = 0; + *p_cycle = table[sel]; + break; + case SQ_ALU_VEC_102: + table[0] = 1; table[1] = 0; table[2] = 2; + *p_cycle = table[sel]; + break; + case SQ_ALU_VEC_201: + table[0] = 2; table[1] = 0; table[2] = 1; + *p_cycle = table[sel]; + break; + case SQ_ALU_VEC_210: + table[0] = 2; table[1] = 1; table[2] = 0; + *p_cycle = table[sel]; + break; + default: + R600_ERR("bad vector bank swizzle value\n"); + ret = -1; + break; + } + return ret; +} + +static int is_const(int sel) +{ + if (sel > 255 && sel < 512) + return 1; + if (sel >= V_SQ_ALU_SRC_0 && sel <= V_SQ_ALU_SRC_LITERAL) + return 1; + return 0; +} + +static void update_chan_counter(struct r600_bc_alu *alu, int *chan_counter) +{ + int num_src; + int i; + int channel_swizzle; + + num_src = r600_bc_get_num_operands(alu); + + for (i = 0; i < num_src; i++) { + channel_swizzle = alu->src[i].chan; + if ((alu->src[i].sel > 0 && alu->src[i].sel < 128) && channel_swizzle <= 3) + chan_counter[channel_swizzle]++; + } +} + +#if 0 +/* we need something like this I think - but this is bogus */ +int check_read_slots(struct r600_bc *bc, struct r600_bc_alu *alu_first) +{ + struct r600_bc_alu *alu; + int chan_counter[4] = { 0 }; + + update_chan_counter(alu_first, chan_counter); + + LIST_FOR_EACH_ENTRY(alu, &alu_first->bs_list, bs_list) { + update_chan_counter(alu, chan_counter); + } + + if (chan_counter[0] > 3 || + chan_counter[1] > 3 || + chan_counter[2] > 3 || + chan_counter[3] > 3) { + R600_ERR("needed to split instruction for input ran out of banks %x %d %d %d %d\n", + alu_first->inst, chan_counter[0], chan_counter[1], chan_counter[2], chan_counter[3]); + return -1; + } + return 0; +} +#endif + +static int check_scalar(struct r600_bc *bc, struct r600_bc_alu *alu) +{ + unsigned swizzle_key; + + swizzle_key = (is_const(alu->src[0].sel) ? 4 : 0 ) + + (is_const(alu->src[1].sel) ? 2 : 0 ) + + (is_const(alu->src[2].sel) ? 1 : 0 ); + + alu->bank_swizzle = bank_swizzle_scl[swizzle_key]; + return 0; +} + +static int check_vector(struct r600_bc *bc, struct r600_bc_alu *alu) +{ + unsigned swizzle_key; + + swizzle_key = (is_const(alu->src[0].sel) ? 4 : 0 ) + + (is_const(alu->src[1].sel) ? 2 : 0 ) + + (is_const(alu->src[2].sel) ? 1 : 0 ); + + alu->bank_swizzle = bank_swizzle_vec[swizzle_key]; + return 0; +} + +static int check_and_set_bank_swizzle(struct r600_bc *bc, struct r600_bc_alu *alu_first) +{ + struct r600_bc_alu *alu; + int num_instr = 1; + + init_gpr(alu_first); + + LIST_FOR_EACH_ENTRY(alu, &alu_first->bs_list, bs_list) { + num_instr++; + } + + if (num_instr == 1) { + check_scalar(bc, alu_first); + + } else { +/* check_read_slots(bc, bc->cf_last->curr_bs_head);*/ + check_vector(bc, alu_first); + LIST_FOR_EACH_ENTRY(alu, &alu_first->bs_list, bs_list) { + check_vector(bc, alu); + } + } + return 0; +} + int r600_bc_add_alu_type(struct r600_bc *bc, const struct r600_bc_alu *alu, int type) { struct r600_bc_alu *nalu = r600_bc_alu(); struct r600_bc_alu *lalu; + struct r600_bc_alu *curr_bs_head; int i, r; if (nalu == NULL) @@ -151,6 +412,12 @@ int r600_bc_add_alu_type(struct r600_bc *bc, const struct r600_bc_alu *alu, int } bc->cf_last->inst = (type << 3); } + if (!bc->cf_last->curr_bs_head) { + bc->cf_last->curr_bs_head = nalu; + LIST_INITHEAD(&nalu->bs_list); + } else { + LIST_ADDTAIL(&nalu->bs_list, &bc->cf_last->curr_bs_head->bs_list); + } if (alu->last && (bc->cf_last->ndw >> 1) >= 124) { bc->force_add_cf = 1; } @@ -185,6 +452,11 @@ int r600_bc_add_alu_type(struct r600_bc *bc, const struct r600_bc_alu *alu, int if (bc->use_mem_constant) bc->cf_last->kcache0_mode = 2; + /* process cur ALU instructions for bank swizzle */ + if (alu->last) { + check_and_set_bank_swizzle(bc, bc->cf_last->curr_bs_head); + bc->cf_last->curr_bs_head = NULL; + } return 0; } @@ -365,7 +637,7 @@ static int r600_bc_alu_build(struct r600_bc *bc, struct r600_bc_alu *alu, unsign S_SQ_ALU_WORD1_OP3_SRC2_CHAN(alu->src[2].chan) | S_SQ_ALU_WORD1_OP3_SRC2_NEG(alu->src[2].neg) | S_SQ_ALU_WORD1_OP3_ALU_INST(alu->inst) | - S_SQ_ALU_WORD1_BANK_SWIZZLE(0); + S_SQ_ALU_WORD1_BANK_SWIZZLE(alu->bank_swizzle); } else { bc->bytecode[id++] = S_SQ_ALU_WORD1_DST_GPR(alu->dst.sel) | S_SQ_ALU_WORD1_DST_CHAN(alu->dst.chan) | @@ -375,7 +647,7 @@ static int r600_bc_alu_build(struct r600_bc *bc, struct r600_bc_alu *alu, unsign S_SQ_ALU_WORD1_OP2_SRC1_ABS(alu->src[1].abs) | S_SQ_ALU_WORD1_OP2_WRITE_MASK(alu->dst.write) | S_SQ_ALU_WORD1_OP2_ALU_INST(alu->inst) | - S_SQ_ALU_WORD1_BANK_SWIZZLE(0) | + S_SQ_ALU_WORD1_BANK_SWIZZLE(alu->bank_swizzle) | S_SQ_ALU_WORD1_OP2_UPDATE_EXECUTE_MASK(alu->predicate) | S_SQ_ALU_WORD1_OP2_UPDATE_PRED(alu->predicate); } diff --git a/src/gallium/drivers/r600/r600_asm.h b/src/gallium/drivers/r600/r600_asm.h index 0d75d99310e..d4b3463af59 100644 --- a/src/gallium/drivers/r600/r600_asm.h +++ b/src/gallium/drivers/r600/r600_asm.h @@ -26,6 +26,9 @@ #include "radeon.h" #include "util/u_double_list.h" +#define NUM_OF_CYCLES 3 +#define NUM_OF_COMPONENTS 4 + struct r600_bc_alu_src { unsigned sel; unsigned chan; @@ -44,6 +47,7 @@ struct r600_bc_alu_dst { struct r600_bc_alu { struct list_head list; + struct list_head bs_list; /* bank swizzle list */ struct r600_bc_alu_src src[3]; struct r600_bc_alu_dst dst; unsigned inst; @@ -52,7 +56,9 @@ struct r600_bc_alu { unsigned predicate; unsigned nliteral; unsigned literal_added; + unsigned bank_swizzle; u32 value[4]; + int hw_gpr[NUM_OF_CYCLES][NUM_OF_COMPONENTS]; }; struct r600_bc_tex { @@ -125,6 +131,7 @@ struct r600_bc_cf { struct list_head tex; struct list_head vtx; struct r600_bc_output output; + struct r600_bc_alu *curr_bs_head; }; #define FC_NONE 0 diff --git a/src/gallium/drivers/r600/r600_sq.h b/src/gallium/drivers/r600/r600_sq.h index 1542059c039..d0f5726d251 100644 --- a/src/gallium/drivers/r600/r600_sq.h +++ b/src/gallium/drivers/r600/r600_sq.h @@ -455,4 +455,16 @@ #define V_SQ_REL_ABSOLUTE 0 #define V_SQ_REL_RELATIVE 1 + +#define SQ_ALU_VEC_012 0x00 +#define SQ_ALU_VEC_021 0x01 +#define SQ_ALU_VEC_120 0x02 +#define SQ_ALU_VEC_102 0x03 +#define SQ_ALU_VEC_201 0x04 +#define SQ_ALU_VEC_210 0x05 + +#define SQ_ALU_SCL_210 0x00000000 +#define SQ_ALU_SCL_122 0x00000001 +#define SQ_ALU_SCL_212 0x00000002 +#define SQ_ALU_SCL_221 0x00000003 #endif diff --git a/src/gallium/drivers/r600/r700_asm.c b/src/gallium/drivers/r600/r700_asm.c index aaeaff59636..7f7ce5a4bac 100644 --- a/src/gallium/drivers/r600/r700_asm.c +++ b/src/gallium/drivers/r600/r700_asm.c @@ -51,7 +51,7 @@ int r700_bc_alu_build(struct r600_bc *bc, struct r600_bc_alu *alu, unsigned id) S_SQ_ALU_WORD1_OP3_SRC2_CHAN(alu->src[2].chan) | S_SQ_ALU_WORD1_OP3_SRC2_NEG(alu->src[2].neg) | S_SQ_ALU_WORD1_OP3_ALU_INST(alu->inst) | - S_SQ_ALU_WORD1_BANK_SWIZZLE(0); + S_SQ_ALU_WORD1_BANK_SWIZZLE(alu->bank_swizzle); } else { bc->bytecode[id++] = S_SQ_ALU_WORD1_DST_GPR(alu->dst.sel) | S_SQ_ALU_WORD1_DST_CHAN(alu->dst.chan) | @@ -61,7 +61,7 @@ int r700_bc_alu_build(struct r600_bc *bc, struct r600_bc_alu *alu, unsigned id) S_SQ_ALU_WORD1_OP2_SRC1_ABS(alu->src[1].abs) | S_SQ_ALU_WORD1_OP2_WRITE_MASK(alu->dst.write) | S_SQ_ALU_WORD1_OP2_ALU_INST(alu->inst) | - S_SQ_ALU_WORD1_BANK_SWIZZLE(0) | + S_SQ_ALU_WORD1_BANK_SWIZZLE(alu->bank_swizzle) | S_SQ_ALU_WORD1_OP2_UPDATE_EXECUTE_MASK(alu->predicate) | S_SQ_ALU_WORD1_OP2_UPDATE_PRED(alu->predicate); } |