FF_VTX = (1<<5),
FF_MEM = (1<<6),
+
+ FF_SET_TEXTURE_OFFSETS = (1<<7),
+ FF_USE_TEXTURE_OFFSETS = (1<<8),
};
/* flags for CF instructions */
{"GET_GRADIENTS_H_FINE", { -1, -1, 0x000107, 0x000107 }, FF_GETGRAD },
{"GET_GRADIENTS_V_FINE", { -1, -1, 0x000108, 0x000108 }, FF_GETGRAD },
{"GET_LERP", { 0x000009, 0x000009, -1, -1 }, 0 },
- {"SET_TEXTURE_OFFSETS", { -1, -1, 0x000009, 0x000009 }, 0 },
+ {"SET_TEXTURE_OFFSETS", { -1, -1, 0x000009, 0x000009 }, FF_SET_TEXTURE_OFFSETS },
{"KEEP_GRADIENTS", { -1, 0x00000A, 0x00000A, 0x00000A }, 0 },
{"SET_GRADIENTS_H", { 0x00000B, 0x00000B, 0x00000B, 0x00000B }, FF_SETGRAD },
{"SET_GRADIENTS_V", { 0x00000C, 0x00000C, 0x00000C, 0x00000C }, FF_SETGRAD },
{"GATHER4", { -1, -1, 0x000015, 0x000015 }, FF_TEX },
{"SAMPLE_G_LB", { 0x000016, 0x000016, 0x000016, 0x000016 }, FF_TEX | FF_USEGRAD},
{"SAMPLE_G_LZ", { 0x000017, 0x000017, -1, -1 }, FF_TEX | FF_USEGRAD},
- {"GATHER4_O", { -1, -1, 0x000017, 0x000017 }, FF_TEX },
+ {"GATHER4_O", { -1, -1, 0x000017, 0x000017 }, FF_TEX | FF_USE_TEXTURE_OFFSETS},
{"SAMPLE_C", { 0x000018, 0x000018, 0x000018, 0x000018 }, FF_TEX },
{"SAMPLE_C_L", { 0x000019, 0x000019, 0x000019, 0x000019 }, FF_TEX },
{"SAMPLE_C_LB", { 0x00001A, 0x00001A, 0x00001A, 0x00001A }, FF_TEX },
{"GATHER4_C", { -1, -1, 0x00001D, 0x00001D }, FF_TEX },
{"SAMPLE_C_G_LB", { 0x00001E, 0x00001E, 0x00001E, 0x00001E }, FF_TEX | FF_USEGRAD},
{"SAMPLE_C_G_LZ", { 0x00001F, 0x00001F, -1, -1 }, FF_TEX | FF_USEGRAD},
- {"GATHER4_C_O", { -1, -1, 0x00001F, 0x00001F }, FF_TEX }
+ {"GATHER4_C_O", { -1, -1, 0x00001F, 0x00001F }, FF_TEX | FF_USE_TEXTURE_OFFSETS}
};
static const struct cf_op_info cf_op_table[] = {
}
}
-void bc_finalizer::emit_set_grad(fetch_node* f) {
+void bc_finalizer::copy_fetch_src(fetch_node &dst, fetch_node &src, unsigned arg_start)
+{
+ int reg = -1;
- assert(f->src.size() == 12);
- unsigned ops[2] = { FETCH_OP_SET_GRADIENTS_V, FETCH_OP_SET_GRADIENTS_H };
+ for (unsigned chan = 0; chan < 4; ++chan) {
- unsigned arg_start = 0;
+ dst.bc.dst_sel[chan] = SEL_MASK;
- for (unsigned op = 0; op < 2; ++op) {
- fetch_node *n = sh.create_fetch();
- n->bc.set_op(ops[op]);
+ unsigned sel = SEL_MASK;
- // FIXME extract this loop into a separate method and reuse it
+ value *v = src.src[arg_start + chan];
- int reg = -1;
+ if (!v || v->is_undef()) {
+ sel = SEL_MASK;
+ } else if (v->is_const()) {
+ literal l = v->literal_value;
+ if (l == literal(0))
+ sel = SEL_0;
+ else if (l == literal(1.0f))
+ sel = SEL_1;
+ else {
+ sblog << "invalid fetch constant operand " << chan << " ";
+ dump::dump_op(&src);
+ sblog << "\n";
+ abort();
+ }
- arg_start += 4;
+ } else if (v->is_any_gpr()) {
+ unsigned vreg = v->gpr.sel();
+ unsigned vchan = v->gpr.chan();
- for (unsigned chan = 0; chan < 4; ++chan) {
+ if (reg == -1)
+ reg = vreg;
+ else if ((unsigned)reg != vreg) {
+ sblog << "invalid fetch source operand " << chan << " ";
+ dump::dump_op(&src);
+ sblog << "\n";
+ abort();
+ }
- n->bc.dst_sel[chan] = SEL_MASK;
+ sel = vchan;
- unsigned sel = SEL_MASK;
+ } else {
+ sblog << "invalid fetch source operand " << chan << " ";
+ dump::dump_op(&src);
+ sblog << "\n";
+ abort();
+ }
- value *v = f->src[arg_start + chan];
+ dst.bc.src_sel[chan] = sel;
+ }
- if (!v || v->is_undef()) {
- sel = SEL_MASK;
- } else if (v->is_const()) {
- literal l = v->literal_value;
- if (l == literal(0))
- sel = SEL_0;
- else if (l == literal(1.0f))
- sel = SEL_1;
- else {
- sblog << "invalid fetch constant operand " << chan << " ";
- dump::dump_op(f);
- sblog << "\n";
- abort();
- }
+ if (reg >= 0)
+ update_ngpr(reg);
- } else if (v->is_any_gpr()) {
- unsigned vreg = v->gpr.sel();
- unsigned vchan = v->gpr.chan();
+ dst.bc.src_gpr = reg >= 0 ? reg : 0;
+}
- if (reg == -1)
- reg = vreg;
- else if ((unsigned)reg != vreg) {
- sblog << "invalid fetch source operand " << chan << " ";
- dump::dump_op(f);
- sblog << "\n";
- abort();
- }
+void bc_finalizer::emit_set_grad(fetch_node* f) {
- sel = vchan;
+ assert(f->src.size() == 12);
+ unsigned ops[2] = { FETCH_OP_SET_GRADIENTS_V, FETCH_OP_SET_GRADIENTS_H };
- } else {
- sblog << "invalid fetch source operand " << chan << " ";
- dump::dump_op(f);
- sblog << "\n";
- abort();
- }
+ unsigned arg_start = 0;
- n->bc.src_sel[chan] = sel;
- }
+ for (unsigned op = 0; op < 2; ++op) {
+ fetch_node *n = sh.create_fetch();
+ n->bc.set_op(ops[op]);
- if (reg >= 0)
- update_ngpr(reg);
+ arg_start += 4;
- n->bc.src_gpr = reg >= 0 ? reg : 0;
+ copy_fetch_src(*n, *f, arg_start);
f->insert_before(n);
}
}
+void bc_finalizer::emit_set_texture_offsets(fetch_node &f) {
+ assert(f.src.size() == 8);
+
+ fetch_node *n = sh.create_fetch();
+
+ n->bc.set_op(FETCH_OP_SET_TEXTURE_OFFSETS);
+
+ copy_fetch_src(*n, f, 4);
+
+ f.insert_before(n);
+}
+
void bc_finalizer::finalize_fetch(fetch_node* f) {
int reg = -1;
src_count = 1;
} else if (flags & FF_USEGRAD) {
emit_set_grad(f);
+ } else if (flags & FF_USE_TEXTURE_OFFSETS) {
+ emit_set_texture_offsets(*f);
}
for (unsigned chan = 0; chan < src_count; ++chan) {
int bc_parser::prepare_fetch_clause(cf_node *cf) {
- vvec grad_v, grad_h;
+ vvec grad_v, grad_h, texture_offsets;
for (node_iterator I = cf->begin(), E = cf->end(); I != E; ++I) {
sh->uses_gradients = true;
}
- if (flags & FF_SETGRAD) {
+ if (flags & (FF_SETGRAD | FF_SET_TEXTURE_OFFSETS)) {
vvec *grad = NULL;
case FETCH_OP_SET_GRADIENTS_H:
grad = &grad_h;
break;
+ case FETCH_OP_SET_TEXTURE_OFFSETS:
+ grad = &texture_offsets;
+ break;
default:
assert(!"unexpected SET_GRAD instruction");
return -1;
(*grad)[s] = sh->get_const_value(1.0f);
}
} else {
-
+ // Fold source values for instructions with hidden target values in to the instructions
+ // using them. The set instructions are later re-emitted by bc_finalizer
if (flags & FF_USEGRAD) {
n->src.resize(12);
std::copy(grad_v.begin(), grad_v.end(), n->src.begin() + 4);
std::copy(grad_h.begin(), grad_h.end(), n->src.begin() + 8);
+ } else if (flags & FF_USE_TEXTURE_OFFSETS) {
+ n->src.resize(8);
+ std::copy(texture_offsets.begin(), texture_offsets.end(), n->src.begin() + 4);
} else {
n->src.resize(4);
}
void cf_peephole();
+private:
+ void copy_fetch_src(fetch_node &dst, fetch_node &src, unsigned arg_start);
+ void emit_set_texture_offsets(fetch_node &f);
};