summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mesa/drivers/dri/i965/brw_fs.cpp143
1 files changed, 128 insertions, 15 deletions
diff --git a/src/mesa/drivers/dri/i965/brw_fs.cpp b/src/mesa/drivers/dri/i965/brw_fs.cpp
index ede1848520..1ef27ce9ce 100644
--- a/src/mesa/drivers/dri/i965/brw_fs.cpp
+++ b/src/mesa/drivers/dri/i965/brw_fs.cpp
@@ -67,6 +67,7 @@ enum fs_opcodes {
FS_OPCODE_DDX,
FS_OPCODE_DDY,
FS_OPCODE_LINTERP,
+ FS_OPCODE_TEX,
};
static int using_new_fs = -1;
@@ -299,53 +300,52 @@ public:
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->shadow_compare = false;
+ }
+
+ fs_inst()
+ {
+ init();
}
fs_inst(int opcode)
{
+ init();
this->opcode = opcode;
- this->saturate = false;
- this->conditional_mod = BRW_CONDITIONAL_NONE;
- this->predicated = false;
}
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_* */
@@ -355,6 +355,10 @@ public:
bool predicated;
int conditional_mod; /**< BRW_CONDITIONAL_* */
+ int mlen; /** SEND message length */
+ int sampler;
+ bool shadow_compare;
+
/** @{
* Annotation for the generated IR. One of the two can be set.
*/
@@ -425,6 +429,7 @@ public:
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 emit_dummy_fs();
@@ -540,7 +545,8 @@ fs_visitor::visit(ir_variable *ir)
int param_index = c->prog_data.nr_params;
/* FINISHME: This is wildly incomplete. */
- assert(ir->type->is_scalar() || ir->type->is_vector());
+ assert(ir->type->is_scalar() || ir->type->is_vector() ||
+ ir->type->is_sampler());
const struct gl_program *fp = &this->brw->fragment_program->Base;
/* Our support for uniforms is piggy-backed on the struct
@@ -869,7 +875,71 @@ fs_visitor::visit(ir_assignment *ir)
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);
+ this->result = dst;
+
+ switch (ir->op) {
+ case ir_tex:
+ inst = emit(fs_inst(FS_OPCODE_TEX, dst, fs_reg(MRF, base_mrf)));
+ break;
+ case ir_txb:
+ case ir_txl:
+ assert(!"FINISHME");
+ break;
+ case ir_txd:
+ case ir_txf:
+ assert(!"GLSL 1.30 features unsupported");
+ break;
+ }
+
+ if (ir->shadow_comparitor)
+ inst->shadow_compare = true;
+ inst->mlen = mlen;
}
void
@@ -1309,6 +1379,46 @@ fs_visitor::generate_math(fs_inst *inst,
BRW_MATH_PRECISION_FULL);
}
+void
+fs_visitor::generate_tex(fs_inst *inst, struct brw_reg dst, struct brw_reg src)
+{
+ int msg_type;
+
+ if (intel->gen == 5) {
+ if (inst->shadow_compare)
+ msg_type = BRW_SAMPLER_MESSAGE_SAMPLE_COMPARE_GEN5;
+ else
+ msg_type = BRW_SAMPLER_MESSAGE_SAMPLE_GEN5;
+ } else {
+ /* 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;
+ }
+
+ int response_length = 4;
+
+ /* 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,
+ response_length,
+ inst->mlen + 1,
+ 0,
+ 1,
+ BRW_SAMPLER_SIMD_MODE_SIMD8);
+}
+
static void
trivial_assign_reg(int header_size, fs_reg *reg)
{
@@ -1538,6 +1648,9 @@ fs_visitor::generate_code()
case FS_OPCODE_LINTERP:
generate_linterp(inst, dst, src);
break;
+ case FS_OPCODE_TEX:
+ generate_tex(inst, dst, src[0]);
+ break;
case FS_OPCODE_FB_WRITE:
generate_fb_write(inst);
break;