From d6b3a193d4d525c5048ebf793e6a63fd98f92d64 Mon Sep 17 00:00:00 2001 From: Zack Rusin Date: Wed, 31 Jul 2013 07:34:49 -0400 Subject: draw: inject frontface info into wireframe outputs Draw module can decompose primitives into wireframe models, which is a fancy word for 'lines', unfortunately that decomposition means that we weren't able to preserve the original front-face info which could be derived from the original primitives (lines don't have a 'face'). To fix it allow draw module to inject a fake face semantic into outputs from which the backends can figure out the original frontfacing info of the primitives. Signed-off-by: Zack Rusin Reviewed-by: Roland Scheidegger Reviewed-by: Jose Fonseca --- src/gallium/auxiliary/draw/draw_context.c | 43 ++++++++++++++++++++++ src/gallium/auxiliary/draw/draw_context.h | 6 +++ src/gallium/auxiliary/draw/draw_pipe.h | 3 ++ src/gallium/auxiliary/draw/draw_pipe_unfilled.c | 49 +++++++++++++++++++++++++ 4 files changed, 101 insertions(+) (limited to 'src/gallium/auxiliary') diff --git a/src/gallium/auxiliary/draw/draw_context.c b/src/gallium/auxiliary/draw/draw_context.c index 29bbc94d0ab..377b852f052 100644 --- a/src/gallium/auxiliary/draw/draw_context.c +++ b/src/gallium/auxiliary/draw/draw_context.c @@ -39,6 +39,7 @@ #include "util/u_helpers.h" #include "util/u_prim.h" #include "draw_context.h" +#include "draw_pipe.h" #include "draw_vs.h" #include "draw_gs.h" @@ -540,6 +541,22 @@ draw_get_shader_info(const struct draw_context *draw) } } +/** + * Prepare outputs slots from the draw module + * + * Certain parts of the draw module can emit additional + * outputs that can be quite useful to the backends, a good + * example of it is the process of decomposing primitives + * into wireframes (aka. lines) which normally would lose + * the face-side information, but using this method we can + * inject another shader output which passes the original + * face side information to the backend. + */ +void +draw_prepare_shader_outputs(struct draw_context *draw) +{ + draw_unfilled_prepare_outputs(draw, draw->pipeline.unfilled); +} /** * Ask the draw module for the location/slot of the given vertex attribute in @@ -1007,3 +1024,29 @@ draw_stats_clipper_primitives(struct draw_context *draw, } } } + + +/** + * Returns true if the draw module will inject the frontface + * info into the outputs. + * + * Given the specified primitive and rasterizer state + * the function will figure out if the draw module + * will inject the front-face information into shader + * outputs. This is done to preserve the front-facing + * info when decomposing primitives into wireframes. + */ +boolean +draw_will_inject_frontface(const struct draw_context *draw) +{ + unsigned reduced_prim = u_reduced_prim(draw->pt.prim); + const struct pipe_rasterizer_state *rast = draw->rasterizer; + + if (reduced_prim != PIPE_PRIM_TRIANGLES) { + return FALSE; + } + + return (rast && + (rast->fill_front != PIPE_POLYGON_MODE_FILL || + rast->fill_back != PIPE_POLYGON_MODE_FILL)); +} diff --git a/src/gallium/auxiliary/draw/draw_context.h b/src/gallium/auxiliary/draw/draw_context.h index c720806feca..46d0de6f853 100644 --- a/src/gallium/auxiliary/draw/draw_context.h +++ b/src/gallium/auxiliary/draw/draw_context.h @@ -126,10 +126,16 @@ draw_install_pstipple_stage(struct draw_context *draw, struct pipe_context *pipe struct tgsi_shader_info * draw_get_shader_info(const struct draw_context *draw); +void +draw_prepare_shader_outputs(struct draw_context *draw); + int draw_find_shader_output(const struct draw_context *draw, uint semantic_name, uint semantic_index); +boolean +draw_will_inject_frontface(const struct draw_context *draw); + uint draw_num_shader_outputs(const struct draw_context *draw); diff --git a/src/gallium/auxiliary/draw/draw_pipe.h b/src/gallium/auxiliary/draw/draw_pipe.h index 547e4bf4d05..70c286f4330 100644 --- a/src/gallium/auxiliary/draw/draw_pipe.h +++ b/src/gallium/auxiliary/draw/draw_pipe.h @@ -103,6 +103,9 @@ void draw_pipe_passthrough_line(struct draw_stage *stage, struct prim_header *he void draw_pipe_passthrough_point(struct draw_stage *stage, struct prim_header *header); +void draw_unfilled_prepare_outputs(struct draw_context *context, + struct draw_stage *stage); + /** * Get a writeable copy of a vertex. diff --git a/src/gallium/auxiliary/draw/draw_pipe_unfilled.c b/src/gallium/auxiliary/draw/draw_pipe_unfilled.c index d87741b91e7..d8a603f61cb 100644 --- a/src/gallium/auxiliary/draw/draw_pipe_unfilled.c +++ b/src/gallium/auxiliary/draw/draw_pipe_unfilled.c @@ -47,6 +47,8 @@ struct unfilled_stage { * and PIPE_POLYGON_MODE_POINT, */ unsigned mode[2]; + + int face_slot; }; @@ -55,8 +57,31 @@ static INLINE struct unfilled_stage *unfilled_stage( struct draw_stage *stage ) return (struct unfilled_stage *)stage; } +static void +inject_front_face_info(struct draw_stage *stage, + struct prim_header *header) +{ + struct unfilled_stage *unfilled = unfilled_stage(stage); + unsigned ccw = header->det < 0.0; + boolean is_front_face = ( + (stage->draw->rasterizer->front_ccw && ccw) || + (!stage->draw->rasterizer->front_ccw && !ccw)); + unsigned slot = unfilled->face_slot; + struct vertex_header *v0 = header->v[0]; + struct vertex_header *v1 = header->v[1]; + struct vertex_header *v2 = header->v[2]; + + /* In case the backend doesn't care about it */ + if (slot < 0) { + return; + } + v0->data[slot][0] = is_front_face; + v1->data[slot][0] = is_front_face; + v2->data[slot][0] = is_front_face; +} + static void point( struct draw_stage *stage, struct vertex_header *v0 ) { @@ -83,6 +108,8 @@ static void points( struct draw_stage *stage, struct vertex_header *v1 = header->v[1]; struct vertex_header *v2 = header->v[2]; + inject_front_face_info(stage, header); + if ((header->flags & DRAW_PIPE_EDGE_FLAG_0) && v0->edgeflag) point( stage, v0 ); if ((header->flags & DRAW_PIPE_EDGE_FLAG_1) && v1->edgeflag) point( stage, v1 ); if ((header->flags & DRAW_PIPE_EDGE_FLAG_2) && v2->edgeflag) point( stage, v2 ); @@ -99,6 +126,8 @@ static void lines( struct draw_stage *stage, if (header->flags & DRAW_PIPE_RESET_STIPPLE) stage->next->reset_stipple_counter( stage->next ); + inject_front_face_info(stage, header); + if ((header->flags & DRAW_PIPE_EDGE_FLAG_2) && v2->edgeflag) line( stage, v2, v0 ); if ((header->flags & DRAW_PIPE_EDGE_FLAG_0) && v0->edgeflag) line( stage, v0, v1 ); if ((header->flags & DRAW_PIPE_EDGE_FLAG_1) && v1->edgeflag) line( stage, v1, v2 ); @@ -192,6 +221,26 @@ static void unfilled_destroy( struct draw_stage *stage ) FREE( stage ); } +/* + * Try to allocate an output slot which we can use + * to preserve the front face information. + */ +void +draw_unfilled_prepare_outputs( struct draw_context *draw, + struct draw_stage *stage ) +{ + struct unfilled_stage *unfilled = unfilled_stage(stage); + const struct pipe_rasterizer_state *rast = draw ? draw->rasterizer : 0; + if (rast && + (rast->fill_front != PIPE_POLYGON_MODE_FILL || + rast->fill_back != PIPE_POLYGON_MODE_FILL)) { + unfilled->face_slot = draw_alloc_extra_vertex_attrib( + stage->draw, TGSI_SEMANTIC_FACE, 0); + } else { + unfilled->face_slot = -1; + } +} + /** * Create unfilled triangle stage. -- cgit v1.2.3