i965/fs: Fix texelFetchOffset()
authorEric Anholt <eric@anholt.net>
Tue, 17 Apr 2012 01:43:48 +0000 (18:43 -0700)
committerEric Anholt <eric@anholt.net>
Tue, 24 Apr 2012 17:00:54 +0000 (10:00 -0700)
It appears that when using 'ld' with the offset bits, address bounds
checking happens before the offset is applied, so parts of the drawing
in piglit texelFetchOffset() with a negative texcoord go black.

src/mesa/drivers/dri/i965/brw_fs_visitor.cpp

index 8e98e1bb76c8604f8c5911fabe9fecd3ed42862e..6e8afbe5b2619a988d120547c1aba8804e05b55c 100644 (file)
@@ -990,8 +990,9 @@ fs_visitor::emit_texture_gen7(ir_texture *ir, fs_reg dst, fs_reg coordinate,
    int base_mrf = 2;
    int reg_width = c->dispatch_width / 8;
    bool header_present = false;
+   int offsets[3];
 
-   if (ir->offset) {
+   if (ir->offset && ir->op != ir_txf) {
       /* The offsets set up by the ir_texture visitor are in the
        * m1 header, so we can't go headerless.
        */
@@ -1054,9 +1055,23 @@ fs_visitor::emit_texture_gen7(ir_texture *ir, fs_reg dst, fs_reg coordinate,
       mlen += reg_width;
       break;
    case ir_txf:
+      /* It appears that the ld instruction used for txf does its
+       * address bounds check before adding in the offset.  To work
+       * around this, just add the integer offset to the integer texel
+       * coordinate, and don't put the offset in the header.
+       */
+      if (ir->offset) {
+        ir_constant *offset = ir->offset->as_constant();
+        offsets[0] = offset->value.i[0];
+        offsets[1] = offset->value.i[1];
+        offsets[2] = offset->value.i[2];
+      } else {
+        memset(offsets, 0, sizeof(offsets));
+      }
+
       /* Unfortunately, the parameters for LD are intermixed: u, lod, v, r. */
-      emit(BRW_OPCODE_MOV,
-          fs_reg(MRF, base_mrf + mlen, BRW_REGISTER_TYPE_D), coordinate);
+      emit(BRW_OPCODE_ADD,
+          fs_reg(MRF, base_mrf + mlen, BRW_REGISTER_TYPE_D), coordinate, offsets[0]);
       coordinate.reg_offset++;
       mlen += reg_width;
 
@@ -1065,8 +1080,8 @@ fs_visitor::emit_texture_gen7(ir_texture *ir, fs_reg dst, fs_reg coordinate,
       mlen += reg_width;
 
       for (int i = 1; i < ir->coordinate->type->vector_elements; i++) {
-        emit(BRW_OPCODE_MOV,
-             fs_reg(MRF, base_mrf + mlen, BRW_REGISTER_TYPE_D), coordinate);
+        emit(BRW_OPCODE_ADD,
+             fs_reg(MRF, base_mrf + mlen, BRW_REGISTER_TYPE_D), coordinate, offsets[i]);
         coordinate.reg_offset++;
         mlen += reg_width;
       }
@@ -1128,7 +1143,7 @@ fs_visitor::visit(ir_texture *ir)
       ir->coordinate->accept(this);
    fs_reg coordinate = this->result;
 
-   if (ir->offset != NULL) {
+   if (ir->offset != NULL && !(intel->gen == 7 && ir->op == ir_txf)) {
       uint32_t offset_bits = brw_texture_offset(ir->offset->as_constant());
 
       /* Explicitly set up the message header by copying g0 to msg reg m1. */