draw: geometry shader fixes
don't overwrite the inputs and make sure the correct primitive is used on entry
This commit is contained in:
parent
9ef6d34f7e
commit
4d0baa73c9
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue