*/
#include "brw_vec4.h"
+#include "glsl/ir_uniform.h"
extern "C" {
-#include "main/macros.h"
-#include "program/prog_parameter.h"
#include "program/sampler.h"
}
this->src[0] = src0;
this->src[1] = src1;
this->src[2] = src2;
+ this->saturate = false;
+ this->force_writemask_all = false;
+ this->no_dd_clear = false;
+ this->no_dd_check = false;
+ this->conditional_mod = BRW_CONDITIONAL_NONE;
+ this->sampler = 0;
+ this->texture_offset = 0;
+ this->target = 0;
+ this->shadow_compare = false;
this->ir = v->base_ir;
+ this->urb_write_flags = BRW_URB_WRITE_NO_FLAGS;
+ this->header_present = false;
+ this->mlen = 0;
+ this->base_mrf = 0;
+ this->offset = 0;
+ this->ir = NULL;
this->annotation = v->current_annotation;
}
return emit(new(mem_ctx) vec4_instruction(this, opcode, dst, src0));
}
+vec4_instruction *
+vec4_visitor::emit(enum opcode opcode, dst_reg dst)
+{
+ return emit(new(mem_ctx) vec4_instruction(this, opcode, dst));
+}
+
vec4_instruction *
vec4_visitor::emit(enum opcode opcode)
{
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)
ALU1(RNDD)
ALU1(RNDE)
ALU1(RNDZ)
+ALU1(F32TO16)
+ALU1(F16TO32)
ALU2(ADD)
ALU2(MUL)
ALU2(MACH)
ALU2(DP3)
ALU2(DP4)
ALU2(DPH)
+ALU2(SHL)
+ALU2(SHR)
+ALU2(ASR)
+ALU3(LRP)
+ALU1(BFREV)
+ALU3(BFE)
+ALU2(BFI1)
+ALU3(BFI2)
+ALU1(FBH)
+ALU1(FBL)
+ALU1(CBIT)
+ALU3(MAD)
+ALU2(ADDC)
+ALU2(SUBB)
/** Gen4 predicated IF. */
vec4_instruction *
vec4_instruction *
vec4_visitor::IF(src_reg src0, src_reg src1, uint32_t condition)
{
- assert(intel->gen >= 6);
+ assert(brw->gen >= 6);
vec4_instruction *inst;
* before before comparison, producing garbage results for floating
* point comparisons.
*/
- if (intel->gen == 4) {
+ if (brw->gen == 4) {
dst.type = src0.type;
if (dst.file == HW_REG)
dst.fixed_hw_reg.type = dst.type;
emit(dot_opcodes[elements - 2], dst, src0, src1);
}
-void
-vec4_visitor::emit_math1_gen6(enum opcode opcode, dst_reg dst, src_reg src)
+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)
{
/* The gen6 math instruction ignores the source modifiers --
* swizzle, abs, negate, and at least some parts of the register
* region description.
*
- * While it would seem that this MOV could be avoided at this point
- * in the case that the swizzle is matched up with the destination
- * writemask, note that uniform packing and register allocation
- * could rearrange our swizzle, so let's leave this matter up to
- * copy propagation later.
+ * Rather than trying to enumerate all these cases, *always* expand the
+ * operand to a temp GRF for gen6.
+ *
+ * For gen7, keep the operand as-is, except if immediate, which gen7 still
+ * can't use.
*/
- src_reg temp_src = src_reg(this, glsl_type::vec4_type);
- emit(MOV(dst_reg(temp_src), src));
+
+ if (brw->gen == 7 && 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);
+}
+
+void
+vec4_visitor::emit_math1_gen6(enum opcode opcode, dst_reg dst, src_reg src)
+{
+ src = fix_math_operand(src);
if (dst.writemask != WRITEMASK_XYZW) {
/* The gen6 math instruction must be align1, so we can't do
*/
dst_reg temp_dst = dst_reg(this, glsl_type::vec4_type);
- emit(opcode, temp_dst, temp_src);
+ emit(opcode, temp_dst, src);
emit(MOV(dst, src_reg(temp_dst)));
} else {
- emit(opcode, dst, temp_src);
+ emit(opcode, dst, src);
}
}
return;
}
- if (intel->gen >= 7) {
- emit(opcode, dst, src);
- } else if (intel->gen == 6) {
+ if (brw->gen >= 6) {
return emit_math1_gen6(opcode, dst, src);
} else {
return emit_math1_gen4(opcode, dst, src);
vec4_visitor::emit_math2_gen6(enum opcode opcode,
dst_reg dst, src_reg src0, src_reg src1)
{
- src_reg expanded;
-
- /* The gen6 math instruction ignores the source modifiers --
- * swizzle, abs, negate, and at least some parts of the register
- * region description. Move the sources to temporaries to make it
- * generally work.
- */
-
- expanded = src_reg(this, glsl_type::vec4_type);
- expanded.type = src0.type;
- emit(MOV(dst_reg(expanded), src0));
- src0 = expanded;
-
- expanded = src_reg(this, glsl_type::vec4_type);
- expanded.type = src1.type;
- emit(MOV(dst_reg(expanded), src1));
- src1 = expanded;
+ src0 = fix_math_operand(src0);
+ src1 = fix_math_operand(src1);
if (dst.writemask != WRITEMASK_XYZW) {
/* The gen6 math instruction must be align1, so we can't do
return;
}
- if (intel->gen >= 7) {
- emit(opcode, dst, src0, src1);
- } else if (intel->gen == 6) {
+ if (brw->gen >= 6) {
return emit_math2_gen6(opcode, dst, src0, src1);
} else {
return emit_math2_gen4(opcode, dst, src0, src1);
}
}
+void
+vec4_visitor::emit_pack_half_2x16(dst_reg dst, src_reg src0)
+{
+ if (brw->gen < 7)
+ assert(!"ir_unop_pack_half_2x16 should be lowered");
+
+ assert(dst.type == BRW_REGISTER_TYPE_UD);
+ assert(src0.type == BRW_REGISTER_TYPE_F);
+
+ /* From the Ivybridge PRM, Vol4, Part3, Section 6.27 f32to16:
+ *
+ * Because this instruction does not have a 16-bit floating-point type,
+ * the destination data type must be Word (W).
+ *
+ * The destination must be DWord-aligned and specify a horizontal stride
+ * (HorzStride) of 2. The 16-bit result is stored in the lower word of
+ * each destination channel and the upper word is not modified.
+ *
+ * The above restriction implies that the f32to16 instruction must use
+ * align1 mode, because only in align1 mode is it possible to specify
+ * horizontal stride. We choose here to defy the hardware docs and emit
+ * align16 instructions.
+ *
+ * (I [chadv] did attempt to emit align1 instructions for VS f32to16
+ * instructions. I was partially successful in that the code passed all
+ * tests. However, the code was dubiously correct and fragile, and the
+ * tests were not harsh enough to probe that frailty. Not trusting the
+ * code, I chose instead to remain in align16 mode in defiance of the hw
+ * docs).
+ *
+ * I've [chadv] experimentally confirmed that, on gen7 hardware and the
+ * simulator, emitting a f32to16 in align16 mode with UD as destination
+ * data type is safe. The behavior differs from that specified in the PRM
+ * in that the upper word of each destination channel is cleared to 0.
+ */
+
+ dst_reg tmp_dst(this, glsl_type::uvec2_type);
+ src_reg tmp_src(tmp_dst);
+
+#if 0
+ /* Verify the undocumented behavior on which the following instructions
+ * rely. If f32to16 fails to clear the upper word of the X and Y channels,
+ * then the result of the bit-or instruction below will be incorrect.
+ *
+ * You should inspect the disasm output in order to verify that the MOV is
+ * not optimized away.
+ */
+ emit(MOV(tmp_dst, src_reg(0x12345678u)));
+#endif
+
+ /* Give tmp the form below, where "." means untouched.
+ *
+ * w z y x w z y x
+ * |.|.|0x0000hhhh|0x0000llll|.|.|0x0000hhhh|0x0000llll|
+ *
+ * That the upper word of each write-channel be 0 is required for the
+ * following bit-shift and bit-or instructions to work. Note that this
+ * relies on the undocumented hardware behavior mentioned above.
+ */
+ tmp_dst.writemask = WRITEMASK_XY;
+ emit(F32TO16(tmp_dst, src0));
+
+ /* Give the write-channels of dst the form:
+ * 0xhhhh0000
+ */
+ tmp_src.swizzle = SWIZZLE_Y;
+ emit(SHL(dst, tmp_src, src_reg(16u)));
+
+ /* Finally, give the write-channels of dst the form of packHalf2x16's
+ * output:
+ * 0xhhhhllll
+ */
+ tmp_src.swizzle = SWIZZLE_X;
+ emit(OR(dst, src_reg(dst), tmp_src));
+}
+
+void
+vec4_visitor::emit_unpack_half_2x16(dst_reg dst, src_reg src0)
+{
+ if (brw->gen < 7)
+ assert(!"ir_unop_unpack_half_2x16 should be lowered");
+
+ assert(dst.type == BRW_REGISTER_TYPE_F);
+ assert(src0.type == BRW_REGISTER_TYPE_UD);
+
+ /* From the Ivybridge PRM, Vol4, Part3, Section 6.26 f16to32:
+ *
+ * Because this instruction does not have a 16-bit floating-point type,
+ * the source data type must be Word (W). The destination type must be
+ * F (Float).
+ *
+ * To use W as the source data type, we must adjust horizontal strides,
+ * which is only possible in align1 mode. All my [chadv] attempts at
+ * emitting align1 instructions for unpackHalf2x16 failed to pass the
+ * Piglit tests, so I gave up.
+ *
+ * I've verified that, on gen7 hardware and the simulator, it is safe to
+ * emit f16to32 in align16 mode with UD as source data type.
+ */
+
+ dst_reg tmp_dst(this, glsl_type::uvec2_type);
+ src_reg tmp_src(tmp_dst);
+
+ tmp_dst.writemask = WRITEMASK_X;
+ emit(AND(tmp_dst, src0, src_reg(0xffffu)));
+
+ tmp_dst.writemask = WRITEMASK_Y;
+ emit(SHR(tmp_dst, src0, src_reg(16u)));
+
+ dst.writemask = WRITEMASK_XY;
+ emit(F16TO32(dst, tmp_src));
+}
+
void
vec4_visitor::visit_instructions(const exec_list *list)
{
* at link time.
*/
return 1;
- default:
+ case GLSL_TYPE_VOID:
+ case GLSL_TYPE_ERROR:
+ case GLSL_TYPE_INTERFACE:
assert(0);
- return 0;
+ break;
}
+
+ return 0;
}
int
* get stored, rather than in some global gl_shader_program uniform
* store.
*/
-int
-vec4_visitor::setup_uniform_values(int loc, const glsl_type *type)
+void
+vec4_visitor::setup_uniform_values(ir_variable *ir)
{
- unsigned int offset = 0;
- float *values = &this->vp->Base.Parameters->ParameterValues[loc][0].f;
-
- if (type->is_matrix()) {
- const glsl_type *column = type->column_type();
-
- for (unsigned int i = 0; i < type->matrix_columns; i++) {
- offset += setup_uniform_values(loc + offset, column);
- }
-
- return offset;
- }
+ int namelen = strlen(ir->name);
- switch (type->base_type) {
- case GLSL_TYPE_FLOAT:
- case GLSL_TYPE_UINT:
- case GLSL_TYPE_INT:
- case GLSL_TYPE_BOOL:
- for (unsigned int i = 0; i < type->vector_elements; i++) {
- c->prog_data.param[this->uniforms * 4 + i] = &values[i];
- }
-
- /* Set up pad elements to get things aligned to a vec4 boundary. */
- for (unsigned int i = type->vector_elements; i < 4; i++) {
- static float zero = 0;
-
- c->prog_data.param[this->uniforms * 4 + i] = &zero;
+ /* The data for our (non-builtin) uniforms is stored in a series of
+ * gl_uniform_driver_storage structs for each subcomponent that
+ * glGetUniformLocation() could name. We know it's been set up in the same
+ * order we'd walk the type, so walk the list of storage and find anything
+ * with our name, or the prefix of a component that starts with our name.
+ */
+ for (unsigned u = 0; u < shader_prog->NumUserUniformStorage; u++) {
+ struct gl_uniform_storage *storage = &shader_prog->UniformStorage[u];
+
+ if (strncmp(ir->name, storage->name, namelen) != 0 ||
+ (storage->name[namelen] != 0 &&
+ storage->name[namelen] != '.' &&
+ storage->name[namelen] != '[')) {
+ continue;
}
- /* Track the size of this uniform vector, for future packing of
- * uniforms.
- */
- this->uniform_vector_size[this->uniforms] = type->vector_elements;
- this->uniforms++;
+ gl_constant_value *components = storage->storage;
+ unsigned vector_count = (MAX2(storage->array_elements, 1) *
+ storage->type->matrix_columns);
- return 1;
+ for (unsigned s = 0; s < vector_count; s++) {
+ uniform_vector_size[uniforms] = storage->type->vector_elements;
- case GLSL_TYPE_STRUCT:
- for (unsigned int i = 0; i < type->length; i++) {
- offset += setup_uniform_values(loc + offset,
- type->fields.structure[i].type);
- }
- return offset;
+ int i;
+ for (i = 0; i < uniform_vector_size[uniforms]; i++) {
+ prog_data->param[uniforms * 4 + i] = &components->f;
+ components++;
+ }
+ for (; i < 4; i++) {
+ static float zero = 0;
+ prog_data->param[uniforms * 4 + i] = &zero;
+ }
- case GLSL_TYPE_ARRAY:
- for (unsigned int i = 0; i < type->length; i++) {
- offset += setup_uniform_values(loc + offset, type->fields.array);
+ uniforms++;
}
- return offset;
-
- case GLSL_TYPE_SAMPLER:
- /* The sampler takes up a slot, but we don't use any values from it. */
- return 1;
-
- default:
- assert(!"not reached");
- return 0;
}
}
{
gl_clip_plane *clip_planes = brw_select_clip_planes(ctx);
- if (intel->gen < 6) {
- /* Pre-Gen6, we compact clip planes. For example, if the user
- * enables just clip planes 0, 1, and 3, we will enable clip planes
- * 0, 1, and 2 in the hardware, and we'll move clip plane 3 to clip
- * plane 2. This simplifies the implementation of the Gen6 clip
- * thread.
- */
- int compacted_clipplane_index = 0;
- for (int i = 0; i < MAX_CLIP_PLANES; ++i) {
- if (!(c->key.userclip_planes_enabled_gen_4_5 & (1 << i)))
- continue;
-
- this->uniform_vector_size[this->uniforms] = 4;
- this->userplane[compacted_clipplane_index] = dst_reg(UNIFORM, this->uniforms);
- this->userplane[compacted_clipplane_index].type = BRW_REGISTER_TYPE_F;
- for (int j = 0; j < 4; ++j) {
- c->prog_data.param[this->uniforms * 4 + j] = &clip_planes[i][j];
- }
- ++compacted_clipplane_index;
- ++this->uniforms;
- }
- } else {
- /* In Gen6 and later, we don't compact clip planes, because this
- * simplifies the implementation of gl_ClipDistance.
- */
- for (int i = 0; i < c->key.nr_userclip_plane_consts; ++i) {
- this->uniform_vector_size[this->uniforms] = 4;
- this->userplane[i] = dst_reg(UNIFORM, this->uniforms);
- this->userplane[i].type = BRW_REGISTER_TYPE_F;
- for (int j = 0; j < 4; ++j) {
- c->prog_data.param[this->uniforms * 4 + j] = &clip_planes[i][j];
- }
- ++this->uniforms;
+ for (int i = 0; i < key->nr_userclip_plane_consts; ++i) {
+ this->uniform_vector_size[this->uniforms] = 4;
+ this->userplane[i] = dst_reg(UNIFORM, this->uniforms);
+ this->userplane[i].type = BRW_REGISTER_TYPE_F;
+ for (int j = 0; j < 4; ++j) {
+ prog_data->param[this->uniforms * 4 + j] = &clip_planes[i][j];
}
+ ++this->uniforms;
}
}
* ParameterValues directly, since unlike brw_fs.cpp, we never
* add new state references during compile.
*/
- int index = _mesa_add_state_reference(this->vp->Base.Parameters,
+ int index = _mesa_add_state_reference(this->prog->Parameters,
(gl_state_index *)slots[i].tokens);
- float *values = &this->vp->Base.Parameters->ParameterValues[index][0].f;
+ float *values = &this->prog->Parameters->ParameterValues[index][0].f;
this->uniform_vector_size[this->uniforms] = 0;
/* Add each of the unique swizzled channels of the element.
int swiz = GET_SWZ(slots[i].swizzle, j);
last_swiz = swiz;
- c->prog_data.param[this->uniforms * 4 + j] = &values[swiz];
+ prog_data->param[this->uniforms * 4 + j] = &values[swiz];
if (swiz <= last_swiz)
this->uniform_vector_size[this->uniforms]++;
}
break;
case ir_unop_f2b:
- if (intel->gen >= 6) {
+ if (brw->gen >= 6) {
emit(CMP(dst_null_d(), op[0], src_reg(0.0f), BRW_CONDITIONAL_NZ));
} else {
inst = emit(MOV(dst_null_f(), op[0]));
break;
case ir_unop_i2b:
- if (intel->gen >= 6) {
+ if (brw->gen >= 6) {
emit(CMP(dst_null_d(), op[0], src_reg(0), BRW_CONDITIONAL_NZ));
} else {
inst = emit(MOV(dst_null_d(), op[0]));
resolve_ud_negate(&this->result);
- if (intel->gen >= 6) {
+ if (brw->gen >= 6) {
vec4_instruction *inst = emit(AND(dst_null_d(),
this->result, src_reg(1)));
inst->conditional_mod = BRW_CONDITIONAL_NZ;
emit(IF(this->result, src_reg(0), BRW_CONDITIONAL_NZ));
}
+dst_reg
+with_writemask(dst_reg const & r, int mask)
+{
+ dst_reg result = r;
+ result.writemask = mask;
+ return result;
+}
+
+
void
vec4_visitor::visit(ir_variable *ir)
{
return;
switch (ir->mode) {
- case ir_var_in:
+ case ir_var_shader_in:
reg = new(mem_ctx) dst_reg(ATTR, ir->location);
-
- /* Do GL_FIXED rescaling for GLES2.0. Our GL_FIXED attributes
- * come in as floating point conversions of the integer values.
- */
- for (int i = ir->location; i < ir->location + type_size(ir->type); i++) {
- if (!c->key.gl_fixed_input_size[i])
- continue;
-
- dst_reg dst = *reg;
- dst.type = brw_type_for_base_type(ir->type);
- dst.writemask = (1 << c->key.gl_fixed_input_size[i]) - 1;
- emit(MUL(dst, src_reg(dst), src_reg(1.0f / 65536.0f)));
- }
break;
- case ir_var_out:
+ case ir_var_shader_out:
reg = new(mem_ctx) dst_reg(this, ir->type);
for (int i = 0; i < type_size(ir->type); i++) {
* ir_binop_ubo_load expressions and not ir_dereference_variable for UBO
* variables, so no need for them to be in variable_ht.
*/
- if (ir->uniform_block != -1)
+ if (ir->is_in_uniform_block())
return;
/* Track how big the whole uniform variable is, in case we need to put a
if (!strncmp(ir->name, "gl_", 3)) {
setup_builtin_uniform_values(ir);
} else {
- setup_uniform_values(ir->location, ir->type);
+ setup_uniform_values(ir);
}
break;
case ir_var_system_value:
- /* VertexID is stored by the VF as the last vertex element, but
- * we don't represent it with a flag in inputs_read, so we call
- * it VERT_ATTRIB_MAX, which setup_attributes() picks up on.
- */
- reg = new(mem_ctx) dst_reg(ATTR, VERT_ATTRIB_MAX);
- prog_data->uses_vertexid = true;
-
- switch (ir->location) {
- case SYSTEM_VALUE_VERTEX_ID:
- reg->writemask = WRITEMASK_X;
- break;
- case SYSTEM_VALUE_INSTANCE_ID:
- reg->writemask = WRITEMASK_Y;
- break;
- default:
- assert(!"not reached");
- break;
- }
+ reg = make_reg_for_system_value(ir);
break;
default:
const ir_function_signature *sig;
exec_list empty;
- sig = ir->matching_signature(&empty);
+ sig = ir->matching_signature(NULL, &empty);
assert(sig);
return true;
}
+bool
+vec4_visitor::try_emit_mad(ir_expression *ir, int mul_arg)
+{
+ /* 3-src instructions were introduced in gen6. */
+ if (brw->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)
{
/* original gen4 does destination conversion before comparison. */
- if (intel->gen < 5)
+ if (brw->gen < 5)
dst.type = src0.type;
emit(CMP(dst, src0, src1, brw_conditional_for_comparison(op)));
{
vec4_instruction *inst;
- if (intel->gen >= 6) {
+ if (brw->gen >= 6) {
inst = emit(BRW_OPCODE_SEL, dst, src0, src1);
inst->conditional_mod = conditionalmod;
} else {
}
}
+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);
break;
case ir_unop_neg:
op[0].negate = !op[0].negate;
- this->result = op[0];
+ emit(MOV(result_dst, op[0]));
break;
case ir_unop_abs:
op[0].abs = true;
op[0].negate = false;
- this->result = op[0];
+ emit(MOV(result_dst, op[0]));
break;
case ir_unop_sign:
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 (brw->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 (brw->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(), result_dst.type);
+
+ 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]));
}
break;
+ case ir_binop_imul_high: {
+ struct brw_reg acc = retype(brw_acc_reg(), result_dst.type);
+
+ emit(MUL(acc, op[0], op[1]));
+ emit(MACH(result_dst, op[0], op[1]));
+ break;
+ }
case ir_binop_div:
/* Floating point should be lowered by DIV_TO_MUL_RCP in the compiler. */
assert(ir->type->is_integer());
emit_math(SHADER_OPCODE_INT_QUOTIENT, result_dst, op[0], op[1]);
break;
+ case ir_binop_carry: {
+ struct brw_reg acc = retype(brw_acc_reg(), BRW_REGISTER_TYPE_UD);
+
+ emit(ADDC(dst_null_ud(), op[0], op[1]));
+ emit(MOV(result_dst, src_reg(acc)));
+ break;
+ }
+ case ir_binop_borrow: {
+ struct brw_reg acc = retype(brw_acc_reg(), BRW_REGISTER_TYPE_UD);
+
+ emit(SUBB(dst_null_ud(), op[0], op[1]));
+ emit(MOV(result_dst, src_reg(acc)));
+ break;
+ }
case ir_binop_mod:
/* Floating point should be lowered by MOD_TO_FRACT in the compiler. */
assert(ir->type->is_integer());
break;
case ir_binop_lshift:
- inst = emit(BRW_OPCODE_SHL, result_dst, op[0], op[1]);
+ inst = emit(SHL(result_dst, op[0], op[1]));
break;
case ir_binop_rshift:
if (ir->type->base_type == GLSL_TYPE_INT)
- inst = emit(BRW_OPCODE_ASR, result_dst, op[0], op[1]);
+ inst = emit(ASR(result_dst, op[0], op[1]));
else
- inst = emit(BRW_OPCODE_SHR, 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: {
src_reg packed_consts = src_reg(this, glsl_type::vec4_type);
packed_consts.type = result.type;
src_reg surf_index =
- src_reg(SURF_INDEX_VS_UBO(uniform_block->value.u[0]));
+ src_reg(prog_data->base.binding_table.ubo_start + uniform_block->value.u[0]);
if (const_offset_ir) {
offset = src_reg(const_offset / 16);
} else {
- emit(BRW_OPCODE_SHR, dst_reg(offset), offset, src_reg(4));
+ emit(SHR(dst_reg(offset), offset, src_reg(4)));
}
vec4_instruction *pull =
break;
}
+ case ir_binop_vector_extract:
+ assert(!"should have been lowered by vec_index_to_cond_assign");
+ break;
+
+ case ir_triop_fma:
+ 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(MAD(result_dst, op[2], op[1], op[0]));
+ break;
+
+ case ir_triop_lrp:
+ 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_csel:
+ emit(CMP(dst_null_d(), op[0], src_reg(0), BRW_CONDITIONAL_NZ));
+ inst = emit(BRW_OPCODE_SEL, result_dst, op[1], op[2]);
+ inst->predicate = BRW_PREDICATE_NORMAL;
+ 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:
assert(!"not reached: should be handled by lower_quadop_vector");
break;
+
+ case ir_unop_pack_half_2x16:
+ emit_pack_half_2x16(result_dst, op[0]);
+ break;
+ case ir_unop_unpack_half_2x16:
+ emit_unpack_half_2x16(result_dst, op[0]);
+ break;
+ case ir_unop_pack_snorm_2x16:
+ case ir_unop_pack_snorm_4x8:
+ case ir_unop_pack_unorm_2x16:
+ case ir_unop_pack_unorm_4x8:
+ case ir_unop_unpack_snorm_2x16:
+ case ir_unop_unpack_snorm_4x8:
+ case ir_unop_unpack_unorm_2x16:
+ case ir_unop_unpack_unorm_4x8:
+ assert(!"not reached: should be handled by lower_packing_builtins");
+ break;
+ case ir_unop_unpack_half_2x16_split_x:
+ case ir_unop_unpack_half_2x16_split_y:
+ case ir_binop_pack_half_2x16_split:
+ assert(!"not reached: should not occur in vertex shader");
+ break;
+ case ir_binop_ldexp:
+ assert(!"not reached: should be handled by ldexp_to_arith()");
+ break;
}
}
this->result.swizzle = swizzle_for_size(type->vector_elements);
}
+
+int
+vec4_visitor::compute_array_stride(ir_dereference_array *ir)
+{
+ /* Under normal circumstances array elements are stored consecutively, so
+ * the stride is equal to the size of the array element.
+ */
+ return type_size(ir->type);
+}
+
+
void
vec4_visitor::visit(ir_dereference_array *ir)
{
ir_constant *constant_index;
src_reg src;
- int element_size = type_size(ir->type);
+ int array_stride = compute_array_stride(ir);
constant_index = ir->array_index->constant_expression_value();
src = this->result;
if (constant_index) {
- src.reg_offset += constant_index->value.i[0] * element_size;
+ src.reg_offset += constant_index->value.i[0] * array_stride;
} else {
/* Variable index array dereference. It eats the "vec4" of the
* base of the array and an index that offsets the Mesa register
src_reg index_reg;
- if (element_size == 1) {
+ if (array_stride == 1) {
index_reg = this->result;
} else {
index_reg = src_reg(this, glsl_type::int_type);
- emit(MUL(dst_reg(index_reg), this->result, src_reg(element_size)));
+ emit(MUL(dst_reg(index_reg), this->result, src_reg(array_stride)));
}
if (src.reladdr) {
void
vec4_visitor::visit(ir_texture *ir)
{
- int sampler = _mesa_get_sampler_uniform_value(ir->sampler, prog, &vp->Base);
+ int sampler =
+ _mesa_get_sampler_uniform_value(ir->sampler, shader_prog, prog);
+
+ /* When tg4 is used with the degenerate ZERO/ONE swizzles, don't bother
+ * emitting anything other than setting up the constant result.
+ */
+ if (ir->op == ir_tg4) {
+ ir_constant *chan = ir->lod_info.component->as_constant();
+ int swiz = GET_SWZ(key->tex.swizzles[sampler], chan->value.i[0]);
+ if (swiz == SWIZZLE_ZERO || swiz == SWIZZLE_ONE) {
+ dst_reg result(this, ir->type);
+ this->result = src_reg(result);
+ emit(MOV(result, src_reg(swiz == SWIZZLE_ONE ? 1.0f : 0.0f)));
+ return;
+ }
+ }
/* Should be lowered by do_lower_texture_projection */
assert(!ir->projector);
shadow_comparitor = this->result;
}
- src_reg lod, dPdx, dPdy;
+ const glsl_type *lod_type = NULL, *sample_index_type = NULL;
+ src_reg lod, dPdx, dPdy, sample_index;
switch (ir->op) {
+ case ir_tex:
+ lod = src_reg(0.0f);
+ lod_type = glsl_type::float_type;
+ break;
case ir_txf:
case ir_txl:
case ir_txs:
ir->lod_info.lod->accept(this);
lod = this->result;
+ lod_type = ir->lod_info.lod->type;
+ break;
+ case ir_query_levels:
+ lod = src_reg(0);
+ lod_type = glsl_type::int_type;
+ break;
+ case ir_txf_ms:
+ ir->lod_info.sample_index->accept(this);
+ sample_index = this->result;
+ sample_index_type = ir->lod_info.sample_index->type;
break;
case ir_txd:
ir->lod_info.grad.dPdx->accept(this);
ir->lod_info.grad.dPdy->accept(this);
dPdy = this->result;
+
+ lod_type = ir->lod_info.grad.dPdx->type;
break;
- case ir_tex:
case ir_txb:
+ case ir_lod:
+ case ir_tg4:
break;
}
case ir_txf:
inst = new(mem_ctx) vec4_instruction(this, SHADER_OPCODE_TXF);
break;
+ case ir_txf_ms:
+ inst = new(mem_ctx) vec4_instruction(this, SHADER_OPCODE_TXF_MS);
+ break;
case ir_txs:
inst = new(mem_ctx) vec4_instruction(this, SHADER_OPCODE_TXS);
break;
+ case ir_tg4:
+ inst = new(mem_ctx) vec4_instruction(this, SHADER_OPCODE_TG4);
+ break;
+ case ir_query_levels:
+ inst = new(mem_ctx) vec4_instruction(this, SHADER_OPCODE_TXS);
+ break;
case ir_txb:
assert(!"TXB is not valid for vertex shaders.");
+ break;
+ case ir_lod:
+ assert(!"LOD is not valid for vertex shaders.");
+ break;
+ default:
+ assert(!"Unrecognized tex op");
}
+ bool use_texture_offset = ir->offset != NULL && ir->op != ir_txf;
+
/* Texel offsets go in the message header; Gen4 also requires headers. */
- inst->header_present = ir->offset || intel->gen < 5;
+ inst->header_present = use_texture_offset || brw->gen < 5 || ir->op == ir_tg4;
inst->base_mrf = 2;
inst->mlen = inst->header_present + 1; /* always at least one */
inst->sampler = sampler;
inst->dst = dst_reg(this, ir->type);
+ inst->dst.writemask = WRITEMASK_XYZW;
inst->shadow_compare = ir->shadow_comparitor != NULL;
- if (ir->offset != NULL && ir->op != ir_txf)
+ if (use_texture_offset)
inst->texture_offset = brw_texture_offset(ir->offset->as_constant());
+ /* Stuff the channel select bits in the top of the texture offset */
+ if (ir->op == ir_tg4)
+ inst->texture_offset |= gather_channel(ir, sampler)<<16;
+
/* MRF for the first parameter */
int param_base = inst->base_mrf + inst->header_present;
- if (ir->op == ir_txs) {
- int writemask = intel->gen == 4 ? WRITEMASK_W : WRITEMASK_X;
- emit(MOV(dst_reg(MRF, param_base, ir->lod_info.lod->type, writemask),
- lod));
+ if (ir->op == ir_txs || ir->op == ir_query_levels) {
+ int writemask = brw->gen == 4 ? WRITEMASK_W : WRITEMASK_X;
+ emit(MOV(dst_reg(MRF, param_base, lod_type, writemask), lod));
} else {
- int i, coord_mask = 0, zero_mask = 0;
/* Load the coordinate */
/* FINISHME: gl_clamp_mask and saturate */
- for (i = 0; i < ir->coordinate->type->vector_elements; i++)
- coord_mask |= (1 << i);
- for (; i < 4; i++)
- zero_mask |= (1 << i);
+ int coord_mask = (1 << ir->coordinate->type->vector_elements) - 1;
+ int zero_mask = 0xf & ~coord_mask;
if (ir->offset && ir->op == ir_txf) {
/* It appears that the ld instruction used for txf does its
emit(MOV(dst_reg(MRF, param_base, ir->coordinate->type, coord_mask),
coordinate));
}
- emit(MOV(dst_reg(MRF, param_base, ir->coordinate->type, zero_mask),
- src_reg(0)));
+ if (zero_mask != 0) {
+ 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));
}
/* Load the LOD info */
- if (ir->op == ir_txl) {
+ if (ir->op == ir_tex || ir->op == ir_txl) {
int mrf, writemask;
- if (intel->gen >= 5) {
+ if (brw->gen >= 5) {
mrf = param_base + 1;
if (ir->shadow_comparitor) {
writemask = WRITEMASK_Y;
writemask = WRITEMASK_X;
inst->mlen++;
}
- } else /* intel->gen == 4 */ {
+ } else /* brw->gen == 4 */ {
mrf = param_base;
- writemask = WRITEMASK_Z;
+ writemask = WRITEMASK_W;
}
- emit(MOV(dst_reg(MRF, mrf, ir->lod_info.lod->type, writemask), lod));
+ emit(MOV(dst_reg(MRF, mrf, lod_type, writemask), lod));
} else if (ir->op == ir_txf) {
- emit(MOV(dst_reg(MRF, param_base, ir->lod_info.lod->type, WRITEMASK_W),
- lod));
+ emit(MOV(dst_reg(MRF, param_base, lod_type, WRITEMASK_W), lod));
+ } else if (ir->op == ir_txf_ms) {
+ emit(MOV(dst_reg(MRF, param_base + 1, sample_index_type, WRITEMASK_X),
+ sample_index));
+ inst->mlen++;
+
+ /* on Gen7, there is an additional MCS parameter here after SI,
+ * but we don't bother to emit it since it's always zero. If
+ * we start supporting texturing from CMS surfaces, this will have
+ * to change
+ */
} else if (ir->op == ir_txd) {
- const glsl_type *type = ir->lod_info.grad.dPdx->type;
+ const glsl_type *type = lod_type;
- if (intel->gen >= 5) {
+ if (brw->gen >= 5) {
dPdx.swizzle = BRW_SWIZZLE4(SWIZZLE_X,SWIZZLE_X,SWIZZLE_Y,SWIZZLE_Y);
dPdy.swizzle = BRW_SWIZZLE4(SWIZZLE_X,SWIZZLE_X,SWIZZLE_Y,SWIZZLE_Y);
emit(MOV(dst_reg(MRF, param_base + 1, type, WRITEMASK_XZ), dPdx));
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 */ {
+ } else /* brw->gen == 4 */ {
emit(MOV(dst_reg(MRF, param_base + 1, type, WRITEMASK_XYZ), dPdx));
emit(MOV(dst_reg(MRF, param_base + 2, type, WRITEMASK_XYZ), dPdy));
inst->mlen += 2;
emit(inst);
+ /* fixup num layers (z) for cube arrays: hardware returns faces * layers;
+ * spec requires layers.
+ */
+ if (ir->op == ir_txs) {
+ glsl_type const *type = ir->sampler->type;
+ if (type->sampler_dimensionality == GLSL_SAMPLER_DIM_CUBE &&
+ type->sampler_array) {
+ emit_math(SHADER_OPCODE_INT_QUOTIENT,
+ with_writemask(inst->dst, WRITEMASK_Z),
+ src_reg(inst->dst), src_reg(6));
+ }
+ }
+
swizzle_result(ir, src_reg(inst->dst), sampler);
}
+/**
+ * Set up the gather channel based on the swizzle, for gather4.
+ */
+uint32_t
+vec4_visitor::gather_channel(ir_texture *ir, int sampler)
+{
+ ir_constant *chan = ir->lod_info.component->as_constant();
+ int swiz = GET_SWZ(key->tex.swizzles[sampler], chan->value.i[0]);
+ switch (swiz) {
+ case SWIZZLE_X: return 0;
+ case SWIZZLE_Y:
+ /* gather4 sampler is broken for green channel on RG32F --
+ * we must ask for blue instead.
+ */
+ if (key->tex.gather_channel_quirk_mask & (1<<sampler))
+ return 2;
+ return 1;
+ case SWIZZLE_Z: return 2;
+ case SWIZZLE_W: return 3;
+ default:
+ assert(!"Not reached"); /* zero, one swizzles handled already */
+ return 0;
+ }
+}
+
void
vec4_visitor::swizzle_result(ir_texture *ir, src_reg orig_val, int sampler)
{
- this->result = orig_val;
+ int s = key->tex.swizzles[sampler];
- int s = c->key.tex.swizzles[sampler];
+ this->result = src_reg(this, ir->type);
+ dst_reg swizzled_result(this->result);
+
+ if (ir->op == ir_query_levels) {
+ /* # levels is in .w */
+ orig_val.swizzle = BRW_SWIZZLE4(SWIZZLE_W, SWIZZLE_W, SWIZZLE_W, SWIZZLE_W);
+ emit(MOV(swizzled_result, orig_val));
+ return;
+ }
if (ir->op == ir_txs || ir->type == glsl_type::float_type
- || s == SWIZZLE_NOOP)
+ || s == SWIZZLE_NOOP || ir->op == ir_tg4) {
+ emit(MOV(swizzled_result, orig_val));
return;
+ }
+
int zero_mask = 0, one_mask = 0, copy_mask = 0;
- int swizzle[4];
+ int swizzle[4] = {0};
for (int i = 0; i < 4; i++) {
switch (GET_SWZ(s, i)) {
}
}
- this->result = src_reg(this, ir->type);
- dst_reg swizzled_result(this->result);
-
if (copy_mask) {
orig_val.swizzle = BRW_SWIZZLE4(swizzle[0], swizzle[1], swizzle[2], swizzle[3]);
swizzled_result.writemask = copy_mask;
*/
this->base_ir = ir->condition;
- if (intel->gen == 6) {
+ if (brw->gen == 6) {
emit_if_gen6(ir);
} else {
uint32_t predicate;
emit(BRW_OPCODE_ENDIF);
}
+void
+vec4_visitor::visit(ir_emit_vertex *)
+{
+ assert(!"not reached");
+}
+
+void
+vec4_visitor::visit(ir_end_primitive *)
+{
+ assert(!"not reached");
+}
+
void
vec4_visitor::emit_ndc_computation()
{
/* Get the position */
- src_reg pos = src_reg(output_reg[VERT_RESULT_HPOS]);
+ src_reg pos = src_reg(output_reg[VARYING_SLOT_POS]);
/* Build ndc coords, which are (x/w, y/w, z/w, 1/w) */
dst_reg ndc = dst_reg(this, glsl_type::vec4_type);
- output_reg[BRW_VERT_RESULT_NDC] = ndc;
+ output_reg[BRW_VARYING_SLOT_NDC] = ndc;
current_annotation = "NDC";
dst_reg ndc_w = ndc;
void
vec4_visitor::emit_psiz_and_flags(struct brw_reg reg)
{
- if (intel->gen < 6 &&
- ((c->prog_data.outputs_written & BITFIELD64_BIT(VERT_RESULT_PSIZ)) ||
- c->key.userclip_active || brw->has_negative_rhw_bug)) {
+ if (brw->gen < 6 &&
+ ((prog_data->vue_map.slots_valid & VARYING_BIT_PSIZ) ||
+ key->userclip_active || brw->has_negative_rhw_bug)) {
dst_reg header1 = dst_reg(this, glsl_type::uvec4_type);
dst_reg header1_w = header1;
header1_w.writemask = WRITEMASK_W;
- GLuint i;
emit(MOV(header1, 0u));
- if (c->prog_data.outputs_written & BITFIELD64_BIT(VERT_RESULT_PSIZ)) {
- src_reg psiz = src_reg(output_reg[VERT_RESULT_PSIZ]);
+ if (prog_data->vue_map.slots_valid & VARYING_BIT_PSIZ) {
+ src_reg psiz = src_reg(output_reg[VARYING_SLOT_PSIZ]);
current_annotation = "Point size";
emit(MUL(header1_w, psiz, src_reg((float)(1 << 11))));
emit(AND(header1_w, src_reg(header1_w), 0x7ff << 8));
}
- current_annotation = "Clipping flags";
- for (i = 0; i < c->key.nr_userclip_plane_consts; i++) {
- vec4_instruction *inst;
+ if (key->userclip_active) {
+ current_annotation = "Clipping flags";
+ dst_reg flags0 = dst_reg(this, glsl_type::uint_type);
+ dst_reg flags1 = dst_reg(this, glsl_type::uint_type);
- inst = emit(DP4(dst_null_f(), src_reg(output_reg[VERT_RESULT_HPOS]),
- src_reg(this->userplane[i])));
- inst->conditional_mod = BRW_CONDITIONAL_L;
+ emit(CMP(dst_null_f(), src_reg(output_reg[VARYING_SLOT_CLIP_DIST0]), src_reg(0.0f), BRW_CONDITIONAL_L));
+ emit(VS_OPCODE_UNPACK_FLAGS_SIMD4X2, flags0, src_reg(0));
+ emit(OR(header1_w, src_reg(header1_w), src_reg(flags0)));
- inst = emit(OR(header1_w, src_reg(header1_w), 1u << i));
- inst->predicate = BRW_PREDICATE_NORMAL;
+ emit(CMP(dst_null_f(), src_reg(output_reg[VARYING_SLOT_CLIP_DIST1]), src_reg(0.0f), BRW_CONDITIONAL_L));
+ emit(VS_OPCODE_UNPACK_FLAGS_SIMD4X2, flags1, src_reg(0));
+ emit(SHL(flags1, src_reg(flags1), src_reg(4)));
+ emit(OR(header1_w, src_reg(header1_w), src_reg(flags1)));
}
/* i965 clipping workaround:
* clipped against all fixed planes.
*/
if (brw->has_negative_rhw_bug) {
-#if 0
- /* FINISHME */
- brw_CMP(p,
- vec8(brw_null_reg()),
- BRW_CONDITIONAL_L,
- brw_swizzle1(output_reg[BRW_VERT_RESULT_NDC], 3),
- brw_imm_f(0));
-
- brw_OR(p, brw_writemask(header1, WRITEMASK_W), header1, brw_imm_ud(1<<6));
- brw_MOV(p, output_reg[BRW_VERT_RESULT_NDC], brw_imm_f(0));
- brw_set_predicate_control(p, BRW_PREDICATE_NONE);
-#endif
+ src_reg ndc_w = src_reg(output_reg[BRW_VARYING_SLOT_NDC]);
+ ndc_w.swizzle = BRW_SWIZZLE_WWWW;
+ emit(CMP(dst_null_f(), ndc_w, src_reg(0.0f), BRW_CONDITIONAL_L));
+ vec4_instruction *inst;
+ inst = emit(OR(header1_w, src_reg(header1_w), src_reg(1u << 6)));
+ inst->predicate = BRW_PREDICATE_NORMAL;
+ inst = emit(MOV(output_reg[BRW_VARYING_SLOT_NDC], src_reg(0.0f)));
+ inst->predicate = BRW_PREDICATE_NORMAL;
}
emit(MOV(retype(reg, BRW_REGISTER_TYPE_UD), src_reg(header1)));
- } else if (intel->gen < 6) {
+ } else if (brw->gen < 6) {
emit(MOV(retype(reg, BRW_REGISTER_TYPE_UD), 0u));
} else {
emit(MOV(retype(reg, BRW_REGISTER_TYPE_D), src_reg(0)));
- if (c->prog_data.outputs_written & BITFIELD64_BIT(VERT_RESULT_PSIZ)) {
+ if (prog_data->vue_map.slots_valid & VARYING_BIT_PSIZ) {
emit(MOV(brw_writemask(reg, WRITEMASK_W),
- src_reg(output_reg[VERT_RESULT_PSIZ])));
+ 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])));
}
}
}
void
-vec4_visitor::emit_clip_distances(struct brw_reg reg, int offset)
+vec4_visitor::emit_clip_distances(dst_reg reg, int offset)
{
- if (intel->gen < 6) {
- /* Clip distance slots are set aside in gen5, but they are not used. It
- * is not clear whether we actually need to set aside space for them,
- * but the performance cost is negligible.
- */
- return;
- }
-
/* From the GLSL 1.30 spec, section 7.1 (Vertex Shader Special Variables):
*
* "If a linked set of shaders forming the vertex stage contains no
* gl_ClipDistance. Accordingly, we use gl_ClipVertex to perform clipping
* if the user wrote to it; otherwise we use gl_Position.
*/
- gl_vert_result clip_vertex = VERT_RESULT_CLIP_VERTEX;
- if (!(c->prog_data.outputs_written
- & BITFIELD64_BIT(VERT_RESULT_CLIP_VERTEX))) {
- clip_vertex = VERT_RESULT_HPOS;
+ gl_varying_slot clip_vertex = VARYING_SLOT_CLIP_VERTEX;
+ if (!(prog_data->vue_map.slots_valid & VARYING_BIT_CLIP_VERTEX)) {
+ clip_vertex = VARYING_SLOT_POS;
}
- for (int i = 0; i + offset < c->key.nr_userclip_plane_consts && i < 4;
+ for (int i = 0; i + offset < key->nr_userclip_plane_consts && i < 4;
++i) {
- emit(DP4(dst_reg(brw_writemask(reg, 1 << i)),
+ reg.writemask = 1 << i;
+ emit(DP4(reg,
src_reg(output_reg[clip_vertex]),
src_reg(this->userplane[i + offset])));
}
}
void
-vec4_visitor::emit_generic_urb_slot(dst_reg reg, int vert_result)
+vec4_visitor::emit_generic_urb_slot(dst_reg reg, int varying)
{
- assert (vert_result < VERT_RESULT_MAX);
- reg.type = output_reg[vert_result].type;
- current_annotation = output_reg_annotation[vert_result];
+ assert (varying < VARYING_SLOT_MAX);
+ reg.type = output_reg[varying].type;
+ current_annotation = output_reg_annotation[varying];
/* Copy the register, saturating if necessary */
vec4_instruction *inst = emit(MOV(reg,
- src_reg(output_reg[vert_result])));
- if ((vert_result == VERT_RESULT_COL0 ||
- vert_result == VERT_RESULT_COL1 ||
- vert_result == VERT_RESULT_BFC0 ||
- vert_result == VERT_RESULT_BFC1) &&
- c->key.clamp_vertex_color) {
+ src_reg(output_reg[varying])));
+ if ((varying == VARYING_SLOT_COL0 ||
+ varying == VARYING_SLOT_COL1 ||
+ varying == VARYING_SLOT_BFC0 ||
+ varying == VARYING_SLOT_BFC1) &&
+ key->clamp_vertex_color) {
inst->saturate = true;
}
}
void
-vec4_visitor::emit_urb_slot(int mrf, int vert_result)
+vec4_visitor::emit_urb_slot(int mrf, int varying)
{
struct brw_reg hw_reg = brw_message_reg(mrf);
dst_reg reg = dst_reg(MRF, mrf);
reg.type = BRW_REGISTER_TYPE_F;
- switch (vert_result) {
- case VERT_RESULT_PSIZ:
+ switch (varying) {
+ case VARYING_SLOT_PSIZ:
/* PSIZ is always in slot 0, and is coupled with other flags. */
current_annotation = "indices, point width, clip flags";
emit_psiz_and_flags(hw_reg);
break;
- case BRW_VERT_RESULT_NDC:
+ case BRW_VARYING_SLOT_NDC:
current_annotation = "NDC";
- emit(MOV(reg, src_reg(output_reg[BRW_VERT_RESULT_NDC])));
+ emit(MOV(reg, src_reg(output_reg[BRW_VARYING_SLOT_NDC])));
break;
- case BRW_VERT_RESULT_HPOS_DUPLICATE:
- case VERT_RESULT_HPOS:
+ case VARYING_SLOT_POS:
current_annotation = "gl_Position";
- emit(MOV(reg, src_reg(output_reg[VERT_RESULT_HPOS])));
+ emit(MOV(reg, src_reg(output_reg[VARYING_SLOT_POS])));
break;
- case VERT_RESULT_CLIP_DIST0:
- case VERT_RESULT_CLIP_DIST1:
- if (this->c->key.uses_clip_distance) {
- emit_generic_urb_slot(reg, vert_result);
- } else {
- current_annotation = "user clip distances";
- emit_clip_distances(hw_reg, (vert_result - VERT_RESULT_CLIP_DIST0) * 4);
- }
- break;
- case VERT_RESULT_EDGE:
+ case VARYING_SLOT_EDGE:
/* This is present when doing unfilled polygons. We're supposed to copy
* the edge flag from the user-provided vertex array
* (glEdgeFlagPointer), or otherwise we'll copy from the current value
emit(MOV(reg, src_reg(dst_reg(ATTR, VERT_ATTRIB_EDGEFLAG,
glsl_type::float_type, WRITEMASK_XYZW))));
break;
- case BRW_VERT_RESULT_PAD:
+ case BRW_VARYING_SLOT_PAD:
/* No need to write to this slot */
break;
default:
- emit_generic_urb_slot(reg, vert_result);
+ emit_generic_urb_slot(reg, varying);
break;
}
}
static int
align_interleaved_urb_mlen(struct brw_context *brw, int mlen)
{
- struct intel_context *intel = &brw->intel;
-
- if (intel->gen >= 6) {
+ if (brw->gen >= 6) {
/* URB data written (does not include the message header reg) must
* be a multiple of 256 bits, or 2 VS registers. See vol5c.5,
* section 5.4.3.2.2: URB_INTERLEAVED.
return mlen;
}
+
/**
- * Generates the VUE payload plus the 1 or 2 URB write instructions to
- * complete the VS thread.
+ * Generates the VUE payload plus the necessary URB write instructions to
+ * output it.
*
* The VUE layout is documented in Volume 2a.
*/
void
-vec4_visitor::emit_urb_writes()
+vec4_visitor::emit_vertex()
{
/* MRF 0 is reserved for the debugger, so start with message header
* in MRF 1.
*/
assert ((max_usable_mrf - base_mrf) % 2 == 0);
- /* First mrf is the g0-based message header containing URB handles and such,
- * which is implied in VS_OPCODE_URB_WRITE.
+ /* First mrf is the g0-based message header containing URB handles and
+ * such.
*/
- mrf++;
+ emit_urb_write_header(mrf++);
- if (intel->gen < 6) {
+ if (brw->gen < 6) {
emit_ndc_computation();
}
- /* Set up the VUE data for the first URB write */
- int slot;
- for (slot = 0; slot < c->prog_data.vue_map.num_slots; ++slot) {
- emit_urb_slot(mrf++, c->prog_data.vue_map.slot_to_vert_result[slot]);
+ /* Lower legacy ff and ClipVertex clipping to clip distances */
+ if (key->userclip_active && !key->uses_clip_distance) {
+ current_annotation = "user clip distances";
- /* If this was max_usable_mrf, we can't fit anything more into this URB
- * WRITE.
- */
- if (mrf > max_usable_mrf) {
- slot++;
- break;
- }
+ output_reg[VARYING_SLOT_CLIP_DIST0] = dst_reg(this, glsl_type::vec4_type);
+ output_reg[VARYING_SLOT_CLIP_DIST1] = dst_reg(this, glsl_type::vec4_type);
+
+ emit_clip_distances(output_reg[VARYING_SLOT_CLIP_DIST0], 0);
+ emit_clip_distances(output_reg[VARYING_SLOT_CLIP_DIST1], 4);
}
- current_annotation = "URB write";
- vec4_instruction *inst = emit(VS_OPCODE_URB_WRITE);
- inst->base_mrf = base_mrf;
- inst->mlen = align_interleaved_urb_mlen(brw, mrf - base_mrf);
- inst->eot = (slot >= c->prog_data.vue_map.num_slots);
+ /* We may need to split this up into several URB writes, so do them in a
+ * loop.
+ */
+ int slot = 0;
+ bool complete = false;
+ do {
+ /* URB offset is in URB row increments, and each of our MRFs is half of
+ * one of those, since we're doing interleaved writes.
+ */
+ int offset = slot / 2;
- /* Optional second URB write */
- if (!inst->eot) {
mrf = base_mrf + 1;
-
- for (; slot < c->prog_data.vue_map.num_slots; ++slot) {
- assert(mrf < max_usable_mrf);
-
- emit_urb_slot(mrf++, c->prog_data.vue_map.slot_to_vert_result[slot]);
+ for (; slot < prog_data->vue_map.num_slots; ++slot) {
+ emit_urb_slot(mrf++, prog_data->vue_map.slot_to_varying[slot]);
+
+ /* If this was max_usable_mrf, we can't fit anything more into this
+ * URB WRITE.
+ */
+ if (mrf > max_usable_mrf) {
+ slot++;
+ break;
+ }
}
+ complete = slot >= prog_data->vue_map.num_slots;
current_annotation = "URB write";
- inst = emit(VS_OPCODE_URB_WRITE);
+ vec4_instruction *inst = emit_urb_write_opcode(complete);
inst->base_mrf = base_mrf;
inst->mlen = align_interleaved_urb_mlen(brw, mrf - base_mrf);
- inst->eot = true;
- /* URB destination offset. In the previous write, we got MRFs
- * 2-13 minus the one header MRF, so 12 regs. URB offset is in
- * URB row increments, and each of our MRFs is half of one of
- * those, since we're doing interleaved writes.
- */
- inst->offset = (max_usable_mrf - base_mrf) / 2;
- }
+ inst->offset += offset;
+ } while(!complete);
}
+
src_reg
vec4_visitor::get_scratch_offset(vec4_instruction *inst,
src_reg *reladdr, int reg_offset)
/* Pre-gen6, the message header uses byte offsets instead of vec4
* (16-byte) offset units.
*/
- if (intel->gen < 6)
+ if (brw->gen < 6)
message_header_scale *= 16;
if (reladdr) {
/* Pre-gen6, the message header uses byte offsets instead of vec4
* (16-byte) offset units.
*/
- if (intel->gen < 6) {
+ if (brw->gen < 6) {
emit_before(inst, MUL(dst_reg(index), index, src_reg(16)));
}
return index;
} else {
- int message_header_scale = intel->gen < 6 ? 16 : 1;
+ int message_header_scale = brw->gen < 6 ? 16 : 1;
return src_reg(reg_offset * message_header_scale);
}
}
int base_offset)
{
int reg_offset = base_offset + orig_src.reg_offset;
- src_reg index = src_reg((unsigned)SURF_INDEX_VERT_CONST_BUFFER);
+ src_reg index = src_reg(prog_data->base.binding_table.pull_constants_start);
src_reg offset = get_pull_constant_offset(inst, orig_src.reladdr, reg_offset);
vec4_instruction *load;
- load = new(mem_ctx) vec4_instruction(this, VS_OPCODE_PULL_CONSTANT_LOAD,
- temp, index, offset);
- load->base_mrf = 14;
- load->mlen = 1;
+ if (brw->gen >= 7) {
+ dst_reg grf_offset = dst_reg(this, glsl_type::int_type);
+ grf_offset.type = offset.type;
+ emit_before(inst, MOV(grf_offset, offset));
+
+ load = new(mem_ctx) vec4_instruction(this,
+ VS_OPCODE_PULL_CONSTANT_LOAD_GEN7,
+ temp, index, src_reg(grf_offset));
+ } else {
+ load = new(mem_ctx) vec4_instruction(this, VS_OPCODE_PULL_CONSTANT_LOAD,
+ temp, index, offset);
+ load->base_mrf = 14;
+ load->mlen = 1;
+ }
emit_before(inst, load);
}
pull_constant_loc[uniform] = prog_data->nr_pull_params / 4;
for (int j = 0; j < uniform_size[uniform] * 4; j++) {
- prog_data->pull_param[prog_data->nr_pull_params++] = values[j];
+ prog_data->pull_param[prog_data->nr_pull_params++]
+ = values[j];
}
}
*reg = temp;
}
-vec4_visitor::vec4_visitor(struct brw_vs_compile *c,
- struct gl_shader_program *prog,
- struct brw_shader *shader)
-{
- this->c = c;
- this->p = &c->func;
- this->brw = p->brw;
- this->intel = &brw->intel;
- this->ctx = &intel->ctx;
- this->prog = prog;
+vec4_visitor::vec4_visitor(struct brw_context *brw,
+ struct brw_vec4_compile *c,
+ struct gl_program *prog,
+ const struct brw_vec4_prog_key *key,
+ struct brw_vec4_prog_data *prog_data,
+ struct gl_shader_program *shader_prog,
+ struct brw_shader *shader,
+ void *mem_ctx,
+ bool debug_flag)
+ : debug_flag(debug_flag)
+{
+ this->brw = brw;
+ this->ctx = &brw->ctx;
+ this->shader_prog = shader_prog;
this->shader = shader;
- this->mem_ctx = ralloc_context(NULL);
+ this->mem_ctx = mem_ctx;
this->failed = false;
this->base_ir = NULL;
this->current_annotation = NULL;
+ memset(this->output_reg_annotation, 0, sizeof(this->output_reg_annotation));
this->c = c;
- this->vp = &c->vp->program;
- this->prog_data = &c->prog_data;
+ this->prog = prog;
+ this->key = key;
+ this->prog_data = prog_data;
this->variable_ht = hash_table_ctor(0,
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;
this->virtual_grf_array_size = 0;
this->live_intervals_valid = false;
- this->max_grf = intel->gen >= 7 ? GEN7_MRF_HACK_START : BRW_MAX_GRF;
+ this->max_grf = brw->gen >= 7 ? GEN7_MRF_HACK_START : BRW_MAX_GRF;
this->uniforms = 0;
}
vec4_visitor::~vec4_visitor()
{
- ralloc_free(this->mem_ctx);
hash_table_dtor(this->variable_ht);
}
this->fail_msg = msg;
- if (INTEL_DEBUG & DEBUG_VS) {
+ if (debug_flag) {
fprintf(stderr, "%s", msg);
}
}