[Mesa-dev] [PATCH 8/8] st/mesa: implement EXT_transform_feedback and ARB_transform_feedback2

Marek Olšák maraeo at gmail.com
Sat Nov 19 12:44:30 PST 2011


---
 src/gallium/auxiliary/cso_cache/cso_context.c |  101 ++++++++++++++++++
 src/gallium/auxiliary/cso_cache/cso_context.h |    8 ++
 src/gallium/auxiliary/util/u_blit.c           |    6 +
 src/gallium/auxiliary/util/u_gen_mipmap.c     |    3 +
 src/mesa/state_tracker/st_atom_rasterizer.c   |    7 +-
 src/mesa/state_tracker/st_cb_bitmap.c         |    3 +
 src/mesa/state_tracker/st_cb_clear.c          |    3 +
 src/mesa/state_tracker/st_cb_drawpixels.c     |    3 +
 src/mesa/state_tracker/st_cb_drawtex.c        |    3 +
 src/mesa/state_tracker/st_cb_xformfb.c        |  142 +++++++++++++++++++------
 src/mesa/state_tracker/st_cb_xformfb.h        |   12 ++
 src/mesa/state_tracker/st_draw.c              |   12 ++-
 src/mesa/state_tracker/st_extensions.c        |   16 +++
 src/mesa/state_tracker/st_glsl_to_tgsi.cpp    |   25 +++++
 src/mesa/state_tracker/st_glsl_to_tgsi.h      |    6 +
 src/mesa/state_tracker/st_program.c           |   12 ++
 16 files changed, 325 insertions(+), 37 deletions(-)

diff --git a/src/gallium/auxiliary/cso_cache/cso_context.c b/src/gallium/auxiliary/cso_cache/cso_context.c
index b2a2b79..49318e7 100644
--- a/src/gallium/auxiliary/cso_cache/cso_context.c
+++ b/src/gallium/auxiliary/cso_cache/cso_context.c
@@ -79,6 +79,7 @@ struct cso_context {
    struct cso_cache *cache;
 
    boolean has_geometry_shader;
+   boolean has_streamout;
 
    struct sampler_info fragment_samplers;
    struct sampler_info vertex_samplers;
@@ -89,6 +90,12 @@ struct cso_context {
    uint nr_vertex_buffers_saved;
    struct pipe_vertex_buffer vertex_buffers_saved[PIPE_MAX_ATTRIBS];
 
+   unsigned nr_so_targets;
+   struct pipe_stream_output_target *so_targets[PIPE_MAX_SO_BUFFERS];
+
+   unsigned nr_so_targets_saved;
+   struct pipe_stream_output_target *so_targets_saved[PIPE_MAX_SO_BUFFERS];
+
    /** Current and saved state.
     * The saved state is used as a 1-deep stack.
     */
@@ -276,6 +283,10 @@ struct cso_context *cso_create_context( struct pipe_context *pipe )
                                 PIPE_SHADER_CAP_MAX_INSTRUCTIONS) > 0) {
       ctx->has_geometry_shader = TRUE;
    }
+   if (pipe->screen->get_param(pipe->screen,
+                               PIPE_CAP_MAX_STREAM_OUTPUT_BUFFERS) != 0) {
+      ctx->has_streamout = TRUE;
+   }
 
    return ctx;
 
@@ -306,6 +317,7 @@ void cso_release_all( struct cso_context *ctx )
       ctx->pipe->set_fragment_sampler_views(ctx->pipe, 0, NULL);
       if (ctx->pipe->set_vertex_sampler_views)
          ctx->pipe->set_vertex_sampler_views(ctx->pipe, 0, NULL);
+      ctx->pipe->set_stream_output_targets(ctx->pipe, 0, NULL, 0);
    }
 
    /* free fragment samplers, views */
@@ -332,6 +344,11 @@ void cso_release_all( struct cso_context *ctx )
                             &ctx->nr_vertex_buffers_saved,
                             NULL, 0);
 
+   for (i = 0; i < PIPE_MAX_SO_BUFFERS; i++) {
+      pipe_so_target_reference(&ctx->so_targets[i], NULL);
+      pipe_so_target_reference(&ctx->so_targets_saved[i], NULL);
+   }
+
    if (ctx->cache) {
       cso_cache_delete( ctx->cache );
       ctx->cache = NULL;
@@ -1311,3 +1328,87 @@ cso_restore_vertex_sampler_views(struct cso_context *ctx)
    restore_sampler_views(ctx, &ctx->vertex_samplers,
                          ctx->pipe->set_vertex_sampler_views);
 }
