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

Brian Paul brianp at vmware.com
Fri Dec 7 13:09:18 PST 2012


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



More information about the mesa-dev mailing list