extern "C" {
#include <sys/types.h>
-/* Evil hack for using libdrm in a c++ compiler. */
-#define virtual virt
-#include "i915_drm.h"
-#include "intel_bufmgr.h"
-#undef virtual
#include "main/macros.h"
#include "main/shaderobj.h"
#include "program/prog_parameter.h"
#include "program/prog_print.h"
#include "program/prog_optimize.h"
+#include "program/sampler.h"
#include "program/hash_table.h"
#include "brw_context.h"
#include "brw_eu.h"
FS_OPCODE_DDX,
FS_OPCODE_DDY,
FS_OPCODE_LINTERP,
+ FS_OPCODE_TEX,
+ FS_OPCODE_TXB,
+ FS_OPCODE_TXL,
+ FS_OPCODE_DISCARD,
};
static int using_new_fs = -1;
+static struct brw_reg brw_reg_from_fs_reg(class fs_reg *reg);
struct gl_shader *
brw_new_shader(GLcontext *ctx, GLuint name, GLuint type)
clone_ir_list(mem_ctx, shader->ir, shader->base.ir);
do_mat_op_to_vec(shader->ir);
+ do_mod_to_fract(shader->ir);
do_div_to_mul_rcp(shader->ir);
do_sub_to_add_neg(shader->ir);
do_explog_to_explog2(shader->ir);
- brw_do_channel_expressions(shader->ir);
- brw_do_vector_splitting(shader->ir);
-
do {
progress = false;
- progress = do_common_optimization(shader->ir, true) || progress;
+ brw_do_channel_expressions(shader->ir);
+ brw_do_vector_splitting(shader->ir);
+
+ progress = do_lower_jumps(shader->ir, true, true,
+ true, /* main return */
+ false, /* continue */
+ false /* loops */
+ ) || progress;
+
+ progress = do_common_optimization(shader->ir, true, 32) || progress;
+
+ progress = lower_noise(shader->ir) || progress;
+ progress =
+ lower_variable_index_to_cond_assign(shader->ir,
+ GL_TRUE, /* input */
+ GL_TRUE, /* output */
+ GL_TRUE, /* temp */
+ GL_TRUE /* uniform */
+ ) || progress;
} while (progress);
+ validate_ir_tree(shader->ir);
+
reparent_ir(shader->ir, shader->ir);
talloc_free(mem_ctx);
}
case GLSL_TYPE_INT:
case GLSL_TYPE_FLOAT:
case GLSL_TYPE_BOOL:
- if (type->is_matrix()) {
- /* In case of incoming uniform/varying matrices, match their
- * allocation behavior. FINISHME: We could just use
- * glsl_type->components() for variables and temps within the
- * shader.
- */
- return type->matrix_columns * 4;
- } else {
- return type->vector_elements;
- }
+ return type->components();
case GLSL_TYPE_ARRAY:
/* FINISHME: uniform/varying arrays. */
return type_size(type->fields.array) * type->length;
return node;
}
- /** Generic unset register constructor. */
- fs_reg()
+ void init()
{
- this->file = BAD_FILE;
this->reg = 0;
this->reg_offset = 0;
- this->hw_reg = -1;
this->negate = 0;
this->abs = 0;
+ this->hw_reg = -1;
+ }
+
+ /** Generic unset register constructor. */
+ fs_reg()
+ {
+ init();
+ this->file = BAD_FILE;
}
/** Immediate value constructor. */
fs_reg(float f)
{
+ init();
this->file = IMM;
- this->reg = 0;
- this->hw_reg = 0;
this->type = BRW_REGISTER_TYPE_F;
this->imm.f = f;
- this->negate = 0;
- this->abs = 0;
}
/** Immediate value constructor. */
fs_reg(int32_t i)
{
+ init();
this->file = IMM;
- this->reg = 0;
- this->hw_reg = 0;
this->type = BRW_REGISTER_TYPE_D;
this->imm.i = i;
- this->negate = 0;
- this->abs = 0;
}
/** Immediate value constructor. */
fs_reg(uint32_t u)
{
+ init();
this->file = IMM;
- this->reg = 0;
- this->hw_reg = 0;
this->type = BRW_REGISTER_TYPE_UD;
this->imm.u = u;
- this->negate = 0;
- this->abs = 0;
}
/** Fixed brw_reg Immediate value constructor. */
fs_reg(struct brw_reg fixed_hw_reg)
{
+ init();
this->file = FIXED_HW_REG;
this->fixed_hw_reg = fixed_hw_reg;
- this->reg = 0;
- this->hw_reg = 0;
this->type = fixed_hw_reg.type;
- this->negate = 0;
- this->abs = 0;
}
fs_reg(enum register_file file, int hw_reg);
return node;
}
- fs_inst()
+ void init()
{
this->opcode = BRW_OPCODE_NOP;
this->saturate = false;
this->conditional_mod = BRW_CONDITIONAL_NONE;
this->predicated = false;
+ this->sampler = 0;
+ this->target = 0;
+ this->eot = false;
+ this->shadow_compare = false;
+ }
+
+ fs_inst()
+ {
+ init();
+ }
+
+ fs_inst(int opcode)
+ {
+ init();
+ this->opcode = opcode;
}
fs_inst(int opcode, fs_reg dst, fs_reg src0)
{
+ init();
this->opcode = opcode;
this->dst = dst;
this->src[0] = src0;
- this->saturate = false;
- this->conditional_mod = BRW_CONDITIONAL_NONE;
- this->predicated = false;
}
fs_inst(int opcode, fs_reg dst, fs_reg src0, fs_reg src1)
{
+ init();
this->opcode = opcode;
this->dst = dst;
this->src[0] = src0;
this->src[1] = src1;
- this->saturate = false;
- this->conditional_mod = BRW_CONDITIONAL_NONE;
- this->predicated = false;
}
fs_inst(int opcode, fs_reg dst, fs_reg src0, fs_reg src1, fs_reg src2)
{
+ init();
this->opcode = opcode;
this->dst = dst;
this->src[0] = src0;
this->src[1] = src1;
this->src[2] = src2;
- this->saturate = false;
- this->conditional_mod = BRW_CONDITIONAL_NONE;
- this->predicated = false;
}
int opcode; /* BRW_OPCODE_* or FS_OPCODE_* */
bool predicated;
int conditional_mod; /**< BRW_CONDITIONAL_* */
+ int mlen; /**< SEND message length */
+ int sampler;
+ int target; /**< MRT target. */
+ bool eot;
+ bool shadow_compare;
+
/** @{
* Annotation for the generated IR. One of the two can be set.
*/
this->c = c;
this->p = &c->func;
this->brw = p->brw;
+ this->fp = brw->fragment_program;
this->intel = &brw->intel;
+ this->ctx = &intel->ctx;
this->mem_ctx = talloc_new(NULL);
this->shader = shader;
this->fail = false;
this->current_annotation = NULL;
this->annotation_string = NULL;
this->annotation_ir = NULL;
+ this->base_ir = NULL;
}
~fs_visitor()
{
void generate_fb_write(fs_inst *inst);
void generate_linterp(fs_inst *inst, struct brw_reg dst,
struct brw_reg *src);
+ void generate_tex(fs_inst *inst, struct brw_reg dst, struct brw_reg src);
void generate_math(fs_inst *inst, struct brw_reg dst, struct brw_reg *src);
+ void generate_discard(fs_inst *inst);
+ void generate_ddx(fs_inst *inst, struct brw_reg dst, struct brw_reg src);
+ void generate_ddy(fs_inst *inst, struct brw_reg dst, struct brw_reg src);
void emit_dummy_fs();
void emit_interpolation();
void emit_fb_writes();
struct brw_reg interp_reg(int location, int channel);
+ int setup_uniform_values(int loc, const glsl_type *type);
struct brw_context *brw;
+ const struct gl_fragment_program *fp;
struct intel_context *intel;
+ GLcontext *ctx;
struct brw_wm_compile *c;
struct brw_compile *p;
struct brw_shader *shader;
/** Fixed HW reg constructor. */
fs_reg::fs_reg(enum register_file file, int hw_reg)
{
+ init();
this->file = file;
- this->reg = 0;
- this->reg_offset = 0;
this->hw_reg = hw_reg;
this->type = BRW_REGISTER_TYPE_F;
- this->negate = 0;
- this->abs = 0;
}
-/** Automatic reg constructor. */
-fs_reg::fs_reg(class fs_visitor *v, const struct glsl_type *type)
+int
+brw_type_for_base_type(const struct glsl_type *type)
{
- this->file = GRF;
- this->reg = v->next_abstract_grf;
- this->reg_offset = 0;
- v->next_abstract_grf += type_size(type);
- this->hw_reg = -1;
- this->negate = 0;
- this->abs = 0;
-
switch (type->base_type) {
case GLSL_TYPE_FLOAT:
- this->type = BRW_REGISTER_TYPE_F;
- break;
+ return BRW_REGISTER_TYPE_F;
case GLSL_TYPE_INT:
case GLSL_TYPE_BOOL:
- this->type = BRW_REGISTER_TYPE_D;
- break;
+ return BRW_REGISTER_TYPE_D;
case GLSL_TYPE_UINT:
- this->type = BRW_REGISTER_TYPE_UD;
- break;
+ return BRW_REGISTER_TYPE_UD;
+ case GLSL_TYPE_ARRAY:
+ case GLSL_TYPE_STRUCT:
+ /* 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.
+ */
+ return BRW_REGISTER_TYPE_UD;
default:
assert(!"not reached");
- this->type = BRW_REGISTER_TYPE_F;
- break;
+ return BRW_REGISTER_TYPE_F;
}
}
+/** Automatic reg constructor. */
+fs_reg::fs_reg(class fs_visitor *v, const struct glsl_type *type)
+{
+ init();
+
+ this->file = GRF;
+ this->reg = v->next_abstract_grf;
+ this->reg_offset = 0;
+ v->next_abstract_grf += type_size(type);
+ this->type = brw_type_for_base_type(type);
+}
+
fs_reg *
fs_visitor::variable_storage(ir_variable *var)
{
return (fs_reg *)hash_table_find(this->variable_ht, var);
}
+/* Our support for uniforms is piggy-backed on the struct
+ * gl_fragment_program, because that's where the values actually
+ * get stored, rather than in some global gl_shader_program uniform
+ * store.
+ */
+int
+fs_visitor::setup_uniform_values(int loc, const glsl_type *type)
+{
+ unsigned int offset = 0;
+ float *vec_values;
+
+ if (type->is_matrix()) {
+ const glsl_type *column = glsl_type::get_instance(GLSL_TYPE_FLOAT,
+ type->vector_elements,
+ 1);
+
+ for (unsigned int i = 0; i < type->matrix_columns; i++) {
+ offset += setup_uniform_values(loc + offset, column);
+ }
+
+ return offset;
+ }
+
+ switch (type->base_type) {
+ case GLSL_TYPE_FLOAT:
+ case GLSL_TYPE_UINT:
+ case GLSL_TYPE_INT:
+ 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];
+ }
+ return 1;
+
+ 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;
+
+ case GLSL_TYPE_ARRAY:
+ for (unsigned int i = 0; i < type->length; i++) {
+ offset += setup_uniform_values(loc + offset, type->fields.array);
+ }
+ 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;
+ }
+}
+
void
fs_visitor::visit(ir_variable *ir)
{
fs_reg *reg = NULL;
+ if (variable_storage(ir))
+ return;
+
if (strcmp(ir->name, "gl_FragColor") == 0) {
this->frag_color = ir;
} else if (strcmp(ir->name, "gl_FragData") == 0) {
this->frag_data = ir;
} else if (strcmp(ir->name, "gl_FragDepth") == 0) {
this->frag_depth = ir;
- assert(!"FINISHME: this hangs currently.");
}
if (ir->mode == ir_var_in) {
- reg = &this->interp_attrs[ir->location];
+ if (strcmp(ir->name, "gl_FrontFacing") == 0) {
+ reg = new(this->mem_ctx) fs_reg(this, ir->type);
+ struct brw_reg r1_6ud = retype(brw_vec1_grf(1, 6), BRW_REGISTER_TYPE_UD);
+ /* bit 31 is "primitive is back face", so checking < (1 << 31) gives
+ * us front face
+ */
+ fs_inst *inst = emit(fs_inst(BRW_OPCODE_CMP,
+ *reg,
+ fs_reg(r1_6ud),
+ fs_reg(1u << 31)));
+ inst->conditional_mod = BRW_CONDITIONAL_L;
+ emit(fs_inst(BRW_OPCODE_AND, *reg, *reg, fs_reg(1u)));
+ } else {
+ reg = &this->interp_attrs[ir->location];
+ }
}
if (ir->mode == ir_var_uniform) {
- const float *vec_values;
int param_index = c->prog_data.nr_params;
- /* FINISHME: This is wildly incomplete. */
- assert(ir->type->is_scalar() || ir->type->is_vector());
-
- const struct gl_program *fp = &this->brw->fragment_program->Base;
- /* Our support for uniforms is piggy-backed on the struct
- * gl_fragment_program, because that's where the values actually
- * get stored, rather than in some global gl_shader_program uniform
- * store.
- */
- vec_values = fp->Parameters->ParameterValues[ir->location];
- for (unsigned int i = 0; i < ir->type->vector_elements; i++) {
- c->prog_data.param[c->prog_data.nr_params++] = &vec_values[i];
- }
+ setup_uniform_values(ir->location, ir->type);
reg = new(this->mem_ctx) fs_reg(UNIFORM, param_index);
}
void
fs_visitor::visit(ir_dereference_record *ir)
{
- assert(!"FINISHME");
+ const glsl_type *struct_type = ir->record->type;
+
+ ir->record->accept(this);
+
+ unsigned int offset = 0;
+ for (unsigned int i = 0; i < struct_type->length; i++) {
+ if (strcmp(struct_type->fields.structure[i].name, ir->field) == 0)
+ break;
+ offset += type_size(struct_type->fields.structure[i].type);
+ }
+ this->result.reg_offset += offset;
+ this->result.type = brw_type_for_base_type(ir->type);
}
void
fs_visitor::visit(ir_dereference_array *ir)
{
- assert(!"FINISHME");
+ ir_constant *index;
+ int element_size;
+
+ ir->array->accept(this);
+ index = ir->array_index->as_constant();
+
+ if (ir->type->is_matrix()) {
+ element_size = ir->type->vector_elements;
+ } else {
+ element_size = type_size(ir->type);
+ this->result.type = brw_type_for_base_type(ir->type);
+ }
+
+ if (index) {
+ assert(this->result.file == UNIFORM ||
+ (this->result.file == GRF &&
+ this->result.reg != 0));
+ this->result.reg_offset += index->value.i[0] * element_size;
+ } else {
+ assert(!"FINISHME: non-constant matrix column");
+ }
}
void
emit(fs_inst(BRW_OPCODE_ADD, this->result, op[0], fs_reg(-1)));
break;
case ir_unop_neg:
+ op[0].negate = !op[0].negate;
this->result = op[0];
- op[0].negate = ~op[0].negate;
break;
case ir_unop_abs:
- this->result = op[0];
op[0].abs = true;
+ this->result = op[0];
break;
case ir_unop_sign:
temp = fs_reg(this, ir->type);
- inst = emit(fs_inst(BRW_OPCODE_CMP, this->result, op[0], fs_reg(0.0f)));
+ emit(fs_inst(BRW_OPCODE_MOV, this->result, fs_reg(0.0f)));
+
+ inst = emit(fs_inst(BRW_OPCODE_CMP, reg_null, op[0], fs_reg(0.0f)));
inst->conditional_mod = BRW_CONDITIONAL_G;
+ inst = emit(fs_inst(BRW_OPCODE_MOV, this->result, fs_reg(1.0f)));
+ inst->predicated = true;
- inst = emit(fs_inst(BRW_OPCODE_CMP, temp, op[0], fs_reg(0.0f)));
+ inst = emit(fs_inst(BRW_OPCODE_CMP, reg_null, op[0], fs_reg(0.0f)));
inst->conditional_mod = BRW_CONDITIONAL_L;
-
- temp.negate = true;
- emit(fs_inst(BRW_OPCODE_ADD, this->result, this->result, temp));
+ inst = emit(fs_inst(BRW_OPCODE_MOV, this->result, fs_reg(-1.0f)));
+ inst->predicated = true;
break;
case ir_unop_rcp:
case ir_binop_less:
inst = emit(fs_inst(BRW_OPCODE_CMP, this->result, op[0], op[1]));
inst->conditional_mod = BRW_CONDITIONAL_L;
+ emit(fs_inst(BRW_OPCODE_AND, this->result, this->result, fs_reg(0x1)));
break;
case ir_binop_greater:
inst = emit(fs_inst(BRW_OPCODE_CMP, this->result, op[0], op[1]));
inst->conditional_mod = BRW_CONDITIONAL_G;
+ emit(fs_inst(BRW_OPCODE_AND, this->result, this->result, fs_reg(0x1)));
break;
case ir_binop_lequal:
inst = emit(fs_inst(BRW_OPCODE_CMP, this->result, op[0], op[1]));
inst->conditional_mod = BRW_CONDITIONAL_LE;
+ emit(fs_inst(BRW_OPCODE_AND, this->result, this->result, fs_reg(0x1)));
break;
case ir_binop_gequal:
inst = emit(fs_inst(BRW_OPCODE_CMP, this->result, op[0], op[1]));
inst->conditional_mod = BRW_CONDITIONAL_GE;
+ emit(fs_inst(BRW_OPCODE_AND, this->result, this->result, fs_reg(0x1)));
break;
case ir_binop_equal:
+ case ir_binop_all_equal: /* same as nequal for scalars */
inst = emit(fs_inst(BRW_OPCODE_CMP, this->result, op[0], op[1]));
inst->conditional_mod = BRW_CONDITIONAL_Z;
+ emit(fs_inst(BRW_OPCODE_AND, this->result, this->result, fs_reg(0x1)));
break;
case ir_binop_nequal:
+ case ir_binop_any_nequal: /* same as nequal for scalars */
inst = emit(fs_inst(BRW_OPCODE_CMP, this->result, op[0], op[1]));
inst->conditional_mod = BRW_CONDITIONAL_NZ;
+ emit(fs_inst(BRW_OPCODE_AND, this->result, this->result, fs_reg(0x1)));
break;
case ir_binop_logic_xor:
case ir_binop_dot:
case ir_binop_cross:
case ir_unop_any:
- assert(!"not reached: should be handled by brw_channel_expressions");
+ assert(!"not reached: should be handled by brw_fs_channel_expressions");
+ break;
+
+ case ir_unop_noise:
+ assert(!"not reached: should be handled by lower_noise");
break;
case ir_unop_sqrt:
emit(fs_inst(BRW_OPCODE_MOV, this->result, op[0]));
break;
case ir_unop_f2i:
- emit(fs_inst(BRW_OPCODE_RNDZ, this->result, op[0]));
+ emit(fs_inst(BRW_OPCODE_MOV, this->result, op[0]));
break;
case ir_unop_f2b:
case ir_unop_i2b:
if (ir->condition) {
/* Get the condition bool into the predicate. */
ir->condition->accept(this);
- inst = emit(fs_inst(BRW_OPCODE_CMP, this->result, fs_reg(0)));
+ inst = emit(fs_inst(BRW_OPCODE_CMP, reg_null, this->result, fs_reg(0)));
inst->conditional_mod = BRW_CONDITIONAL_NZ;
}
for (i = 0; i < type_size(ir->lhs->type); i++) {
- if (i < 4 && !(write_mask & (1 << i)))
- continue;
-
- inst = emit(fs_inst(BRW_OPCODE_MOV, l, r));
- if (ir->condition)
- inst->predicated = true;
+ if (i >= 4 || (write_mask & (1 << i))) {
+ inst = emit(fs_inst(BRW_OPCODE_MOV, l, r));
+ if (ir->condition)
+ inst->predicated = true;
+ r.reg_offset++;
+ }
l.reg_offset++;
- r.reg_offset++;
}
}
void
fs_visitor::visit(ir_texture *ir)
{
- assert(!"FINISHME");
+ int base_mrf = 2;
+ fs_inst *inst = NULL;
+ unsigned int mlen = 0;
+
+ ir->coordinate->accept(this);
+ fs_reg coordinate = this->result;
+
+ if (ir->projector) {
+ fs_reg inv_proj = fs_reg(this, glsl_type::float_type);
+
+ ir->projector->accept(this);
+ emit(fs_inst(FS_OPCODE_RCP, inv_proj, this->result));
+
+ fs_reg proj_coordinate = fs_reg(this, ir->coordinate->type);
+ for (unsigned int i = 0; i < ir->coordinate->type->vector_elements; i++) {
+ emit(fs_inst(BRW_OPCODE_MUL, proj_coordinate, coordinate, inv_proj));
+ coordinate.reg_offset++;
+ proj_coordinate.reg_offset++;
+ }
+ proj_coordinate.reg_offset = 0;
+
+ coordinate = proj_coordinate;
+ }
+
+ for (mlen = 0; mlen < ir->coordinate->type->vector_elements; mlen++) {
+ emit(fs_inst(BRW_OPCODE_MOV, fs_reg(MRF, base_mrf + mlen), coordinate));
+ coordinate.reg_offset++;
+ }
+
+ /* Pre-Ironlake, the 8-wide sampler always took u,v,r. */
+ if (intel->gen < 5)
+ mlen = 3;
+
+ if (ir->shadow_comparitor) {
+ /* For shadow comparisons, we have to supply u,v,r. */
+ mlen = 3;
+
+ ir->shadow_comparitor->accept(this);
+ emit(fs_inst(BRW_OPCODE_MOV, fs_reg(MRF, base_mrf + mlen), this->result));
+ mlen++;
+ }
+
+ /* Do we ever want to handle writemasking on texture samples? Is it
+ * performance relevant?
+ */
+ fs_reg dst = fs_reg(this, glsl_type::vec4_type);
+
+ switch (ir->op) {
+ case ir_tex:
+ inst = emit(fs_inst(FS_OPCODE_TEX, dst, fs_reg(MRF, base_mrf)));
+ break;
+ case ir_txb:
+ ir->lod_info.bias->accept(this);
+ emit(fs_inst(BRW_OPCODE_MOV, fs_reg(MRF, base_mrf + mlen), this->result));
+ mlen++;
+
+ inst = emit(fs_inst(FS_OPCODE_TXB, dst, fs_reg(MRF, base_mrf)));
+ break;
+ case ir_txl:
+ ir->lod_info.lod->accept(this);
+ emit(fs_inst(BRW_OPCODE_MOV, fs_reg(MRF, base_mrf + mlen), this->result));
+ mlen++;
+
+ inst = emit(fs_inst(FS_OPCODE_TXL, dst, fs_reg(MRF, base_mrf)));
+ break;
+ case ir_txd:
+ case ir_txf:
+ assert(!"GLSL 1.30 features unsupported");
+ break;
+ }
+
+ inst->sampler =
+ _mesa_get_sampler_uniform_value(ir->sampler,
+ ctx->Shader.CurrentProgram,
+ &brw->fragment_program->Base);
+ inst->sampler = c->fp->program.Base.SamplerUnits[inst->sampler];
+
+ this->result = dst;
+
+ if (ir->shadow_comparitor)
+ inst->shadow_compare = true;
+ inst->mlen = mlen;
}
void
void
fs_visitor::visit(ir_discard *ir)
{
- assert(!"FINISHME");
+ assert(ir->condition == NULL); /* FINISHME */
+
+ emit(fs_inst(FS_OPCODE_DISCARD));
}
void
void
fs_visitor::visit(ir_if *ir)
{
- assert(!"FINISHME");
+ fs_inst *inst;
+
+ /* Don't point the annotation at the if statement, because then it plus
+ * the then and else blocks get printed.
+ */
+ this->base_ir = ir->condition;
+
+ /* Generate the condition into the condition code. */
+ ir->condition->accept(this);
+ inst = emit(fs_inst(BRW_OPCODE_MOV, fs_reg(brw_null_reg()), this->result));
+ inst->conditional_mod = BRW_CONDITIONAL_NZ;
+
+ inst = emit(fs_inst(BRW_OPCODE_IF));
+ inst->predicated = true;
+
+ foreach_iter(exec_list_iterator, iter, ir->then_instructions) {
+ ir_instruction *ir = (ir_instruction *)iter.get();
+ this->base_ir = ir;
+
+ ir->accept(this);
+ }
+
+ if (!ir->else_instructions.is_empty()) {
+ emit(fs_inst(BRW_OPCODE_ELSE));
+
+ foreach_iter(exec_list_iterator, iter, ir->else_instructions) {
+ ir_instruction *ir = (ir_instruction *)iter.get();
+ this->base_ir = ir;
+
+ ir->accept(this);
+ }
+ }
+
+ emit(fs_inst(BRW_OPCODE_ENDIF));
}
void
fs_visitor::visit(ir_loop *ir)
{
- assert(!"FINISHME");
+ fs_reg counter = reg_undef;
+
+ if (ir->counter) {
+ this->base_ir = ir->counter;
+ ir->counter->accept(this);
+ counter = *(variable_storage(ir->counter));
+
+ if (ir->from) {
+ this->base_ir = ir->from;
+ ir->from->accept(this);
+
+ emit(fs_inst(BRW_OPCODE_MOV, counter, this->result));
+ }
+ }
+
+ /* Start a safety counter. If the user messed up their loop
+ * counting, we don't want to hang the GPU.
+ */
+ fs_reg max_iter = fs_reg(this, glsl_type::int_type);
+ emit(fs_inst(BRW_OPCODE_MOV, max_iter, fs_reg(10000)));
+
+ emit(fs_inst(BRW_OPCODE_DO));
+
+ if (ir->to) {
+ this->base_ir = ir->to;
+ ir->to->accept(this);
+
+ fs_inst *inst = emit(fs_inst(BRW_OPCODE_CMP, reg_null,
+ counter, this->result));
+ switch (ir->cmp) {
+ case ir_binop_equal:
+ inst->conditional_mod = BRW_CONDITIONAL_Z;
+ break;
+ case ir_binop_nequal:
+ inst->conditional_mod = BRW_CONDITIONAL_NZ;
+ break;
+ case ir_binop_gequal:
+ inst->conditional_mod = BRW_CONDITIONAL_GE;
+ break;
+ case ir_binop_lequal:
+ inst->conditional_mod = BRW_CONDITIONAL_LE;
+ break;
+ case ir_binop_greater:
+ inst->conditional_mod = BRW_CONDITIONAL_G;
+ break;
+ case ir_binop_less:
+ inst->conditional_mod = BRW_CONDITIONAL_L;
+ break;
+ default:
+ assert(!"not reached: unknown loop condition");
+ this->fail = true;
+ break;
+ }
+
+ inst = emit(fs_inst(BRW_OPCODE_BREAK));
+ inst->predicated = true;
+ }
+
+ foreach_iter(exec_list_iterator, iter, ir->body_instructions) {
+ ir_instruction *ir = (ir_instruction *)iter.get();
+ fs_inst *inst;
+
+ this->base_ir = ir;
+ ir->accept(this);
+
+ /* Check the maximum loop iters counter. */
+ inst = emit(fs_inst(BRW_OPCODE_ADD, max_iter, max_iter, fs_reg(-1)));
+ inst->conditional_mod = BRW_CONDITIONAL_Z;
+
+ inst = emit(fs_inst(BRW_OPCODE_BREAK));
+ inst->predicated = true;
+ }
+
+ if (ir->increment) {
+ this->base_ir = ir->increment;
+ ir->increment->accept(this);
+ emit(fs_inst(BRW_OPCODE_ADD, counter, counter, this->result));
+ }
+
+ emit(fs_inst(BRW_OPCODE_WHILE));
}
void
fs_visitor::visit(ir_loop_jump *ir)
{
- assert(!"FINISHME");
+ switch (ir->mode) {
+ case ir_loop_jump::jump_break:
+ emit(fs_inst(BRW_OPCODE_BREAK));
+ break;
+ case ir_loop_jump::jump_continue:
+ emit(fs_inst(BRW_OPCODE_CONTINUE));
+ break;
+ }
}
void
this->current_annotation = "compute pixel centers";
this->pixel_x = fs_reg(this, glsl_type::uint_type);
this->pixel_y = fs_reg(this, glsl_type::uint_type);
+ this->pixel_x.type = BRW_REGISTER_TYPE_UW;
+ this->pixel_y.type = BRW_REGISTER_TYPE_UW;
emit(fs_inst(BRW_OPCODE_ADD,
this->pixel_x,
fs_reg(stride(suboffset(g1_uw, 4), 2, 4, 0)),
emit(fs_inst(BRW_OPCODE_ADD,
this->delta_y,
this->pixel_y,
- fs_reg(brw_vec1_grf(1, 1))));
+ fs_reg(negate(brw_vec1_grf(1, 1)))));
this->current_annotation = "compute pos.w and 1/pos.w";
/* Compute wpos. Unlike many other varying inputs, we usually need it
this->pixel_w = fs_reg(this, glsl_type::float_type);
emit(fs_inst(FS_OPCODE_RCP, this->pixel_w, wpos));
- /* FINISHME: gl_FrontFacing */
-
foreach_iter(exec_list_iterator, iter, *this->shader->ir) {
ir_instruction *ir = (ir_instruction *)iter.get();
ir_variable *var = ir->as_variable();
void
fs_visitor::emit_fb_writes()
{
- this->current_annotation = "FB write";
+ this->current_annotation = "FB write header";
+ int nr = 0;
+
+ /* m0, m1 header */
+ nr += 2;
+
+ if (c->key.aa_dest_stencil_reg) {
+ emit(fs_inst(BRW_OPCODE_MOV, fs_reg(MRF, nr++),
+ fs_reg(brw_vec8_grf(c->key.aa_dest_stencil_reg, 0))));
+ }
+
+ /* Reserve space for color. It'll be filled in per MRT below. */
+ int color_mrf = nr;
+ nr += 4;
+
+ if (c->key.source_depth_to_render_target) {
+ if (c->key.computes_depth) {
+ /* Hand over gl_FragDepth. */
+ assert(this->frag_depth);
+ fs_reg depth = *(variable_storage(this->frag_depth));
+
+ emit(fs_inst(BRW_OPCODE_MOV, fs_reg(MRF, nr++), depth));
+ } else {
+ /* Pass through the payload depth. */
+ emit(fs_inst(BRW_OPCODE_MOV, fs_reg(MRF, nr++),
+ fs_reg(brw_vec8_grf(c->key.source_depth_reg, 0))));
+ }
+ }
- assert(this->frag_color || !"FINISHME: MRT");
- fs_reg color = *(variable_storage(this->frag_color));
+ if (c->key.dest_depth_reg) {
+ emit(fs_inst(BRW_OPCODE_MOV, fs_reg(MRF, nr++),
+ fs_reg(brw_vec8_grf(c->key.dest_depth_reg, 0))));
+ }
+
+ fs_reg color = reg_undef;
+ if (this->frag_color)
+ color = *(variable_storage(this->frag_color));
+ else if (this->frag_data)
+ color = *(variable_storage(this->frag_data));
+
+ for (int target = 0; target < c->key.nr_color_regions; target++) {
+ this->current_annotation = talloc_asprintf(this->mem_ctx,
+ "FB write target %d",
+ target);
+ if (this->frag_color || this->frag_data) {
+ for (int i = 0; i < 4; i++) {
+ emit(fs_inst(BRW_OPCODE_MOV,
+ fs_reg(MRF, color_mrf + i),
+ color));
+ color.reg_offset++;
+ }
+ }
+
+ if (this->frag_color)
+ color.reg_offset -= 4;
- for (int i = 0; i < 4; i++) {
- emit(fs_inst(BRW_OPCODE_MOV,
- fs_reg(MRF, 2 + i),
- color));
- color.reg_offset++;
+ fs_inst *inst = emit(fs_inst(FS_OPCODE_FB_WRITE,
+ reg_undef, reg_undef));
+ inst->target = target;
+ inst->mlen = nr;
+ if (target == c->key.nr_color_regions - 1)
+ inst->eot = true;
}
- emit(fs_inst(FS_OPCODE_FB_WRITE,
- fs_reg(0),
- fs_reg(0)));
+ if (c->key.nr_color_regions == 0) {
+ fs_inst *inst = emit(fs_inst(FS_OPCODE_FB_WRITE,
+ reg_undef, reg_undef));
+ inst->mlen = nr;
+ inst->eot = true;
+ }
this->current_annotation = NULL;
}
void
fs_visitor::generate_fb_write(fs_inst *inst)
{
- GLboolean eot = 1; /* FINISHME: MRT */
- /* FINISHME: AADS */
+ GLboolean eot = inst->eot;
/* Header is 2 regs, g0 and g1 are the contents. g0 will be implied
* move, here's g1.
brw_vec8_grf(1, 0));
brw_pop_insn_state(p);
- int nr = 2 + 4;
-
brw_fb_WRITE(p,
8, /* dispatch_width */
retype(vec8(brw_null_reg()), BRW_REGISTER_TYPE_UW),
0, /* base MRF */
retype(brw_vec8_grf(0, 0), BRW_REGISTER_TYPE_UW),
- 0, /* FINISHME: MRT target */
- nr,
+ inst->target,
+ inst->mlen,
0,
eot);
}
BRW_MATH_PRECISION_FULL);
}
+void
+fs_visitor::generate_tex(fs_inst *inst, struct brw_reg dst, struct brw_reg src)
+{
+ int msg_type = -1;
+ int rlen = 4;
+
+ if (intel->gen == 5) {
+ switch (inst->opcode) {
+ case FS_OPCODE_TEX:
+ if (inst->shadow_compare) {
+ msg_type = BRW_SAMPLER_MESSAGE_SAMPLE_COMPARE_GEN5;
+ } else {
+ msg_type = BRW_SAMPLER_MESSAGE_SAMPLE_GEN5;
+ }
+ break;
+ case FS_OPCODE_TXB:
+ if (inst->shadow_compare) {
+ msg_type = BRW_SAMPLER_MESSAGE_SAMPLE_BIAS_COMPARE_GEN5;
+ } else {
+ msg_type = BRW_SAMPLER_MESSAGE_SAMPLE_BIAS_GEN5;
+ }
+ break;
+ }
+ } else {
+ switch (inst->opcode) {
+ case FS_OPCODE_TEX:
+ /* Note that G45 and older determines shadow compare and dispatch width
+ * from message length for most messages.
+ */
+ if (inst->shadow_compare) {
+ msg_type = BRW_SAMPLER_MESSAGE_SIMD16_SAMPLE_COMPARE;
+ } else {
+ msg_type = BRW_SAMPLER_MESSAGE_SIMD16_SAMPLE;
+ }
+ case FS_OPCODE_TXB:
+ if (inst->shadow_compare) {
+ assert(!"FINISHME: shadow compare with bias.");
+ msg_type = BRW_SAMPLER_MESSAGE_SIMD16_SAMPLE_BIAS;
+ } else {
+ msg_type = BRW_SAMPLER_MESSAGE_SIMD16_SAMPLE_BIAS;
+ rlen = 8;
+ }
+ break;
+ }
+ }
+ assert(msg_type != -1);
+
+ /* g0 header. */
+ src.nr--;
+
+ brw_SAMPLE(p,
+ retype(dst, BRW_REGISTER_TYPE_UW),
+ src.nr,
+ retype(brw_vec8_grf(0, 0), BRW_REGISTER_TYPE_UW),
+ SURF_INDEX_TEXTURE(inst->sampler),
+ inst->sampler,
+ WRITEMASK_XYZW,
+ msg_type,
+ rlen,
+ inst->mlen + 1,
+ 0,
+ 1,
+ BRW_SAMPLER_SIMD_MODE_SIMD8);
+}
+
+
+/* For OPCODE_DDX and OPCODE_DDY, per channel of output we've got input
+ * looking like:
+ *
+ * arg0: ss0.tl ss0.tr ss0.bl ss0.br ss1.tl ss1.tr ss1.bl ss1.br
+ *
+ * and we're trying to produce:
+ *
+ * DDX DDY
+ * dst: (ss0.tr - ss0.tl) (ss0.tl - ss0.bl)
+ * (ss0.tr - ss0.tl) (ss0.tr - ss0.br)
+ * (ss0.br - ss0.bl) (ss0.tl - ss0.bl)
+ * (ss0.br - ss0.bl) (ss0.tr - ss0.br)
+ * (ss1.tr - ss1.tl) (ss1.tl - ss1.bl)
+ * (ss1.tr - ss1.tl) (ss1.tr - ss1.br)
+ * (ss1.br - ss1.bl) (ss1.tl - ss1.bl)
+ * (ss1.br - ss1.bl) (ss1.tr - ss1.br)
+ *
+ * and add another set of two more subspans if in 16-pixel dispatch mode.
+ *
+ * For DDX, it ends up being easy: width = 2, horiz=0 gets us the same result
+ * for each pair, and vertstride = 2 jumps us 2 elements after processing a
+ * pair. But for DDY, it's harder, as we want to produce the pairs swizzled
+ * between each other. We could probably do it like ddx and swizzle the right
+ * order later, but bail for now and just produce
+ * ((ss0.tl - ss0.bl)x4 (ss1.tl - ss1.bl)x4)
+ */
+void
+fs_visitor::generate_ddx(fs_inst *inst, struct brw_reg dst, struct brw_reg src)
+{
+ struct brw_reg src0 = brw_reg(src.file, src.nr, 1,
+ BRW_REGISTER_TYPE_F,
+ BRW_VERTICAL_STRIDE_2,
+ BRW_WIDTH_2,
+ BRW_HORIZONTAL_STRIDE_0,
+ BRW_SWIZZLE_XYZW, WRITEMASK_XYZW);
+ struct brw_reg src1 = brw_reg(src.file, src.nr, 0,
+ BRW_REGISTER_TYPE_F,
+ BRW_VERTICAL_STRIDE_2,
+ BRW_WIDTH_2,
+ BRW_HORIZONTAL_STRIDE_0,
+ BRW_SWIZZLE_XYZW, WRITEMASK_XYZW);
+ brw_ADD(p, dst, src0, negate(src1));
+}
+
+void
+fs_visitor::generate_ddy(fs_inst *inst, struct brw_reg dst, struct brw_reg src)
+{
+ struct brw_reg src0 = brw_reg(src.file, src.nr, 0,
+ BRW_REGISTER_TYPE_F,
+ BRW_VERTICAL_STRIDE_4,
+ BRW_WIDTH_4,
+ BRW_HORIZONTAL_STRIDE_0,
+ BRW_SWIZZLE_XYZW, WRITEMASK_XYZW);
+ struct brw_reg src1 = brw_reg(src.file, src.nr, 2,
+ BRW_REGISTER_TYPE_F,
+ BRW_VERTICAL_STRIDE_4,
+ BRW_WIDTH_4,
+ BRW_HORIZONTAL_STRIDE_0,
+ BRW_SWIZZLE_XYZW, WRITEMASK_XYZW);
+ brw_ADD(p, dst, src0, negate(src1));
+}
+
+void
+fs_visitor::generate_discard(fs_inst *inst)
+{
+ 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_NOT(p, c->emit_mask_reg, brw_mask_reg(1)); /* IMASK */
+ brw_AND(p, g0, c->emit_mask_reg, g0);
+ brw_pop_insn_state(p);
+}
+
static void
trivial_assign_reg(int header_size, fs_reg *reg)
{
c->prog_data.first_curbe_grf = c->key.nr_payload_regs;
c->prog_data.curb_read_length = ALIGN(c->prog_data.nr_params, 8) / 8;
+ if (intel->gen == 5 && (c->prog_data.first_curbe_grf +
+ c->prog_data.curb_read_length) & 1) {
+ /* Align the start of the interpolation coefficients so that we can use
+ * the PLN instruction.
+ */
+ c->prog_data.first_curbe_grf++;
+ }
+
/* Map the offsets in the UNIFORM file to fixed HW regs. */
foreach_iter(exec_list_iterator, iter, this->instructions) {
fs_inst *inst = (fs_inst *)iter.get();
for (unsigned int i = 0; i < 3; i++) {
if (inst->src[i].file == UNIFORM) {
int constant_nr = inst->src[i].hw_reg + inst->src[i].reg_offset;
- struct brw_reg brw_reg;
+ struct brw_reg brw_reg = brw_vec1_grf(c->prog_data.first_curbe_grf +
+ constant_nr / 8,
+ constant_nr % 8);
- brw_reg = brw_vec1_grf(c->prog_data.first_curbe_grf +
- constant_nr / 8,
- constant_nr % 8);
- inst->src[i] = fs_reg(brw_reg);
+ inst->src[i].file = FIXED_HW_REG;
+ inst->src[i].fixed_hw_reg = brw_reg;
}
}
}
last_grf = MAX2(last_grf, inst->src[1].hw_reg);
}
- this->grf_used = last_grf;
+ this->grf_used = last_grf + 1;
}
static struct brw_reg brw_reg_from_fs_reg(fs_reg *reg)
brw_reg = brw_imm_f(reg->imm.f);
break;
case BRW_REGISTER_TYPE_D:
- brw_reg = brw_imm_f(reg->imm.i);
+ brw_reg = brw_imm_d(reg->imm.i);
break;
case BRW_REGISTER_TYPE_UD:
- brw_reg = brw_imm_f(reg->imm.u);
+ brw_reg = brw_imm_ud(reg->imm.u);
break;
default:
assert(!"not reached");
{
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];
+
+ if_depth_in_loop[loop_stack_depth] = 0;
+ memset(&if_stack, 0, sizeof(if_stack));
foreach_iter(exec_list_iterator, iter, this->instructions) {
fs_inst *inst = (fs_inst *)iter.get();
struct brw_reg src[3], dst;
case BRW_OPCODE_MUL:
brw_MUL(p, dst, src[0], src[1]);
break;
+
+ case BRW_OPCODE_FRC:
+ brw_FRC(p, dst, src[0]);
+ break;
+ case BRW_OPCODE_RNDD:
+ brw_RNDD(p, dst, src[0]);
+ break;
+ case BRW_OPCODE_RNDZ:
+ brw_RNDZ(p, dst, src[0]);
+ break;
+
+ case BRW_OPCODE_AND:
+ brw_AND(p, dst, src[0], src[1]);
+ break;
+ case BRW_OPCODE_OR:
+ brw_OR(p, dst, src[0], src[1]);
+ break;
+ case BRW_OPCODE_XOR:
+ brw_XOR(p, dst, src[0], src[1]);
+ break;
+
+ case BRW_OPCODE_CMP:
+ brw_CMP(p, dst, inst->conditional_mod, src[0], src[1]);
+ break;
+ case BRW_OPCODE_SEL:
+ brw_SEL(p, dst, src[0], src[1]);
+ break;
+
+ case BRW_OPCODE_IF:
+ assert(if_stack_depth < 16);
+ if_stack[if_stack_depth] = brw_IF(p, BRW_EXECUTE_8);
+ if_depth_in_loop[loop_stack_depth]++;
+ if_stack_depth++;
+ break;
+ case BRW_OPCODE_ELSE:
+ if_stack[if_stack_depth - 1] =
+ brw_ELSE(p, if_stack[if_stack_depth - 1]);
+ break;
+ case BRW_OPCODE_ENDIF:
+ if_stack_depth--;
+ brw_ENDIF(p , if_stack[if_stack_depth]);
+ if_depth_in_loop[loop_stack_depth]--;
+ break;
+
+ case BRW_OPCODE_DO:
+ loop_stack[loop_stack_depth++] = brw_DO(p, BRW_EXECUTE_8);
+ if_depth_in_loop[loop_stack_depth] = 0;
+ break;
+
+ case BRW_OPCODE_BREAK:
+ brw_BREAK(p, if_depth_in_loop[loop_stack_depth]);
+ brw_set_predicate_control(p, BRW_PREDICATE_NONE);
+ break;
+ case BRW_OPCODE_CONTINUE:
+ brw_CONT(p, if_depth_in_loop[loop_stack_depth]);
+ brw_set_predicate_control(p, BRW_PREDICATE_NONE);
+ break;
+
+ case BRW_OPCODE_WHILE: {
+ struct brw_instruction *inst0, *inst1;
+ GLuint br = 1;
+
+ if (intel->gen == 5)
+ br = 2;
+
+ assert(loop_stack_depth > 0);
+ loop_stack_depth--;
+ inst0 = inst1 = brw_WHILE(p, loop_stack[loop_stack_depth]);
+ /* patch all the BREAK/CONT instructions from last BGNLOOP */
+ while (inst0 > loop_stack[loop_stack_depth]) {
+ inst0--;
+ if (inst0->header.opcode == BRW_OPCODE_BREAK &&
+ inst0->bits3.if_else.jump_count == 0) {
+ inst0->bits3.if_else.jump_count = br * (inst1 - inst0 + 1);
+ }
+ else if (inst0->header.opcode == BRW_OPCODE_CONTINUE &&
+ inst0->bits3.if_else.jump_count == 0) {
+ inst0->bits3.if_else.jump_count = br * (inst1 - inst0);
+ }
+ }
+ }
+ break;
+
case FS_OPCODE_RCP:
case FS_OPCODE_RSQ:
case FS_OPCODE_SQRT:
case FS_OPCODE_LINTERP:
generate_linterp(inst, dst, src);
break;
+ case FS_OPCODE_TEX:
+ case FS_OPCODE_TXB:
+ case FS_OPCODE_TXL:
+ generate_tex(inst, dst, src[0]);
+ break;
+ case FS_OPCODE_DISCARD:
+ generate_discard(inst);
+ break;
+ case FS_OPCODE_DDX:
+ generate_ddx(inst, dst, src[0]);
+ break;
+ case FS_OPCODE_DDY:
+ generate_ddy(inst, dst, src[0]);
+ break;
case FS_OPCODE_FB_WRITE:
generate_fb_write(inst);
break;
default:
- assert(!"not reached");
+ if (inst->opcode < (int)ARRAY_SIZE(brw_opcodes)) {
+ _mesa_problem(ctx, "Unsupported opcode `%s' in FS",
+ brw_opcodes[inst->opcode].name);
+ } else {
+ _mesa_problem(ctx, "Unsupported opcode %d in FS", inst->opcode);
+ }
+ this->fail = true;
}
if (annotation_len < p->nr_insn) {
ir->accept(&v);
}
- if (v.fail)
- return GL_FALSE;
-
v.emit_fb_writes();
v.assign_curb_setup();
v.assign_urb_setup();
v.generate_code();
+ assert(!v.fail); /* FINISHME: Cleanly fail, tested at link time, etc. */
+
+ if (v.fail)
+ return GL_FALSE;
+
if (INTEL_DEBUG & DEBUG_WM) {
const char *last_annotation_string = NULL;
ir_instruction *last_annotation_ir = NULL;