src0, src1); \
}
+#define ALU3(op) \
+ vec4_instruction * \
+ vec4_visitor::op(dst_reg dst, src_reg src0, src_reg src1, src_reg src2)\
+ { \
+ return new(mem_ctx) vec4_instruction(this, BRW_OPCODE_##op, dst, \
+ src0, src1, src2); \
+ }
+
ALU1(NOT)
ALU1(MOV)
ALU1(FRC)
ALU2(SHL)
ALU2(SHR)
ALU2(ASR)
+ALU3(LRP)
+ALU1(BFREV)
+ALU3(BFE)
+ALU2(BFI1)
+ALU3(BFI2)
+ALU1(FBH)
+ALU1(FBL)
+ALU1(CBIT)
/** Gen4 predicated IF. */
vec4_instruction *
emit(dot_opcodes[elements - 2], dst, src0, src1);
}
+src_reg
+vec4_visitor::fix_3src_operand(src_reg src)
+{
+ /* Using vec4 uniforms in SIMD4x2 programs is difficult. You'd like to be
+ * able to use vertical stride of zero to replicate the vec4 uniform, like
+ *
+ * g3<0;4,1>:f - [0, 4][1, 5][2, 6][3, 7]
+ *
+ * But you can't, since vertical stride is always four in three-source
+ * instructions. Instead, insert a MOV instruction to do the replication so
+ * that the three-source instruction can consume it.
+ */
+
+ /* The MOV is only needed if the source is a uniform or immediate. */
+ if (src.file != UNIFORM && src.file != IMM)
+ return src;
+
+ dst_reg expanded = dst_reg(this, glsl_type::vec4_type);
+ expanded.type = src.type;
+ emit(MOV(expanded, src));
+ return src_reg(expanded);
+}
+
src_reg
vec4_visitor::fix_math_operand(src_reg src)
{
return true;
}
+bool
+vec4_visitor::try_emit_mad(ir_expression *ir, int mul_arg)
+{
+ /* 3-src instructions were introduced in gen6. */
+ if (intel->gen < 6)
+ return false;
+
+ /* MAD can only handle floating-point data. */
+ if (ir->type->base_type != GLSL_TYPE_FLOAT)
+ return false;
+
+ ir_rvalue *nonmul = ir->operands[1 - mul_arg];
+ ir_expression *mul = ir->operands[mul_arg]->as_expression();
+
+ if (!mul || mul->operation != ir_binop_mul)
+ return false;
+
+ nonmul->accept(this);
+ src_reg src0 = fix_3src_operand(this->result);
+
+ mul->operands[0]->accept(this);
+ src_reg src1 = fix_3src_operand(this->result);
+
+ mul->operands[1]->accept(this);
+ src_reg src2 = fix_3src_operand(this->result);
+
+ this->result = src_reg(this, ir->type);
+ emit(BRW_OPCODE_MAD, dst_reg(this->result), src0, src1, src2);
+
+ return true;
+}
+
void
vec4_visitor::emit_bool_comparison(unsigned int op,
dst_reg dst, src_reg src0, src_reg src1)
}
}
+static bool
+is_16bit_constant(ir_rvalue *rvalue)
+{
+ ir_constant *constant = rvalue->as_constant();
+ if (!constant)
+ return false;
+
+ if (constant->type != glsl_type::int_type &&
+ constant->type != glsl_type::uint_type)
+ return false;
+
+ return constant->value.u[0] < (1 << 16);
+}
+
void
vec4_visitor::visit(ir_expression *ir)
{
if (try_emit_sat(ir))
return;
+ if (ir->operation == ir_binop_add) {
+ if (try_emit_mad(ir, 0) || try_emit_mad(ir, 1))
+ return;
+ }
+
for (operand = 0; operand < ir->get_num_operands(); operand++) {
this->result.file = BAD_FILE;
ir->operands[operand]->accept(this);
assert(!"derivatives not valid in vertex shader");
break;
+ case ir_unop_bitfield_reverse:
+ emit(BFREV(result_dst, op[0]));
+ break;
+ case ir_unop_bit_count:
+ emit(CBIT(result_dst, op[0]));
+ break;
+ case ir_unop_find_msb: {
+ src_reg temp = src_reg(this, glsl_type::uint_type);
+
+ inst = emit(FBH(dst_reg(temp), op[0]));
+ inst->dst.writemask = WRITEMASK_XYZW;
+
+ /* FBH counts from the MSB side, while GLSL's findMSB() wants the count
+ * from the LSB side. If FBH didn't return an error (0xFFFFFFFF), then
+ * subtract the result from 31 to convert the MSB count into an LSB count.
+ */
+
+ /* FBH only supports UD type for dst, so use a MOV to convert UD to D. */
+ temp.swizzle = BRW_SWIZZLE_NOOP;
+ emit(MOV(result_dst, temp));
+
+ src_reg src_tmp = src_reg(result_dst);
+ emit(CMP(dst_null_d(), src_tmp, src_reg(-1), BRW_CONDITIONAL_NZ));
+
+ src_tmp.negate = true;
+ inst = emit(ADD(result_dst, src_tmp, src_reg(31)));
+ inst->predicate = BRW_PREDICATE_NORMAL;
+ break;
+ }
+ case ir_unop_find_lsb:
+ emit(FBL(result_dst, op[0]));
+ break;
+
case ir_unop_noise:
assert(!"not reached: should be handled by lower_noise");
break;
case ir_binop_mul:
if (ir->type->is_integer()) {
- /* For integer multiplication, the MUL uses the low 16 bits
- * of one of the operands (src0 on gen6, src1 on gen7). The
- * MACH accumulates in the contribution of the upper 16 bits
- * of that operand.
- *
- * FINISHME: Emit just the MUL if we know an operand is small
- * enough.
- */
- struct brw_reg acc = retype(brw_acc_reg(), BRW_REGISTER_TYPE_D);
-
- emit(MUL(acc, op[0], op[1]));
- emit(MACH(dst_null_d(), op[0], op[1]));
- emit(MOV(result_dst, src_reg(acc)));
+ /* For integer multiplication, the MUL uses the low 16 bits of one of
+ * the operands (src0 through SNB, src1 on IVB and later). The MACH
+ * accumulates in the contribution of the upper 16 bits of that
+ * operand. If we can determine that one of the args is in the low
+ * 16 bits, though, we can just emit a single MUL.
+ */
+ if (is_16bit_constant(ir->operands[0])) {
+ if (intel->gen < 7)
+ emit(MUL(result_dst, op[0], op[1]));
+ else
+ emit(MUL(result_dst, op[1], op[0]));
+ } else if (is_16bit_constant(ir->operands[1])) {
+ if (intel->gen < 7)
+ emit(MUL(result_dst, op[1], op[0]));
+ else
+ emit(MUL(result_dst, op[0], op[1]));
+ } else {
+ struct brw_reg acc = retype(brw_acc_reg(), BRW_REGISTER_TYPE_D);
+
+ emit(MUL(acc, op[0], op[1]));
+ emit(MACH(dst_null_d(), op[0], op[1]));
+ emit(MOV(result_dst, src_reg(acc)));
+ }
} else {
emit(MUL(result_dst, op[0], op[1]));
}
inst = emit(SHR(result_dst, op[0], op[1]));
break;
+ case ir_binop_bfm:
+ emit(BFI1(result_dst, op[0], op[1]));
+ break;
+
case ir_binop_ubo_load: {
ir_constant *uniform_block = ir->operands[0]->as_constant();
ir_constant *const_offset_ir = ir->operands[1]->as_constant();
break;
}
+ case ir_binop_vector_extract:
+ assert(!"should have been lowered by vec_index_to_cond_assign");
+ break;
+
case ir_triop_lrp:
- assert(!"not reached: should be handled by lrp_to_arith");
+ op[0] = fix_3src_operand(op[0]);
+ op[1] = fix_3src_operand(op[1]);
+ op[2] = fix_3src_operand(op[2]);
+ /* Note that the instruction's argument order is reversed from GLSL
+ * and the IR.
+ */
+ emit(LRP(result_dst, op[2], op[1], op[0]));
+ break;
+
+ case ir_triop_bfi:
+ op[0] = fix_3src_operand(op[0]);
+ op[1] = fix_3src_operand(op[1]);
+ op[2] = fix_3src_operand(op[2]);
+ emit(BFI2(result_dst, op[0], op[1], op[2]));
+ break;
+
+ case ir_triop_bitfield_extract:
+ op[0] = fix_3src_operand(op[0]);
+ op[1] = fix_3src_operand(op[1]);
+ op[2] = fix_3src_operand(op[2]);
+ /* Note that the instruction's argument order is reversed from GLSL
+ * and the IR.
+ */
+ emit(BFE(result_dst, op[2], op[1], op[0]));
+ break;
+
+ case ir_triop_vector_insert:
+ assert(!"should have been lowered by lower_vector_insert");
+ break;
+
+ case ir_quadop_bitfield_insert:
+ assert(!"not reached: should be handled by "
+ "bitfield_insert_to_bfm_bfi\n");
break;
case ir_quadop_vector:
shadow_comparitor = this->result;
}
- const glsl_type *lod_type, *sample_index_type;
+ const glsl_type *lod_type = NULL, *sample_index_type = NULL;
src_reg lod, dPdx, dPdy, sample_index;
switch (ir->op) {
case ir_tex:
emit(MOV(dst_reg(MRF, param_base, ir->coordinate->type, zero_mask),
src_reg(0)));
/* Load the shadow comparitor */
- if (ir->shadow_comparitor) {
+ if (ir->shadow_comparitor && ir->op != ir_txd) {
emit(MOV(dst_reg(MRF, param_base + 1, ir->shadow_comparitor->type,
WRITEMASK_X),
shadow_comparitor));
emit(MOV(dst_reg(MRF, param_base + 1, type, WRITEMASK_YW), dPdy));
inst->mlen++;
- if (ir->type->vector_elements == 3) {
+ if (ir->type->vector_elements == 3 || ir->shadow_comparitor) {
dPdx.swizzle = BRW_SWIZZLE_ZZZZ;
dPdy.swizzle = BRW_SWIZZLE_ZZZZ;
emit(MOV(dst_reg(MRF, param_base + 2, type, WRITEMASK_X), dPdx));
emit(MOV(dst_reg(MRF, param_base + 2, type, WRITEMASK_Y), dPdy));
inst->mlen++;
+
+ if (ir->shadow_comparitor) {
+ emit(MOV(dst_reg(MRF, param_base + 2,
+ ir->shadow_comparitor->type, WRITEMASK_Z),
+ shadow_comparitor));
+ }
}
} else /* intel->gen == 4 */ {
emit(MOV(dst_reg(MRF, param_base + 1, type, WRITEMASK_XYZ), dPdx));
current_annotation = "Clipping flags";
for (i = 0; i < key->nr_userclip_plane_consts; i++) {
vec4_instruction *inst;
+ gl_varying_slot slot = (prog_data->vue_map.slots_valid & VARYING_BIT_CLIP_VERTEX)
+ ? VARYING_SLOT_CLIP_VERTEX : VARYING_SLOT_POS;
- inst = emit(DP4(dst_null_f(), src_reg(output_reg[VARYING_SLOT_POS]),
+ inst = emit(DP4(dst_null_f(), src_reg(output_reg[slot]),
src_reg(this->userplane[i])));
inst->conditional_mod = BRW_CONDITIONAL_L;
emit(MOV(brw_writemask(reg, WRITEMASK_W),
src_reg(output_reg[VARYING_SLOT_PSIZ])));
}
+ if (prog_data->vue_map.slots_valid & VARYING_BIT_LAYER) {
+ emit(MOV(retype(brw_writemask(reg, WRITEMASK_Y), BRW_REGISTER_TYPE_D),
+ src_reg(output_reg[VARYING_SLOT_LAYER])));
+ }
}
}
current_annotation = "NDC";
emit(MOV(reg, src_reg(output_reg[BRW_VARYING_SLOT_NDC])));
break;
- case BRW_VARYING_SLOT_POS_DUPLICATE:
case VARYING_SLOT_POS:
current_annotation = "gl_Position";
emit(MOV(reg, src_reg(output_reg[VARYING_SLOT_POS])));
struct brw_vec4_prog_data *prog_data,
struct gl_shader_program *shader_prog,
struct brw_shader *shader,
- void *mem_ctx)
+ void *mem_ctx,
+ bool debug_flag)
+ : debug_flag(debug_flag)
{
this->brw = brw;
this->intel = &brw->intel;
hash_table_pointer_hash,
hash_table_pointer_compare);
- this->virtual_grf_def = NULL;
- this->virtual_grf_use = NULL;
+ this->virtual_grf_start = NULL;
+ this->virtual_grf_end = NULL;
this->virtual_grf_sizes = NULL;
this->virtual_grf_count = 0;
this->virtual_grf_reg_map = NULL;
void *mem_ctx)
: vec4_visitor(brw, &vs_compile->base, &vs_compile->vp->program.Base,
&vs_compile->key.base, &vs_prog_data->base, prog, shader,
- mem_ctx),
+ mem_ctx, INTEL_DEBUG & DEBUG_VS),
vs_compile(vs_compile),
vs_prog_data(vs_prog_data)
{
this->fail_msg = msg;
- if (INTEL_DEBUG & DEBUG_VS) {
+ if (debug_flag) {
fprintf(stderr, "%s", msg);
}
}