}
}
+/* The message length for all SEND messages is restricted to [1,15]. This
+ * includes 1 for the header, so anything in slots 14 and above needs to be
+ * placed in a general-purpose register and emitted using a second URB write.
+ */
+#define MAX_SLOTS_IN_FIRST_URB_WRITE 14
+
+/**
+ * Determine whether the given vertex output can be written directly to a MRF
+ * or whether it has to be stored in a general-purpose register.
+ */
+static inline bool can_use_direct_mrf(int vert_result,
+ int first_reladdr_output, int slot)
+{
+ if (vert_result == VERT_RESULT_HPOS || vert_result == VERT_RESULT_PSIZ) {
+ /* These never go straight into MRF's. They are placed in the MRF by
+ * epilog code.
+ */
+ return false;
+ }
+ if (first_reladdr_output <= vert_result && vert_result < VERT_RESULT_MAX) {
+ /* Relative addressing might be used to access this vert_result, so it
+ * needs to go into a general-purpose register.
+ */
+ return false;
+ }
+ if (slot >= MAX_SLOTS_IN_FIRST_URB_WRITE) {
+ /* This output won't go out until the second URB write so it must be
+ * stored in a general-purpose register until then.
+ */
+ return false;
+ }
+ return true;
+}
+
/**
* Preallocate GRF register before code emit.
* Do things as simply as possible. Allocate and populate all regs
static void brw_vs_alloc_regs( struct brw_vs_compile *c )
{
struct intel_context *intel = &c->func.brw->intel;
- GLuint i, reg = 0, mrf, j;
+ GLuint i, reg = 0, slot;
int attributes_in_vue;
int first_reladdr_output;
int max_constant;
int constant = 0;
- int vert_result_reoder[VERT_RESULT_MAX];
- int bfc = 0;
+ struct brw_vertex_program *vp = c->vp;
+ const struct gl_program_parameter_list *params = vp->program.Base.Parameters;
/* Determine whether to use a real constant buffer or use a block
* of GRF registers for constants. The later is faster but only
if (constant == max_constant)
c->vp->use_const_buffer = GL_TRUE;
+ /* Set up the references to the pull parameters if present. This backend
+ * uses a 1:1 mapping from Mesa IR's index to location in the pull constant
+ * buffer, while the new VS backend allocates values to the pull buffer on
+ * demand.
+ */
+ if (c->vp->use_const_buffer) {
+ for (i = 0; i < params->NumParameters * 4; i++) {
+ c->prog_data.pull_param[i] = ¶ms->ParameterValues[i / 4][i % 4].f;
+ }
+ c->prog_data.nr_pull_params = i;
+ }
+
for (i = 0; i < constant; i++) {
c->regs[PROGRAM_STATE_VAR][i] = stride(brw_vec4_grf(reg + i / 2,
(i % 2) * 4),
/* Allocate outputs. The non-position outputs go straight into message regs.
*/
- c->nr_outputs = 0;
+ brw_compute_vue_map(&c->vue_map, intel, c->key.nr_userclip,
+ c->key.two_side_color, c->prog_data.outputs_written);
c->first_output = reg;
- c->first_overflow_output = 0;
-
- if (intel->gen >= 6) {
- mrf = 3;
- if (c->key.nr_userclip)
- mrf += 2;
- } else if (intel->gen == 5)
- mrf = 8;
- else
- mrf = 4;
first_reladdr_output = get_first_reladdr_output(&c->vp->program);
- for (i = 0; i < VERT_RESULT_MAX; i++)
- vert_result_reoder[i] = i;
-
- /* adjust attribute order in VUE for BFC0/BFC1 on Gen6+ */
- if (intel->gen >= 6 && c->key.two_side_color) {
- if ((c->prog_data.outputs_written & BITFIELD64_BIT(VERT_RESULT_COL1)) &&
- (c->prog_data.outputs_written & BITFIELD64_BIT(VERT_RESULT_BFC1))) {
- assert(c->prog_data.outputs_written & BITFIELD64_BIT(VERT_RESULT_COL0));
- assert(c->prog_data.outputs_written & BITFIELD64_BIT(VERT_RESULT_BFC0));
- bfc = 2;
- } else if ((c->prog_data.outputs_written & BITFIELD64_BIT(VERT_RESULT_COL0)) &&
- (c->prog_data.outputs_written & BITFIELD64_BIT(VERT_RESULT_BFC0)))
- bfc = 1;
-
- if (bfc) {
- for (i = 0; i < bfc; i++) {
- vert_result_reoder[VERT_RESULT_COL0 + i * 2 + 0] = VERT_RESULT_COL0 + i;
- vert_result_reoder[VERT_RESULT_COL0 + i * 2 + 1] = VERT_RESULT_BFC0 + i;
- }
-
- for (i = VERT_RESULT_COL0 + bfc * 2; i < VERT_RESULT_BFC0 + bfc; i++) {
- vert_result_reoder[i] = i - bfc;
- }
- }
- }
-
- for (j = 0; j < VERT_RESULT_MAX; j++) {
- i = vert_result_reoder[j];
-
- if (c->prog_data.outputs_written & BITFIELD64_BIT(i)) {
- c->nr_outputs++;
- assert(i < Elements(c->regs[PROGRAM_OUTPUT]));
- if (i == VERT_RESULT_HPOS) {
- c->regs[PROGRAM_OUTPUT][i] = brw_vec8_grf(reg, 0);
- reg++;
- }
- else if (i == VERT_RESULT_PSIZ) {
- c->regs[PROGRAM_OUTPUT][i] = brw_vec8_grf(reg, 0);
- reg++;
- }
- else {
- /* Two restrictions on our compute-to-MRF here. The
- * message length for all SEND messages is restricted to
- * [1,15], so we can't use mrf 15, as that means a length
- * of 16.
- *
- * Additionally, URB writes are aligned to URB rows, so we
- * need to put an even number of registers of URB data in
- * each URB write so that the later write is aligned. A
- * message length of 15 means 1 message header reg plus 14
- * regs of URB data.
- *
- * For attributes beyond the compute-to-MRF, we compute to
- * GRFs and they will be written in the second URB_WRITE.
- */
- if (first_reladdr_output > i && mrf < 15) {
- c->regs[PROGRAM_OUTPUT][i] = brw_message_reg(mrf);
- mrf++;
- }
- else {
- if (mrf >= 15 && !c->first_overflow_output)
- c->first_overflow_output = i;
- c->regs[PROGRAM_OUTPUT][i] = brw_vec8_grf(reg, 0);
- reg++;
- mrf++;
- }
- }
+ for (slot = 0; slot < c->vue_map.num_slots; slot++) {
+ int vert_result = c->vue_map.slot_to_vert_result[slot];
+ assert(vert_result < Elements(c->regs[PROGRAM_OUTPUT]));
+ if (can_use_direct_mrf(vert_result, first_reladdr_output, slot)) {
+ c->regs[PROGRAM_OUTPUT][vert_result] = brw_message_reg(slot + 1);
+ } else {
+ c->regs[PROGRAM_OUTPUT][vert_result] = brw_vec8_grf(reg, 0);
+ reg++;
}
}
/* The VS VUEs are shared by VF (outputting our inputs) and VS, so size
* them to fit the biggest thing they need to.
*/
- attributes_in_vue = MAX2(c->nr_outputs, c->nr_inputs);
+ attributes_in_vue = MAX2(c->vue_map.num_slots, c->nr_inputs);
- /* See emit_vertex_write() for where the VUE's overhead on top of the
- * attributes comes from.
- */
- if (intel->gen >= 7) {
- int header_regs = 2;
- if (c->key.nr_userclip)
- header_regs += 2;
-
- /* Each attribute is 16 bytes (1 vec4), so dividing by 4 gives us the
- * number of 64-byte (512-bit) units.
- */
- c->prog_data.urb_entry_size = (attributes_in_vue + header_regs + 3) / 4;
- } else if (intel->gen == 6) {
- int header_regs = 2;
- if (c->key.nr_userclip)
- header_regs += 2;
-
- /* Each attribute is 16 bytes (1 vec4), so dividing by 8 gives us the
+ if (intel->gen == 6) {
+ /* Each attribute is 32 bytes (2 vec4s), so dividing by 8 gives us the
* number of 128-byte (1024-bit) units.
*/
- c->prog_data.urb_entry_size = (attributes_in_vue + header_regs + 7) / 8;
- } else if (intel->gen == 5)
+ c->prog_data.urb_entry_size = ALIGN(attributes_in_vue, 8) / 8;
+ } else {
/* Each attribute is 16 bytes (1 vec4), so dividing by 4 gives us the
* number of 64-byte (512-bit) units.
*/
- c->prog_data.urb_entry_size = (attributes_in_vue + 6 + 3) / 4;
- else
- c->prog_data.urb_entry_size = (attributes_in_vue + 2 + 3) / 4;
+ c->prog_data.urb_entry_size = ALIGN(attributes_in_vue, 4) / 4;
+ }
c->prog_data.total_grf = reg;
brw_MAC(p, dst, arg0, arg1);
}
-/** 3 or 4-component vector normalization */
-static void emit_nrm( struct brw_vs_compile *c,
- struct brw_reg dst,
- struct brw_reg arg0,
- int num_comps)
-{
- struct brw_compile *p = &c->func;
- struct brw_reg tmp = get_tmp(c);
-
- /* tmp = dot(arg0, arg0) */
- if (num_comps == 3)
- brw_DP3(p, tmp, arg0, arg0);
- else
- brw_DP4(p, tmp, arg0, arg0);
-
- /* tmp = 1 / sqrt(tmp) */
- emit_math1(c, BRW_MATH_FUNCTION_RSQ, tmp, tmp, BRW_MATH_PRECISION_FULL);
-
- /* dst = arg0 * tmp */
- brw_MUL(p, dst, arg0, tmp);
-
- release_tmp(c, tmp);
-}
-
-
static struct brw_reg
get_constant(struct brw_vs_compile *c,
const struct prog_instruction *inst,
if (component >= 0) {
params = c->vp->program.Base.Parameters;
- f = params->ParameterValues[src->Index][component];
+ f = params->ParameterValues[src->Index][component].f;
if (src->Abs)
f = fabs(f);
struct brw_reg ndc;
int eot;
GLuint len_vertex_header = 2;
- int next_mrf, i;
+ int i;
int msg_len;
+ int slot;
if (c->key.copy_edgeflag) {
brw_MOV(p,
else
m = brw_message_reg(4);
- brw_DP4(p, brw_writemask(m, (1 << (i & 7))),pos, c->userplane[i]);
+ brw_DP4(p, brw_writemask(m, (1 << (i & 3))),pos, c->userplane[i]);
}
}
} else if ((c->prog_data.outputs_written &
}
/* Move variable-addressed, non-overflow outputs to their MRFs. */
- next_mrf = 2 + len_vertex_header;
- for (i = 0; i < VERT_RESULT_MAX; i++) {
- if (c->first_overflow_output > 0 && i >= c->first_overflow_output)
- break;
- if (!(c->prog_data.outputs_written & BITFIELD64_BIT(i)))
- continue;
- if (i == VERT_RESULT_PSIZ)
- continue;
+ for (slot = len_vertex_header; slot < c->vue_map.num_slots; ++slot) {
+ if (slot >= MAX_SLOTS_IN_FIRST_URB_WRITE)
+ break;
- if (i >= VERT_RESULT_TEX0 &&
- c->regs[PROGRAM_OUTPUT][i].file == BRW_GENERAL_REGISTER_FILE) {
- brw_MOV(p, brw_message_reg(next_mrf), c->regs[PROGRAM_OUTPUT][i]);
- next_mrf++;
- } else if (c->regs[PROGRAM_OUTPUT][i].file == BRW_MESSAGE_REGISTER_FILE) {
- next_mrf = c->regs[PROGRAM_OUTPUT][i].nr + 1;
+ int mrf = slot + 1;
+ int vert_result = c->vue_map.slot_to_vert_result[slot];
+ if (c->regs[PROGRAM_OUTPUT][vert_result].file ==
+ BRW_GENERAL_REGISTER_FILE) {
+ brw_MOV(p, brw_message_reg(mrf),
+ c->regs[PROGRAM_OUTPUT][vert_result]);
}
}
- eot = (c->first_overflow_output == 0);
+ eot = (slot >= c->vue_map.num_slots);
- /* Message header, plus VUE header, plus the (first set of) outputs. */
- msg_len = 1 + len_vertex_header + c->nr_outputs;
+ /* Message header, plus the (first part of the) VUE. */
+ msg_len = 1 + slot;
msg_len = align_interleaved_urb_mlen(brw, msg_len);
- /* Any outputs beyond BRW_MAX_MRF should be past first_overflow_output */
- msg_len = MIN2(msg_len, (BRW_MAX_MRF - 1)),
+ /* Any outputs beyond BRW_MAX_MRF should be in the second URB write */
+ assert (msg_len <= BRW_MAX_MRF - 1);
brw_urb_WRITE(p,
brw_null_reg(), /* dest */
0, /* urb destination offset */
BRW_URB_SWIZZLE_INTERLEAVE);
- if (c->first_overflow_output > 0) {
+ if (slot < c->vue_map.num_slots) {
/* Not all of the vertex outputs/results fit into the MRF.
* Move the overflowed attributes from the GRF to the MRF and
* issue another brw_urb_WRITE().
*/
- GLuint i, mrf = 1;
- for (i = c->first_overflow_output; i < VERT_RESULT_MAX; i++) {
- if (c->prog_data.outputs_written & BITFIELD64_BIT(i)) {
- /* move from GRF to MRF */
- brw_MOV(p, brw_message_reg(mrf), c->regs[PROGRAM_OUTPUT][i]);
- mrf++;
- }
+ GLuint mrf = 1;
+ for (; slot < c->vue_map.num_slots; ++slot) {
+ int vert_result = c->vue_map.slot_to_vert_result[slot];
+ /* move from GRF to MRF */
+ brw_MOV(p, brw_message_reg(mrf),
+ c->regs[PROGRAM_OUTPUT][vert_result]);
+ mrf++;
}
brw_urb_WRITE(p,
0, /* response len */
1, /* eot */
1, /* writes complete */
- 14 / 2, /* urb destination offset */
+ MAX_SLOTS_IN_FIRST_URB_WRITE / 2, /* urb destination offset */
BRW_URB_SWIZZLE_INTERLEAVE);
}
}
if (val.address_mode != BRW_ADDRESS_DIRECT)
return GL_FALSE;
+ if (val.negate || val.abs)
+ return GL_FALSE;
+
switch (prev_insn->header.opcode) {
case BRW_OPCODE_MOV:
case BRW_OPCODE_MAC:
}
}
+static void
+brw_vs_rescale_gl_fixed(struct brw_vs_compile *c)
+{
+ struct brw_compile *p = &c->func;
+ int i;
+
+ for (i = 0; i < VERT_ATTRIB_MAX; i++) {
+ if (!(c->prog_data.inputs_read & (1 << i)))
+ continue;
+
+ if (c->key.gl_fixed_input_size[i] != 0) {
+ struct brw_reg reg = c->regs[PROGRAM_INPUT][i];
+
+ brw_MUL(p,
+ brw_writemask(reg, (1 << c->key.gl_fixed_input_size[i]) - 1),
+ reg, brw_imm_f(1.0 / 65536.0));
+ }
+ }
+}
+
/* Emit the vertex program instructions here.
*/
-void brw_vs_emit(struct brw_vs_compile *c )
+void brw_old_vs_emit(struct brw_vs_compile *c )
{
#define MAX_IF_DEPTH 32
#define MAX_LOOP_DEPTH 32
*/
brw_vs_alloc_regs(c);
+ brw_vs_rescale_gl_fixed(c);
+
if (c->needs_stack)
brw_MOV(p, get_addr_reg(stack_index), brw_address(c->stack));
const struct prog_src_register *src = &inst->SrcReg[i];
index = src->Index;
file = src->File;
- if (file == PROGRAM_OUTPUT && c->output_regs[index].used_in_src)
- args[i] = c->output_regs[index].reg;
- else
+ if (file == PROGRAM_OUTPUT && c->output_regs[index].used_in_src) {
+ /* Can't just make get_arg "do the right thing" here because
+ * other callers of get_arg and get_src_reg don't expect any
+ * special behavior for the c->output_regs[index].used_in_src
+ * case.
+ */
+ args[i] = c->output_regs[index].reg;
+ args[i].dw1.bits.swizzle =
+ BRW_SWIZZLE4(GET_SWZ(src->Swizzle, 0),
+ GET_SWZ(src->Swizzle, 1),
+ GET_SWZ(src->Swizzle, 2),
+ GET_SWZ(src->Swizzle, 3));
+
+ /* Note this is ok for non-swizzle ARB_vp instructions */
+ args[i].negate = src->Negate ? 1 : 0;
+ } else
args[i] = get_arg(c, inst, i);
}
index = inst->DstReg.Index;
file = inst->DstReg.File;
if (file == PROGRAM_OUTPUT && c->output_regs[index].used_in_src)
- dst = c->output_regs[index].reg;
+ /* Can't just make get_dst "do the right thing" here because other
+ * callers of get_dst don't expect any special behavior for the
+ * c->output_regs[index].used_in_src case.
+ */
+ dst = brw_writemask(c->output_regs[index].reg, inst->DstReg.WriteMask);
else
dst = get_dst(c, inst->DstReg);
case OPCODE_DPH:
brw_DPH(p, dst, args[0], args[1]);
break;
- case OPCODE_NRM3:
- emit_nrm(c, dst, args[0], 3);
- break;
- case OPCODE_NRM4:
- emit_nrm(c, dst, args[0], 4);
- break;
case OPCODE_DST:
unalias2(c, dst, args[0], args[1], emit_dst_noalias);
break;