[Mesa-dev] [PATCH] draw/softpipe: EXT_transform_feedback support (v1)

Brian Paul brianp at vmware.com
Thu Jan 5 08:28:49 PST 2012


This looks pretty good to me, though I haven't been following the xfb 
work too closely.  Just minor comments below.

-Brian

On 01/05/2012 07:17 AM, Dave Airlie wrote:
> From: Dave Airlie<airlied at redhat.com>
>
> This replaces the current code with an implementation compatible with
> the new gallium interface. I've left some of the remains of the interface
> intact so llvmpipe keeps building correctly, and I'll take a look at fixing
> llvmpipe up later.
>
> This passes 119/134 of the piglit EXT_transform_feedback tests, the alignment tests fail due to an unrelated integer vertex fetching bug, need to look into the others later.
>
> Signed-off-by: Dave Airlie<airlied at redhat.com>
> ---
>   src/gallium/auxiliary/draw/draw_context.c     |   21 +++--
>   src/gallium/auxiliary/draw/draw_context.h     |   12 +++-
>   src/gallium/auxiliary/draw/draw_private.h     |    4 +-
>   src/gallium/auxiliary/draw/draw_pt_so_emit.c  |  112 ++++++++++++++----------
>   src/gallium/auxiliary/draw/draw_vbuf.h        |    3 +-
>   src/gallium/auxiliary/draw/draw_vs_exec.c     |    1 +
>   src/gallium/drivers/softpipe/sp_context.c     |    1 -
>   src/gallium/drivers/softpipe/sp_context.h     |   12 +--
>   src/gallium/drivers/softpipe/sp_draw_arrays.c |   62 ++-----------
>   src/gallium/drivers/softpipe/sp_prim_vbuf.c   |   11 +--
>   src/gallium/drivers/softpipe/sp_query.c       |   25 +++++-
>   src/gallium/drivers/softpipe/sp_screen.c      |    5 +-
>   src/gallium/drivers/softpipe/sp_setup.c       |    6 +-
>   src/gallium/drivers/softpipe/sp_state.h       |    3 -
>   src/gallium/drivers/softpipe/sp_state_so.c    |  118 +++++++-----------------
>   15 files changed, 179 insertions(+), 217 deletions(-)
>
> diff --git a/src/gallium/auxiliary/draw/draw_context.c b/src/gallium/auxiliary/draw/draw_context.c
> index 9c00687..b4acbe1 100644
> --- a/src/gallium/auxiliary/draw/draw_context.c
> +++ b/src/gallium/auxiliary/draw/draw_context.c
> @@ -708,16 +708,25 @@ draw_get_rasterizer_no_cull( struct draw_context *draw,
>   }
>
>   void
> +draw_set_mapped_so_targets(struct draw_context *draw,
> +                           int num_targets,
> +                           struct draw_so_target *targets[PIPE_MAX_SO_BUFFERS])
> +{
> +   int i;
> +
> +   for (i = 0; i<  num_targets; i++)
> +      draw->so.targets[i] = targets[i];
> +   for (i = num_targets; i<  PIPE_MAX_SO_BUFFERS; i++)
> +      draw->so.targets[i] = NULL;
> +
> +   draw->so.num_targets = num_targets;
> +}
> +
> +void
>   draw_set_mapped_so_buffers(struct draw_context *draw,
>                              void *buffers[PIPE_MAX_SO_BUFFERS],
>                              unsigned num_buffers)
>   {
> -   int i;
> -
> -   for (i = 0; i<  num_buffers; ++i) {
> -      draw->so.buffers[i] = buffers[i];
> -   }
> -   draw->so.num_buffers = num_buffers;
>   }
>
>   void
> diff --git a/src/gallium/auxiliary/draw/draw_context.h b/src/gallium/auxiliary/draw/draw_context.h
> index 93577d0..6b20130 100644
> --- a/src/gallium/auxiliary/draw/draw_context.h
> +++ b/src/gallium/auxiliary/draw/draw_context.h
> @@ -50,7 +50,11 @@ struct draw_fragment_shader;
>   struct tgsi_sampler;
>   struct gallivm_state;
>
> -
> +struct draw_so_target {
> +   struct pipe_stream_output_target b;

'b' is kind of a strange name, would 'target' be better?

> +   void *mapping;
> +   int internal_offset;

Is internal_offset in bytes?  Maybe add a comment about that.

> +};
>
>   struct draw_context *draw_create( struct pipe_context *pipe );
>
> @@ -200,6 +204,12 @@ void
>   draw_set_mapped_so_buffers(struct draw_context *draw,
>                              void *buffers[PIPE_MAX_SO_BUFFERS],
>                              unsigned num_buffers);
> +
> +void
> +draw_set_mapped_so_targets(struct draw_context *draw,
> +                           int num_targets,
> +                           struct draw_so_target *targets[PIPE_MAX_SO_BUFFERS]);
> +
>   void
>   draw_set_so_state(struct draw_context *draw,
>                     struct pipe_stream_output_info *state);
> diff --git a/src/gallium/auxiliary/draw/draw_private.h b/src/gallium/auxiliary/draw/draw_private.h
> index 89653e1..b5de5d2 100644
> --- a/src/gallium/auxiliary/draw/draw_private.h
> +++ b/src/gallium/auxiliary/draw/draw_private.h
> @@ -271,8 +271,8 @@ struct draw_context
>      /** Stream output (vertex feedback) state */
>      struct {
>         struct pipe_stream_output_info state;
> -      void *buffers[PIPE_MAX_SO_BUFFERS];
> -      uint num_buffers;
> +      struct draw_so_target *targets[PIPE_MAX_SO_BUFFERS];
> +      uint num_targets;
>      } so;
>
>      /* Clip derived state:
> diff --git a/src/gallium/auxiliary/draw/draw_pt_so_emit.c b/src/gallium/auxiliary/draw/draw_pt_so_emit.c
> index 2dc9e29..241a4a6 100644
> --- a/src/gallium/auxiliary/draw/draw_pt_so_emit.c
> +++ b/src/gallium/auxiliary/draw/draw_pt_so_emit.c
> @@ -25,29 +25,29 @@
>    *
>    **************************************************************************/
>
> -#include "draw/draw_context.h"
>   #include "draw/draw_private.h"
> +#include "draw/draw_vs.h"
> +#include "draw/draw_context.h"
>   #include "draw/draw_vbuf.h"
>   #include "draw/draw_vertex.h"
>   #include "draw/draw_pt.h"
>
> +#include "pipe/p_state.h"
> +
>   #include "util/u_math.h"
>   #include "util/u_memory.h"
>

