[Mesa-dev] [PATCH 6/6] draw: fix/improve dirty state validation

Jose Fonseca jfonseca at vmware.com
Sat Dec 8 02:48:29 PST 2012


Reviewed-by: Jose Fonseca <jfonseca at vmware.com>

Series looks excellent Brian. Thanks for nailing this issue. I never stop to be amazed on how state derivation bugs go unnoticed for so long, just because most apps ends up touch a lot of state at the same time. One could try to write piglit tests that draw something, change one bit of state, re-draw, but it would take a lot of tests to cover everything.

Slight different issue -- you originally were looking into draw module and user buffer pointers -- is draw module actually properly flushing whenever user buffers are used? Or is that still outstanding?

Jose

----- Original Message -----
> This patch does two things:
> 
> 1. Constant buffer state changes were broken (but happened to work by
>    dumb luck).  The problem is we weren't calling draw_do_flush() in
>    draw_set_mapped_constant_buffer() when we changed that state.  All
>    the
>    other draw_set_foo() functions were calling draw_do_flush()
>    already.
> 
> 2. Use a simpler state validation step when we're changing
> light-weight
>    parameter state such as constant buffers, viewport dims or clip
>    planes.
>    There's no need to revalidate the whole pipeline when changing
>    state
>    like that.  The new validation method is called bind_parameters()
>    and is called instead of the prepare() method.  A new
>    DRAW_FLUSH_PARAMETER_CHANGE flag is used to signal these
>    light-weight
>    state changes.  This results in a modest but measurable increase
>    in
>    FPS for many Mesa demos.
> ---
>  src/gallium/auxiliary/draw/draw_context.c          |    6 ++-
>  src/gallium/auxiliary/draw/draw_pipe.c             |    2 +-
>  src/gallium/auxiliary/draw/draw_private.h          |    7 ++-
>  src/gallium/auxiliary/draw/draw_pt.c               |   14 ++++++-
>  src/gallium/auxiliary/draw/draw_pt.h               |    7 +++
>  .../auxiliary/draw/draw_pt_fetch_shade_pipeline.c  |   10 +++++
>  .../draw/draw_pt_fetch_shade_pipeline_llvm.c       |   43
>  ++++++++++++-------
>  src/gallium/auxiliary/draw/draw_pt_vsplit.c        |    2 +-
>  8 files changed, 68 insertions(+), 23 deletions(-)
> 
> diff --git a/src/gallium/auxiliary/draw/draw_context.c
> b/src/gallium/auxiliary/draw/draw_context.c
> index c231aba..bc2f0e1 100644
> --- a/src/gallium/auxiliary/draw/draw_context.c
> +++ b/src/gallium/auxiliary/draw/draw_context.c
> @@ -289,7 +289,7 @@ void draw_set_rasterize_stage( struct
> draw_context *draw,
>  void draw_set_clip_state( struct draw_context *draw,
>                            const struct pipe_clip_state *clip )
>  {
> -   draw_do_flush( draw, DRAW_FLUSH_STATE_CHANGE );
> +   draw_do_flush(draw, DRAW_FLUSH_PARAMETER_CHANGE);
>  
>     memcpy(&draw->plane[6], clip->ucp, sizeof(clip->ucp));
>  }
> @@ -301,7 +301,7 @@ void draw_set_clip_state( struct draw_context
> *draw,
>  void draw_set_viewport_state( struct draw_context *draw,
>                                const struct pipe_viewport_state
>                                *viewport )
>  {
> -   draw_do_flush( draw, DRAW_FLUSH_STATE_CHANGE );
> +   draw_do_flush(draw, DRAW_FLUSH_PARAMETER_CHANGE);
>     draw->viewport = *viewport; /* struct copy */
>     draw->identity_viewport = (viewport->scale[0] == 1.0f &&
>                                viewport->scale[1] == 1.0f &&
> @@ -368,6 +368,8 @@ draw_set_mapped_constant_buffer(struct
> draw_context *draw,
>                  shader_type == PIPE_SHADER_GEOMETRY);
>     debug_assert(slot < PIPE_MAX_CONSTANT_BUFFERS);
>  
> +   draw_do_flush(draw, DRAW_FLUSH_PARAMETER_CHANGE);
> +
>     switch (shader_type) {
>     case PIPE_SHADER_VERTEX:
>        draw->pt.user.vs_constants[slot] = buffer;
> diff --git a/src/gallium/auxiliary/draw/draw_pipe.c
> b/src/gallium/auxiliary/draw/draw_pipe.c
> index ac449b7..f1ee6cb 100644
> --- a/src/gallium/auxiliary/draw/draw_pipe.c
> +++ b/src/gallium/auxiliary/draw/draw_pipe.c
> @@ -347,6 +347,6 @@ void draw_pipeline_flush( struct draw_context
> *draw,
>                            unsigned flags )
>  {
>     draw->pipeline.first->flush( draw->pipeline.first, flags );
> -   if (!(flags & DRAW_FLUSH_BACKEND))
> +   if (flags & DRAW_FLUSH_STATE_CHANGE)
>        draw->pipeline.first = draw->pipeline.validate;
>  }
> diff --git a/src/gallium/auxiliary/draw/draw_private.h
> b/src/gallium/auxiliary/draw/draw_private.h
> index e52b3fd..2223fcb 100644
> --- a/src/gallium/auxiliary/draw/draw_private.h
> +++ b/src/gallium/auxiliary/draw/draw_private.h
> @@ -144,6 +144,8 @@ struct draw_context
>        unsigned opt;     /**< bitmask of PT_x flags */
>        unsigned eltSize; /* saved eltSize for flushing */
>  
> +      boolean rebind_parameters;
> +
>        struct {
>           struct draw_pt_middle_end *fetch_emit;
>           struct draw_pt_middle_end *fetch_shade_emit;
> @@ -434,8 +436,9 @@ void draw_pipeline_flush( struct draw_context
> *draw,
>   * Flushing
>   */
>  
> -#define DRAW_FLUSH_STATE_CHANGE              0x8
> -#define DRAW_FLUSH_BACKEND                   0x10
> +#define DRAW_FLUSH_PARAMETER_CHANGE 0x1  /**< Constants, viewport,
> etc */
> +#define DRAW_FLUSH_STATE_CHANGE     0x2  /**< Other/heavy state
> changes */
> +#define DRAW_FLUSH_BACKEND          0x4  /**< Flush the output
> buffer */
>  
>  
>  void draw_do_flush( struct draw_context *draw, unsigned flags );
> diff --git a/src/gallium/auxiliary/draw/draw_pt.c
> b/src/gallium/auxiliary/draw/draw_pt.c
> index 7113b9e..ddaedcd 100644
> --- a/src/gallium/auxiliary/draw/draw_pt.c
> +++ b/src/gallium/auxiliary/draw/draw_pt.c
> @@ -139,6 +139,12 @@ draw_pt_arrays(struct draw_context *draw,
>        draw->pt.opt = opt;
>     }
>  
> +   if (draw->pt.rebind_parameters) {
> +      /* update constants, viewport dims, clip planes, etc */
> +      middle->bind_parameters(middle);
> +      draw->pt.rebind_parameters = FALSE;
> +   }
> +
>     frontend->run( frontend, start, count );
>  
>     return TRUE;
> @@ -146,13 +152,19 @@ draw_pt_arrays(struct draw_context *draw,
>  
>  void draw_pt_flush( struct draw_context *draw, unsigned flags )
>  {
> +   assert(flags);
> +
>     if (draw->pt.frontend) {
>        draw->pt.frontend->flush( draw->pt.frontend, flags );
>  
>        /* don't prepare if we only are flushing the backend */
> -      if (!(flags & DRAW_FLUSH_BACKEND))
> +      if (flags & DRAW_FLUSH_STATE_CHANGE)
>           draw->pt.frontend = NULL;
>     }
> +
> +   if (flags & DRAW_FLUSH_PARAMETER_CHANGE) {
> +      draw->pt.rebind_parameters = TRUE;
> +   }
>  }
>  
>  
> diff --git a/src/gallium/auxiliary/draw/draw_pt.h
> b/src/gallium/auxiliary/draw/draw_pt.h
> index 2c2efdc..7d07363 100644
> --- a/src/gallium/auxiliary/draw/draw_pt.h
> +++ b/src/gallium/auxiliary/draw/draw_pt.h
> @@ -93,6 +93,13 @@ struct draw_pt_middle_end {
>  		    unsigned opt,
>                      unsigned *max_vertices );
>  
> +   /**
> +    * Bind/update parameter state such as constants, viewport dims
> +    * and clip planes.  Basically, stuff which isn't "baked" into
> the
> +    * shader or pipeline state.
> +    */
> +   void (*bind_parameters)(struct draw_pt_middle_end *);
> +
>     void (*run)( struct draw_pt_middle_end *,
>                  const unsigned *fetch_elts,
>                  unsigned fetch_count,
> diff --git
> a/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline.c
> b/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline.c
> index a6f5484..d1b76b1 100644
> --- a/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline.c
> +++ b/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline.c
> @@ -137,6 +137,15 @@ static void fetch_pipeline_prepare( struct
> draw_pt_middle_end *middle,
>  }
>  
>  
> +static void
> +fetch_pipeline_bind_parameters(struct draw_pt_middle_end *middle)
> +{
> +   /* No-op since the vertex shader executor and drawing pipeline
> +    * just grab the constants, viewport, etc. from the draw context
> state.
> +    */
> +}
> +
> +
>  static void fetch( struct pt_fetch *fetch,
>                     const struct draw_fetch_info *fetch_info,
>                     char *output)
> @@ -421,6 +430,7 @@ struct draw_pt_middle_end
> *draw_pt_fetch_pipeline_or_emit( struct draw_context *
>        goto fail;
>  
>     fpme->base.prepare        = fetch_pipeline_prepare;
> +   fpme->base.bind_parameters  = fetch_pipeline_bind_parameters;
>     fpme->base.run            = fetch_pipeline_run;
>     fpme->base.run_linear     = fetch_pipeline_linear_run;
>     fpme->base.run_linear_elts = fetch_pipeline_linear_run_elts;
> diff --git
> a/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline_llvm.c
> b/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline_llvm.c
> index 2230a7e..bfad54b 100644
> --- a/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline_llvm.c
> +++ b/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline_llvm.c
> @@ -180,24 +180,34 @@ llvm_middle_end_prepare( struct
> draw_pt_middle_end *middle,
>  
>        fpme->current_variant = variant;
>     }
> +}
>  
> -   /* Bind the VS and GS input constants, clip planes and viewport
> */
> -   {
> -      unsigned i;
>  
> -      for (i = 0; i <
> Elements(fpme->llvm->jit_context.vs_constants); ++i) {
> -         fpme->llvm->jit_context.vs_constants[i] =
> -            draw->pt.user.vs_constants[i];
> -      }
> -      for (i = 0; i <
> Elements(fpme->llvm->jit_context.gs_constants); ++i) {
> -         fpme->llvm->jit_context.gs_constants[i] =
> -            draw->pt.user.gs_constants[i];
> -      }
> -      fpme->llvm->jit_context.planes =
> -         (float (*) [DRAW_TOTAL_CLIP_PLANES][4])
> draw->pt.user.planes[0];
> -      fpme->llvm->jit_context.viewport =
> -         (float *) draw->viewport.scale;
> -   }
> +/**
> + * Bind/update constant buffer pointers, clip planes and viewport
> dims.
> + * These are "light weight" parameters which aren't baked into the
> + * generated code.  Updating these items is much cheaper than
> revalidating
> + * and rebuilding the generated pipeline code.
> + */
> +static void
> +llvm_middle_end_bind_parameters(struct draw_pt_middle_end *middle)
> +{
> +   struct llvm_middle_end *fpme = (struct llvm_middle_end *)middle;
> +   struct draw_context *draw = fpme->draw;
> +   unsigned i;
> +
> +   for (i = 0; i < Elements(fpme->llvm->jit_context.vs_constants);
> ++i) {
> +      fpme->llvm->jit_context.vs_constants[i] =
> draw->pt.user.vs_constants[i];
> +   }
> +
> +   for (i = 0; i < Elements(fpme->llvm->jit_context.gs_constants);
> ++i) {
> +      fpme->llvm->jit_context.gs_constants[i] =
> draw->pt.user.gs_constants[i];
> +   }
> +
> +   fpme->llvm->jit_context.planes =
> +      (float (*)[DRAW_TOTAL_CLIP_PLANES][4])
> draw->pt.user.planes[0];
> +
> +   fpme->llvm->jit_context.viewport = (float *)
> draw->viewport.scale;
>  }
>  
>  
> @@ -448,6 +458,7 @@ draw_pt_fetch_pipeline_or_emit_llvm(struct
> draw_context *draw)
>        goto fail;
>  
>     fpme->base.prepare         = llvm_middle_end_prepare;
> +   fpme->base.bind_parameters = llvm_middle_end_bind_parameters;
>     fpme->base.run             = llvm_middle_end_run;
>     fpme->base.run_linear      = llvm_middle_end_linear_run;
>     fpme->base.run_linear_elts = llvm_middle_end_linear_run_elts;
> diff --git a/src/gallium/auxiliary/draw/draw_pt_vsplit.c
> b/src/gallium/auxiliary/draw/draw_pt_vsplit.c
> index 0fed057..c2d2a8f 100644
> --- a/src/gallium/auxiliary/draw/draw_pt_vsplit.c
> +++ b/src/gallium/auxiliary/draw/draw_pt_vsplit.c
> @@ -182,7 +182,7 @@ static void vsplit_flush(struct draw_pt_front_end
> *frontend, unsigned flags)
>  {
>     struct vsplit_frontend *vsplit = (struct vsplit_frontend *)
>     frontend;
>  
> -   if (!(flags & DRAW_FLUSH_BACKEND)) {
> +   if (flags & DRAW_FLUSH_STATE_CHANGE) {
>        vsplit->middle->finish(vsplit->middle);
>        vsplit->middle = NULL;
>     }
> --
> 1.7.3.4
> 
> _______________________________________________
> mesa-dev mailing list
> mesa-dev at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/mesa-dev
> 


More information about the mesa-dev mailing list