From 0235757422d825c37ca2d2c3feb9e58a28deedd4 Mon Sep 17 00:00:00 2001 From: Kenneth Graunke Date: Thu, 16 Feb 2017 21:24:20 -0800 Subject: [PATCH] i965: Properly reset SVBI counters on ResumeTransformFeedback(). This fixes Piglit's ARB_transform_feedback2/change-objects-while-paused GLES 3.0 test. When resuming the transform feedback object, we need to reset the SVBI counters so we continue writing at the correct point in the buffer. Instead of SO_WRITE_OFFSET counters (with a DWord offset), we have the Streamed Vertex Buffer Index (SVBI) counters, which contain a count of vertices emitted. Unfortunately, there's no straightforward way to store the current SVBI counter values to a buffer. They're not available in a register. You can use a bit in the 3DSTATE_SVB_INDEX packet to copy them to another internal counter which 3DPRIMITIVE can use...but there's no good way to extract that either. So, once again, we use SO_NUM_PRIMS_WRITTEN to calculate the vertex numbers. Thankfully, we can reuse most of the existing Gen7+ code. Signed-off-by: Kenneth Graunke Reviewed-by: Iago Toral Quiroga --- src/mesa/drivers/dri/i965/brw_context.c | 2 + src/mesa/drivers/dri/i965/brw_context.h | 6 ++ src/mesa/drivers/dri/i965/gen6_sol.c | 118 ++++++++++++++++++++---- 3 files changed, 108 insertions(+), 18 deletions(-) diff --git a/src/mesa/drivers/dri/i965/brw_context.c b/src/mesa/drivers/dri/i965/brw_context.c index c56a14e3d66..6a9f1570c31 100644 --- a/src/mesa/drivers/dri/i965/brw_context.c +++ b/src/mesa/drivers/dri/i965/brw_context.c @@ -481,6 +481,8 @@ brw_init_driver_functions(struct brw_context *brw, } else { functions->BeginTransformFeedback = brw_begin_transform_feedback; functions->EndTransformFeedback = brw_end_transform_feedback; + functions->PauseTransformFeedback = brw_pause_transform_feedback; + functions->ResumeTransformFeedback = brw_resume_transform_feedback; } if (brw->gen >= 6) diff --git a/src/mesa/drivers/dri/i965/brw_context.h b/src/mesa/drivers/dri/i965/brw_context.h index dde52cce67f..4cb96ce6cff 100644 --- a/src/mesa/drivers/dri/i965/brw_context.h +++ b/src/mesa/drivers/dri/i965/brw_context.h @@ -1461,6 +1461,12 @@ void brw_end_transform_feedback(struct gl_context *ctx, struct gl_transform_feedback_object *obj); void +brw_pause_transform_feedback(struct gl_context *ctx, + struct gl_transform_feedback_object *obj); +void +brw_resume_transform_feedback(struct gl_context *ctx, + struct gl_transform_feedback_object *obj); +void brw_save_primitives_written_counters(struct brw_context *brw, struct brw_transform_feedback_object *obj); void diff --git a/src/mesa/drivers/dri/i965/gen6_sol.c b/src/mesa/drivers/dri/i965/gen6_sol.c index f1cc2d59fd4..702cb2830f0 100644 --- a/src/mesa/drivers/dri/i965/gen6_sol.c +++ b/src/mesa/drivers/dri/i965/gen6_sol.c @@ -314,18 +314,12 @@ brw_save_primitives_written_counters(struct brw_context *brw, obj->prim_count_buffer_index += streams; } -/** - * Compute the number of vertices written by this transform feedback operation. - */ -void -brw_compute_xfb_vertices_written(struct brw_context *brw, - struct brw_transform_feedback_object *obj) +static void +compute_vertices_written_so_far(struct brw_context *brw, + struct brw_transform_feedback_object *obj, + uint64_t *vertices_written) { const struct gl_context *ctx = &brw->ctx; - - if (obj->vertices_written_valid || !obj->base.EndedAnytime) - return; - unsigned vertices_per_prim = 0; switch (obj->primitive_mode) { @@ -346,8 +340,22 @@ brw_compute_xfb_vertices_written(struct brw_context *brw, tally_prims_generated(brw, obj); for (int i = 0; i < ctx->Const.MaxVertexStreams; i++) { - obj->vertices_written[i] = vertices_per_prim * obj->prims_generated[i]; + vertices_written[i] = vertices_per_prim * obj->prims_generated[i]; } +} + +/** + * Compute the number of vertices written by this transform feedback operation. + */ +void +brw_compute_xfb_vertices_written(struct brw_context *brw, + struct brw_transform_feedback_object *obj) +{ + if (obj->vertices_written_valid || !obj->base.EndedAnytime) + return; + + compute_vertices_written_so_far(brw, obj, obj->vertices_written); + obj->vertices_written_valid = true; } @@ -423,18 +431,92 @@ brw_begin_transform_feedback(struct gl_context *ctx, GLenum mode, OUT_BATCH(0xffffffff); ADVANCE_BATCH(); } + + /* We're about to lose the information needed to compute the number of + * vertices written during the last Begin/EndTransformFeedback section, + * so we can't delay it any further. + */ + brw_compute_xfb_vertices_written(brw, brw_obj); + + /* No primitives have been generated yet. */ + for (int i = 0; i < BRW_MAX_XFB_STREAMS; i++) { + brw_obj->prims_generated[i] = 0; + } + + /* Store the starting value of the SO_NUM_PRIMS_WRITTEN counters. */ + brw_save_primitives_written_counters(brw, brw_obj); + + brw_obj->primitive_mode = mode; } void brw_end_transform_feedback(struct gl_context *ctx, struct gl_transform_feedback_object *obj) { - /* After EndTransformFeedback, it's likely that the client program will try - * to draw using the contents of the transform feedback buffer as vertex - * input. In order for this to work, we need to flush the data through at - * least the GS stage of the pipeline, and flush out the render cache. For - * simplicity, just do a full flush. - */ struct brw_context *brw = brw_context(ctx); - brw_emit_mi_flush(brw); + struct brw_transform_feedback_object *brw_obj = + (struct brw_transform_feedback_object *) obj; + + /* Store the ending value of the SO_NUM_PRIMS_WRITTEN counters. */ + if (!obj->Paused) + brw_save_primitives_written_counters(brw, brw_obj); + + /* EndTransformFeedback() means that we need to update the number of + * vertices written. Since it's only necessary if DrawTransformFeedback() + * is called and it means mapping a buffer object, we delay computing it + * until it's absolutely necessary to try and avoid stalls. + */ + brw_obj->vertices_written_valid = false; +} + +void +brw_pause_transform_feedback(struct gl_context *ctx, + struct gl_transform_feedback_object *obj) +{ + struct brw_context *brw = brw_context(ctx); + struct brw_transform_feedback_object *brw_obj = + (struct brw_transform_feedback_object *) obj; + + /* Store the temporary ending value of the SO_NUM_PRIMS_WRITTEN counters. + * While this operation is paused, other transform feedback actions may + * occur, which will contribute to the counters. We need to exclude that + * from our counts. + */ + brw_save_primitives_written_counters(brw, brw_obj); +} + +void +brw_resume_transform_feedback(struct gl_context *ctx, + struct gl_transform_feedback_object *obj) +{ + struct brw_context *brw = brw_context(ctx); + struct brw_transform_feedback_object *brw_obj = + (struct brw_transform_feedback_object *) obj; + + /* Reload SVBI 0 with the count of vertices written so far. */ + uint64_t svbi; + compute_vertices_written_so_far(brw, brw_obj, &svbi); + + BEGIN_BATCH(4); + OUT_BATCH(_3DSTATE_GS_SVB_INDEX << 16 | (4 - 2)); + OUT_BATCH(0); /* SVBI 0 */ + OUT_BATCH((uint32_t) svbi); /* starting index */ + OUT_BATCH(brw_obj->max_index); + ADVANCE_BATCH(); + + /* Initialize the rest of the unused streams to sane values. Otherwise, + * they may indicate that there is no room to write data and prevent + * anything from happening at all. + */ + for (int i = 1; i < 4; i++) { + BEGIN_BATCH(4); + OUT_BATCH(_3DSTATE_GS_SVB_INDEX << 16 | (4 - 2)); + OUT_BATCH(i << SVB_INDEX_SHIFT); + OUT_BATCH(0); /* starting index */ + OUT_BATCH(0xffffffff); + ADVANCE_BATCH(); + } + + /* Store the new starting value of the SO_NUM_PRIMS_WRITTEN counters. */ + brw_save_primitives_written_counters(brw, brw_obj); }