From: Zack Rusin Date: Wed, 31 Jul 2013 11:34:49 +0000 (-0400) Subject: draw: inject frontface info into wireframe outputs X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=d6b3a193d4d525c5048ebf793e6a63fd98f92d64;p=mesa.git 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 --- 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. diff --git a/src/gallium/drivers/i915/i915_state_derived.c b/src/gallium/drivers/i915/i915_state_derived.c index e01f16e715c..e1d18403d5d 100644 --- a/src/gallium/drivers/i915/i915_state_derived.c +++ b/src/gallium/drivers/i915/i915_state_derived.c @@ -67,6 +67,8 @@ static void calculate_vertex_layout(struct i915_context *i915) colors[0] = colors[1] = fog = needW = face = FALSE; memset(&vinfo, 0, sizeof(vinfo)); + draw_prepare_shader_outputs(i915->draw); + /* Determine which fragment program inputs are needed. Setup HW vertex * layout below, in the HW-specific attribute order. */ diff --git a/src/gallium/drivers/llvmpipe/lp_context.h b/src/gallium/drivers/llvmpipe/lp_context.h index 9495e42feee..fc948a727fe 100644 --- a/src/gallium/drivers/llvmpipe/lp_context.h +++ b/src/gallium/drivers/llvmpipe/lp_context.h @@ -122,6 +122,9 @@ struct llvmpipe_context { /** Which geometry shader output slot contains layer */ int layer_slot; + /** A fake frontface output for unfilled primitives */ + int face_slot; + /**< minimum resolvable depth value, for polygon offset */ double mrd; diff --git a/src/gallium/drivers/llvmpipe/lp_setup.c b/src/gallium/drivers/llvmpipe/lp_setup.c index 65f61edc360..5fde01fa13b 100644 --- a/src/gallium/drivers/llvmpipe/lp_setup.c +++ b/src/gallium/drivers/llvmpipe/lp_setup.c @@ -1053,6 +1053,7 @@ lp_setup_update_state( struct lp_setup_context *setup, setup->psize = lp->psize_slot; setup->viewport_index_slot = lp->viewport_index_slot; setup->layer_slot = lp->layer_slot; + setup->face_slot = lp->face_slot; assert(lp->dirty == 0); diff --git a/src/gallium/drivers/llvmpipe/lp_setup_context.h b/src/gallium/drivers/llvmpipe/lp_setup_context.h index 89c23bbb3ac..ea1d0d688d8 100644 --- a/src/gallium/drivers/llvmpipe/lp_setup_context.h +++ b/src/gallium/drivers/llvmpipe/lp_setup_context.h @@ -106,6 +106,7 @@ struct lp_setup_context float psize; unsigned viewport_index_slot; unsigned layer_slot; + unsigned face_slot; struct pipe_framebuffer_state fb; struct u_rect framebuffer; diff --git a/src/gallium/drivers/llvmpipe/lp_setup_line.c b/src/gallium/drivers/llvmpipe/lp_setup_line.c index bfed59cba0a..3b16163ba59 100644 --- a/src/gallium/drivers/llvmpipe/lp_setup_line.c +++ b/src/gallium/drivers/llvmpipe/lp_setup_line.c @@ -37,6 +37,7 @@ #include "lp_state_fs.h" #include "lp_state_setup.h" #include "lp_context.h" +#include "draw/draw_context.h" #define NUM_CHANNELS 4 @@ -45,6 +46,7 @@ struct lp_line_info { float dx; float dy; float oneoverarea; + boolean frontfacing; const float (*v1)[4]; const float (*v2)[4]; @@ -214,7 +216,8 @@ static void setup_line_coefficients( struct lp_setup_context *setup, case LP_INTERP_FACING: for (i = 0; i < NUM_CHANNELS; i++) if (usage_mask & (1 << i)) - constant_coef(setup, info, slot+1, 1.0, i); + constant_coef(setup, info, slot+1, + info->frontfacing ? 1.0f : -1.0f, i); break; default: @@ -613,15 +616,22 @@ try_setup_line( struct lp_setup_context *setup, plane[2].dcdx = y[2] - y[3]; plane[3].dcdx = y[3] - y[0]; + if (draw_will_inject_frontface(lp_context->draw) && + setup->face_slot > 0) { + line->inputs.frontfacing = v1[setup->face_slot][0]; + } else { + line->inputs.frontfacing = TRUE; + } + /* Setup parameter interpolants: */ info.a0 = GET_A0(&line->inputs); info.dadx = GET_DADX(&line->inputs); info.dady = GET_DADY(&line->inputs); + info.frontfacing = line->inputs.frontfacing; setup_line_coefficients(setup, &info); - line->inputs.frontfacing = TRUE; line->inputs.disable = FALSE; line->inputs.opaque = FALSE; line->inputs.layer = layer; diff --git a/src/gallium/drivers/llvmpipe/lp_setup_point.c b/src/gallium/drivers/llvmpipe/lp_setup_point.c index 868a9a904b7..cbcc8d4f2f3 100644 --- a/src/gallium/drivers/llvmpipe/lp_setup_point.c +++ b/src/gallium/drivers/llvmpipe/lp_setup_point.c @@ -38,6 +38,7 @@ #include "lp_state_setup.h" #include "lp_context.h" #include "tgsi/tgsi_scan.h" +#include "draw/draw_context.h" #define NUM_CHANNELS 4 @@ -51,6 +52,8 @@ struct point_info { float (*a0)[4]; float (*dadx)[4]; float (*dady)[4]; + + boolean frontfacing; }; @@ -276,7 +279,8 @@ setup_point_coefficients( struct lp_setup_context *setup, case LP_INTERP_FACING: for (i = 0; i < NUM_CHANNELS; i++) if (usage_mask & (1 << i)) - constant_coef(setup, info, slot+1, 1.0, i); + constant_coef(setup, info, slot+1, + info->frontfacing ? 1.0f : -1.0f, i); break; default: @@ -384,6 +388,13 @@ try_setup_point( struct lp_setup_context *setup, lp_context->pipeline_statistics.c_primitives++; } + if (draw_will_inject_frontface(lp_context->draw) && + setup->face_slot > 0) { + point->inputs.frontfacing = v0[setup->face_slot][0]; + } else { + point->inputs.frontfacing = TRUE; + } + info.v0 = v0; info.dx01 = 0; info.dx12 = fixed_width; @@ -392,12 +403,12 @@ try_setup_point( struct lp_setup_context *setup, info.a0 = GET_A0(&point->inputs); info.dadx = GET_DADX(&point->inputs); info.dady = GET_DADY(&point->inputs); + info.frontfacing = point->inputs.frontfacing; /* Setup parameter interpolants: */ setup_point_coefficients(setup, &info); - point->inputs.frontfacing = TRUE; point->inputs.disable = FALSE; point->inputs.opaque = FALSE; point->inputs.layer = layer; diff --git a/src/gallium/drivers/llvmpipe/lp_state_derived.c b/src/gallium/drivers/llvmpipe/lp_state_derived.c index dc80358c7be..5a51b50821e 100644 --- a/src/gallium/drivers/llvmpipe/lp_state_derived.c +++ b/src/gallium/drivers/llvmpipe/lp_state_derived.c @@ -53,6 +53,8 @@ compute_vertex_info(struct llvmpipe_context *llvmpipe) int vs_index; uint i; + draw_prepare_shader_outputs(llvmpipe->draw); + llvmpipe->color_slot[0] = -1; llvmpipe->color_slot[1] = -1; llvmpipe->bcolor_slot[0] = -1; @@ -138,6 +140,13 @@ compute_vertex_info(struct llvmpipe_context *llvmpipe) llvmpipe->layer_slot = 0; } + /* Check for a fake front face for unfilled primitives*/ + vs_index = draw_find_shader_output(llvmpipe->draw, + TGSI_SEMANTIC_FACE, 0); + if (vs_index >= 0) { + llvmpipe->face_slot = vinfo->num_attribs; + draw_emit_vertex_attr(vinfo, EMIT_4F, INTERP_CONSTANT, vs_index); + } draw_compute_vertex_size(vinfo); lp_setup_set_vertex_info(llvmpipe->setup, vinfo); diff --git a/src/gallium/drivers/r300/r300_state_derived.c b/src/gallium/drivers/r300/r300_state_derived.c index 1013557bde9..da86cd2aaa5 100644 --- a/src/gallium/drivers/r300/r300_state_derived.c +++ b/src/gallium/drivers/r300/r300_state_derived.c @@ -1079,6 +1079,7 @@ void r300_update_derived_state(struct r300_context* r300) if (r300->draw) { memset(&r300->vertex_info, 0, sizeof(struct vertex_info)); + draw_prepare_shader_outputs(r300->draw); r300_draw_emit_all_attribs(r300); draw_compute_vertex_size(&r300->vertex_info); r300_swtcl_vertex_psc(r300); diff --git a/src/gallium/drivers/softpipe/sp_state_derived.c b/src/gallium/drivers/softpipe/sp_state_derived.c index 61153494c5b..9aa97d2d202 100644 --- a/src/gallium/drivers/softpipe/sp_state_derived.c +++ b/src/gallium/drivers/softpipe/sp_state_derived.c @@ -65,6 +65,8 @@ softpipe_get_vertex_info(struct softpipe_context *softpipe) { struct vertex_info *vinfo = &softpipe->vertex_info; + draw_prepare_shader_outputs(softpipe->draw); + if (vinfo->num_attribs == 0) { /* compute vertex layout now */ const struct tgsi_shader_info *fsInfo = &softpipe->fs_variant->info; diff --git a/src/gallium/drivers/svga/svga_swtnl_state.c b/src/gallium/drivers/svga/svga_swtnl_state.c index d744f18ee72..d60af3fb834 100644 --- a/src/gallium/drivers/svga/svga_swtnl_state.c +++ b/src/gallium/drivers/svga/svga_swtnl_state.c @@ -162,6 +162,7 @@ svga_swtnl_update_vdecl( struct svga_context *svga ) memset(vinfo, 0, sizeof(*vinfo)); memset(vdecl, 0, sizeof(vdecl)); + draw_prepare_shader_outputs(draw); /* always add position */ src = draw_find_shader_output(draw, TGSI_SEMANTIC_POSITION, 0); draw_emit_vertex_attr(vinfo, EMIT_4F, INTERP_LINEAR, src);