[Mesa-dev] [PATCH 8/8] i965: Flush pipeline on EndTransformFeedback.

Kenneth Graunke kenneth at whitecape.org
Wed Dec 14 01:44:37 PST 2011


On 12/13/2011 03:35 PM, Paul Berry wrote:
> A common use case for transform feedback is to perform one draw
> operation that writes transform feedback output to a buffer, followed
> by a second draw operation that consumes that buffer as vertex input.
> Since vertex input is consumed at an earlier pipeline stage than
> writing transform feedback output, we need to flush the pipeline to
> ensure that the transform feedback output is completely written before
> the data is consumed.
> 
> In an ideal world, we would do some dependency tracking, so that we
> would only flush the pipeline if the next draw call was about to
> consume data generated by a previous draw call in the same batch.
> However, since we don't have that sort of dependency tracking
> infrastructure right now, we just unconditionally flush the buffer
> every time glEndTransformFeedback() is called.  This will cause a
> performance hit compared to the ideal case (since we will sometimes
> flush the pipeline unnecessarily), but fortunately the performance hit
> will be confined to circumstances where transform feedback is in use.
> ---
>  src/mesa/drivers/dri/i965/brw_context.c |    8 ++++++--
>  src/mesa/drivers/dri/i965/brw_context.h |    5 +++++
>  src/mesa/drivers/dri/i965/gen6_sol.c    |   16 ++++++++++++++++
>  3 files changed, 27 insertions(+), 2 deletions(-)
> 
> diff --git a/src/mesa/drivers/dri/i965/brw_context.c b/src/mesa/drivers/dri/i965/brw_context.c
> index eb68bf4..f7b88c3 100644
> --- a/src/mesa/drivers/dri/i965/brw_context.c
> +++ b/src/mesa/drivers/dri/i965/brw_context.c
> @@ -52,6 +52,7 @@
>  
>  #include "tnl/t_pipeline.h"
>  #include "glsl/ralloc.h"
> +#include "intel_batchbuffer.h"
>  
>  /***************************************
>   * Mesa's Driver Functions
> @@ -109,7 +110,8 @@ static void brwPrepareExecBegin(struct gl_context *ctx)
>     }
>  }
>  
> -static void brwInitDriverFunctions( struct dd_function_table *functions )
> +static void brwInitDriverFunctions(struct intel_context *intel,
> +                                   struct dd_function_table *functions)
>  {
>     intelInitDriverFunctions( functions );
>  
> @@ -117,6 +119,8 @@ static void brwInitDriverFunctions( struct dd_function_table *functions )
>     brw_init_queryobj_functions(functions);
>  
>     functions->PrepareExecBegin = brwPrepareExecBegin;
> +   if (intel->gen == 6)
> +      functions->EndTransformFeedback = gen6_end_transform_feedback;

Unfortunately, this doesn't work: brwInitDriverFunctions is called
before intelInitContext, so intel->gen isn't set yet.  So this function
pointer never gets set, and gen6_end_transform_feedback never happens.

I blithely tried moving the brwInitDriverFunctions call after
intelInitContext, but that crashes.  Also, setting anything in
"functions" after intelInitContext simply doesn't take; something
must've copied the table (remapping code most likely).  In other words,
a generation check just isn't going to happen.

I think the best solution is to set the function pointer unconditionally
and add

   if (intel->gen < 6)
      return;

to the top of gen6_end_transform_feedback so it becomes a no-op on
earlier platforms.

Sorry for suggesting the generation check earlier; I didn't realize it
was impossible.

>  }
>  
>  bool
> @@ -136,7 +140,7 @@ brwCreateContext(int api,
>        return false;
>     }
>  
> -   brwInitDriverFunctions( &functions );
> +   brwInitDriverFunctions(intel, &functions);
>  
>     if (!intelInitContext( intel, api, mesaVis, driContextPriv,
>  			  sharedContextPrivate, &functions )) {
> diff --git a/src/mesa/drivers/dri/i965/brw_context.h b/src/mesa/drivers/dri/i965/brw_context.h
> index da1de02..fa6c883 100644
> --- a/src/mesa/drivers/dri/i965/brw_context.h
> +++ b/src/mesa/drivers/dri/i965/brw_context.h
> @@ -1071,6 +1071,11 @@ void brw_init_surface_formats(struct brw_context *brw);
>  bool
>  brw_fprog_uses_noperspective(const struct gl_fragment_program *fprog);
>  
> +/* gen6_sol.c */
> +void
> +gen6_end_transform_feedback(struct gl_context *ctx,
> +                            struct gl_transform_feedback_object *obj);
> +
>  
>  
>  /*======================================================================
> diff --git a/src/mesa/drivers/dri/i965/gen6_sol.c b/src/mesa/drivers/dri/i965/gen6_sol.c
> index af372c1..53e3325 100644
> --- a/src/mesa/drivers/dri/i965/gen6_sol.c
> +++ b/src/mesa/drivers/dri/i965/gen6_sol.c
> @@ -28,6 +28,7 @@
>  
>  #include "brw_context.h"
>  #include "intel_buffer_objects.h"
> +#include "intel_batchbuffer.h"
>  #include "brw_defines.h"
>  
>  static void
> @@ -100,3 +101,18 @@ const struct brw_tracked_state gen6_sol_surface = {
>     },
>     .emit = brw_update_sol_surfaces,
>  };
> +
> +void
> +gen6_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);
> +   struct intel_context *intel = &brw->intel;
> +   intel_batchbuffer_emit_mi_flush(intel);
> +}


More information about the mesa-dev mailing list