summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/mesa/drivers/dri/r300/compiler/r300_fragprog_swizzle.c12
-rw-r--r--src/mesa/drivers/dri/r300/compiler/r300_fragprog_swizzle.h1
-rw-r--r--src/mesa/drivers/dri/r300/compiler/radeon_compiler_util.c35
-rw-r--r--src/mesa/drivers/dri/r300/compiler/radeon_compiler_util.h8
-rw-r--r--src/mesa/drivers/dri/r300/compiler/radeon_pair_regalloc.c88
-rw-r--r--src/mesa/drivers/dri/r300/compiler/radeon_variable.c17
6 files changed, 120 insertions, 41 deletions
diff --git a/src/mesa/drivers/dri/r300/compiler/r300_fragprog_swizzle.c b/src/mesa/drivers/dri/r300/compiler/r300_fragprog_swizzle.c
index 5223aaa71a4..603818f78fc 100644
--- a/src/mesa/drivers/dri/r300/compiler/r300_fragprog_swizzle.c
+++ b/src/mesa/drivers/dri/r300/compiler/r300_fragprog_swizzle.c
@@ -87,6 +87,18 @@ static const struct swizzle_data* lookup_native_swizzle(unsigned int swizzle)
return 0;
}
+/**
+ * Determines if the given swizzle is valid for r300/r400. In most situations
+ * it is better to use r300_swizzle_is_native() which can be accesed via
+ * struct radeon_compiler *c; c->SwizzleCaps->IsNative().
+ */
+int r300_swizzle_is_native_basic(unsigned int swizzle)
+{
+ if(lookup_native_swizzle(swizzle))
+ return 1;
+ else
+ return 0;
+}
/**
* Check whether the given instruction supports the swizzle and negate
diff --git a/src/mesa/drivers/dri/r300/compiler/r300_fragprog_swizzle.h b/src/mesa/drivers/dri/r300/compiler/r300_fragprog_swizzle.h
index 118476af132..f2635be140d 100644
--- a/src/mesa/drivers/dri/r300/compiler/r300_fragprog_swizzle.h
+++ b/src/mesa/drivers/dri/r300/compiler/r300_fragprog_swizzle.h
@@ -34,5 +34,6 @@ extern struct rc_swizzle_caps r300_swizzle_caps;
unsigned int r300FPTranslateRGBSwizzle(unsigned int src, unsigned int swizzle);
unsigned int r300FPTranslateAlphaSwizzle(unsigned int src, unsigned int swizzle);
+int r300_swizzle_is_native_basic(unsigned int swizzle);
#endif /* __R300_FRAGPROG_SWIZZLE_H_ */
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 3a6b0a7af15..b077e7b7d65 100644
--- a/src/mesa/drivers/dri/r300/compiler/radeon_compiler_util.c
+++ b/src/mesa/drivers/dri/r300/compiler/radeon_compiler_util.c
@@ -141,7 +141,11 @@ static unsigned int srcs_need_rewrite(const struct rc_opcode_info * info)
}
}
-static unsigned int adjust_channels(
+/**
+ * @return A swizzle the results from converting old_swizzle using
+ * conversion_swizzle
+ */
+unsigned int rc_adjust_channels(
unsigned int old_swizzle,
unsigned int conversion_swizzle)
{
@@ -197,7 +201,8 @@ void rc_pair_rewrite_writemask(
for (i = 0; i < info->NumSrcRegs; i++) {
sub->Arg[i].Swizzle =
- adjust_channels(sub->Arg[i].Swizzle, conversion_swizzle);
+ rc_adjust_channels(sub->Arg[i].Swizzle,
+ conversion_swizzle);
}
}
@@ -207,7 +212,7 @@ static void normal_rewrite_writemask_cb(
struct rc_src_register * src)
{
unsigned int * new_mask = (unsigned int *)userdata;
- src->Swizzle = adjust_channels(src->Swizzle, *new_mask);
+ src->Swizzle = rc_adjust_channels(src->Swizzle, *new_mask);
}
/**
@@ -605,3 +610,27 @@ struct rc_instruction * rc_match_bgnloop(struct rc_instruction * bgnloop)
}
return NULL;
}
+
+/**
+ * @return A conversion swizzle for converting from old_mask->new_mask
+ */
+unsigned int rc_make_conversion_swizzle(
+ unsigned int old_mask,
+ unsigned int new_mask)
+{
+ unsigned int conversion_swizzle = rc_init_swizzle(RC_SWIZZLE_UNUSED, 0);
+ unsigned int old_idx;
+ unsigned int new_idx = 0;
+ for (old_idx = 0; old_idx < 4; old_idx++) {
+ if (!GET_BIT(old_mask, old_idx))
+ continue;
+ for ( ; new_idx < 4; new_idx++) {
+ if (GET_BIT(new_mask, new_idx)) {
+ SET_SWZ(conversion_swizzle, old_idx, new_idx);
+ new_idx++;
+ break;
+ }
+ }
+ }
+ return conversion_swizzle;
+}
diff --git a/src/mesa/drivers/dri/r300/compiler/radeon_compiler_util.h b/src/mesa/drivers/dri/r300/compiler/radeon_compiler_util.h
index 1a0b96242e0..2af289dfabd 100644
--- a/src/mesa/drivers/dri/r300/compiler/radeon_compiler_util.h
+++ b/src/mesa/drivers/dri/r300/compiler/radeon_compiler_util.h
@@ -27,6 +27,10 @@ rc_swizzle rc_mask_to_swizzle(unsigned int mask);
unsigned swizzle_mask(unsigned swizzle, unsigned mask);
+unsigned int rc_adjust_channels(
+ unsigned int old_swizzle,
+ unsigned int conversion_swizzle);
+
void rc_pair_rewrite_writemask(
struct rc_pair_sub_instruction * sub,
unsigned int conversion_swizzle);
@@ -78,4 +82,8 @@ rc_opcode rc_get_flow_control_inst(struct rc_instruction * inst);
struct rc_instruction * rc_match_endloop(struct rc_instruction * endloop);
struct rc_instruction * rc_match_bgnloop(struct rc_instruction * bgnloop);
+unsigned int rc_make_conversion_swizzle(
+ unsigned int old_mask,
+ unsigned int new_mask);
+
#endif /* RADEON_PROGRAM_UTIL_H */
diff --git a/src/mesa/drivers/dri/r300/compiler/radeon_pair_regalloc.c b/src/mesa/drivers/dri/r300/compiler/radeon_pair_regalloc.c
index fd03c73b324..828c7533a01 100644
--- a/src/mesa/drivers/dri/r300/compiler/radeon_pair_regalloc.c
+++ b/src/mesa/drivers/dri/r300/compiler/radeon_pair_regalloc.c
@@ -34,6 +34,7 @@
#include "program/register_allocate.h"
#include "ralloc.h"
+#include "r300_fragprog_swizzle.h"
#include "radeon_compiler.h"
#include "radeon_compiler_util.h"
#include "radeon_dataflow.h"
@@ -232,6 +233,26 @@ static unsigned int is_derivative(rc_opcode op)
return (op == RC_OPCODE_DDX || op == RC_OPCODE_DDY);
}
+static int find_class(
+ struct rc_class * classes,
+ unsigned int writemask,
+ unsigned int max_writemask_count)
+{
+ unsigned int i;
+ for (i = 0; i < RC_REG_CLASS_COUNT; i++) {
+ unsigned int j;
+ if (classes[i].WritemaskCount > max_writemask_count) {
+ continue;
+ }
+ for (j = 0; j < 3; j++) {
+ if (classes[i].Writemasks[j] == writemask) {
+ return i;
+ }
+ }
+ }
+ return -1;
+}
+
static enum rc_reg_class variable_get_class(
struct rc_variable * variable,
struct rc_class * classes)
@@ -240,25 +261,48 @@ static enum rc_reg_class variable_get_class(
unsigned int can_change_writemask= 1;
unsigned int writemask = rc_variable_writemask_sum(variable);
struct rc_list * readers = rc_variable_readers_union(variable);
+ int class_index;
if (!variable->C->is_r500) {
- unsigned int mask_count = 0;
+ struct rc_class c;
/* The assumption here is that if an instruction has type
* RC_INSTRUCTION_NORMAL then it is a TEX instruction.
* r300 and r400 can't swizzle the result of a TEX lookup. */
if (variable->Inst->Type == RC_INSTRUCTION_NORMAL) {
writemask = RC_MASK_XYZW;
}
- for (i = 0; i < 4; i++) {
- if (GET_BIT(writemask, i)) {
- mask_count++;
- }
+
+ /* Check if it is possible to do swizzle packing for r300/r400
+ * without creating non-native swizzles. */
+ class_index = find_class(classes, writemask, 3);
+ if (class_index < 0) {
+ goto error;
}
- /* XXX We should do swizzle packing for r300 and r400 here.
- * We need to figure out how not to create non-native
- * swizzles. */
- if (mask_count > 1) {
- can_change_writemask = 0;
+ c = classes[class_index];
+ for (i = 0; i < c.WritemaskCount; i++) {
+ int j;
+ unsigned int conversion_swizzle =
+ rc_make_conversion_swizzle(
+ writemask, c.Writemasks[i]);
+ for (j = 0; j < variable->ReaderCount; j++) {
+ unsigned int old_swizzle;
+ unsigned int new_swizzle;
+ struct rc_reader r = variable->Readers[j];
+ if (r.Inst->Type == RC_INSTRUCTION_PAIR ) {
+ old_swizzle = r.U.P.Arg->Swizzle;
+ } else {
+ old_swizzle = r.U.I.Src->Swizzle;
+ }
+ new_swizzle = rc_adjust_channels(
+ old_swizzle, conversion_swizzle);
+ if (!r300_swizzle_is_native_basic(new_swizzle)) {
+ can_change_writemask = 0;
+ break;
+ }
+ }
+ if (!can_change_writemask) {
+ break;
+ }
}
}
@@ -285,20 +329,18 @@ static enum rc_reg_class variable_get_class(
}
}
}
- for (i = 0; i < RC_REG_CLASS_COUNT; i++) {
- unsigned int j;
- if (!can_change_writemask && classes[i].WritemaskCount > 1) {
- continue;
- }
- for (j = 0; j < 3; j++) {
- if (classes[i].Writemasks[j] == writemask) {
- return classes[i].Class;
- }
- }
- }
- rc_error(variable->C, "Could not find class for index=%u mask=%u\n",
+
+ class_index = find_class(classes, writemask,
+ can_change_writemask ? 3 : 1);
+ if (class_index > -1) {
+ return classes[class_index].Class;
+ } else {
+error:
+ rc_error(variable->C,
+ "Could not find class for index=%u mask=%u\n",
variable->Dst.Index, writemask);
- return 0;
+ return 0;
+ }
}
static unsigned int overlap_live_intervals_array(
diff --git a/src/mesa/drivers/dri/r300/compiler/radeon_variable.c b/src/mesa/drivers/dri/r300/compiler/radeon_variable.c
index 082717ed5eb..16fa5d28902 100644
--- a/src/mesa/drivers/dri/r300/compiler/radeon_variable.c
+++ b/src/mesa/drivers/dri/r300/compiler/radeon_variable.c
@@ -44,24 +44,11 @@ void rc_variable_change_dst(
unsigned int new_index,
unsigned int new_writemask)
{
- unsigned int new_idx, old_idx;
- unsigned int conversion_swizzle = rc_init_swizzle(RC_SWIZZLE_UNUSED, 0);
struct rc_variable * var_ptr;
struct rc_list * readers;
unsigned int old_mask = rc_variable_writemask_sum(var);
-
- new_idx = 0;
- for (old_idx = 0; old_idx < 4; old_idx++) {
- if (!GET_BIT(old_mask, old_idx))
- continue;
- for ( ; new_idx < 4; new_idx++) {
- if (GET_BIT(new_writemask, new_idx)) {
- SET_SWZ(conversion_swizzle, old_idx, new_idx);
- new_idx++;
- break;
- }
- }
- }
+ unsigned int conversion_swizzle =
+ rc_make_conversion_swizzle(old_mask, new_writemask);
for (var_ptr = var; var_ptr; var_ptr = var_ptr->Friend) {
if (var_ptr->Inst->Type == RC_INSTRUCTION_NORMAL) {