summaryrefslogtreecommitdiff
path: root/src/mesa/drivers/dri/i965
diff options
context:
space:
mode:
Diffstat (limited to 'src/mesa/drivers/dri/i965')
-rw-r--r--src/mesa/drivers/dri/i965/Makefile5
-rw-r--r--src/mesa/drivers/dri/i965/brw_context.c9
-rw-r--r--src/mesa/drivers/dri/i965/brw_context.h26
-rw-r--r--src/mesa/drivers/dri/i965/brw_defines.h3
-rw-r--r--src/mesa/drivers/dri/i965/brw_disasm.c80
-rw-r--r--src/mesa/drivers/dri/i965/brw_draw_upload.c4
-rw-r--r--src/mesa/drivers/dri/i965/brw_eu.c6
-rw-r--r--src/mesa/drivers/dri/i965/brw_eu.h10
-rw-r--r--src/mesa/drivers/dri/i965/brw_eu_emit.c63
-rw-r--r--src/mesa/drivers/dri/i965/brw_fs.cpp1924
-rw-r--r--src/mesa/drivers/dri/i965/brw_fs_channel_expressions.cpp365
-rw-r--r--src/mesa/drivers/dri/i965/brw_fs_vector_splitting.cpp391
-rw-r--r--src/mesa/drivers/dri/i965/brw_misc_state.c4
-rw-r--r--src/mesa/drivers/dri/i965/brw_optimize.c81
-rw-r--r--src/mesa/drivers/dri/i965/brw_program.c36
-rw-r--r--src/mesa/drivers/dri/i965/brw_state.h1
-rw-r--r--src/mesa/drivers/dri/i965/brw_state_upload.c7
-rw-r--r--src/mesa/drivers/dri/i965/brw_structs.h11
-rw-r--r--src/mesa/drivers/dri/i965/brw_vs.c8
-rw-r--r--src/mesa/drivers/dri/i965/brw_vs_emit.c134
-rw-r--r--src/mesa/drivers/dri/i965/brw_vtbl.c1
-rw-r--r--src/mesa/drivers/dri/i965/brw_wm.c27
-rw-r--r--src/mesa/drivers/dri/i965/brw_wm.h21
-rw-r--r--src/mesa/drivers/dri/i965/brw_wm_debug.c8
-rw-r--r--src/mesa/drivers/dri/i965/brw_wm_emit.c138
-rw-r--r--src/mesa/drivers/dri/i965/brw_wm_fp.c11
-rw-r--r--src/mesa/drivers/dri/i965/brw_wm_glsl.c26
-rw-r--r--src/mesa/drivers/dri/i965/brw_wm_iz.c2
-rw-r--r--src/mesa/drivers/dri/i965/brw_wm_pass0.c2
-rw-r--r--src/mesa/drivers/dri/i965/brw_wm_pass1.c6
-rw-r--r--src/mesa/drivers/dri/i965/brw_wm_pass2.c4
-rw-r--r--src/mesa/drivers/dri/i965/brw_wm_state.c18
-rw-r--r--src/mesa/drivers/dri/i965/gen6_cc.c2
-rw-r--r--src/mesa/drivers/dri/i965/gen6_wm_state.c71
34 files changed, 3307 insertions, 198 deletions
diff --git a/src/mesa/drivers/dri/i965/Makefile b/src/mesa/drivers/dri/i965/Makefile
index e381a5c714..bea48e1313 100644
--- a/src/mesa/drivers/dri/i965/Makefile
+++ b/src/mesa/drivers/dri/i965/Makefile
@@ -104,6 +104,11 @@ C_SOURCES = \
$(COMMON_SOURCES) \
$(DRIVER_SOURCES)
+CXX_SOURCES = \
+ brw_fs.cpp \
+ brw_fs_channel_expressions.cpp \
+ brw_fs_vector_splitting.cpp
+
ASM_SOURCES =
DRIVER_DEFINES = -I../intel
diff --git a/src/mesa/drivers/dri/i965/brw_context.c b/src/mesa/drivers/dri/i965/brw_context.c
index 6d064b822e..d2b20165f9 100644
--- a/src/mesa/drivers/dri/i965/brw_context.c
+++ b/src/mesa/drivers/dri/i965/brw_context.c
@@ -144,7 +144,8 @@ GLboolean brwCreateContext( int api,
brw->CMD_VF_STATISTICS = CMD_VF_STATISTICS_GM45;
brw->CMD_PIPELINE_SELECT = CMD_PIPELINE_SELECT_GM45;
brw->has_surface_tile_offset = GL_TRUE;
- brw->has_compr4 = GL_TRUE;
+ if (intel->gen < 6)
+ brw->has_compr4 = GL_TRUE;
brw->has_aa_line_parameters = GL_TRUE;
brw->has_pln = GL_TRUE;
} else {
@@ -153,7 +154,11 @@ GLboolean brwCreateContext( int api,
}
/* WM maximum threads is number of EUs times number of threads per EU. */
- if (intel->gen == 5) {
+ if (intel->gen >= 6) {
+ brw->urb.size = 1024;
+ brw->vs_max_threads = 60;
+ brw->wm_max_threads = 80;
+ } else if (intel->gen == 5) {
brw->urb.size = 1024;
brw->vs_max_threads = 72;
brw->wm_max_threads = 12 * 6;
diff --git a/src/mesa/drivers/dri/i965/brw_context.h b/src/mesa/drivers/dri/i965/brw_context.h
index cc4e6638e8..703a7de78d 100644
--- a/src/mesa/drivers/dri/i965/brw_context.h
+++ b/src/mesa/drivers/dri/i965/brw_context.h
@@ -179,6 +179,16 @@ struct brw_fragment_program {
GLbitfield tex_units_used;
};
+struct brw_shader {
+ struct gl_shader base;
+
+ /** Shader IR transformed for native compile, at link time. */
+ struct exec_list *ir;
+};
+
+struct brw_shader_program {
+ struct gl_shader_program base;
+};
/* Data about a particular attempt to compile a program. Note that
* there can be many of these, each in a different GL state
@@ -654,7 +664,13 @@ struct brw_context
drm_intel_bo *prog_bo;
drm_intel_bo *state_bo;
- drm_intel_bo *const_bo;
+ drm_intel_bo *const_bo; /* pull constant buffer. */
+ /**
+ * This is the push constant BO on gen6.
+ *
+ * Pre-gen6, push constants live in the CURBE.
+ */
+ drm_intel_bo *push_const_bo;
} wm;
@@ -686,7 +702,13 @@ struct brw_context
#define BRW_PACKCOLOR8888(r,g,b,a) ((r<<24) | (g<<16) | (b<<8) | a)
-
+struct brw_instruction_info {
+ char *name;
+ int nsrc;
+ int ndst;
+ GLboolean is_arith;
+};
+extern const struct brw_instruction_info brw_opcodes[128];
/*======================================================================
* brw_vtbl.c
diff --git a/src/mesa/drivers/dri/i965/brw_defines.h b/src/mesa/drivers/dri/i965/brw_defines.h
index f7a68cead7..6b8e9e05d0 100644
--- a/src/mesa/drivers/dri/i965/brw_defines.h
+++ b/src/mesa/drivers/dri/i965/brw_defines.h
@@ -686,6 +686,9 @@
#define BRW_SAMPLER_MESSAGE_SAMPLE_BIAS_GEN5 1
#define BRW_SAMPLER_MESSAGE_SAMPLE_LOD_GEN5 2
#define BRW_SAMPLER_MESSAGE_SAMPLE_COMPARE_GEN5 3
+#define BRW_SAMPLER_MESSAGE_SAMPLE_DERIVS_GEN5 4
+#define BRW_SAMPLER_MESSAGE_SAMPLE_BIAS_COMPARE_GEN5 5
+#define BRW_SAMPLER_MESSAGE_SAMPLE_LOD_COMPARE_GEN5 6
/* for GEN5 only */
#define BRW_SAMPLER_SIMD_MODE_SIMD4X2 0
diff --git a/src/mesa/drivers/dri/i965/brw_disasm.c b/src/mesa/drivers/dri/i965/brw_disasm.c
index d230714536..f74a236834 100644
--- a/src/mesa/drivers/dri/i965/brw_disasm.c
+++ b/src/mesa/drivers/dri/i965/brw_disasm.c
@@ -159,6 +159,11 @@ char *saturate[2] = {
[1] = ".sat"
};
+char *accwr[2] = {
+ [0] = "",
+ [1] = "AccWrEnable"
+};
+
char *exec_size[8] = {
[0] = "1",
[1] = "2",
@@ -206,6 +211,7 @@ char *compr_ctrl[4] = {
[0] = "",
[1] = "sechalf",
[2] = "compr",
+ [3] = "compr4",
};
char *dep_ctrl[4] = {
@@ -235,6 +241,16 @@ char *reg_encoding[8] = {
[7] = "F"
};
+int reg_type_size[8] = {
+ [0] = 4,
+ [1] = 4,
+ [2] = 2,
+ [3] = 2,
+ [4] = 1,
+ [5] = 1,
+ [7] = 4
+};
+
char *imm_encoding[8] = {
[0] = "UD",
[1] = "D",
@@ -423,6 +439,11 @@ static int print_opcode (FILE *file, int id)
static int reg (FILE *file, GLuint _reg_file, GLuint _reg_nr)
{
int err = 0;
+
+ /* Clear the Compr4 instruction compression bit. */
+ if (_reg_file == BRW_MESSAGE_REGISTER_FILE)
+ _reg_nr &= ~(1 << 7);
+
if (_reg_file == BRW_ARCHITECTURE_REGISTER_FILE) {
switch (_reg_nr & 0xf0) {
case BRW_ARF_NULL:
@@ -476,7 +497,8 @@ static int dest (FILE *file, struct brw_instruction *inst)
if (err == -1)
return 0;
if (inst->bits1.da1.dest_subreg_nr)
- format (file, ".%d", inst->bits1.da1.dest_subreg_nr);
+ format (file, ".%d", inst->bits1.da1.dest_subreg_nr /
+ reg_type_size[inst->bits1.da1.dest_reg_type]);
format (file, "<%d>", inst->bits1.da1.dest_horiz_stride);
err |= control (file, "dest reg encoding", reg_encoding, inst->bits1.da1.dest_reg_type, NULL);
}
@@ -484,7 +506,8 @@ static int dest (FILE *file, struct brw_instruction *inst)
{
string (file, "g[a0");
if (inst->bits1.ia1.dest_subreg_nr)
- format (file, ".%d", inst->bits1.ia1.dest_subreg_nr);
+ format (file, ".%d", inst->bits1.ia1.dest_subreg_nr /
+ reg_type_size[inst->bits1.ia1.dest_reg_type]);
if (inst->bits1.ia1.dest_indirect_offset)
format (file, " %d", inst->bits1.ia1.dest_indirect_offset);
string (file, "]");
@@ -500,7 +523,8 @@ static int dest (FILE *file, struct brw_instruction *inst)
if (err == -1)
return 0;
if (inst->bits1.da16.dest_subreg_nr)
- format (file, ".%d", inst->bits1.da16.dest_subreg_nr);
+ format (file, ".%d", inst->bits1.da16.dest_subreg_nr /
+ reg_type_size[inst->bits1.da16.dest_reg_type]);
string (file, "<1>");
err |= control (file, "writemask", writemask, inst->bits1.da16.dest_writemask, NULL);
err |= control (file, "dest reg encoding", reg_encoding, inst->bits1.da16.dest_reg_type, NULL);
@@ -541,7 +565,7 @@ static int src_da1 (FILE *file, GLuint type, GLuint _reg_file,
if (err == -1)
return 0;
if (sub_reg_num)
- format (file, ".%d", sub_reg_num);
+ format (file, ".%d", sub_reg_num / reg_type_size[type]); /* use formal style like spec */
src_align1_region (file, _vert_stride, _width, _horiz_stride);
err |= control (file, "src reg encoding", reg_encoding, type, NULL);
return err;
@@ -595,11 +619,12 @@ static int src_da16 (FILE *file,
if (err == -1)
return 0;
if (_subreg_nr)
- format (file, ".%d", _subreg_nr);
+ /* bit4 for subreg number byte addressing. Make this same meaning as
+ in da1 case, so output looks consistent. */
+ format (file, ".%d", 16 / reg_type_size[_reg_type]);
string (file, "<");
err |= control (file, "vert stride", vert_stride, _vert_stride, NULL);
string (file, ",4,1>");
- err |= control (file, "src da16 reg type", reg_encoding, _reg_type, NULL);
/*
* Three kinds of swizzle display:
* identity - nothing printed
@@ -863,12 +888,25 @@ int brw_disasm (FILE *file, struct brw_instruction *inst, int gen)
inst->bits3.math.precision, &space);
break;
case BRW_MESSAGE_TARGET_SAMPLER:
- format (file, " (%d, %d, ",
- inst->bits3.sampler.binding_table_index,
- inst->bits3.sampler.sampler);
- err |= control (file, "sampler target format", sampler_target_format,
- inst->bits3.sampler.return_format, NULL);
- string (file, ")");
+ if (gen >= 5) {
+ format (file, " (%d, %d, %d, %d)",
+ inst->bits3.sampler_gen5.binding_table_index,
+ inst->bits3.sampler_gen5.sampler,
+ inst->bits3.sampler_gen5.msg_type,
+ inst->bits3.sampler_gen5.simd_mode);
+ } else if (0 /* FINISHME: is_g4x */) {
+ format (file, " (%d, %d)",
+ inst->bits3.sampler_g4x.binding_table_index,
+ inst->bits3.sampler_g4x.sampler);
+ } else {
+ format (file, " (%d, %d, ",
+ inst->bits3.sampler.binding_table_index,
+ inst->bits3.sampler.sampler);
+ err |= control (file, "sampler target format",
+ sampler_target_format,
+ inst->bits3.sampler.return_format, NULL);
+ string (file, ")");
+ }
break;
case BRW_MESSAGE_TARGET_DATAPORT_READ:
if (gen >= 6) {
@@ -929,6 +967,11 @@ int brw_disasm (FILE *file, struct brw_instruction *inst, int gen)
inst->bits3.urb.used, &space);
err |= control (file, "urb complete", urb_complete,
inst->bits3.urb.complete, &space);
+ if (gen >= 5) {
+ format (file, " mlen %d, rlen %d\n",
+ inst->bits3.urb_gen5.msg_length,
+ inst->bits3.urb_gen5.response_length);
+ }
break;
case BRW_MESSAGE_TARGET_THREAD_SPAWNER:
break;
@@ -957,8 +1000,19 @@ int brw_disasm (FILE *file, struct brw_instruction *inst, int gen)
err |= control(file, "access mode", access_mode, inst->header.access_mode, &space);
err |= control (file, "mask control", mask_ctrl, inst->header.mask_control, &space);
err |= control (file, "dependency control", dep_ctrl, inst->header.dependency_control, &space);
- err |= control (file, "compression control", compr_ctrl, inst->header.compression_control, &space);
+
+ if (inst->header.compression_control == BRW_COMPRESSION_COMPRESSED &&
+ opcode[inst->header.opcode].ndst > 0 &&
+ inst->bits1.da1.dest_reg_file == BRW_MESSAGE_REGISTER_FILE &&
+ inst->bits1.da1.dest_reg_nr & (1 << 7)) {
+ format (file, " compr4");
+ } else {
+ err |= control (file, "compression control", compr_ctrl,
+ inst->header.compression_control, &space);
+ }
err |= control (file, "thread control", thread_ctrl, inst->header.thread_control, &space);
+ if (gen >= 6)
+ err |= control (file, "acc write control", accwr, inst->header.acc_wr_control, &space);
if (inst->header.opcode == BRW_OPCODE_SEND)
err |= control (file, "end of thread", end_of_thread,
inst->bits3.generic.end_of_thread, &space);
diff --git a/src/mesa/drivers/dri/i965/brw_draw_upload.c b/src/mesa/drivers/dri/i965/brw_draw_upload.c
index f07aab86e9..249e874ab1 100644
--- a/src/mesa/drivers/dri/i965/brw_draw_upload.c
+++ b/src/mesa/drivers/dri/i965/brw_draw_upload.c
@@ -476,7 +476,7 @@ static void brw_emit_vertices(struct brw_context *brw)
if (brw->vb.nr_enabled == 0) {
BEGIN_BATCH(3);
OUT_BATCH((CMD_VERTEX_ELEMENT << 16) | 1);
- if (IS_GEN6(intel->intelScreen->deviceID)) {
+ if (intel->gen >= 6) {
OUT_BATCH((0 << GEN6_VE0_INDEX_SHIFT) |
GEN6_VE0_VALID |
(BRW_SURFACEFORMAT_R32G32B32A32_FLOAT << BRW_VE0_FORMAT_SHIFT) |
@@ -553,7 +553,7 @@ static void brw_emit_vertices(struct brw_context *brw)
break;
}
- if (IS_GEN6(intel->intelScreen->deviceID)) {
+ if (intel->gen >= 6) {
OUT_BATCH((i << GEN6_VE0_INDEX_SHIFT) |
GEN6_VE0_VALID |
(format << BRW_VE0_FORMAT_SHIFT) |
diff --git a/src/mesa/drivers/dri/i965/brw_eu.c b/src/mesa/drivers/dri/i965/brw_eu.c
index 4e7c1226ad..2ff39e8e64 100644
--- a/src/mesa/drivers/dri/i965/brw_eu.c
+++ b/src/mesa/drivers/dri/i965/brw_eu.c
@@ -85,6 +85,12 @@ void brw_set_saturate( struct brw_compile *p, GLuint value )
p->current->header.saturate = value;
}
+void brw_set_acc_write_control(struct brw_compile *p, GLuint value)
+{
+ if (p->brw->intel.gen >= 6)
+ p->current->header.acc_wr_control = value;
+}
+
void brw_push_insn_state( struct brw_compile *p )
{
assert(p->current != &p->stack[BRW_EU_MAX_INSN_STACK-1]);
diff --git a/src/mesa/drivers/dri/i965/brw_eu.h b/src/mesa/drivers/dri/i965/brw_eu.h
index ffdddd0a38..c63db16460 100644
--- a/src/mesa/drivers/dri/i965/brw_eu.h
+++ b/src/mesa/drivers/dri/i965/brw_eu.h
@@ -633,6 +633,8 @@ static INLINE struct brw_reg brw_swizzle( struct brw_reg reg,
GLuint z,
GLuint w)
{
+ assert(reg.file != BRW_IMMEDIATE_VALUE);
+
reg.dw1.bits.swizzle = BRW_SWIZZLE4(BRW_GET_SWZ(reg.dw1.bits.swizzle, x),
BRW_GET_SWZ(reg.dw1.bits.swizzle, y),
BRW_GET_SWZ(reg.dw1.bits.swizzle, z),
@@ -650,6 +652,7 @@ static INLINE struct brw_reg brw_swizzle1( struct brw_reg reg,
static INLINE struct brw_reg brw_writemask( struct brw_reg reg,
GLuint mask )
{
+ assert(reg.file != BRW_IMMEDIATE_VALUE);
reg.dw1.bits.writemask &= mask;
return reg;
}
@@ -657,6 +660,7 @@ static INLINE struct brw_reg brw_writemask( struct brw_reg reg,
static INLINE struct brw_reg brw_set_writemask( struct brw_reg reg,
GLuint mask )
{
+ assert(reg.file != BRW_IMMEDIATE_VALUE);
reg.dw1.bits.writemask = mask;
return reg;
}
@@ -766,6 +770,7 @@ void brw_set_compression_control( struct brw_compile *p, GLboolean control );
void brw_set_predicate_control_flag_value( struct brw_compile *p, GLuint value );
void brw_set_predicate_control( struct brw_compile *p, GLuint pc );
void brw_set_conditionalmod( struct brw_compile *p, GLuint conditional );
+void brw_set_acc_write_control(struct brw_compile *p, GLuint value);
void brw_init_compile( struct brw_context *, struct brw_compile *p );
const GLuint *brw_get_program( struct brw_compile *p, GLuint *sz );
@@ -840,6 +845,7 @@ void brw_ff_sync(struct brw_compile *p,
GLboolean eot);
void brw_fb_WRITE(struct brw_compile *p,
+ int dispatch_width,
struct brw_reg dest,
GLuint msg_reg_nr,
struct brw_reg src0,
@@ -925,8 +931,8 @@ struct brw_instruction *brw_DO(struct brw_compile *p,
struct brw_instruction *brw_WHILE(struct brw_compile *p,
struct brw_instruction *patch_insn);
-struct brw_instruction *brw_BREAK(struct brw_compile *p);
-struct brw_instruction *brw_CONT(struct brw_compile *p);
+struct brw_instruction *brw_BREAK(struct brw_compile *p, int pop_count);
+struct brw_instruction *brw_CONT(struct brw_compile *p, int pop_count);
/* Forward jumps:
*/
void brw_land_fwd_jump(struct brw_compile *p,
diff --git a/src/mesa/drivers/dri/i965/brw_eu_emit.c b/src/mesa/drivers/dri/i965/brw_eu_emit.c
index 0d5d17f501..0906150613 100644
--- a/src/mesa/drivers/dri/i965/brw_eu_emit.c
+++ b/src/mesa/drivers/dri/i965/brw_eu_emit.c
@@ -75,6 +75,8 @@ static void brw_set_dest( struct brw_instruction *insn,
else {
insn->bits1.da16.dest_subreg_nr = dest.subnr / 16;
insn->bits1.da16.dest_writemask = dest.dw1.bits.writemask;
+ /* even ignored in da16, still need to set as '01' */
+ insn->bits1.da16.dest_horiz_stride = 1;
}
}
else {
@@ -90,6 +92,8 @@ static void brw_set_dest( struct brw_instruction *insn,
}
else {
insn->bits1.ia16.dest_indirect_offset = dest.dw1.bits.indirect_offset;
+ /* even ignored in da16, still need to set as '01' */
+ insn->bits1.ia16.dest_horiz_stride = 1;
}
}
@@ -368,9 +372,23 @@ static void brw_set_dp_write_message( struct brw_context *brw,
GLuint send_commit_msg)
{
struct intel_context *intel = &brw->intel;
- brw_set_src1(insn, brw_imm_d(0));
+ brw_set_src1(insn, brw_imm_ud(0));
- if (intel->gen == 5) {
+ if (intel->gen >= 6) {
+ insn->bits3.dp_render_cache.binding_table_index = binding_table_index;
+ insn->bits3.dp_render_cache.msg_control = msg_control;
+ insn->bits3.dp_render_cache.pixel_scoreboard_clear = pixel_scoreboard_clear;
+ insn->bits3.dp_render_cache.msg_type = msg_type;
+ insn->bits3.dp_render_cache.send_commit_msg = send_commit_msg;
+ insn->bits3.dp_render_cache.header_present = 0; /* XXX */
+ insn->bits3.dp_render_cache.response_length = response_length;
+ insn->bits3.dp_render_cache.msg_length = msg_length;
+ insn->bits3.dp_render_cache.end_of_thread = end_of_thread;
+ insn->header.destreg__conditionalmod = BRW_MESSAGE_TARGET_DATAPORT_WRITE;
+ /* XXX really need below? */
+ insn->bits2.send_gen5.sfid = BRW_MESSAGE_TARGET_DATAPORT_WRITE;
+ insn->bits2.send_gen5.end_of_thread = end_of_thread;
+ } else if (intel->gen == 5) {
insn->bits3.dp_write_gen5.binding_table_index = binding_table_index;
insn->bits3.dp_write_gen5.msg_control = msg_control;
insn->bits3.dp_write_gen5.pixel_scoreboard_clear = pixel_scoreboard_clear;
@@ -759,7 +777,7 @@ void brw_ENDIF(struct brw_compile *p,
}
}
-struct brw_instruction *brw_BREAK(struct brw_compile *p)
+struct brw_instruction *brw_BREAK(struct brw_compile *p, int pop_count)
{
struct brw_instruction *insn;
insn = next_insn(p, BRW_OPCODE_BREAK);
@@ -770,10 +788,11 @@ struct brw_instruction *brw_BREAK(struct brw_compile *p)
insn->header.execution_size = BRW_EXECUTE_8;
/* insn->header.mask_control = BRW_MASK_DISABLE; */
insn->bits3.if_else.pad0 = 0;
+ insn->bits3.if_else.pop_count = pop_count;
return insn;
}
-struct brw_instruction *brw_CONT(struct brw_compile *p)
+struct brw_instruction *brw_CONT(struct brw_compile *p, int pop_count)
{
struct brw_instruction *insn;
insn = next_insn(p, BRW_OPCODE_CONTINUE);
@@ -784,6 +803,7 @@ struct brw_instruction *brw_CONT(struct brw_compile *p)
insn->header.execution_size = BRW_EXECUTE_8;
/* insn->header.mask_control = BRW_MASK_DISABLE; */
insn->bits3.if_else.pad0 = 0;
+ insn->bits3.if_else.pop_count = pop_count;
return insn;
}
@@ -1332,6 +1352,7 @@ void brw_dp_READ_4_vs_relative(struct brw_compile *p,
void brw_fb_WRITE(struct brw_compile *p,
+ int dispatch_width,
struct brw_reg dest,
GLuint msg_reg_nr,
struct brw_reg src0,
@@ -1340,22 +1361,40 @@ void brw_fb_WRITE(struct brw_compile *p,
GLuint response_length,
GLboolean eot)
{
- struct brw_instruction *insn = next_insn(p, BRW_OPCODE_SEND);
-
+ struct intel_context *intel = &p->brw->intel;
+ struct brw_instruction *insn;
+ GLuint msg_control, msg_type;
+
+ insn = next_insn(p, BRW_OPCODE_SEND);
insn->header.predicate_control = 0; /* XXX */
- insn->header.compression_control = BRW_COMPRESSION_NONE;
- insn->header.destreg__conditionalmod = msg_reg_nr;
-
+ insn->header.compression_control = BRW_COMPRESSION_NONE;
+
+ if (intel->gen >= 6) {
+ /* headerless version, just submit color payload */
+ src0 = brw_message_reg(msg_reg_nr);
+
+ msg_type = BRW_DATAPORT_WRITE_MESSAGE_RENDER_TARGET_WRITE_GEN6;
+ } else {
+ insn->header.destreg__conditionalmod = msg_reg_nr;
+
+ msg_type = BRW_DATAPORT_WRITE_MESSAGE_RENDER_TARGET_WRITE;
+ }
+
+ if (dispatch_width == 16)
+ msg_control = BRW_DATAPORT_RENDER_TARGET_WRITE_SIMD16_SINGLE_SOURCE;
+ else
+ msg_control = BRW_DATAPORT_RENDER_TARGET_WRITE_SIMD8_SINGLE_SOURCE_SUBSPAN01;
+
brw_set_dest(insn, dest);
brw_set_src0(insn, src0);
brw_set_dp_write_message(p->brw,
insn,
binding_table_index,
- BRW_DATAPORT_RENDER_TARGET_WRITE_SIMD16_SINGLE_SOURCE, /* msg_control */
- BRW_DATAPORT_WRITE_MESSAGE_RENDER_TARGET_WRITE, /* msg_type */
+ msg_control,
+ msg_type,
msg_length,
1, /* pixel scoreboard */
- response_length,
+ response_length,
eot,
0 /* send_commit_msg */);
}
diff --git a/src/mesa/drivers/dri/i965/brw_fs.cpp b/src/mesa/drivers/dri/i965/brw_fs.cpp
new file mode 100644
index 0000000000..34c5d5262f
--- /dev/null
+++ b/src/mesa/drivers/dri/i965/brw_fs.cpp
@@ -0,0 +1,1924 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ * Eric Anholt <eric@anholt.net>
+ *
+ */
+
+extern "C" {
+
+#include <sys/types.h>
+
+#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/hash_table.h"
+#include "brw_context.h"
+#include "brw_eu.h"
+#include "brw_wm.h"
+#include "talloc.h"
+}
+#include "../glsl/glsl_types.h"
+#include "../glsl/ir_optimization.h"
+#include "../glsl/ir_print_visitor.h"
+
+enum register_file {
+ ARF = BRW_ARCHITECTURE_REGISTER_FILE,
+ GRF = BRW_GENERAL_REGISTER_FILE,
+ MRF = BRW_MESSAGE_REGISTER_FILE,
+ IMM = BRW_IMMEDIATE_VALUE,
+ FIXED_HW_REG, /* a struct brw_reg */
+ UNIFORM, /* prog_data->params[hw_reg] */
+ BAD_FILE
+};
+
+enum fs_opcodes {
+ FS_OPCODE_FB_WRITE = 256,
+ FS_OPCODE_RCP,
+ FS_OPCODE_RSQ,
+ FS_OPCODE_SQRT,
+ FS_OPCODE_EXP2,
+ FS_OPCODE_LOG2,
+ FS_OPCODE_POW,
+ FS_OPCODE_SIN,
+ FS_OPCODE_COS,
+ 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;
+
+struct gl_shader *
+brw_new_shader(GLcontext *ctx, GLuint name, GLuint type)
+{
+ struct brw_shader *shader;
+
+ shader = talloc_zero(NULL, struct brw_shader);
+ if (shader) {
+ shader->base.Type = type;
+ shader->base.Name = name;
+ _mesa_init_shader(ctx, &shader->base);
+ }
+
+ return &shader->base;
+}
+
+struct gl_shader_program *
+brw_new_shader_program(GLcontext *ctx, GLuint name)
+{
+ struct brw_shader_program *prog;
+ prog = talloc_zero(NULL, struct brw_shader_program);
+ if (prog) {
+ prog->base.Name = name;
+ _mesa_init_shader_program(ctx, &prog->base);
+ }
+ return &prog->base;
+}
+
+GLboolean
+brw_compile_shader(GLcontext *ctx, struct gl_shader *shader)
+{
+ if (!_mesa_ir_compile_shader(ctx, shader))
+ return GL_FALSE;
+
+ return GL_TRUE;
+}
+
+GLboolean
+brw_link_shader(GLcontext *ctx, struct gl_shader_program *prog)
+{
+ if (using_new_fs == -1)
+ using_new_fs = getenv("INTEL_NEW_FS") != NULL;
+
+ for (unsigned i = 0; i < prog->_NumLinkedShaders; i++) {
+ struct brw_shader *shader = (struct brw_shader *)prog->_LinkedShaders[i];
+
+ if (using_new_fs && shader->base.Type == GL_FRAGMENT_SHADER) {
+ void *mem_ctx = talloc_new(NULL);
+ bool progress;
+
+ if (shader->ir)
+ talloc_free(shader->ir);
+ shader->ir = new(shader) exec_list;
+ 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;
+ } while (progress);
+
+ validate_ir_tree(shader->ir);
+
+ reparent_ir(shader->ir, shader->ir);
+ talloc_free(mem_ctx);
+ }
+ }
+
+ if (!_mesa_ir_link_shader(ctx, prog))
+ return GL_FALSE;
+
+ return GL_TRUE;
+}
+
+static int
+type_size(const struct glsl_type *type)
+{
+ unsigned int size, i;
+
+ switch (type->base_type) {
+ case GLSL_TYPE_UINT:
+ case GLSL_TYPE_INT:
+ case GLSL_TYPE_FLOAT:
+ case GLSL_TYPE_BOOL:
+ return type->components();
+ case GLSL_TYPE_ARRAY:
+ /* FINISHME: uniform/varying arrays. */
+ return type_size(type->fields.array) * type->length;
+ case GLSL_TYPE_STRUCT:
+ size = 0;
+ for (i = 0; i < type->length; i++) {
+ size += type_size(type->fields.structure[i].type);
+ }
+ return size;
+ case GLSL_TYPE_SAMPLER:
+ /* Samplers take up no register space, since they're baked in at
+ * link time.
+ */
+ return 0;
+ default:
+ assert(!"not reached");
+ return 0;
+ }
+}
+
+class fs_reg {
+public:
+ /* Callers of this talloc-based new need not call delete. It's
+ * easier to just talloc_free 'ctx' (or any of its ancestors). */
+ static void* operator new(size_t size, void *ctx)
+ {
+ void *node;
+
+ node = talloc_size(ctx, size);
+ assert(node != NULL);
+
+ return node;
+ }
+
+ /** Generic unset register constructor. */
+ fs_reg()
+ {
+ this->file = BAD_FILE;
+ this->reg = 0;
+ this->reg_offset = 0;
+ this->hw_reg = -1;
+ this->negate = 0;
+ this->abs = 0;
+ }
+
+ /** Immediate value constructor. */
+ fs_reg(float f)
+ {
+ 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)
+ {
+ 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)
+ {
+ 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)
+ {
+ 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);
+ fs_reg(class fs_visitor *v, const struct glsl_type *type);
+
+ /** Register file: ARF, GRF, MRF, IMM. */
+ enum register_file file;
+ /** Abstract register number. 0 = fixed hw reg */
+ int reg;
+ /** Offset within the abstract register. */
+ int reg_offset;
+ /** HW register number. Generally unset until register allocation. */
+ int hw_reg;
+ /** Register type. BRW_REGISTER_TYPE_* */
+ int type;
+ bool negate;
+ bool abs;
+ struct brw_reg fixed_hw_reg;
+
+ /** Value for file == BRW_IMMMEDIATE_FILE */
+ union {
+ int32_t i;
+ uint32_t u;
+ float f;
+ } imm;
+};
+
+static const fs_reg reg_undef;
+static const fs_reg reg_null(ARF, BRW_ARF_NULL);
+
+class fs_inst : public exec_node {
+public:
+ /* Callers of this talloc-based new need not call delete. It's
+ * easier to just talloc_free 'ctx' (or any of its ancestors). */
+ static void* operator new(size_t size, void *ctx)
+ {
+ void *node;
+
+ node = talloc_zero_size(ctx, size);
+ assert(node != NULL);
+
+ return node;
+ }
+
+ 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;
+ }
+
+ fs_inst(int opcode, fs_reg dst, fs_reg src0)
+ {
+ init();
+ this->opcode = opcode;
+ this->dst = dst;
+ this->src[0] = src0;
+ }
+
+ 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;
+ }
+
+ 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;
+ }
+
+ int opcode; /* BRW_OPCODE_* or FS_OPCODE_* */
+ fs_reg dst;
+ fs_reg src[3];
+ bool saturate;
+ 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.
+ */
+ ir_instruction *ir;
+ const char *annotation;
+ /** @} */
+};
+
+class fs_visitor : public ir_visitor
+{
+public:
+
+ fs_visitor(struct brw_wm_compile *c, struct brw_shader *shader)
+ {
+ this->c = c;
+ this->p = &c->func;
+ this->brw = p->brw;
+ this->intel = &brw->intel;
+ this->ctx = &intel->ctx;
+ this->mem_ctx = talloc_new(NULL);
+ this->shader = shader;
+ this->fail = false;
+ this->next_abstract_grf = 1;
+ this->variable_ht = hash_table_ctor(0,
+ hash_table_pointer_hash,
+ hash_table_pointer_compare);
+
+ this->frag_color = NULL;
+ this->frag_data = NULL;
+ this->frag_depth = NULL;
+ this->first_non_payload_grf = 0;
+
+ this->current_annotation = NULL;
+ this->annotation_string = NULL;
+ this->annotation_ir = NULL;
+ }
+ ~fs_visitor()
+ {
+ talloc_free(this->mem_ctx);
+ hash_table_dtor(this->variable_ht);
+ }
+
+ fs_reg *variable_storage(ir_variable *var);
+
+ void visit(ir_variable *ir);
+ void visit(ir_assignment *ir);
+ void visit(ir_dereference_variable *ir);
+ void visit(ir_dereference_record *ir);
+ void visit(ir_dereference_array *ir);
+ void visit(ir_expression *ir);
+ void visit(ir_texture *ir);
+ void visit(ir_if *ir);
+ void visit(ir_constant *ir);
+ void visit(ir_swizzle *ir);
+ void visit(ir_return *ir);
+ void visit(ir_loop *ir);
+ void visit(ir_loop_jump *ir);
+ void visit(ir_discard *ir);
+ void visit(ir_call *ir);
+ void visit(ir_function *ir);
+ void visit(ir_function_signature *ir);
+
+ fs_inst *emit(fs_inst inst);
+ void assign_curb_setup();
+ void assign_urb_setup();
+ void assign_regs();
+ void generate_code();
+ 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 emit_dummy_fs();
+ void emit_interpolation();
+ void emit_pinterp(int location);
+ void emit_fb_writes();
+
+ struct brw_reg interp_reg(int location, int channel);
+
+ struct brw_context *brw;
+ struct intel_context *intel;
+ GLcontext *ctx;
+ struct brw_wm_compile *c;
+ struct brw_compile *p;
+ struct brw_shader *shader;
+ void *mem_ctx;
+ exec_list instructions;
+ int next_abstract_grf;
+ struct hash_table *variable_ht;
+ ir_variable *frag_color, *frag_data, *frag_depth;
+ int first_non_payload_grf;
+
+ /** @{ debug annotation info */
+ const char *current_annotation;
+ ir_instruction *base_ir;
+ const char **annotation_string;
+ ir_instruction **annotation_ir;
+ /** @} */
+
+ bool fail;
+
+ /* Result of last visit() method. */
+ fs_reg result;
+
+ fs_reg pixel_x;
+ fs_reg pixel_y;
+ fs_reg pixel_w;
+ fs_reg delta_x;
+ fs_reg delta_y;
+ fs_reg interp_attrs[64];
+
+ int grf_used;
+
+};
+
+/** Fixed HW reg constructor. */
+fs_reg::fs_reg(enum register_file file, int hw_reg)
+{
+ 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)
+{
+ 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;
+ case GLSL_TYPE_INT:
+ case GLSL_TYPE_BOOL:
+ this->type = BRW_REGISTER_TYPE_D;
+ break;
+ case GLSL_TYPE_UINT:
+ this->type = BRW_REGISTER_TYPE_UD;
+ break;
+ default:
+ assert(!"not reached");
+ this->type = BRW_REGISTER_TYPE_F;
+ break;
+ }
+}
+
+fs_reg *
+fs_visitor::variable_storage(ir_variable *var)
+{
+ return (fs_reg *)hash_table_find(this->variable_ht, var);
+}
+
+void
+fs_visitor::visit(ir_variable *ir)
+{
+ fs_reg *reg = NULL;
+
+ 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 (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() ||
+ ir->type->is_sampler());
+
+ 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];
+ }
+
+ reg = new(this->mem_ctx) fs_reg(UNIFORM, param_index);
+ }
+
+ if (!reg)
+ reg = new(this->mem_ctx) fs_reg(this, ir->type);
+
+ hash_table_insert(this->variable_ht, reg, ir);
+}
+
+void
+fs_visitor::visit(ir_dereference_variable *ir)
+{
+ fs_reg *reg = variable_storage(ir->var);
+ this->result = *reg;
+}
+
+void
+fs_visitor::visit(ir_dereference_record *ir)
+{
+ assert(!"FINISHME");
+}
+
+void
+fs_visitor::visit(ir_dereference_array *ir)
+{
+ 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);
+ }
+
+ 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
+fs_visitor::visit(ir_expression *ir)
+{
+ unsigned int operand;
+ fs_reg op[2], temp;
+ fs_reg result;
+ fs_inst *inst;
+
+ for (operand = 0; operand < ir->get_num_operands(); operand++) {
+ ir->operands[operand]->accept(this);
+ if (this->result.file == BAD_FILE) {
+ ir_print_visitor v;
+ printf("Failed to get tree for expression operand:\n");
+ ir->operands[operand]->accept(&v);
+ this->fail = true;
+ }
+ op[operand] = this->result;
+
+ /* Matrix expression operands should have been broken down to vector
+ * operations already.
+ */
+ assert(!ir->operands[operand]->type->is_matrix());
+ /* And then those vector operands should have been broken down to scalar.
+ */
+ assert(!ir->operands[operand]->type->is_vector());
+ }
+
+ /* Storage for our result. If our result goes into an assignment, it will
+ * just get copy-propagated out, so no worries.
+ */
+ this->result = fs_reg(this, ir->type);
+
+ switch (ir->operation) {
+ case ir_unop_logic_not:
+ 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];
+ break;
+ case ir_unop_abs:
+ op[0].abs = true;
+ this->result = op[0];
+ break;
+ case ir_unop_sign:
+ temp = fs_reg(this, ir->type);
+
+ 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, reg_null, op[0], fs_reg(0.0f)));
+ inst->conditional_mod = BRW_CONDITIONAL_L;
+ inst = emit(fs_inst(BRW_OPCODE_MOV, this->result, fs_reg(-1.0f)));
+ inst->predicated = true;
+
+ break;
+ case ir_unop_rcp:
+ emit(fs_inst(FS_OPCODE_RCP, this->result, op[0]));
+ break;
+
+ case ir_unop_exp2:
+ emit(fs_inst(FS_OPCODE_EXP2, this->result, op[0]));
+ break;
+ case ir_unop_log2:
+ emit(fs_inst(FS_OPCODE_LOG2, this->result, op[0]));
+ break;
+ case ir_unop_exp:
+ case ir_unop_log:
+ assert(!"not reached: should be handled by ir_explog_to_explog2");
+ break;
+ case ir_unop_sin:
+ emit(fs_inst(FS_OPCODE_SIN, this->result, op[0]));
+ break;
+ case ir_unop_cos:
+ emit(fs_inst(FS_OPCODE_COS, this->result, op[0]));
+ break;
+
+ case ir_unop_dFdx:
+ emit(fs_inst(FS_OPCODE_DDX, this->result, op[0]));
+ break;
+ case ir_unop_dFdy:
+ emit(fs_inst(FS_OPCODE_DDY, this->result, op[0]));
+ break;
+
+ case ir_binop_add:
+ emit(fs_inst(BRW_OPCODE_ADD, this->result, op[0], op[1]));
+ break;
+ case ir_binop_sub:
+ assert(!"not reached: should be handled by ir_sub_to_add_neg");
+ break;
+
+ case ir_binop_mul:
+ emit(fs_inst(BRW_OPCODE_MUL, this->result, op[0], op[1]));
+ break;
+ case ir_binop_div:
+ assert(!"not reached: should be handled by ir_div_to_mul_rcp");
+ break;
+ case ir_binop_mod:
+ assert(!"ir_binop_mod should have been converted to b * fract(a/b)");
+ break;
+
+ 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:
+ 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:
+ 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:
+ emit(fs_inst(BRW_OPCODE_XOR, this->result, op[0], op[1]));
+ break;
+
+ case ir_binop_logic_or:
+ emit(fs_inst(BRW_OPCODE_OR, this->result, op[0], op[1]));
+ break;
+
+ case ir_binop_logic_and:
+ emit(fs_inst(BRW_OPCODE_AND, this->result, op[0], op[1]));
+ break;
+
+ case ir_binop_dot:
+ case ir_binop_cross:
+ case ir_unop_any:
+ assert(!"not reached: should be handled by brw_channel_expressions");
+ break;
+
+ case ir_unop_sqrt:
+ emit(fs_inst(FS_OPCODE_SQRT, this->result, op[0]));
+ break;
+
+ case ir_unop_rsq:
+ emit(fs_inst(FS_OPCODE_RSQ, this->result, op[0]));
+ break;
+
+ case ir_unop_i2f:
+ case ir_unop_b2f:
+ case ir_unop_b2i:
+ 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]));
+ break;
+ case ir_unop_f2b:
+ case ir_unop_i2b:
+ inst = emit(fs_inst(BRW_OPCODE_CMP, this->result, op[0], fs_reg(0.0f)));
+ inst->conditional_mod = BRW_CONDITIONAL_NZ;
+
+ case ir_unop_trunc:
+ emit(fs_inst(BRW_OPCODE_RNDD, this->result, op[0]));
+ break;
+ case ir_unop_ceil:
+ op[0].negate = ~op[0].negate;
+ inst = emit(fs_inst(BRW_OPCODE_RNDD, this->result, op[0]));
+ this->result.negate = true;
+ break;
+ case ir_unop_floor:
+ inst = emit(fs_inst(BRW_OPCODE_RNDD, this->result, op[0]));
+ break;
+ case ir_unop_fract:
+ inst = emit(fs_inst(BRW_OPCODE_FRC, this->result, op[0]));
+ break;
+
+ case ir_binop_min:
+ inst = emit(fs_inst(BRW_OPCODE_CMP, this->result, op[0], op[1]));
+ inst->conditional_mod = BRW_CONDITIONAL_L;
+
+ inst = emit(fs_inst(BRW_OPCODE_SEL, this->result, op[0], op[1]));
+ inst->predicated = true;
+ break;
+ case ir_binop_max:
+ inst = emit(fs_inst(BRW_OPCODE_CMP, this->result, op[0], op[1]));
+ inst->conditional_mod = BRW_CONDITIONAL_G;
+
+ inst = emit(fs_inst(BRW_OPCODE_SEL, this->result, op[0], op[1]));
+ inst->predicated = true;
+ break;
+
+ case ir_binop_pow:
+ inst = emit(fs_inst(FS_OPCODE_POW, this->result, op[0], op[1]));
+ break;
+
+ case ir_unop_bit_not:
+ case ir_unop_u2f:
+ case ir_binop_lshift:
+ case ir_binop_rshift:
+ case ir_binop_bit_and:
+ case ir_binop_bit_xor:
+ case ir_binop_bit_or:
+ assert(!"GLSL 1.30 features unsupported");
+ break;
+ }
+}
+
+void
+fs_visitor::visit(ir_assignment *ir)
+{
+ struct fs_reg l, r;
+ int i;
+ int write_mask;
+ fs_inst *inst;
+
+ /* FINISHME: arrays on the lhs */
+ ir->lhs->accept(this);
+ l = this->result;
+
+ ir->rhs->accept(this);
+ r = this->result;
+
+ /* FINISHME: This should really set to the correct maximal writemask for each
+ * FINISHME: component written (in the loops below). This case can only
+ * FINISHME: occur for matrices, arrays, and structures.
+ */
+ if (ir->write_mask == 0) {
+ assert(!ir->lhs->type->is_scalar() && !ir->lhs->type->is_vector());
+ write_mask = WRITEMASK_XYZW;
+ } else {
+ assert(ir->lhs->type->is_vector() || ir->lhs->type->is_scalar());
+ write_mask = ir->write_mask;
+ }
+
+ assert(l.file != BAD_FILE);
+ assert(r.file != BAD_FILE);
+
+ 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->conditional_mod = BRW_CONDITIONAL_NZ;
+ }
+
+ for (i = 0; i < type_size(ir->lhs->type); i++) {
+ if (i >= 4 || (write_mask & (1 << i))) {
+ inst = emit(fs_inst(BRW_OPCODE_MOV, l, r));
+ if (ir->condition)
+ inst->predicated = true;
+ }
+ l.reg_offset++;
+ r.reg_offset++;
+ }
+}
+
+void
+fs_visitor::visit(ir_texture *ir)
+{
+ 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;
+ }
+
+ this->result = dst;
+
+ if (ir->shadow_comparitor)
+ inst->shadow_compare = true;
+ inst->mlen = mlen;
+}
+
+void
+fs_visitor::visit(ir_swizzle *ir)
+{
+ ir->val->accept(this);
+ fs_reg val = this->result;
+
+ fs_reg result = fs_reg(this, ir->type);
+ this->result = result;
+
+ for (unsigned int i = 0; i < ir->type->vector_elements; i++) {
+ fs_reg channel = val;
+ int swiz = 0;
+
+ switch (i) {
+ case 0:
+ swiz = ir->mask.x;
+ break;
+ case 1:
+ swiz = ir->mask.y;
+ break;
+ case 2:
+ swiz = ir->mask.z;
+ break;
+ case 3:
+ swiz = ir->mask.w;
+ break;
+ }
+
+ channel.reg_offset += swiz;
+ emit(fs_inst(BRW_OPCODE_MOV, result, channel));
+ result.reg_offset++;
+ }
+}
+
+void
+fs_visitor::visit(ir_discard *ir)
+{
+ assert(ir->condition == NULL); /* FINISHME */
+
+ emit(fs_inst(FS_OPCODE_DISCARD));
+}
+
+void
+fs_visitor::visit(ir_constant *ir)
+{
+ fs_reg reg(this, ir->type);
+ this->result = reg;
+
+ for (unsigned int i = 0; i < ir->type->vector_elements; i++) {
+ switch (ir->type->base_type) {
+ case GLSL_TYPE_FLOAT:
+ emit(fs_inst(BRW_OPCODE_MOV, reg, fs_reg(ir->value.f[i])));
+ break;
+ case GLSL_TYPE_UINT:
+ emit(fs_inst(BRW_OPCODE_MOV, reg, fs_reg(ir->value.u[i])));
+ break;
+ case GLSL_TYPE_INT:
+ emit(fs_inst(BRW_OPCODE_MOV, reg, fs_reg(ir->value.i[i])));
+ break;
+ case GLSL_TYPE_BOOL:
+ emit(fs_inst(BRW_OPCODE_MOV, reg, fs_reg((int)ir->value.b[i])));
+ break;
+ default:
+ assert(!"Non-float/uint/int/bool constant");
+ }
+ reg.reg_offset++;
+ }
+}
+
+void
+fs_visitor::visit(ir_if *ir)
+{
+ 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(!ir->from);
+ assert(!ir->to);
+ assert(!ir->increment);
+ assert(!ir->counter);
+
+ emit(fs_inst(BRW_OPCODE_DO));
+
+ /* 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)));
+
+ 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;
+ }
+
+ emit(fs_inst(BRW_OPCODE_WHILE));
+}
+
+void
+fs_visitor::visit(ir_loop_jump *ir)
+{
+ 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
+fs_visitor::visit(ir_call *ir)
+{
+ assert(!"FINISHME");
+}
+
+void
+fs_visitor::visit(ir_return *ir)
+{
+ assert(!"FINISHME");
+}
+
+void
+fs_visitor::visit(ir_function *ir)
+{
+ /* Ignore function bodies other than main() -- we shouldn't see calls to
+ * them since they should all be inlined before we get to ir_to_mesa.
+ */
+ if (strcmp(ir->name, "main") == 0) {
+ const ir_function_signature *sig;
+ exec_list empty;
+
+ sig = ir->matching_signature(&empty);
+
+ assert(sig);
+
+ foreach_iter(exec_list_iterator, iter, sig->body) {
+ ir_instruction *ir = (ir_instruction *)iter.get();
+ this->base_ir = ir;
+
+ ir->accept(this);
+ }
+ }
+}
+
+void
+fs_visitor::visit(ir_function_signature *ir)
+{
+ assert(!"not reached");
+ (void)ir;
+}
+
+fs_inst *
+fs_visitor::emit(fs_inst inst)
+{
+ fs_inst *list_inst = new(mem_ctx) fs_inst;
+ *list_inst = inst;
+
+ list_inst->annotation = this->current_annotation;
+ list_inst->ir = this->base_ir;
+
+ this->instructions.push_tail(list_inst);
+
+ return list_inst;
+}
+
+/** Emits a dummy fragment shader consisting of magenta for bringup purposes. */
+void
+fs_visitor::emit_dummy_fs()
+{
+ /* Everyone's favorite color. */
+ emit(fs_inst(BRW_OPCODE_MOV,
+ fs_reg(MRF, 2),
+ fs_reg(1.0f)));
+ emit(fs_inst(BRW_OPCODE_MOV,
+ fs_reg(MRF, 3),
+ fs_reg(0.0f)));
+ emit(fs_inst(BRW_OPCODE_MOV,
+ fs_reg(MRF, 4),
+ fs_reg(1.0f)));
+ emit(fs_inst(BRW_OPCODE_MOV,
+ fs_reg(MRF, 5),
+ fs_reg(0.0f)));
+
+ fs_inst *write;
+ write = emit(fs_inst(FS_OPCODE_FB_WRITE,
+ fs_reg(0),
+ fs_reg(0)));
+}
+
+/* The register location here is relative to the start of the URB
+ * data. It will get adjusted to be a real location before
+ * generate_code() time.
+ */
+struct brw_reg
+fs_visitor::interp_reg(int location, int channel)
+{
+ int regnr = location * 2 + channel / 2;
+ int stride = (channel & 1) * 4;
+
+ return brw_vec1_grf(regnr, stride);
+}
+
+/** Emits the interpolation for the varying inputs. */
+void
+fs_visitor::emit_interpolation()
+{
+ struct brw_reg g1_uw = retype(brw_vec1_grf(1, 0), BRW_REGISTER_TYPE_UW);
+ /* For now, the source regs for the setup URB data will be unset,
+ * since we don't know until codegen how many push constants we'll
+ * use, and therefore what the setup URB offset is.
+ */
+ fs_reg src_reg = reg_undef;
+
+ 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);
+ emit(fs_inst(BRW_OPCODE_ADD,
+ this->pixel_x,
+ fs_reg(stride(suboffset(g1_uw, 4), 2, 4, 0)),
+ fs_reg(brw_imm_v(0x10101010))));
+ emit(fs_inst(BRW_OPCODE_ADD,
+ this->pixel_y,
+ fs_reg(stride(suboffset(g1_uw, 5), 2, 4, 0)),
+ fs_reg(brw_imm_v(0x11001100))));
+
+ this->current_annotation = "compute pixel deltas from v0";
+ this->delta_x = fs_reg(this, glsl_type::float_type);
+ this->delta_y = fs_reg(this, glsl_type::float_type);
+ emit(fs_inst(BRW_OPCODE_ADD,
+ this->delta_x,
+ this->pixel_x,
+ fs_reg(negate(brw_vec1_grf(1, 0)))));
+ emit(fs_inst(BRW_OPCODE_ADD,
+ this->delta_y,
+ this->pixel_y,
+ fs_reg(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
+ * to produce 1/w, and the varying variable wouldn't show up.
+ */
+ fs_reg wpos = fs_reg(this, glsl_type::vec4_type);
+ this->interp_attrs[FRAG_ATTRIB_WPOS] = wpos;
+ emit(fs_inst(BRW_OPCODE_MOV, wpos, this->pixel_x)); /* FINISHME: ARB_fcc */
+ wpos.reg_offset++;
+ emit(fs_inst(BRW_OPCODE_MOV, wpos, this->pixel_y)); /* FINISHME: ARB_fcc */
+ wpos.reg_offset++;
+ emit(fs_inst(FS_OPCODE_LINTERP, wpos, this->delta_x, this->delta_y,
+ interp_reg(FRAG_ATTRIB_WPOS, 2)));
+ wpos.reg_offset++;
+ emit(fs_inst(FS_OPCODE_LINTERP, wpos, this->delta_x, this->delta_y,
+ interp_reg(FRAG_ATTRIB_WPOS, 3)));
+ /* Compute the pixel W value from wpos.w. */
+ 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();
+
+ if (!var)
+ continue;
+
+ if (var->mode != ir_var_in)
+ continue;
+
+ /* If it's already set up (WPOS), skip. */
+ if (var->location == 0)
+ continue;
+
+ this->current_annotation = talloc_asprintf(this->mem_ctx,
+ "interpolate %s "
+ "(FRAG_ATTRIB[%d])",
+ var->name,
+ var->location);
+ emit_pinterp(var->location);
+ }
+ this->current_annotation = NULL;
+}
+
+void
+fs_visitor::emit_pinterp(int location)
+{
+ fs_reg interp_attr = fs_reg(this, glsl_type::vec4_type);
+ this->interp_attrs[location] = interp_attr;
+
+ for (unsigned int i = 0; i < 4; i++) {
+ struct brw_reg interp = interp_reg(location, i);
+ emit(fs_inst(FS_OPCODE_LINTERP,
+ interp_attr,
+ this->delta_x,
+ this->delta_y,
+ fs_reg(interp)));
+ interp_attr.reg_offset++;
+ }
+ interp_attr.reg_offset -= 4;
+
+ for (unsigned int i = 0; i < 4; i++) {
+ emit(fs_inst(BRW_OPCODE_MUL,
+ interp_attr,
+ interp_attr,
+ this->pixel_w));
+ interp_attr.reg_offset++;
+ }
+}
+
+void
+fs_visitor::emit_fb_writes()
+{
+ this->current_annotation = "FB write";
+
+ assert(this->frag_color || !"FINISHME: MRT");
+ fs_reg color = *(variable_storage(this->frag_color));
+
+ for (int i = 0; i < 4; i++) {
+ emit(fs_inst(BRW_OPCODE_MOV,
+ fs_reg(MRF, 2 + i),
+ color));
+ color.reg_offset++;
+ }
+
+ emit(fs_inst(FS_OPCODE_FB_WRITE,
+ fs_reg(0),
+ fs_reg(0)));
+
+ this->current_annotation = NULL;
+}
+
+void
+fs_visitor::generate_fb_write(fs_inst *inst)
+{
+ GLboolean eot = 1; /* FINISHME: MRT */
+ /* FINISHME: AADS */
+
+ /* Header is 2 regs, g0 and g1 are the contents. g0 will be implied
+ * move, here's g1.
+ */
+ brw_push_insn_state(p);
+ brw_set_mask_control(p, BRW_MASK_DISABLE);
+ brw_set_compression_control(p, BRW_COMPRESSION_NONE);
+ brw_MOV(p,
+ brw_message_reg(1),
+ 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,
+ 0,
+ eot);
+}
+
+void
+fs_visitor::generate_linterp(fs_inst *inst,
+ struct brw_reg dst, struct brw_reg *src)
+{
+ struct brw_reg delta_x = src[0];
+ struct brw_reg delta_y = src[1];
+ struct brw_reg interp = src[2];
+
+ if (brw->has_pln &&
+ delta_y.nr == delta_x.nr + 1 &&
+ (intel->gen >= 6 || (delta_x.nr & 1) == 0)) {
+ brw_PLN(p, dst, interp, delta_x);
+ } else {
+ brw_LINE(p, brw_null_reg(), interp, delta_x);
+ brw_MAC(p, dst, suboffset(interp, 1), delta_y);
+ }
+}
+
+void
+fs_visitor::generate_math(fs_inst *inst,
+ struct brw_reg dst, struct brw_reg *src)
+{
+ int op;
+
+ switch (inst->opcode) {
+ case FS_OPCODE_RCP:
+ op = BRW_MATH_FUNCTION_INV;
+ break;
+ case FS_OPCODE_RSQ:
+ op = BRW_MATH_FUNCTION_RSQ;
+ break;
+ case FS_OPCODE_SQRT:
+ op = BRW_MATH_FUNCTION_SQRT;
+ break;
+ case FS_OPCODE_EXP2:
+ op = BRW_MATH_FUNCTION_EXP;
+ break;
+ case FS_OPCODE_LOG2:
+ op = BRW_MATH_FUNCTION_LOG;
+ break;
+ case FS_OPCODE_POW:
+ op = BRW_MATH_FUNCTION_POW;
+ break;
+ case FS_OPCODE_SIN:
+ op = BRW_MATH_FUNCTION_SIN;
+ break;
+ case FS_OPCODE_COS:
+ op = BRW_MATH_FUNCTION_COS;
+ break;
+ default:
+ assert(!"not reached: unknown math function");
+ op = 0;
+ break;
+ }
+
+ if (inst->opcode == FS_OPCODE_POW) {
+ brw_MOV(p, brw_message_reg(3), src[1]);
+ }
+
+ brw_math(p, dst,
+ op,
+ inst->saturate ? BRW_MATH_SATURATE_SATURATE :
+ BRW_MATH_SATURATE_NONE,
+ 2, src[0],
+ BRW_MATH_DATA_VECTOR,
+ 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);
+}
+
+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)
+{
+ if (reg->file == GRF && reg->reg != 0) {
+ reg->hw_reg = header_size + reg->reg - 1 + reg->reg_offset;
+ reg->reg = 0;
+ }
+}
+
+void
+fs_visitor::assign_curb_setup()
+{
+ 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;
+
+ /* 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 = brw_vec1_grf(c->prog_data.first_curbe_grf +
+ constant_nr / 8,
+ constant_nr % 8);
+
+ inst->src[i].file = FIXED_HW_REG;
+ inst->src[i].fixed_hw_reg = brw_reg;
+ }
+ }
+ }
+}
+
+void
+fs_visitor::assign_urb_setup()
+{
+ int urb_start = c->prog_data.first_curbe_grf + c->prog_data.curb_read_length;
+ int interp_reg_nr[FRAG_ATTRIB_MAX];
+
+ c->prog_data.urb_read_length = 0;
+
+ /* Figure out where each of the incoming setup attributes lands. */
+ for (unsigned int i = 0; i < FRAG_ATTRIB_MAX; i++) {
+ interp_reg_nr[i] = -1;
+
+ if (i != FRAG_ATTRIB_WPOS &&
+ !(brw->fragment_program->Base.InputsRead & BITFIELD64_BIT(i)))
+ continue;
+
+ /* Each attribute is 4 setup channels, each of which is half a reg. */
+ interp_reg_nr[i] = urb_start + c->prog_data.urb_read_length;
+ c->prog_data.urb_read_length += 2;
+ }
+
+ /* Map the register numbers for FS_OPCODE_LINTERP so that it uses
+ * the correct setup input.
+ */
+ foreach_iter(exec_list_iterator, iter, this->instructions) {
+ fs_inst *inst = (fs_inst *)iter.get();
+
+ if (inst->opcode != FS_OPCODE_LINTERP)
+ continue;
+
+ assert(inst->src[2].file == FIXED_HW_REG);
+
+ int location = inst->src[2].fixed_hw_reg.nr / 2;
+ assert(interp_reg_nr[location] != -1);
+ inst->src[2].fixed_hw_reg.nr = (interp_reg_nr[location] +
+ (inst->src[2].fixed_hw_reg.nr & 1));
+ }
+
+ this->first_non_payload_grf = urb_start + c->prog_data.urb_read_length;
+}
+
+void
+fs_visitor::assign_regs()
+{
+ int header_size = this->first_non_payload_grf;
+ int last_grf = 0;
+
+ /* FINISHME: trivial assignment of register numbers */
+ foreach_iter(exec_list_iterator, iter, this->instructions) {
+ fs_inst *inst = (fs_inst *)iter.get();
+
+ trivial_assign_reg(header_size, &inst->dst);
+ trivial_assign_reg(header_size, &inst->src[0]);
+ trivial_assign_reg(header_size, &inst->src[1]);
+
+ last_grf = MAX2(last_grf, inst->dst.hw_reg);
+ last_grf = MAX2(last_grf, inst->src[0].hw_reg);
+ last_grf = MAX2(last_grf, inst->src[1].hw_reg);
+ }
+
+ this->grf_used = last_grf + 1;
+}
+
+static struct brw_reg brw_reg_from_fs_reg(fs_reg *reg)
+{
+ struct brw_reg brw_reg;
+
+ switch (reg->file) {
+ case GRF:
+ case ARF:
+ case MRF:
+ brw_reg = brw_vec8_reg(reg->file,
+ reg->hw_reg, 0);
+ brw_reg = retype(brw_reg, reg->type);
+ break;
+ case IMM:
+ switch (reg->type) {
+ case BRW_REGISTER_TYPE_F:
+ brw_reg = brw_imm_f(reg->imm.f);
+ break;
+ case BRW_REGISTER_TYPE_D:
+ brw_reg = brw_imm_d(reg->imm.i);
+ break;
+ case BRW_REGISTER_TYPE_UD:
+ brw_reg = brw_imm_ud(reg->imm.u);
+ break;
+ default:
+ assert(!"not reached");
+ break;
+ }
+ break;
+ case FIXED_HW_REG:
+ brw_reg = reg->fixed_hw_reg;
+ break;
+ case BAD_FILE:
+ /* Probably unused. */
+ brw_reg = brw_null_reg();
+ break;
+ case UNIFORM:
+ assert(!"not reached");
+ brw_reg = brw_null_reg();
+ break;
+ }
+ if (reg->abs)
+ brw_reg = brw_abs(brw_reg);
+ if (reg->negate)
+ brw_reg = negate(brw_reg);
+
+ return brw_reg;
+}
+
+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];
+
+ 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;
+
+ for (unsigned int i = 0; i < 3; i++) {
+ src[i] = brw_reg_from_fs_reg(&inst->src[i]);
+ }
+ dst = brw_reg_from_fs_reg(&inst->dst);
+
+ brw_set_conditionalmod(p, inst->conditional_mod);
+ brw_set_predicate_control(p, inst->predicated);
+
+ switch (inst->opcode) {
+ case BRW_OPCODE_MOV:
+ brw_MOV(p, dst, src[0]);
+ break;
+ case BRW_OPCODE_ADD:
+ brw_ADD(p, dst, src[0], src[1]);
+ break;
+ 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_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]);
+ 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_EXP2:
+ case FS_OPCODE_LOG2:
+ case FS_OPCODE_POW:
+ case FS_OPCODE_SIN:
+ case FS_OPCODE_COS:
+ generate_math(inst, dst, src);
+ break;
+ 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_FB_WRITE:
+ generate_fb_write(inst);
+ break;
+ default:
+ 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) {
+ 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);
+ }
+
+ 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;
+ GLcontext *ctx = &intel->ctx;
+ struct brw_shader *shader = NULL;
+ struct gl_shader_program *prog = ctx->Shader.CurrentProgram;
+
+ if (!prog)
+ return GL_FALSE;
+
+ if (!using_new_fs)
+ return GL_FALSE;
+
+ for (unsigned int i = 0; i < prog->_NumLinkedShaders; i++) {
+ if (prog->_LinkedShaders[i]->Type == GL_FRAGMENT_SHADER) {
+ shader = (struct brw_shader *)prog->_LinkedShaders[i];
+ break;
+ }
+ }
+ if (!shader)
+ return GL_FALSE;
+
+ /* We always use 8-wide mode, at least for now. For one, flow
+ * control only works in 8-wide. Also, when we're fragment shader
+ * bound, we're almost always under register pressure as well, so
+ * 8-wide would save us from the performance cliff of spilling
+ * regs.
+ */
+ c->dispatch_width = 8;
+
+ if (INTEL_DEBUG & DEBUG_WM) {
+ printf("GLSL IR for native fragment shader %d:\n", prog->Name);
+ _mesa_print_ir(shader->ir, NULL);
+ printf("\n");
+ }
+
+ /* Now the main event: Visit the shader IR and generate our FS IR for it.
+ */
+ fs_visitor v(c, shader);
+
+ if (0) {
+ v.emit_dummy_fs();
+ } else {
+ v.emit_interpolation();
+
+ /* Generate FS IR for main(). (the visitor only descends into
+ * functions called "main").
+ */
+ foreach_iter(exec_list_iterator, iter, *shader->ir) {
+ ir_instruction *ir = (ir_instruction *)iter.get();
+ v.base_ir = ir;
+ ir->accept(&v);
+ }
+
+ if (v.fail)
+ return GL_FALSE;
+
+ v.emit_fb_writes();
+ v.assign_curb_setup();
+ v.assign_urb_setup();
+ v.assign_regs();
+ }
+
+ v.generate_code();
+
+ 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);
+ }
+ 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;
+}
diff --git a/src/mesa/drivers/dri/i965/brw_fs_channel_expressions.cpp b/src/mesa/drivers/dri/i965/brw_fs_channel_expressions.cpp
new file mode 100644
index 0000000000..d8d58a9467
--- /dev/null
+++ b/src/mesa/drivers/dri/i965/brw_fs_channel_expressions.cpp
@@ -0,0 +1,365 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file brw_wm_channel_expressions.cpp
+ *
+ * Breaks vector operations down into operations on each component.
+ *
+ * The 965 fragment shader receives 8 or 16 pixels at a time, so each
+ * channel of a vector is laid out as 1 or 2 8-float registers. Each
+ * ALU operation operates on one of those channel registers. As a
+ * result, there is no value to the 965 fragment shader in tracking
+ * "vector" expressions in the sense of GLSL fragment shaders, when
+ * doing a channel at a time may help in constant folding, algebraic
+ * simplification, and reducing the liveness of channel registers.
+ *
+ * The exception to the desire to break everything down to floats is
+ * texturing. The texture sampler returns a writemasked masked
+ * 4/8-register sequence containing the texture values. We don't want
+ * to dispatch to the sampler separately for each channel we need, so
+ * we do retain the vector types in that case.
+ */
+
+extern "C" {
+#include "main/core.h"
+#include "brw_wm.h"
+}
+#include "../glsl/ir.h"
+#include "../glsl/ir_expression_flattening.h"
+#include "../glsl/glsl_types.h"
+
+class ir_channel_expressions_visitor : public ir_hierarchical_visitor {
+public:
+ ir_channel_expressions_visitor()
+ {
+ this->progress = false;
+ this->mem_ctx = NULL;
+ }
+
+ ir_visitor_status visit_leave(ir_assignment *);
+
+ ir_rvalue *get_element(ir_variable *var, unsigned int element);
+ void assign(ir_assignment *ir, int elem, ir_rvalue *val);
+
+ bool progress;
+ void *mem_ctx;
+};
+
+static bool
+channel_expressions_predicate(ir_instruction *ir)
+{
+ ir_expression *expr = ir->as_expression();
+ unsigned int i;
+
+ if (!expr)
+ return false;
+
+ for (i = 0; i < expr->get_num_operands(); i++) {
+ if (expr->operands[i]->type->is_vector())
+ return true;
+ }
+
+ return false;
+}
+
+extern "C" {
+GLboolean
+brw_do_channel_expressions(exec_list *instructions)
+{
+ ir_channel_expressions_visitor v;
+
+ /* Pull out any matrix expression to a separate assignment to a
+ * temp. This will make our handling of the breakdown to
+ * operations on the matrix's vector components much easier.
+ */
+ do_expression_flattening(instructions, channel_expressions_predicate);
+
+ visit_list_elements(&v, instructions);
+
+ return v.progress;
+}
+}
+
+ir_rvalue *
+ir_channel_expressions_visitor::get_element(ir_variable *var, unsigned int elem)
+{
+ ir_dereference *deref;
+
+ if (var->type->is_scalar())
+ return new(mem_ctx) ir_dereference_variable(var);
+
+ assert(elem < var->type->components());
+ deref = new(mem_ctx) ir_dereference_variable(var);
+ return new(mem_ctx) ir_swizzle(deref, elem, 0, 0, 0, 1);
+}
+
+void
+ir_channel_expressions_visitor::assign(ir_assignment *ir, int elem, ir_rvalue *val)
+{
+ ir_dereference *lhs = ir->lhs->clone(mem_ctx, NULL);
+ ir_assignment *assign;
+ ir_swizzle *val_swiz;
+
+ /* This assign-of-expression should have been generated by the
+ * expression flattening visitor (since we never short circit to
+ * not flatten, even for plain assignments of variables), so the
+ * writemask is always full.
+ */
+ assert(ir->write_mask == (1 << ir->lhs->type->components()) - 1);
+
+ /* Smear the float across all the channels for the masked write. */
+ val_swiz = new(mem_ctx) ir_swizzle(val, 0, 0, 0, 0,
+ ir->lhs->type->components());
+ assign = new(mem_ctx) ir_assignment(lhs, val_swiz, NULL, (1 << elem));
+ ir->insert_before(assign);
+}
+
+ir_visitor_status
+ir_channel_expressions_visitor::visit_leave(ir_assignment *ir)
+{
+ ir_expression *expr = ir->rhs->as_expression();
+ bool found_vector = false;
+ unsigned int i, vector_elements = 1;
+ ir_variable *op_var[2];
+
+ if (!expr)
+ return visit_continue;
+
+ if (!this->mem_ctx)
+ this->mem_ctx = talloc_parent(ir);
+
+ for (i = 0; i < expr->get_num_operands(); i++) {
+ if (expr->operands[i]->type->is_vector()) {
+ found_vector = true;
+ vector_elements = expr->operands[i]->type->vector_elements;
+ break;
+ }
+ }
+ if (!found_vector)
+ return visit_continue;
+
+ /* Store the expression operands in temps so we can use them
+ * multiple times.
+ */
+ for (i = 0; i < expr->get_num_operands(); i++) {
+ ir_assignment *assign;
+ ir_dereference *deref;
+
+ assert(!expr->operands[i]->type->is_matrix());
+
+ op_var[i] = new(mem_ctx) ir_variable(expr->operands[i]->type,
+ "channel_expressions",
+ ir_var_temporary);
+ ir->insert_before(op_var[i]);
+
+ deref = new(mem_ctx) ir_dereference_variable(op_var[i]);
+ assign = new(mem_ctx) ir_assignment(deref,
+ expr->operands[i],
+ NULL);
+ ir->insert_before(assign);
+ }
+
+ const glsl_type *element_type = glsl_type::get_instance(ir->lhs->type->base_type,
+ 1, 1);
+
+ /* OK, time to break down this vector operation. */
+ switch (expr->operation) {
+ case ir_unop_bit_not:
+ case ir_unop_logic_not:
+ case ir_unop_neg:
+ case ir_unop_abs:
+ case ir_unop_sign:
+ case ir_unop_rcp:
+ case ir_unop_rsq:
+ case ir_unop_sqrt:
+ case ir_unop_exp:
+ case ir_unop_log:
+ case ir_unop_exp2:
+ case ir_unop_log2:
+ case ir_unop_f2i:
+ case ir_unop_i2f:
+ case ir_unop_f2b:
+ case ir_unop_b2f:
+ case ir_unop_i2b:
+ case ir_unop_b2i:
+ case ir_unop_u2f:
+ case ir_unop_trunc:
+ case ir_unop_ceil:
+ case ir_unop_floor:
+ case ir_unop_fract:
+ case ir_unop_sin:
+ case ir_unop_cos:
+ case ir_unop_dFdx:
+ case ir_unop_dFdy:
+ for (i = 0; i < vector_elements; i++) {
+ ir_rvalue *op0 = get_element(op_var[0], i);
+
+ assign(ir, i, new(mem_ctx) ir_expression(expr->operation,
+ element_type,
+ op0,
+ NULL));
+ }
+ break;
+
+ case ir_binop_add:
+ case ir_binop_sub:
+ case ir_binop_mul:
+ case ir_binop_div:
+ case ir_binop_mod:
+ case ir_binop_min:
+ case ir_binop_max:
+ case ir_binop_pow:
+ case ir_binop_lshift:
+ case ir_binop_rshift:
+ case ir_binop_bit_and:
+ case ir_binop_bit_xor:
+ case ir_binop_bit_or:
+ for (i = 0; i < vector_elements; i++) {
+ ir_rvalue *op0 = get_element(op_var[0], i);
+ ir_rvalue *op1 = get_element(op_var[1], i);
+
+ assign(ir, i, new(mem_ctx) ir_expression(expr->operation,
+ element_type,
+ op0,
+ op1));
+ }
+ break;
+
+ case ir_unop_any: {
+ ir_expression *temp;
+ temp = new(mem_ctx) ir_expression(ir_binop_logic_or,
+ element_type,
+ get_element(op_var[0], 0),
+ get_element(op_var[0], 1));
+
+ for (i = 2; i < vector_elements; i++) {
+ temp = new(mem_ctx) ir_expression(ir_binop_logic_or,
+ element_type,
+ get_element(op_var[0], i),
+ temp);
+ }
+ assign(ir, 0, temp);
+ break;
+ }
+
+ case ir_binop_dot: {
+ ir_expression *last = NULL;
+ for (i = 0; i < vector_elements; i++) {
+ ir_rvalue *op0 = get_element(op_var[0], i);
+ ir_rvalue *op1 = get_element(op_var[1], i);
+ ir_expression *temp;
+
+ temp = new(mem_ctx) ir_expression(ir_binop_mul,
+ element_type,
+ op0,
+ op1);
+ if (last) {
+ last = new(mem_ctx) ir_expression(ir_binop_add,
+ element_type,
+ temp,
+ last);
+ } else {
+ last = temp;
+ }
+ }
+ assign(ir, 0, last);
+ break;
+ }
+
+ case ir_binop_cross: {
+ for (i = 0; i < vector_elements; i++) {
+ int swiz0 = (i + 1) % 3;
+ int swiz1 = (i + 2) % 3;
+ ir_expression *temp1, *temp2;
+
+ temp1 = new(mem_ctx) ir_expression(ir_binop_mul,
+ element_type,
+ get_element(op_var[0], swiz0),
+ get_element(op_var[1], swiz1));
+
+ temp2 = new(mem_ctx) ir_expression(ir_binop_mul,
+ element_type,
+ get_element(op_var[1], swiz0),
+ get_element(op_var[0], swiz1));
+
+ temp2 = new(mem_ctx) ir_expression(ir_unop_neg,
+ element_type,
+ temp2,
+ NULL);
+
+ assign(ir, i, new(mem_ctx) ir_expression(ir_binop_add,
+ element_type,
+ temp1, temp2));
+ }
+ break;
+ }
+
+ case ir_binop_less:
+ case ir_binop_greater:
+ case ir_binop_lequal:
+ case ir_binop_gequal:
+ case ir_binop_logic_and:
+ case ir_binop_logic_xor:
+ case ir_binop_logic_or:
+ ir->print();
+ printf("\n");
+ assert(!"not reached: expression operates on scalars only");
+ break;
+ case ir_binop_equal:
+ case ir_binop_nequal: {
+ ir_expression *last = NULL;
+ for (i = 0; i < vector_elements; i++) {
+ ir_rvalue *op0 = get_element(op_var[0], i);
+ ir_rvalue *op1 = get_element(op_var[1], i);
+ ir_expression *temp;
+ ir_expression_operation join;
+
+ if (expr->operation == ir_binop_equal)
+ join = ir_binop_logic_and;
+ else
+ join = ir_binop_logic_or;
+
+ temp = new(mem_ctx) ir_expression(expr->operation,
+ element_type,
+ op0,
+ op1);
+ if (last) {
+ last = new(mem_ctx) ir_expression(join,
+ element_type,
+ temp,
+ last);
+ } else {
+ last = temp;
+ }
+ }
+ assign(ir, 0, last);
+ break;
+ }
+ }
+
+ ir->remove();
+ this->progress = true;
+
+ return visit_continue;
+}
diff --git a/src/mesa/drivers/dri/i965/brw_fs_vector_splitting.cpp b/src/mesa/drivers/dri/i965/brw_fs_vector_splitting.cpp
new file mode 100644
index 0000000000..00d5c20248
--- /dev/null
+++ b/src/mesa/drivers/dri/i965/brw_fs_vector_splitting.cpp
@@ -0,0 +1,391 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file brw_wm_vector_splitting.cpp
+ *
+ * If a vector is only ever referenced by its components, then
+ * split those components out to individual variables so they can be
+ * handled normally by other optimization passes.
+ *
+ * This skips vectors in uniforms and varyings, which need to be
+ * accessible as vectors for their access by the GL. Also, vector
+ * results of non-variable-derefs in assignments aren't handled
+ * because to do so we would have to store the vector result to a
+ * temporary in order to unload each channel, and to do so would just
+ * loop us back to where we started. For the 965, this is exactly the
+ * behavior we want for the results of texture lookups, but probably not for
+ */
+
+extern "C" {
+#include "main/core.h"
+#include "intel_context.h"
+}
+#include "../glsl/ir.h"
+#include "../glsl/ir_visitor.h"
+#include "../glsl/ir_print_visitor.h"
+#include "../glsl/ir_rvalue_visitor.h"
+#include "../glsl/glsl_types.h"
+
+static bool debug = false;
+
+class variable_entry : public exec_node
+{
+public:
+ variable_entry(ir_variable *var)
+ {
+ this->var = var;
+ this->whole_vector_access = 0;
+ this->declaration = false;
+ this->mem_ctx = NULL;
+ }
+
+ ir_variable *var; /* The key: the variable's pointer. */
+
+ /** Number of times the variable is referenced, including assignments. */
+ unsigned whole_vector_access;
+
+ bool declaration; /* If the variable had a decl in the instruction stream */
+
+ ir_variable *components[4];
+
+ /** talloc_parent(this->var) -- the shader's talloc context. */
+ void *mem_ctx;
+};
+
+class ir_vector_reference_visitor : public ir_hierarchical_visitor {
+public:
+ ir_vector_reference_visitor(void)
+ {
+ this->mem_ctx = talloc_new(NULL);
+ this->variable_list.make_empty();
+ }
+
+ ~ir_vector_reference_visitor(void)
+ {
+ talloc_free(mem_ctx);
+ }
+
+ virtual ir_visitor_status visit(ir_variable *);
+ virtual ir_visitor_status visit(ir_dereference_variable *);
+ virtual ir_visitor_status visit_enter(ir_swizzle *);
+ virtual ir_visitor_status visit_enter(ir_assignment *);
+ virtual ir_visitor_status visit_enter(ir_function_signature *);
+
+ variable_entry *get_variable_entry(ir_variable *var);
+
+ /* List of variable_entry */
+ exec_list variable_list;
+
+ void *mem_ctx;
+};
+
+variable_entry *
+ir_vector_reference_visitor::get_variable_entry(ir_variable *var)
+{
+ assert(var);
+
+ if (!var->type->is_vector())
+ return NULL;
+
+ switch (var->mode) {
+ case ir_var_uniform:
+ case ir_var_in:
+ case ir_var_out:
+ case ir_var_inout:
+ /* Can't split varyings or uniforms. Function in/outs won't get split
+ * either, so don't care about the ambiguity.
+ */
+ return NULL;
+ case ir_var_auto:
+ case ir_var_temporary:
+ break;
+ }
+
+ foreach_iter(exec_list_iterator, iter, this->variable_list) {
+ variable_entry *entry = (variable_entry *)iter.get();
+ if (entry->var == var)
+ return entry;
+ }
+
+ variable_entry *entry = new(mem_ctx) variable_entry(var);
+ this->variable_list.push_tail(entry);
+ return entry;
+}
+
+
+ir_visitor_status
+ir_vector_reference_visitor::visit(ir_variable *ir)
+{
+ variable_entry *entry = this->get_variable_entry(ir);
+
+ if (entry)
+ entry->declaration = true;
+
+ return visit_continue;
+}
+
+ir_visitor_status
+ir_vector_reference_visitor::visit(ir_dereference_variable *ir)
+{
+ ir_variable *const var = ir->var;
+ variable_entry *entry = this->get_variable_entry(var);
+
+ if (entry)
+ entry->whole_vector_access++;
+
+ return visit_continue;
+}
+
+ir_visitor_status
+ir_vector_reference_visitor::visit_enter(ir_swizzle *ir)
+{
+ /* Don't descend into a vector ir_dereference_variable below. */
+ if (ir->val->as_dereference_variable() && ir->type->is_scalar())
+ return visit_continue_with_parent;
+
+ return visit_continue;
+}
+
+ir_visitor_status
+ir_vector_reference_visitor::visit_enter(ir_assignment *ir)
+{
+ if (ir->lhs->as_dereference_variable() &&
+ ir->rhs->as_dereference_variable() &&
+ !ir->condition) {
+ /* We'll split copies of a vector to copies of channels, so don't
+ * descend to the ir_dereference_variables.
+ */
+ return visit_continue_with_parent;
+ }
+ if (ir->lhs->as_dereference_variable() &&
+ is_power_of_two(ir->write_mask) &&
+ !ir->condition) {
+ /* If we're writing just a channel, then channel-splitting the LHS is OK.
+ */
+ ir->rhs->accept(this);
+ return visit_continue_with_parent;
+ }
+ return visit_continue;
+}
+
+ir_visitor_status
+ir_vector_reference_visitor::visit_enter(ir_function_signature *ir)
+{
+ /* We don't want to descend into the function parameters and
+ * split them, so just accept the body here.
+ */
+ visit_list_elements(this, &ir->body);
+ return visit_continue_with_parent;
+}
+
+class ir_vector_splitting_visitor : public ir_rvalue_visitor {
+public:
+ ir_vector_splitting_visitor(exec_list *vars)
+ {
+ this->variable_list = vars;
+ }
+
+ virtual ir_visitor_status visit_leave(ir_assignment *);
+
+ void handle_rvalue(ir_rvalue **rvalue);
+ struct variable_entry *get_splitting_entry(ir_variable *var);
+
+ exec_list *variable_list;
+ void *mem_ctx;
+};
+
+struct variable_entry *
+ir_vector_splitting_visitor::get_splitting_entry(ir_variable *var)
+{
+ assert(var);
+
+ if (!var->type->is_vector())
+ return NULL;
+
+ foreach_iter(exec_list_iterator, iter, *this->variable_list) {
+ variable_entry *entry = (variable_entry *)iter.get();
+ if (entry->var == var) {
+ return entry;
+ }
+ }
+
+ return NULL;
+}
+
+void
+ir_vector_splitting_visitor::handle_rvalue(ir_rvalue **rvalue)
+{
+ if (!*rvalue)
+ return;
+
+ ir_swizzle *swiz = (*rvalue)->as_swizzle();
+ if (!swiz || !swiz->type->is_scalar())
+ return;
+
+ ir_dereference_variable *deref_var = swiz->val->as_dereference_variable();
+ if (!deref_var)
+ return;
+
+ variable_entry *entry = get_splitting_entry(deref_var->var);
+ if (!entry)
+ return;
+
+ ir_variable *var = entry->components[swiz->mask.x];
+ *rvalue = new(entry->mem_ctx) ir_dereference_variable(var);
+}
+
+ir_visitor_status
+ir_vector_splitting_visitor::visit_leave(ir_assignment *ir)
+{
+ ir_dereference_variable *lhs_deref = ir->lhs->as_dereference_variable();
+ ir_dereference_variable *rhs_deref = ir->rhs->as_dereference_variable();
+ variable_entry *lhs = lhs_deref ? get_splitting_entry(lhs_deref->var) : NULL;
+ variable_entry *rhs = rhs_deref ? get_splitting_entry(rhs_deref->var) : NULL;
+
+ if (lhs_deref && rhs_deref && (lhs || rhs) && !ir->condition) {
+ /* Straight assignment of vector variables. */
+ for (unsigned int i = 0; i < ir->rhs->type->vector_elements; i++) {
+ ir_dereference *new_lhs;
+ ir_rvalue *new_rhs;
+ void *mem_ctx = lhs ? lhs->mem_ctx : rhs->mem_ctx;
+ unsigned int writemask;
+
+ if (lhs) {
+ new_lhs = new(mem_ctx) ir_dereference_variable(lhs->components[i]);
+ writemask = (ir->write_mask >> i) & 1;
+ } else {
+ new_lhs = ir->lhs->clone(mem_ctx, NULL);
+ writemask = ir->write_mask & (1 << i);
+ }
+
+ if (rhs) {
+ new_rhs = new(mem_ctx) ir_dereference_variable(rhs->components[i]);
+ /* If we're writing into a writemask, smear it out to that channel. */
+ if (!lhs)
+ new_rhs = new(mem_ctx) ir_swizzle(new_rhs, i, i, i, i, i + 1);
+ } else {
+ new_rhs = new(mem_ctx) ir_swizzle(ir->rhs->clone(mem_ctx, NULL),
+ i, i, i, i, 1);
+ }
+
+ ir->insert_before(new(mem_ctx) ir_assignment(new_lhs,
+ new_rhs,
+ NULL, writemask));
+ }
+ ir->remove();
+ } else if (lhs) {
+ int elem = -1;
+
+ switch (ir->write_mask) {
+ case (1 << 0):
+ elem = 0;
+ break;
+ case (1 << 1):
+ elem = 1;
+ break;
+ case (1 << 2):
+ elem = 2;
+ break;
+ case (1 << 3):
+ elem = 3;
+ break;
+ default:
+ ir->print();
+ assert(!"not reached: non-channelwise dereference of LHS.");
+ }
+
+ ir->lhs = new(mem_ctx) ir_dereference_variable(lhs->components[elem]);
+ ir->write_mask = (1 << 0);
+
+ handle_rvalue(&ir->rhs);
+ ir->rhs = new(mem_ctx) ir_swizzle(ir->rhs,
+ elem, elem, elem, elem, 1);
+ } else {
+ handle_rvalue(&ir->rhs);
+ }
+
+ handle_rvalue(&ir->condition);
+
+ return visit_continue;
+}
+
+extern "C" {
+bool
+brw_do_vector_splitting(exec_list *instructions)
+{
+ ir_vector_reference_visitor refs;
+
+ visit_list_elements(&refs, instructions);
+
+ /* Trim out variables we can't split. */
+ foreach_iter(exec_list_iterator, iter, refs.variable_list) {
+ variable_entry *entry = (variable_entry *)iter.get();
+
+ if (debug) {
+ printf("vector %s@%p: decl %d, whole_access %d\n",
+ entry->var->name, (void *) entry->var, entry->declaration,
+ entry->whole_vector_access);
+ }
+
+ if (!entry->declaration || entry->whole_vector_access) {
+ entry->remove();
+ }
+ }
+
+ if (refs.variable_list.is_empty())
+ return false;
+
+ void *mem_ctx = talloc_new(NULL);
+
+ /* Replace the decls of the vectors to be split with their split
+ * components.
+ */
+ foreach_iter(exec_list_iterator, iter, refs.variable_list) {
+ variable_entry *entry = (variable_entry *)iter.get();
+ const struct glsl_type *type;
+ type = glsl_type::get_instance(entry->var->type->base_type, 1, 1);
+
+ entry->mem_ctx = talloc_parent(entry->var);
+
+ for (unsigned int i = 0; i < entry->var->type->vector_elements; i++) {
+ const char *name = talloc_asprintf(mem_ctx, "%s_%c",
+ entry->var->name,
+ "xyzw"[i]);
+
+ entry->components[i] = new(entry->mem_ctx) ir_variable(type, name,
+ ir_var_temporary);
+ entry->var->insert_before(entry->components[i]);
+ }
+
+ entry->var->remove();
+ }
+
+ ir_vector_splitting_visitor split(&refs.variable_list);
+ visit_list_elements(&split, instructions);
+
+ talloc_free(mem_ctx);
+
+ return true;
+}
+}
diff --git a/src/mesa/drivers/dri/i965/brw_misc_state.c b/src/mesa/drivers/dri/i965/brw_misc_state.c
index 572175f463..6eeaba7772 100644
--- a/src/mesa/drivers/dri/i965/brw_misc_state.c
+++ b/src/mesa/drivers/dri/i965/brw_misc_state.c
@@ -281,7 +281,7 @@ static void emit_depthbuffer(struct brw_context *brw)
}
assert(region->tiling != I915_TILING_X);
- if (IS_GEN6(intel->intelScreen->deviceID))
+ if (intel->gen >= 6)
assert(region->tiling != I915_TILING_NONE);
BEGIN_BATCH(len);
@@ -295,7 +295,7 @@ static void emit_depthbuffer(struct brw_context *brw)
I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER,
0);
OUT_BATCH((BRW_SURFACE_MIPMAPLAYOUT_BELOW << 1) |
- ((region->pitch - 1) << 6) |
+ ((region->width - 1) << 6) |
((region->height - 1) << 19));
OUT_BATCH(0);
diff --git a/src/mesa/drivers/dri/i965/brw_optimize.c b/src/mesa/drivers/dri/i965/brw_optimize.c
index 8aa6fb6cc6..cbed2bd5cb 100644
--- a/src/mesa/drivers/dri/i965/brw_optimize.c
+++ b/src/mesa/drivers/dri/i965/brw_optimize.c
@@ -32,12 +32,7 @@
#include "brw_defines.h"
#include "brw_eu.h"
-static const struct {
- char *name;
- int nsrc;
- int ndst;
- GLboolean is_arith;
-} inst_opcode[128] = {
+const struct brw_instruction_info brw_opcodes[128] = {
[BRW_OPCODE_MOV] = { .name = "mov", .nsrc = 1, .ndst = 1, .is_arith = 1 },
[BRW_OPCODE_FRC] = { .name = "frc", .nsrc = 1, .ndst = 1, .is_arith = 1 },
[BRW_OPCODE_RNDU] = { .name = "rndu", .nsrc = 1, .ndst = 1, .is_arith = 1 },
@@ -94,7 +89,7 @@ static const struct {
static INLINE
GLboolean brw_is_arithmetic_inst(const struct brw_instruction *inst)
{
- return inst_opcode[inst->header.opcode].is_arith;
+ return brw_opcodes[inst->header.opcode].is_arith;
}
static const GLuint inst_stride[7] = {
@@ -122,7 +117,7 @@ brw_is_grf_written(const struct brw_instruction *inst,
int reg_index, int size,
int gen)
{
- if (inst_opcode[inst->header.opcode].ndst == 0)
+ if (brw_opcodes[inst->header.opcode].ndst == 0)
return GL_FALSE;
if (inst->bits1.da1.dest_address_mode != BRW_ADDRESS_DIRECT)
@@ -161,20 +156,19 @@ brw_is_grf_written(const struct brw_instruction *inst,
return left < right;
}
-/* Specific path for message register since we need to handle the compr4 case */
-static INLINE GLboolean
-brw_is_mrf_written(const struct brw_instruction *inst, int reg_index, int size)
+static GLboolean
+brw_is_mrf_written_alu(const struct brw_instruction *inst,
+ int reg_index, int size)
{
- if (inst_opcode[inst->header.opcode].ndst == 0)
+ if (brw_opcodes[inst->header.opcode].ndst == 0)
return GL_FALSE;
- if (inst->bits1.da1.dest_address_mode != BRW_ADDRESS_DIRECT)
- if (inst->bits1.ia1.dest_reg_file == BRW_MESSAGE_REGISTER_FILE)
- return GL_TRUE;
-
if (inst->bits1.da1.dest_reg_file != BRW_MESSAGE_REGISTER_FILE)
return GL_FALSE;
+ if (inst->bits1.da1.dest_address_mode != BRW_ADDRESS_DIRECT)
+ return GL_TRUE;
+
const int reg_start = reg_index * REG_SIZE;
const int reg_end = reg_start + size;
@@ -188,8 +182,6 @@ brw_is_mrf_written(const struct brw_instruction *inst, int reg_index, int size)
if (is_compr4 && inst->header.execution_size != BRW_EXECUTE_16)
return GL_TRUE;
- GLboolean is_written = GL_FALSE;
-
/* Here we write mrf_{i} and mrf_{i+4}. So we read two times 8 elements */
if (is_compr4) {
const int length = 8 * type_size * inst->bits1.da1.dest_horiz_stride;
@@ -210,7 +202,8 @@ brw_is_mrf_written(const struct brw_instruction *inst, int reg_index, int size)
const int left1 = MAX2(write_start1, reg_start);
const int right1 = MIN2(write_end1, reg_end);
- is_written = left0 < right0 || left1 < right1;
+ if (left0 < right0 || left1 < right1)
+ return GL_TRUE;
}
else {
int length;
@@ -223,25 +216,41 @@ brw_is_mrf_written(const struct brw_instruction *inst, int reg_index, int size)
+ inst->bits1.da1.dest_subreg_nr;
const int write_end = write_start + length;
const int left = MAX2(write_start, reg_start);
- const int right = MIN2(write_end, reg_end);;
+ const int right = MIN2(write_end, reg_end);
- is_written = left < right;
+ if (left < right)
+ return GL_TRUE;
}
- /* SEND may perform an implicit mov to a mrf register */
- if (is_written == GL_FALSE &&
- inst->header.opcode == BRW_OPCODE_SEND &&
- inst->bits1.da1.src0_reg_file != 0) {
+ return GL_FALSE;
+}
- const int mrf_start = inst->header.destreg__conditionalmod;
- const int write_start = mrf_start * REG_SIZE;
- const int write_end = write_start + REG_SIZE;
- const int left = MAX2(write_start, reg_start);
- const int right = MIN2(write_end, reg_end);;
- is_written = left < right;
- }
+/* SEND may perform an implicit mov to a mrf register */
+static GLboolean brw_is_mrf_written_send(const struct brw_instruction *inst,
+ int reg_index, int size)
+{
+
+ const int reg_start = reg_index * REG_SIZE;
+ const int reg_end = reg_start + size;
+ const int mrf_start = inst->header.destreg__conditionalmod;
+ const int write_start = mrf_start * REG_SIZE;
+ const int write_end = write_start + REG_SIZE;
+ const int left = MAX2(write_start, reg_start);
+ const int right = MIN2(write_end, reg_end);
+
+ if (inst->header.opcode != BRW_OPCODE_SEND ||
+ inst->bits1.da1.src0_reg_file == 0)
+ return GL_FALSE;
- return is_written;
+ return left < right;
+}
+
+/* Specific path for message register since we need to handle the compr4 case */
+static INLINE GLboolean
+brw_is_mrf_written(const struct brw_instruction *inst, int reg_index, int size)
+{
+ return (brw_is_mrf_written_alu(inst, reg_index, size) ||
+ brw_is_mrf_written_send(inst, reg_index, size));
}
static INLINE GLboolean
@@ -284,7 +293,7 @@ static INLINE GLboolean
brw_is_grf_read(const struct brw_instruction *inst, int reg_index, int size)
{
int i, j;
- if (inst_opcode[inst->header.opcode].nsrc == 0)
+ if (brw_opcodes[inst->header.opcode].nsrc == 0)
return GL_FALSE;
/* Look at first source. We must take into account register regions to
@@ -292,7 +301,7 @@ brw_is_grf_read(const struct brw_instruction *inst, int reg_index, int size)
* since we do not take into account the fact that some complete registers
* may be skipped
*/
- if (inst_opcode[inst->header.opcode].nsrc >= 1) {
+ if (brw_opcodes[inst->header.opcode].nsrc >= 1) {
if (inst->bits2.da1.src0_address_mode != BRW_ADDRESS_DIRECT)
if (inst->bits1.ia1.src0_reg_file == BRW_GENERAL_REGISTER_FILE)
@@ -327,7 +336,7 @@ brw_is_grf_read(const struct brw_instruction *inst, int reg_index, int size)
}
/* Second src register */
- if (inst_opcode[inst->header.opcode].nsrc >= 2) {
+ if (brw_opcodes[inst->header.opcode].nsrc >= 2) {
if (inst->bits3.da1.src1_address_mode != BRW_ADDRESS_DIRECT)
if (inst->bits1.ia1.src1_reg_file == BRW_GENERAL_REGISTER_FILE)
diff --git a/src/mesa/drivers/dri/i965/brw_program.c b/src/mesa/drivers/dri/i965/brw_program.c
index 4b08d2599b..bc152204a4 100644
--- a/src/mesa/drivers/dri/i965/brw_program.c
+++ b/src/mesa/drivers/dri/i965/brw_program.c
@@ -36,6 +36,7 @@
#include "program/program.h"
#include "program/programopt.h"
#include "tnl/tnl.h"
+#include "talloc.h"
#include "brw_context.h"
#include "brw_wm.h"
@@ -114,10 +115,7 @@ shader_error(GLcontext *ctx, struct gl_program *prog, const char *msg)
shader = _mesa_lookup_shader_program(ctx, prog->Id);
if (shader) {
- if (shader->InfoLog) {
- free(shader->InfoLog);
- }
- shader->InfoLog = _mesa_strdup(msg);
+ shader->InfoLog = talloc_strdup_append(shader->InfoLog, msg);
shader->LinkStatus = GL_FALSE;
}
}
@@ -170,6 +168,9 @@ static GLboolean brwProgramStringNotify( GLcontext *ctx,
* See piglit glsl-{vs,fs}-functions-[23] tests.
*/
for (i = 0; i < prog->NumInstructions; i++) {
+ struct prog_instruction *inst = prog->Instructions + i;
+ int r;
+
if (prog->Instructions[i].Opcode == OPCODE_CAL) {
shader_error(ctx, prog,
"i965 driver doesn't yet support uninlined function "
@@ -177,16 +178,28 @@ static GLboolean brwProgramStringNotify( GLcontext *ctx,
"the end of the function to work around it.\n");
return GL_FALSE;
}
- if (prog->Instructions[i].DstReg.RelAddr &&
- prog->Instructions[i].DstReg.File == PROGRAM_INPUT) {
+
+ if (prog->Instructions[i].Opcode == OPCODE_RET) {
shader_error(ctx, prog,
- "Variable indexing of shader inputs unsupported\n");
+ "i965 driver doesn't yet support \"return\" "
+ "from main().\n");
return GL_FALSE;
}
- if (prog->Instructions[i].DstReg.RelAddr &&
+
+ for (r = 0; r < _mesa_num_inst_src_regs(inst->Opcode); r++) {
+ if (prog->Instructions[i].SrcReg[r].RelAddr &&
+ prog->Instructions[i].SrcReg[r].File == PROGRAM_INPUT) {
+ shader_error(ctx, prog,
+ "Variable indexing of shader inputs unsupported\n");
+ return GL_FALSE;
+ }
+ }
+
+ if (target == GL_FRAGMENT_PROGRAM_ARB &&
+ prog->Instructions[i].DstReg.RelAddr &&
prog->Instructions[i].DstReg.File == PROGRAM_OUTPUT) {
shader_error(ctx, prog,
- "Variable indexing of shader outputs unsupported\n");
+ "Variable indexing of FS outputs unsupported\n");
return GL_FALSE;
}
if (target == GL_FRAGMENT_PROGRAM_ARB) {
@@ -218,5 +231,10 @@ void brwInitFragProgFuncs( struct dd_function_table *functions )
functions->DeleteProgram = brwDeleteProgram;
functions->IsProgramNative = brwIsProgramNative;
functions->ProgramStringNotify = brwProgramStringNotify;
+
+ functions->NewShader = brw_new_shader;
+ functions->NewShaderProgram = brw_new_shader_program;
+ functions->CompileShader = brw_compile_shader;
+ functions->LinkShader = brw_link_shader;
}
diff --git a/src/mesa/drivers/dri/i965/brw_state.h b/src/mesa/drivers/dri/i965/brw_state.h
index af08446f2d..c5d296b129 100644
--- a/src/mesa/drivers/dri/i965/brw_state.h
+++ b/src/mesa/drivers/dri/i965/brw_state.h
@@ -107,6 +107,7 @@ extern const struct brw_tracked_state gen6_sf_vp;
extern const struct brw_tracked_state gen6_urb;
extern const struct brw_tracked_state gen6_viewport_state;
extern const struct brw_tracked_state gen6_vs_state;
+extern const struct brw_tracked_state gen6_wm_constants;
extern const struct brw_tracked_state gen6_wm_state;
/***********************************************************************
diff --git a/src/mesa/drivers/dri/i965/brw_state_upload.c b/src/mesa/drivers/dri/i965/brw_state_upload.c
index f92a19c2aa..a0c130557e 100644
--- a/src/mesa/drivers/dri/i965/brw_state_upload.c
+++ b/src/mesa/drivers/dri/i965/brw_state_upload.c
@@ -35,7 +35,6 @@
#include "brw_state.h"
#include "intel_batchbuffer.h"
#include "intel_buffers.h"
-#include "intel_chipset.h"
/* This is used to initialize brw->state.atoms[]. We could use this
* list directly except for a single atom, brw_constant_buffer, which
@@ -129,7 +128,7 @@ const struct brw_tracked_state *gen6_atoms[] =
&gen6_cc_state_pointers,
&brw_vs_constants, /* Before vs_surfaces and constant_buffer */
- &brw_wm_constants, /* Before wm_surfaces and constant_buffer */
+ &gen6_wm_constants, /* Before wm_surfaces and constant_buffer */
&brw_vs_surfaces, /* must do before unit */
&brw_wm_constant_surface, /* must do before wm surfaces/bind bo */
@@ -351,7 +350,7 @@ void brw_validate_state( struct brw_context *brw )
brw_add_validated_bo(brw, intel->batch->buf);
- if (IS_GEN6(intel->intelScreen->deviceID)) {
+ if (intel->gen >= 6) {
atoms = gen6_atoms;
num_atoms = ARRAY_SIZE(gen6_atoms);
} else {
@@ -425,7 +424,7 @@ void brw_upload_state(struct brw_context *brw)
const struct brw_tracked_state **atoms;
int num_atoms;
- if (IS_GEN6(intel->intelScreen->deviceID)) {
+ if (intel->gen >= 6) {
atoms = gen6_atoms;
num_atoms = ARRAY_SIZE(gen6_atoms);
} else {
diff --git a/src/mesa/drivers/dri/i965/brw_structs.h b/src/mesa/drivers/dri/i965/brw_structs.h
index 2fde42a706..2a118e01c5 100644
--- a/src/mesa/drivers/dri/i965/brw_structs.h
+++ b/src/mesa/drivers/dri/i965/brw_structs.h
@@ -750,7 +750,7 @@ struct gen6_depth_stencil_state
} ds1;
struct {
- GLuint pad0:25;
+ GLuint pad0:26;
GLuint depth_write_enable:1;
GLuint depth_test_func:3;
GLuint pad1:1;
@@ -1305,13 +1305,14 @@ struct brw_instruction
GLuint access_mode:1;
GLuint mask_control:1;
GLuint dependency_control:2;
- GLuint compression_control:2;
+ GLuint compression_control:2; /* gen6: quater control */
GLuint thread_control:2;
GLuint predicate_control:4;
GLuint predicate_inverse:1;
GLuint execution_size:3;
GLuint destreg__conditionalmod:4; /* destreg - send, conditionalmod - others */
- GLuint pad0:2;
+ GLuint acc_wr_control:1;
+ GLuint cmpt_control:1;
GLuint debug_control:1;
GLuint saturate:1;
} header;
@@ -1359,7 +1360,7 @@ struct brw_instruction
GLuint dest_writemask:4;
GLuint dest_subreg_nr:1;
GLuint dest_reg_nr:8;
- GLuint pad1:2;
+ GLuint dest_horiz_stride:2;
GLuint dest_address_mode:1;
} da16;
@@ -1373,7 +1374,7 @@ struct brw_instruction
GLuint dest_writemask:4;
GLint dest_indirect_offset:6;
GLuint dest_subreg_nr:3;
- GLuint pad1:2;
+ GLuint dest_horiz_stride:2;
GLuint dest_address_mode:1;
} ia16;
} bits1;
diff --git a/src/mesa/drivers/dri/i965/brw_vs.c b/src/mesa/drivers/dri/i965/brw_vs.c
index 9a832af9a9..9f90e1e5e5 100644
--- a/src/mesa/drivers/dri/i965/brw_vs.c
+++ b/src/mesa/drivers/dri/i965/brw_vs.c
@@ -75,10 +75,10 @@ static void do_vs_prog( struct brw_context *brw,
c.prog_data.outputs_written |= BITFIELD64_BIT(VERT_RESULT_TEX0 + i);
}
- if (0)
- _mesa_print_program(&c.vp->program.Base);
-
-
+ if (0) {
+ _mesa_fprint_program_opt(stdout, &c.vp->program.Base, PROG_PRINT_DEBUG,
+ GL_TRUE);
+ }
/* Emit GEN4 code.
*/
diff --git a/src/mesa/drivers/dri/i965/brw_vs_emit.c b/src/mesa/drivers/dri/i965/brw_vs_emit.c
index b6b558e9a6..1d88c6b5a4 100644
--- a/src/mesa/drivers/dri/i965/brw_vs_emit.c
+++ b/src/mesa/drivers/dri/i965/brw_vs_emit.c
@@ -47,6 +47,7 @@ brw_vs_arg_can_be_immediate(enum prog_opcode opcode, int arg)
[OPCODE_MOV] = 1,
[OPCODE_ADD] = 2,
[OPCODE_CMP] = 3,
+ [OPCODE_DP2] = 2,
[OPCODE_DP3] = 2,
[OPCODE_DP4] = 2,
[OPCODE_DPH] = 2,
@@ -97,6 +98,39 @@ static void release_tmps( struct brw_vs_compile *c )
c->last_tmp = c->first_tmp;
}
+static int
+get_first_reladdr_output(struct gl_vertex_program *vp)
+{
+ int i;
+ int first_reladdr_output = VERT_RESULT_MAX;
+
+ for (i = 0; i < vp->Base.NumInstructions; i++) {
+ struct prog_instruction *inst = vp->Base.Instructions + i;
+
+ if (inst->DstReg.File == PROGRAM_OUTPUT &&
+ inst->DstReg.RelAddr &&
+ inst->DstReg.Index < first_reladdr_output)
+ first_reladdr_output = inst->DstReg.Index;
+ }
+
+ return first_reladdr_output;
+}
+
+/* Clears the record of which vp_const_buffer elements have been
+ * loaded into our constant buffer registers, for the starts of new
+ * blocks after control flow.
+ */
+static void
+clear_current_const(struct brw_vs_compile *c)
+{
+ unsigned int i;
+
+ if (c->vp->use_const_buffer) {
+ for (i = 0; i < 3; i++) {
+ c->current_const[i].index = -1;
+ }
+ }
+}
/**
* Preallocate GRF register before code emit.
@@ -108,6 +142,7 @@ static void brw_vs_alloc_regs( struct brw_vs_compile *c )
struct intel_context *intel = &c->func.brw->intel;
GLuint i, reg = 0, mrf;
int attributes_in_vue;
+ int first_reladdr_output;
/* Determine whether to use a real constant buffer or use a block
* of GRF registers for constants. The later is faster but only
@@ -225,6 +260,7 @@ static void brw_vs_alloc_regs( struct brw_vs_compile *c )
else
mrf = 4;
+ first_reladdr_output = get_first_reladdr_output(&c->vp->program);
for (i = 0; i < VERT_RESULT_MAX; i++) {
if (c->prog_data.outputs_written & BITFIELD64_BIT(i)) {
c->nr_outputs++;
@@ -253,15 +289,16 @@ static void brw_vs_alloc_regs( struct brw_vs_compile *c )
* For attributes beyond the compute-to-MRF, we compute to
* GRFs and they will be written in the second URB_WRITE.
*/
- if (mrf < 15) {
+ if (first_reladdr_output > i && mrf < 15) {
c->regs[PROGRAM_OUTPUT][i] = brw_message_reg(mrf);
mrf++;
}
else {
- if (!c->first_overflow_output)
+ if (mrf >= 15 && !c->first_overflow_output)
c->first_overflow_output = i;
c->regs[PROGRAM_OUTPUT][i] = brw_vec8_grf(reg, 0);
reg++;
+ mrf++;
}
}
}
@@ -292,10 +329,10 @@ static void brw_vs_alloc_regs( struct brw_vs_compile *c )
if (c->vp->use_const_buffer) {
for (i = 0; i < 3; i++) {
- c->current_const[i].index = -1;
c->current_const[i].reg = brw_vec8_grf(reg, 0);
reg++;
}
+ clear_current_const(c);
}
for (i = 0; i < 128; i++) {
@@ -502,6 +539,23 @@ static void emit_cmp( struct brw_compile *p,
brw_set_predicate_control(p, BRW_PREDICATE_NONE);
}
+static void emit_sign(struct brw_vs_compile *c,
+ struct brw_reg dst,
+ struct brw_reg arg0)
+{
+ struct brw_compile *p = &c->func;
+
+ brw_MOV(p, dst, brw_imm_f(0));
+
+ brw_CMP(p, brw_null_reg(), BRW_CONDITIONAL_L, arg0, brw_imm_f(0));
+ brw_MOV(p, dst, brw_imm_f(-1.0));
+ brw_set_predicate_control(p, BRW_PREDICATE_NONE);
+
+ brw_CMP(p, brw_null_reg(), BRW_CONDITIONAL_G, arg0, brw_imm_f(0));
+ brw_MOV(p, dst, brw_imm_f(1.0));
+ brw_set_predicate_control(p, BRW_PREDICATE_NONE);
+}
+
static void emit_max( struct brw_compile *p,
struct brw_reg dst,
struct brw_reg arg0,
@@ -1010,13 +1064,11 @@ move_to_reladdr_dst(struct brw_vs_compile *c,
int reg_size = 32;
struct brw_reg addr_reg = c->regs[PROGRAM_ADDRESS][0];
struct brw_reg vp_address = retype(vec1(addr_reg), BRW_REGISTER_TYPE_D);
- struct brw_reg temp_base = c->regs[inst->DstReg.File][0];
- GLuint byte_offset = temp_base.nr * 32 + temp_base.subnr;
+ struct brw_reg base = c->regs[inst->DstReg.File][inst->DstReg.Index];
+ GLuint byte_offset = base.nr * 32 + base.subnr;
struct brw_reg indirect = brw_vec4_indirect(0,0);
struct brw_reg acc = retype(vec1(get_tmp(c)), BRW_REGISTER_TYPE_UW);
- byte_offset += inst->DstReg.Index * reg_size;
-
brw_push_insn_state(p);
brw_set_access_mode(p, BRW_ALIGN_1);
@@ -1162,10 +1214,12 @@ static struct brw_reg get_arg( struct brw_vs_compile *c,
/* Convert 3-bit swizzle to 2-bit.
*/
- reg.dw1.bits.swizzle = BRW_SWIZZLE4(GET_SWZ(src->Swizzle, 0),
- GET_SWZ(src->Swizzle, 1),
- GET_SWZ(src->Swizzle, 2),
- GET_SWZ(src->Swizzle, 3));
+ if (reg.file != BRW_IMMEDIATE_VALUE) {
+ reg.dw1.bits.swizzle = BRW_SWIZZLE4(GET_SWZ(src->Swizzle, 0),
+ GET_SWZ(src->Swizzle, 1),
+ GET_SWZ(src->Swizzle, 2),
+ GET_SWZ(src->Swizzle, 3));
+ }
/* Note this is ok for non-swizzle instructions:
*/
@@ -1211,6 +1265,7 @@ static struct brw_reg get_dst( struct brw_vs_compile *c,
reg = brw_null_reg();
}
+ assert(reg.type != BRW_IMMEDIATE_VALUE);
reg.dw1.bits.writemask = dst.WriteMask;
return reg;
@@ -1299,6 +1354,7 @@ static void emit_vertex_write( struct brw_vs_compile *c)
struct brw_reg ndc;
int eot;
GLuint len_vertex_header = 2;
+ int next_mrf, i;
if (c->key.copy_edgeflag) {
brw_MOV(p,
@@ -1376,6 +1432,7 @@ static void emit_vertex_write( struct brw_vs_compile *c)
* of zeros followed by two sets of NDC coordinates:
*/
brw_set_access_mode(p, BRW_ALIGN_1);
+ brw_set_acc_write_control(p, 0);
/* The VUE layout is documented in Volume 2a. */
if (intel->gen >= 6) {
@@ -1416,6 +1473,23 @@ static void emit_vertex_write( struct brw_vs_compile *c)
len_vertex_header = 2;
}
+ /* Move variable-addressed, non-overflow outputs to their MRFs. */
+ next_mrf = 2 + len_vertex_header;
+ for (i = 0; i < VERT_RESULT_MAX; i++) {
+ if (c->first_overflow_output > 0 && i >= c->first_overflow_output)
+ break;
+ if (!(c->prog_data.outputs_written & BITFIELD64_BIT(i)))
+ continue;
+
+ if (i >= VERT_RESULT_TEX0 &&
+ c->regs[PROGRAM_OUTPUT][i].file == BRW_GENERAL_REGISTER_FILE) {
+ brw_MOV(p, brw_message_reg(next_mrf), c->regs[PROGRAM_OUTPUT][i]);
+ next_mrf++;
+ } else if (c->regs[PROGRAM_OUTPUT][i].file == BRW_MESSAGE_REGISTER_FILE) {
+ next_mrf = c->regs[PROGRAM_OUTPUT][i].nr + 1;
+ }
+ }
+
eot = (c->first_overflow_output == 0);
brw_urb_WRITE(p,
@@ -1541,18 +1615,23 @@ void brw_vs_emit(struct brw_vs_compile *c )
const GLuint nr_insns = c->vp->program.Base.NumInstructions;
GLuint insn, if_depth = 0, loop_depth = 0;
struct brw_instruction *if_inst[MAX_IF_DEPTH], *loop_inst[MAX_LOOP_DEPTH] = { 0 };
+ int if_depth_in_loop[MAX_LOOP_DEPTH];
const struct brw_indirect stack_index = brw_indirect(0, 0);
GLuint index;
GLuint file;
if (INTEL_DEBUG & DEBUG_VS) {
printf("vs-mesa:\n");
- _mesa_print_program(&c->vp->program.Base);
+ _mesa_fprint_program_opt(stdout, &c->vp->program.Base, PROG_PRINT_DEBUG,
+ GL_TRUE);
printf("\n");
}
brw_set_compression_control(p, BRW_COMPRESSION_NONE);
brw_set_access_mode(p, BRW_ALIGN_16);
+ if_depth_in_loop[loop_depth] = 0;
+
+ brw_set_acc_write_control(p, 1);
for (insn = 0; insn < nr_insns; insn++) {
GLuint i;
@@ -1591,7 +1670,7 @@ void brw_vs_emit(struct brw_vs_compile *c )
const struct prog_instruction *inst = &c->vp->program.Base.Instructions[insn];
struct brw_reg args[3], dst;
GLuint i;
-
+
#if 0
printf("%d: ", insn);
_mesa_print_instruction(inst);
@@ -1636,6 +1715,9 @@ void brw_vs_emit(struct brw_vs_compile *c )
case OPCODE_COS:
emit_math1(c, BRW_MATH_FUNCTION_COS, dst, args[0], BRW_MATH_PRECISION_FULL);
break;
+ case OPCODE_DP2:
+ brw_DP2(p, dst, args[0], args[1]);
+ break;
case OPCODE_DP3:
brw_DP3(p, dst, args[0], args[1]);
break;
@@ -1732,6 +1814,9 @@ void brw_vs_emit(struct brw_vs_compile *c )
case OPCODE_SLE:
unalias2(c, dst, args[0], args[1], emit_sle);
break;
+ case OPCODE_SSG:
+ unalias1(c, dst, args[0], emit_sign);
+ break;
case OPCODE_SUB:
brw_ADD(p, dst, args[0], negate(args[1]));
break;
@@ -1753,31 +1838,38 @@ void brw_vs_emit(struct brw_vs_compile *c )
if_inst[if_depth] = brw_IF(p, BRW_EXECUTE_8);
/* Note that brw_IF smashes the predicate_control field. */
if_inst[if_depth]->header.predicate_control = get_predicate(inst);
+ if_depth_in_loop[loop_depth]++;
if_depth++;
break;
case OPCODE_ELSE:
+ clear_current_const(c);
assert(if_depth > 0);
if_inst[if_depth-1] = brw_ELSE(p, if_inst[if_depth-1]);
break;
case OPCODE_ENDIF:
+ clear_current_const(c);
assert(if_depth > 0);
brw_ENDIF(p, if_inst[--if_depth]);
+ if_depth_in_loop[loop_depth]--;
break;
case OPCODE_BGNLOOP:
+ clear_current_const(c);
loop_inst[loop_depth++] = brw_DO(p, BRW_EXECUTE_8);
+ if_depth_in_loop[loop_depth] = 0;
break;
case OPCODE_BRK:
brw_set_predicate_control(p, get_predicate(inst));
- brw_BREAK(p);
+ brw_BREAK(p, if_depth_in_loop[loop_depth]);
brw_set_predicate_control(p, BRW_PREDICATE_NONE);
break;
case OPCODE_CONT:
brw_set_predicate_control(p, get_predicate(inst));
- brw_CONT(p);
+ brw_CONT(p, if_depth_in_loop[loop_depth]);
brw_set_predicate_control(p, BRW_PREDICATE_NONE);
break;
case OPCODE_ENDLOOP:
{
+ clear_current_const(c);
struct brw_instruction *inst0, *inst1;
GLuint br = 1;
@@ -1793,12 +1885,10 @@ void brw_vs_emit(struct brw_vs_compile *c )
if (inst0->header.opcode == BRW_OPCODE_BREAK &&
inst0->bits3.if_else.jump_count == 0) {
inst0->bits3.if_else.jump_count = br * (inst1 - inst0 + 1);
- inst0->bits3.if_else.pop_count = 0;
}
else if (inst0->header.opcode == BRW_OPCODE_CONTINUE &&
inst0->bits3.if_else.jump_count == 0) {
inst0->bits3.if_else.jump_count = br * (inst1 - inst0);
- inst0->bits3.if_else.pop_count = 0;
}
}
}
@@ -1883,11 +1973,9 @@ void brw_vs_emit(struct brw_vs_compile *c )
}
}
- if (inst->DstReg.RelAddr && inst->DstReg.File == PROGRAM_TEMPORARY) {
- /* We don't do RelAddr of PROGRAM_OUTPUT yet, because of the
- * compute-to-mrf and the fact that we are allocating
- * registers for only the used PROGRAM_OUTPUTs.
- */
+ if (inst->DstReg.RelAddr) {
+ assert(inst->DstReg.File == PROGRAM_TEMPORARY||
+ inst->DstReg.File == PROGRAM_OUTPUT);
move_to_reladdr_dst(c, inst, dst);
}
@@ -1903,7 +1991,7 @@ void brw_vs_emit(struct brw_vs_compile *c )
printf("vs-native:\n");
for (i = 0; i < p->nr_insn; i++)
- brw_disasm(stderr, &p->store[i], intel->gen);
+ brw_disasm(stdout, &p->store[i], intel->gen);
printf("\n");
}
}
diff --git a/src/mesa/drivers/dri/i965/brw_vtbl.c b/src/mesa/drivers/dri/i965/brw_vtbl.c
index 14227a5133..8f1601d10f 100644
--- a/src/mesa/drivers/dri/i965/brw_vtbl.c
+++ b/src/mesa/drivers/dri/i965/brw_vtbl.c
@@ -101,6 +101,7 @@ static void brw_destroy_context( struct intel_context *intel )
dri_bo_release(&brw->wm.prog_bo);
dri_bo_release(&brw->wm.state_bo);
dri_bo_release(&brw->wm.const_bo);
+ dri_bo_release(&brw->wm.push_const_bo);
dri_bo_release(&brw->cc.prog_bo);
dri_bo_release(&brw->cc.state_bo);
dri_bo_release(&brw->cc.vp_bo);
diff --git a/src/mesa/drivers/dri/i965/brw_wm.c b/src/mesa/drivers/dri/i965/brw_wm.c
index e182fc3202..d70be7bda2 100644
--- a/src/mesa/drivers/dri/i965/brw_wm.c
+++ b/src/mesa/drivers/dri/i965/brw_wm.c
@@ -32,7 +32,7 @@
#include "brw_context.h"
#include "brw_wm.h"
#include "brw_state.h"
-
+#include "main/formats.h"
/** Return number of src args for given instruction */
GLuint brw_wm_nr_args( GLuint opcode )
@@ -68,6 +68,7 @@ GLuint brw_wm_is_scalar_result( GLuint opcode )
case OPCODE_RCP:
case OPCODE_RSQ:
case OPCODE_SIN:
+ case OPCODE_DP2:
case OPCODE_DP3:
case OPCODE_DP4:
case OPCODE_DPH:
@@ -177,17 +178,19 @@ static void do_wm_prog( struct brw_context *brw,
/* temporary sanity check assertion */
ASSERT(fp->isGLSL == brw_wm_is_glsl(&c->fp->program));
- /*
- * Shader which use GLSL features such as flow control are handled
- * differently from "simple" shaders.
- */
- if (fp->isGLSL) {
- c->dispatch_width = 8;
- brw_wm_glsl_emit(brw, c);
- }
- else {
- c->dispatch_width = 16;
- brw_wm_non_glsl_emit(brw, c);
+ if (!brw_wm_fs_emit(brw, c)) {
+ /*
+ * Shader which use GLSL features such as flow control are handled
+ * differently from "simple" shaders.
+ */
+ if (fp->isGLSL) {
+ c->dispatch_width = 8;
+ brw_wm_glsl_emit(brw, c);
+ }
+ else {
+ c->dispatch_width = 16;
+ brw_wm_non_glsl_emit(brw, c);
+ }
}
if (INTEL_DEBUG & DEBUG_WM)
diff --git a/src/mesa/drivers/dri/i965/brw_wm.h b/src/mesa/drivers/dri/i965/brw_wm.h
index f40977fab8..2639d4f26b 100644
--- a/src/mesa/drivers/dri/i965/brw_wm.h
+++ b/src/mesa/drivers/dri/i965/brw_wm.h
@@ -61,7 +61,7 @@ struct brw_wm_prog_key {
GLuint source_depth_reg:3;
GLuint aa_dest_stencil_reg:3;
GLuint dest_depth_reg:3;
- GLuint nr_depth_regs:3;
+ GLuint nr_payload_regs:4;
GLuint computes_depth:1; /* could be derived from program string */
GLuint source_depth_to_render_target:1;
GLuint flat_shade:1;
@@ -306,6 +306,7 @@ void brw_wm_lookup_iz( GLuint line_aa,
GLboolean brw_wm_is_glsl(const struct gl_fragment_program *fp);
void brw_wm_glsl_emit(struct brw_context *brw, struct brw_wm_compile *c);
+GLboolean brw_wm_fs_emit(struct brw_context *brw, struct brw_wm_compile *c);
/* brw_wm_emit.c */
void emit_alu1(struct brw_compile *p,
@@ -343,6 +344,11 @@ void emit_delta_xy(struct brw_compile *p,
const struct brw_reg *dst,
GLuint mask,
const struct brw_reg *arg0);
+void emit_dp2(struct brw_compile *p,
+ const struct brw_reg *dst,
+ GLuint mask,
+ const struct brw_reg *arg0,
+ const struct brw_reg *arg1);
void emit_dp3(struct brw_compile *p,
const struct brw_reg *dst,
GLuint mask,
@@ -425,6 +431,10 @@ void emit_sop(struct brw_compile *p,
GLuint cond,
const struct brw_reg *arg0,
const struct brw_reg *arg1);
+void emit_sign(struct brw_compile *p,
+ const struct brw_reg *dst,
+ GLuint mask,
+ const struct brw_reg *arg0);
void emit_tex(struct brw_wm_compile *c,
struct brw_reg *dst,
GLuint dst_flags,
@@ -450,4 +460,13 @@ void emit_xpd(struct brw_compile *p,
const struct brw_reg *arg0,
const struct brw_reg *arg1);
+GLboolean brw_compile_shader(GLcontext *ctx,
+ struct gl_shader *shader);
+GLboolean brw_link_shader(GLcontext *ctx, struct gl_shader_program *prog);
+struct gl_shader *brw_new_shader(GLcontext *ctx, GLuint name, GLuint type);
+struct gl_shader_program *brw_new_shader_program(GLcontext *ctx, GLuint name);
+
+GLboolean brw_do_channel_expressions(struct exec_list *instructions);
+GLboolean brw_do_vector_splitting(struct exec_list *instructions);
+
#endif
diff --git a/src/mesa/drivers/dri/i965/brw_wm_debug.c b/src/mesa/drivers/dri/i965/brw_wm_debug.c
index a78cc8b54e..6a91251a80 100644
--- a/src/mesa/drivers/dri/i965/brw_wm_debug.c
+++ b/src/mesa/drivers/dri/i965/brw_wm_debug.c
@@ -44,16 +44,16 @@ void brw_wm_print_value( struct brw_wm_compile *c,
printf("undef");
else if( value - c->vreg >= 0 &&
value - c->vreg < BRW_WM_MAX_VREG)
- printf("r%d", value - c->vreg);
+ printf("r%ld", (long) (value - c->vreg));
else if (value - c->creg >= 0 &&
value - c->creg < BRW_WM_MAX_PARAM)
- printf("c%d", value - c->creg);
+ printf("c%ld", (long) (value - c->creg));
else if (value - c->payload.input_interp >= 0 &&
value - c->payload.input_interp < FRAG_ATTRIB_MAX)
- printf("i%d", value - c->payload.input_interp);
+ printf("i%ld", (long) (value - c->payload.input_interp));
else if (value - c->payload.depth >= 0 &&
value - c->payload.depth < FRAG_ATTRIB_MAX)
- printf("d%d", value - c->payload.depth);
+ printf("d%ld", (long) (value - c->payload.depth));
else
printf("?");
}
diff --git a/src/mesa/drivers/dri/i965/brw_wm_emit.c b/src/mesa/drivers/dri/i965/brw_wm_emit.c
index d9fa2e6335..f3ad01b3fe 100644
--- a/src/mesa/drivers/dri/i965/brw_wm_emit.c
+++ b/src/mesa/drivers/dri/i965/brw_wm_emit.c
@@ -668,6 +668,28 @@ void emit_cmp(struct brw_compile *p,
}
}
+void emit_sign(struct brw_compile *p,
+ const struct brw_reg *dst,
+ GLuint mask,
+ const struct brw_reg *arg0)
+{
+ GLuint i;
+
+ for (i = 0; i < 4; i++) {
+ if (mask & (1<<i)) {
+ brw_MOV(p, dst[i], brw_imm_f(0.0));
+
+ brw_CMP(p, brw_null_reg(), BRW_CONDITIONAL_L, arg0[i], brw_imm_f(0));
+ brw_MOV(p, dst[i], brw_imm_f(-1.0));
+ brw_set_predicate_control(p, BRW_PREDICATE_NONE);
+
+ brw_CMP(p, brw_null_reg(), BRW_CONDITIONAL_G, arg0[i], brw_imm_f(0));
+ brw_MOV(p, dst[i], brw_imm_f(1.0));
+ brw_set_predicate_control(p, BRW_PREDICATE_NONE);
+ }
+ }
+}
+
void emit_max(struct brw_compile *p,
const struct brw_reg *dst,
GLuint mask,
@@ -709,6 +731,27 @@ void emit_min(struct brw_compile *p,
}
+void emit_dp2(struct brw_compile *p,
+ const struct brw_reg *dst,
+ GLuint mask,
+ const struct brw_reg *arg0,
+ const struct brw_reg *arg1)
+{
+ int dst_chan = _mesa_ffs(mask & WRITEMASK_XYZW) - 1;
+
+ if (!(mask & WRITEMASK_XYZW))
+ return; /* Do not emit dead code */
+
+ assert(is_power_of_two(mask & WRITEMASK_XYZW));
+
+ brw_MUL(p, brw_null_reg(), arg0[0], arg1[0]);
+
+ brw_set_saturate(p, (mask & SATURATE) ? 1 : 0);
+ brw_MAC(p, dst[dst_chan], arg0[1], arg1[1]);
+ brw_set_saturate(p, 0);
+}
+
+
void emit_dp3(struct brw_compile *p,
const struct brw_reg *dst,
GLuint mask,
@@ -809,21 +852,28 @@ void emit_math1(struct brw_wm_compile *c,
const struct brw_reg *arg0)
{
struct brw_compile *p = &c->func;
+ struct intel_context *intel = &p->brw->intel;
int dst_chan = _mesa_ffs(mask & WRITEMASK_XYZW) - 1;
GLuint saturate = ((mask & SATURATE) ?
BRW_MATH_SATURATE_SATURATE :
BRW_MATH_SATURATE_NONE);
+ struct brw_reg src;
+
+ if (intel->gen >= 6 && arg0[0].hstride == BRW_HORIZONTAL_STRIDE_0) {
+ /* Gen6 math requires that source and dst horizontal stride be 1.
+ *
+ */
+ src = *dst;
+ brw_MOV(p, src, arg0[0]);
+ } else {
+ src = arg0[0];
+ }
if (!(mask & WRITEMASK_XYZW))
return; /* Do not emit dead code */
assert(is_power_of_two(mask & WRITEMASK_XYZW));
- /* If compressed, this will write message reg 2,3 from arg0.x's 16
- * channels.
- */
- brw_MOV(p, brw_message_reg(2), arg0[0]);
-
/* Send two messages to perform all 16 operations:
*/
brw_push_insn_state(p);
@@ -833,7 +883,7 @@ void emit_math1(struct brw_wm_compile *c,
function,
saturate,
2,
- brw_null_reg(),
+ src,
BRW_MATH_DATA_VECTOR,
BRW_MATH_PRECISION_FULL);
@@ -844,7 +894,7 @@ void emit_math1(struct brw_wm_compile *c,
function,
saturate,
3,
- brw_null_reg(),
+ sechalf(src),
BRW_MATH_DATA_VECTOR,
BRW_MATH_PRECISION_FULL);
}
@@ -873,13 +923,6 @@ void emit_math2(struct brw_wm_compile *c,
brw_push_insn_state(p);
brw_set_compression_control(p, BRW_COMPRESSION_NONE);
- brw_MOV(p, brw_message_reg(2), arg0[0]);
- if (c->dispatch_width == 16) {
- brw_set_compression_control(p, BRW_COMPRESSION_2NDHALF);
- brw_MOV(p, brw_message_reg(4), sechalf(arg0[0]));
- }
-
- brw_set_compression_control(p, BRW_COMPRESSION_NONE);
brw_MOV(p, brw_message_reg(3), arg1[0]);
if (c->dispatch_width == 16) {
brw_set_compression_control(p, BRW_COMPRESSION_2NDHALF);
@@ -892,7 +935,7 @@ void emit_math2(struct brw_wm_compile *c,
function,
saturate,
2,
- brw_null_reg(),
+ arg0[0],
BRW_MATH_DATA_VECTOR,
BRW_MATH_PRECISION_FULL);
@@ -905,7 +948,7 @@ void emit_math2(struct brw_wm_compile *c,
function,
saturate,
4,
- brw_null_reg(),
+ sechalf(arg0[0]),
BRW_MATH_DATA_VECTOR,
BRW_MATH_PRECISION_FULL);
}
@@ -1199,6 +1242,7 @@ static void fire_fb_write( struct brw_wm_compile *c,
GLuint eot )
{
struct brw_compile *p = &c->func;
+ struct intel_context *intel = &p->brw->intel;
struct brw_reg dst;
if (c->dispatch_width == 16)
@@ -1209,6 +1253,7 @@ static void fire_fb_write( struct brw_wm_compile *c,
/* Pass through control information:
*/
/* mov (8) m1.0<1>:ud r1.0<8;8,1>:ud { Align1 NoMask } */
+ if (intel->gen < 6) /* gen6, use headerless for fb write */
{
brw_push_insn_state(p);
brw_set_mask_control(p, BRW_MASK_DISABLE); /* ? */
@@ -1222,6 +1267,7 @@ static void fire_fb_write( struct brw_wm_compile *c,
/* Send framebuffer write message: */
/* send (16) null.0<1>:uw m0 r0.0<8;8,1>:uw 0x85a04000:ud { Align1 EOT } */
brw_fb_WRITE(p,
+ c->dispatch_width,
dst,
base_reg,
retype(brw_vec8_grf(0, 0), BRW_REGISTER_TYPE_UW),
@@ -1263,8 +1309,10 @@ void emit_fb_write(struct brw_wm_compile *c,
{
struct brw_compile *p = &c->func;
struct brw_context *brw = p->brw;
+ struct intel_context *intel = &brw->intel;
GLuint nr = 2;
GLuint channel;
+ int base_reg; /* For gen6 fb write with no header, starting from color payload directly!. */
/* Reserve a space for AA - may not be needed:
*/
@@ -1276,9 +1324,40 @@ void emit_fb_write(struct brw_wm_compile *c,
*/
brw_push_insn_state(p);
+ if (intel->gen >= 6)
+ base_reg = nr;
+ else
+ base_reg = 0;
+
for (channel = 0; channel < 4; channel++) {
- if (c->dispatch_width == 16 && brw->has_compr4) {
- /* By setting the high bit of the MRF register number, we indicate
+ if (intel->gen >= 6) {
+ /* gen6 SIMD16 single source DP write looks like:
+ * m + 0: r0
+ * m + 1: r1
+ * m + 2: g0
+ * m + 3: g1
+ * m + 4: b0
+ * m + 5: b1
+ * m + 6: a0
+ * m + 7: a1
+ */
+ if (c->dispatch_width == 16) {
+ brw_MOV(p, brw_message_reg(nr + channel * 2), arg0[channel]);
+ } else {
+ brw_MOV(p, brw_message_reg(nr + channel), arg0[channel]);
+ }
+ } else if (c->dispatch_width == 16 && brw->has_compr4) {
+ /* pre-gen6 SIMD16 single source DP write looks like:
+ * m + 0: r0
+ * m + 1: g0
+ * m + 2: b0
+ * m + 3: a0
+ * m + 4: r1
+ * m + 5: g1
+ * m + 6: b1
+ * m + 7: a1
+ *
+ * By setting the high bit of the MRF register number, we indicate
* that we want COMPR4 mode - instead of doing the usual destination
* + 1 for the second half we get destination + 4.
*/
@@ -1303,7 +1382,11 @@ void emit_fb_write(struct brw_wm_compile *c,
}
/* skip over the regs populated above:
*/
- nr += 8;
+ if (c->dispatch_width == 16)
+ nr += 8;
+ else
+ nr += 4;
+
brw_pop_insn_state(p);
if (c->key.source_depth_to_render_target)
@@ -1336,11 +1419,16 @@ void emit_fb_write(struct brw_wm_compile *c,
nr += 2;
}
+ if (intel->gen >= 6) {
+ /* Subtract off the message header, since we send headerless. */
+ nr -= 2;
+ }
+
if (!c->key.runtime_check_aads_emit) {
if (c->key.aa_dest_stencil_reg)
emit_aa(c, arg1, 2);
- fire_fb_write(c, 0, nr, target, eot);
+ fire_fb_write(c, base_reg, nr, target, eot);
}
else {
struct brw_reg v1_null_ud = vec1(retype(brw_null_reg(), BRW_REGISTER_TYPE_UD));
@@ -1562,6 +1650,10 @@ void brw_wm_emit( struct brw_wm_compile *c )
emit_ddxy(p, dst, dst_flags, GL_FALSE, args[0]);
break;
+ case OPCODE_DP2:
+ emit_dp2(p, dst, dst_flags, args[0], args[1]);
+ break;
+
case OPCODE_DP3:
emit_dp3(p, dst, dst_flags, args[0], args[1]);
break;
@@ -1673,6 +1765,10 @@ void brw_wm_emit( struct brw_wm_compile *c )
emit_sne(p, dst, dst_flags, args[0], args[1]);
break;
+ case OPCODE_SSG:
+ emit_sign(p, dst, dst_flags, args[0]);
+ break;
+
case OPCODE_LIT:
emit_lit(c, dst, dst_flags, args[0]);
break;
@@ -1724,7 +1820,7 @@ void brw_wm_emit( struct brw_wm_compile *c )
printf("wm-native:\n");
for (i = 0; i < p->nr_insn; i++)
- brw_disasm(stderr, &p->store[i], p->brw->intel.gen);
+ brw_disasm(stdout, &p->store[i], p->brw->intel.gen);
printf("\n");
}
}
diff --git a/src/mesa/drivers/dri/i965/brw_wm_fp.c b/src/mesa/drivers/dri/i965/brw_wm_fp.c
index 0bef874b88..3870bf10fc 100644
--- a/src/mesa/drivers/dri/i965/brw_wm_fp.c
+++ b/src/mesa/drivers/dri/i965/brw_wm_fp.c
@@ -88,6 +88,7 @@ static struct prog_src_register src_reg(GLuint file, GLuint idx)
reg.RelAddr = 0;
reg.Negate = NEGATE_NONE;
reg.Abs = 0;
+ reg.HasIndex2 = 0;
return reg;
}
@@ -1036,13 +1037,12 @@ static void print_insns( const struct prog_instruction *insn,
for (i = 0; i < nr; i++, insn++) {
printf("%3d: ", i);
if (insn->Opcode < MAX_OPCODE)
- _mesa_print_instruction(insn);
+ _mesa_fprint_instruction_opt(stdout, insn, 0, PROG_PRINT_DEBUG, NULL);
else if (insn->Opcode < MAX_WM_OPCODE) {
GLuint idx = insn->Opcode - MAX_OPCODE;
- _mesa_print_alu_instruction(insn,
- wm_opcode_strings[idx],
- 3);
+ _mesa_fprint_alu_instruction(stdout, insn, wm_opcode_strings[idx],
+ 3, PROG_PRINT_DEBUG, NULL);
}
else
printf("965 Opcode %d\n", insn->Opcode);
@@ -1061,7 +1061,8 @@ void brw_wm_pass_fp( struct brw_wm_compile *c )
if (INTEL_DEBUG & DEBUG_WM) {
printf("pre-fp:\n");
- _mesa_print_program(&fp->program.Base);
+ _mesa_fprint_program_opt(stdout, &fp->program.Base, PROG_PRINT_DEBUG,
+ GL_TRUE);
printf("\n");
}
diff --git a/src/mesa/drivers/dri/i965/brw_wm_glsl.c b/src/mesa/drivers/dri/i965/brw_wm_glsl.c
index 575f89b17f..c1083c5942 100644
--- a/src/mesa/drivers/dri/i965/brw_wm_glsl.c
+++ b/src/mesa/drivers/dri/i965/brw_wm_glsl.c
@@ -303,13 +303,13 @@ static void prealloc_reg(struct brw_wm_compile *c)
c->first_free_grf = 0;
for (i = 0; i < 4; i++) {
- if (i < c->key.nr_depth_regs)
+ if (i < (c->key.nr_payload_regs + 1) / 2)
reg = brw_vec8_grf(i * 2, 0);
else
reg = brw_vec8_grf(0, 0);
set_reg(c, PROGRAM_PAYLOAD, PAYLOAD_DEPTH, i, reg);
}
- reg_index += 2 * c->key.nr_depth_regs;
+ reg_index += c->key.nr_payload_regs;
/* constants */
{
@@ -380,7 +380,7 @@ static void prealloc_reg(struct brw_wm_compile *c)
}
}
- c->prog_data.first_curbe_grf = c->key.nr_depth_regs * 2;
+ c->prog_data.first_curbe_grf = c->key.nr_payload_regs;
c->prog_data.urb_read_length = urb_read_length;
c->prog_data.curb_read_length = c->nr_creg;
c->emit_mask_reg = brw_uw1_reg(BRW_GENERAL_REGISTER_FILE, reg_index, 0);
@@ -1803,12 +1803,15 @@ static void brw_wm_emit_glsl(struct brw_context *brw, struct brw_wm_compile *c)
#define MAX_IF_DEPTH 32
#define MAX_LOOP_DEPTH 32
struct brw_instruction *if_inst[MAX_IF_DEPTH], *loop_inst[MAX_LOOP_DEPTH];
+ int if_depth_in_loop[MAX_LOOP_DEPTH];
GLuint i, if_depth = 0, loop_depth = 0;
struct brw_compile *p = &c->func;
struct brw_indirect stack_index = brw_indirect(0, 0);
c->out_of_regs = GL_FALSE;
+ if_depth_in_loop[loop_depth] = 0;
+
prealloc_reg(c);
brw_set_compression_control(p, BRW_COMPRESSION_NONE);
brw_MOV(p, get_addr_reg(stack_index), brw_address(c->stack));
@@ -1903,6 +1906,9 @@ static void brw_wm_emit_glsl(struct brw_context *brw, struct brw_wm_compile *c)
case OPCODE_SWZ:
emit_alu1(p, brw_MOV, dst, dst_flags, args[0]);
break;
+ case OPCODE_DP2:
+ emit_dp2(p, dst, dst_flags, args[0], args[1]);
+ break;
case OPCODE_DP3:
emit_dp3(p, dst, dst_flags, args[0], args[1]);
break;
@@ -1971,6 +1977,9 @@ static void brw_wm_emit_glsl(struct brw_context *brw, struct brw_wm_compile *c)
emit_sop(p, dst, dst_flags,
BRW_CONDITIONAL_NEQ, args[0], args[1]);
break;
+ case OPCODE_SSG:
+ emit_sign(p, dst, dst_flags, args[0]);
+ break;
case OPCODE_MUL:
emit_alu2(p, brw_MUL, dst, dst_flags, args[0], args[1]);
break;
@@ -2014,6 +2023,7 @@ static void brw_wm_emit_glsl(struct brw_context *brw, struct brw_wm_compile *c)
case OPCODE_IF:
assert(if_depth < MAX_IF_DEPTH);
if_inst[if_depth++] = brw_IF(p, BRW_EXECUTE_8);
+ if_depth_in_loop[loop_depth]++;
break;
case OPCODE_ELSE:
assert(if_depth > 0);
@@ -2022,6 +2032,7 @@ static void brw_wm_emit_glsl(struct brw_context *brw, struct brw_wm_compile *c)
case OPCODE_ENDIF:
assert(if_depth > 0);
brw_ENDIF(p, if_inst[--if_depth]);
+ if_depth_in_loop[loop_depth]--;
break;
case OPCODE_BGNSUB:
brw_save_label(p, inst->Comment, p->nr_insn);
@@ -2056,13 +2067,14 @@ static void brw_wm_emit_glsl(struct brw_context *brw, struct brw_wm_compile *c)
case OPCODE_BGNLOOP:
/* XXX may need to invalidate the current_constant regs */
loop_inst[loop_depth++] = brw_DO(p, BRW_EXECUTE_8);
+ if_depth_in_loop[loop_depth] = 0;
break;
case OPCODE_BRK:
- brw_BREAK(p);
+ brw_BREAK(p, if_depth_in_loop[loop_depth]);
brw_set_predicate_control(p, BRW_PREDICATE_NONE);
break;
case OPCODE_CONT:
- brw_CONT(p);
+ brw_CONT(p, if_depth_in_loop[loop_depth]);
brw_set_predicate_control(p, BRW_PREDICATE_NONE);
break;
case OPCODE_ENDLOOP:
@@ -2082,12 +2094,10 @@ static void brw_wm_emit_glsl(struct brw_context *brw, struct brw_wm_compile *c)
if (inst0->header.opcode == BRW_OPCODE_BREAK &&
inst0->bits3.if_else.jump_count == 0) {
inst0->bits3.if_else.jump_count = br * (inst1 - inst0 + 1);
- inst0->bits3.if_else.pop_count = 0;
}
else if (inst0->header.opcode == BRW_OPCODE_CONTINUE &&
inst0->bits3.if_else.jump_count == 0) {
inst0->bits3.if_else.jump_count = br * (inst1 - inst0);
- inst0->bits3.if_else.pop_count = 0;
}
}
}
@@ -2111,7 +2121,7 @@ static void brw_wm_emit_glsl(struct brw_context *brw, struct brw_wm_compile *c)
if (INTEL_DEBUG & DEBUG_WM) {
printf("wm-native:\n");
for (i = 0; i < p->nr_insn; i++)
- brw_disasm(stderr, &p->store[i], intel->gen);
+ brw_disasm(stdout, &p->store[i], intel->gen);
printf("\n");
}
}
diff --git a/src/mesa/drivers/dri/i965/brw_wm_iz.c b/src/mesa/drivers/dri/i965/brw_wm_iz.c
index 5e399ac62a..8505ef1951 100644
--- a/src/mesa/drivers/dri/i965/brw_wm_iz.c
+++ b/src/mesa/drivers/dri/i965/brw_wm_iz.c
@@ -152,6 +152,6 @@ void brw_wm_lookup_iz( GLuint line_aa,
reg+=2;
}
- key->nr_depth_regs = (reg+1)/2;
+ key->nr_payload_regs = reg;
}
diff --git a/src/mesa/drivers/dri/i965/brw_wm_pass0.c b/src/mesa/drivers/dri/i965/brw_wm_pass0.c
index 05de85a957..8fc960b445 100644
--- a/src/mesa/drivers/dri/i965/brw_wm_pass0.c
+++ b/src/mesa/drivers/dri/i965/brw_wm_pass0.c
@@ -379,7 +379,7 @@ static void pass0_init_payload( struct brw_wm_compile *c )
GLuint i;
for (i = 0; i < 4; i++) {
- GLuint j = i >= c->key.nr_depth_regs ? 0 : i;
+ GLuint j = i >= (c->key.nr_payload_regs + 1) / 2 ? 0 : i;
pass0_set_fpreg_value( c, PROGRAM_PAYLOAD, PAYLOAD_DEPTH, i,
&c->payload.depth[j] );
}
diff --git a/src/mesa/drivers/dri/i965/brw_wm_pass1.c b/src/mesa/drivers/dri/i965/brw_wm_pass1.c
index b449394029..962515a99e 100644
--- a/src/mesa/drivers/dri/i965/brw_wm_pass1.c
+++ b/src/mesa/drivers/dri/i965/brw_wm_pass1.c
@@ -158,6 +158,7 @@ void brw_wm_pass1( struct brw_wm_compile *c )
case OPCODE_FLR:
case OPCODE_FRC:
case OPCODE_MOV:
+ case OPCODE_SSG:
case OPCODE_SWZ:
case OPCODE_TRUNC:
read0 = writemask;
@@ -254,6 +255,11 @@ void brw_wm_pass1( struct brw_wm_compile *c )
read2 = WRITEMASK_W; /* pixel w */
break;
+ case OPCODE_DP2:
+ read0 = WRITEMASK_XY;
+ read1 = WRITEMASK_XY;
+ break;
+
case OPCODE_DP3:
read0 = WRITEMASK_XYZ;
read1 = WRITEMASK_XYZ;
diff --git a/src/mesa/drivers/dri/i965/brw_wm_pass2.c b/src/mesa/drivers/dri/i965/brw_wm_pass2.c
index 31303febf0..54acb3038b 100644
--- a/src/mesa/drivers/dri/i965/brw_wm_pass2.c
+++ b/src/mesa/drivers/dri/i965/brw_wm_pass2.c
@@ -76,7 +76,7 @@ static void init_registers( struct brw_wm_compile *c )
for (j = 0; j < c->grf_limit; j++)
c->pass2_grf[j].nextuse = BRW_WM_MAX_INSN;
- for (j = 0; j < c->key.nr_depth_regs; j++)
+ for (j = 0; j < (c->key.nr_payload_regs + 1) / 2; j++)
prealloc_reg(c, &c->payload.depth[j], i++);
for (j = 0; j < c->nr_creg; j++)
@@ -101,7 +101,7 @@ static void init_registers( struct brw_wm_compile *c )
assert(nr_interp_regs >= 1);
- c->prog_data.first_curbe_grf = c->key.nr_depth_regs * 2;
+ c->prog_data.first_curbe_grf = ALIGN(c->key.nr_payload_regs, 2);
c->prog_data.urb_read_length = nr_interp_regs * 2;
c->prog_data.curb_read_length = c->nr_creg * 2;
diff --git a/src/mesa/drivers/dri/i965/brw_wm_state.c b/src/mesa/drivers/dri/i965/brw_wm_state.c
index c1cf4db1ca..6699d0a73e 100644
--- a/src/mesa/drivers/dri/i965/brw_wm_state.c
+++ b/src/mesa/drivers/dri/i965/brw_wm_state.c
@@ -104,8 +104,22 @@ wm_unit_populate_key(struct brw_context *brw, struct brw_wm_unit_key *key)
key->uses_kill = fp->UsesKill || ctx->Color.AlphaEnabled;
key->is_glsl = bfp->isGLSL;
- /* temporary sanity check assertion */
- ASSERT(bfp->isGLSL == brw_wm_is_glsl(fp));
+ /* If using the fragment shader backend, the program is always
+ * 8-wide.
+ */
+ if (ctx->Shader.CurrentProgram) {
+ int i;
+
+ for (i = 0; i < ctx->Shader.CurrentProgram->_NumLinkedShaders; i++) {
+ struct brw_shader *shader =
+ (struct brw_shader *)ctx->Shader.CurrentProgram->_LinkedShaders[i];;
+
+ if (shader->base.Type == GL_FRAGMENT_SHADER &&
+ shader->ir != NULL) {
+ key->is_glsl = GL_TRUE;
+ }
+ }
+ }
/* _NEW_DEPTH */
key->stats_wm = intel->stats_wm;
diff --git a/src/mesa/drivers/dri/i965/gen6_cc.c b/src/mesa/drivers/dri/i965/gen6_cc.c
index f7acad6912..26f1070a16 100644
--- a/src/mesa/drivers/dri/i965/gen6_cc.c
+++ b/src/mesa/drivers/dri/i965/gen6_cc.c
@@ -267,9 +267,9 @@ static void upload_cc_state_pointers(struct brw_context *brw)
BEGIN_BATCH(4);
OUT_BATCH(CMD_3D_CC_STATE_POINTERS << 16 | (4 - 2));
- OUT_RELOC(brw->cc.state_bo, I915_GEM_DOMAIN_INSTRUCTION, 0, 1);
OUT_RELOC(brw->cc.blend_state_bo, I915_GEM_DOMAIN_INSTRUCTION, 0, 1);
OUT_RELOC(brw->cc.depth_stencil_state_bo, I915_GEM_DOMAIN_INSTRUCTION, 0, 1);
+ OUT_RELOC(brw->cc.state_bo, I915_GEM_DOMAIN_INSTRUCTION, 0, 1);
ADVANCE_BATCH();
intel_batchbuffer_emit_mi_flush(intel->batch);
diff --git a/src/mesa/drivers/dri/i965/gen6_wm_state.c b/src/mesa/drivers/dri/i965/gen6_wm_state.c
index 863c85449d..2cd640de17 100644
--- a/src/mesa/drivers/dri/i965/gen6_wm_state.c
+++ b/src/mesa/drivers/dri/i965/gen6_wm_state.c
@@ -34,18 +34,59 @@
#include "intel_batchbuffer.h"
static void
+prepare_wm_constants(struct brw_context *brw)
+{
+ struct intel_context *intel = &brw->intel;
+ GLcontext *ctx = &intel->ctx;
+ const struct brw_fragment_program *fp =
+ brw_fragment_program_const(brw->fragment_program);
+
+ drm_intel_bo_unreference(brw->wm.push_const_bo);
+ brw->wm.push_const_bo = NULL;
+
+ /* Updates the ParamaterValues[i] pointers for all parameters of the
+ * basic type of PROGRAM_STATE_VAR.
+ */
+ /* XXX: Should this happen somewhere before to get our state flag set? */
+ _mesa_load_state_parameters(ctx, fp->program.Base.Parameters);
+
+ if (brw->wm.prog_data->nr_params != 0) {
+ float *constants;
+ unsigned int i;
+
+ brw->wm.push_const_bo = drm_intel_bo_alloc(intel->bufmgr,
+ "WM constant_bo",
+ brw->wm.prog_data->nr_params *
+ sizeof(float),
+ 4096);
+ drm_intel_gem_bo_map_gtt(brw->wm.push_const_bo);
+ constants = brw->wm.push_const_bo->virtual;
+ for (i = 0; i < brw->wm.prog_data->nr_params; i++) {
+ constants[i] = *brw->wm.prog_data->param[i];
+ }
+ drm_intel_gem_bo_unmap_gtt(brw->wm.push_const_bo);
+ }
+}
+
+const struct brw_tracked_state gen6_wm_constants = {
+ .dirty = {
+ .mesa = _NEW_PROGRAM_CONSTANTS,
+ .brw = 0,
+ .cache = 0,
+ },
+ .prepare = prepare_wm_constants,
+};
+
+static void
upload_wm_state(struct brw_context *brw)
{
struct intel_context *intel = &brw->intel;
GLcontext *ctx = &intel->ctx;
const struct brw_fragment_program *fp =
brw_fragment_program_const(brw->fragment_program);
- unsigned int nr_params = fp->program.Base.Parameters->NumParameters;
- drm_intel_bo *constant_bo;
- int i;
uint32_t dw2, dw4, dw5, dw6;
- if (fp->use_const_buffer || nr_params == 0) {
+ if (fp->use_const_buffer || brw->wm.prog_data->nr_params == 0) {
/* Disable the push constant buffers. */
BEGIN_BATCH(5);
OUT_BATCH(CMD_3D_CONSTANT_PS_STATE << 16 | (5 - 2));
@@ -55,35 +96,17 @@ upload_wm_state(struct brw_context *brw)
OUT_BATCH(0);
ADVANCE_BATCH();
} else {
- /* Updates the ParamaterValues[i] pointers for all parameters of the
- * basic type of PROGRAM_STATE_VAR.
- */
- _mesa_load_state_parameters(ctx, fp->program.Base.Parameters);
-
- constant_bo = drm_intel_bo_alloc(intel->bufmgr, "WM constant_bo",
- nr_params * 4 * sizeof(float),
- 4096);
- drm_intel_gem_bo_map_gtt(constant_bo);
- for (i = 0; i < nr_params; i++) {
- memcpy((char *)constant_bo->virtual + i * 4 * sizeof(float),
- fp->program.Base.Parameters->ParameterValues[i],
- 4 * sizeof(float));
- }
- drm_intel_gem_bo_unmap_gtt(constant_bo);
-
BEGIN_BATCH(5);
OUT_BATCH(CMD_3D_CONSTANT_PS_STATE << 16 |
GEN6_CONSTANT_BUFFER_0_ENABLE |
(5 - 2));
- OUT_RELOC(constant_bo,
+ OUT_RELOC(brw->wm.push_const_bo,
I915_GEM_DOMAIN_RENDER, 0, /* XXX: bad domain */
- ALIGN(nr_params, 2) / 2 - 1);
+ ALIGN(brw->wm.prog_data->nr_params, 8) / 8 - 1);
OUT_BATCH(0);
OUT_BATCH(0);
OUT_BATCH(0);
ADVANCE_BATCH();
-
- drm_intel_bo_unreference(constant_bo);
}
intel_batchbuffer_emit_mi_flush(intel->batch);