*/
#include <stdio.h>
#include <errno.h>
+#include <byteswap.h>
#include "util/u_format.h"
#include "util/u_memory.h"
#include "pipe/p_shader_tokens.h"
if(alu->is_op3)
return 3;
- switch (bc->chiprev) {
- case CHIPREV_R600:
- case CHIPREV_R700:
+ switch (bc->chip_class) {
+ case R600:
+ case R700:
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_ADD_INT:
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_MULHI_UINT:
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_RECIPSQRT_CLAMPED:
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_INT_TO_FLT:
case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_SIN:
case V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_COS:
return 1;
"Need instruction operand number for 0x%x.\n", alu->inst);
}
break;
- case CHIPREV_EVERGREEN:
+ case EVERGREEN:
+ case CAYMAN:
switch (alu->inst) {
case EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_NOP:
return 0;
case EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_ADD:
+ case EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_ADD_INT:
case EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLE:
case EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLGT:
case EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLGE:
case EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLNE:
case EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MUL:
+ case EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MULHI_UINT:
case EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MAX:
case EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MIN:
case EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_SETE:
case EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_RECIPSQRT_IEEE:
case EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_FLT_TO_INT:
case EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_FLT_TO_INT_FLOOR:
+ case EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_INT_TO_FLT:
case EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_SIN:
case EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_COS:
return 1;
return tex;
}
-int r600_bc_init(struct r600_bc *bc, enum radeon_family family)
+void r600_bc_init(struct r600_bc *bc, enum chip_class chip_class)
{
LIST_INITHEAD(&bc->cf);
- bc->family = family;
- switch (bc->family) {
- case CHIP_R600:
- case CHIP_RV610:
- case CHIP_RV630:
- case CHIP_RV670:
- case CHIP_RV620:
- case CHIP_RV635:
- case CHIP_RS780:
- case CHIP_RS880:
- bc->chiprev = CHIPREV_R600;
- break;
- case CHIP_RV770:
- case CHIP_RV730:
- case CHIP_RV710:
- case CHIP_RV740:
- bc->chiprev = CHIPREV_R700;
- break;
- case CHIP_CEDAR:
- case CHIP_REDWOOD:
- case CHIP_JUNIPER:
- case CHIP_CYPRESS:
- case CHIP_HEMLOCK:
- case CHIP_PALM:
- case CHIP_BARTS:
- case CHIP_TURKS:
- case CHIP_CAICOS:
- bc->chiprev = CHIPREV_EVERGREEN;
- break;
- default:
- R600_ERR("unknown family %d\n", bc->family);
- return -EINVAL;
- }
- return 0;
+ bc->chip_class = chip_class;
}
static int r600_bc_add_cf(struct r600_bc *bc)
{
int r;
+ if (bc->cf_last && (bc->cf_last->inst == output->inst ||
+ (bc->cf_last->inst == BC_INST(bc, V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT) &&
+ output->inst == BC_INST(bc, V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT_DONE))) &&
+ output->type == bc->cf_last->output.type &&
+ output->elem_size == bc->cf_last->output.elem_size &&
+ output->swizzle_x == bc->cf_last->output.swizzle_x &&
+ output->swizzle_y == bc->cf_last->output.swizzle_y &&
+ output->swizzle_z == bc->cf_last->output.swizzle_z &&
+ output->swizzle_w == bc->cf_last->output.swizzle_w &&
+ (output->burst_count + bc->cf_last->output.burst_count) <= 16) {
+
+ if ((output->gpr + output->burst_count) == bc->cf_last->output.gpr &&
+ (output->array_base + output->burst_count) == bc->cf_last->output.array_base) {
+
+ bc->cf_last->output.end_of_program |= output->end_of_program;
+ bc->cf_last->output.inst = output->inst;
+ bc->cf_last->output.gpr = output->gpr;
+ bc->cf_last->output.array_base = output->array_base;
+ bc->cf_last->output.burst_count += output->burst_count;
+ return 0;
+
+ } else if (output->gpr == (bc->cf_last->output.gpr + bc->cf_last->output.burst_count) &&
+ output->array_base == (bc->cf_last->output.array_base + bc->cf_last->output.burst_count)) {
+
+ bc->cf_last->output.end_of_program |= output->end_of_program;
+ bc->cf_last->output.inst = output->inst;
+ bc->cf_last->output.burst_count += output->burst_count;
+ return 0;
+ }
+ }
+
r = r600_bc_add_cf(bc);
if (r)
return r;
/* alu instructions that can ony exits once per group */
static int is_alu_once_inst(struct r600_bc *bc, struct r600_bc_alu *alu)
{
- switch (bc->chiprev) {
- case CHIPREV_R600:
- case CHIPREV_R700:
+ switch (bc->chip_class) {
+ case R600:
+ case 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_PRED_SETNE_PUSH_INT ||
alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETLT_PUSH_INT ||
alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_PRED_SETLE_PUSH_INT);
- case CHIPREV_EVERGREEN:
+ case EVERGREEN:
+ case CAYMAN:
default:
return !alu->is_op3 && (
alu->inst == EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_KILLE ||
static int is_alu_reduction_inst(struct r600_bc *bc, struct r600_bc_alu *alu)
{
- switch (bc->chiprev) {
- case CHIPREV_R600:
- case CHIPREV_R700:
+ switch (bc->chip_class) {
+ case R600:
+ case R700:
return !alu->is_op3 && (
alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_CUBE ||
alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_DOT4 ||
alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_DOT4_IEEE ||
alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MAX4);
- case CHIPREV_EVERGREEN:
+ case EVERGREEN:
+ case CAYMAN:
default:
return !alu->is_op3 && (
alu->inst == EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_CUBE ||
}
}
+static int is_alu_cube_inst(struct r600_bc *bc, struct r600_bc_alu *alu)
+{
+ switch (bc->chip_class) {
+ case R600:
+ case R700:
+ return !alu->is_op3 &&
+ alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_CUBE;
+ case EVERGREEN:
+ case CAYMAN:
+ default:
+ return !alu->is_op3 &&
+ alu->inst == EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_CUBE;
+ }
+}
+
static int is_alu_mova_inst(struct r600_bc *bc, struct r600_bc_alu *alu)
{
- switch (bc->chiprev) {
- case CHIPREV_R600:
- case CHIPREV_R700:
+ switch (bc->chip_class) {
+ case R600:
+ case R700:
return !alu->is_op3 && (
alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MOVA ||
alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MOVA_FLOOR ||
alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MOVA_INT);
- case CHIPREV_EVERGREEN:
+ case EVERGREEN:
+ case CAYMAN:
default:
return !alu->is_op3 && (
alu->inst == EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MOVA_INT);
static int is_alu_vec_unit_inst(struct r600_bc *bc, struct r600_bc_alu *alu)
{
return is_alu_reduction_inst(bc, alu) ||
- is_alu_mova_inst(bc, alu);
+ is_alu_mova_inst(bc, alu) ||
+ (bc->chip_class == EVERGREEN &&
+ alu->inst == EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_FLT_TO_INT_FLOOR);
}
/* alu instructions that can only execute on the trans unit */
static int is_alu_trans_unit_inst(struct r600_bc *bc, struct r600_bc_alu *alu)
{
- switch (bc->chiprev) {
- case CHIPREV_R600:
- case CHIPREV_R700:
+ switch (bc->chip_class) {
+ case R600:
+ case R700:
if (!alu->is_op3)
return alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_ASHR_INT ||
alu->inst == V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_FLT_TO_INT ||
alu->inst == V_SQ_ALU_WORD1_OP3_SQ_OP3_INST_MUL_LIT_D2 ||
alu->inst == V_SQ_ALU_WORD1_OP3_SQ_OP3_INST_MUL_LIT_M2 ||
alu->inst == V_SQ_ALU_WORD1_OP3_SQ_OP3_INST_MUL_LIT_M4;
- case CHIPREV_EVERGREEN:
+ case EVERGREEN:
+ case CAYMAN:
default:
if (!alu->is_op3)
+ /* Note that FLT_TO_INT_* instructions are vector-only instructions
+ * on Evergreen, despite what the documentation says. FLT_TO_INT
+ * can do both vector and scalar. */
return alu->inst == EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_ASHR_INT ||
- alu->inst == EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_FLT_TO_INT ||
alu->inst == EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_INT_TO_FLT ||
alu->inst == EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_LSHL_INT ||
alu->inst == EG_V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_LSHR_INT ||
{
struct r600_bc_alu *alu;
unsigned i, chan, trans;
+ int max_slots = bc->chip_class == CAYMAN ? 4 : 5;
- for (i = 0; i < 5; i++)
+ for (i = 0; i < max_slots; i++)
assignment[i] = NULL;
for (alu = alu_first; alu; alu = LIST_ENTRY(struct r600_bc_alu, alu->list.next, list)) {
chan = alu->dst.chan;
- if (is_alu_trans_unit_inst(bc, alu))
+ if (max_slots == 4)
+ trans = 0;
+ else if (is_alu_trans_unit_inst(bc, alu))
trans = 1;
else if (is_alu_vec_unit_inst(bc, alu))
trans = 0;
else if (assignment[chan])
- trans = 1; // assume ALU_INST_PREFER_VECTOR
+ trans = 1; /* Assume ALU_INST_PREFER_VECTOR. */
else
trans = 0;
if (trans) {
if (assignment[4]) {
- assert(0); //ALU.Trans has already been allocated
+ assert(0); /* ALU.Trans has already been allocated. */
return -1;
}
assignment[4] = alu;
} else {
if (assignment[chan]) {
- assert(0); //ALU.chan has already been allocated
+ assert(0); /* ALU.chan has already been allocated. */
return -1;
}
assignment[chan] = alu;
int hw_cfile_elem[4];
};
-const unsigned cycle_for_bank_swizzle_vec[][3] = {
+static const unsigned cycle_for_bank_swizzle_vec[][3] = {
[SQ_ALU_VEC_012] = { 0, 1, 2 },
[SQ_ALU_VEC_021] = { 0, 2, 1 },
[SQ_ALU_VEC_120] = { 1, 2, 0 },
[SQ_ALU_VEC_210] = { 2, 1, 0 }
};
-const unsigned cycle_for_bank_swizzle_scl[][3] = {
+static const unsigned cycle_for_bank_swizzle_scl[][3] = {
[SQ_ALU_SCL_210] = { 2, 1, 0 },
[SQ_ALU_SCL_122] = { 1, 2, 2 },
[SQ_ALU_SCL_212] = { 2, 1, 2 },
if (bs->hw_gpr[cycle][chan] == -1)
bs->hw_gpr[cycle][chan] = sel;
else if (bs->hw_gpr[cycle][chan] != (int)sel) {
- // Another scalar operation has already used GPR read port for channel
+ /* Another scalar operation has already used the GPR read port for the channel. */
return -1;
}
return 0;
static int reserve_cfile(struct r600_bc *bc, struct alu_bank_swizzle *bs, unsigned sel, unsigned chan)
{
int res, num_res = 4;
- if (bc->chiprev >= CHIPREV_R700) {
+ if (bc->chip_class >= R700) {
num_res = 2;
chan /= 2;
}
return 0;
} else if (bs->hw_cfile_addr[res] == sel &&
bs->hw_cfile_elem[res] == chan)
- return 0; // Read for this scalar element already reserved, nothing to do here.
+ return 0; /* Read for this scalar element already reserved, nothing to do here. */
}
- // All cfile read ports are used, cannot reference vector element
+ /* All cfile read ports are used, cannot reference vector element. */
return -1;
}
static int is_cfile(unsigned sel)
{
return (sel > 255 && sel < 512) ||
- (sel > 511 && sel < 4607) || // Kcache before translate
- (sel > 127 && sel < 192); // Kcache after translate
+ (sel > 511 && sel < 4607) || /* Kcache before translation. */
+ (sel > 127 && sel < 192); /* Kcache after translation. */
}
static int is_const(int sel)
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,
- // second source uses first source’s reservation
+ /* Nothing to do; special-case optimization,
+ * second source uses first source’s reservation. */
continue;
else {
r = reserve_gpr(bs, sel, elem, cycle);
if (r)
return r;
}
- // No restrictions on PV, PS, literal or special constants
+ /* No restrictions on PV, PS, literal or special constants. */
}
return 0;
}
for (const_count = 0, src = 0; src < num_src; ++src) {
sel = alu->src[src].sel;
elem = alu->src[src].chan;
- if (is_const(sel)) { // Any constant, including literal and inline constants
+ if (is_const(sel)) { /* Any constant, including literal and inline constants. */
if (const_count >= 2)
- // More than two references to a constant in
- // transcendental operation.
+ /* More than two references to a constant in
+ * transcendental operation. */
return -1;
else
const_count++;
if (is_gpr(sel)) {
cycle = cycle_for_bank_swizzle_scl[bank_swizzle][src];
if (cycle < const_count)
- // Cycle for GPR load conflicts with
- // constant load in transcendental operation.
+ /* Cycle for GPR load conflicts with
+ * constant load in transcendental operation. */
return -1;
r = reserve_gpr(bs, sel, elem, cycle);
if (r)
return r;
}
- // Constants already processed
- // No restrictions on PV, PS
+ /* PV PS restrictions */
+ if (const_count && (sel == 254 || sel == 255)) {
+ cycle = cycle_for_bank_swizzle_scl[bank_swizzle][src];
+ if (cycle < const_count)
+ return -1;
+ }
}
return 0;
}
struct alu_bank_swizzle bs;
int bank_swizzle[5];
int i, r = 0, forced = 0;
+ boolean scalar_only = bc->chip_class == CAYMAN ? false : true;
+ int max_slots = bc->chip_class == CAYMAN ? 4 : 5;
- for (i = 0; i < 5; i++)
+ for (i = 0; i < max_slots; i++) {
if (slots[i] && slots[i]->bank_swizzle_force) {
slots[i]->bank_swizzle = slots[i]->bank_swizzle_force;
forced = 1;
}
-
+ if (i < 4 && slots[i])
+ scalar_only = false;
+ }
if (forced)
return 0;
- // just check every possible combination of bank swizzle
- // not very efficent, but works on the first try in most of the cases
+ /* Just check every possible combination of bank swizzle.
+ * Not very efficent, but works on the first try in most of the cases. */
for (i = 0; i < 4; i++)
bank_swizzle[i] = SQ_ALU_VEC_012;
bank_swizzle[4] = SQ_ALU_SCL_210;
while(bank_swizzle[4] <= SQ_ALU_SCL_221) {
- init_bank_swizzle(&bs);
- for (i = 0; i < 4; i++) {
- if (slots[i]) {
- r = check_vector(bc, slots[i], &bs, bank_swizzle[i]);
- if (r)
- break;
+
+ if (max_slots == 4) {
+ for (i = 0; i < max_slots; i++) {
+ if (bank_swizzle[i] == SQ_ALU_VEC_210)
+ return -1;
}
}
- if (!r && slots[4]) {
+ init_bank_swizzle(&bs);
+ if (scalar_only == false) {
+ for (i = 0; i < 4; i++) {
+ if (slots[i]) {
+ r = check_vector(bc, slots[i], &bs, bank_swizzle[i]);
+ if (r)
+ break;
+ }
+ }
+ } else
+ r = 0;
+
+ if (!r && slots[4] && max_slots == 5) {
r = check_scalar(bc, slots[4], &bs, bank_swizzle[4]);
}
if (!r) {
- for (i = 0; i < 5; i++) {
+ for (i = 0; i < max_slots; i++) {
if (slots[i])
slots[i]->bank_swizzle = bank_swizzle[i];
}
return 0;
}
- for (i = 0; i < 5; i++) {
- bank_swizzle[i]++;
- if (bank_swizzle[i] <= SQ_ALU_VEC_210)
- break;
- else
- bank_swizzle[i] = SQ_ALU_VEC_012;
+ if (scalar_only) {
+ bank_swizzle[4]++;
+ } else {
+ for (i = 0; i < max_slots; i++) {
+ bank_swizzle[i]++;
+ if (bank_swizzle[i] <= SQ_ALU_VEC_210)
+ break;
+ else
+ bank_swizzle[i] = SQ_ALU_VEC_012;
+ }
}
}
- // couldn't find a working swizzle
+ /* Couldn't find a working swizzle. */
return -1;
}
struct r600_bc_alu *prev[5];
int gpr[5], chan[5];
int i, j, r, src, num_src;
+ int max_slots = bc->chip_class == CAYMAN ? 4 : 5;
r = assign_alu_units(bc, alu_prev, prev);
if (r)
return r;
- for (i = 0; i < 5; ++i) {
+ for (i = 0; i < max_slots; ++i) {
if(prev[i] && prev[i]->dst.write && !prev[i]->dst.rel) {
gpr[i] = prev[i]->dst.sel;
- if (is_alu_reduction_inst(bc, prev[i]))
+ /* cube writes more than PV.X */
+ if (!is_alu_cube_inst(bc, prev[i]) && is_alu_reduction_inst(bc, prev[i]))
chan[i] = 0;
else
chan[i] = prev[i]->dst.chan;
gpr[i] = -1;
}
- for (i = 0; i < 5; ++i) {
+ for (i = 0; i < max_slots; ++i) {
struct r600_bc_alu *alu = slots[i];
if(!alu)
continue;
if (!is_gpr(alu->src[src].sel) || alu->src[src].rel)
continue;
- if (alu->src[src].sel == gpr[4] &&
- alu->src[src].chan == chan[4]) {
- alu->src[src].sel = V_SQ_ALU_SRC_PS;
- alu->src[src].chan = 0;
- continue;
+ if (bc->chip_class < CAYMAN) {
+ if (alu->src[src].sel == gpr[4] &&
+ alu->src[src].chan == chan[4]) {
+ alu->src[src].sel = V_SQ_ALU_SRC_PS;
+ alu->src[src].chan = 0;
+ continue;
+ }
}
for (j = 0; j < 4; ++j) {
case -1:
*sel = V_SQ_ALU_SRC_M_1_INT;
break;
- case 0x3F800000: // 1.0f
+ case 0x3F800000: /* 1.0f */
*sel = V_SQ_ALU_SRC_1;
break;
- case 0x3F000000: // 0.5f
+ case 0x3F000000: /* 0.5f */
*sel = V_SQ_ALU_SRC_0_5;
break;
- case 0xBF800000: // -1.0f
+ case 0xBF800000: /* -1.0f */
*sel = V_SQ_ALU_SRC_1;
*neg ^= 1;
break;
- case 0xBF000000: // -0.5f
+ case 0xBF000000: /* -0.5f */
*sel = V_SQ_ALU_SRC_0_5;
*neg ^= 1;
break;
for (i = 0; i < num_src; ++i) {
if (alu->src[i].sel == V_SQ_ALU_SRC_LITERAL) {
- uint32_t value = alu->src[i].value[alu->src[i].chan];
+ uint32_t value = alu->src[i].value;
unsigned found = 0;
for (j = 0; j < *nliteral; ++j) {
if (literal[j] == value) {
for (i = 0; i < num_src; ++i) {
if (alu->src[i].sel == V_SQ_ALU_SRC_LITERAL) {
- uint32_t value = alu->src[i].value[alu->src[i].chan];
+ uint32_t value = alu->src[i].value;
for (j = 0; j < nliteral; ++j) {
if (literal[j] == value) {
alu->src[i].chan = j;
int i, j, r, src, num_src;
int num_once_inst = 0;
int have_mova = 0, have_rel = 0;
+ int max_slots = bc->chip_class == CAYMAN ? 4 : 5;
r = assign_alu_units(bc, alu_prev, prev);
if (r)
return r;
- for (i = 0; i < 5; ++i) {
+ for (i = 0; i < max_slots; ++i) {
struct r600_bc_alu *alu;
/* check number of literals */
if (slots[i] && r600_bc_alu_nliterals(bc, slots[i], literal, &nliteral))
return 0;
- // let's check used slots
+ /* Let's check used slots. */
if (prev[i] && !slots[i]) {
result[i] = prev[i];
continue;
} else if (prev[i] && slots[i]) {
- if (result[4] == NULL && prev[4] == NULL && slots[4] == NULL) {
- // trans unit is still free try to use it
+ if (max_slots == 5 && result[4] == NULL && prev[4] == NULL && slots[4] == NULL) {
+ /* Trans unit is still free try to use it. */
if (is_alu_any_unit_inst(bc, slots[i])) {
result[i] = prev[i];
result[4] = slots[i];
} else
result[i] = slots[i];
- // let's check source gprs
alu = slots[i];
num_once_inst += is_alu_once_inst(bc, alu);
+ /* Let's check dst gpr. */
+ if (alu->dst.rel) {
+ if (have_mova)
+ return 0;
+ have_rel = 1;
+ }
+
+ /* Let's check source gprs */
num_src = r600_bc_get_num_operands(bc, alu);
for (src = 0; src < num_src; ++src) {
if (alu->src[src].rel) {
have_rel = 1;
}
- // constants doesn't matter
+ /* Constants don't matter. */
if (!is_gpr(alu->src[src].sel))
continue;
- for (j = 0; j < 5; ++j) {
+ for (j = 0; j < max_slots; ++j) {
if (!prev[j] || !prev[j]->dst.write)
continue;
- // if it's relative then we can't determin which gpr is really used
+ /* If it's relative then we can't determin which gpr is really used. */
if (prev[j]->dst.chan == alu->src[src].chan &&
(prev[j]->dst.sel == alu->src[src].sel ||
prev[j]->dst.rel || alu->src[src].rel))
bc->cf_last->ndw -= align(prev_nliteral, 2);
/* sort instructions */
- for (i = 0; i < 5; ++i) {
+ for (i = 0; i < max_slots; ++i) {
slots[i] = result[i];
if (result[i]) {
LIST_DEL(&result[i]->list);
LIST_ENTRY(struct r600_bc_alu, bc->cf_last->alu.prev, list)->last = 1;
/* determine new first instruction */
- for (i = 0; i < 5; ++i) {
+ for (i = 0; i < max_slots; ++i) {
if (result[i]) {
bc->cf_last->curr_bs_head = result[i];
break;
/* Collect required cache lines. */
for (i = 0; i < 3; ++i) {
- bool found = false;
+ boolean found = false;
unsigned int line;
if (alu->src[i].sel < 512)
/* Setup the kcache lines. */
for (i = 0; i < count; ++i) {
- bool found = false;
+ boolean found = false;
for (j = 0; j < 2; ++j) {
if (kcache[j].mode == V_SQ_CF_KCACHE_LOCK_2 &&
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],
+ r600_bc_special_constants(nalu->src[i].value,
&nalu->src[i].sel, &nalu->src[i].neg);
}
if (nalu->dst.sel >= bc->ngpr) {
uint32_t literal[4];
unsigned nliteral;
struct r600_bc_alu *slots[5];
+ int max_slots = bc->chip_class == CAYMAN ? 4 : 5;
r = assign_alu_units(bc, bc->cf_last->curr_bs_head, slots);
if (r)
return r;
if (r)
return r;
- for (i = 0, nliteral = 0; i < 5; i++) {
+ for (i = 0, nliteral = 0; i < max_slots; i++) {
if (slots[i]) {
r = r600_bc_alu_nliterals(bc, slots[i], literal, &nliteral);
if (r)
return r600_bc_add_alu_type(bc, alu, BC_INST(bc, V_SQ_CF_ALU_WORD1_SQ_CF_INST_ALU));
}
+static unsigned r600_bc_num_tex_and_vtx_instructions(const struct r600_bc *bc)
+{
+ switch (bc->chip_class) {
+ case R600:
+ return 8;
+
+ case R700:
+ return 16;
+
+ case EVERGREEN:
+ case CAYMAN:
+ return 64;
+
+ default:
+ R600_ERR("Unknown chip class %d.\n", bc->chip_class);
+ return 8;
+ }
+}
+
+static inline boolean last_inst_was_vtx_fetch(struct r600_bc *bc)
+{
+ if (bc->chip_class == CAYMAN) {
+ if (bc->cf_last->inst != CM_V_SQ_CF_WORD1_SQ_CF_INST_TC)
+ return TRUE;
+ } else {
+ if (bc->cf_last->inst != V_SQ_CF_WORD1_SQ_CF_INST_VTX &&
+ bc->cf_last->inst != V_SQ_CF_WORD1_SQ_CF_INST_VTX_TC)
+ return TRUE;
+ }
+ return FALSE;
+}
+
int r600_bc_add_vtx(struct r600_bc *bc, const struct r600_bc_vtx *vtx)
{
struct r600_bc_vtx *nvtx = r600_bc_vtx();
/* cf can contains only alu or only vtx or only tex */
if (bc->cf_last == NULL ||
- (bc->cf_last->inst != V_SQ_CF_WORD1_SQ_CF_INST_VTX &&
- bc->cf_last->inst != V_SQ_CF_WORD1_SQ_CF_INST_VTX_TC) ||
- bc->force_add_cf) {
+ last_inst_was_vtx_fetch(bc) ||
+ bc->force_add_cf) {
r = r600_bc_add_cf(bc);
if (r) {
free(nvtx);
return r;
}
- bc->cf_last->inst = V_SQ_CF_WORD1_SQ_CF_INST_VTX;
+ if (bc->chip_class == CAYMAN)
+ bc->cf_last->inst = CM_V_SQ_CF_WORD1_SQ_CF_INST_TC;
+ else
+ bc->cf_last->inst = V_SQ_CF_WORD1_SQ_CF_INST_VTX;
}
LIST_ADDTAIL(&nvtx->list, &bc->cf_last->vtx);
/* each fetch use 4 dwords */
bc->cf_last->ndw += 4;
bc->ndw += 4;
- if ((bc->cf_last->ndw / 4) > 7)
+ if ((bc->cf_last->ndw / 4) >= r600_bc_num_tex_and_vtx_instructions(bc))
bc->force_add_cf = 1;
return 0;
}
return -ENOMEM;
memcpy(ntex, tex, sizeof(struct r600_bc_tex));
+ /* we can't fetch data und use it as texture lookup address in the same TEX clause */
+ if (bc->cf_last != NULL &&
+ bc->cf_last->inst == V_SQ_CF_WORD1_SQ_CF_INST_TEX) {
+ struct r600_bc_tex *ttex;
+ LIST_FOR_EACH_ENTRY(ttex, &bc->cf_last->tex, list) {
+ if (ttex->dst_gpr == ntex->src_gpr) {
+ bc->force_add_cf = 1;
+ break;
+ }
+ }
+ /* slight hack to make gradients always go into same cf */
+ if (ntex->inst == SQ_TEX_INST_SET_GRADIENTS_H)
+ bc->force_add_cf = 1;
+ }
+
/* cf can contains only alu or only vtx or only tex */
if (bc->cf_last == NULL ||
bc->cf_last->inst != V_SQ_CF_WORD1_SQ_CF_INST_TEX ||
/* each texture fetch use 4 dwords */
bc->cf_last->ndw += 4;
bc->ndw += 4;
- if ((bc->cf_last->ndw / 4) > 7)
+ if ((bc->cf_last->ndw / 4) >= r600_bc_num_tex_and_vtx_instructions(bc))
bc->force_add_cf = 1;
return 0;
}
return 0;
}
+int cm_bc_add_cf_end(struct r600_bc *bc)
+{
+ return r600_bc_add_cfinst(bc, CM_V_SQ_CF_WORD1_SQ_CF_INST_END);
+}
+
/* common to all 3 families */
static int r600_bc_vtx_build(struct r600_bc *bc, struct r600_bc_vtx *vtx, unsigned id)
{
- unsigned fetch_resource_start = 0;
-
- /* check if we are fetch shader */
- /* fetch shader can also access vertex resource,
- * first fetch shader resource is at 160
- */
- if (bc->type == -1) {
- switch (bc->chiprev) {
- /* r600 */
- case CHIPREV_R600:
- /* r700 */
- case CHIPREV_R700:
- fetch_resource_start = 160;
- break;
- /* evergreen */
- case CHIPREV_EVERGREEN:
- fetch_resource_start = 0;
- break;
- default:
- fprintf(stderr, "%s:%s:%d unknown chiprev %d\n",
- __FILE__, __func__, __LINE__, bc->chiprev);
- break;
- }
- }
- bc->bytecode[id++] = S_SQ_VTX_WORD0_BUFFER_ID(vtx->buffer_id + fetch_resource_start) |
+ bc->bytecode[id] = S_SQ_VTX_WORD0_BUFFER_ID(vtx->buffer_id) |
+ S_SQ_VTX_WORD0_FETCH_TYPE(vtx->fetch_type) |
S_SQ_VTX_WORD0_SRC_GPR(vtx->src_gpr) |
- S_SQ_VTX_WORD0_SRC_SEL_X(vtx->src_sel_x) |
- S_SQ_VTX_WORD0_MEGA_FETCH_COUNT(vtx->mega_fetch_count);
+ S_SQ_VTX_WORD0_SRC_SEL_X(vtx->src_sel_x);
+ if (bc->chip_class < CAYMAN)
+ bc->bytecode[id] |= S_SQ_VTX_WORD0_MEGA_FETCH_COUNT(vtx->mega_fetch_count);
+ id++;
bc->bytecode[id++] = S_SQ_VTX_WORD1_DST_SEL_X(vtx->dst_sel_x) |
S_SQ_VTX_WORD1_DST_SEL_Y(vtx->dst_sel_y) |
S_SQ_VTX_WORD1_DST_SEL_Z(vtx->dst_sel_z) |
S_SQ_VTX_WORD1_FORMAT_COMP_ALL(vtx->format_comp_all) |
S_SQ_VTX_WORD1_SRF_MODE_ALL(vtx->srf_mode_all) |
S_SQ_VTX_WORD1_GPR_DST_GPR(vtx->dst_gpr);
- bc->bytecode[id++] = S_SQ_VTX_WORD2_MEGA_FETCH(1);
+ bc->bytecode[id] = S_SQ_VTX_WORD2_OFFSET(vtx->offset)|
+ S_SQ_VTX_WORD2_ENDIAN_SWAP(vtx->endian);
+ if (bc->chip_class < CAYMAN)
+ bc->bytecode[id] |= S_SQ_VTX_WORD2_MEGA_FETCH(1);
+ id++;
bc->bytecode[id++] = 0;
return 0;
}
return 0;
}
+static void r600_bc_cf_vtx_build(uint32_t *bytecode, const struct r600_bc_cf *cf)
+{
+ *bytecode++ = S_SQ_CF_WORD0_ADDR(cf->addr >> 1);
+ *bytecode++ = S_SQ_CF_WORD1_CF_INST(cf->inst) |
+ S_SQ_CF_WORD1_BARRIER(1) |
+ S_SQ_CF_WORD1_COUNT((cf->ndw / 4) - 1);
+}
+
/* common for r600/r700 - eg in eg_asm.c */
static int r600_bc_cf_build(struct r600_bc *bc, struct r600_bc_cf *cf)
{
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_USES_WATERFALL(bc->chip_class == 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:
- 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);
+ if (bc->chip_class == R700)
+ r700_bc_cf_vtx_build(&bc->bytecode[id], cf);
+ else
+ r600_bc_cf_vtx_build(&bc->bytecode[id], cf);
break;
case V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT:
case V_SQ_CF_ALLOC_EXPORT_WORD1_SQ_CF_INST_EXPORT_DONE:
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) |
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 CM_V_SQ_CF_WORD1_SQ_CF_INST_END:
break;
default:
R600_ERR("unsupported CF instruction (0x%X)\n", cf->inst);
return -ENOMEM;
LIST_FOR_EACH_ENTRY(cf, &bc->cf, list) {
addr = cf->addr;
- if (bc->chiprev == CHIPREV_EVERGREEN)
+ if (bc->chip_class >= EVERGREEN)
r = eg_bc_cf_build(bc, cf);
else
r = r600_bc_cf_build(bc, cf);
if (r)
return r;
r600_bc_alu_adjust_literals(bc, alu, literal, nliteral);
- switch(bc->chiprev) {
- case CHIPREV_R600:
+ switch(bc->chip_class) {
+ case R600:
r = r600_bc_alu_build(bc, alu, addr);
break;
- case CHIPREV_R700:
- case CHIPREV_EVERGREEN: /* eg alu is same encoding as r700 */
+ case R700:
+ case EVERGREEN: /* eg alu is same encoding as r700 */
+ case CAYMAN: /* eg alu is same encoding as r700 */
r = r700_bc_alu_build(bc, alu, addr);
break;
default:
- R600_ERR("unknown family %d\n", bc->family);
+ R600_ERR("unknown chip class %d.\n", bc->chip_class);
return -EINVAL;
}
if (r)
}
break;
case V_SQ_CF_WORD1_SQ_CF_INST_TEX:
+ if (bc->chip_class == CAYMAN) {
+ LIST_FOR_EACH_ENTRY(vtx, &cf->vtx, list) {
+ r = r600_bc_vtx_build(bc, vtx, addr);
+ if (r)
+ return r;
+ addr += 4;
+ }
+ }
LIST_FOR_EACH_ENTRY(tex, &cf->tex, list) {
r = r600_bc_tex_build(bc, tex, addr);
if (r)
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 CM_V_SQ_CF_WORD1_SQ_CF_INST_END:
break;
default:
R600_ERR("unsupported CF instruction (0x%X)\n", cf->inst);
unsigned nliteral;
char chip = '6';
- switch (bc->chiprev) {
- case 1:
+ switch (bc->chip_class) {
+ case R700:
chip = '7';
break;
- case 2:
+ case EVERGREEN:
chip = 'E';
break;
- case 0:
+ case CAYMAN:
+ chip = 'C';
+ break;
+ case R600:
default:
chip = '6';
break;
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:
fprintf(stderr, "%04d %08X EXPORT ", id, bc->bytecode[id]);
fprintf(stderr, "GPR:%X ", cf->output.gpr);
fprintf(stderr, "ELEM_SIZE:%X ", cf->output.elem_size);
fprintf(stderr, "SWIZ_Y:%X ", cf->output.swizzle_y);
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, "BURST_COUNT:%d ", cf->output.burst_count);
fprintf(stderr, "EOP:%X\n", cf->output.end_of_program);
break;
case V_SQ_CF_WORD1_SQ_CF_INST_JUMP:
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 CM_V_SQ_CF_WORD1_SQ_CF_INST_END:
fprintf(stderr, "%04d %08X CF ", id, bc->bytecode[id]);
fprintf(stderr, "ADDR:%d\n", cf->cf_addr);
id++;
}
LIST_FOR_EACH_ENTRY(tex, &cf->tex, list) {
- //TODO
+ fprintf(stderr, "%04d %08X ", id, bc->bytecode[id]);
+ fprintf(stderr, "INST:%d ", tex->inst);
+ fprintf(stderr, "RESOURCE_ID:%d ", tex->resource_id);
+ fprintf(stderr, "SRC(GPR:%d ", tex->src_gpr);
+ fprintf(stderr, "REL:%d)\n", tex->src_rel);
+ id++;
+ fprintf(stderr, "%04d %08X ", id, bc->bytecode[id]);
+ fprintf(stderr, "DST(GPR:%d ", tex->dst_gpr);
+ fprintf(stderr, "REL:%d ", tex->dst_rel);
+ fprintf(stderr, "SEL_X:%d ", tex->dst_sel_x);
+ fprintf(stderr, "SEL_Y:%d ", tex->dst_sel_y);
+ fprintf(stderr, "SEL_Z:%d ", tex->dst_sel_z);
+ fprintf(stderr, "SEL_W:%d) ", tex->dst_sel_w);
+ fprintf(stderr, "LOD_BIAS:%d ", tex->lod_bias);
+ fprintf(stderr, "COORD_TYPE_X:%d ", tex->coord_type_x);
+ fprintf(stderr, "COORD_TYPE_Y:%d ", tex->coord_type_y);
+ fprintf(stderr, "COORD_TYPE_Z:%d ", tex->coord_type_z);
+ fprintf(stderr, "COORD_TYPE_W:%d\n", tex->coord_type_w);
+ id++;
+ fprintf(stderr, "%04d %08X ", id, bc->bytecode[id]);
+ fprintf(stderr, "OFFSET_X:%d ", tex->offset_x);
+ fprintf(stderr, "OFFSET_Y:%d ", tex->offset_y);
+ fprintf(stderr, "OFFSET_Z:%d ", tex->offset_z);
+ fprintf(stderr, "SAMPLER_ID:%d ", tex->sampler_id);
+ fprintf(stderr, "SRC(SEL_X:%d ", tex->src_sel_x);
+ fprintf(stderr, "SEL_Y:%d ", tex->src_sel_y);
+ fprintf(stderr, "SEL_Z:%d ", tex->src_sel_z);
+ fprintf(stderr, "SEL_W:%d)\n", tex->src_sel_w);
+ id++;
+ fprintf(stderr, "%04d %08X \n", id, bc->bytecode[id]);
+ id++;
}
LIST_FOR_EACH_ENTRY(vtx, &cf->vtx, list) {
- //TODO
+ fprintf(stderr, "%04d %08X ", id, bc->bytecode[id]);
+ fprintf(stderr, "INST:%d ", vtx->inst);
+ fprintf(stderr, "FETCH_TYPE:%d ", vtx->fetch_type);
+ fprintf(stderr, "BUFFER_ID:%d\n", vtx->buffer_id);
+ id++;
+ /* This assumes that no semantic fetches exist */
+ fprintf(stderr, "%04d %08X ", id, bc->bytecode[id]);
+ fprintf(stderr, "SRC(GPR:%d ", vtx->src_gpr);
+ fprintf(stderr, "SEL_X:%d) ", vtx->src_sel_x);
+ if (bc->chip_class < CAYMAN)
+ fprintf(stderr, "MEGA_FETCH_COUNT:%d ", vtx->mega_fetch_count);
+ else
+ fprintf(stderr, "SEL_Y:%d) ", 0);
+ fprintf(stderr, "DST(GPR:%d ", vtx->dst_gpr);
+ fprintf(stderr, "SEL_X:%d ", vtx->dst_sel_x);
+ fprintf(stderr, "SEL_Y:%d ", vtx->dst_sel_y);
+ fprintf(stderr, "SEL_Z:%d ", vtx->dst_sel_z);
+ fprintf(stderr, "SEL_W:%d) ", vtx->dst_sel_w);
+ fprintf(stderr, "USE_CONST_FIELDS:%d ", vtx->use_const_fields);
+ fprintf(stderr, "FORMAT(DATA:%d ", vtx->data_format);
+ fprintf(stderr, "NUM:%d ", vtx->num_format_all);
+ fprintf(stderr, "COMP:%d ", vtx->format_comp_all);
+ fprintf(stderr, "MODE:%d)\n", vtx->srf_mode_all);
+ id++;
+ fprintf(stderr, "%04d %08X ", id, bc->bytecode[id]);
+ fprintf(stderr, "ENDIAN:%d ", vtx->endian);
+ fprintf(stderr, "OFFSET:%d\n", vtx->offset);
+ /* TODO */
+ id++;
+ fprintf(stderr, "%04d %08X \n", id, bc->bytecode[id]);
+ id++;
}
}
fprintf(stderr, "--------------------------------------\n");
}
-void r600_cf_vtx(struct r600_vertex_element *ve, u32 *bytecode, unsigned count)
-{
- struct r600_pipe_state *rstate;
- unsigned i = 0;
-
- 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_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_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_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);
-
- rstate = &ve->rstate;
- rstate->id = R600_PIPE_STATE_FETCH_SHADER;
- rstate->nregs = 0;
- r600_pipe_state_add_reg(rstate, R_0288A4_SQ_PGM_RESOURCES_FS,
- 0x00000000, 0xFFFFFFFF, NULL);
- r600_pipe_state_add_reg(rstate, R_0288DC_SQ_PGM_CF_OFFSET_FS,
- 0x00000000, 0xFFFFFFFF, NULL);
- r600_pipe_state_add_reg(rstate, R_028894_SQ_PGM_START_FS,
- r600_bo_offset(ve->fetch_shader) >> 8,
- 0xFFFFFFFF, ve->fetch_shader);
-}
-
-void r600_cf_vtx_tc(struct r600_vertex_element *ve, u32 *bytecode, unsigned count)
-{
- struct r600_pipe_state *rstate;
- unsigned i = 0;
-
- 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_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_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_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);
-
- rstate = &ve->rstate;
- rstate->id = R600_PIPE_STATE_FETCH_SHADER;
- rstate->nregs = 0;
- r600_pipe_state_add_reg(rstate, R_0288A4_SQ_PGM_RESOURCES_FS,
- 0x00000000, 0xFFFFFFFF, NULL);
- r600_pipe_state_add_reg(rstate, R_0288DC_SQ_PGM_CF_OFFSET_FS,
- 0x00000000, 0xFFFFFFFF, NULL);
- r600_pipe_state_add_reg(rstate, R_028894_SQ_PGM_START_FS,
- r600_bo_offset(ve->fetch_shader) >> 8,
- 0xFFFFFFFF, ve->fetch_shader);
-}
-
static void r600_vertex_data_type(enum pipe_format pformat, unsigned *format,
- unsigned *num_format, unsigned *format_comp)
+ unsigned *num_format, unsigned *format_comp, unsigned *endian)
{
const struct util_format_description *desc;
unsigned i;
*format = 0;
*num_format = 0;
*format_comp = 0;
+ *endian = ENDIAN_NONE;
desc = util_format_description(pformat);
if (desc->layout != UTIL_FORMAT_LAYOUT_PLAIN) {
}
}
+ *endian = r600_endian_swap(desc->channel[i].size);
+
switch (desc->channel[i].type) {
- /* Half-floats, floats, doubles */
+ /* Half-floats, floats, ints */
case UTIL_FORMAT_TYPE_FLOAT:
switch (desc->channel[i].size) {
case 16:
*format = FMT_16_16_FLOAT;
break;
case 3:
- *format = FMT_16_16_16_FLOAT;
- break;
case 4:
*format = FMT_16_16_16_16_FLOAT;
break;
*format = FMT_8_8;
break;
case 3:
- // *format = FMT_8_8_8; /* fails piglit draw-vertices test */
- // break;
case 4:
*format = FMT_8_8_8_8;
break;
*format = FMT_16_16;
break;
case 3:
- // *format = FMT_16_16_16; /* fails piglit draw-vertices test */
- // break;
case 4:
*format = FMT_16_16_16_16;
break;
int r600_vertex_elements_build_fetch_shader(struct r600_pipe_context *rctx, struct r600_vertex_element *ve)
{
- unsigned ndw, i;
- u32 *bytecode;
- unsigned fetch_resource_start = 0, format, num_format, format_comp;
+ static int dump_shaders = -1;
+
+ struct r600_bc bc;
+ struct r600_bc_vtx vtx;
struct pipe_vertex_element *elements = ve->elements;
const struct util_format_description *desc;
+ unsigned fetch_resource_start = rctx->chip_class >= EVERGREEN ? 0 : 160;
+ unsigned format, num_format, format_comp, endian;
+ u32 *bytecode;
+ int i, r;
- /* 2 dwords for cf aligned to 4 + 4 dwords per input */
- ndw = 8 + ve->count * 4;
- ve->fs_size = ndw * 4;
-
- /* use PIPE_BIND_VERTEX_BUFFER so we use the cache buffer manager */
- ve->fetch_shader = r600_bo(rctx->radeon, ndw*4, 256, PIPE_BIND_VERTEX_BUFFER, 0);
- if (ve->fetch_shader == NULL) {
- return -ENOMEM;
- }
-
- bytecode = r600_bo_map(rctx->radeon, ve->fetch_shader, 0, NULL);
- if (bytecode == NULL) {
- r600_bo_reference(rctx->radeon, &ve->fetch_shader, NULL);
- return -ENOMEM;
- }
-
- if (rctx->family >= CHIP_CEDAR) {
- eg_cf_vtx(ve, &bytecode[0], (ndw - 8) / 4);
- } else {
- r600_cf_vtx(ve, &bytecode[0], (ndw - 8) / 4);
- fetch_resource_start = 160;
- }
-
- /* vertex elements offset need special handling, if offset is bigger
- * than what we can put in fetch instruction then we need to alterate
- * the vertex resource offset. In such case in order to simplify code
- * we will bound one resource per elements. It's a worst case scenario.
- */
+ /* Vertex element offsets need special handling. If the offset is
+ * bigger than what we can put in the fetch instruction we need to
+ * alter the vertex resource offset. In order to simplify code we
+ * will bind one resource per element in such cases. It's a worst
+ * case scenario. */
for (i = 0; i < ve->count; i++) {
ve->vbuffer_offset[i] = C_SQ_VTX_WORD2_OFFSET & elements[i].src_offset;
if (ve->vbuffer_offset[i]) {
}
}
+ memset(&bc, 0, sizeof(bc));
+ r600_bc_init(&bc, rctx->chip_class);
+
+ for (i = 0; i < ve->count; i++) {
+ if (elements[i].instance_divisor > 1) {
+ struct r600_bc_alu alu;
+
+ memset(&alu, 0, sizeof(alu));
+ alu.inst = BC_INST(&bc, V_SQ_ALU_WORD1_OP2_SQ_OP2_INST_MULHI_UINT);
+ alu.src[0].sel = 0;
+ alu.src[0].chan = 3;
+
+ alu.src[1].sel = V_SQ_ALU_SRC_LITERAL;
+ alu.src[1].value = (1ll << 32) / elements[i].instance_divisor + 1;
+
+ alu.dst.sel = i + 1;
+ alu.dst.chan = 3;
+ alu.dst.write = 1;
+ alu.last = 1;
+
+ if ((r = r600_bc_add_alu(&bc, &alu))) {
+ r600_bc_clear(&bc);
+ return r;
+ }
+ }
+ }
+
for (i = 0; i < ve->count; i++) {
unsigned vbuffer_index;
- r600_vertex_data_type(ve->hw_format[i], &format, &num_format, &format_comp);
- desc = util_format_description(ve->hw_format[i]);
+ r600_vertex_data_type(ve->elements[i].src_format, &format, &num_format, &format_comp, &endian);
+ desc = util_format_description(ve->elements[i].src_format);
if (desc == NULL) {
- R600_ERR("unknown format %d\n", ve->hw_format[i]);
- r600_bo_reference(rctx->radeon, &ve->fetch_shader, NULL);
+ r600_bc_clear(&bc);
+ R600_ERR("unknown format %d\n", ve->elements[i].src_format);
return -EINVAL;
}
/* see above for vbuffer_need_offset explanation */
vbuffer_index = elements[i].vertex_buffer_index;
- if (ve->vbuffer_need_offset) {
- bytecode[8 + i * 4 + 0] = S_SQ_VTX_WORD0_BUFFER_ID(i + fetch_resource_start);
- } else {
- bytecode[8 + i * 4 + 0] = S_SQ_VTX_WORD0_BUFFER_ID(vbuffer_index + fetch_resource_start);
+ memset(&vtx, 0, sizeof(vtx));
+ vtx.buffer_id = (ve->vbuffer_need_offset ? i : vbuffer_index) + fetch_resource_start;
+ vtx.fetch_type = elements[i].instance_divisor ? 1 : 0;
+ vtx.src_gpr = elements[i].instance_divisor > 1 ? i + 1 : 0;
+ vtx.src_sel_x = elements[i].instance_divisor ? 3 : 0;
+ vtx.mega_fetch_count = 0x1F;
+ vtx.dst_gpr = i + 1;
+ vtx.dst_sel_x = desc->swizzle[0];
+ vtx.dst_sel_y = desc->swizzle[1];
+ vtx.dst_sel_z = desc->swizzle[2];
+ vtx.dst_sel_w = desc->swizzle[3];
+ vtx.data_format = format;
+ vtx.num_format_all = num_format;
+ vtx.format_comp_all = format_comp;
+ vtx.srf_mode_all = 1;
+ vtx.offset = elements[i].src_offset;
+ vtx.endian = endian;
+
+ if ((r = r600_bc_add_vtx(&bc, &vtx))) {
+ r600_bc_clear(&bc);
+ return r;
}
- bytecode[8 + i * 4 + 0] |= S_SQ_VTX_WORD0_SRC_GPR(0) |
- S_SQ_VTX_WORD0_SRC_SEL_X(0) |
- S_SQ_VTX_WORD0_MEGA_FETCH_COUNT(0x1F);
- bytecode[8 + i * 4 + 1] = S_SQ_VTX_WORD1_DST_SEL_X(desc->swizzle[0]) |
- S_SQ_VTX_WORD1_DST_SEL_Y(desc->swizzle[1]) |
- S_SQ_VTX_WORD1_DST_SEL_Z(desc->swizzle[2]) |
- S_SQ_VTX_WORD1_DST_SEL_W(desc->swizzle[3]) |
- S_SQ_VTX_WORD1_USE_CONST_FIELDS(0) |
- S_SQ_VTX_WORD1_DATA_FORMAT(format) |
- S_SQ_VTX_WORD1_NUM_FORMAT_ALL(num_format) |
- S_SQ_VTX_WORD1_FORMAT_COMP_ALL(format_comp) |
- S_SQ_VTX_WORD1_SRF_MODE_ALL(1) |
- S_SQ_VTX_WORD1_GPR_DST_GPR(i + 1);
- bytecode[8 + i * 4 + 2] = S_SQ_VTX_WORD2_OFFSET(elements[i].src_offset) |
- S_SQ_VTX_WORD2_MEGA_FETCH(1);
- bytecode[8 + i * 4 + 3] = 0;
}
+
+ r600_bc_add_cfinst(&bc, BC_INST(&bc, V_SQ_CF_WORD1_SQ_CF_INST_RETURN));
+
+ if ((r = r600_bc_build(&bc))) {
+ r600_bc_clear(&bc);
+ return r;
+ }
+
+ if (dump_shaders == -1)
+ dump_shaders = debug_get_bool_option("R600_DUMP_SHADERS", FALSE);
+
+ if (dump_shaders) {
+ fprintf(stderr, "--------------------------------------------------------------\n");
+ r600_bc_dump(&bc);
+ fprintf(stderr, "______________________________________________________________\n");
+ }
+
+ ve->fs_size = bc.ndw*4;
+
+ /* use PIPE_BIND_VERTEX_BUFFER so we use the cache buffer manager */
+ ve->fetch_shader = r600_bo(rctx->radeon, ve->fs_size, 256, PIPE_BIND_VERTEX_BUFFER, PIPE_USAGE_IMMUTABLE);
+ if (ve->fetch_shader == NULL) {
+ r600_bc_clear(&bc);
+ return -ENOMEM;
+ }
+
+ bytecode = r600_bo_map(rctx->radeon, ve->fetch_shader, 0, NULL);
+ if (bytecode == NULL) {
+ r600_bc_clear(&bc);
+ r600_bo_reference(rctx->radeon, &ve->fetch_shader, NULL);
+ return -ENOMEM;
+ }
+
+ if (R600_BIG_ENDIAN) {
+ for (i = 0; i < ve->fs_size / 4; ++i) {
+ bytecode[i] = bswap_32(bc.bytecode[i]);
+ }
+ } else {
+ memcpy(bytecode, bc.bytecode, ve->fs_size);
+ }
+
r600_bo_unmap(rctx->radeon, ve->fetch_shader);
+ r600_bc_clear(&bc);
+
+ if (rctx->chip_class >= EVERGREEN)
+ evergreen_fetch_shader(&rctx->context, ve);
+ else
+ r600_fetch_shader(&rctx->context, ve);
+
return 0;
}