GLboolean
brw_link_shader(struct gl_context *ctx, struct gl_shader_program *prog)
{
- struct intel_context *intel = intel_context(ctx);
-
struct brw_shader *shader =
(struct brw_shader *)prog->_LinkedShaders[MESA_SHADER_FRAGMENT];
if (shader != NULL) {
GL_TRUE, /* temp */
GL_TRUE /* uniform */
) || progress;
- if (intel->gen == 6) {
- progress = do_if_to_cond_assign(shader->ir) || progress;
- }
} while (progress);
validate_ir_tree(shader->ir);
return BRW_REGISTER_TYPE_UD;
case GLSL_TYPE_ARRAY:
case GLSL_TYPE_STRUCT:
+ case GLSL_TYPE_SAMPLER:
/* These should be overridden with the type of the member when
* dereferenced into. BRW_REGISTER_TYPE_UD seems like a likely
* way to trip up if we don't.
case GLSL_TYPE_BOOL:
vec_values = fp->Base.Parameters->ParameterValues[loc];
for (unsigned int i = 0; i < type->vector_elements; i++) {
- c->prog_data.param[c->prog_data.nr_params++] = &vec_values[i];
+ unsigned int param = c->prog_data.nr_params++;
+
+ assert(param < ARRAY_SIZE(c->prog_data.param));
+
+ switch (type->base_type) {
+ case GLSL_TYPE_FLOAT:
+ c->prog_data.param_convert[param] = PARAM_NO_CONVERT;
+ break;
+ case GLSL_TYPE_UINT:
+ c->prog_data.param_convert[param] = PARAM_CONVERT_F2U;
+ break;
+ case GLSL_TYPE_INT:
+ c->prog_data.param_convert[param] = PARAM_CONVERT_F2I;
+ break;
+ case GLSL_TYPE_BOOL:
+ c->prog_data.param_convert[param] = PARAM_CONVERT_F2B;
+ break;
+ }
+
+ c->prog_data.param[param] = &vec_values[i];
}
return 1;
break;
last_swiz = swiz;
+ c->prog_data.param_convert[c->prog_data.nr_params] =
+ PARAM_NO_CONVERT;
c->prog_data.param[c->prog_data.nr_params++] = &vec_values[swiz];
}
}
}
reg = new(this->mem_ctx) fs_reg(UNIFORM, param_index);
+ reg->type = brw_type_for_base_type(ir->type);
}
if (!reg)
break;
case ir_unop_bit_not:
- case ir_unop_u2f:
- case ir_binop_lshift:
- case ir_binop_rshift:
+ inst = emit(fs_inst(BRW_OPCODE_NOT, this->result, op[0]));
+ break;
case ir_binop_bit_and:
+ inst = emit(fs_inst(BRW_OPCODE_AND, this->result, op[0], op[1]));
+ break;
case ir_binop_bit_xor:
+ inst = emit(fs_inst(BRW_OPCODE_XOR, this->result, op[0], op[1]));
+ break;
case ir_binop_bit_or:
+ inst = emit(fs_inst(BRW_OPCODE_OR, this->result, op[0], op[1]));
+ break;
+
+ case ir_unop_u2f:
+ case ir_binop_lshift:
+ case ir_binop_rshift:
assert(!"GLSL 1.30 features unsupported");
break;
}
assert(!ir->projector);
sampler = _mesa_get_sampler_uniform_value(ir->sampler,
- ctx->Shader.CurrentProgram,
+ ctx->Shader.CurrentFragmentProgram,
&brw->fragment_program->Base);
sampler = c->fp->program.Base.SamplerUnits[sampler];
0
};
+ c->prog_data.param_convert[c->prog_data.nr_params] =
+ PARAM_NO_CONVERT;
+ c->prog_data.param_convert[c->prog_data.nr_params + 1] =
+ PARAM_NO_CONVERT;
+
fs_reg scale_x = fs_reg(UNIFORM, c->prog_data.nr_params);
fs_reg scale_y = fs_reg(UNIFORM, c->prog_data.nr_params + 1);
GLuint index = _mesa_add_state_reference(params,
brw_MOV(p,
brw_message_reg(inst->base_mrf),
brw_vec8_grf(0, 0));
+
+ if (inst->target > 0) {
+ /* Set the render target index for choosing BLEND_STATE. */
+ brw_MOV(p, retype(brw_vec1_reg(BRW_MESSAGE_REGISTER_FILE, 0, 2),
+ BRW_REGISTER_TYPE_UD),
+ brw_imm_ud(inst->target));
+ }
+
+ /* Clear viewport index, render target array index. */
+ brw_AND(p, retype(brw_vec1_reg(BRW_MESSAGE_REGISTER_FILE, 0, 0),
+ BRW_REGISTER_TYPE_UD),
+ retype(brw_vec1_grf(0, 0), BRW_REGISTER_TYPE_UD),
+ brw_imm_ud(0xf7ff));
+
implied_header = brw_null_reg();
} else {
implied_header = retype(brw_vec8_grf(0, 0), BRW_REGISTER_TYPE_UW);
void
fs_visitor::generate_discard_not(fs_inst *inst, struct brw_reg mask)
{
- brw_push_insn_state(p);
- brw_set_mask_control(p, BRW_MASK_DISABLE);
- brw_NOT(p, mask, brw_mask_reg(1)); /* IMASK */
- brw_pop_insn_state(p);
+ if (intel->gen >= 6) {
+ /* Gen6 no longer has the mask reg for us to just read the
+ * active channels from. However, cmp updates just the channels
+ * of the flag reg that are enabled, so we can get at the
+ * channel enables that way. In this step, make a reg of ones
+ * we'll compare to.
+ */
+ brw_MOV(p, mask, brw_imm_ud(1));
+ } else {
+ brw_push_insn_state(p);
+ brw_set_mask_control(p, BRW_MASK_DISABLE);
+ brw_NOT(p, mask, brw_mask_reg(1)); /* IMASK */
+ brw_pop_insn_state(p);
+ }
}
void
fs_visitor::generate_discard_and(fs_inst *inst, struct brw_reg mask)
{
- struct brw_reg g0 = retype(brw_vec1_grf(0, 0), BRW_REGISTER_TYPE_UW);
- mask = brw_uw1_reg(mask.file, mask.nr, 0);
+ if (intel->gen >= 6) {
+ struct brw_reg f0 = brw_flag_reg();
+ struct brw_reg g1 = retype(brw_vec1_grf(1, 7), BRW_REGISTER_TYPE_UW);
+
+ brw_push_insn_state(p);
+ brw_set_mask_control(p, BRW_MASK_DISABLE);
+ brw_MOV(p, f0, brw_imm_uw(0xffff)); /* inactive channels undiscarded */
+ brw_pop_insn_state(p);
+
+ brw_CMP(p, retype(brw_null_reg(), BRW_REGISTER_TYPE_UD),
+ BRW_CONDITIONAL_Z, mask, brw_imm_ud(0)); /* active channels fail test */
+ /* Undo CMP's whacking of predication*/
+ brw_set_predicate_control(p, BRW_PREDICATE_NONE);
+
+ brw_push_insn_state(p);
+ brw_set_mask_control(p, BRW_MASK_DISABLE);
+ brw_AND(p, g1, f0, g1);
+ brw_pop_insn_state(p);
+ } else {
+ struct brw_reg g0 = retype(brw_vec1_grf(0, 0), BRW_REGISTER_TYPE_UW);
- brw_push_insn_state(p);
- brw_set_mask_control(p, BRW_MASK_DISABLE);
- brw_AND(p, g0, mask, g0);
- brw_pop_insn_state(p);
+ mask = brw_uw1_reg(mask.file, mask.nr, 0);
+
+ brw_push_insn_state(p);
+ brw_set_mask_control(p, BRW_MASK_DISABLE);
+ brw_AND(p, g0, mask, g0);
+ brw_pop_insn_state(p);
+ }
}
void
brw_MOV(p,
retype(brw_message_reg(inst->base_mrf + 1), BRW_REGISTER_TYPE_UD),
retype(src, BRW_REGISTER_TYPE_UD));
- brw_oword_block_write(p, brw_message_reg(inst->base_mrf), 1, inst->offset);
+ brw_oword_block_write_scratch(p, brw_message_reg(inst->base_mrf), 1,
+ inst->offset);
}
void
if (intel->gen == 4 && !intel->is_g4x)
brw_MOV(p, brw_null_reg(), dst);
- brw_oword_block_read(p, dst, brw_message_reg(inst->base_mrf), 1,
- inst->offset);
+ brw_oword_block_read_scratch(p, dst, brw_message_reg(inst->base_mrf), 1,
+ inst->offset);
+
+ if (intel->gen == 4 && !intel->is_g4x) {
+ /* gen4 errata: destination from a send can't be used as a
+ * destination until it's been read. Just read it so we don't
+ * have to worry.
+ */
+ brw_MOV(p, brw_null_reg(), dst);
+ }
+}
+
+
+void
+fs_visitor::generate_pull_constant_load(fs_inst *inst, struct brw_reg dst)
+{
+ assert(inst->mlen != 0);
+
+ /* Clear any post destination dependencies that would be ignored by
+ * the block read. See the B-Spec for pre-gen5 send instruction.
+ *
+ * This could use a better solution, since texture sampling and
+ * math reads could potentially run into it as well -- anywhere
+ * that we have a SEND with a destination that is a register that
+ * was written but not read within the last N instructions (what's
+ * N? unsure). This is rare because of dead code elimination, but
+ * not impossible.
+ */
+ if (intel->gen == 4 && !intel->is_g4x)
+ brw_MOV(p, brw_null_reg(), dst);
+
+ brw_oword_block_read(p, dst, brw_message_reg(inst->base_mrf),
+ inst->offset, SURF_INDEX_FRAG_CONST_BUFFER);
if (intel->gen == 4 && !intel->is_g4x) {
/* gen4 errata: destination from a send can't be used as a
constant_nr % 8);
inst->src[i].file = FIXED_HW_REG;
- inst->src[i].fixed_hw_reg = brw_reg;
+ inst->src[i].fixed_hw_reg = retype(brw_reg, inst->src[i].type);
}
}
}
}
}
+/**
+ * Choose accesses from the UNIFORM file to demote to using the pull
+ * constant buffer.
+ *
+ * We allow a fragment shader to have more than the specified minimum
+ * maximum number of fragment shader uniform components (64). If
+ * there are too many of these, they'd fill up all of register space.
+ * So, this will push some of them out to the pull constant buffer and
+ * update the program to load them.
+ */
+void
+fs_visitor::setup_pull_constants()
+{
+ /* Only allow 16 registers (128 uniform components) as push constants. */
+ unsigned int max_uniform_components = 16 * 8;
+ if (c->prog_data.nr_params <= max_uniform_components)
+ return;
+
+ /* Just demote the end of the list. We could probably do better
+ * here, demoting things that are rarely used in the program first.
+ */
+ int pull_uniform_base = max_uniform_components;
+ int pull_uniform_count = c->prog_data.nr_params - pull_uniform_base;
+
+ foreach_iter(exec_list_iterator, iter, this->instructions) {
+ fs_inst *inst = (fs_inst *)iter.get();
+
+ for (int i = 0; i < 3; i++) {
+ if (inst->src[i].file != UNIFORM)
+ continue;
+
+ int uniform_nr = inst->src[i].hw_reg + inst->src[i].reg_offset;
+ if (uniform_nr < pull_uniform_base)
+ continue;
+
+ fs_reg dst = fs_reg(this, glsl_type::float_type);
+ fs_inst *pull = new(mem_ctx) fs_inst(FS_OPCODE_PULL_CONSTANT_LOAD,
+ dst);
+ pull->offset = ((uniform_nr - pull_uniform_base) * 4) & ~15;
+ pull->ir = inst->ir;
+ pull->annotation = inst->annotation;
+ pull->base_mrf = 14;
+ pull->mlen = 1;
+
+ inst->insert_before(pull);
+
+ inst->src[i].file = GRF;
+ inst->src[i].reg = dst.reg;
+ inst->src[i].reg_offset = 0;
+ inst->src[i].smear = (uniform_nr - pull_uniform_base) & 3;
+ }
+ }
+
+ for (int i = 0; i < pull_uniform_count; i++) {
+ c->prog_data.pull_param[i] = c->prog_data.param[pull_uniform_base + i];
+ c->prog_data.pull_param_convert[i] =
+ c->prog_data.param_convert[pull_uniform_base + i];
+ }
+ c->prog_data.nr_params -= pull_uniform_count;
+ c->prog_data.nr_pull_params = pull_uniform_count;
+}
+
void
fs_visitor::calculate_live_intervals()
{
int *use = talloc_array(mem_ctx, int, num_vars);
int loop_depth = 0;
int loop_start = 0;
+ int bb_header_ip = 0;
for (int i = 0; i < num_vars; i++) {
def[i] = 1 << 30;
loop_depth--;
if (loop_depth == 0) {
- /* FINISHME:
- *
- * Patches up any vars marked for use within the loop as
- * live until the end. This is conservative, as there
- * will often be variables defined and used inside the
- * loop but dead at the end of the loop body.
+ /* Patches up the use of vars marked for being live across
+ * the whole loop.
*/
for (int i = 0; i < num_vars; i++) {
if (use[i] == loop_start) {
}
}
} else {
- int eip = ip;
-
- if (loop_depth)
- eip = loop_start;
-
for (unsigned int i = 0; i < 3; i++) {
if (inst->src[i].file == GRF && inst->src[i].reg != 0) {
- use[inst->src[i].reg] = MAX2(use[inst->src[i].reg], eip);
+ int reg = inst->src[i].reg;
+
+ if (!loop_depth || (this->virtual_grf_sizes[reg] == 1 &&
+ def[reg] >= bb_header_ip)) {
+ use[reg] = ip;
+ } else {
+ def[reg] = MIN2(loop_start, def[reg]);
+ use[reg] = loop_start;
+
+ /* Nobody else is going to go smash our start to
+ * later in the loop now, because def[reg] now
+ * points before the bb header.
+ */
+ }
}
}
if (inst->dst.file == GRF && inst->dst.reg != 0) {
- def[inst->dst.reg] = MIN2(def[inst->dst.reg], eip);
+ int reg = inst->dst.reg;
+
+ if (!loop_depth || (this->virtual_grf_sizes[reg] == 1 &&
+ !inst->predicated)) {
+ def[reg] = MIN2(def[reg], ip);
+ } else {
+ def[reg] = MIN2(def[reg], loop_start);
+ }
}
}
ip++;
+
+ /* Set the basic block header IP. This is used for determining
+ * if a complete def of single-register virtual GRF in a loop
+ * dominates a use in the same basic block. It's a quick way to
+ * reduce the live interval range of most register used in a
+ * loop.
+ */
+ if (inst->opcode == BRW_OPCODE_IF ||
+ inst->opcode == BRW_OPCODE_ELSE ||
+ inst->opcode == BRW_OPCODE_ENDIF ||
+ inst->opcode == BRW_OPCODE_DO ||
+ inst->opcode == BRW_OPCODE_WHILE ||
+ inst->opcode == BRW_OPCODE_BREAK ||
+ inst->opcode == BRW_OPCODE_CONTINUE) {
+ bb_header_ip = ip;
+ }
}
talloc_free(this->virtual_grf_def);
scan_inst->src[i].reg_offset = inst->src[0].reg_offset;
scan_inst->src[i].abs |= inst->src[0].abs;
scan_inst->src[i].negate ^= inst->src[0].negate;
+ scan_inst->src[i].smear = inst->src[0].smear;
}
}
}
inst->predicated ||
inst->dst.file != MRF || inst->src[0].file != GRF ||
inst->dst.type != inst->src[0].type ||
- inst->src[0].abs || inst->src[0].negate)
+ inst->src[0].abs || inst->src[0].negate || inst->src[0].smear != -1)
continue;
/* Can't compute-to-MRF this GRF if someone else was going to
case GRF:
case ARF:
case MRF:
- brw_reg = brw_vec8_reg(reg->file,
- reg->hw_reg, 0);
+ if (reg->smear == -1) {
+ brw_reg = brw_vec8_reg(reg->file,
+ reg->hw_reg, 0);
+ } else {
+ brw_reg = brw_vec1_reg(reg->file,
+ reg->hw_reg, reg->smear);
+ }
brw_reg = retype(brw_reg, reg->type);
break;
case IMM:
void
fs_visitor::generate_code()
{
- unsigned int annotation_len = 0;
int last_native_inst = 0;
struct brw_instruction *if_stack[16], *loop_stack[16];
int if_stack_depth = 0, loop_stack_depth = 0;
int if_depth_in_loop[16];
+ const char *last_annotation_string = NULL;
+ ir_instruction *last_annotation_ir = NULL;
+
+ if (unlikely(INTEL_DEBUG & DEBUG_WM)) {
+ printf("Native code for fragment shader %d:\n",
+ ctx->Shader.CurrentFragmentProgram->Name);
+ }
if_depth_in_loop[loop_stack_depth] = 0;
fs_inst *inst = (fs_inst *)iter.get();
struct brw_reg src[3], dst;
+ if (unlikely(INTEL_DEBUG & DEBUG_WM)) {
+ if (last_annotation_ir != inst->ir) {
+ last_annotation_ir = inst->ir;
+ if (last_annotation_ir) {
+ printf(" ");
+ last_annotation_ir->print();
+ printf("\n");
+ }
+ }
+ if (last_annotation_string != inst->annotation) {
+ last_annotation_string = inst->annotation;
+ if (last_annotation_string)
+ printf(" %s\n", last_annotation_string);
+ }
+ }
+
for (unsigned int i = 0; i < 3; i++) {
src[i] = brw_reg_from_fs_reg(&inst->src[i]);
}
generate_unspill(inst, dst);
break;
+ case FS_OPCODE_PULL_CONSTANT_LOAD:
+ generate_pull_constant_load(inst, dst);
+ break;
+
case FS_OPCODE_FB_WRITE:
generate_fb_write(inst);
break;
this->fail = true;
}
- if (annotation_len < p->nr_insn) {
- annotation_len *= 2;
- if (annotation_len < 16)
- annotation_len = 16;
-
- this->annotation_string = talloc_realloc(this->mem_ctx,
- annotation_string,
- const char *,
- annotation_len);
- this->annotation_ir = talloc_realloc(this->mem_ctx,
- annotation_ir,
- ir_instruction *,
- annotation_len);
+ if (unlikely(INTEL_DEBUG & DEBUG_WM)) {
+ for (unsigned int i = last_native_inst; i < p->nr_insn; i++) {
+ if (0) {
+ printf("0x%08x 0x%08x 0x%08x 0x%08x ",
+ ((uint32_t *)&p->store[i])[3],
+ ((uint32_t *)&p->store[i])[2],
+ ((uint32_t *)&p->store[i])[1],
+ ((uint32_t *)&p->store[i])[0]);
+ }
+ brw_disasm(stdout, &p->store[i], intel->gen);
+ printf("\n");
+ }
}
- for (unsigned int i = last_native_inst; i < p->nr_insn; i++) {
- this->annotation_string[i] = inst->annotation;
- this->annotation_ir[i] = inst->ir;
- }
last_native_inst = p->nr_insn;
}
}
GLboolean
brw_wm_fs_emit(struct brw_context *brw, struct brw_wm_compile *c)
{
- struct brw_compile *p = &c->func;
struct intel_context *intel = &brw->intel;
struct gl_context *ctx = &intel->ctx;
- struct gl_shader_program *prog = ctx->Shader.CurrentProgram;
+ struct gl_shader_program *prog = ctx->Shader.CurrentFragmentProgram;
if (!prog)
return GL_FALSE;
*/
c->dispatch_width = 8;
- if (INTEL_DEBUG & DEBUG_WM) {
+ if (unlikely(INTEL_DEBUG & DEBUG_WM)) {
printf("GLSL IR for native fragment shader %d:\n", prog->Name);
_mesa_print_ir(shader->ir, NULL);
printf("\n");
v.emit_fb_writes();
v.split_virtual_grfs();
+ v.setup_pull_constants();
v.assign_curb_setup();
v.assign_urb_setup();
if (v.fail)
return GL_FALSE;
- if (INTEL_DEBUG & DEBUG_WM) {
- const char *last_annotation_string = NULL;
- ir_instruction *last_annotation_ir = NULL;
-
- printf("Native code for fragment shader %d:\n", prog->Name);
- for (unsigned int i = 0; i < p->nr_insn; i++) {
- if (last_annotation_ir != v.annotation_ir[i]) {
- last_annotation_ir = v.annotation_ir[i];
- if (last_annotation_ir) {
- printf(" ");
- last_annotation_ir->print();
- printf("\n");
- }
- }
- if (last_annotation_string != v.annotation_string[i]) {
- last_annotation_string = v.annotation_string[i];
- if (last_annotation_string)
- printf(" %s\n", last_annotation_string);
- }
- if (0) {
- printf("0x%08x 0x%08x 0x%08x 0x%08x ",
- ((uint32_t *)&p->store[i])[3],
- ((uint32_t *)&p->store[i])[2],
- ((uint32_t *)&p->store[i])[1],
- ((uint32_t *)&p->store[i])[0]);
- }
- brw_disasm(stdout, &p->store[i], intel->gen);
- }
- printf("\n");
- }
-
c->prog_data.total_grf = v.grf_used;
- c->prog_data.total_scratch = 0;
return GL_TRUE;
}