A comment on this struct explaining what it's for would be good.

>   struct pt_so_emit {
>      struct draw_context *draw;
>
> -   void *buffers[PIPE_MAX_SO_BUFFERS];
> -
>      unsigned input_vertex_stride;
>      const float (*inputs)[4];
>
>      boolean has_so;
>
> -   boolean single_buffer;
> -
>      unsigned emitted_primitives;
>      unsigned emitted_vertices;
> +   unsigned generated_primitives;
>   };
>
>
> @@ -55,15 +55,15 @@ void draw_pt_so_emit_prepare(struct pt_so_emit *emit)
>   {
>      struct draw_context *draw = emit->draw;
>
> -   emit->has_so = (draw->so.state.num_outputs>  0);
> +   emit->has_so = (draw->vs.vertex_shader->state.stream_output.num_outputs>  0);
>
>      /* if we have a state with outputs make sure we have
>       * buffers to output to */

The closing */ should go on the next line.


>      if (emit->has_so) {
>         boolean has_valid_buffer = FALSE;
>         unsigned i;
> -      for (i = 0; i<  draw->so.num_buffers; ++i) {
> -         if (draw->so.buffers[i]) {
> +      for (i = 0; i<  draw->so.num_targets; ++i) {
> +         if (draw->so.targets[i]) {
>               has_valid_buffer = TRUE;
>               break;
>            }
> @@ -122,6 +122,29 @@ is_component_writable(unsigned mask,
>      }
>   }
>
> +static inline int mask_num_comps(int register_mask)

Gallium is still using INLINE.


> +{
> +   int comps = 0;
> +   switch (register_mask) {
> +   case TGSI_WRITEMASK_XYZW:
> +      comps = 4;
> +      break;
> +   case TGSI_WRITEMASK_XYZ:
> +      comps = 3;
> +      break;
> +   case TGSI_WRITEMASK_XY:
> +      comps = 2;
> +      break;
> +   case TGSI_WRITEMASK_X:
> +      comps = 1;
> +      break;
> +   default:
> +      assert(0);
> +      break;
> +   }
> +   return comps;
> +}
> +
>   static void so_emit_prim(struct pt_so_emit *so,
>                            unsigned *indices,
>                            unsigned num_vertices)
> @@ -131,57 +154,56 @@ static void so_emit_prim(struct pt_so_emit *so,
>      struct draw_context *draw = so->draw;
>      const float (*input_ptr)[4];
>      const struct pipe_stream_output_info *state =
> -&draw->so.state;
> -   float **buffer = 0;
> +&draw->vs.vertex_shader->state.stream_output;
> +   float *buffer;
> +   int buffer_total_bytes[PIPE_MAX_SO_BUFFERS];
>
>      input_ptr = so->inputs;
>
> +   ++so->generated_primitives;
> +
> +   for (i = 0; i<  draw->so.num_targets; i++) {
> +      struct draw_so_target *target = draw->so.targets[i];
> +      buffer_total_bytes[i] = target->internal_offset;
> +   }
> +
> +   /* check have we space to emit prim first - if not don't do anything */
> +   for (i = 0; i<  num_vertices; ++i) {
> +      for (slot = 0; slot<  state->num_outputs; ++slot) {
> +         unsigned writemask = state->output[slot].register_mask;
> +         int ob = state->output[slot].output_buffer;
> +
> +         if ((buffer_total_bytes[ob] + mask_num_comps(writemask) * sizeof(float))>
> +             draw->so.targets[ob]->b.buffer_size) {
> +            return;
> +         }
> +         buffer_total_bytes[ob] += mask_num_comps(writemask) * sizeof(float);
> +      }
> +   }
> +
>      for (i = 0; i<  num_vertices; ++i) {
>         const float (*input)[4];
>         unsigned total_written_compos = 0;
>         /*debug_printf("%d) vertex index = %d (prim idx = %d)\n", i, indices[i], prim_idx);*/
>         input = (const float (*)[4])(
>            (const char *)input_ptr + (indices[i] * input_vertex_stride));
> +
>         for (slot = 0; slot<  state->num_outputs; ++slot) {
>            unsigned idx = state->output[slot].register_index;
>            unsigned writemask = state->output[slot].register_mask;
>            unsigned written_compos = 0;
>            unsigned compo;
> +         int ob = state->output[slot].output_buffer;
>
> -         buffer = (float**)&so->buffers[state->output[slot].output_buffer];
> -
> -         /*debug_printf("\tSlot = %d, vs_slot = %d, idx = %d:\n",
> -           slot, vs_slot, idx);*/
> -#if 1
> -         assert(!util_is_inf_or_nan(input[idx][0]));
> -         assert(!util_is_inf_or_nan(input[idx][1]));
> -         assert(!util_is_inf_or_nan(input[idx][2]));
> -         assert(!util_is_inf_or_nan(input[idx][3]));
> -#endif
> +         buffer = (float *)((char *)draw->so.targets[ob]->mapping + draw->so.targets[ob]->b.buffer_offset + draw->so.targets[ob]->internal_offset);
>            for (compo = 0; compo<  4; ++compo) {
>               if (is_component_writable(writemask, compo)) {
> -               float *buf = *buffer;
> -               buf[written_compos++] = input[idx][compo];
> +               buffer[written_compos++] = input[idx][compo];
>               }
>            }
> -#if 0
> -         debug_printf("\t\t(writemask = %d)%f %f %f %f\n",
> -                      writemask,
> -                      input[idx][0],
> -                      input[idx][1],
> -                      input[idx][2],
> -                      input[idx][3]);
> -#endif
> -         *buffer += written_compos;
> +         draw->so.targets[ob]->internal_offset += written_compos * sizeof(float);
>            total_written_compos += written_compos;
>         }
> -      if (so->single_buffer) {
> -         int stride = (int)state->stride -
> -                      sizeof(float) * total_written_compos;
> -
> -         debug_assert(stride>= 0);
> -         *buffer = (float*) (((char*)*buffer) + stride);
> -      }
>      }
>      so->emitted_vertices += num_vertices;
>      ++so->emitted_primitives;
> @@ -235,23 +257,18 @@ void draw_pt_so_emit( struct pt_so_emit *emit,
>   {
>      struct draw_context *draw = emit->draw;
>      struct vbuf_render *render = draw->render;
> +   struct pipe_stream_output_info *so;
>      unsigned start, i;
>
>      if (!emit->has_so)
>         return;
>
> +   so =&draw->vs.vertex_shader->state.stream_output;
>      emit->emitted_vertices = 0;
>      emit->emitted_primitives = 0;
> +   emit->generated_primitives = 0;
>      emit->input_vertex_stride = input_verts->stride;
>      emit->inputs = (const float (*)[4])input_verts->verts->data;
> -   for (i = 0; i<  draw->so.num_buffers; ++i) {
> -      emit->buffers[i] = draw->so.buffers[i];
> -   }
> -   emit->single_buffer = TRUE;
> -   for (i = 0; i<  draw->so.state.num_outputs; ++i) {
> -      if (draw->so.state.output[i].output_buffer != 0)
> -         emit->single_buffer = FALSE;
> -   }
>
>      /* XXX: need to flush to get prim_vbuf.c to release its allocation??*/
>      draw_do_flush( draw, DRAW_FLUSH_BACKEND );
> @@ -272,7 +289,8 @@ void draw_pt_so_emit( struct pt_so_emit *emit,
>
>      render->set_stream_output_info(render,
>                                     emit->emitted_primitives,
> -                                  emit->emitted_vertices);
> +                                  emit->emitted_vertices,
> +                                  emit->generated_primitives);
>   }
>
>
> diff --git a/src/gallium/auxiliary/draw/draw_vbuf.h b/src/gallium/auxiliary/draw/draw_vbuf.h
> index e32803c..6496fe3 100644
> --- a/src/gallium/auxiliary/draw/draw_vbuf.h
> +++ b/src/gallium/auxiliary/draw/draw_vbuf.h
> @@ -124,7 +124,8 @@ struct vbuf_render {
>       */
>      void (*set_stream_output_info)( struct vbuf_render *vbufr,
>                                      unsigned primitive_count,
> -                                   unsigned vertices_count );
> +                                   unsigned vertices_count,
> +                                   unsigned primitive_generated );
>   };
>
>
> diff --git a/src/gallium/auxiliary/draw/draw_vs_exec.c b/src/gallium/auxiliary/draw/draw_vs_exec.c
> index d9c4209..3f89881 100644
> --- a/src/gallium/auxiliary/draw/draw_vs_exec.c
> +++ b/src/gallium/auxiliary/draw/draw_vs_exec.c
> @@ -217,6 +217,7 @@ draw_create_vs_exec(struct draw_context *draw,
>
>      tgsi_scan_shader(state->tokens,&vs->base.info);
>
> +   vs->base.state.stream_output = state->stream_output;
>      vs->base.draw = draw;
>      vs->base.prepare = vs_exec_prepare;
>      vs->base.run_linear = vs_exec_run_linear;
> diff --git a/src/gallium/drivers/softpipe/sp_context.c b/src/gallium/drivers/softpipe/sp_context.c
> index a720600..1299384 100644
> --- a/src/gallium/drivers/softpipe/sp_context.c
> +++ b/src/gallium/drivers/softpipe/sp_context.c
> @@ -257,7 +257,6 @@ softpipe_create_context( struct pipe_screen *screen,
>      softpipe->pipe.set_framebuffer_state = softpipe_set_framebuffer_state;
>
>      softpipe->pipe.draw_vbo = softpipe_draw_vbo;
> -   /* XXX softpipe->pipe.draw_stream_output = softpipe_draw_stream_output; */
>
>      softpipe->pipe.clear = softpipe_clear;
>      softpipe->pipe.flush = softpipe_flush_wrapped;
> diff --git a/src/gallium/drivers/softpipe/sp_context.h b/src/gallium/drivers/softpipe/sp_context.h
> index 5442aba..c657bd6 100644
> --- a/src/gallium/drivers/softpipe/sp_context.h
> +++ b/src/gallium/drivers/softpipe/sp_context.h
> @@ -55,7 +55,6 @@ struct sp_vertex_shader;
>   struct sp_velems_state;
>   struct sp_so_state;
>
> -
>   struct softpipe_context {
>      struct pipe_context pipe;  /**<  base class */
>
> @@ -88,13 +87,12 @@ struct softpipe_context {
>      struct pipe_viewport_state viewport;
>      struct pipe_vertex_buffer vertex_buffer[PIPE_MAX_ATTRIBS];
>      struct pipe_index_buffer index_buffer;
> -   struct {
> -      struct softpipe_resource *buffer[PIPE_MAX_SO_BUFFERS];
> -      int offset[PIPE_MAX_SO_BUFFERS];
> -      int so_count[PIPE_MAX_SO_BUFFERS];
> -      int num_buffers;
> -   } so_target;
> +
> +   struct draw_so_target *so_targets[PIPE_MAX_SO_BUFFERS];
> +   int num_so_targets;
> +
>      struct pipe_query_data_so_statistics so_stats;
> +   unsigned num_primitives_generated;
>
>      unsigned num_fragment_samplers;
>      unsigned num_fragment_sampler_views;
> diff --git a/src/gallium/drivers/softpipe/sp_draw_arrays.c b/src/gallium/drivers/softpipe/sp_draw_arrays.c
> index 69b5b96..10b625c 100644
> --- a/src/gallium/drivers/softpipe/sp_draw_arrays.c
> +++ b/src/gallium/drivers/softpipe/sp_draw_arrays.c
> @@ -43,58 +43,6 @@
>
>   #include "draw/draw_context.h"
>
> -
> -
> -
> -
> -void
> -softpipe_draw_stream_output(struct pipe_context *pipe, unsigned mode)
> -{
> -   struct softpipe_context *sp = softpipe_context(pipe);
> -   struct draw_context *draw = sp->draw;
> -   const unsigned start = 0;
> -   const unsigned count = sp->so_target.so_count[0];
> -   void *buf = sp->so_target.buffer[0]->data;
> -   int offset = sp->so_target.offset[0];
> -
> -   if (!softpipe_check_render_cond(sp) ||
> -       sp->so_target.num_buffers != 1)
> -      return;
> -
> -   sp->reduced_api_prim = u_reduced_prim(mode);
> -
> -   if (sp->dirty) {
> -      softpipe_update_derived(sp, sp->reduced_api_prim);
> -   }
> -
> -   softpipe_map_transfers(sp);
> -
> -   /* Map so buffers */
> -   if (offset<  0) /* we were appending so start from beginning */
> -      offset = 0;
> -   buf = (void*)((int32_t*)buf + offset);
> -   draw_set_mapped_vertex_buffer(draw, 0, buf);
> -
> -   draw_set_mapped_index_buffer(draw, NULL);
> -
> -   /* draw! */
> -   draw_arrays(draw, mode, start, count);
> -
> -   /* unmap vertex/index buffers - will cause draw module to flush */
> -   draw_set_mapped_vertex_buffer(draw, 0, NULL);
> -
> -   /*
> -    * TODO: Flush only when a user vertex/index buffer is present
> -    * (or even better, modify draw module to do this
> -    * internally when this condition is seen?)
> -    */
> -   draw_flush(draw);
> -
> -   /* Note: leave drawing surfaces mapped */
> -   sp->dirty_render_cache = TRUE;
> -}
> -
> -
>   /**
>    * This function handles drawing indexed and non-indexed prims,
>    * instanced and non-instanced drawing, with or without min/max element
> @@ -139,6 +87,14 @@ softpipe_draw_vbo(struct pipe_context *pipe,
>
>      draw_set_mapped_index_buffer(draw, mapped_indices);
>
> +   for (i = 0; i<  sp->num_so_targets; i++) {
> +      void *buf = softpipe_resource(sp->so_targets[i]->b.buffer)->data;
> +      sp->so_targets[i]->mapping = buf;
> +   }
> +
> +   draw_set_mapped_so_targets(draw, sp->num_so_targets,
> +                              sp->so_targets);
> +
>      /* draw! */
>      draw_vbo(draw, info);
>
> @@ -150,6 +106,8 @@ softpipe_draw_vbo(struct pipe_context *pipe,
>         draw_set_mapped_index_buffer(draw, NULL);
>      }
>
> +   draw_set_mapped_so_targets(draw, 0, NULL);
> +
>      /*
>       * TODO: Flush only when a user vertex/index buffer is present
>       * (or even better, modify draw module to do this
> diff --git a/src/gallium/drivers/softpipe/sp_prim_vbuf.c b/src/gallium/drivers/softpipe/sp_prim_vbuf.c
> index c60249d..acc7e45 100644
> --- a/src/gallium/drivers/softpipe/sp_prim_vbuf.c
> +++ b/src/gallium/drivers/softpipe/sp_prim_vbuf.c
> @@ -543,19 +543,16 @@ sp_vbuf_draw_arrays(struct vbuf_render *vbr, uint start, uint nr)
>   }
>
>   static void
> -sp_vbuf_so_info(struct vbuf_render *vbr, uint primitives, uint vertices)
> +sp_vbuf_so_info(struct vbuf_render *vbr, uint primitives, uint vertices,
> +                uint prim_generated)
>   {
>      struct softpipe_vbuf_render *cvbr = softpipe_vbuf_render(vbr);
>      struct softpipe_context *softpipe = cvbr->softpipe;
> -   unsigned i;
> -
> -   for (i = 0; i<  softpipe->so_target.num_buffers; ++i) {
> -      softpipe->so_target.so_count[i] += vertices;
> -   }
>
> -   softpipe->so_stats.num_primitives_written = primitives;
> +   softpipe->so_stats.num_primitives_written += primitives;
>      softpipe->so_stats.primitives_storage_needed =
>         vertices * 4 /*sizeof(float|int32)*/ * 4 /*x,y,z,w*/;
> +   softpipe->num_primitives_generated += prim_generated;
>   }
>
>
> diff --git a/src/gallium/drivers/softpipe/sp_query.c b/src/gallium/drivers/softpipe/sp_query.c
> index c2c48e8..2e54e02 100644
> --- a/src/gallium/drivers/softpipe/sp_query.c
> +++ b/src/gallium/drivers/softpipe/sp_query.c
> @@ -42,6 +42,7 @@ struct softpipe_query {
>      uint64_t start;
>      uint64_t end;
>      struct pipe_query_data_so_statistics so;
> +   unsigned num_primitives_generated;
>   };
>
>
> @@ -59,6 +60,8 @@ softpipe_create_query(struct pipe_context *pipe,
>      assert(type == PIPE_QUERY_OCCLUSION_COUNTER ||
>             type == PIPE_QUERY_TIME_ELAPSED ||
>             type == PIPE_QUERY_SO_STATISTICS ||
> +          type == PIPE_QUERY_PRIMITIVES_EMITTED ||
> +          type == PIPE_QUERY_PRIMITIVES_GENERATED ||
>             type == PIPE_QUERY_GPU_FINISHED ||
>             type == PIPE_QUERY_TIMESTAMP ||
>             type == PIPE_QUERY_TIMESTAMP_DISJOINT);
> @@ -91,8 +94,14 @@ softpipe_begin_query(struct pipe_context *pipe, struct pipe_query *q)
>         sq->start = 1000*os_time_get();
>         break;
>      case PIPE_QUERY_SO_STATISTICS:
> -      sq->so.num_primitives_written = 0;
>         sq->so.primitives_storage_needed = 0;
> +   case PIPE_QUERY_PRIMITIVES_EMITTED:
> +      sq->so.num_primitives_written = 0;
> +      softpipe->so_stats.num_primitives_written = 0;
> +      break;
> +   case PIPE_QUERY_PRIMITIVES_GENERATED:
> +      sq->num_primitives_generated = 0;
> +      softpipe->num_primitives_generated = 0;
>         break;
>      case PIPE_QUERY_TIMESTAMP:
>      case PIPE_QUERY_GPU_FINISHED:
> @@ -125,10 +134,14 @@ softpipe_end_query(struct pipe_context *pipe, struct pipe_query *q)
>         sq->end = 1000*os_time_get();
>         break;
>      case PIPE_QUERY_SO_STATISTICS:
> -      sq->so.num_primitives_written =
> -         softpipe->so_stats.num_primitives_written;
>         sq->so.primitives_storage_needed =
>            softpipe->so_stats.primitives_storage_needed;
> +   case PIPE_QUERY_PRIMITIVES_EMITTED:
> +      sq->so.num_primitives_written =
> +         softpipe->so_stats.num_primitives_written;
> +      break;
> +   case PIPE_QUERY_PRIMITIVES_GENERATED:
> +      sq->num_primitives_generated = softpipe->num_primitives_generated;
>         break;
>      case PIPE_QUERY_GPU_FINISHED:
>         break;
> @@ -166,6 +179,12 @@ softpipe_get_query_result(struct pipe_context *pipe,
>                sizeof(struct pipe_query_data_timestamp_disjoint));
>      }
>         break;
> +   case PIPE_QUERY_PRIMITIVES_EMITTED:
> +      *result = sq->so.num_primitives_written;
> +      break;
> +   case PIPE_QUERY_PRIMITIVES_GENERATED:
> +      *result = sq->num_primitives_generated;
> +      break;
>      default:
>         *result = sq->end - sq->start;
>         break;
> diff --git a/src/gallium/drivers/softpipe/sp_screen.c b/src/gallium/drivers/softpipe/sp_screen.c
> index e58a486..8e88bb5 100644
> --- a/src/gallium/drivers/softpipe/sp_screen.c
> +++ b/src/gallium/drivers/softpipe/sp_screen.c
> @@ -106,7 +106,10 @@ softpipe_get_param(struct pipe_screen *screen, enum pipe_cap param)
>      case PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_INTEGER:
>         return 1;
>      case PIPE_CAP_MAX_STREAM_OUTPUT_BUFFERS:
> -      return 0;
> +      return 4;

s/4/PIPE_MAX_SO_BUFFERS/?

BTW, is PIPE_MAX_SO_BUFFERS enough?  I know that's the min required 
for GL_EXT_transform_feedback, but I wonder what other GLs advertise 
and what hardware typically supports.



> +   case PIPE_CAP_MAX_STREAM_OUTPUT_SEPARATE_COMPONENTS:
> +   case PIPE_CAP_MAX_STREAM_OUTPUT_INTERLEAVED_COMPONENTS:
> +      return 16*4;
>      case PIPE_CAP_PRIMITIVE_RESTART:
>         return 1;
>      case PIPE_CAP_DEPTHSTENCIL_CLEAR_SEPARATE:
> diff --git a/src/gallium/drivers/softpipe/sp_setup.c b/src/gallium/drivers/softpipe/sp_setup.c
> index 656d001..0d67af3 100644
> --- a/src/gallium/drivers/softpipe/sp_setup.c
> +++ b/src/gallium/drivers/softpipe/sp_setup.c
> @@ -807,7 +807,7 @@ sp_setup_tri(struct setup_context *setup,
>      print_vertex(setup, v2);
>   #endif
>
> -   if (setup->softpipe->no_rast)
> +   if (setup->softpipe->no_rast || setup->softpipe->rasterizer->rasterizer_discard)
>         return;
>
>      det = calc_det(v0, v1, v2);
> @@ -1073,7 +1073,7 @@ sp_setup_line(struct setup_context *setup,
>      print_vertex(setup, v1);
>   #endif
>
> -   if (setup->softpipe->no_rast)
> +   if (setup->softpipe->no_rast || setup->softpipe->rasterizer->rasterizer_discard)
>         return;
>
>      if (dx == 0&&  dy == 0)
> @@ -1206,7 +1206,7 @@ sp_setup_point(struct setup_context *setup,
>      print_vertex(setup, v0);
>   #endif
>
> -   if (softpipe->no_rast)
> +   if (setup->softpipe->no_rast || setup->softpipe->rasterizer->rasterizer_discard)
>         return;
>
>      assert(setup->softpipe->reduced_prim == PIPE_PRIM_POINTS);
> diff --git a/src/gallium/drivers/softpipe/sp_state.h b/src/gallium/drivers/softpipe/sp_state.h
> index bdda294..6df40c6 100644
> --- a/src/gallium/drivers/softpipe/sp_state.h
> +++ b/src/gallium/drivers/softpipe/sp_state.h
> @@ -159,9 +159,6 @@ softpipe_draw_vbo(struct pipe_context *pipe,
>                     const struct pipe_draw_info *info);
>
>   void
> -softpipe_draw_stream_output(struct pipe_context *pipe, unsigned mode);
> -
> -void
>   softpipe_map_transfers(struct softpipe_context *sp);
>
>   void
> diff --git a/src/gallium/drivers/softpipe/sp_state_so.c b/src/gallium/drivers/softpipe/sp_state_so.c
> index 31ef384..7abaa1a 100644
> --- a/src/gallium/drivers/softpipe/sp_state_so.c
> +++ b/src/gallium/drivers/softpipe/sp_state_so.c
> @@ -32,109 +32,61 @@
>   #include "util/u_format.h"
>   #include "util/u_memory.h"
>   #include "draw/draw_context.h"
> +#include "pipebuffer/pb_buffer.h"
>
> -
> -static void *
> -softpipe_create_stream_output_state(struct pipe_context *pipe,
> -                                    const struct pipe_stream_output_info *templ)
> -{
> -   struct sp_so_state *so;
> -   so = (struct sp_so_state *) CALLOC_STRUCT(sp_so_state);
> -
> -   if (so) {
> -      so->base.num_outputs = templ->num_outputs;
> -      so->base.stride = templ->stride;
> -      memcpy(so->base.output, templ->output,
> -             templ->num_outputs * sizeof(templ->output[0]));
> -   }
> -   return so;
> -}
> -
> -
> -static void
> -softpipe_bind_stream_output_state(struct pipe_context *pipe,
> -                                  void *so)
> +static struct pipe_stream_output_target *
> +softpipe_create_so_target(struct pipe_context *pipe,
> +                          struct pipe_resource *buffer,
> +                          unsigned buffer_offset,
> +                          unsigned buffer_size)
>   {
> -   struct softpipe_context *softpipe = softpipe_context(pipe);
> -   struct sp_so_state *sp_so = (struct sp_so_state *) so;
> -
> -   softpipe->so = sp_so;
> -
> -   softpipe->dirty |= SP_NEW_SO;
> -
> -   if (sp_so)
> -      draw_set_so_state(softpipe->draw,&sp_so->base);
> +   struct draw_so_target *t;
> +
> +   t = CALLOC_STRUCT(draw_so_target);
> +   t->b.context = pipe;
> +   t->b.reference.count = 1;
> +   pipe_resource_reference(&t->b.buffer, buffer);
> +   t->b.buffer_offset = buffer_offset;
> +   t->b.buffer_size = buffer_size;
> +   return&t->b;
>   }
>
> -
> -static void
> -softpipe_delete_stream_output_state(struct pipe_context *pipe, void *so)
> +static void softpipe_so_target_destroy(struct pipe_context *pipe,
> +                                       struct pipe_stream_output_target *target)

Lets keep the formatting like:

static void
softpipe_so_target_destroy(...)

To be consistent.


>   {
> -   FREE( so );
> +   struct pipe_stream_output_target *b = target;
> +   pipe_resource_reference(&b->buffer, NULL);
> +   FREE(b);

Why isn't that written as

pipe_resource_reference(&target->buffer, NULL);
FREE(target);



>   }
>
> -
> -static void
> -softpipe_set_stream_output_buffers(struct pipe_context *pipe,
> -                                   struct pipe_resource **buffers,
> -                                   int *offsets,
> -                                   int num_buffers)
> +static void softpipe_set_so_targets(struct pipe_context *pipe,
> +                                    unsigned num_targets,
> +                                    struct pipe_stream_output_target **targets,
> +                                    unsigned append_bitmask)
>   {
>      struct softpipe_context *softpipe = softpipe_context(pipe);
>      int i;
> -   void *map_buffers[PIPE_MAX_SO_BUFFERS];
> -
> -   assert(num_buffers<= PIPE_MAX_SO_BUFFERS);
> -   if (num_buffers>  PIPE_MAX_SO_BUFFERS)
> -      num_buffers = PIPE_MAX_SO_BUFFERS;
> -
> -   softpipe->dirty |= SP_NEW_SO_BUFFERS;
>
> -   for (i = 0; i<  num_buffers; ++i) {
> -      void *mapped;
> -      struct softpipe_resource *res = softpipe_resource(buffers[i]);
> +   if (softpipe->num_so_targets) {
>
> -      if (!res) {
> -         /* the whole call is invalid, bail out */
> -         softpipe->so_target.num_buffers = 0;
> -         draw_set_mapped_so_buffers(softpipe->draw, 0, 0);
> -         return;
> -      }
> +   }

Maybe I'm misreading the patch here, but that looks like an empty 
conditional.


>
> -      softpipe->so_target.buffer[i] = res;
> -      softpipe->so_target.offset[i] = offsets[i];
> -      softpipe->so_target.so_count[i] = 0;
> +   for (i = 0; i<  num_targets; i++) {
> +      pipe_so_target_reference((struct pipe_stream_output_target **)&softpipe->so_targets[i], targets[i]);
> +   }
>
> -      mapped = res->data;
> -      if (offsets[i]>= 0)
> -         map_buffers[i] = ((char*)mapped) + offsets[i];
> -      else {
> -         /* this is a buffer append */
> -         assert(!"appending not implemented");
> -         map_buffers[i] = mapped;
> -      }
> +   for (; i<  softpipe->num_so_targets; i++) {
> +      pipe_so_target_reference((struct pipe_stream_output_target **)&softpipe->so_targets[i], NULL);
>      }
> -   softpipe->so_target.num_buffers = num_buffers;
>
> -   draw_set_mapped_so_buffers(softpipe->draw, map_buffers, num_buffers);
> +   softpipe->num_so_targets = num_targets;
>   }
>
> -
> -
>   void
>   softpipe_init_streamout_funcs(struct pipe_context *pipe)
>   {
> -#if 0
> -   pipe->create_stream_output_state = softpipe_create_stream_output_state;
> -   pipe->bind_stream_output_state = softpipe_bind_stream_output_state;
> -   pipe->delete_stream_output_state = softpipe_delete_stream_output_state;
> -
> -   pipe->set_stream_output_buffers = softpipe_set_stream_output_buffers;
> -#else
> -   (void) softpipe_create_stream_output_state;
> -   (void) softpipe_bind_stream_output_state;
> -   (void) softpipe_delete_stream_output_state;
> -   (void) softpipe_set_stream_output_buffers;
> -#endif
> +   pipe->create_stream_output_target = softpipe_create_so_target;
> +   pipe->stream_output_target_destroy = softpipe_so_target_destroy;
> +   pipe->set_stream_output_targets = softpipe_set_so_targets;
>   }
>



More information about the mesa-dev mailing list