summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Stellard <tstellar@gmail.com>2010-09-29 23:52:49 -0700
committerTom Stellard <tstellar@gmail.com>2010-11-03 02:12:36 -0700
commit8f98b937de93c2cbbdedf5fd93f8637f39cd3c52 (patch)
treebecc2543d451efcabdb699d30aa561b4f6f043f2
parent83f32a43f817a36454671c4c8427075854cff4a8 (diff)
r300/compiler: Convert RGB to alpha in the scheduler.better-sched
-rw-r--r--src/mesa/drivers/dri/r300/compiler/radeon_pair_schedule.c354
-rw-r--r--src/mesa/drivers/dri/r300/compiler/radeon_program.c11
-rw-r--r--src/mesa/drivers/dri/r300/compiler/radeon_program.h1
-rw-r--r--src/mesa/drivers/dri/r300/compiler/radeon_program_pair.h4
-rw-r--r--src/mesa/drivers/dri/r300/compiler/radeon_program_print.c1
5 files changed, 354 insertions, 17 deletions
diff --git a/src/mesa/drivers/dri/r300/compiler/radeon_pair_schedule.c b/src/mesa/drivers/dri/r300/compiler/radeon_pair_schedule.c
index d4a38607d9e..5c0300e63de 100644
--- a/src/mesa/drivers/dri/r300/compiler/radeon_pair_schedule.c
+++ b/src/mesa/drivers/dri/r300/compiler/radeon_pair_schedule.c
@@ -54,6 +54,9 @@ struct schedule_instruction {
* this instruction can be scheduled.
*/
unsigned int NumDependencies:5;
+
+ /*XXX Comment this. */
+ struct rc_reader_data GlobalReaders;
};
@@ -94,6 +97,16 @@ struct register_state {
struct reg_value * Values[4];
};
+struct remap_reg {
+ struct rc_instruciont * Inst;
+ unsigned int OldIndex:(RC_REGISTER_INDEX_BITS+1);
+ unsigned int OldSwizzle:3;
+ unsigned int NewIndex:(RC_REGISTER_INDEX_BITS+1);
+ unsigned int NewSwizzle:3;
+ unsigned int OnlyTexReads:1;
+ struct remap_reg * Next;
+};
+
struct schedule_state {
struct radeon_compiler * C;
struct schedule_instruction * Current;
@@ -110,8 +123,29 @@ struct schedule_state {
struct schedule_instruction *ReadyAlpha;
struct schedule_instruction *ReadyTEX;
/*@}*/
+
+ struct remap_reg * Remaps;
};
+static void print_list(struct schedule_instruction * sinst)
+{
+ struct schedule_instruction * temp;
+ for (temp = sinst; temp; temp = temp->NextReady) {
+ fprintf(stderr, "%u ->", temp->Instruction->IP);
+ }
+}
+
+static void print_ready(struct schedule_state * s)
+{
+ fprintf(stderr, "Full: ");
+ print_list(s->ReadyFullALU);
+ fprintf(stderr, "\nRGB: ");
+ print_list(s->ReadyRGB);
+ fprintf(stderr, "\nAlpha: ");
+ print_list(s->ReadyAlpha);
+ fprintf(stderr, "\n");
+}
+
static struct reg_value ** get_reg_valuep(struct schedule_state * s,
rc_register_file file, unsigned int index, unsigned int chan)
{
@@ -524,6 +558,239 @@ static void presub_nop(struct rc_instruction * emitted) {
}
}
}
+
+struct rgb_to_alpha_data {
+ rc_register_file OldFile;
+ unsigned int OldIndex;
+ unsigned int OldSwizzle;
+ unsigned int NewIndex;
+ unsigned int CantUse;
+};
+
+static void rgb_to_alpha_remap (
+ void * userdata,
+ struct rc_instruction * inst,
+ struct rc_pair_instruction_arg * arg)
+{
+ int new_src_index;
+ unsigned int i;
+ struct rc_pair_instruction_source * old_src =
+ rc_pair_get_src(&inst->U.P, arg);
+ struct rgb_to_alpha_data * d = userdata;
+// if (old_src) fprintf(stderr,"file=%u oldfile=%u index=%u oldindex=%u\n",old_src->File, d->OldFile, old_src->Index, d->OldIndex);
+ if (!old_src || old_src->File != d->OldFile || old_src->Index != d->OldIndex)
+ return;
+
+ for (i = 0; i < 3; i++) {
+ if (get_swz(arg->Swizzle, i) == d->OldSwizzle) {
+// fprintf(stderr, "old swz=%u\n", arg->Swizzle);
+ SET_SWZ(arg->Swizzle, i, RC_SWIZZLE_W);
+// fprintf(stderr, "new swz=%u\n", arg->Swizzle);
+ }
+ }
+ old_src->Used = 0;
+ new_src_index = rc_pair_alloc_source(&inst->U.P, 0, 1, old_src->File,
+ old_src->Index);
+ /* This conversion is not possible, we must have made a mistake in
+ * is_rgb_to_alpha_possible. */
+ /* XXX Error message here: */
+ if (new_src_index < 0) {
+ assert(0);
+ return;
+ }
+
+ arg->Source = new_src_index;
+}
+
+static void is_rgb_to_alpha_possible(
+ void * userdata,
+ struct rc_instruction * inst,
+ struct rc_pair_instruction_arg * arg,
+ struct rc_pair_instruction_source * src)
+{
+ unsigned int chan_count = 0;
+ unsigned int alpha_sources = 0;
+ unsigned int i;
+ struct rc_reader_data * reader_data = userdata;
+
+ /* XXX Function here ? */
+ switch(inst->U.P.RGB.Opcode) {
+ case RC_OPCODE_DDX:
+ case RC_OPCODE_DDY:
+ reader_data->Abort = 1;
+ return;
+ default:
+ break;
+ }
+
+ switch(inst->U.P.Alpha.Opcode) {
+ case RC_OPCODE_DDX:
+ case RC_OPCODE_DDY:
+ reader_data->Abort = 1;
+ return;
+ default:
+ break;
+ }
+
+ if (!src)
+ return;
+
+ /* XXX There are some cases where we can still do the conversion if
+ * a reader reads from a presubtract source, but for now we'll prevent
+ * it. */
+ if (arg->Source == RC_PAIR_PRESUB_SRC) {
+ reader_data->Abort = 1;
+ return;
+ }
+
+ /* XXX Make sure the source only reads from one component.
+ * XXX I think we should be allowed to read from the same swizzle
+ * twice*/
+ for (i = 0; i < 3; i++) {
+ rc_swizzle swz = get_swz(arg->Swizzle, i);
+ switch(swz) {
+ case RC_SWIZZLE_X:
+ case RC_SWIZZLE_Y:
+ case RC_SWIZZLE_Z:
+ case RC_SWIZZLE_W:
+ chan_count++;
+ break;
+ default:
+ break;
+ }
+ }
+// fprintf(stderr, "Chan count = %u\n", chan_count);
+ if (chan_count > 1) {
+ reader_data->Abort = 1;
+ return;
+ }
+
+ /* Make sure there are enough alpha sources */
+ for (i = 0; i < 3; i++) {
+ if (inst->U.P.Alpha.Src[i].Used) {
+ /* XXX Pass NewIndex as callback data here. */
+ /*if (inst->U.P.Alpha.Src[i].File == RC_FILE_TEMPORARY
+ && inst->U.P.Alpha.Src[i].Index == d->NewIndex) {
+ break;
+ }*/
+ alpha_sources++;
+ }
+ }
+ if (alpha_sources > 2) {
+// fprintf(stderr, "not enough alpha sources.\n");
+ reader_data->Abort = 1;
+ return;
+ }
+}
+
+static int convert_rgb_to_alpha(
+ struct schedule_state * s,
+ struct schedule_instruction * sched_inst)
+{
+ struct rc_pair_instruction * pair_inst = &sched_inst->Instruction->U.P;
+ unsigned int old_mask = pair_inst->RGB.WriteMask;
+ struct reg_value * reg = get_reg_value(s, RC_FILE_TEMPORARY,
+ pair_inst->RGB.DestIndex, old_mask);
+ unsigned int old_swz = rc_mask_to_swizzle(old_mask);
+ struct rgb_to_alpha_data d;
+ unsigned int i;
+
+// fprintf(stderr, "Abort = %u Readers = %u\n", sched_inst->GlobalReaders.Abort, sched_inst->GlobalReaders.ReaderCount);
+ if (sched_inst->GlobalReaders.Abort)
+ return 0;
+
+ /* XXX Function here ? */
+ switch(pair_inst->RGB.Opcode) {
+ case RC_OPCODE_DDX:
+ case RC_OPCODE_DDY:
+ return 0;
+ default:
+ break;
+ }
+
+ switch(pair_inst->Alpha.Opcode) {
+ case RC_OPCODE_DDX:
+ case RC_OPCODE_DDY:
+ return 0;
+ default:
+ break;
+ }
+ /* XXX There are more of these. */
+ /* XXX Are these even a problem? */
+ if (pair_inst->RGB.Opcode == RC_OPCODE_DP3) {
+ return 0;
+ }
+ assert(sched_inst->NumWriteValues == 1);
+
+ if (!sched_inst->WriteValues[0]) {
+ assert(0);
+ return 0;
+ }
+
+ /* XXX This is not correct. */
+ d.OldFile = RC_FILE_TEMPORARY;
+ d.OldIndex = pair_inst->RGB.DestIndex;
+ d.OldSwizzle = old_swz;
+ d.CantUse = 1;
+ for (i = 0; i < RC_REGISTER_MAX_INDEX; i++) {
+ /*XXX Is temp file ok here? */
+ struct reg_value ** new_regvalp = get_reg_valuep(
+ s, RC_FILE_TEMPORARY, i, 3);
+ if (!*new_regvalp) {
+ struct reg_value ** old_regvalp =
+ get_reg_valuep(s,
+ RC_FILE_TEMPORARY,
+ d.OldIndex,
+ old_mask);
+ d.CantUse = 0;
+ d.NewIndex = i;
+ *new_regvalp = *old_regvalp;
+ *old_regvalp = NULL;
+ break;
+ }
+ }
+ if (d.CantUse) {
+ return 0;
+ }
+
+// fprintf(stderr, "Converting %u.%u to %u.%u\n", d.OldIndex, d.OldSwizzle,
+// d.NewIndex, RC_SWIZZLE_W);
+ pair_inst->Alpha.Opcode = pair_inst->RGB.Opcode;
+ pair_inst->Alpha.DestIndex = pair_inst->RGB.DestIndex;
+ pair_inst->Alpha.WriteMask = 1;
+ pair_inst->Alpha.Target = pair_inst->RGB.Target;
+ pair_inst->Alpha.OutputWriteMask = pair_inst->RGB.OutputWriteMask;
+ pair_inst->Alpha.DepthWriteMask = pair_inst->RGB.DepthWriteMask;
+ pair_inst->Alpha.Saturate = pair_inst->RGB.Saturate;
+ memcpy(pair_inst->Alpha.Arg, pair_inst->RGB.Arg,
+ sizeof(pair_inst->Alpha.Arg));
+ /*XXX HACK */
+ for (i = 0; i < 3; i++) {
+ unsigned int j;
+ for (j = 0; j < 3; j++) {
+ unsigned int swz = get_swz(pair_inst->Alpha.Arg[i].Swizzle, j);
+ if (swz != RC_SWIZZLE_UNUSED) {
+ pair_inst->Alpha.Arg[i].Swizzle = swz;
+ break;
+ }
+ }
+ }
+ pair_inst->RGB.Opcode = RC_OPCODE_NOP;
+ pair_inst->RGB.DestIndex = 0;
+ pair_inst->RGB.WriteMask = 0;
+ pair_inst->RGB.Target = 0;
+ pair_inst->RGB.OutputWriteMask = 0;
+ pair_inst->RGB.DepthWriteMask = 0;
+ pair_inst->RGB.Saturate = 0;
+ memset(pair_inst->RGB.Arg, 0, sizeof(pair_inst->RGB.Arg));
+
+ for(i = 0; i < sched_inst->GlobalReaders.ReaderCount; i++) {
+ struct rc_reader reader = sched_inst->GlobalReaders.Readers[i];
+ rgb_to_alpha_remap(&d, reader.Inst, reader.U.Arg);
+ }
+ return 1;
+}
+
/**
* Find a good ALU instruction or pair of ALU instruction and emit it.
*
@@ -535,24 +802,17 @@ static void emit_one_alu(struct schedule_state *s, struct rc_instruction * befor
{
struct schedule_instruction * sinst;
- if (s->ReadyFullALU || !(s->ReadyRGB && s->ReadyAlpha)) {
- if (s->ReadyFullALU) {
- sinst = s->ReadyFullALU;
- s->ReadyFullALU = s->ReadyFullALU->NextReady;
- } else if (s->ReadyRGB) {
- sinst = s->ReadyRGB;
- s->ReadyRGB = s->ReadyRGB->NextReady;
- } else {
- sinst = s->ReadyAlpha;
- s->ReadyAlpha = s->ReadyAlpha->NextReady;
- }
-
+// print_ready(s);
+ if (s->ReadyFullALU) {
+ sinst = s->ReadyFullALU;
+ s->ReadyFullALU = s->ReadyFullALU->NextReady;
rc_insert_instruction(before->Prev, sinst->Instruction);
commit_alu_instruction(s, sinst);
} else {
struct schedule_instruction **prgb;
struct schedule_instruction **palpha;
-
+ struct schedule_instruction *prev;
+pair:
/* Some pairings might fail because they require too
* many source slots; try all possible pairings if necessary */
for(prgb = &s->ReadyRGB; *prgb; prgb = &(*prgb)->NextReady) {
@@ -571,10 +831,50 @@ static void emit_one_alu(struct schedule_state *s, struct rc_instruction * befor
goto success;
}
}
-
- /* No success in pairing; just take the first RGB instruction */
- sinst = s->ReadyRGB;
- s->ReadyRGB = s->ReadyRGB->NextReady;
+ prev = NULL;
+ /* No success in pairing, now try to convert one of the RGB
+ * instructions to an Alpha so we can pair it with another RGB.
+ * XXX We should only try this if there is more than one ready RGB
+ * instruction */
+ for(prgb = &s->ReadyRGB; *prgb; prgb = &(*prgb)->NextReady) {
+// fprintf(stderr,"checking...\n");
+ if ((*prgb)->NumWriteValues == 1) {
+ struct schedule_instruction * prgb_next;
+ if (!convert_rgb_to_alpha(s, *prgb))
+ goto cont_loop;
+// fprintf(stderr, "conversion success!\n");
+ prgb_next = (*prgb)->NextReady;
+// fprintf(stderr, "prev: %d cur: %d next: %d\n",
+// prev ? prev->Instruction->IP : -1,
+// (*prgb)->Instruction->IP,
+// prgb_next ? prgb_next->Instruction->IP : -1);
+ /* Add instruction to the Alpha ready list. */
+ (*prgb)->NextReady = s->ReadyAlpha;
+ s->ReadyAlpha = *prgb;
+ /* Remove instruction from the RGB ready list.*/
+ if (prev)
+ prev->NextReady = prgb_next;
+ else
+ s->ReadyRGB = prgb_next;
+// print_ready(s);
+ goto pair;
+ }
+// fprintf(stderr, "setting prev\n");
+cont_loop:
+ prev = *prgb;
+ }
+ /* Still no success in pairing, just take the first RGB
+ * or alpha instruction. */
+ if (s->ReadyRGB) {
+ sinst = s->ReadyRGB;
+ s->ReadyRGB = s->ReadyRGB->NextReady;
+ } else if (s->ReadyAlpha) {
+ sinst = s->ReadyAlpha;
+ s->ReadyAlpha = s->ReadyAlpha->NextReady;
+ } else {
+ /*XXX Something real bad has happened. */
+ assert(0);
+ }
rc_insert_instruction(before->Prev, sinst->Instruction);
commit_alu_instruction(s, sinst);
@@ -651,6 +951,16 @@ static void scan_write(void * data, struct rc_instruction * inst,
}
}
+static void is_rgb_to_alpha_possible_normal(
+ void * userdata,
+ struct rc_instruction * inst,
+ struct rc_src_register * src)
+{
+ struct rc_reader_data * reader_data = userdata;
+ reader_data->Abort = 1;
+
+}
+
static void schedule_block(struct r300_fragment_program_compiler * c,
struct rc_instruction * begin, struct rc_instruction * end)
{
@@ -682,6 +992,11 @@ static void schedule_block(struct r300_fragment_program_compiler * c,
if (!s.Current->NumDependencies)
instruction_ready(&s, s.Current);
+
+ /* Get global readers for possible RGB->Alpha conversion. */
+ rc_get_readers(s.C, inst, &s.Current->GlobalReaders,
+ is_rgb_to_alpha_possible_normal,
+ is_rgb_to_alpha_possible, NULL);
}
/* Temporarily unlink all instructions */
@@ -710,8 +1025,13 @@ static int is_controlflow(struct rc_instruction * inst)
void rc_pair_schedule(struct radeon_compiler *cc, void *user)
{
+ struct schedule_state s;
+
struct r300_fragment_program_compiler *c = (struct r300_fragment_program_compiler*)cc;
struct rc_instruction * inst = c->Base.Program.Instructions.Next;
+
+ memset(&s, 0, sizeof(s));
+ s.C = &c->Base;
while(inst != &c->Base.Program.Instructions) {
struct rc_instruction * first;
diff --git a/src/mesa/drivers/dri/r300/compiler/radeon_program.c b/src/mesa/drivers/dri/r300/compiler/radeon_program.c
index 24b685fbeb4..14dade9be78 100644
--- a/src/mesa/drivers/dri/r300/compiler/radeon_program.c
+++ b/src/mesa/drivers/dri/r300/compiler/radeon_program.c
@@ -182,3 +182,14 @@ unsigned int rc_recompute_ips(struct radeon_compiler * c)
return ip;
}
+
+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;
+ default: return RC_SWIZZLE_UNUSED;
+ }
+}
diff --git a/src/mesa/drivers/dri/r300/compiler/radeon_program.h b/src/mesa/drivers/dri/r300/compiler/radeon_program.h
index f0a77d7b539..b0ded82f1a0 100644
--- a/src/mesa/drivers/dri/r300/compiler/radeon_program.h
+++ b/src/mesa/drivers/dri/r300/compiler/radeon_program.h
@@ -233,4 +233,5 @@ unsigned int rc_recompute_ips(struct radeon_compiler * c);
void rc_print_program(const struct rc_program *prog);
+rc_swizzle rc_mask_to_swizzle(unsigned int mask);
#endif
diff --git a/src/mesa/drivers/dri/r300/compiler/radeon_program_pair.h b/src/mesa/drivers/dri/r300/compiler/radeon_program_pair.h
index 54d44a2098b..54ca56762b1 100644
--- a/src/mesa/drivers/dri/r300/compiler/radeon_program_pair.h
+++ b/src/mesa/drivers/dri/r300/compiler/radeon_program_pair.h
@@ -118,6 +118,10 @@ void rc_pair_foreach_source_that_rgb_reads(
unsigned int rc_source_type_that_arg_reads(
unsigned int source,
unsigned int swizzle);
+
+struct rc_pair_instruction_source * rc_pair_get_src(
+ struct rc_pair_instruction * pair_inst,
+ struct rc_pair_instruction_arg * arg);
/*@}*/
diff --git a/src/mesa/drivers/dri/r300/compiler/radeon_program_print.c b/src/mesa/drivers/dri/r300/compiler/radeon_program_print.c
index 618ab5a099b..ae13f6742f8 100644
--- a/src/mesa/drivers/dri/r300/compiler/radeon_program_print.c
+++ b/src/mesa/drivers/dri/r300/compiler/radeon_program_print.c
@@ -129,6 +129,7 @@ static char rc_swizzle_char(unsigned int swz)
case RC_SWIZZLE_HALF: return 'H';
case RC_SWIZZLE_UNUSED: return '_';
}
+ fprintf(stderr, "bad swz: %u\n", swz);
return '?';
}