#define BCP_DUMP(q)
#endif
-extern "C" {
#include "r600_pipe.h"
#include "r600_shader.h"
-}
#include <stack>
if (pshader) {
switch (bc->type) {
case TGSI_PROCESSOR_FRAGMENT: t = TARGET_PS; break;
- case TGSI_PROCESSOR_VERTEX: t = TARGET_VS; break;
+ case TGSI_PROCESSOR_VERTEX:
+ t = pshader->vs_as_es ? TARGET_ES : TARGET_VS;
+ break;
+ case TGSI_PROCESSOR_GEOMETRY: t = TARGET_GS; break;
case TGSI_PROCESSOR_COMPUTE: t = TARGET_COMPUTE; break;
default: assert(!"unknown shader target"); return -1; break;
}
if ((r = decode_cf(i, eop)))
return r;
- } while (!eop || (i >> 1) <= max_cf);
+ } while (!eop || (i >> 1) < max_cf);
return 0;
}
}
}
- if (sh->target == TARGET_VS)
+ // GS inputs can add indirect addressing
+ if (sh->target == TARGET_GS) {
+ if (pshader->num_arrays) {
+ for (unsigned i = 0; i < pshader->num_arrays; ++i) {
+ r600_shader_array &a = pshader->arrays[i];
+ sh->add_gpr_array(a.gpr_start, a.gpr_count, a.comp_mask);
+ }
+ }
+ }
+
+ if (sh->target == TARGET_VS || sh->target == TARGET_ES)
+ sh->add_input(0, 1, 0x0F);
+ else if (sh->target == TARGET_GS) {
sh->add_input(0, 1, 0x0F);
+ sh->add_input(1, 1, 0x0F);
+ }
bool ps_interp = ctx.hw_class >= HW_CLASS_EVERGREEN
&& sh->target == TARGET_PS;
- unsigned linear = 0, persp = 0, centroid = 1;
+ bool ij_interpolators[6];
+ memset(ij_interpolators, 0, sizeof(ij_interpolators));
for (unsigned i = 0; i < pshader->ninput; ++i) {
r600_shader_io & in = pshader->input[i];
bool preloaded = sh->target == TARGET_PS && !(ps_interp && in.spi_sid);
sh->add_input(in.gpr, preloaded, /*in.write_mask*/ 0x0F);
if (ps_interp && in.spi_sid) {
- if (in.interpolate == TGSI_INTERPOLATE_LINEAR ||
- in.interpolate == TGSI_INTERPOLATE_COLOR)
- linear = 1;
- else if (in.interpolate == TGSI_INTERPOLATE_PERSPECTIVE)
- persp = 1;
- if (in.centroid)
- centroid = 2;
+ int k = eg_get_interpolator_index(in.interpolate, in.interpolate_location);
+ if (k >= 0)
+ ij_interpolators[k] |= true;
}
}
if (ps_interp) {
- unsigned mask = (1 << (2 * (linear + persp) * centroid)) - 1;
+ /* add the egcm ij interpolators to live inputs */
+ unsigned num_ij = 0;
+ for (unsigned i = 0; i < Elements(ij_interpolators); i++) {
+ num_ij += ij_interpolators[i];
+ }
+
+ unsigned mask = (1 << (2 * num_ij)) - 1;
unsigned gpr = 0;
while (mask) {
if (cf->bc.rw_rel)
gpr_reladdr = true;
assert(!cf->bc.rw_rel);
- } else if (flags & (CF_STRM | CF_RAT)) {
+ } else if (flags & CF_MEM) {
if (cf->bc.rw_rel)
gpr_reladdr = true;
assert(!cf->bc.rw_rel);
} else if (src.sel == ALU_SRC_PS || src.sel == ALU_SRC_PV) {
unsigned pgroup = !cgroup, prev_slot = src.sel == ALU_SRC_PS ?
SLOT_TRANS : src.chan;
+
+ // XXX shouldn't happen but llvm backend uses PS on cayman
+ if (prev_slot == SLOT_TRANS && ctx.is_cayman())
+ prev_slot = SLOT_X;
+
alu_node *prev_alu = slots[pgroup][prev_slot];
assert(prev_alu);
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);
}
} while (1);
c->bc.end_of_program = eop;
- } else if (flags & (CF_STRM | CF_RAT)) {
+ } else if (flags & CF_MEM) {
unsigned burst_count = c->bc.burst_count;
unsigned eop = c->bc.end_of_program;
sh->get_gpr_value(true, c->bc.rw_gpr, s, false);
}
- if ((flags & CF_RAT) && (c->bc.type & 1)) { // indexed write
+ if (((flags & CF_RAT) || (!(flags & CF_STRM))) && (c->bc.type & 1)) { // indexed write
c->src.resize(8);
for(int s = 0; s < 3; ++s) {
c->src[4 + s] =
c->flags |= NF_DONT_HOIST | NF_DONT_MOVE;
}
+ if (flags & CF_EMIT) {
+ // Instruction implicitly depends on prior [EMIT_][CUT]_VERTEX
+ c->src.push_back(sh->get_special_value(SV_GEOMETRY_EMIT));
+ c->dst.push_back(sh->get_special_value(SV_GEOMETRY_EMIT));
+ if (sh->target == TARGET_ES) {
+ // For ES shaders this is an export
+ c->flags |= NF_DONT_KILL;
+ }
+ }
+
if (!burst_count--)
break;
c->bc.end_of_program = eop;
+ } else if (flags & CF_EMIT) {
+ /* quick peephole */
+ cf_node *prev = static_cast<cf_node *>(c->prev);
+ if (c->bc.op == CF_OP_CUT_VERTEX &&
+ prev && prev->is_valid() &&
+ prev->bc.op == CF_OP_EMIT_VERTEX &&
+ c->bc.count == prev->bc.count) {
+ prev->bc.set_op(CF_OP_EMIT_CUT_VERTEX);
+ prev->bc.end_of_program = c->bc.end_of_program;
+ c->remove();
+ }
+ else {
+ c->flags |= NF_DONT_KILL | NF_DONT_HOIST | NF_DONT_MOVE;
+
+ c->src.push_back(sh->get_special_value(SV_GEOMETRY_EMIT));
+ c->dst.push_back(sh->get_special_value(SV_GEOMETRY_EMIT));
+ }
}
}
}
int bc_parser::prepare_loop(cf_node* c) {
+ assert(c->bc.addr-1 < cf_map.size());
cf_node *end = cf_map[c->bc.addr - 1];
assert(end->bc.op == CF_OP_LOOP_END);
c->insert_before(reg);
rep->move(c, end->next);
+ reg->src_loop = true;
+
loop_stack.push(reg);
return 0;
}
int bc_parser::prepare_if(cf_node* c) {
+ assert(c->bc.addr-1 < cf_map.size());
cf_node *c_else = NULL, *end = cf_map[c->bc.addr];
+ if (!end)
+ return 0; // not quite sure how this happens, malformed input?
+
BCP_DUMP(
sblog << "parsing JUMP @" << c->bc.id;
sblog << "\n";
if (c_else->parent != c->parent)
c_else = NULL;
- if (end->parent != c->parent)
+ if (end && end->parent != c->parent)
end = NULL;
region_node *reg = sh->create_region();