i965/gen6+: Add support for noperspective interpolation.
authorPaul Berry <stereotype441@gmail.com>
Sat, 22 Oct 2011 16:33:16 +0000 (09:33 -0700)
committerPaul Berry <stereotype441@gmail.com>
Thu, 27 Oct 2011 22:32:20 +0000 (15:32 -0700)
This required the following changes:

- WM setup now makes the appropriate set of barycentric coordinates
  (perspective vs. noperspective) available to the fragment shader,
  based on whether the shader requires perspective interpolation,
  noperspective interpolation, both, or neither.

- The fragment shader backend now uses the appropriate set of
  barycentric coordiantes when interpolating, based on the
  interpolation mode returned by
  ir_variable::determine_interpolation_mode().

- SF setup now uses gl_fragment_program::InterpQualifier to determine
  which attributes are to be flat shaded (as opposed to the old logic,
  which only flat shaded colors).

- CLIP setup now ensures that the clipper outputs non-perspective
  barycentric coordinates when they are needed by the fragment shader.

Fixes the remaining piglit tests of interpolation qualifiers that were
failing:
- interpolation-flat-*-smooth-none
- interpolation-flat-other-flat-none
- interpolation-noperspective-*
- interpolation-smooth-gl_*Color-flat-*

Reviewed-by: Eric Anholt <eric@anholt.net>
src/mesa/drivers/dri/i965/brw_context.h
src/mesa/drivers/dri/i965/brw_fs.cpp
src/mesa/drivers/dri/i965/brw_wm.c
src/mesa/drivers/dri/i965/gen6_clip_state.c
src/mesa/drivers/dri/i965/gen6_sf_state.c
src/mesa/drivers/dri/i965/gen6_wm_state.c
src/mesa/drivers/dri/i965/gen7_clip_state.c
src/mesa/drivers/dri/i965/gen7_sf_state.c
src/mesa/drivers/dri/i965/gen7_wm_state.c

index 4ae8580ac5777d85ea45a27d019d7e76de01aa6c..1d6e58b0cfc2db42fe24d901e45cf2db32e3e025 100644 (file)
@@ -978,7 +978,12 @@ gl_clip_plane *brw_select_clip_planes(struct gl_context *ctx);
 
 /* brw_wm.c */
 unsigned
-brw_compute_barycentric_interp_modes(void);
+brw_compute_barycentric_interp_modes(bool shade_model_flat,
+                                     const struct gl_fragment_program *fprog);
+
+/* gen6_clip_state.c */
+bool
+brw_fprog_uses_noperspective(const struct gl_fragment_program *fprog);
 
 
 
