[Mesa-dev] [PATCH 2/2] draw: implement pipeline statistics in the draw module

Jose Fonseca jfonseca at vmware.com
Fri Apr 12 02:00:58 PDT 2013



----- Original Message -----
> This is a basic implementation of the pipeline statistics in the
> draw module. The interface is similar to the stream output statistics
> and also requires that the callers explicitly enable it.
> Included is the implementation of the interface in llvmpipe and
> softpipe. Only softpipe enables the pipeline statistics capability
> though because llvmpipe is lacking gathering of the fragment shading
> and rasterization statistics.
> 
> Signed-off-by: Zack Rusin <zackr at vmware.com>
> ---
>  src/gallium/auxiliary/draw/draw_context.c          |   16 +++++++++
>  src/gallium/auxiliary/draw/draw_context.h          |    7 ++++
>  src/gallium/auxiliary/draw/draw_gs.c               |   24 +++++++++++---
>  src/gallium/auxiliary/draw/draw_private.h          |    3 ++
>  src/gallium/auxiliary/draw/draw_pt.c               |    6 ++++
>  src/gallium/auxiliary/draw/draw_pt_emit.c          |   21 ++++++++++++
>  .../auxiliary/draw/draw_pt_fetch_shade_pipeline.c  |    6 ++++
>  .../draw/draw_pt_fetch_shade_pipeline_llvm.c       |    7 ++++
>  src/gallium/auxiliary/draw/draw_vbuf.h             |    8 +++++
>  src/gallium/auxiliary/util/u_prim.h                |   35
>  +++++++++++---------
>  src/gallium/drivers/llvmpipe/lp_context.h          |    3 ++
>  src/gallium/drivers/llvmpipe/lp_draw_arrays.c      |    6 ++++
>  src/gallium/drivers/llvmpipe/lp_query.c            |   16 +++++++++
>  src/gallium/drivers/llvmpipe/lp_query.h            |    2 ++
>  src/gallium/drivers/llvmpipe/lp_rast.c             |    2 ++
>  src/gallium/drivers/llvmpipe/lp_setup_vbuf.c       |   23 +++++++++++++
>  src/gallium/drivers/softpipe/sp_context.h          |    3 ++
>  src/gallium/drivers/softpipe/sp_draw_arrays.c      |    7 ++++
>  src/gallium/drivers/softpipe/sp_prim_vbuf.c        |   23 +++++++++++++
>  src/gallium/drivers/softpipe/sp_quad_fs.c          |    5 +++
>  src/gallium/drivers/softpipe/sp_query.c            |   18 +++++++++-
>  src/gallium/drivers/softpipe/sp_screen.c           |    2 +-
>  src/gallium/drivers/softpipe/sp_setup.c            |    4 +++
>  23 files changed, 226 insertions(+), 21 deletions(-)
> 
> diff --git a/src/gallium/auxiliary/draw/draw_context.c
> b/src/gallium/auxiliary/draw/draw_context.c
> index 2fb9bac..0f98021 100644
> --- a/src/gallium/auxiliary/draw/draw_context.c
> +++ b/src/gallium/auxiliary/draw/draw_context.c
> @@ -842,3 +842,19 @@ draw_get_shader_param(unsigned shader, enum
> pipe_shader_cap param)
>     return draw_get_shader_param_no_llvm(shader, param);
>  }
>  
> +/**
> + * Enables or disables collection of statistics.
> + *
> + * Draw module is capable of generating statistics for the vertex
> + * processing pipeline. Collection of that data isn't free and so
> + * it's disabled by default. The users of the module can enable
> + * (or disable) this functionality through this function.
> + * The actual data will be emitted through the VBUF interface,
> + * the 'pipeline_statistics' callback to be exact.

I wonder if, instead of sending statistics down the pipe with through vbuf, it would be simpler to just have

   void draw_statistics_start(struct draw_context *draw)
   void draw_statistics_end(struct draw_context *draw,
                            struct pipe_query_data_pipeline_statistics *out_statistics)

It seems to me that thist would map nicely to the pipe query calls.  Of course, the setup/fragment statistics would need to be filled independently, and the draw module would need to flush in these calls.

This would also allow to accumulate multiple statistics across multiple draws nicely, and probably less overhead.

Jose


> + */
> +void
> +draw_collect_pipeline_statistics(struct draw_context *draw,
> +                                 boolean enable)
> +{
> +   draw->collect_statistics = enable;
> +}
> diff --git a/src/gallium/auxiliary/draw/draw_context.h
> b/src/gallium/auxiliary/draw/draw_context.h
> index 1d25b7f..94fac88 100644
> --- a/src/gallium/auxiliary/draw/draw_context.h
> +++ b/src/gallium/auxiliary/draw/draw_context.h
> @@ -264,6 +264,13 @@ void draw_set_driver_clipping( struct draw_context
> *draw,
>  void draw_set_force_passthrough( struct draw_context *draw,
>                                   boolean enable );
>  
> +
> +/*******************************************************************************
> + * Draw statistics
> + */
> +void draw_collect_pipeline_statistics(struct draw_context *draw,
> +                                      boolean enable);
> +
>  /*******************************************************************************
>   * Draw pipeline
>   */
> diff --git a/src/gallium/auxiliary/draw/draw_gs.c
> b/src/gallium/auxiliary/draw/draw_gs.c
> index 70db837..ce820ef 100644
> --- a/src/gallium/auxiliary/draw/draw_gs.c
> +++ b/src/gallium/auxiliary/draw/draw_gs.c
> @@ -353,6 +353,10 @@ static void gs_flush(struct draw_geometry_shader
> *shader)
>  
>     unsigned input_primitives = shader->fetched_prim_count;
>  
> +   if (shader->draw->collect_statistics) {
> +      shader->draw->statistics.gs_invocations += input_primitives;
> +   }
> +
>     debug_assert(input_primitives > 0 &&
>                  input_primitives <= 4);
>  
> @@ -493,11 +497,14 @@ int draw_geometry_shader_run(struct
> draw_geometry_shader *shader,
>        input_prim->count;
>     unsigned num_in_primitives =
>        align(
> -         MAX2(u_gs_prims_for_vertices(input_prim->prim, num_input_verts),
> -              u_gs_prims_for_vertices(shader->input_primitive,
> num_input_verts)),
> +         MAX2(u_decomposed_prims_for_vertices(input_prim->prim,
> +                                              num_input_verts),
> +              u_decomposed_prims_for_vertices(shader->input_primitive,
> +                                              num_input_verts)),
>           shader->vector_length);
> -   unsigned max_out_prims =
> u_gs_prims_for_vertices(shader->output_primitive,
> -
> shader->max_output_vertices)
> +   unsigned max_out_prims =
> +      u_decomposed_prims_for_vertices(shader->output_primitive,
> +                                      shader->max_output_vertices)
>        * num_in_primitives;
>  
>     //Assume at least one primitive
> @@ -593,6 +600,15 @@ int draw_geometry_shader_run(struct draw_geometry_shader
> *shader,
>     output_prims->primitive_count = shader->emitted_primitives;
>     output_verts->count = shader->emitted_vertices;
>  
> +   if (shader->draw->collect_statistics) {
> +      unsigned i;
> +      for (i = 0; i < shader->emitted_primitives; ++i) {
> +         shader->draw->statistics.gs_primitives +=
> +            u_decomposed_prims_for_vertices(shader->output_primitive,
> +                                            shader->primitive_lengths[i]);
> +      }
> +   }
> +
>  #if 0
>     debug_printf("GS finished, prims = %d, verts = %d\n",
>                  output_prims->primitive_count,
> diff --git a/src/gallium/auxiliary/draw/draw_private.h
> b/src/gallium/auxiliary/draw/draw_private.h
> index 757ed26..d6a3e7c 100644
> --- a/src/gallium/auxiliary/draw/draw_private.h
> +++ b/src/gallium/auxiliary/draw/draw_private.h
> @@ -312,6 +312,9 @@ struct draw_context
>     const struct pipe_sampler_state
>     *samplers[PIPE_SHADER_TYPES][PIPE_MAX_SAMPLERS];
>     unsigned num_samplers[PIPE_SHADER_TYPES];
>  
> +   struct pipe_query_data_pipeline_statistics statistics;
> +   boolean collect_statistics;
> +
>     void *driver_private;
>  };
>  
> diff --git a/src/gallium/auxiliary/draw/draw_pt.c
> b/src/gallium/auxiliary/draw/draw_pt.c
> index 853bd67..dd333d7 100644
> --- a/src/gallium/auxiliary/draw/draw_pt.c
> +++ b/src/gallium/auxiliary/draw/draw_pt.c
> @@ -545,6 +545,12 @@ draw_vbo(struct draw_context *draw,
>        return;
>     }
>  
> +   /* If we're collecting stats then make sure we start from scratch */
> +   if (draw->collect_statistics) {
> +      memset(&draw->statistics, 0, sizeof(draw->statistics));
> +   }
> +
> +
>     draw->pt.max_index = index_limit - 1;
>  
>     /*
> diff --git a/src/gallium/auxiliary/draw/draw_pt_emit.c
> b/src/gallium/auxiliary/draw/draw_pt_emit.c
> index 942ddc4..0801eff 100644
> --- a/src/gallium/auxiliary/draw/draw_pt_emit.c
> +++ b/src/gallium/auxiliary/draw/draw_pt_emit.c
> @@ -33,6 +33,7 @@
>  #include "draw/draw_pt.h"
>  #include "translate/translate.h"
>  #include "translate/translate_cache.h"
> +#include "util/u_prim.h"
>  
>  struct pt_emit {
>     struct draw_context *draw;
> @@ -179,11 +180,21 @@ draw_pt_emit(struct pt_emit *emit,
>          i < prim_info->primitive_count;
>          start += prim_info->primitive_lengths[i], i++)
>     {
> +      if (draw->collect_statistics) {
> +         draw->statistics.c_invocations +=
> +            u_decomposed_prims_for_vertices(prim_info->prim,
> +
> prim_info->primitive_lengths[i]);
> +      }
> +
>        render->draw_elements(render,
>                              elts + start,
>                              prim_info->primitive_lengths[i]);
>     }
>  
> +   if (draw->collect_statistics) {
> +      render->pipeline_statistics(render, &draw->statistics);
> +   }
> +
>     render->release_vertices(render);
>  }
>  
> @@ -252,11 +263,21 @@ draw_pt_emit_linear(struct pt_emit *emit,
>          i < prim_info->primitive_count;
>          start += prim_info->primitive_lengths[i], i++)
>     {
> +      if (draw->collect_statistics) {
> +         draw->statistics.c_invocations +=
> +            u_decomposed_prims_for_vertices(prim_info->prim,
> +
> prim_info->primitive_lengths[i]);
> +      }
> +
>        render->draw_arrays(render,
>                            start,
>                            prim_info->primitive_lengths[i]);
>     }
>  
> +   if (draw->collect_statistics) {
> +      render->pipeline_statistics(render, &draw->statistics);
> +   }
> +
>     render->release_vertices(render);
>  
>     return;
> 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 72d3912..e17f161 100644
> --- a/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline.c
> +++ b/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline.c
> @@ -240,6 +240,12 @@ static void fetch_pipeline_generic( struct
> draw_pt_middle_end *middle,
>        assert(0);
>        return;
>     }
> +   if (draw->collect_statistics) {
> +      draw->statistics.ia_vertices += fetch_info->count;
> +      draw->statistics.ia_primitives +=
> +         u_decomposed_prims_for_vertices(prim_info->prim,
> fetch_info->count);
> +      draw->statistics.vs_invocations += fetch_info->count;
> +   }
>  
>     /* Fetch into our vertex buffer.
>      */
> 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 ec0f758..d312dc4 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
> @@ -27,6 +27,7 @@
>  
>  #include "util/u_math.h"
>  #include "util/u_memory.h"
> +#include "util/u_prim.h"
>  #include "draw/draw_context.h"
>  #include "draw/draw_gs.h"
>  #include "draw/draw_vbuf.h"
> @@ -333,6 +334,12 @@ llvm_pipeline_generic( struct draw_pt_middle_end
> *middle,
>        assert(0);
>        return;
>     }
> +   if (draw->collect_statistics) {
> +      draw->statistics.ia_vertices += fetch_info->count;
> +      draw->statistics.ia_primitives +=
> +         u_decomposed_prims_for_vertices(prim_info->prim,
> fetch_info->count);
> +      draw->statistics.vs_invocations += fetch_info->count;
> +   }
>  
>     if (fetch_info->linear)
>        clipped = fpme->current_variant->jit_func( &fpme->llvm->jit_context,
> diff --git a/src/gallium/auxiliary/draw/draw_vbuf.h
> b/src/gallium/auxiliary/draw/draw_vbuf.h
> index f10d185..bf1c73c 100644
> --- a/src/gallium/auxiliary/draw/draw_vbuf.h
> +++ b/src/gallium/auxiliary/draw/draw_vbuf.h
> @@ -43,6 +43,7 @@
>  struct pipe_rasterizer_state;
>  struct draw_context;
>  struct vertex_info;
> +struct pipe_query_data_pipeline_statistics;
>  
>  
>  /**
> @@ -126,6 +127,13 @@ struct vbuf_render {
>                                     unsigned primitive_count,
>                                     unsigned vertices_count,
>                                     unsigned primitive_generated );
> +
> +   /**
> +    * Called after all relevant statistics have been accumulated.
> +    */
> +   void (*pipeline_statistics)(
> +      struct vbuf_render *vbufr,
> +      const struct pipe_query_data_pipeline_statistics *stats );
>  };
>  
>  
> diff --git a/src/gallium/auxiliary/util/u_prim.h
> b/src/gallium/auxiliary/util/u_prim.h
> index d62c636..99bb66c 100644
> --- a/src/gallium/auxiliary/util/u_prim.h
> +++ b/src/gallium/auxiliary/util/u_prim.h
> @@ -165,12 +165,14 @@ u_vertices_per_prim(int primitive)
>  /**
>   * Returns the number of decomposed primitives for the given
>   * vertex count.
> - * Geometry shader is invoked once for each triangle in
> + * Parts of the pipline are invoked once for each triangle in
>   * triangle strip, triangle fans and triangles and once
> - * for each line in line strip, line loop, lines.
> + * for each line in line strip, line loop, lines. Also
> + * statistics depend on knowing the exact number of decomposed
> + * primitives for a set of vertices.
>   */
>  static INLINE unsigned
> -u_gs_prims_for_vertices(int primitive, int vertices)
> +u_decomposed_prims_for_vertices(int primitive, int vertices)
>  {
>     switch(primitive) {
>     case PIPE_PRIM_POINTS:
> @@ -180,31 +182,34 @@ u_gs_prims_for_vertices(int primitive, int vertices)
>     case PIPE_PRIM_LINE_LOOP:
>        return vertices;
>     case PIPE_PRIM_LINE_STRIP:
> -      return vertices - 1;
> +      return (vertices > 1) ? vertices - 1 : 0;
>     case PIPE_PRIM_TRIANGLES:
>        return vertices /  3;
>     case PIPE_PRIM_TRIANGLE_STRIP:
> -      return vertices - 2;
> +      return (vertices > 2) ? vertices - 2 : 0;
>     case PIPE_PRIM_TRIANGLE_FAN:
> -      return vertices - 2;
> +      return (vertices > 2) ? vertices - 2 : 0;
>     case PIPE_PRIM_LINES_ADJACENCY:
>        return vertices / 2;
>     case PIPE_PRIM_LINE_STRIP_ADJACENCY:
> -      return vertices - 1;
> +      return (vertices > 1) ? vertices - 1 : 0;
>     case PIPE_PRIM_TRIANGLES_ADJACENCY:
>        return vertices / 3;
>     case PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY:
> -      return vertices - 2;
> -
> -   /* following primitives should never be used
> -    * with geometry shaders abd their size is
> -    * undefined */
> -   case PIPE_PRIM_POLYGON:
> +      return (vertices > 2) ? vertices - 2 : 0;
>     case PIPE_PRIM_QUADS:
> +      return vertices / 4;
>     case PIPE_PRIM_QUAD_STRIP:
> +      return (vertices > 4) ? (vertices - 2) / 2 : 0;
> +   /* Polygons can't be decomposed
> +    * because the number of their vertices isn't known so
> +    * for them and whatever else we don't recognize just
> +    * return 1 if the number of vertices is greater than
> +    * 3 and zero otherwise */
> +   case PIPE_PRIM_POLYGON:
>     default:
> -      debug_printf("Unrecognized geometry shader primitive");
> -      return 3;
> +      debug_printf("Invalid decomposition primitive!\n");
> +      return (vertices > 3) ? 1 : 0;
>     }
>  }
>  
> diff --git a/src/gallium/drivers/llvmpipe/lp_context.h
> b/src/gallium/drivers/llvmpipe/lp_context.h
> index 6ee7b99..d605dba 100644
> --- a/src/gallium/drivers/llvmpipe/lp_context.h
> +++ b/src/gallium/drivers/llvmpipe/lp_context.h
> @@ -94,6 +94,9 @@ struct llvmpipe_context {
>     struct pipe_query_data_so_statistics so_stats;
>     unsigned num_primitives_generated;
>  
> +   struct pipe_query_data_pipeline_statistics pipeline_statistics;
> +   unsigned active_statistics_queries;
> +
>     unsigned dirty; /**< Mask of LP_NEW_x flags */
>  
>     unsigned active_occlusion_query;
> diff --git a/src/gallium/drivers/llvmpipe/lp_draw_arrays.c
> b/src/gallium/drivers/llvmpipe/lp_draw_arrays.c
> index efeca25..8b7903b 100644
> --- a/src/gallium/drivers/llvmpipe/lp_draw_arrays.c
> +++ b/src/gallium/drivers/llvmpipe/lp_draw_arrays.c
> @@ -108,6 +108,12 @@ llvmpipe_draw_vbo(struct pipe_context *pipe, const
> struct pipe_draw_info *info)
>           draw_vs_attach_so(lp->vs->draw_data,
>           &lp->gs->shader.stream_output);
>        }
>     }
> +   if (lp->active_statistics_queries) {
> +      memset(&lp->pipeline_statistics, 0,
> +             sizeof(lp->pipeline_statistics));
> +   }
> +   draw_collect_pipeline_statistics(draw,
> +                                    lp->active_statistics_queries > 0);
>  
>     /* draw! */
>     draw_vbo(draw, info);
> diff --git a/src/gallium/drivers/llvmpipe/lp_query.c
> b/src/gallium/drivers/llvmpipe/lp_query.c
> index 013d192..319a070 100644
> --- a/src/gallium/drivers/llvmpipe/lp_query.c
> +++ b/src/gallium/drivers/llvmpipe/lp_query.c
> @@ -144,6 +144,12 @@ llvmpipe_get_query_result(struct pipe_context *pipe,
>        stats->primitives_storage_needed = pq->num_primitives_generated;
>     }
>        break;
> +   case PIPE_QUERY_PIPELINE_STATISTICS: {
> +      struct pipe_query_data_pipeline_statistics *stats =
> +         (struct pipe_query_data_pipeline_statistics *)vresult;
> +      *stats = pq->stats;
> +   }
> +      break;
>     default:
>        assert(0);
>        break;
> @@ -188,6 +194,11 @@ llvmpipe_begin_query(struct pipe_context *pipe, struct
> pipe_query *q)
>        llvmpipe->num_primitives_generated = 0;
>     }
>  
> +   if (pq->type == PIPE_QUERY_PIPELINE_STATISTICS) {
> +      memset(&pq->stats, 0, sizeof(pq->stats));
> +      llvmpipe->active_statistics_queries++;
> +   }
> +
>     if (pq->type == PIPE_QUERY_OCCLUSION_COUNTER) {
>        llvmpipe->active_occlusion_query = TRUE;
>        llvmpipe->dirty |= LP_NEW_OCCLUSION_QUERY;
> @@ -216,6 +227,11 @@ llvmpipe_end_query(struct pipe_context *pipe, struct
> pipe_query *q)
>        pq->num_primitives_generated = llvmpipe->num_primitives_generated;
>     }
>  
> +   if (pq->type == PIPE_QUERY_PIPELINE_STATISTICS) {
> +      pq->stats = llvmpipe->pipeline_statistics;
> +      llvmpipe->active_statistics_queries--;
> +   }
> +
>     if (pq->type == PIPE_QUERY_OCCLUSION_COUNTER) {
>        assert(llvmpipe->active_occlusion_query);
>        llvmpipe->active_occlusion_query = FALSE;
> diff --git a/src/gallium/drivers/llvmpipe/lp_query.h
> b/src/gallium/drivers/llvmpipe/lp_query.h
> index 19d977f..68dfe99 100644
> --- a/src/gallium/drivers/llvmpipe/lp_query.h
> +++ b/src/gallium/drivers/llvmpipe/lp_query.h
> @@ -47,6 +47,8 @@ struct llvmpipe_query {
>     unsigned type;                   /* PIPE_QUERY_* */
>     unsigned num_primitives_generated;
>     unsigned num_primitives_written;
> +
> +   struct pipe_query_data_pipeline_statistics stats;
>  };
>  
>  
> diff --git a/src/gallium/drivers/llvmpipe/lp_rast.c
> b/src/gallium/drivers/llvmpipe/lp_rast.c
> index 6cb2702..29dd933 100644
> --- a/src/gallium/drivers/llvmpipe/lp_rast.c
> +++ b/src/gallium/drivers/llvmpipe/lp_rast.c
> @@ -477,6 +477,7 @@ lp_rast_begin_query(struct lp_rasterizer_task *task,
>     case PIPE_QUERY_PRIMITIVES_GENERATED:
>     case PIPE_QUERY_PRIMITIVES_EMITTED:
>     case PIPE_QUERY_SO_STATISTICS:
> +   case PIPE_QUERY_PIPELINE_STATISTICS:
>        break;
>     default:
>        assert(0);
> @@ -509,6 +510,7 @@ lp_rast_end_query(struct lp_rasterizer_task *task,
>     case PIPE_QUERY_PRIMITIVES_GENERATED:
>     case PIPE_QUERY_PRIMITIVES_EMITTED:
>     case PIPE_QUERY_SO_STATISTICS:
> +   case PIPE_QUERY_PIPELINE_STATISTICS:
>        break;
>     default:
>        assert(0);
> diff --git a/src/gallium/drivers/llvmpipe/lp_setup_vbuf.c
> b/src/gallium/drivers/llvmpipe/lp_setup_vbuf.c
> index 9e0a5b3..f2a1f21 100644
> --- a/src/gallium/drivers/llvmpipe/lp_setup_vbuf.c
> +++ b/src/gallium/drivers/llvmpipe/lp_setup_vbuf.c
> @@ -547,6 +547,28 @@ lp_setup_so_info(struct vbuf_render *vbr, uint
> primitives, uint vertices,
>     lp->num_primitives_generated += prim_generated;
>  }
>  
> +static void
> +lp_setup_pipeline_statistics(
> +   struct vbuf_render *vbr,
> +   const struct pipe_query_data_pipeline_statistics *stats)
> +{
> +   struct lp_setup_context *setup = lp_setup_context(vbr);
> +   struct llvmpipe_context *llvmpipe = llvmpipe_context(setup->pipe);
> +
> +   llvmpipe->pipeline_statistics.ia_vertices =
> +      stats->ia_vertices;
> +   llvmpipe->pipeline_statistics.ia_primitives =
> +      stats->ia_primitives;
> +   llvmpipe->pipeline_statistics.vs_invocations =
> +      stats->vs_invocations;
> +   llvmpipe->pipeline_statistics.gs_invocations =
> +      stats->gs_invocations;
> +   llvmpipe->pipeline_statistics.gs_primitives =
> +      stats->gs_primitives;
> +   llvmpipe->pipeline_statistics.c_invocations =
> +      stats->c_invocations;
> +}
> +
>  /**
>   * Create the post-transform vertex handler for the given context.
>   */
> @@ -566,4 +588,5 @@ lp_setup_init_vbuf(struct lp_setup_context *setup)
>     setup->base.release_vertices = lp_setup_release_vertices;
>     setup->base.destroy = lp_setup_vbuf_destroy;
>     setup->base.set_stream_output_info = lp_setup_so_info;
> +   setup->base.pipeline_statistics = lp_setup_pipeline_statistics;
>  }
> diff --git a/src/gallium/drivers/softpipe/sp_context.h
> b/src/gallium/drivers/softpipe/sp_context.h
> index d78352a..431864a 100644
> --- a/src/gallium/drivers/softpipe/sp_context.h
> +++ b/src/gallium/drivers/softpipe/sp_context.h
> @@ -92,6 +92,9 @@ struct softpipe_context {
>     struct pipe_query_data_so_statistics so_stats;
>     unsigned num_primitives_generated;
>  
> +   struct pipe_query_data_pipeline_statistics pipeline_statistics;
> +   unsigned active_statistics_queries;
> +
>     unsigned num_samplers[PIPE_SHADER_TYPES];
>     unsigned num_sampler_views[PIPE_SHADER_TYPES];
>  
> diff --git a/src/gallium/drivers/softpipe/sp_draw_arrays.c
> b/src/gallium/drivers/softpipe/sp_draw_arrays.c
> index ba9e781..570644e 100644
> --- a/src/gallium/drivers/softpipe/sp_draw_arrays.c
> +++ b/src/gallium/drivers/softpipe/sp_draw_arrays.c
> @@ -105,6 +105,13 @@ softpipe_draw_vbo(struct pipe_context *pipe,
>     draw_set_mapped_so_targets(draw, sp->num_so_targets,
>                                sp->so_targets);
>  
> +   if (sp->active_statistics_queries) {
> +      memset(&sp->pipeline_statistics, 0,
> +             sizeof(sp->pipeline_statistics));
> +   }
> +   draw_collect_pipeline_statistics(draw,
> +                                    sp->active_statistics_queries > 0);
> +
>     /* draw! */
>     draw_vbo(draw, info);
>  
> diff --git a/src/gallium/drivers/softpipe/sp_prim_vbuf.c
> b/src/gallium/drivers/softpipe/sp_prim_vbuf.c
> index bb5ebcc..b4962ba 100644
> --- a/src/gallium/drivers/softpipe/sp_prim_vbuf.c
> +++ b/src/gallium/drivers/softpipe/sp_prim_vbuf.c
> @@ -600,6 +600,28 @@ sp_vbuf_so_info(struct vbuf_render *vbr, uint
> primitives, uint vertices,
>     softpipe->num_primitives_generated += prim_generated;
>  }
>  
> +static void
> +sp_vbuf_pipeline_statistics(
> +   struct vbuf_render *vbr,
> +   const struct pipe_query_data_pipeline_statistics *stats)
> +{
> +   struct softpipe_vbuf_render *cvbr = softpipe_vbuf_render(vbr);
> +   struct softpipe_context *softpipe = cvbr->softpipe;
> +
> +   softpipe->pipeline_statistics.ia_vertices =
> +      stats->ia_vertices;
> +   softpipe->pipeline_statistics.ia_primitives =
> +      stats->ia_primitives;
> +   softpipe->pipeline_statistics.vs_invocations =
> +      stats->vs_invocations;
> +   softpipe->pipeline_statistics.gs_invocations =
> +      stats->gs_invocations;
> +   softpipe->pipeline_statistics.gs_primitives =
> +      stats->gs_primitives;
> +   softpipe->pipeline_statistics.c_invocations =
> +      stats->c_invocations;
> +}
> +
>  
>  static void
>  sp_vbuf_destroy(struct vbuf_render *vbr)
> @@ -634,6 +656,7 @@ sp_create_vbuf_backend(struct softpipe_context *sp)
>     cvbr->base.draw_arrays = sp_vbuf_draw_arrays;
>     cvbr->base.release_vertices = sp_vbuf_release_vertices;
>     cvbr->base.set_stream_output_info = sp_vbuf_so_info;
> +   cvbr->base.pipeline_statistics = sp_vbuf_pipeline_statistics;
>     cvbr->base.destroy = sp_vbuf_destroy;
>  
>     cvbr->softpipe = sp;
> diff --git a/src/gallium/drivers/softpipe/sp_quad_fs.c
> b/src/gallium/drivers/softpipe/sp_quad_fs.c
> index f32fe5f..d379f64 100644
> --- a/src/gallium/drivers/softpipe/sp_quad_fs.c
> +++ b/src/gallium/drivers/softpipe/sp_quad_fs.c
> @@ -73,6 +73,11 @@ shade_quad(struct quad_stage *qs, struct quad_header
> *quad)
>     struct softpipe_context *softpipe = qs->softpipe;
>     struct tgsi_exec_machine *machine = softpipe->fs_machine;
>  
> +   if (softpipe->active_statistics_queries) {
> +      softpipe->pipeline_statistics.ps_invocations +=
> +         util_bitcount(quad->inout.mask);
> +   }
> +
>     /* run shader */
>     machine->flatshade_color = softpipe->rasterizer->flatshade ? TRUE :
>     FALSE;
>     return softpipe->fs_variant->run( softpipe->fs_variant, machine, quad );
> diff --git a/src/gallium/drivers/softpipe/sp_query.c
> b/src/gallium/drivers/softpipe/sp_query.c
> index 2dd82c8..34a8d5e 100644
> --- a/src/gallium/drivers/softpipe/sp_query.c
> +++ b/src/gallium/drivers/softpipe/sp_query.c
> @@ -43,6 +43,8 @@ struct softpipe_query {
>     uint64_t end;
>     struct pipe_query_data_so_statistics so;
>     unsigned num_primitives_generated;
> +
> +   struct pipe_query_data_pipeline_statistics stats;
>  };
>  
>  
> @@ -61,7 +63,8 @@ softpipe_create_query(struct pipe_context *pipe,
>            type == PIPE_QUERY_TIME_ELAPSED ||
>            type == PIPE_QUERY_SO_STATISTICS ||
>            type == PIPE_QUERY_PRIMITIVES_EMITTED ||
> -          type == PIPE_QUERY_PRIMITIVES_GENERATED ||
> +          type == PIPE_QUERY_PRIMITIVES_GENERATED ||
> +          type == PIPE_QUERY_PIPELINE_STATISTICS ||
>            type == PIPE_QUERY_GPU_FINISHED ||
>            type == PIPE_QUERY_TIMESTAMP ||
>            type == PIPE_QUERY_TIMESTAMP_DISJOINT);
> @@ -106,6 +109,10 @@ softpipe_begin_query(struct pipe_context *pipe, struct
> pipe_query *q)
>     case PIPE_QUERY_TIMESTAMP:
>     case PIPE_QUERY_GPU_FINISHED:
>        break;
> +   case PIPE_QUERY_PIPELINE_STATISTICS:
> +      memset(&sq->stats, 0, sizeof(sq->stats));
> +      softpipe->active_statistics_queries++;
> +      break;
>     default:
>        assert(0);
>        break;
> @@ -145,6 +152,11 @@ softpipe_end_query(struct pipe_context *pipe, struct
> pipe_query *q)
>        break;
>     case PIPE_QUERY_GPU_FINISHED:
>        break;
> +   case PIPE_QUERY_PIPELINE_STATISTICS:
> +      memcpy(&sq->stats, &softpipe->pipeline_statistics,
> +             sizeof(struct pipe_query_data_pipeline_statistics));;
> +      softpipe->active_statistics_queries--;
> +      break;
>     default:
>        assert(0);
>        break;
> @@ -167,6 +179,10 @@ softpipe_get_query_result(struct pipe_context *pipe,
>        memcpy(vresult, &sq->so,
>               sizeof(struct pipe_query_data_so_statistics));
>        break;
> +   case PIPE_QUERY_PIPELINE_STATISTICS:
> +      memcpy(vresult, &sq->stats,
> +             sizeof(struct pipe_query_data_pipeline_statistics));;
> +      break;
>     case PIPE_QUERY_GPU_FINISHED:
>        *result = TRUE;
>        break;
> diff --git a/src/gallium/drivers/softpipe/sp_screen.c
> b/src/gallium/drivers/softpipe/sp_screen.c
> index 6915f91..b2b7f2e 100644
> --- a/src/gallium/drivers/softpipe/sp_screen.c
> +++ b/src/gallium/drivers/softpipe/sp_screen.c
> @@ -87,7 +87,7 @@ softpipe_get_param(struct pipe_screen *screen, enum
> pipe_cap param)
>     case PIPE_CAP_QUERY_TIME_ELAPSED:
>        return 1;
>     case PIPE_CAP_QUERY_PIPELINE_STATISTICS:
> -      return 0;
> +      return 1;
>     case PIPE_CAP_TEXTURE_MIRROR_CLAMP:
>        return 1;
>     case PIPE_CAP_TEXTURE_SHADOW_MAP:
> diff --git a/src/gallium/drivers/softpipe/sp_setup.c
> b/src/gallium/drivers/softpipe/sp_setup.c
> index 3dad131..08cd4da 100644
> --- a/src/gallium/drivers/softpipe/sp_setup.c
> +++ b/src/gallium/drivers/softpipe/sp_setup.c
> @@ -857,6 +857,10 @@ sp_setup_tri(struct setup_context *setup,
>  
>     flush_spans( setup );
>  
> +   if (setup->softpipe->active_statistics_queries) {
> +      setup->softpipe->pipeline_statistics.c_primitives++;
> +   }
> +
>  #if DEBUG_FRAGS
>     printf("Tri: %u frags emitted, %u written\n",
>            setup->numFragsEmitted,
> --
> 1.7.10.4
> 
> 


More information about the mesa-dev mailing list