From: Tom Stellard Date: Sun, 23 Oct 2011 01:30:46 +0000 (-0700) Subject: r300/compiler: Fix scheduler bug causing texture corruption X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=17a1c0cb0d9e04607c1726d04ef23485979dfc98;p=mesa.git r300/compiler: Fix scheduler bug causing texture corruption We weren't setting TEX_SEM_WAIT on instructions that read the value of a TEX instruction and also wrote the same register as the TEX instruction. This is the sequence we were miscompiling: 1: TEX temp[0], input[2].xy__, 2D[0] ... 16: src0.xyz = temp[22], src1.xyz = temp[0], src2.xyz = temp[19] MAD temp[0].xyz, src0.xxx, src1.xyz, src2.xxx https://bugs.freedesktop.org/show_bug.cgi?id=42090 --- diff --git a/src/gallium/drivers/r300/compiler/radeon_pair_schedule.c b/src/gallium/drivers/r300/compiler/radeon_pair_schedule.c index b3b0f6fc25b..fa2e80f238c 100644 --- a/src/gallium/drivers/r300/compiler/radeon_pair_schedule.c +++ b/src/gallium/drivers/r300/compiler/radeon_pair_schedule.c @@ -132,6 +132,9 @@ struct remap_reg { struct schedule_state { struct radeon_compiler * C; struct schedule_instruction * Current; + /** Array of the previous writers of Current's destination register + * indexed by channel. */ + struct schedule_instruction * PrevWriter[4]; struct register_state Temporary[RC_REGISTER_MAX_INDEX]; @@ -1137,6 +1140,19 @@ static void emit_one_alu(struct schedule_state *s, struct rc_instruction * befor presub_nop(before->Prev); } +static void add_tex_reader( + struct schedule_state * s, + struct schedule_instruction * writer, + struct schedule_instruction * reader) +{ + if (!writer || writer->Instruction->Type != RC_INSTRUCTION_NORMAL) { + /*Not a TEX instructions */ + return; + } + reader->TexReadCount++; + rc_list_add(&writer->TexReaders, rc_list(&s->C->Pool, reader)); +} + static void scan_read(void * data, struct rc_instruction * inst, rc_register_file file, unsigned int index, unsigned int chan) { @@ -1150,7 +1166,22 @@ static void scan_read(void * data, struct rc_instruction * inst, if (*v && (*v)->Writer == s->Current) { /* The instruction reads and writes to a register component. * In this case, we only want to increment dependencies by one. + * Why? + * Because each instruction depends on the writers of its source + * registers _and_ the most recent writer of its destination + * register. In this case, the current instruction (s->Current) + * has a dependency that both writes to one of its source + * registers and was the most recent writer to its destination + * register. We have already marked this dependency in + * scan_write(), so we don't need to do it again. + */ + + /* We need to make sure we are adding s->Current to the + * previous writer's list of TexReaders, if the previous writer + * was a TEX instruction. */ + add_tex_reader(s, s->PrevWriter[chan], s->Current); + return; } @@ -1171,12 +1202,7 @@ static void scan_read(void * data, struct rc_instruction * inst, /* Only update the current instruction's dependencies if the * register it reads from has been written to in this block. */ if ((*v)->Writer) { - if ((*v)->Writer->Instruction->Type == - RC_INSTRUCTION_NORMAL) { - s->Current->TexReadCount++; - rc_list_add(&((*v)->Writer->TexReaders), - rc_list(&s->C->Pool, s->Current)); - } + add_tex_reader(s, (*v)->Writer, s->Current); s->Current->NumDependencies++; } } @@ -1209,6 +1235,9 @@ static void scan_write(void * data, struct rc_instruction * inst, if (*pv) { (*pv)->Next = newv; s->Current->NumDependencies++; + /* Keep track of the previous writer to s->Current's destination + * register */ + s->PrevWriter[chan] = (*pv)->Writer; } *pv = newv;