draw/llvmpipe: allow independent so attachments to the vs
authorZack Rusin <zackr@vmware.com>
Sat, 30 Mar 2013 13:21:41 +0000 (06:21 -0700)
committerZack Rusin <zackr@vmware.com>
Wed, 3 Apr 2013 17:16:25 +0000 (10:16 -0700)
When geometry shaders are present, one needs to be able to create
an empty geometry shader with stream output that needs to be
resolved later and attached to the currently bound vertex shader.
Lets add support for it to llvmpipe and draw. draw allows attaching
independent stream output info to any vertex shader and llvmpipe
resolves at draw time which vertex shader the given empty geometry
shader should be linked to.

Signed-off-by: Zack Rusin <zackr@vmware.com>
Reviewed-by: Brian Paul <brianp@vmware.com>
Reviewed-by: José Fonseca <jfonseca@vmware.com>
src/gallium/auxiliary/draw/draw_context.c
src/gallium/auxiliary/draw/draw_context.h
src/gallium/auxiliary/draw/draw_private.h
src/gallium/auxiliary/draw/draw_vs.c
src/gallium/drivers/llvmpipe/lp_draw_arrays.c
src/gallium/drivers/llvmpipe/lp_state_gs.c

index bb56f1bdee5db87210a96c54d8b2e2d2494a5787..2fb9bacf4c6765fb1cd9630818101225f6559d0e 100644 (file)
@@ -734,15 +734,6 @@ draw_set_mapped_so_targets(struct draw_context *draw,
    draw->so.num_targets = num_targets;
 }
 
-void
-draw_set_so_state(struct draw_context *draw,
-                  struct pipe_stream_output_info *state)
-{
-   memcpy(&draw->so.state,
-          state,
-          sizeof(struct pipe_stream_output_info));
-}
-
 void
 draw_set_sampler_views(struct draw_context *draw,
                        unsigned shader_stage,
index 426fd44f5ebfeae814f7b4e9487d2b5617bca681..1d25b7f255e07f2723b6b2d2d0dd1c21801c683e 100644 (file)
@@ -171,6 +171,9 @@ void draw_bind_vertex_shader(struct draw_context *draw,
                              struct draw_vertex_shader *dvs);
 void draw_delete_vertex_shader(struct draw_context *draw,
                                struct draw_vertex_shader *dvs);
+void draw_vs_attach_so(struct draw_vertex_shader *dvs,
+                       const struct pipe_stream_output_info *info);
+void draw_vs_reset_so(struct draw_vertex_shader *dvs);
 
 
 /*
@@ -226,10 +229,6 @@ 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);
-
 
 /***********************************************************************
  * draw_pt.c 
index 5063c3c8f646575e7404cdd99e74078cc6acc3de..757ed2645efe8a125b3cffb8651694c863de0a67 100644 (file)
@@ -279,7 +279,6 @@ struct draw_context
 
    /** Stream output (vertex feedback) state */
    struct {
-      struct pipe_stream_output_info state;
       struct draw_so_target *targets[PIPE_MAX_SO_BUFFERS];
       uint num_targets;
    } so;
index 266cca713e1591f30f3614955e0237cde107ba85..afec3760e770e24170504f55df03b58a009ced07 100644 (file)
@@ -245,3 +245,16 @@ draw_vs_get_emit( struct draw_context *draw,
    
    return draw->vs.emit;
 }
+
+void
+draw_vs_attach_so(struct draw_vertex_shader *dvs,
+                  const struct pipe_stream_output_info *info)
+{
+   dvs->state.stream_output = *info;
+}
+
+void
+draw_vs_reset_so(struct draw_vertex_shader *dvs)
+{
+   memset(&dvs->state.stream_output, 0, sizeof(dvs->state.stream_output));
+}
index ae00c49d490b1b138df5a2d93c50f27744ff7409..efeca255755a231428948ca2bfe30789195c4af6 100644 (file)
@@ -101,6 +101,13 @@ llvmpipe_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info)
    llvmpipe_prepare_geometry_sampling(lp,
                                       lp->num_sampler_views[PIPE_SHADER_GEOMETRY],
                                       lp->sampler_views[PIPE_SHADER_GEOMETRY]);
+   if (lp->gs && !lp->gs->shader.tokens) {
+      /* we have an empty geometry shader with stream output, so
+         attach the stream output info to the current vertex shader */
+      if (lp->vs) {
+         draw_vs_attach_so(lp->vs->draw_data, &lp->gs->shader.stream_output);
+      }
+   }
 
    /* draw! */
    draw_vbo(draw, info);
@@ -116,6 +123,14 @@ llvmpipe_draw_vbo(struct pipe_context *pipe, const struct pipe_draw_info *info)
    }
    draw_set_mapped_so_targets(draw, 0, NULL);
 
+   if (lp->gs && !lp->gs->shader.tokens) {
+      /* we have attached stream output to the vs for rendering,
+         now lets reset it */
+      if (lp->vs) {
+         draw_vs_reset_so(lp->vs->draw_data);
+      }
+   }
+   
    llvmpipe_cleanup_vertex_sampling(lp);
    llvmpipe_cleanup_geometry_sampling(lp);
 
index fd6f5f7d0da4a60f9471b211de0a45abc6fa6d56..b18795cdc4fdf46bd457be11d1769589bc47b81d 100644 (file)
@@ -53,15 +53,18 @@ llvmpipe_create_gs_state(struct pipe_context *pipe,
    if (0)
       tgsi_dump(templ->tokens, 0);
 
-   /* copy shader tokens, the ones passed in will go away.
-    */
-   state->shader.tokens = tgsi_dup_tokens(templ->tokens);
-   if (state->shader.tokens == NULL)
-      goto fail;
-
-   state->draw_data = draw_create_geometry_shader(llvmpipe->draw, templ);
-   if (state->draw_data == NULL)
-      goto fail;
+   /* copy stream output info */
+   state->shader = *templ;
+   if (templ->tokens) {
+      /* copy shader tokens, the ones passed in will go away. */
+      state->shader.tokens = tgsi_dup_tokens(templ->tokens);
+      if (state->shader.tokens == NULL)
+         goto fail;
+
+      state->draw_data = draw_create_geometry_shader(llvmpipe->draw, templ);
+      if (state->draw_data == NULL)
+         goto fail;
+   }
 
    return state;