#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"
}
}
+/**
+ * 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
}
}
}
+
+
+/**
+ * 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));
+}
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);
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.
* and PIPE_POLYGON_MODE_POINT,
*/
unsigned mode[2];
+
+ int face_slot;
};
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 )
{
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 );
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 );
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.
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.
*/
/** 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;
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);
float psize;
unsigned viewport_index_slot;
unsigned layer_slot;
+ unsigned face_slot;
struct pipe_framebuffer_state fb;
struct u_rect framebuffer;
#include "lp_state_fs.h"
#include "lp_state_setup.h"
#include "lp_context.h"
+#include "draw/draw_context.h"
#define NUM_CHANNELS 4
float dx;
float dy;
float oneoverarea;
+ boolean frontfacing;
const float (*v1)[4];
const float (*v2)[4];
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:
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;
#include "lp_state_setup.h"
#include "lp_context.h"
#include "tgsi/tgsi_scan.h"
+#include "draw/draw_context.h"
#define NUM_CHANNELS 4
float (*a0)[4];
float (*dadx)[4];
float (*dady)[4];
+
+ boolean frontfacing;
};
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:
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;
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;
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;
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);
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);
{
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;
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);