+
+
+void
+cso_set_stream_outputs(struct cso_context *ctx,
+                       unsigned num_targets,
+                       struct pipe_stream_output_target **targets,
+                       unsigned append_bitmask)
+{
+   struct pipe_context *pipe = ctx->pipe;
+   uint i;
+
+   if (!ctx->has_streamout) {
+      assert(num_targets == 0);
+      return;
+   }
+
+   if (ctx->nr_so_targets == 0 && num_targets == 0) {
+      /* Nothing to do. */
+      return;
+   }
+
+   /* reference new targets */
+   for (i = 0; i < num_targets; i++) {
+      pipe_so_target_reference(&ctx->so_targets[i], targets[i]);
+   }
+   /* unref extra old targets, if any */
+   for (; i < ctx->nr_so_targets; i++) {
+      pipe_so_target_reference(&ctx->so_targets[i], NULL);
+   }
+
+   pipe->set_stream_output_targets(pipe, num_targets, targets,
+                                   append_bitmask);
+   ctx->nr_so_targets = num_targets;
+}
+
+void
+cso_save_stream_outputs(struct cso_context *ctx)
+{
+   uint i;
+
+   if (!ctx->has_streamout) {
+      return;
+   }
+
+   ctx->nr_so_targets_saved = ctx->nr_so_targets;
+
+   for (i = 0; i < ctx->nr_so_targets; i++) {
+      assert(!ctx->so_targets_saved[i]);
+      pipe_so_target_reference(&ctx->so_targets_saved[i], ctx->so_targets[i]);
+   }
+}
+
+void
+cso_restore_stream_outputs(struct cso_context *ctx)
+{
+   struct pipe_context *pipe = ctx->pipe;
+   uint i;
+
+   if (!ctx->has_streamout) {
+      return;
+   }
+
+   if (ctx->nr_so_targets == 0 && ctx->nr_so_targets_saved == 0) {
+      /* Nothing to do. */
+      return;
+   }
+
+   for (i = 0; i < ctx->nr_so_targets_saved; i++) {
+      pipe_so_target_reference(&ctx->so_targets[i], NULL);
+      /* move the reference from one pointer to another */
+      ctx->so_targets[i] = ctx->so_targets_saved[i];
+      ctx->so_targets_saved[i] = NULL;
+   }
+   for (; i < ctx->nr_so_targets; i++) {
+      pipe_so_target_reference(&ctx->so_targets[i], NULL);
+   }
+
+   /* ~0 means append */
+   pipe->set_stream_output_targets(pipe, ctx->nr_so_targets_saved,
+                                   ctx->so_targets, ~0);
+
+   ctx->nr_so_targets = ctx->nr_so_targets_saved;
+   ctx->nr_so_targets_saved = 0;
+}
diff --git a/src/gallium/auxiliary/cso_cache/cso_context.h b/src/gallium/auxiliary/cso_cache/cso_context.h
index 00edc9f..5102d70 100644
--- a/src/gallium/auxiliary/cso_cache/cso_context.h
+++ b/src/gallium/auxiliary/cso_cache/cso_context.h
@@ -117,6 +117,14 @@ void cso_save_vertex_buffers(struct cso_context *ctx);
 void cso_restore_vertex_buffers(struct cso_context *ctx);
 
 
+void cso_set_stream_outputs(struct cso_context *ctx,
+                            unsigned num_targets,
+                            struct pipe_stream_output_target **targets,
+                            unsigned append_bitmask);
+void cso_save_stream_outputs(struct cso_context *ctx);
+void cso_restore_stream_outputs(struct cso_context *ctx);
+
+
 /* These aren't really sensible -- most of the time the api provides
  * object semantics for shaders anyway, and the cases where it doesn't
  * (eg mesa's internall-generated texenv programs), it will be up to
diff --git a/src/gallium/auxiliary/util/u_blit.c b/src/gallium/auxiliary/util/u_blit.c
index 3a0d7d4..bba0031 100644
--- a/src/gallium/auxiliary/util/u_blit.c
+++ b/src/gallium/auxiliary/util/u_blit.c
@@ -529,6 +529,7 @@ util_blit_pixels_writemask(struct blit_state *ctx,
    cso_save_rasterizer(ctx->cso);
    cso_save_samplers(ctx->cso);
    cso_save_fragment_sampler_views(ctx->cso);
+   cso_save_stream_outputs(ctx->cso);
    cso_save_viewport(ctx->cso);
    cso_save_framebuffer(ctx->cso);
    cso_save_fragment_shader(ctx->cso);
@@ -546,6 +547,7 @@ util_blit_pixels_writemask(struct blit_state *ctx,
    cso_set_rasterizer(ctx->cso, &ctx->rasterizer);
    cso_set_clip(ctx->cso, &ctx->clip);
    cso_set_vertex_elements(ctx->cso, 2, ctx->velem);
+   cso_set_stream_outputs(ctx->cso, 0, NULL, 0);
 
    /* sampler */
    ctx->sampler.normalized_coords = normalized;
