iris: Fix zeroing of transform feedback offsets in strange cases.
authorKenneth Graunke <kenneth@whitecape.org>
Sat, 27 Apr 2019 07:24:05 +0000 (00:24 -0700)
committerKenneth Graunke <kenneth@whitecape.org>
Sat, 27 Apr 2019 08:07:14 +0000 (01:07 -0700)
Some of the dEQP.functional.transform_feedback tests end up doing
the following sequence of operations:

   1. BeginTransformFeedback
   2. PauseTransformFeedback
   3. Draw
   4. ResumeTransformFeedback

At step 1, we'd pack 3DSTATE_SO_BUFFER commands saying to zero the
SO_WRITE_OFFSET registers.  At step 2, we disable streamout, so step 3
doesn't bother emitting those commands.  Then, step 4 re-packs new
3DSTATE_SO_BUFFER commands with offset = 0xFFFFFFFF, saying to continue
appending at the existing offset.  This loads the value from the BO as
the offsets - but we never actually zeroed it.

So, just maintain a flag saying "we actually emitted the commands",
and stomp offset back to zero until we emit some.

src/gallium/drivers/iris/iris_context.h
src/gallium/drivers/iris/iris_state.c

index 1153cb84bb93e56db602fb75181963f8ac6af34e..51bbdb681e72fa0ec9c80317ca2b77546d4d5333 100644 (file)
@@ -332,6 +332,9 @@ struct iris_stream_output_target {
 
    /** Stride (dwords-per-vertex) during this transform feedback operation */
    uint16_t stride;
+
+   /** Has 3DSTATE_SO_BUFFER actually been emitted, zeroing the offsets? */
+   bool zeroed;
 };
 
 /**
index 04766716bc05aee5f33b91119ad85608047e621f..479703f30fa7412d336e398590d878e6dbb63d8d 100644 (file)
@@ -2984,20 +2984,30 @@ iris_set_stream_output_targets(struct pipe_context *ctx,
    for (unsigned i = 0; i < 4; i++,
         so_buffers += GENX(3DSTATE_SO_BUFFER_length)) {
 
-      if (i >= num_targets || !targets[i]) {
+      struct iris_stream_output_target *tgt = (void *) ice->state.so_target[i];
+      unsigned offset = offsets[i];
+
+      if (!tgt) {
          iris_pack_command(GENX(3DSTATE_SO_BUFFER), so_buffers, sob)
             sob.SOBufferIndex = i;
          continue;
       }
 
-      struct iris_stream_output_target *tgt = (void *) targets[i];
       struct iris_resource *res = (void *) tgt->base.buffer;
 
       /* Note that offsets[i] will either be 0, causing us to zero
        * the value in the buffer, or 0xFFFFFFFF, which happens to mean
        * "continue appending at the existing offset."
        */
-      assert(offsets[i] == 0 || offsets[i] == 0xFFFFFFFF);
+      assert(offset == 0 || offset == 0xFFFFFFFF);
+
+      /* We might be called by Begin (offset = 0), Pause, then Resume
+       * (offset = 0xFFFFFFFF) before ever drawing (where these commands
+       * will actually be sent to the GPU).  In this case, we don't want
+       * to append - we still want to do our initial zeroing.
+       */
+      if (!tgt->zeroed)
+         offset = 0;
 
       iris_pack_command(GENX(3DSTATE_SO_BUFFER), so_buffers, sob) {
          sob.SurfaceBaseAddress =
@@ -3010,7 +3020,7 @@ iris_set_stream_output_targets(struct pipe_context *ctx,
          sob.SurfaceSize = MAX2(tgt->base.buffer_size / 4, 1) - 1;
 
          sob.SOBufferIndex = i;
-         sob.StreamOffset = offsets[i];
+         sob.StreamOffset = offset;
          sob.StreamOutputBufferOffsetAddress =
             rw_bo(NULL, iris_resource_bo(tgt->offset.res)->gtt_offset +
                         tgt->offset.offset);
@@ -4717,6 +4727,7 @@ iris_upload_dirty_render_state(struct iris_context *ice,
             struct iris_stream_output_target *tgt =
                (void *) ice->state.so_target[i];
             if (tgt) {
+               tgt->zeroed = true;
                iris_use_pinned_bo(batch, iris_resource_bo(tgt->base.buffer),
                                   true);
                iris_use_pinned_bo(batch, iris_resource_bo(tgt->offset.res),