summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZack Rusin <[email protected]>2010-06-10 13:07:27 -0400
committerZack Rusin <[email protected]>2010-06-10 13:07:27 -0400
commit4d0baa73c9e1a40b4ac089c786af79dc7f1ff219 (patch)
tree747b07c1e64f8de2bd3d587d151078e47ebc02ac
parent9ef6d34f7e03f3d33c0ebad4191f3300a9062c4a (diff)
draw: geometry shader fixes
don't overwrite the inputs and make sure the correct primitive is used on entry
-rw-r--r--src/gallium/auxiliary/draw/draw_gs.c47
-rw-r--r--src/gallium/auxiliary/draw/draw_gs.h3
-rw-r--r--src/gallium/auxiliary/draw/draw_private.h5
-rw-r--r--src/gallium/auxiliary/draw/draw_pt_fetch_shade_pipeline.c35
-rw-r--r--src/gallium/auxiliary/util/u_prim.h46
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 9dd19bdc36a..a679f4bf05d 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 6a9800c43f4..a91f5313e21 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 ca8f9cfab1e..fe867ff8e27 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 4f88b27b7d5..2301e542aab 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 64390e13851..606b9b5c6b9 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