aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/mesa/drivers/dri/i965/brw_defines.h8
-rw-r--r--src/mesa/drivers/dri/i965/brw_eu.h4
-rw-r--r--src/mesa/drivers/dri/i965/brw_eu_emit.c72
-rw-r--r--src/mesa/drivers/dri/i965/brw_fs_generator.cpp4
-rw-r--r--src/mesa/drivers/dri/i965/brw_shader.cpp2
-rw-r--r--src/mesa/drivers/dri/i965/brw_vec4_generator.cpp4
6 files changed, 94 insertions, 0 deletions
diff --git a/src/mesa/drivers/dri/i965/brw_defines.h b/src/mesa/drivers/dri/i965/brw_defines.h
index 5072e680db1..7b5dd45edc5 100644
--- a/src/mesa/drivers/dri/i965/brw_defines.h
+++ b/src/mesa/drivers/dri/i965/brw_defines.h
@@ -919,6 +919,14 @@ enum opcode {
SHADER_OPCODE_URB_WRITE_SIMD8,
/**
+ * Return the index of an arbitrary live channel (i.e. one of the channels
+ * enabled in the current execution mask) and assign it to the first
+ * component of the destination. Expected to be used as input for the
+ * BROADCAST pseudo-opcode.
+ */
+ SHADER_OPCODE_FIND_LIVE_CHANNEL,
+
+ /**
* Pick the channel from its first source register given by the index
* specified as second source. Useful for variable indexing of surfaces.
*/
diff --git a/src/mesa/drivers/dri/i965/brw_eu.h b/src/mesa/drivers/dri/i965/brw_eu.h
index a0c938a142b..0e7be1e1ea0 100644
--- a/src/mesa/drivers/dri/i965/brw_eu.h
+++ b/src/mesa/drivers/dri/i965/brw_eu.h
@@ -462,6 +462,10 @@ brw_pixel_interpolator_query(struct brw_codegen *p,
unsigned response_length);
void
+brw_find_live_channel(struct brw_codegen *p,
+ struct brw_reg dst);
+
+void
brw_broadcast(struct brw_codegen *p,
struct brw_reg dst,
struct brw_reg src,
diff --git a/src/mesa/drivers/dri/i965/brw_eu_emit.c b/src/mesa/drivers/dri/i965/brw_eu_emit.c
index 73bed49ecee..e78d0bec268 100644
--- a/src/mesa/drivers/dri/i965/brw_eu_emit.c
+++ b/src/mesa/drivers/dri/i965/brw_eu_emit.c
@@ -3213,6 +3213,78 @@ brw_pixel_interpolator_query(struct brw_codegen *p,
}
void
+brw_find_live_channel(struct brw_codegen *p, struct brw_reg dst)
+{
+ const struct brw_device_info *devinfo = p->devinfo;
+ brw_inst *inst;
+
+ assert(devinfo->gen >= 7);
+
+ brw_push_insn_state(p);
+
+ if (brw_inst_access_mode(devinfo, p->current) == BRW_ALIGN_1) {
+ brw_set_default_mask_control(p, BRW_MASK_DISABLE);
+
+ if (devinfo->gen >= 8) {
+ /* Getting the first active channel index is easy on Gen8: Just find
+ * the first bit set in the mask register. The same register exists
+ * on HSW already but it reads back as all ones when the current
+ * instruction has execution masking disabled, so it's kind of
+ * useless.
+ */
+ inst = brw_FBL(p, vec1(dst),
+ retype(brw_mask_reg(0), BRW_REGISTER_TYPE_UD));
+
+ /* Quarter control has the effect of magically shifting the value of
+ * this register. Make sure it's set to zero.
+ */
+ brw_inst_set_qtr_control(devinfo, inst, GEN6_COMPRESSION_1Q);
+ } else {
+ const struct brw_reg flag = retype(brw_flag_reg(1, 0),
+ BRW_REGISTER_TYPE_UD);
+
+ brw_MOV(p, flag, brw_imm_ud(0));
+
+ /* Run a 16-wide instruction returning zero with execution masking
+ * and a conditional modifier enabled in order to get the current
+ * execution mask in f1.0.
+ */
+ inst = brw_MOV(p, brw_null_reg(), brw_imm_ud(0));
+ brw_inst_set_exec_size(devinfo, inst, BRW_EXECUTE_16);
+ brw_inst_set_mask_control(devinfo, inst, BRW_MASK_ENABLE);
+ brw_inst_set_cond_modifier(devinfo, inst, BRW_CONDITIONAL_Z);
+ brw_inst_set_flag_reg_nr(devinfo, inst, 1);
+
+ brw_FBL(p, vec1(dst), flag);
+ }
+ } else {
+ brw_set_default_mask_control(p, BRW_MASK_DISABLE);
+
+ if (devinfo->gen >= 8) {
+ /* In SIMD4x2 mode the first active channel index is just the
+ * negation of the first bit of the mask register.
+ */
+ inst = brw_AND(p, brw_writemask(dst, WRITEMASK_X),
+ negate(retype(brw_mask_reg(0), BRW_REGISTER_TYPE_UD)),
+ brw_imm_ud(1));
+
+ } else {
+ /* Overwrite the destination without and with execution masking to
+ * find out which of the channels is active.
+ */
+ brw_MOV(p, brw_writemask(vec4(dst), WRITEMASK_X),
+ brw_imm_ud(1));
+
+ inst = brw_MOV(p, brw_writemask(vec4(dst), WRITEMASK_X),
+ brw_imm_ud(0));
+ brw_inst_set_mask_control(devinfo, inst, BRW_MASK_ENABLE);
+ }
+ }
+
+ brw_pop_insn_state(p);
+}
+
+void
brw_broadcast(struct brw_codegen *p,
struct brw_reg dst,
struct brw_reg src,
diff --git a/src/mesa/drivers/dri/i965/brw_fs_generator.cpp b/src/mesa/drivers/dri/i965/brw_fs_generator.cpp
index 2c6a12e4bec..d476c92b73a 100644
--- a/src/mesa/drivers/dri/i965/brw_fs_generator.cpp
+++ b/src/mesa/drivers/dri/i965/brw_fs_generator.cpp
@@ -2061,6 +2061,10 @@ fs_generator::generate_code(const cfg_t *cfg, int dispatch_width)
generate_set_simd4x2_offset(inst, dst, src[0]);
break;
+ case SHADER_OPCODE_FIND_LIVE_CHANNEL:
+ brw_find_live_channel(p, dst);
+ break;
+
case SHADER_OPCODE_BROADCAST:
brw_broadcast(p, dst, src[0], src[1]);
break;
diff --git a/src/mesa/drivers/dri/i965/brw_shader.cpp b/src/mesa/drivers/dri/i965/brw_shader.cpp
index 1944c2648c8..c1fd859fef5 100644
--- a/src/mesa/drivers/dri/i965/brw_shader.cpp
+++ b/src/mesa/drivers/dri/i965/brw_shader.cpp
@@ -517,6 +517,8 @@ brw_instruction_name(enum opcode op)
case SHADER_OPCODE_URB_WRITE_SIMD8:
return "gen8_urb_write_simd8";
+ case SHADER_OPCODE_FIND_LIVE_CHANNEL:
+ return "find_live_channel";
case SHADER_OPCODE_BROADCAST:
return "broadcast";
diff --git a/src/mesa/drivers/dri/i965/brw_vec4_generator.cpp b/src/mesa/drivers/dri/i965/brw_vec4_generator.cpp
index 3dc808c85ee..9d37c93bfa4 100644
--- a/src/mesa/drivers/dri/i965/brw_vec4_generator.cpp
+++ b/src/mesa/drivers/dri/i965/brw_vec4_generator.cpp
@@ -1512,6 +1512,10 @@ vec4_generator::generate_code(const cfg_t *cfg)
brw_memory_fence(p, dst);
break;
+ case SHADER_OPCODE_FIND_LIVE_CHANNEL:
+ brw_find_live_channel(p, dst);
+ break;
+
case SHADER_OPCODE_BROADCAST:
brw_broadcast(p, dst, src[0], src[1]);
break;