diff options
author | Tom Stellard <tstellar@gmail.com> | 2010-09-29 23:52:49 -0700 |
---|---|---|
committer | Tom Stellard <tstellar@gmail.com> | 2010-11-03 02:12:36 -0700 |
commit | 8f98b937de93c2cbbdedf5fd93f8637f39cd3c52 (patch) | |
tree | becc2543d451efcabdb699d30aa561b4f6f043f2 | |
parent | 83f32a43f817a36454671c4c8427075854cff4a8 (diff) |
r300/compiler: Convert RGB to alpha in the scheduler.better-sched
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 '?'; } |