@@ -622,6 +624,7 @@ util_blit_pixels_writemask(struct blit_state *ctx,
    cso_restore_clip(ctx->cso);
    cso_restore_vertex_elements(ctx->cso);
    cso_restore_vertex_buffers(ctx->cso);
+   cso_restore_stream_outputs(ctx->cso);
 
    pipe_sampler_view_reference(&sampler_view, NULL);
    if (dst_surface != dst)
@@ -722,6 +725,7 @@ util_blit_pixels_tex(struct blit_state *ctx,
    cso_save_rasterizer(ctx->cso);
    cso_save_samplers(ctx->cso);
    cso_save_fragment_sampler_views(ctx->cso);
+   cso_save_stream_outputs(ctx->cso);
    cso_save_viewport(ctx->cso);
    cso_save_framebuffer(ctx->cso);
    cso_save_fragment_shader(ctx->cso);
@@ -737,6 +741,7 @@ util_blit_pixels_tex(struct blit_state *ctx,
    cso_set_rasterizer(ctx->cso, &ctx->rasterizer);
    cso_set_clip(ctx->cso, &ctx->clip);
    cso_set_vertex_elements(ctx->cso, 2, ctx->velem);
+   cso_set_stream_outputs(ctx->cso, 0, NULL, 0);
 
    /* sampler */
    ctx->sampler.normalized_coords = normalized;
@@ -801,4 +806,5 @@ util_blit_pixels_tex(struct blit_state *ctx,
    cso_restore_clip(ctx->cso);
    cso_restore_vertex_elements(ctx->cso);
    cso_restore_vertex_buffers(ctx->cso);
+   cso_restore_stream_outputs(ctx->cso);
 }
diff --git a/src/gallium/auxiliary/util/u_gen_mipmap.c b/src/gallium/auxiliary/util/u_gen_mipmap.c
index 436a0e42..7cce815 100644
--- a/src/gallium/auxiliary/util/u_gen_mipmap.c
+++ b/src/gallium/auxiliary/util/u_gen_mipmap.c
@@ -1558,6 +1558,7 @@ util_gen_mipmap(struct gen_mipmap_state *ctx,
    cso_save_rasterizer(ctx->cso);
    cso_save_samplers(ctx->cso);
    cso_save_fragment_sampler_views(ctx->cso);
+   cso_save_stream_outputs(ctx->cso);
    cso_save_framebuffer(ctx->cso);
    cso_save_fragment_shader(ctx->cso);
    cso_save_vertex_shader(ctx->cso);
@@ -1572,6 +1573,7 @@ util_gen_mipmap(struct gen_mipmap_state *ctx,
    cso_set_rasterizer(ctx->cso, &ctx->rasterizer);
    cso_set_clip(ctx->cso, &ctx->clip);
    cso_set_vertex_elements(ctx->cso, 2, ctx->velem);
+   cso_set_stream_outputs(ctx->cso, 0, NULL, 0);
 
    set_fragment_shader(ctx, type);
    set_vertex_shader(ctx);
@@ -1688,4 +1690,5 @@ util_gen_mipmap(struct gen_mipmap_state *ctx,
    cso_restore_viewport(ctx->cso);
    cso_restore_clip(ctx->cso);
    cso_restore_vertex_elements(ctx->cso);
+   cso_restore_stream_outputs(ctx->cso);
 }
diff --git a/src/mesa/state_tracker/st_atom_rasterizer.c b/src/mesa/state_tracker/st_atom_rasterizer.c
index 250cbb2..4aa0b4e 100644
--- a/src/mesa/state_tracker/st_atom_rasterizer.c
+++ b/src/mesa/state_tracker/st_atom_rasterizer.c
@@ -256,9 +256,11 @@ static void update_raster_state( struct st_context *st )
 
    /* _NEW_FRAG_CLAMP */
    raster->clamp_fragment_color = ctx->Color._ClampFragmentColor;
-
    raster->gl_rasterization_rules = 1;
 
+   /* _NEW_TRANSFORM */
+   raster->rasterizer_discard = ctx->TransformFeedback.RasterDiscard;
+
    cso_set_rasterizer(st->cso_context, raster);
 }
 
@@ -273,7 +275,8 @@ const struct st_tracked_state st_update_rasterizer = {
        _NEW_POLYGON |
        _NEW_PROGRAM |
        _NEW_SCISSOR |
-       _NEW_FRAG_CLAMP),      /* mesa state dependencies*/
+       _NEW_FRAG_CLAMP |
+       _NEW_TRANSFORM),      /* mesa state dependencies*/
       ST_NEW_VERTEX_PROGRAM,  /* state tracker dependencies */
    },
    update_raster_state     /* update function */
diff --git a/src/mesa/state_tracker/st_cb_bitmap.c b/src/mesa/state_tracker/st_cb_bitmap.c
index fa37be0..af33bcf 100644
--- a/src/mesa/state_tracker/st_cb_bitmap.c
+++ b/src/mesa/state_tracker/st_cb_bitmap.c
@@ -483,6 +483,7 @@ draw_bitmap_quad(struct gl_context *ctx, GLint x, GLint y, GLfloat z,
    cso_save_fragment_sampler_views(cso);
    cso_save_viewport(cso);
    cso_save_fragment_shader(cso);
+   cso_save_stream_outputs(cso);
    cso_save_vertex_shader(cso);
    cso_save_geometry_shader(cso);
    cso_save_vertex_elements(cso);
@@ -542,6 +543,7 @@ draw_bitmap_quad(struct gl_context *ctx, GLint x, GLint y, GLfloat z,
    }
 
    cso_set_vertex_elements(cso, 3, st->velems_util_draw);
+   cso_set_stream_outputs(st->cso_context, 0, NULL, 0);
 
    /* convert Z from [0,1] to [-1,-1] to match viewport Z scale/bias */
    z = z * 2.0f - 1.0f;
@@ -568,6 +570,7 @@ draw_bitmap_quad(struct gl_context *ctx, GLint x, GLint y, GLfloat z,
    cso_restore_geometry_shader(cso);
    cso_restore_vertex_elements(cso);
    cso_restore_vertex_buffers(cso);
+   cso_restore_stream_outputs(cso);
 }
 
 
diff --git a/src/mesa/state_tracker/st_cb_clear.c b/src/mesa/state_tracker/st_cb_clear.c
index 89273e2..636ff06 100644
--- a/src/mesa/state_tracker/st_cb_clear.c
+++ b/src/mesa/state_tracker/st_cb_clear.c
@@ -250,6 +250,7 @@ clear_with_quad(struct gl_context *ctx,
    cso_save_viewport(st->cso_context);
    cso_save_clip(st->cso_context);
    cso_save_fragment_shader(st->cso_context);
+   cso_save_stream_outputs(st->cso_context);
    cso_save_vertex_shader(st->cso_context);
    cso_save_geometry_shader(st->cso_context);
    cso_save_vertex_elements(st->cso_context);
@@ -306,6 +307,7 @@ clear_with_quad(struct gl_context *ctx,
    }
 
    cso_set_vertex_elements(st->cso_context, 2, st->velems_util_draw);
+   cso_set_stream_outputs(st->cso_context, 0, NULL, 0);
 
    cso_set_rasterizer(st->cso_context, &st->clear.raster);
 
@@ -350,6 +352,7 @@ clear_with_quad(struct gl_context *ctx,
    cso_restore_geometry_shader(st->cso_context);
    cso_restore_vertex_elements(st->cso_context);
    cso_restore_vertex_buffers(st->cso_context);
+   cso_restore_stream_outputs(st->cso_context);
 }
 
 
diff --git a/src/mesa/state_tracker/st_cb_drawpixels.c b/src/mesa/state_tracker/st_cb_drawpixels.c
index 95805fd..360830b 100644
--- a/src/mesa/state_tracker/st_cb_drawpixels.c
+++ b/src/mesa/state_tracker/st_cb_drawpixels.c
@@ -671,6 +671,7 @@ draw_textured_quad(struct gl_context *ctx, GLint x, GLint y, GLfloat z,
    cso_save_samplers(cso);
    cso_save_fragment_sampler_views(cso);
    cso_save_fragment_shader(cso);
+   cso_save_stream_outputs(cso);
    cso_save_vertex_shader(cso);
    cso_save_geometry_shader(cso);
    cso_save_vertex_elements(cso);
@@ -761,6 +762,7 @@ draw_textured_quad(struct gl_context *ctx, GLint x, GLint y, GLfloat z,
    }
 
    cso_set_vertex_elements(cso, 3, st->velems_util_draw);
+   cso_set_stream_outputs(st->cso_context, 0, NULL, 0);
 
    /* texture state: */
    cso_set_fragment_sampler_views(cso, num_sampler_view, sv);
@@ -796,6 +798,7 @@ draw_textured_quad(struct gl_context *ctx, GLint x, GLint y, GLfloat z,
    cso_restore_geometry_shader(cso);
    cso_restore_vertex_elements(cso);
    cso_restore_vertex_buffers(cso);
+   cso_restore_stream_outputs(cso);
    if (write_stencil) {
       cso_restore_depth_stencil_alpha(cso);
       cso_restore_blend(cso);
diff --git a/src/mesa/state_tracker/st_cb_drawtex.c b/src/mesa/state_tracker/st_cb_drawtex.c
index 332b0d1..6144eb9 100644
--- a/src/mesa/state_tracker/st_cb_drawtex.c
+++ b/src/mesa/state_tracker/st_cb_drawtex.c
@@ -227,6 +227,7 @@ st_DrawTex(struct gl_context *ctx, GLfloat x, GLfloat y, GLfloat z,
 
 
    cso_save_viewport(cso);
+   cso_save_stream_outputs(cso);
    cso_save_vertex_shader(cso);
    cso_save_geometry_shader(cso);
    cso_save_vertex_elements(cso);
@@ -246,6 +247,7 @@ st_DrawTex(struct gl_context *ctx, GLfloat x, GLfloat y, GLfloat z,
       velements[i].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
    }
    cso_set_vertex_elements(cso, numAttribs, velements);
+   cso_set_stream_outputs(st->cso_context, 0, NULL, 0);
 
    /* viewport state: viewport matching window dims */
    {
@@ -281,6 +283,7 @@ st_DrawTex(struct gl_context *ctx, GLfloat x, GLfloat y, GLfloat z,
    cso_restore_geometry_shader(cso);
    cso_restore_vertex_elements(cso);
    cso_restore_vertex_buffers(cso);
+   cso_restore_stream_outputs(cso);
 }
 
 
diff --git a/src/mesa/state_tracker/st_cb_xformfb.c b/src/mesa/state_tracker/st_cb_xformfb.c
index a17b54d..2fc28dc 100644
--- a/src/mesa/state_tracker/st_cb_xformfb.c
+++ b/src/mesa/state_tracker/st_cb_xformfb.c
@@ -30,70 +30,122 @@
  * Transform feedback functions.
  *
  * \author Brian Paul
+ *         Marek Olšák
  */
 
 
-#include "main/imports.h"
+#include "main/bufferobj.h"
 #include "main/context.h"
 #include "main/mfeatures.h"
 #include "main/transformfeedback.h"
 
+#include "st_cb_bufferobjects.h"
 #include "st_cb_xformfb.h"
+#include "st_context.h"
 
+#include "pipe/p_context.h"
+#include "util/u_draw.h"
+#include "util/u_inlines.h"
+#include "cso_cache/cso_context.h"
 
 #if FEATURE_EXT_transform_feedback
 
-#if 0
+struct st_transform_feedback_object {
+   struct gl_transform_feedback_object base;
+
+   unsigned num_targets;
+   struct pipe_stream_output_target *targets[PIPE_MAX_SO_BUFFERS];
+};
+
+
 static struct gl_transform_feedback_object *
 st_new_transform_feedback(struct gl_context *ctx, GLuint name)
 {
-   struct gl_transform_feedback_object *obj;
-   obj = CALLOC_STRUCT(gl_transform_feedback_object);
-   if (obj) {
-      obj->Name = name;
-      obj->RefCount = 1;
-   }
-   return obj;
+   struct st_transform_feedback_object *obj;
+
+   obj = CALLOC_STRUCT(st_transform_feedback_object);
+   if (!obj)
+      return NULL;
+
+   obj->base.Name = name;
+   obj->base.RefCount = 1;
+   return &obj->base;
 }
-#endif
 
-#if 0
+
 static void
 st_delete_transform_feedback(struct gl_context *ctx,
                              struct gl_transform_feedback_object *obj)
 {
-   GLuint i;
+   struct st_transform_feedback_object *sobj =
+         (struct st_transform_feedback_object*)obj;
+   unsigned i;
+
+   /* Unreference targets. */
+   for (i = 0; i < sobj->num_targets; i++) {
+      pipe_so_target_reference(&sobj->targets[i], NULL);
+   }
 
-   for (i = 0; i < Elements(obj->Buffers); i++) {
-      _mesa_reference_buffer_object(ctx, &obj->Buffers[i], NULL);
+   for (i = 0; i < Elements(sobj->base.Buffers); i++) {
+      _mesa_reference_buffer_object(ctx, &sobj->base.Buffers[i], NULL);
    }
 
    free(obj);
 }
-#endif
 
 
+/* XXX Do we really need the mode? */
 static void
 st_begin_transform_feedback(struct gl_context *ctx, GLenum mode,
                             struct gl_transform_feedback_object *obj)
 {
-   /* to-do */
-}
-
+   struct st_context *st = st_context(ctx);
+   struct pipe_context *pipe = st->pipe;
+   struct st_transform_feedback_object *sobj =
+         (struct st_transform_feedback_object*)obj;
+   unsigned i, max_num_targets;
+
+   max_num_targets = MIN2(Elements(sobj->base.Buffers),
+                          Elements(sobj->targets));
+
+   /* Convert the transform feedback state into the gallium representation. */
+   for (i = 0; i < max_num_targets; i++) {
+      struct st_buffer_object *bo = st_buffer_object(sobj->base.Buffers[i]);
+
+      if (bo) {
+         /* Check whether we need to recreate the target. */
+         if (!sobj->targets[i] ||
+             sobj->targets[i]->buffer != bo->buffer ||
+             sobj->targets[i]->buffer_offset != sobj->base.Offset[i] ||
+             sobj->targets[i]->buffer_size != sobj->base.Size[i]) {
+            /* Create a new target. */
+            struct pipe_stream_output_target *so_target =
+                  pipe->create_stream_output_target(pipe, bo->buffer,
+                                                    sobj->base.Offset[i],
+                                                    sobj->base.Size[i]);
+
+            pipe_so_target_reference(&sobj->targets[i], NULL);
+            sobj->targets[i] = so_target;
+         }
+
+         sobj->num_targets = i+1;
+      } else {
+         pipe_so_target_reference(&sobj->targets[i], NULL);
+      }
+   }
 
-static void
-st_end_transform_feedback(struct gl_context *ctx,
-                          struct gl_transform_feedback_object *obj)
-{
-   /* to-do */
+   /* Start writing at the beginning of each target. */
+   cso_set_stream_outputs(st->cso_context, sobj->num_targets, sobj->targets,
+                          0);
 }
 
 
 static void
-st_pause_transform_feedback(struct gl_context *ctx,
-                            struct gl_transform_feedback_object *obj)
+st_stop_transform_feedback(struct gl_context *ctx,
+                           struct gl_transform_feedback_object *obj)
 {
-   /* to-do */
+   struct st_context *st = st_context(ctx);
+   cso_set_stream_outputs(st->cso_context, 0, NULL, 0);
 }
 
 
@@ -101,20 +153,44 @@ static void
 st_resume_transform_feedback(struct gl_context *ctx,
                              struct gl_transform_feedback_object *obj)
 {
-   /* to-do */
+   struct st_context *st = st_context(ctx);
+   struct st_transform_feedback_object *sobj =
+         (struct st_transform_feedback_object*)obj;
+
+   cso_set_stream_outputs(st->cso_context, sobj->num_targets, sobj->targets,
+                          ~0);
+}
+
+/* Set count_from_stream_output to any stream output target
+ * from the transform feedback object. */
+void
+st_transform_feedback_draw_init(struct gl_transform_feedback_object *obj,
+                                struct pipe_draw_info *out)
+{
+   struct st_transform_feedback_object *sobj =
+         (struct st_transform_feedback_object*)obj;
+   unsigned i;
+
+   for (i = 0; i < Elements(sobj->targets); i++) {
+      if (sobj->targets[i]) {
+         out->count_from_stream_output = sobj->targets[i];
+         return;
+      }
+   }
+
+   assert(0);
+   out->count_from_stream_output = NULL;
 }
 
 
 void
 st_init_xformfb_functions(struct dd_function_table *functions)
 {
-   /* let core Mesa plug in its functions */
-   _mesa_init_transform_feedback_functions(functions);
-
-   /* then override a few: */
+   functions->NewTransformFeedback = st_new_transform_feedback;
+   functions->DeleteTransformFeedback = st_delete_transform_feedback;
    functions->BeginTransformFeedback = st_begin_transform_feedback;
-   functions->EndTransformFeedback = st_end_transform_feedback;
-   functions->PauseTransformFeedback = st_pause_transform_feedback;
+   functions->EndTransformFeedback = st_stop_transform_feedback;
+   functions->PauseTransformFeedback = st_stop_transform_feedback;
    functions->ResumeTransformFeedback = st_resume_transform_feedback;
 }
 
diff --git a/src/mesa/state_tracker/st_cb_xformfb.h b/src/mesa/state_tracker/st_cb_xformfb.h
index 1215ebe..c5261b3 100644
--- a/src/mesa/state_tracker/st_cb_xformfb.h
+++ b/src/mesa/state_tracker/st_cb_xformfb.h
@@ -33,12 +33,18 @@
 #include "main/mfeatures.h"
 
 struct dd_function_table;
+struct gl_transform_feedback_object;
+struct pipe_draw_info;
 
 #if FEATURE_EXT_transform_feedback
 
 extern void
 st_init_xformfb_functions(struct dd_function_table *functions);
 
+extern void
+st_transform_feedback_draw_init(struct gl_transform_feedback_object *obj,
+                                struct pipe_draw_info *out);
+
 #else
 
 static INLINE void
@@ -46,6 +52,12 @@ st_init_xformfb_functions(struct dd_function_table *functions)
 {
 }
 
+static INLINE void
+st_transform_feedback_draw_init(struct gl_transform_feedback_object *obj,
+                                struct pipe_draw_info *out)
+{
+}
+
 #endif /* FEATURE_EXT_transform_feedback */
 
 #endif /* ST_CB_XFORMFB_H */
diff --git a/src/mesa/state_tracker/st_draw.c b/src/mesa/state_tracker/st_draw.c
index 275756d..c7c3ae9 100644
--- a/src/mesa/state_tracker/st_draw.c
+++ b/src/mesa/state_tracker/st_draw.c
@@ -51,6 +51,7 @@
 #include "st_context.h"
 #include "st_atom.h"
 #include "st_cb_bufferobjects.h"
+#include "st_cb_xformfb.h"
 #include "st_draw.h"
 #include "st_program.h"
 
@@ -940,7 +941,6 @@ st_draw_vbo(struct gl_context *ctx,
 
    /* Mesa core state should have been validated already */
    assert(ctx->NewState == 0x0);
-   assert(!tfb_vertcount);
 
    if (ib) {
       /* Gallium probably doesn't want this in some cases. */
@@ -1034,6 +1034,11 @@ st_draw_vbo(struct gl_context *ctx,
       info.restart_index = ctx->Array.RestartIndex;
    }
 
+   /* Set info.count_from_stream_output. */
+   if (tfb_vertcount) {
+      st_transform_feedback_draw_init(tfb_vertcount, &info);
+   }
+
    /* do actual drawing */
    for (i = 0; i < nr_prims; i++) {
       info.mode = translate_prim( ctx, prims[i].mode );
@@ -1046,7 +1051,10 @@ st_draw_vbo(struct gl_context *ctx,
          info.max_index = info.start + info.count - 1;
       }
 
-      if (info.primitive_restart) {
+      if (info.count_from_stream_output) {
+         pipe->draw_vbo(pipe, &info);
+      }
+      else if (info.primitive_restart) {
          if (st->sw_primitive_restart) {
             /* Handle primitive restart for drivers that doesn't support it */
             handle_fallback_primitive_restart(pipe, ib, &ibuffer, &info);
diff --git a/src/mesa/state_tracker/st_extensions.c b/src/mesa/state_tracker/st_extensions.c
index 3563e1d..4857e66 100644
--- a/src/mesa/state_tracker/st_extensions.c
+++ b/src/mesa/state_tracker/st_extensions.c
@@ -223,6 +223,13 @@ void st_init_limits(struct st_context *st)
       c->UniformBooleanTrue = ~0;
    }
 
+   c->MaxTransformFeedbackSeparateAttribs =
+      screen->get_param(screen, PIPE_CAP_MAX_STREAM_OUTPUT_SEPARATE_ATTRIBS);
+   c->MaxTransformFeedbackSeparateComponents =
+      screen->get_param(screen, PIPE_CAP_MAX_STREAM_OUTPUT_SEPARATE_COMPONENTS);
+   c->MaxTransformFeedbackInterleavedComponents =
+      screen->get_param(screen, PIPE_CAP_MAX_STREAM_OUTPUT_INTERLEAVED_COMPONENTS);
+
    c->StripTextureBorder = GL_TRUE;
 }
 
@@ -664,4 +671,13 @@ void st_init_extensions(struct st_context *st)
                                    PIPE_BIND_SAMPLER_VIEW)) {
       ctx->Extensions.ARB_depth_buffer_float = GL_TRUE;
    }
+
+   if (screen->get_param(screen, PIPE_CAP_MAX_STREAM_OUTPUT_BUFFERS) != 0) {
+      ctx->Extensions.EXT_transform_feedback = GL_TRUE;
+
+      if (screen->get_param(screen,
+                            PIPE_CAP_STREAM_OUTPUT_PAUSE_RESUME) != 0) {
+         ctx->Extensions.ARB_transform_feedback2 = GL_TRUE;
+      }
+   }
 }
diff --git a/src/mesa/state_tracker/st_glsl_to_tgsi.cpp b/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
index 929c7af..cd5980d 100644
--- a/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
+++ b/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
@@ -5089,4 +5089,29 @@ st_link_shader(struct gl_context *ctx, struct gl_shader_program *prog)
    return GL_TRUE;
 }
 
+void
+st_translate_stream_output_info(struct glsl_to_tgsi_visitor *glsl_to_tgsi,
+                                const GLuint outputMapping[],
+                                struct pipe_stream_output_info *so)
+{
+   static unsigned comps_to_mask[] = {
+      0,
+      TGSI_WRITEMASK_X,
+      TGSI_WRITEMASK_XY,
+      TGSI_WRITEMASK_XYZ,
+      TGSI_WRITEMASK_XYZW
+   };
+   unsigned i;
+   struct gl_transform_feedback_info *info =
+      &glsl_to_tgsi->shader_program->LinkedTransformFeedback;
+
+   for (i = 0; i < info->NumOutputs; i++) {
+      assert(info->Outputs[i].NumComponents < Elements(comps_to_mask));
+      so->output_buffer[i] = info->Outputs[i].OutputBuffer;
+      so->register_index[i] = outputMapping[info->Outputs[i].OutputRegister];
+      so->register_mask[i] = comps_to_mask[info->Outputs[i].NumComponents];
+   }
+   so->num_outputs = info->NumOutputs;
+}
+
 } /* extern "C" */
diff --git a/src/mesa/state_tracker/st_glsl_to_tgsi.h b/src/mesa/state_tracker/st_glsl_to_tgsi.h
index fafe52e..1f71f33 100644
--- a/src/mesa/state_tracker/st_glsl_to_tgsi.h
+++ b/src/mesa/state_tracker/st_glsl_to_tgsi.h
@@ -66,6 +66,12 @@ st_new_shader_program(struct gl_context *ctx, GLuint name);
 
 GLboolean st_link_shader(struct gl_context *ctx, struct gl_shader_program *prog);
 
+void
+st_translate_stream_output_info(struct glsl_to_tgsi_visitor *glsl_to_tgsi,
+                                const GLuint outputMapping[],
+                                struct pipe_stream_output_info *so);
+
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/mesa/state_tracker/st_program.c b/src/mesa/state_tracker/st_program.c
index e031579..daec102 100644
--- a/src/mesa/state_tracker/st_program.c
+++ b/src/mesa/state_tracker/st_program.c
@@ -367,6 +367,12 @@ st_translate_vertex_program(struct st_context *st,
 
    ureg_destroy( ureg );
 
+   if (stvp->glsl_to_tgsi) {
+      st_translate_stream_output_info(stvp->glsl_to_tgsi,
+                                      stvp->result_to_output,
+                                      &vpv->tgsi.stream_output);
+   }
+
    vpv->driver_shader = pipe->create_vs_state(pipe, &vpv->tgsi);
 
    if (ST_DEBUG & DEBUG_TGSI) {
@@ -975,6 +981,12 @@ st_translate_geometry_program(struct st_context *st,
    stgp->tgsi.tokens = ureg_get_tokens( ureg, NULL );
    ureg_destroy( ureg );
 
+   if (stgp->glsl_to_tgsi) {
+      st_translate_stream_output_info(stgp->glsl_to_tgsi,
+                                      outputMapping,
+                                      &stgp->tgsi.stream_output);
+   }
+
    /* fill in new variant */
    gpv->driver_shader = pipe->create_gs_state(pipe, &stgp->tgsi);
    gpv->key = *key;
-- 
1.7.5.4



More information about the mesa-dev mailing list