i965/fs: add support for gather4 with nonconstant offsets
authorChris Forbes <chrisf@ijw.co.nz>
Tue, 8 Oct 2013 09:10:34 +0000 (22:10 +1300)
committerChris Forbes <chrisf@ijw.co.nz>
Sat, 26 Oct 2013 09:08:51 +0000 (22:08 +1300)
V3: fixup crazy check for whether we need to emit the coordinate after
    custom handling.

Signed-off-by: Chris Forbes <chrisf@ijw.co.nz>
Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
src/mesa/drivers/dri/i965/brw_fs_visitor.cpp

index 7dabc4767dc67664031d1ccbd44ead3f2bbce835..314fe2ab5193950ef793e79c3c3c0167d28a31d9 100644 (file)
@@ -1251,11 +1251,13 @@ fs_visitor::emit_texture_gen7(ir_texture *ir, fs_reg dst, fs_reg coordinate,
       next.reg_offset++;
    }
 
+   bool has_nonconstant_offset = ir->offset && !ir->offset->as_constant();
+   bool coordinate_done = false;
+
    /* Set up the LOD info */
    switch (ir->op) {
    case ir_tex:
    case ir_lod:
-   case ir_tg4:
       break;
    case ir_txb:
       emit(MOV(next, lod));
@@ -1290,6 +1292,8 @@ fs_visitor::emit_texture_gen7(ir_texture *ir, fs_reg dst, fs_reg coordinate,
             next.reg_offset++;
          }
       }
+
+      coordinate_done = true;
       break;
    }
    case ir_txs:
@@ -1328,6 +1332,8 @@ fs_visitor::emit_texture_gen7(ir_texture *ir, fs_reg dst, fs_reg coordinate,
         coordinate.reg_offset++;
         next.reg_offset++;
       }
+
+      coordinate_done = true;
       break;
    case ir_txf_ms:
       emit(MOV(next.retype(BRW_REGISTER_TYPE_UD), sample_index));
@@ -1348,15 +1354,44 @@ fs_visitor::emit_texture_gen7(ir_texture *ir, fs_reg dst, fs_reg coordinate,
          coordinate.reg_offset++;
          next.reg_offset++;
       }
+
+      coordinate_done = true;
+      break;
+   case ir_tg4:
+      if (has_nonconstant_offset) {
+         /* More crazy intermixing */
+         ir->offset->accept(this);
+         fs_reg offset_value = this->result;
+
+         for (int i = 0; i < 2; i++) { /* u, v */
+            emit(MOV(next, coordinate));
+            coordinate.reg_offset++;
+            next.reg_offset++;
+         }
+
+         for (int i = 0; i < 2; i++) { /* offu, offv */
+            emit(MOV(next.retype(BRW_REGISTER_TYPE_D), offset_value));
+            offset_value.reg_offset++;
+            next.reg_offset++;
+         }
+
+         if (ir->coordinate->type->vector_elements == 3) { /* r if present */
+            emit(MOV(next, coordinate));
+            coordinate.reg_offset++;
+            next.reg_offset++;
+         }
+
+         coordinate_done = true;
+      }
       break;
    }
 
    /* Set up the coordinate (except for cases where it was done above) */
-   if (ir->op != ir_txd && ir->op != ir_txs && ir->op != ir_txf && ir->op != ir_txf_ms && ir->op != ir_query_levels) {
+   if (ir->coordinate && !coordinate_done) {
       for (int i = 0; i < ir->coordinate->type->vector_elements; i++) {
-        emit(MOV(next, coordinate));
-        coordinate.reg_offset++;
-        next.reg_offset++;
+         emit(MOV(next, coordinate));
+         coordinate.reg_offset++;
+         next.reg_offset++;
       }
    }
 
@@ -1372,14 +1407,18 @@ fs_visitor::emit_texture_gen7(ir_texture *ir, fs_reg dst, fs_reg coordinate,
    case ir_txs: inst = emit(SHADER_OPCODE_TXS, dst, payload); break;
    case ir_query_levels: inst = emit(SHADER_OPCODE_TXS, dst, payload); break;
    case ir_lod: inst = emit(SHADER_OPCODE_LOD, dst, payload); break;
-   case ir_tg4: inst = emit(SHADER_OPCODE_TG4, dst, payload); break;
+   case ir_tg4:
+      if (has_nonconstant_offset)
+         inst = emit(SHADER_OPCODE_TG4_OFFSET, dst, payload);
+      else
+         inst = emit(SHADER_OPCODE_TG4, dst, payload);
+      break;
    }
    inst->base_mrf = -1;
    if (reg_width == 2)
       inst->mlen = next.reg_offset * reg_width - header_present;
    else
       inst->mlen = next.reg_offset * reg_width;
-
    inst->header_present = header_present;
    inst->regs_written = 4;