drm/i915: Add support for resetting the SO write pointers on gen7.
authorEric Anholt <eric@anholt.net>
Tue, 3 Jan 2012 17:23:29 +0000 (09:23 -0800)
committerKeith Packard <keithp@keithp.com>
Tue, 3 Jan 2012 17:31:18 +0000 (09:31 -0800)
These registers are automatically incremented by the hardware during
transform feedback to track where the next streamed vertex output
should go.  Unlike the previous generation, which had a packet for
setting the corresponding registers to a defined value, gen7 only has
MI_LOAD_REGISTER_IMM to do so.  That's a secure packet (since it loads
an arbitrary register), so we need to do it from the kernel, and it
needs to be settable atomically with the batchbuffer execution so that
two clients doing transform feedback don't stomp on each others'
state.

Instead of building a more complicated interface involcing setting the
registers to a specific value, just set them to 0 when asked and
userland can tweak its pointers accordingly.

Signed-off-by: Eric Anholt <eric@anholt.net>
Reviewed-by: Eugeni Dodonov <eugeni.dodonov@intel.com>
Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
Signed-off-by: Keith Packard <keithp@keithp.com>
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/i915_gem_execbuffer.c
drivers/gpu/drm/i915/i915_reg.h
include/drm/i915_drm.h

index 77dace6a01f62751dec6c94b5a5cbe91b94d590a..5f4d5893e98356ff8b657a3a3048858d8ba15fab 100644 (file)
@@ -781,6 +781,9 @@ static int i915_getparam(struct drm_device *dev, void *data,
        case I915_PARAM_HAS_RELAXED_DELTA:
                value = 1;
                break;
+       case I915_PARAM_HAS_GEN7_SOL_RESET:
+               value = 1;
+               break;
        default:
                DRM_DEBUG_DRIVER("Unknown parameter %d\n",
                                 param->param);
index 11545ff90db646b16a42f6cdc382733229f5d2e2..c01cb20184970e16e85f2ed3d4738deac7d5eff2 100644 (file)
@@ -970,6 +970,31 @@ i915_gem_execbuffer_retire_commands(struct drm_device *dev,
        }
 }
 
+static int
+i915_reset_gen7_sol_offsets(struct drm_device *dev,
+                           struct intel_ring_buffer *ring)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       int ret, i;
+
+       if (!IS_GEN7(dev) || ring != &dev_priv->ring[RCS])
+               return 0;
+
+       ret = intel_ring_begin(ring, 4 * 3);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < 4; i++) {
+               intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1));
+               intel_ring_emit(ring, GEN7_SO_WRITE_OFFSET(i));
+               intel_ring_emit(ring, 0);
+       }
+
+       intel_ring_advance(ring);
+
+       return 0;
+}
+
 static int
 i915_gem_do_execbuffer(struct drm_device *dev, void *data,
                       struct drm_file *file,
@@ -1184,6 +1209,12 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
                dev_priv->relative_constants_mode = mode;
        }
 
+       if (args->flags & I915_EXEC_GEN7_SOL_RESET) {
+               ret = i915_reset_gen7_sol_offsets(dev, ring);
+               if (ret)
+                       goto err;
+       }
+
        trace_i915_gem_ring_dispatch(ring, seqno);
 
        exec_start = batch_obj->gtt_offset + args->batch_start_offset;
index edced95aa75f9c1efb62860b42b687a6a328547b..c3afb783cb9d93bf7c79dd32a18d8627ed6bfd0d 100644 (file)
 #define CPT_AUD_CNTL_ST_A              0xE50B4
 #define CPT_AUD_CNTRL_ST2              0xE50C0
 
+/* These are the 4 32-bit write offset registers for each stream
+ * output buffer.  It determines the offset from the
+ * 3DSTATE_SO_BUFFERs that the next streamed vertex output goes to.
+ */
+#define GEN7_SO_WRITE_OFFSET(n)                (0x5280 + (n) * 4)
+
 #endif /* _I915_REG_H_ */
index 1b4da1a9ec0f6d653cd8e4500e124e418ed78b46..924f6a454fed97d9b84dbbbbdfc32751b82759db 100644 (file)
@@ -295,6 +295,7 @@ typedef struct drm_i915_irq_wait {
 #define I915_PARAM_HAS_COHERENT_RINGS   13
 #define I915_PARAM_HAS_EXEC_CONSTANTS   14
 #define I915_PARAM_HAS_RELAXED_DELTA    15
+#define I915_PARAM_HAS_GEN7_SOL_RESET   16
 
 typedef struct drm_i915_getparam {
        int param;
@@ -657,6 +658,9 @@ struct drm_i915_gem_execbuffer2 {
        __u64 rsvd2;
 };
 
+/** Resets the SO write offset registers for transform feedback on gen7. */
+#define I915_EXEC_GEN7_SOL_RESET       (1<<8)
+
 struct drm_i915_gem_pin {
        /** Handle of the buffer to be pinned. */
        __u32 handle;