i965/gen6+: Parameterize barycentric interpolation modes.
authorPaul Berry <stereotype441@gmail.com>
Sat, 22 Oct 2011 00:20:32 +0000 (17:20 -0700)
committerPaul Berry <stereotype441@gmail.com>
Thu, 27 Oct 2011 22:31:53 +0000 (15:31 -0700)
This patch modifies the fragment shader back-end so that instead of
using a single delta_x/delta_y register pair to store barycentric
coordinates, it uses an array of such register pairs, one for each
possible intepolation mode.

When setting up the WM, we intstruct it to only provide the
barycentric coordinates that are actually needed by the fragment
shader--that is computed by brw_compute_barycentric_interp_modes().
Currently this function returns just
BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC, because this is the only
interpolation mode we support.  However, that will change in a later
patch.

Reviewed-by: Eric Anholt <eric@anholt.net>
src/mesa/drivers/dri/i965/brw_context.h
src/mesa/drivers/dri/i965/brw_defines.h
src/mesa/drivers/dri/i965/brw_fs.cpp
src/mesa/drivers/dri/i965/brw_fs.h
src/mesa/drivers/dri/i965/brw_fs_reg_allocate.cpp
src/mesa/drivers/dri/i965/brw_fs_visitor.cpp
src/mesa/drivers/dri/i965/brw_wm.c
src/mesa/drivers/dri/i965/brw_wm.h
src/mesa/drivers/dri/i965/gen6_wm_state.c
src/mesa/drivers/dri/i965/gen7_wm_state.c

index ff25b093b47f862fc684e81f4f1ca64ae26fb93c..4ae8580ac5777d85ea45a27d019d7e76de01aa6c 100644 (file)
@@ -976,6 +976,11 @@ void brw_compute_vue_map(struct brw_vue_map *vue_map,
                          GLbitfield64 outputs_written);
 gl_clip_plane *brw_select_clip_planes(struct gl_context *ctx);
 
+/* brw_wm.c */
+unsigned
+brw_compute_barycentric_interp_modes(void);
+
+
 
 /*======================================================================
  * Inline conversion functions.  These are better-typed than the
index 61a739c3a9849da9033c465f6aab3201a00595b0..d302a61cdbcc99fd77aeccce43d0becffc5901e9 100644 (file)
@@ -1215,6 +1215,16 @@ enum brw_message_target {
 /* DW12: attr 0-7 wrap shortest enables */
 /* DW13: attr 8-16 wrap shortest enables */
 
+enum brw_wm_barycentric_interp_mode {
+   BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC                = 0,
+   BRW_WM_PERSPECTIVE_CENTROID_BARYCENTRIC     = 1,
+   BRW_WM_PERSPECTIVE_SAMPLE_BARYCENTRIC       = 2,
+   BRW_WM_NONPERSPECTIVE_PIXEL_BARYCENTRIC     = 3,
+   BRW_WM_NONPERSPECTIVE_CENTROID_BARYCENTRIC  = 4,
+   BRW_WM_NONPERSPECTIVE_SAMPLE_BARYCENTRIC    = 5,
+   BRW_WM_BARYCENTRIC_INTERP_MODE_COUNT  = 6
+};
+
 #define _3DSTATE_WM                            0x7814 /* GEN6+ */
 /* DW1: kernel pointer */
 /* DW2 */
