}
}
-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)
{
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);
}
}
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);
}
/**
}
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;
+}
#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"
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)
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;
+ }
}
}
}
}
}
- 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(
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) {