summaryrefslogtreecommitdiff
path: root/src/mesa/drivers/dri/r300/compiler/radeon_compiler_util.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mesa/drivers/dri/r300/compiler/radeon_compiler_util.c')
-rw-r--r--src/mesa/drivers/dri/r300/compiler/radeon_compiler_util.c207
1 files changed, 207 insertions, 0 deletions
diff --git a/src/mesa/drivers/dri/r300/compiler/radeon_compiler_util.c b/src/mesa/drivers/dri/r300/compiler/radeon_compiler_util.c
index 97f4c75849..bf393a9fb1 100644
--- a/src/mesa/drivers/dri/r300/compiler/radeon_compiler_util.c
+++ b/src/mesa/drivers/dri/r300/compiler/radeon_compiler_util.c
@@ -31,6 +31,8 @@
#include "radeon_compiler_util.h"
+#include "radeon_compiler.h"
+#include "radeon_dataflow.h"
/**
*/
unsigned int rc_swizzle_to_writemask(unsigned int swz)
@@ -46,6 +48,91 @@ unsigned int rc_swizzle_to_writemask(unsigned int swz)
return mask;
}
+rc_swizzle get_swz(unsigned int swz, rc_swizzle idx)
+{
+ if (idx & 0x4)
+ return idx;
+ return GET_SWZ(swz, idx);
+}
+
+unsigned int combine_swizzles4(unsigned int src,
+ rc_swizzle swz_x, rc_swizzle swz_y, rc_swizzle swz_z, rc_swizzle swz_w)
+{
+ unsigned int ret = 0;
+
+ ret |= get_swz(src, swz_x);
+ ret |= get_swz(src, swz_y) << 3;
+ ret |= get_swz(src, swz_z) << 6;
+ ret |= get_swz(src, swz_w) << 9;
+
+ return ret;
+}
+
+unsigned int combine_swizzles(unsigned int src, unsigned int swz)
+{
+ unsigned int ret = 0;
+
+ ret |= get_swz(src, GET_SWZ(swz, RC_SWIZZLE_X));
+ ret |= get_swz(src, GET_SWZ(swz, RC_SWIZZLE_Y)) << 3;
+ ret |= get_swz(src, GET_SWZ(swz, RC_SWIZZLE_Z)) << 6;
+ ret |= get_swz(src, GET_SWZ(swz, RC_SWIZZLE_W)) << 9;
+
+ return ret;
+}
+
+/**
+ * @param mask Must be either RC_MASK_X, RC_MASK_Y, RC_MASK_Z, or RC_MASK_W
+ */
+rc_swizzle rc_mask_to_swizzle(unsigned int mask)
+{
+ switch (mask) {
+ case RC_MASK_X: return RC_SWIZZLE_X;
+ case RC_MASK_Y: return RC_SWIZZLE_Y;
+ case RC_MASK_Z: return RC_SWIZZLE_Z;
+ case RC_MASK_W: return RC_SWIZZLE_W;
+ }
+ return RC_SWIZZLE_UNUSED;
+}
+
+/* Reorder mask bits according to swizzle. */
+unsigned swizzle_mask(unsigned swizzle, unsigned mask)
+{
+ unsigned ret = 0;
+ for (unsigned chan = 0; chan < 4; ++chan) {
+ unsigned swz = GET_SWZ(swizzle, chan);
+ if (swz < 4)
+ ret |= GET_BIT(mask, swz) << chan;
+ }
+ return ret;
+}
+
+/**
+ * Left multiplication of a register with a swizzle
+ */
+struct rc_src_register lmul_swizzle(unsigned int swizzle, struct rc_src_register srcreg)
+{
+ struct rc_src_register tmp = srcreg;
+ int i;
+ tmp.Swizzle = 0;
+ tmp.Negate = 0;
+ for(i = 0; i < 4; ++i) {
+ rc_swizzle swz = GET_SWZ(swizzle, i);
+ if (swz < 4) {
+ tmp.Swizzle |= GET_SWZ(srcreg.Swizzle, swz) << (i*3);
+ tmp.Negate |= GET_BIT(srcreg.Negate, swz) << i;
+ } else {
+ tmp.Swizzle |= swz << (i*3);
+ }
+ }
+ return tmp;
+}
+
+void reset_srcreg(struct rc_src_register* reg)
+{
+ memset(reg, 0, sizeof(struct rc_src_register));
+ reg->Swizzle = RC_SWIZZLE_XYZW;
+}
+
unsigned int rc_src_reads_dst_mask(
rc_register_file src_file,
unsigned int src_idx,
@@ -59,3 +146,123 @@ unsigned int rc_src_reads_dst_mask(
}
return dst_mask & rc_swizzle_to_writemask(src_swz);
}
+
+unsigned int rc_source_type_swz(unsigned int swizzle, unsigned int channels)
+{
+ unsigned int chan;
+ unsigned int swz = RC_SWIZZLE_UNUSED;
+ unsigned int ret = RC_SOURCE_NONE;
+
+ for(chan = 0; chan < channels; chan++) {
+ swz = GET_SWZ(swizzle, chan);
+ if (swz == RC_SWIZZLE_W) {
+ ret |= RC_SOURCE_ALPHA;
+ } else if (swz == RC_SWIZZLE_X || swz == RC_SWIZZLE_Y
+ || swz == RC_SWIZZLE_Z) {
+ ret |= RC_SOURCE_RGB;
+ }
+ }
+ return ret;
+}
+
+unsigned int rc_source_type_mask(unsigned int mask)
+{
+ unsigned int ret = RC_SOURCE_NONE;
+
+ if (mask & RC_MASK_XYZ)
+ ret |= RC_SOURCE_RGB;
+
+ if (mask & RC_MASK_W)
+ ret |= RC_SOURCE_ALPHA;
+
+ return ret;
+}
+
+struct can_use_presub_data {
+ struct rc_src_register RemoveSrcs[3];
+ unsigned int RGBCount;
+ unsigned int AlphaCount;
+};
+
+static void can_use_presub_read_cb(
+ void * userdata,
+ struct rc_instruction * inst,
+ rc_register_file file,
+ unsigned int index,
+ unsigned int mask)
+{
+ struct can_use_presub_data * d = userdata;
+ unsigned int src_type = rc_source_type_mask(mask);
+ unsigned int i;
+
+ if (file == RC_FILE_NONE)
+ return;
+
+ for(i = 0; i < 3; i++) {
+ if (d->RemoveSrcs[i].File == file
+ && d->RemoveSrcs[i].Index == index) {
+ src_type &=
+ ~rc_source_type_swz(d->RemoveSrcs[i].Swizzle, 4);
+ }
+ }
+
+ if (src_type & RC_SOURCE_RGB)
+ d->RGBCount++;
+
+ if (src_type & RC_SOURCE_ALPHA)
+ d->AlphaCount++;
+}
+
+unsigned int rc_inst_can_use_presub(
+ struct rc_instruction * inst,
+ rc_presubtract_op presub_op,
+ unsigned int presub_writemask,
+ struct rc_src_register replace_reg,
+ struct rc_src_register presub_src0,
+ struct rc_src_register presub_src1)
+{
+ struct can_use_presub_data d;
+ unsigned int num_presub_srcs;
+ unsigned int presub_src_type = rc_source_type_mask(presub_writemask);
+ const struct rc_opcode_info * info =
+ rc_get_opcode_info(inst->U.I.Opcode);
+
+ if (presub_op == RC_PRESUB_NONE) {
+ return 1;
+ }
+
+ if (info->HasTexture) {
+ return 0;
+ }
+
+ /* We can't use more than one presubtract value in an
+ * instruction, unless the two prsubtract operations
+ * are the same and read from the same registers.
+ * XXX For now we will limit instructions to only one presubtract
+ * value.*/
+ if (inst->U.I.PreSub.Opcode != RC_PRESUB_NONE) {
+ return 0;
+ }
+
+ memset(&d, 0, sizeof(d));
+ d.RemoveSrcs[0] = replace_reg;
+ d.RemoveSrcs[1] = presub_src0;
+ d.RemoveSrcs[2] = presub_src1;
+
+ rc_for_all_reads_mask(inst, can_use_presub_read_cb, &d);
+
+ num_presub_srcs = rc_presubtract_src_reg_count(presub_op);
+
+ if ((presub_src_type & RC_SOURCE_RGB)
+ && d.RGBCount + num_presub_srcs > 3) {
+ return 0;
+ }
+
+ if ((presub_src_type & RC_SOURCE_ALPHA)
+ && d.AlphaCount + num_presub_srcs > 3) {
+ return 0;
+ }
+
+ return 1;
+}
+