r300/compiler: Fix scheduler bug causing texture corruption
authorTom Stellard <tstellar@gmail.com>
Sun, 23 Oct 2011 01:30:46 +0000 (18:30 -0700)
committerTom Stellard <tstellar@gmail.com>
Fri, 28 Oct 2011 00:35:31 +0000 (20:35 -0400)
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

src/gallium/drivers/r300/compiler/radeon_pair_schedule.c

index b3b0f6fc25bf2873afe06200e74f01eac536a671..fa2e80f238c6ba1fc1e6e42a54b47d69892541df 100644 (file)
@@ -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;