Mesa (master): draw: geometry shader fixes

Zack Rusin zack at kemper.freedesktop.org
Thu Jun 10 10:08:17 PDT 2010


Module: Mesa
Branch: master
Commit: 4d0baa73c9e1a40b4ac089c786af79dc7f1ff219
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=4d0baa73c9e1a40b4ac089c786af79dc7f1ff219

Author: Zack Rusin <zack at kde.org>
Date:   Thu Jun 10 13:07:27 2010 -0400

draw: geometry shader fixes

don't overwrite the inputs and make sure the correct primitive
is used on entry

---

 src/gallium/auxiliary/draw/draw_gs.c               |   47 ++++++++++++++++++--
 src/gallium/auxiliary/draw/draw_gs.h               |    3 +
 src/gallium/auxiliary/draw/draw_private.h          |    5 ++
 .../auxiliary/draw/draw_pt_fetch_shade_pipeline.c  |   35 +++++----------
 src/gallium/auxiliary/util/u_prim.h                |   46 +++++++++++++++++++
 5 files changed, 109 insertions(+), 27 deletions(-)

diff --git a/src/gallium/auxiliary/draw/draw_gs.c b/src/gallium/auxiliary/draw/draw_gs.c
index 9dd19bd..a679f4b 100644
--- a/src/gallium/auxiliary/draw/draw_gs.c
+++ b/src/gallium/auxiliary/draw/draw_gs.c
@@ -91,6 +91,7 @@ draw_create_geometry_shader(struct draw_context *draw,
    if (!gs)
       return NULL;
 
+   gs->draw = draw;
    gs->state = *state;
    gs->state.tokens = tgsi_dup_tokens(state->tokens);
    if (!gs->state.tokens) {
@@ -266,6 +267,7 @@ draw_geometry_fetch_outputs(struct draw_geometry_shader *shader,
 }
 
 int draw_geometry_shader_run(struct draw_geometry_shader *shader,
+                             unsigned pipe_prim,
                              const float (*input)[4],
                              float (*output)[4],
                              const void *constants[PIPE_MAX_CONSTANT_BUFFERS],
@@ -275,12 +277,20 @@ int draw_geometry_shader_run(struct draw_geometry_shader *shader,
 {
    struct tgsi_exec_machine *machine = shader->machine;
    unsigned int i;
-   unsigned num_in_vertices = u_vertices_per_prim(shader->input_primitive);
-   unsigned num_in_primitives = count/num_in_vertices;
+   unsigned num_in_primitives =
+      u_gs_prims_for_vertices(pipe_prim, count);
    unsigned inputs_from_vs = 0;
    float (*tmp_output)[4];
+   unsigned alloc_count = draw_max_output_vertices(shader->draw,
+                                                   pipe_prim,
+                                                   count);
+   /* this is bad, but we can't be overwriting the output array
+    * because it's the same as input array here */
+   struct vertex_header *pipeline_verts =
+      (struct vertex_header *)MALLOC(vertex_size * alloc_count);
 
-   if (0) debug_printf("%s count = %d\n", __FUNCTION__, count);
+   if (0) debug_printf("%s count = %d (prims = %d)\n", __FUNCTION__,
+                       count, num_in_primitives);
 
    shader->emitted_vertices = 0;
    shader->emitted_primitives = 0;
@@ -293,7 +303,9 @@ int draw_geometry_shader_run(struct draw_geometry_shader *shader,
       if (shader->info.input_semantic_name[i] != TGSI_SEMANTIC_PRIMID)
          ++inputs_from_vs;
    }
-   tmp_output = output;
+
+   tmp_output = (      float (*)[4])pipeline_verts->data;
+
    for (i = 0; i < num_in_primitives; ++i) {
       unsigned int max_input_primitives = 1;
       /* FIXME: handle all the primitives produced by the gs, not just
@@ -318,6 +330,12 @@ int draw_geometry_shader_run(struct draw_geometry_shader *shader,
       draw_geometry_fetch_outputs(shader, out_prim_count,
                                   &tmp_output, vertex_size);
    }
+
+   memcpy(output, pipeline_verts->data,
+          shader->info.num_outputs * 4 * sizeof(float) +
+          vertex_size * (shader->emitted_vertices -1));
+
+   FREE(pipeline_verts);
    return shader->emitted_vertices;
 }
 
@@ -337,3 +355,24 @@ void draw_geometry_shader_prepare(struct draw_geometry_shader *shader,
                                     draw->gs.samplers);
    }
 }
+
+int draw_max_output_vertices(struct draw_context *draw,
+                             unsigned pipe_prim,
+                             unsigned count)
+{
+   unsigned alloc_count = align( count, 4 );
+
+   if (draw->gs.geometry_shader) {
+      unsigned input_primitives = u_gs_prims_for_vertices(pipe_prim,
+                                                          count);
+      /* max GS output is number of input primitives * max output
+       * vertices per each invocation */
+      unsigned gs_max_verts = input_primitives *
+                              draw->gs.geometry_shader->max_output_vertices;
+      if (gs_max_verts > count)
+         alloc_count = align(gs_max_verts, 4);
+   }
+   /*debug_printf("------- alloc count = %d (input = %d)\n",
+                  alloc_count, count);*/
+   return alloc_count;
+}
diff --git a/src/gallium/auxiliary/draw/draw_gs.h b/src/gallium/auxiliary/draw/draw_gs.h
index 6a9800c..a91f531 100644
--- a/src/gallium/auxiliary/draw/draw_gs.h
+++ b/src/gallium/auxiliary/draw/draw_gs.h
@@ -68,6 +68,7 @@ struct draw_geometry_shader {
  * smaller than the GS_MAX_OUTPUT_VERTICES shader property.
  */
 int draw_geometry_shader_run(struct draw_geometry_shader *shader,
+                             unsigned pipe_prim,
                              const float (*input)[4],
                              float (*output)[4],
                              const void *constants[PIPE_MAX_CONSTANT_BUFFERS],
@@ -80,5 +81,7 @@ void draw_geometry_shader_prepare(struct draw_geometry_shader *shader,
 
 void draw_geometry_shader_delete(struct draw_geometry_shader *shader);
 
+int draw_gs_max_output_vertices(struct draw_geometry_shader *shader,
+                                unsigned pipe_prim);
 
 #endif
diff --git a/src/gallium/auxiliary/draw/draw_private.h b/src/gallium/auxiliary/draw/draw_private.h
index ca8f9cf..fe867ff 100644
--- a/src/gallium/auxiliary/draw/draw_private.h
+++ b/src/gallium/auxiliary/draw/draw_private.h
@@ -380,4 +380,9 @@ draw_get_rasterizer_no_cull( struct draw_context *draw,
                              boolean flatshade );
 
 
+int draw_max_output_vertices(struct draw_context *draw,
+                             unsigned pipe_prim,
+                             unsigned count);
+
+
 #endif /* DRAW_PRIVATE_H */
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 4f88b27..2301e54 100644
--- a/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline.c
+++ b/src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline.c
@@ -52,26 +52,6 @@ struct fetch_pipeline_middle_end {
    unsigned opt;
 };
 
-static int max_out_vertex_count(
-   struct fetch_pipeline_middle_end *fpme, int count)
-{
-   struct draw_context *draw = fpme->draw;
-   unsigned alloc_count = align( count, 4 );
-
-   if (draw->gs.geometry_shader) {
-      unsigned input_primitives = count / u_vertices_per_prim(fpme->input_prim);
-      /* max GS output is number of input primitives * max output
-       * vertices per each invocation */
-      unsigned gs_max_verts = input_primitives *
-                              draw->gs.geometry_shader->max_output_vertices;
-      if (gs_max_verts > count)
-         alloc_count = align(gs_max_verts, 4);
-   }
-   /*debug_printf("------- alloc count = %d (input = %d)\n",
-                  alloc_count, count);*/
-   return alloc_count;
-}
-
 static void fetch_pipeline_prepare( struct draw_pt_middle_end *middle,
                                     unsigned in_prim,
                                     unsigned out_prim,
@@ -160,7 +140,9 @@ static void fetch_pipeline_run( struct draw_pt_middle_end *middle,
    struct draw_geometry_shader *gshader = draw->gs.geometry_shader;
    unsigned opt = fpme->opt;
    struct vertex_header *pipeline_verts;
-   unsigned alloc_count = max_out_vertex_count(fpme, fetch_count);
+   unsigned alloc_count = draw_max_output_vertices(draw,
+                                                   fpme->input_prim,
+                                                   fetch_count);
 
    pipeline_verts =
       (struct vertex_header *)MALLOC(fpme->vertex_size * alloc_count);
@@ -194,6 +176,7 @@ static void fetch_pipeline_run( struct draw_pt_middle_end *middle,
       if (gshader) {
          fetch_count =
             draw_geometry_shader_run(gshader,
+                                     fpme->input_prim,
                                      (const float (*)[4])pipeline_verts->data,
                                      (      float (*)[4])pipeline_verts->data,
                                      draw->pt.user.gs_constants,
@@ -253,7 +236,9 @@ static void fetch_pipeline_linear_run( struct draw_pt_middle_end *middle,
    struct draw_geometry_shader *geometry_shader = draw->gs.geometry_shader;
    unsigned opt = fpme->opt;
    struct vertex_header *pipeline_verts;
-   unsigned alloc_count = max_out_vertex_count(fpme, count);
+   unsigned alloc_count = draw_max_output_vertices(draw,
+                                                   fpme->input_prim,
+                                                   count);
 
    pipeline_verts =
       (struct vertex_header *)MALLOC(fpme->vertex_size * alloc_count);
@@ -288,6 +273,7 @@ static void fetch_pipeline_linear_run( struct draw_pt_middle_end *middle,
       if (geometry_shader) {
          count =
             draw_geometry_shader_run(geometry_shader,
+                                     fpme->input_prim,
                                      (const float (*)[4])pipeline_verts->data,
                                      (      float (*)[4])pipeline_verts->data,
                                      draw->pt.user.gs_constants,
@@ -345,7 +331,9 @@ static boolean fetch_pipeline_linear_run_elts( struct draw_pt_middle_end *middle
    struct draw_geometry_shader *geometry_shader = draw->gs.geometry_shader;
    unsigned opt = fpme->opt;
    struct vertex_header *pipeline_verts;
-   unsigned alloc_count = max_out_vertex_count(fpme, count);
+   unsigned alloc_count = draw_max_output_vertices(draw,
+                                                   fpme->input_prim,
+                                                   count);
 
    pipeline_verts =
       (struct vertex_header *)MALLOC(fpme->vertex_size * alloc_count);
@@ -376,6 +364,7 @@ static boolean fetch_pipeline_linear_run_elts( struct draw_pt_middle_end *middle
       if (geometry_shader) {
          count =
             draw_geometry_shader_run(geometry_shader,
+                                     fpme->input_prim,
                                      (const float (*)[4])pipeline_verts->data,
                                      (      float (*)[4])pipeline_verts->data,
                                      draw->pt.user.gs_constants,
diff --git a/src/gallium/auxiliary/util/u_prim.h b/src/gallium/auxiliary/util/u_prim.h
index 64390e1..606b9b5 100644
--- a/src/gallium/auxiliary/util/u_prim.h
+++ b/src/gallium/auxiliary/util/u_prim.h
@@ -169,6 +169,52 @@ 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
+ * triangle strip, triangle fans and triangles and once
+ * for each line in line strip, line loop, lines.
+ */
+static INLINE unsigned
+u_gs_prims_for_vertices(int primitive, int vertices)
+{
+   switch(primitive) {
+   case PIPE_PRIM_POINTS:
+      return vertices;
+   case PIPE_PRIM_LINES:
+      return vertices / 2;
+   case PIPE_PRIM_LINE_LOOP:
+      return vertices;
+   case PIPE_PRIM_LINE_STRIP:
+      return vertices - 1;
+   case PIPE_PRIM_TRIANGLES:
+      return vertices /  3;
+   case PIPE_PRIM_TRIANGLE_STRIP:
+      return vertices - 2;
+   case PIPE_PRIM_TRIANGLE_FAN:
+      return vertices - 2;
+   case PIPE_PRIM_LINES_ADJACENCY:
+      return vertices / 2;
+   case PIPE_PRIM_LINE_STRIP_ADJACENCY:
+      return vertices - 1;
+   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:
+   case PIPE_PRIM_QUADS:
+   case PIPE_PRIM_QUAD_STRIP:
+   default:
+      debug_printf("Unrecognized geometry shader primitive");
+      return 3;
+   }
+}
+
 const char *u_prim_name( unsigned pipe_prim );
 
 #endif



More information about the mesa-commit mailing list