@@ -1269,6 +1279,7 @@ enum brw_message_target {
 # define GEN6_WM_PERSPECTIVE_SAMPLE_BARYCENTRIC                (1 << 12)
 # define GEN6_WM_PERSPECTIVE_CENTROID_BARYCENTRIC      (1 << 11)
 # define GEN6_WM_PERSPECTIVE_PIXEL_BARYCENTRIC         (1 << 10)
+# define GEN6_WM_BARYCENTRIC_INTERPOLATION_MODE_SHIFT   10
 # define GEN6_WM_POINT_RASTRULE_UPPER_RIGHT            (1 << 9)
 # define GEN6_WM_MSRAST_OFF_PIXEL                      (0 << 1)
 # define GEN6_WM_MSRAST_OFF_PATTERN                    (1 << 1)
@@ -1306,12 +1317,7 @@ enum brw_message_target {
 # define GEN7_WM_POSITION_ZW_PIXEL                     (0 << 17)
 # define GEN7_WM_POSITION_ZW_CENTROID                  (2 << 17)
 # define GEN7_WM_POSITION_ZW_SAMPLE                    (3 << 17)
-# define GEN7_WM_NONPERSPECTIVE_SAMPLE_BARYCENTRIC     (1 << 16)
-# define GEN7_WM_NONPERSPECTIVE_CENTROID_BARYCENTRIC   (1 << 15)
-# define GEN7_WM_NONPERSPECTIVE_PIXEL_BARYCENTRIC      (1 << 14)
-# define GEN7_WM_PERSPECTIVE_SAMPLE_BARYCENTRIC                (1 << 13)
-# define GEN7_WM_PERSPECTIVE_CENTROID_BARYCENTRIC      (1 << 12)
-# define GEN7_WM_PERSPECTIVE_PIXEL_BARYCENTRIC         (1 << 11)
+# define GEN7_WM_BARYCENTRIC_INTERPOLATION_MODE_SHIFT   11
 # define GEN7_WM_USES_INPUT_COVERAGE_MASK              (1 << 10)
 # define GEN7_WM_LINE_END_CAP_AA_WIDTH_0_5             (0 << 8)
 # define GEN7_WM_LINE_END_CAP_AA_WIDTH_1_0             (1 << 8)
index 3848915cf80caa4a71763230c0a8d14644e933de..b3ad505b71e66954927e546c33ffee248e6613d2 100644 (file)
@@ -407,8 +407,10 @@ fs_visitor::emit_fragcoord_interpolation(ir_variable *ir)
       emit(BRW_OPCODE_MOV, wpos,
           fs_reg(brw_vec8_grf(c->source_depth_reg, 0)));
    } else {
-      emit(FS_OPCODE_LINTERP, wpos, this->delta_x, this->delta_y,
-          interp_reg(FRAG_ATTRIB_WPOS, 2));
+      emit(FS_OPCODE_LINTERP, wpos,
+           this->delta_x[BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC],
+           this->delta_y[BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC],
+           interp_reg(FRAG_ATTRIB_WPOS, 2));
    }
    wpos.reg_offset++;
 
@@ -481,8 +483,11 @@ fs_visitor::emit_general_interpolation(ir_variable *ir)
                  emit(BRW_OPCODE_MOV, attr, fs_reg(1.0f));
               } else {
                  struct brw_reg interp = interp_reg(location, k);
-                 emit(FS_OPCODE_LINTERP, attr,
-                      this->delta_x, this->delta_y, fs_reg(interp));
+                  brw_wm_barycentric_interp_mode barycoord_mode =
+                     BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC;
+                  emit(FS_OPCODE_LINTERP, attr,
+                       this->delta_x[barycoord_mode],
+                       this->delta_y[barycoord_mode], fs_reg(interp));
               }
               attr.reg_offset++;
            }
@@ -768,9 +773,15 @@ fs_visitor::split_virtual_grfs()
         split_grf[i] = false;
    }
 
