i965: Implement ARB_fragment_layer_viewport.
authorKenneth Graunke <kenneth@whitecape.org>
Wed, 17 Jun 2015 20:06:18 +0000 (13:06 -0700)
committerKenneth Graunke <kenneth@whitecape.org>
Thu, 29 Oct 2015 05:05:08 +0000 (22:05 -0700)
Normally, we could read gl_Layer from bits 26:16 of R0.0.  However, the
specification requires that bogus out-of-range 32-bit values written by
previous stages need to appear in the fragment shader as-written.

Instead, we pass in the full 32-bit value from the VUE header as an
extra flat-shaded varying.  We have the SF override the value to 0
when the previous stage didn't actually write a value (it's actually
defined to return 0).

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

index 2eef7af4e11d46e963ce5d794c1d4e6ef3007d4a..5a82b041370910b287fdaed6414bb61ed9569c68 100644 (file)
@@ -1442,6 +1442,9 @@ fs_visitor::calculate_urb_setup()
             }
          }
       } else {
+         bool include_vue_header =
+            nir->info.inputs_read & (VARYING_BIT_LAYER | VARYING_BIT_VIEWPORT);
+
          /* We have enough input varyings that the SF/SBE pipeline stage can't
           * arbitrarily rearrange them to suit our whim; we have to put them
           * in an order that matches the output of the previous pipeline stage
@@ -1451,7 +1454,9 @@ fs_visitor::calculate_urb_setup()
          brw_compute_vue_map(devinfo, &prev_stage_vue_map,
                              key->input_slots_valid,
                              nir->info.separate_shader);
-         int first_slot = 2 * BRW_SF_URB_ENTRY_READ_OFFSET;
+         int first_slot =
+            include_vue_header ? 0 : 2 * BRW_SF_URB_ENTRY_READ_OFFSET;
+
          assert(prev_stage_vue_map.num_slots <= first_slot + 32);
          for (int slot = first_slot; slot < prev_stage_vue_map.num_slots;
               slot++) {
index 4950ba4fe67b3a3d649c79e2fd8cff8bafba0dab..9c1f95c2229bb7671248ff309625c94432683e03 100644 (file)
@@ -71,6 +71,14 @@ fs_visitor::nir_setup_inputs()
                                              var->data.origin_upper_left);
          emit_percomp(bld, fs_inst(BRW_OPCODE_MOV, bld.dispatch_width(),
                                    input, reg), 0xF);
+      } else if (var->data.location == VARYING_SLOT_LAYER) {
+         struct brw_reg reg = suboffset(interp_reg(VARYING_SLOT_LAYER, 1), 3);
+         reg.type = BRW_REGISTER_TYPE_D;
+         bld.emit(FS_OPCODE_CINTERP, retype(input, BRW_REGISTER_TYPE_D), reg);
+      } else if (var->data.location == VARYING_SLOT_VIEWPORT) {
+         struct brw_reg reg = suboffset(interp_reg(VARYING_SLOT_VIEWPORT, 2), 3);
+         reg.type = BRW_REGISTER_TYPE_D;
+         bld.emit(FS_OPCODE_CINTERP, retype(input, BRW_REGISTER_TYPE_D), reg);
       } else {
          emit_general_interpolation(input, var->name, var->type,
                                     (glsl_interp_qualifier) var->data.interpolation,
index 0c8c05304f5fdee4a8180a98adcd4346c0c69eba..2634e6ba6fd20a3e65629ea9087172512e10c629 100644 (file)
@@ -60,6 +60,23 @@ get_attr_override(const struct brw_vue_map *vue_map, int urb_entry_read_offset,
    /* Find the VUE slot for this attribute. */
    int slot = vue_map->varying_to_slot[fs_attr];
 
+   /* Viewport and Layer are stored in the VUE header.  We need to override
+    * them to zero if earlier stages didn't write them, as GL requires that
+    * they read back as zero when not explicitly set.
+    */
+   if (fs_attr == VARYING_SLOT_VIEWPORT || fs_attr == VARYING_SLOT_LAYER) {
+      unsigned override =
+         ATTRIBUTE_0_OVERRIDE_X | ATTRIBUTE_0_OVERRIDE_W |
+         ATTRIBUTE_CONST_0000 << ATTRIBUTE_0_CONST_SOURCE_SHIFT;
+
+      if (!(vue_map->slots_valid & VARYING_BIT_LAYER))
+         override |= ATTRIBUTE_0_OVERRIDE_Y;
+      if (!(vue_map->slots_valid & VARYING_BIT_VIEWPORT))
+         override |= ATTRIBUTE_0_OVERRIDE_Z;
+
+      return override;
+   }
+
    /* If there was only a back color written but not front, use back
     * as the color instead of undefined
     */
@@ -169,6 +186,20 @@ calculate_attr_overrides(const struct brw_context *brw,
 
    *urb_entry_read_offset = BRW_SF_URB_ENTRY_READ_OFFSET;
 
+   /* BRW_NEW_FRAGMENT_PROGRAM
+    *
+    * If the fragment shader reads VARYING_SLOT_LAYER, then we need to pass in
+    * the full vertex header.  Otherwise, we can program the SF to start
+    * reading at an offset of 1 (2 varying slots) to skip unnecessary data:
+    * - VARYING_SLOT_PSIZ and BRW_VARYING_SLOT_NDC on gen4-5
+    * - VARYING_SLOT_{PSIZ,LAYER} and VARYING_SLOT_POS on gen6+
+    */
+
+   bool fs_needs_vue_header = brw->fragment_program->Base.InputsRead &
+      (VARYING_BIT_LAYER | VARYING_BIT_VIEWPORT);
+
+   *urb_entry_read_offset = fs_needs_vue_header ? 0 : 1;
+
    /* _NEW_LIGHT */
    bool shade_model_flat = brw->ctx.Light.ShadeModel == GL_FLAT;
 
index c6826d63dde2c0c25a1c36f22b95ba4e7df96ac6..4433410b4121a09a4b2467c3dbcfe2e27a095f43 100644 (file)
@@ -287,6 +287,7 @@ intelInitExtensions(struct gl_context *ctx)
       ctx->Extensions.ARB_conditional_render_inverted = true;
       ctx->Extensions.ARB_draw_buffers_blend = true;
       ctx->Extensions.ARB_ES3_compatibility = true;
+      ctx->Extensions.ARB_fragment_layer_viewport = true;
       ctx->Extensions.ARB_sample_shading = true;
       ctx->Extensions.ARB_shading_language_420pack = true;
       ctx->Extensions.ARB_shading_language_packing = true;