intel/blorp: Take a destination swizzle in blorp_blit
[mesa.git] / src / mesa / drivers / dri / i965 / brw_fs_generator.cpp
index 78a45b6d919efc7bbd7face057bd5d2f1a042ceb..2f4ba7b55929c4a0e8f1fec1d4d75e26d0544fc9 100644 (file)
@@ -54,9 +54,9 @@ brw_file_from_reg(fs_reg *reg)
 }
 
 static struct brw_reg
-brw_reg_from_fs_reg(const struct brw_codegen *p,
-                    fs_inst *inst, fs_reg *reg, unsigned gen)
+brw_reg_from_fs_reg(fs_inst *inst, fs_reg *reg, unsigned gen, bool compressed)
 {
+   assert(reg->reg_offset == 0);
    struct brw_reg brw_reg;
 
    switch (reg->file) {
@@ -66,27 +66,34 @@ brw_reg_from_fs_reg(const struct brw_codegen *p,
    case VGRF:
       if (reg->stride == 0) {
          brw_reg = brw_vec1_reg(brw_file_from_reg(reg), reg->nr, 0);
-      } else if (!p->compressed &&
-                 inst->exec_size * reg->stride * type_sz(reg->type) <= 32) {
-         brw_reg = brw_vecn_reg(inst->exec_size, brw_file_from_reg(reg),
-                                reg->nr, 0);
-         brw_reg = stride(brw_reg, inst->exec_size * reg->stride,
-                          inst->exec_size, reg->stride);
       } else {
          /* From the Haswell PRM:
           *
-          * VertStride must be used to cross GRF register boundaries. This
-          * rule implies that elements within a 'Width' cannot cross GRF
-          * boundaries.
+          *  "VertStride must be used to cross GRF register boundaries. This
+          *   rule implies that elements within a 'Width' cannot cross GRF
+          *   boundaries."
           *
-          * So, for registers that are large enough, we have to split the exec
-          * size in two and trust the compression state to sort it out.
+          * The maximum width value that could satisfy this restriction is:
           */
-         assert(inst->exec_size / 2 * reg->stride * type_sz(reg->type) <= 32);
-         brw_reg = brw_vecn_reg(inst->exec_size / 2, brw_file_from_reg(reg),
-                                reg->nr, 0);
-         brw_reg = stride(brw_reg, inst->exec_size / 2 * reg->stride,
-                          inst->exec_size / 2, reg->stride);
+         const unsigned reg_width = REG_SIZE / (reg->stride * type_sz(reg->type));
+
+         /* Because the hardware can only split source regions at a whole
+          * multiple of width during decompression (i.e. vertically), clamp
+          * the value obtained above to the physical execution size of a
+          * single decompressed chunk of the instruction:
+          */
+         const unsigned phys_width = compressed ? inst->exec_size / 2 :
+                                     inst->exec_size;
+
+         /* XXX - The equation above is strictly speaking not correct on
+          *       hardware that supports unbalanced GRF writes -- On Gen9+
+          *       each decompressed chunk of the instruction may have a
+          *       different execution size when the number of components
+          *       written to each destination GRF is not the same.
+          */
+         const unsigned width = MIN2(reg_width, phys_width);
+         brw_reg = brw_vecn_reg(width, brw_file_from_reg(reg), reg->nr, 0);
+         brw_reg = stride(brw_reg, width * reg->stride, width, reg->stride);
       }
 
       brw_reg = retype(brw_reg, reg->type);
@@ -97,6 +104,7 @@ brw_reg_from_fs_reg(const struct brw_codegen *p,
    case ARF:
    case FIXED_GRF:
    case IMM:
+      assert(reg->subreg_offset == 0);
       brw_reg = reg->as_brw_reg();
       break;
    case BAD_FILE:
@@ -206,7 +214,7 @@ fs_generator::fire_fb_write(fs_inst *inst,
    if (inst->opcode == FS_OPCODE_REP_FB_WRITE)
       msg_control = BRW_DATAPORT_RENDER_TARGET_WRITE_SIMD16_SINGLE_SOURCE_REPLICATED;
    else if (prog_data->dual_src_blend) {
-      if (!inst->force_sechalf)
+      if (!inst->group)
          msg_control = BRW_DATAPORT_RENDER_TARGET_WRITE_SIMD8_DUAL_SOURCE_SUBSPAN01;
       else
          msg_control = BRW_DATAPORT_RENDER_TARGET_WRITE_SIMD8_DUAL_SOURCE_SUBSPAN23;
@@ -223,7 +231,6 @@ fs_generator::fire_fb_write(fs_inst *inst,
 
 
    brw_fb_WRITE(p,
-                dispatch_width,
                 payload,
                 implied_header,
                 msg_control,
@@ -346,6 +353,22 @@ fs_generator::generate_fb_write(fs_inst *inst, struct brw_reg payload)
    }
 }
 
+void
+fs_generator::generate_fb_read(fs_inst *inst, struct brw_reg dst,
+                               struct brw_reg payload)
+{
+   brw_wm_prog_data *prog_data =
+      reinterpret_cast<brw_wm_prog_data *>(this->prog_data);
+   const unsigned surf_index =
+      prog_data->binding_table.render_target_start + inst->target;
+
+   gen9_fb_READ(p, dst, payload, surf_index,
+                inst->header_size, inst->regs_written,
+                prog_data->persample_dispatch);
+
+   brw_mark_surface_used(&prog_data->base, surf_index);
+}
+
 void
 fs_generator::generate_mov_indirect(fs_inst *inst,
                                     struct brw_reg dst,
@@ -433,7 +456,7 @@ fs_generator::generate_urb_read(fs_inst *inst,
    assert(header.type == BRW_REGISTER_TYPE_UD);
 
    brw_inst *send = brw_next_insn(p, BRW_OPCODE_SEND);
-   brw_set_dest(p, send, dst);
+   brw_set_dest(p, send, retype(dst, BRW_REGISTER_TYPE_UD));
    brw_set_src0(p, send, header);
    brw_set_src1(p, send, brw_imm_ud(0u));
 
@@ -541,7 +564,7 @@ fs_generator::generate_linterp(fs_inst *inst,
     * See also: emit_interpolation_setup_gen4().
     */
    struct brw_reg delta_x = src[0];
-   struct brw_reg delta_y = offset(src[0], dispatch_width / 8);
+   struct brw_reg delta_y = offset(src[0], inst->exec_size / 8);
    struct brw_reg interp = src[1];
 
    if (devinfo->has_pln &&
@@ -1046,28 +1069,44 @@ fs_generator::generate_discard_jump(fs_inst *inst)
     * current block (or the program).
     */
    this->discard_halt_patches.push_tail(new(mem_ctx) ip_record(p->nr_insn));
-
-   brw_push_insn_state(p);
-   brw_set_default_mask_control(p, BRW_MASK_DISABLE);
    gen6_HALT(p);
-   brw_pop_insn_state(p);
 }
 
 void
 fs_generator::generate_scratch_write(fs_inst *inst, struct brw_reg src)
 {
+   /* The 32-wide messages only respect the first 16-wide half of the channel
+    * enable signals which are replicated identically for the second group of
+    * 16 channels, so we cannot use them unless the write is marked
+    * force_writemask_all.
+    */
+   const unsigned lower_size = inst->force_writemask_all ? inst->exec_size :
+                               MIN2(16, inst->exec_size);
+   const unsigned block_size = 4 * lower_size / REG_SIZE;
    assert(inst->mlen != 0);
 
-   brw_MOV(p,
-          brw_uvec_mrf(inst->exec_size, (inst->base_mrf + 1), 0),
-          retype(src, BRW_REGISTER_TYPE_UD));
-   brw_oword_block_write_scratch(p, brw_message_reg(inst->base_mrf),
-                                 inst->exec_size / 8, inst->offset);
+   brw_push_insn_state(p);
+   brw_set_default_exec_size(p, cvt(lower_size) - 1);
+   brw_set_default_compression(p, lower_size > 8);
+
+   for (unsigned i = 0; i < inst->exec_size / lower_size; i++) {
+      brw_set_default_group(p, inst->group + lower_size * i);
+
+      brw_MOV(p, brw_uvec_mrf(lower_size, inst->base_mrf + 1, 0),
+              retype(offset(src, block_size * i), BRW_REGISTER_TYPE_UD));
+
+      brw_oword_block_write_scratch(p, brw_message_reg(inst->base_mrf),
+                                    block_size,
+                                    inst->offset + block_size * REG_SIZE * i);
+   }
+
+   brw_pop_insn_state(p);
 }
 
 void
 fs_generator::generate_scratch_read(fs_inst *inst, struct brw_reg dst)
 {
+   assert(inst->exec_size <= 16 || inst->force_writemask_all);
    assert(inst->mlen != 0);
 
    brw_oword_block_read_scratch(p, dst, brw_message_reg(inst->base_mrf),
@@ -1077,6 +1116,8 @@ fs_generator::generate_scratch_read(fs_inst *inst, struct brw_reg dst)
 void
 fs_generator::generate_scratch_read_gen7(fs_inst *inst, struct brw_reg dst)
 {
+   assert(inst->exec_size <= 16 || inst->force_writemask_all);
+
    gen7_block_read_scratch(p, dst, inst->exec_size / 8, inst->offset);
 }
 
@@ -1148,7 +1189,7 @@ fs_generator::generate_uniform_pull_constant_load_gen7(fs_inst *inst,
       brw_inst_set_exec_size(devinfo, send, BRW_EXECUTE_4);
       brw_pop_insn_state(p);
 
-      brw_set_dest(p, send, dst);
+      brw_set_dest(p, send, retype(dst, BRW_REGISTER_TYPE_UD));
       brw_set_src0(p, send, src);
       brw_set_sampler_message(p, send,
                               surf_index,
@@ -1205,10 +1246,11 @@ fs_generator::generate_varying_pull_constant_load_gen4(fs_inst *inst,
    uint32_t surf_index = index.ud;
 
    uint32_t simd_mode, rlen, msg_type;
-   if (dispatch_width == 16) {
+   if (inst->exec_size == 16) {
       simd_mode = BRW_SAMPLER_SIMD_MODE_SIMD16;
       rlen = 8;
    } else {
+      assert(inst->exec_size == 8);
       simd_mode = BRW_SAMPLER_SIMD_MODE_SIMD8;
       rlen = 4;
    }
@@ -1230,7 +1272,7 @@ fs_generator::generate_varying_pull_constant_load_gen4(fs_inst *inst,
    gen6_resolve_implied_move(p, &header, inst->base_mrf);
 
    brw_inst *send = brw_next_insn(p, BRW_OPCODE_SEND);
-   brw_inst_set_qtr_control(p->devinfo, send, BRW_COMPRESSION_NONE);
+   brw_inst_set_compression(devinfo, send, false);
    brw_set_dest(p, send, retype(dst, BRW_REGISTER_TYPE_UW));
    brw_set_src0(p, send, header);
    if (devinfo->gen < 6)
@@ -1266,11 +1308,12 @@ fs_generator::generate_varying_pull_constant_load_gen7(fs_inst *inst,
    assert(index.type == BRW_REGISTER_TYPE_UD);
 
    uint32_t simd_mode, rlen, mlen;
-   if (dispatch_width == 16) {
+   if (inst->exec_size == 16) {
       mlen = 2;
       rlen = 8;
       simd_mode = BRW_SAMPLER_SIMD_MODE_SIMD16;
    } else {
+      assert(inst->exec_size == 8);
       mlen = 1;
       rlen = 4;
       simd_mode = BRW_SAMPLER_SIMD_MODE_SIMD8;
@@ -1406,9 +1449,9 @@ fs_generator::generate_set_sample_id(fs_inst *inst,
           src0.type == BRW_REGISTER_TYPE_UD);
 
    struct brw_reg reg = stride(src1, 1, 4, 0);
-   if (devinfo->gen >= 8 || dispatch_width == 8) {
+   if (devinfo->gen >= 8 || inst->exec_size == 8) {
       brw_ADD(p, dst, src0, reg);
-   } else if (dispatch_width == 16) {
+   } else if (inst->exec_size == 16) {
       brw_push_insn_state(p);
       brw_set_default_exec_size(p, BRW_EXECUTE_8);
       brw_set_default_compression_control(p, BRW_COMPRESSION_NONE);
@@ -1541,8 +1584,6 @@ fs_generator::generate_code(const cfg_t *cfg, int dispatch_width)
       brw_NOP(p);
 
    this->dispatch_width = dispatch_width;
-   if (dispatch_width == 16)
-      brw_set_default_compression_control(p, BRW_COMPRESSION_COMPRESSED);
 
    int start_offset = p->next_insn_offset;
    int spill_count = 0, fill_count = 0;
@@ -1577,36 +1618,27 @@ fs_generator::generate_code(const cfg_t *cfg, int dispatch_width)
       if (unlikely(debug_flag))
          annotate(p->devinfo, &annotation, cfg, inst, p->next_insn_offset);
 
-      switch (inst->exec_size) {
-      case 1:
-      case 2:
-      case 4:
-         assert(inst->force_writemask_all);
-         brw_set_default_compression_control(p, BRW_COMPRESSION_NONE);
-         break;
-      case 8:
-         if (inst->force_sechalf) {
-            brw_set_default_compression_control(p, BRW_COMPRESSION_2NDHALF);
-         } else {
-            brw_set_default_compression_control(p, BRW_COMPRESSION_NONE);
-         }
-         break;
-      case 16:
-      case 32:
-         /* If the instruction writes to more than one register, it needs to
-          * be a "compressed" instruction on Gen <= 5.
-          */
-         if (inst->dst.component_size(inst->exec_size) > REG_SIZE)
-            brw_set_default_compression_control(p, BRW_COMPRESSION_COMPRESSED);
-         else
-            brw_set_default_compression_control(p, BRW_COMPRESSION_NONE);
-         break;
-      default:
-         unreachable("Invalid instruction width");
-      }
+      /* If the instruction writes to more than one register, it needs to be
+       * explicitly marked as compressed on Gen <= 5.  On Gen >= 6 the
+       * hardware figures out by itself what the right compression mode is,
+       * but we still need to know whether the instruction is compressed to
+       * set up the source register regions appropriately.
+       *
+       * XXX - This is wrong for instructions that write a single register but
+       *       read more than one which should strictly speaking be treated as
+       *       compressed.  For instructions that don't write any registers it
+       *       relies on the destination being a null register of the correct
+       *       type and regioning so the instruction is considered compressed
+       *       or not accordingly.
+       */
+      const bool compressed =
+           inst->dst.component_size(inst->exec_size) > REG_SIZE;
+      brw_set_default_compression(p, compressed);
+      brw_set_default_group(p, inst->group);
 
       for (unsigned int i = 0; i < inst->sources; i++) {
-        src[i] = brw_reg_from_fs_reg(p, inst, &inst->src[i], devinfo->gen);
+         src[i] = brw_reg_from_fs_reg(inst, &inst->src[i], devinfo->gen,
+                                      compressed);
 
         /* The accumulator result appears to get used for the
          * conditional modifier generation.  When negating a UD
@@ -1618,7 +1650,7 @@ fs_generator::generate_code(const cfg_t *cfg, int dispatch_width)
                inst->src[i].type != BRW_REGISTER_TYPE_UD ||
                !inst->src[i].negate);
       }
-      dst = brw_reg_from_fs_reg(p, inst, &inst->dst, devinfo->gen);
+      dst = brw_reg_from_fs_reg(inst, &inst->dst, devinfo->gen, compressed);
 
       brw_set_default_access_mode(p, BRW_ALIGN_1);
       brw_set_default_predicate_control(p, inst->predicate);
@@ -1629,6 +1661,8 @@ fs_generator::generate_code(const cfg_t *cfg, int dispatch_width)
       brw_set_default_acc_write_control(p, inst->writes_accumulator);
       brw_set_default_exec_size(p, cvt(inst->exec_size) - 1);
 
+      assert(inst->force_writemask_all || inst->exec_size >= 4);
+      assert(inst->force_writemask_all || inst->group % inst->exec_size == 0);
       assert(inst->base_mrf + inst->mlen <= BRW_MAX_MRF(devinfo->gen));
       assert(inst->mlen <= BRW_MAX_MSG_LENGTH);
 
@@ -1739,6 +1773,9 @@ fs_generator::generate_code(const cfg_t *cfg, int dispatch_width)
          /* FBL only supports UD type for dst. */
          brw_FBL(p, retype(dst, BRW_REGISTER_TYPE_UD), src[0]);
          break;
+      case BRW_OPCODE_LZD:
+         brw_LZD(p, dst, src[0]);
+         break;
       case BRW_OPCODE_CBIT:
          assert(devinfo->gen >= 7);
          /* CBIT only supports UD type for dst. */
@@ -1778,7 +1815,7 @@ fs_generator::generate_code(const cfg_t *cfg, int dispatch_width)
            assert(devinfo->gen == 6);
            gen6_IF(p, inst->conditional_mod, src[0], src[1]);
         } else {
-           brw_IF(p, dispatch_width == 16 ? BRW_EXECUTE_16 : BRW_EXECUTE_8);
+           brw_IF(p, brw_inst_exec_size(devinfo, p->current));
         }
         break;
 
@@ -1790,16 +1827,14 @@ fs_generator::generate_code(const cfg_t *cfg, int dispatch_width)
         break;
 
       case BRW_OPCODE_DO:
-        brw_DO(p, dispatch_width == 16 ? BRW_EXECUTE_16 : BRW_EXECUTE_8);
+        brw_DO(p, brw_inst_exec_size(devinfo, p->current));
         break;
 
       case BRW_OPCODE_BREAK:
         brw_BREAK(p);
-        brw_set_default_predicate_control(p, BRW_PREDICATE_NONE);
         break;
       case BRW_OPCODE_CONTINUE:
          brw_CONT(p);
-        brw_set_default_predicate_control(p, BRW_PREDICATE_NONE);
         break;
 
       case BRW_OPCODE_WHILE:
@@ -1946,6 +1981,10 @@ fs_generator::generate_code(const cfg_t *cfg, int dispatch_width)
         generate_fb_write(inst, src[0]);
         break;
 
+      case FS_OPCODE_FB_READ:
+         generate_fb_read(inst, dst, src[0]);
+         break;
+
       case FS_OPCODE_MOV_DISPATCH_TO_FLAGS:
          generate_mov_dispatch_to_flags(inst);
          break;
@@ -2006,6 +2045,7 @@ fs_generator::generate_code(const cfg_t *cfg, int dispatch_width)
          break;
 
       case SHADER_OPCODE_BROADCAST:
+         assert(inst->force_writemask_all);
          brw_broadcast(p, dst, src[0], src[1]);
          break;
 
@@ -2033,11 +2073,6 @@ fs_generator::generate_code(const cfg_t *cfg, int dispatch_width)
          }
          break;
 
-      case FS_OPCODE_INTERPOLATE_AT_CENTROID:
-         generate_pixel_interpolator_query(inst, dst, src[0], src[1],
-                                           GEN7_PIXEL_INTERPOLATOR_LOC_CENTROID);
-         break;
-
       case FS_OPCODE_INTERPOLATE_AT_SAMPLE:
          generate_pixel_interpolator_query(inst, dst, src[0], src[1],
                                            GEN7_PIXEL_INTERPOLATOR_LOC_SAMPLE);
@@ -2061,6 +2096,13 @@ fs_generator::generate_code(const cfg_t *cfg, int dispatch_width)
         generate_barrier(inst, src[0]);
         break;
 
+      case BRW_OPCODE_DIM:
+         assert(devinfo->is_haswell);
+         assert(src[0].type == BRW_REGISTER_TYPE_DF);
+         assert(dst.type == BRW_REGISTER_TYPE_DF);
+         brw_DIM(p, dst, retype(src[0], BRW_REGISTER_TYPE_F));
+         break;
+
       default:
          unreachable("Unsupported opcode");
 
@@ -2085,7 +2127,7 @@ fs_generator::generate_code(const cfg_t *cfg, int dispatch_width)
       }
    }
 
-   brw_set_uip_jip(p);
+   brw_set_uip_jip(p, start_offset);
    annotation_finalize(&annotation, p->next_insn_offset);
 
 #ifndef NDEBUG