summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOlivier Galibert <[email protected]>2012-06-19 20:51:19 +0200
committerBrian Paul <[email protected]>2012-06-19 14:40:44 -0600
commit4625a9b1adf7a30c56e2bbeb41573fbba4465851 (patch)
tree8cd525253000a4f8a8328ce6b54a22a805ae31b5
parentcfc5b3094163bc5c945594903d90f21873bb5d66 (diff)
draw: fix flat shading and screen-space linear interpolation in clipper
This includes: - picking up correctly which attributes are flatshaded and which are noperspective - copying the flatshaded attributes when needed, including the non-built-in ones - correctly interpolating the noperspective attributes in screen-space instead than in a 3d-correct fashion. Signed-off-by: Olivier Galibert <[email protected]> Reviewed-by: Brian Paul <[email protected]>
-rw-r--r--src/gallium/auxiliary/draw/draw_pipe_clip.c144
1 files changed, 113 insertions, 31 deletions
diff --git a/src/gallium/auxiliary/draw/draw_pipe_clip.c b/src/gallium/auxiliary/draw/draw_pipe_clip.c
index 4da4d653d99..2d36eb3ddca 100644
--- a/src/gallium/auxiliary/draw/draw_pipe_clip.c
+++ b/src/gallium/auxiliary/draw/draw_pipe_clip.c
@@ -39,6 +39,7 @@
#include "draw_vs.h"
#include "draw_pipe.h"
+#include "draw_fs.h"
#ifndef IS_NEGATIVE
@@ -56,11 +57,12 @@
struct clip_stage {
struct draw_stage stage; /**< base class */
- /* Basically duplicate some of the flatshading logic here:
- */
- boolean flat;
- uint num_color_attribs;
- uint color_attribs[4]; /* front/back primary/secondary colors */
+ /* List of the attributes to be flatshaded. */
+ uint num_flat_attribs;
+ uint flat_attribs[PIPE_MAX_SHADER_OUTPUTS];
+
+ /* Mask of attributes in noperspective mode */
+ boolean noperspective_attribs[PIPE_MAX_SHADER_OUTPUTS];
float (*plane)[4];
};
@@ -91,17 +93,16 @@ static void interp_attr( float dst[4],
/**
- * Copy front/back, primary/secondary colors from src vertex to dst vertex.
- * Used when flat shading.
+ * Copy flat shaded attributes src vertex to dst vertex.
*/
-static void copy_colors( struct draw_stage *stage,
- struct vertex_header *dst,
- const struct vertex_header *src )
+static void copy_flat( struct draw_stage *stage,
+ struct vertex_header *dst,
+ const struct vertex_header *src )
{
const struct clip_stage *clipper = clip_stage(stage);
uint i;
- for (i = 0; i < clipper->num_color_attribs; i++) {
- const uint attr = clipper->color_attribs[i];
+ for (i = 0; i < clipper->num_flat_attribs; i++) {
+ const uint attr = clipper->flat_attribs[i];
COPY_4FV(dst->data[attr], src->data[attr]);
}
}
@@ -120,6 +121,7 @@ static void interp( const struct clip_stage *clip,
const unsigned pos_attr = draw_current_shader_position_output(clip->stage.draw);
const unsigned clip_attr = draw_current_shader_clipvertex_output(clip->stage.draw);
unsigned j;
+ float t_nopersp;
/* Vertex header.
*/
@@ -148,12 +150,36 @@ static void interp( const struct clip_stage *clip,
dst->data[pos_attr][2] = pos[2] * oow * scale[2] + trans[2];
dst->data[pos_attr][3] = oow;
}
+
+ /**
+ * Compute the t in screen-space instead of 3d space to use
+ * for noperspective interpolation.
+ *
+ * The points can be aligned with the X axis, so in that case try
+ * the Y. When both points are at the same screen position, we can
+ * pick whatever value (the interpolated point won't be in front
+ * anyway), so just use the 3d t.
+ */
+ {
+ int k;
+ t_nopersp = t;
+ for (k = 0; k < 2; k++)
+ if (in->data[pos_attr][k] != out->data[pos_attr][k]) {
+ t_nopersp = (dst->data[pos_attr][k] - out->data[pos_attr][k]) /
+ (in->data[pos_attr][k] - out->data[pos_attr][k]);
+ break;
+ }
+ }
/* Other attributes
*/
for (j = 0; j < nr_attrs; j++) {
- if (j != pos_attr && j != clip_attr)
- interp_attr(dst->data[j], t, in->data[j], out->data[j]);
+ if (j != pos_attr && j != clip_attr) {
+ if (clip->noperspective_attribs[j])
+ interp_attr(dst->data[j], t_nopersp, in->data[j], out->data[j]);
+ else
+ interp_attr(dst->data[j], t, in->data[j], out->data[j]);
+ }
}
}
@@ -406,14 +432,14 @@ do_clip_tri( struct draw_stage *stage,
/* If flat-shading, copy provoking vertex color to polygon vertex[0]
*/
if (n >= 3) {
- if (clipper->flat) {
+ if (clipper->num_flat_attribs) {
if (stage->draw->rasterizer->flatshade_first) {
if (inlist[0] != header->v[0]) {
assert(tmpnr < MAX_CLIPPED_VERTICES + 1);
if (tmpnr >= MAX_CLIPPED_VERTICES + 1)
return;
inlist[0] = dup_vert(stage, inlist[0], tmpnr++);
- copy_colors(stage, inlist[0], header->v[0]);
+ copy_flat(stage, inlist[0], header->v[0]);
}
}
else {
@@ -422,7 +448,7 @@ do_clip_tri( struct draw_stage *stage,
if (tmpnr >= MAX_CLIPPED_VERTICES + 1)
return;
inlist[0] = dup_vert(stage, inlist[0], tmpnr++);
- copy_colors(stage, inlist[0], header->v[2]);
+ copy_flat(stage, inlist[0], header->v[2]);
}
}
}
@@ -471,10 +497,7 @@ do_clip_line( struct draw_stage *stage,
if (v0->clipmask) {
interp( clipper, stage->tmp[0], t0, v0, v1 );
-
- if (clipper->flat)
- copy_colors(stage, stage->tmp[0], v0);
-
+ copy_flat(stage, stage->tmp[0], v0);
newprim.v[0] = stage->tmp[0];
}
else {
@@ -548,20 +571,79 @@ static void
clip_init_state( struct draw_stage *stage )
{
struct clip_stage *clipper = clip_stage( stage );
+ const struct draw_vertex_shader *vs = stage->draw->vs.vertex_shader;
+ const struct draw_fragment_shader *fs = stage->draw->fs.fragment_shader;
+ uint i;
- clipper->flat = stage->draw->rasterizer->flatshade ? TRUE : FALSE;
+ /* We need to know for each attribute what kind of interpolation is
+ * done on it (flat, smooth or noperspective). But the information
+ * is not directly accessible for outputs, only for inputs. So we
+ * have to match semantic name and index between the VS (or GS/ES)
+ * outputs and the FS inputs to get to the interpolation mode.
+ *
+ * The only hitch is with gl_FrontColor/gl_BackColor which map to
+ * gl_Color, and their Secondary versions. First there are (up to)
+ * two outputs for one input, so we tuck the information in a
+ * specific array. Second if they don't have qualifiers, the
+ * default value has to be picked from the global shade mode.
+ */
- if (clipper->flat) {
- const struct draw_vertex_shader *vs = stage->draw->vs.vertex_shader;
- uint i;
+ /* First pick up the interpolation mode for
+ * gl_Color/gl_SecondaryColor, with the correct default.
+ */
+ int indexed_interp[2];
+ indexed_interp[0] = indexed_interp[1] = stage->draw->rasterizer->flatshade ?
+ TGSI_INTERPOLATE_CONSTANT : TGSI_INTERPOLATE_PERSPECTIVE;
+
+ for (i = 0; i < fs->info.num_inputs; i++) {
+ if (fs->info.input_semantic_name[i] == TGSI_SEMANTIC_COLOR) {
+ if (fs->info.input_interpolate[i] != TGSI_INTERPOLATE_COLOR)
+ indexed_interp[fs->info.input_semantic_index[i]] = fs->info.input_interpolate[i];
+ }
+ }
- clipper->num_color_attribs = 0;
- for (i = 0; i < vs->info.num_outputs; i++) {
- if (vs->info.output_semantic_name[i] == TGSI_SEMANTIC_COLOR ||
- vs->info.output_semantic_name[i] == TGSI_SEMANTIC_BCOLOR) {
- clipper->color_attribs[clipper->num_color_attribs++] = i;
- }
+ /* Then resolve the interpolation mode for every output attribute.
+ *
+ * Given how the rest of the code, the most efficient way is to
+ * have a vector of flat-mode attributes, and a mask for
+ * noperspective attributes.
+ */
+
+ clipper->num_flat_attribs = 0;
+ memset(clipper->noperspective_attribs, 0, sizeof(clipper->noperspective_attribs));
+ for (i = 0; i < vs->info.num_outputs; i++) {
+ /* Find the interpolation mode for a specific attribute
+ */
+ int interp;
+
+ /* If it's gl_{Front,Back}{,Secondary}Color, pick up the mode
+ * from the array we've filled before. */
+ if (vs->info.output_semantic_name[i] == TGSI_SEMANTIC_COLOR ||
+ vs->info.output_semantic_name[i] == TGSI_SEMANTIC_BCOLOR) {
+ interp = indexed_interp[vs->info.output_semantic_index[i]];
+ } else {
+ /* Otherwise, search in the FS inputs, with a decent default
+ * if we don't find it.
+ */
+ uint j;
+ interp = TGSI_INTERPOLATE_PERSPECTIVE;
+ for (j = 0; j < fs->info.num_inputs; j++) {
+ if (vs->info.output_semantic_name[i] == fs->info.input_semantic_name[j] &&
+ vs->info.output_semantic_index[i] == fs->info.input_semantic_index[j]) {
+ interp = fs->info.input_interpolate[j];
+ break;
+ }
+ }
}
+
+ /* If it's flat, add it to the flat vector. Otherwise update
+ * the noperspective mask.
+ */
+ if (interp == TGSI_INTERPOLATE_CONSTANT) {
+ clipper->flat_attribs[clipper->num_flat_attribs] = i;
+ clipper->num_flat_attribs++;
+ } else
+ clipper->noperspective_attribs[i] = interp == TGSI_INTERPOLATE_LINEAR;
}
stage->tri = clip_tri;