-   if (brw->has_pln && this->delta_x.file == GRF) {
-      /* PLN opcodes rely on the delta_xy being contiguous. */
-      split_grf[this->delta_x.reg] = false;
+   if (brw->has_pln &&
+       this->delta_x[BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC].file == GRF) {
+      /* PLN opcodes rely on the delta_xy being contiguous.  We only have to
+       * check this for BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC, because prior to
+       * Gen6, that was the only supported interpolation mode, and since Gen6,
+       * delta_x and delta_y are in fixed hardware registers.
+       */
+      split_grf[this->delta_x[BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC].reg] =
+         false;
    }
 
    foreach_list(node, &this->instructions) {
index f5af9ea936a38ae1296b350f48fc4198955f51d1..e2ad6499e9500772e110bffbdb6a44ec9f60dd30 100644 (file)
@@ -594,8 +594,8 @@ public:
    fs_reg pixel_y;
    fs_reg wpos_w;
    fs_reg pixel_w;
-   fs_reg delta_x;
-   fs_reg delta_y;
+   fs_reg delta_x[BRW_WM_BARYCENTRIC_INTERP_MODE_COUNT];
+   fs_reg delta_y[BRW_WM_BARYCENTRIC_INTERP_MODE_COUNT];
    fs_reg reg_null_cmp;
 
    int grf_used;
index 6e38cc250e8b92b8caea790982a3ed93ca0b3712..3f875cc63d93bbeca944184004ab1dead3db5a59 100644 (file)
@@ -202,8 +202,17 @@ fs_visitor::assign_regs()
    for (int i = 0; i < this->virtual_grf_next; i++) {
       for (int c = 0; c < class_count; c++) {
         if (class_sizes[c] == this->virtual_grf_sizes[i]) {
+            /* Special case: on pre-GEN6 hardware that supports PLN, the
+             * second operand of a PLN instruction needs to be an
+             * even-numbered register, so we have a special register class
+             * wm_aligned_pairs_class to handle this case.  pre-GEN6 always
+             * uses this->delta_x[BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC] as the
+             * second operand of a PLN instruction (since it doesn't support
+             * any other interpolation modes).  So all we need to do is find
+             * that register and set it to the appropriate class.
+             */
            if (brw->wm.aligned_pairs_class >= 0 &&
-               this->delta_x.reg == i) {
+               this->delta_x[BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC].reg == i) {
               ra_set_node_class(g, i, brw->wm.aligned_pairs_class);
            } else {
               ra_set_node_class(g, i, brw->wm.classes[c]);
index 215cdcdb02200b17ea59d8a08e90f6f60e787572..2f95014d2a2ad97d3d04ecee2a9a938551096326 100644 (file)
@@ -1754,16 +1754,20 @@ fs_visitor::emit_interpolation_setup_gen4()
 
    this->current_annotation = "compute pixel deltas from v0";
    if (brw->has_pln) {
-      this->delta_x = fs_reg(this, glsl_type::vec2_type);
-      this->delta_y = this->delta_x;
-      this->delta_y.reg_offset++;
+      this->delta_x[BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC] =
+         fs_reg(this, glsl_type::vec2_type);
+      this->delta_y[BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC] =
+         this->delta_x[BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC];
+      this->delta_y[BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC].reg_offset++;
    } else {
-      this->delta_x = fs_reg(this, glsl_type::float_type);
-      this->delta_y = fs_reg(this, glsl_type::float_type);
+      this->delta_x[BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC] =
+         fs_reg(this, glsl_type::float_type);
+      this->delta_y[BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC] =
+         fs_reg(this, glsl_type::float_type);
    }
-   emit(BRW_OPCODE_ADD, this->delta_x,
+   emit(BRW_OPCODE_ADD, this->delta_x[BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC],
        this->pixel_x, fs_reg(negate(brw_vec1_grf(1, 0))));
-   emit(BRW_OPCODE_ADD, this->delta_y,
+   emit(BRW_OPCODE_ADD, this->delta_y[BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC],
        this->pixel_y, fs_reg(negate(brw_vec1_grf(1, 1))));
 
    this->current_annotation = "compute pos.w and 1/pos.w";
@@ -1771,7 +1775,9 @@ fs_visitor::emit_interpolation_setup_gen4()
     * interpolate the other attributes.
     */
    this->wpos_w = fs_reg(this, glsl_type::float_type);
-   emit(FS_OPCODE_LINTERP, wpos_w, this->delta_x, this->delta_y,
+   emit(FS_OPCODE_LINTERP, wpos_w,
+        this->delta_x[BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC],
+        this->delta_y[BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC],
        interp_reg(FRAG_ATTRIB_WPOS, 3));
    /* Compute the pixel 1/W value from wpos.w. */
    this->pixel_w = fs_reg(this, glsl_type::float_type);
@@ -1814,8 +1820,11 @@ fs_visitor::emit_interpolation_setup_gen6()
    this->wpos_w = fs_reg(this, glsl_type::float_type);
    emit_math(SHADER_OPCODE_RCP, this->wpos_w, this->pixel_w);
 
-   this->delta_x = fs_reg(brw_vec8_grf(2, 0));
-   this->delta_y = fs_reg(brw_vec8_grf(3, 0));
+   for (int i = 0; i < BRW_WM_BARYCENTRIC_INTERP_MODE_COUNT; ++i) {
+      uint8_t reg = c->barycentric_coord_reg[i];
+      this->delta_x[i] = fs_reg(brw_vec8_grf(reg, 0));
+      this->delta_y[i] = fs_reg(brw_vec8_grf(reg + 1, 0));
+   }
 
    this->current_annotation = NULL;
 }
index b60173ed4bfd7310be6576f3db5c8c1fbdcabc1b..81dad4f76da4ffb4694c05dbf46c7061fa6cae2a 100644 (file)
@@ -123,6 +123,19 @@ brw_wm_non_glsl_emit(struct brw_context *brw, struct brw_wm_compile *c)
    brw_wm_emit(c);
 }
 
+
+/**
+ * Return a bitfield where bit n is set if barycentric interpolation mode n
+ * (see enum brw_wm_barycentric_interp_mode) is needed by the fragment shader.
+ */
+unsigned
+brw_compute_barycentric_interp_modes(void)
+{
+   /* At the moment the only interpolation mode we support is perspective. */
+   return (1 << BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC);
+}
+
+
 void
 brw_wm_payload_setup(struct brw_context *brw,
                     struct brw_wm_compile *c)
@@ -130,22 +143,31 @@ brw_wm_payload_setup(struct brw_context *brw,
    struct intel_context *intel = &brw->intel;
    bool uses_depth = (c->fp->program.Base.InputsRead &
                      (1 << FRAG_ATTRIB_WPOS)) != 0;
+   unsigned barycentric_interp_modes =
+      brw_compute_barycentric_interp_modes();
+   int i;
 
    if (intel->gen >= 6) {
       /* R0-1: masks, pixel X/Y coordinates. */
       c->nr_payload_regs = 2;
       /* R2: only for 32-pixel dispatch.*/
-      /* R3-4: perspective pixel location barycentric */
-      c->nr_payload_regs += 2;
-      /* R5-6: perspective pixel location bary for dispatch width != 8 */
-      if (c->dispatch_width == 16) {
-        c->nr_payload_regs += 2;
+
+      /* R3-26: barycentric interpolation coordinates.  These appear in the
+       * same order that they appear in the brw_wm_barycentric_interp_mode
+       * enum.  Each set of coordinates occupies 2 registers if dispatch width
+       * == 8 and 4 registers if dispatch width == 16.  Coordinates only
+       * appear if they were enabled using the "Barycentric Interpolation
+       * Mode" bits in WM_STATE.
+       */
+      for (i = 0; i < BRW_WM_BARYCENTRIC_INTERP_MODE_COUNT; ++i) {
+         if (barycentric_interp_modes & (1 << i)) {
+            c->barycentric_coord_reg[i] = c->nr_payload_regs;
+            c->nr_payload_regs += 2;
+            if (c->dispatch_width == 16) {
+               c->nr_payload_regs += 2;
+            }
+         }
       }
-      /* R7-10: perspective centroid barycentric */
-      /* R11-14: perspective sample barycentric */
-      /* R15-18: linear pixel location barycentric */
-      /* R19-22: linear centroid barycentric */
-      /* R23-26: linear sample barycentric */
 
       /* R27: interpolated depth if uses source depth */
       if (uses_depth) {
index efd18e96bec0d150a5b59d1d368aa32a65c41121..76cf4533b56de11ea59d1613c9a64683b3d11490 100644 (file)
@@ -215,6 +215,7 @@ struct brw_wm_compile {
    uint8_t source_w_reg;
    uint8_t aa_dest_stencil_reg;
    uint8_t dest_depth_reg;
+   uint8_t barycentric_coord_reg[BRW_WM_BARYCENTRIC_INTERP_MODE_COUNT];
    uint8_t nr_payload_regs;
    GLuint computes_depth:1;    /* could be derived from program string */
    GLuint source_depth_to_render_target:1;
index 24fc81dd2402021dbf1c59de988bc3c636eb0434..178375f4133e18ce51c86e2af85fba2c5c7641af 100644 (file)
@@ -178,7 +178,8 @@ upload_wm_state(struct brw_context *brw)
       dw5 |= GEN6_WM_DISPATCH_ENABLE;
    }
 
-   dw6 |= GEN6_WM_PERSPECTIVE_PIXEL_BARYCENTRIC;
+   dw6 |= brw_compute_barycentric_interp_modes() <<
+      GEN6_WM_BARYCENTRIC_INTERPOLATION_MODE_SHIFT;
 
    dw6 |= _mesa_bitcount_64(brw->fragment_program->Base.InputsRead) <<
       GEN6_WM_NUM_SF_OUTPUTS_SHIFT;
index aae3c1164fb43e4e190e05eb7c947efbcfed81da..fc23c2e161549a1089da87ae5f64f5d4d1624436 100644 (file)
@@ -72,7 +72,8 @@ upload_wm_state(struct brw_context *brw)
       dw1 |= GEN7_WM_DISPATCH_ENABLE;
    }
 
-   dw1 |= GEN7_WM_PERSPECTIVE_PIXEL_BARYCENTRIC;
+   dw1 |= brw_compute_barycentric_interp_modes() <<
+      GEN7_WM_BARYCENTRIC_INTERPOLATION_MODE_SHIFT;
 
    BEGIN_BATCH(3);
    OUT_BATCH(_3DSTATE_WM << 16 | (3 - 2));