index 185e00d5a28f65dc3d0bf34f2406451778b41d0f..31c311661f02b21fad4eab49024cebf7c25c96a4 100644 (file)
@@ -469,7 +469,7 @@ fs_visitor::emit_general_interpolation(ir_variable *ir)
               attr.reg_offset++;
            }
         } else {
-           /* Perspective interpolation case. */
+           /* Smooth/noperspective interpolation case. */
            for (unsigned int k = 0; k < type->vector_elements; k++) {
               /* FINISHME: At some point we probably want to push
                * this farther by giving similar treatment to the
@@ -483,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);
-                  brw_wm_barycentric_interp_mode barycoord_mode =
-                     BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC;
+                  brw_wm_barycentric_interp_mode barycoord_mode;
+                  if (interpolation_mode == INTERP_QUALIFIER_SMOOTH)
+                     barycoord_mode = BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC;
+                  else
+                     barycoord_mode = BRW_WM_NONPERSPECTIVE_PIXEL_BARYCENTRIC;
                   emit(FS_OPCODE_LINTERP, attr,
                        this->delta_x[barycoord_mode],
                        this->delta_y[barycoord_mode], fs_reg(interp));
index 81dad4f76da4ffb4694c05dbf46c7061fa6cae2a..63c770debcc61748502513a924355b0c546b6678 100644 (file)
@@ -129,10 +129,41 @@ brw_wm_non_glsl_emit(struct brw_context *brw, struct brw_wm_compile *c)
  * (see enum brw_wm_barycentric_interp_mode) is needed by the fragment shader.
  */
 unsigned
-brw_compute_barycentric_interp_modes(void)
+brw_compute_barycentric_interp_modes(bool shade_model_flat,
+                                     const struct gl_fragment_program *fprog)
 {
-   /* At the moment the only interpolation mode we support is perspective. */
-   return (1 << BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC);
+   unsigned barycentric_interp_modes = 0;
+   int attr;
+
+   /* Loop through all fragment shader inputs to figure out what interpolation
+    * modes are in use, and set the appropriate bits in
+    * barycentric_interp_modes.
+    */
+   for (attr = 0; attr < FRAG_ATTRIB_MAX; ++attr) {
+      enum glsl_interp_qualifier interp_qualifier =
+         fprog->InterpQualifier[attr];
+      bool is_gl_Color = attr == FRAG_ATTRIB_COL0 || attr == FRAG_ATTRIB_COL1;
+
+      /* Ignore unused inputs. */
+      if (!(fprog->Base.InputsRead & BITFIELD64_BIT(attr)))
+         continue;
+
+      /* Ignore WPOS and FACE, because they don't require interpolation. */
+      if (attr == FRAG_ATTRIB_WPOS || attr == FRAG_ATTRIB_FACE)
+         continue;
+
+      if (interp_qualifier == INTERP_QUALIFIER_NOPERSPECTIVE) {
+         barycentric_interp_modes |=
+            1 << BRW_WM_NONPERSPECTIVE_PIXEL_BARYCENTRIC;
+      } else if (interp_qualifier == INTERP_QUALIFIER_SMOOTH ||
+                 (!(shade_model_flat && is_gl_Color) &&
+                  interp_qualifier == INTERP_QUALIFIER_NONE)) {
+         barycentric_interp_modes |=
+            1 << BRW_WM_PERSPECTIVE_PIXEL_BARYCENTRIC;
+      }
+   }
+
+   return barycentric_interp_modes;
 }
 
 
@@ -144,7 +175,8 @@ brw_wm_payload_setup(struct brw_context *brw,
    bool uses_depth = (c->fp->program.Base.InputsRead &
                      (1 << FRAG_ATTRIB_WPOS)) != 0;
    unsigned barycentric_interp_modes =
-      brw_compute_barycentric_interp_modes();
+      brw_compute_barycentric_interp_modes(c->key.flat_shade,
+                                           &c->fp->program);
    int i;
 
    if (intel->gen >= 6) {
index 9b36af47dde7f9169cdd50ed6a767843549d075a..b3bb8aee3ec3bb9bd0c46df3c49f4f9b2ebf604d 100644 (file)
 #include "brw_util.h"
 #include "intel_batchbuffer.h"
 
+/**
+ * Return true if at least one of the inputs used by the given fragment
+ * program has the GLSL "noperspective" interpolation qualifier.
+ */
+bool
+brw_fprog_uses_noperspective(const struct gl_fragment_program *fprog)
+{
+   int attr;
+   for (attr = 0; attr < FRAG_ATTRIB_MAX; ++attr) {
+      /* Ignore unused inputs. */
+      if (!(fprog->Base.InputsRead & BITFIELD64_BIT(attr)))
+         continue;
+
+      if (fprog->InterpQualifier[attr] == INTERP_QUALIFIER_NOPERSPECTIVE)
+         return true;
+   }
+   return false;
+}
+
+
 static void
 upload_clip_state(struct brw_context *brw)
 {
@@ -38,6 +58,14 @@ upload_clip_state(struct brw_context *brw)
    struct gl_context *ctx = &intel->ctx;
    uint32_t depth_clamp = 0;
    uint32_t provoking, userclip;
+   uint32_t nonperspective_barycentric_enable_flag = 0;
+   /* BRW_NEW_FRAGMENT_PROGRAM */
+   const struct gl_fragment_program *fprog = brw->fragment_program;
+
+   if (brw_fprog_uses_noperspective(fprog)) {
+      nonperspective_barycentric_enable_flag =
+         GEN6_CLIP_NON_PERSPECTIVE_BARYCENTRIC_ENABLE;
+   }
 
    if (!ctx->Transform.DepthClamp)
       depth_clamp = GEN6_CLIP_Z_TEST;
@@ -64,6 +92,7 @@ upload_clip_state(struct brw_context *brw)
    OUT_BATCH(GEN6_CLIP_ENABLE |
             GEN6_CLIP_API_OGL |
             GEN6_CLIP_MODE_NORMAL |
+             nonperspective_barycentric_enable_flag |
             GEN6_CLIP_XY_TEST |
             userclip << GEN6_USER_CLIP_CLIP_DISTANCES_SHIFT |
             depth_clamp |
@@ -77,7 +106,8 @@ upload_clip_state(struct brw_context *brw)
 const struct brw_tracked_state gen6_clip_state = {
    .dirty = {
       .mesa  = _NEW_TRANSFORM | _NEW_LIGHT,
-      .brw   = BRW_NEW_CONTEXT,
+      .brw   = (BRW_NEW_CONTEXT |
+                BRW_NEW_FRAGMENT_PROGRAM),
       .cache = 0
    },
    .emit = upload_clip_state,
index 67b649e7b79d1c5b6443635a1d33e5e01d36fc28..67119d8d1822df790637b8b37a36b7fe900f3e4e 100644 (file)
@@ -118,6 +118,8 @@ upload_sf_state(struct brw_context *brw)
    GLbitfield64 vs_outputs_written = brw->vs.prog_data->outputs_written;
    /* BRW_NEW_FRAGMENT_PROGRAM */
    uint32_t num_outputs = _mesa_bitcount_64(brw->fragment_program->Base.InputsRead);
+   /* _NEW_LIGHT */
+   bool shade_model_flat = ctx->Light.ShadeModel == GL_FLAT;
    uint32_t dw1, dw2, dw3, dw4, dw16, dw17;
    int i;
    /* _NEW_BUFFER */
@@ -263,6 +265,10 @@ upload_sf_state(struct brw_context *brw)
     * they source from.
     */
    for (; attr < FRAG_ATTRIB_MAX; attr++) {
+      enum glsl_interp_qualifier interp_qualifier =
+         brw->fragment_program->InterpQualifier[attr];
+      bool is_gl_Color = attr == FRAG_ATTRIB_COL0 || attr == FRAG_ATTRIB_COL1;
+
       if (!(brw->fragment_program->Base.InputsRead & BITFIELD64_BIT(attr)))
         continue;
 
@@ -277,17 +283,10 @@ upload_sf_state(struct brw_context *brw)
         dw16 |= (1 << input_index);
 
       /* flat shading */
-      if (ctx->Light.ShadeModel == GL_FLAT) {
-         /*
-          * Setup the Constant Interpolation Enable bit mask for each
-          * corresponding attribute(currently, we only care two attrs:
-          * FRAG_BIT_COL0 and FRAG_BIT_COL1).
-          *
-          * FIXME: should we care other attributes?
-          */
-         if (attr == FRAG_ATTRIB_COL0 || attr == FRAG_ATTRIB_COL1)
-             dw17 |= (1 << input_index);
-      }
+      if (interp_qualifier == INTERP_QUALIFIER_FLAT ||
+          (shade_model_flat && is_gl_Color &&
+           interp_qualifier == INTERP_QUALIFIER_NONE))
+         dw17 |= (1 << input_index);
 
       /* The hardware can only do the overrides on 16 overrides at a
        * time, and the other up to 16 have to be lined up so that the
index 178375f4133e18ce51c86e2af85fba2c5c7641af..ac1b1a3cc5ed9ae8a9e8236c5f1440a6d7159287 100644 (file)
@@ -99,6 +99,9 @@ upload_wm_state(struct brw_context *brw)
       brw_fragment_program_const(brw->fragment_program);
    uint32_t dw2, dw4, dw5, dw6;
 
+   /* _NEW_LIGHT */
+   bool flat_shade = (ctx->Light.ShadeModel == GL_FLAT);
+
     /* CACHE_NEW_WM_PROG */
    if (brw->wm.prog_data->nr_params == 0) {
       /* Disable the push constant buffers. */
@@ -168,6 +171,8 @@ upload_wm_state(struct brw_context *brw)
       dw5 |= GEN6_WM_USES_SOURCE_DEPTH | GEN6_WM_USES_SOURCE_W;
    if (fp->program.Base.OutputsWritten & BITFIELD64_BIT(FRAG_RESULT_DEPTH))
       dw5 |= GEN6_WM_COMPUTED_DEPTH;
+   dw6 |= brw_compute_barycentric_interp_modes(flat_shade, &fp->program) <<
+      GEN6_WM_BARYCENTRIC_INTERPOLATION_MODE_SHIFT;
 
    /* _NEW_COLOR */
    if (fp->program.UsesKill || ctx->Color.AlphaEnabled)
@@ -178,9 +183,6 @@ upload_wm_state(struct brw_context *brw)
       dw5 |= GEN6_WM_DISPATCH_ENABLE;
    }
 
-   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;
 
@@ -206,6 +208,7 @@ upload_wm_state(struct brw_context *brw)
 const struct brw_tracked_state gen6_wm_state = {
    .dirty = {
       .mesa  = (_NEW_LINE |
+                _NEW_LIGHT |
                _NEW_COLOR |
                _NEW_BUFFERS |
                _NEW_PROGRAM_CONSTANTS |
index da8d73a698e06613623383550532fc00448678e1..c32cd988297dbeef569f8e28f836e2da6daacb84 100644 (file)
@@ -35,10 +35,18 @@ upload_clip_state(struct brw_context *brw)
    uint32_t depth_clamp = 0;
    uint32_t provoking, userclip;
    uint32_t dw1 = GEN6_CLIP_STATISTICS_ENABLE;
+   uint32_t nonperspective_barycentric_enable_flag = 0;
+   /* BRW_NEW_FRAGMENT_PROGRAM */
+   const struct gl_fragment_program *fprog = brw->fragment_program;
 
    /* _NEW_BUFFERS */
    bool render_to_fbo = brw->intel.ctx.DrawBuffer->Name != 0;
 
+   if (brw_fprog_uses_noperspective(fprog)) {
+      nonperspective_barycentric_enable_flag =
+         GEN6_CLIP_NON_PERSPECTIVE_BARYCENTRIC_ENABLE;
+   }
+
    dw1 |= GEN7_CLIP_EARLY_CULL;
 
    /* _NEW_POLYGON */
@@ -90,6 +98,7 @@ upload_clip_state(struct brw_context *brw)
    OUT_BATCH(GEN6_CLIP_ENABLE |
             GEN6_CLIP_API_OGL |
             GEN6_CLIP_MODE_NORMAL |
+             nonperspective_barycentric_enable_flag |
             GEN6_CLIP_XY_TEST |
             userclip << GEN6_USER_CLIP_CLIP_DISTANCES_SHIFT |
             depth_clamp |
@@ -106,7 +115,8 @@ const struct brw_tracked_state gen7_clip_state = {
                 _NEW_POLYGON |
                 _NEW_LIGHT |
                 _NEW_TRANSFORM),
-      .brw   = BRW_NEW_CONTEXT,
+      .brw   = (BRW_NEW_CONTEXT |
+                BRW_NEW_FRAGMENT_PROGRAM),
       .cache = 0
    },
    .emit = upload_clip_state,
index e796a01b74dbab20691847c6de57ec188acf078f..d3ffbd39b4b292a0b81ce6f1dd185ed4d2737004 100644 (file)
@@ -39,6 +39,8 @@ upload_sbe_state(struct brw_context *brw)
    GLbitfield64 vs_outputs_written = brw->vs.prog_data->outputs_written;
    /* BRW_NEW_FRAGMENT_PROGRAM */
    uint32_t num_outputs = _mesa_bitcount_64(brw->fragment_program->Base.InputsRead);
+   /* _NEW_LIGHT */
+   bool shade_model_flat = ctx->Light.ShadeModel == GL_FLAT;
    uint32_t dw1, dw10, dw11;
    int i;
    int attr = 0, input_index = 0;
@@ -74,6 +76,10 @@ upload_sbe_state(struct brw_context *brw)
     * they source from.
     */
    for (; attr < FRAG_ATTRIB_MAX; attr++) {
+      enum glsl_interp_qualifier interp_qualifier =
+         brw->fragment_program->InterpQualifier[attr];
+      bool is_gl_Color = attr == FRAG_ATTRIB_COL0 || attr == FRAG_ATTRIB_COL1;
+
       if (!(brw->fragment_program->Base.InputsRead & BITFIELD64_BIT(attr)))
         continue;
 
@@ -87,17 +93,10 @@ upload_sbe_state(struct brw_context *brw)
         dw10 |= (1 << input_index);
 
       /* flat shading */
-      if (ctx->Light.ShadeModel == GL_FLAT) {
-         /*
-          * Setup the Constant Interpolation Enable bit mask for each
-          * corresponding attribute(currently, we only care two attrs:
-          * FRAG_BIT_COL0 and FRAG_BIT_COL1).
-          *
-          * FIXME: should we care other attributes?
-          */
-         if (attr == FRAG_ATTRIB_COL0 || attr == FRAG_ATTRIB_COL1)
-             dw11 |= (1 << input_index);
-      }
+      if (interp_qualifier == INTERP_QUALIFIER_FLAT ||
+          (shade_model_flat && is_gl_Color &&
+           interp_qualifier == INTERP_QUALIFIER_NONE))
+         dw11 |= (1 << input_index);
 
       /* The hardware can only do the overrides on 16 overrides at a
        * time, and the other up to 16 have to be lined up so that the
index fc23c2e161549a1089da87ae5f64f5d4d1624436..ba83340bde9f8bac5e5dadb95b6fcd9fb253b995 100644 (file)
@@ -41,6 +41,9 @@ upload_wm_state(struct brw_context *brw)
    bool writes_depth = false;
    uint32_t dw1;
 
+   /* _NEW_LIGHT */
+   bool flat_shade = (ctx->Light.ShadeModel == GL_FLAT);
+
    dw1 = 0;
    dw1 |= GEN7_WM_STATISTICS_ENABLE;
    dw1 |= GEN7_WM_LINE_AA_WIDTH_1_0;
@@ -61,6 +64,8 @@ upload_wm_state(struct brw_context *brw)
       writes_depth = true;
       dw1 |= GEN7_WM_PSCDEPTH_ON;
    }
+   dw1 |= brw_compute_barycentric_interp_modes(flat_shade, &fp->program) <<
+      GEN7_WM_BARYCENTRIC_INTERPOLATION_MODE_SHIFT;
 
    /* _NEW_COLOR */
    if (fp->program.UsesKill || ctx->Color.AlphaEnabled)
@@ -72,9 +77,6 @@ upload_wm_state(struct brw_context *brw)
       dw1 |= GEN7_WM_DISPATCH_ENABLE;
    }
 
-   dw1 |= brw_compute_barycentric_interp_modes() <<
-      GEN7_WM_BARYCENTRIC_INTERPOLATION_MODE_SHIFT;
-
    BEGIN_BATCH(3);
    OUT_BATCH(_3DSTATE_WM << 16 | (3 - 2));
    OUT_BATCH(dw1);
@@ -84,7 +86,7 @@ upload_wm_state(struct brw_context *brw)
 
 const struct brw_tracked_state gen7_wm_state = {
    .dirty = {
-      .mesa  = (_NEW_LINE | _NEW_POLYGON |
+      .mesa  = (_NEW_LINE | _NEW_LIGHT | _NEW_POLYGON |
                _NEW_COLOR | _NEW_BUFFERS),
       .brw   = (BRW_NEW_FRAGMENT_PROGRAM |
                BRW_NEW_URB_FENCE |