From: Kenneth Graunke Date: Sat, 27 Apr 2019 07:24:05 +0000 (-0700) Subject: iris: Fix zeroing of transform feedback offsets in strange cases. X-Git-Tag: upstream/19.3.0~6876 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=6bd4cb920e9c0b431df3ab2f5878b2b24182fd00;p=platform%2Fupstream%2Fmesa.git iris: Fix zeroing of transform feedback offsets in strange cases. 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. --- diff --git a/src/gallium/drivers/iris/iris_context.h b/src/gallium/drivers/iris/iris_context.h index 1153cb8..51bbdb6 100644 --- a/src/gallium/drivers/iris/iris_context.h +++ b/src/gallium/drivers/iris/iris_context.h @@ -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; }; /** diff --git a/src/gallium/drivers/iris/iris_state.c b/src/gallium/drivers/iris/iris_state.c index 0476671..479703f 100644 --- a/src/gallium/drivers/iris/iris_state.c +++ b/src/gallium/drivers/iris/iris_state.c @@ -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),