From 4d0baa73c9e1a40b4ac089c786af79dc7f1ff219 Mon Sep 17 00:00:00 2001 From: Zack Rusin Date: Thu, 10 Jun 2010 13:07:27 -0400 Subject: [PATCH] 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 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 -- 2.11.0