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 <zackr@vmware.com> Reviewed-by: Roland Scheidegger <sroland@vmware.com> Reviewed-by: Jose Fonseca <jfonseca@vmware.com>
This commit is contained in:
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user