summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZack Rusin <[email protected]>2013-09-19 13:38:12 -0400
committerZack Rusin <[email protected]>2013-09-25 19:42:22 -0400
commitd83ef680e2c6d11c446aae16a65445f12984fb85 (patch)
tree8fab38e9c4749db5cfcec33ce5af496712c7740f
parent60c448faea54a56047202204c486b8d399429909 (diff)
draw/clip: don't emit so many empty triangles
Compress empty triangles (don't emit more than one in a row) and never emit empty triangles if we already generated a triangle covering a non-null area. We can't skip all null-triangles because c_primitives expects ones that were generated from vertices exactly at the clipping-plane, to be emitted. Signed-off-by: Zack Rusin <[email protected]> Reviewed-by: José Fonseca <[email protected]> Reviewed-by: Roland Scheidegger <[email protected]>
-rw-r--r--src/gallium/auxiliary/draw/draw_pipe_clip.c39
1 files changed, 39 insertions, 0 deletions
diff --git a/src/gallium/auxiliary/draw/draw_pipe_clip.c b/src/gallium/auxiliary/draw/draw_pipe_clip.c
index 0f90bfdff08..dbb67575843 100644
--- a/src/gallium/auxiliary/draw/draw_pipe_clip.c
+++ b/src/gallium/auxiliary/draw/draw_pipe_clip.c
@@ -209,6 +209,29 @@ static void interp( const struct clip_stage *clip,
}
}
+/**
+ * Checks whether the specifed triangle is empty and if it is returns
+ * true, otherwise returns false.
+ * Triangle is considered null/empty if it's area is qual to zero.
+ */
+static INLINE boolean
+is_tri_null(struct draw_context *draw, const struct prim_header *header)
+{
+ const unsigned pos_attr = draw_current_shader_position_output(draw);
+ float x1 = header->v[1]->data[pos_attr][0] - header->v[0]->data[pos_attr][0];
+ float y1 = header->v[1]->data[pos_attr][1] - header->v[0]->data[pos_attr][1];
+ float z1 = header->v[1]->data[pos_attr][2] - header->v[0]->data[pos_attr][2];
+
+ float x2 = header->v[2]->data[pos_attr][0] - header->v[0]->data[pos_attr][0];
+ float y2 = header->v[2]->data[pos_attr][1] - header->v[0]->data[pos_attr][1];
+ float z2 = header->v[2]->data[pos_attr][2] - header->v[0]->data[pos_attr][2];
+
+ float vx = y1 * z2 - z1 * y2;
+ float vy = x1 * z2 - z1 * x2;
+ float vz = x1 * y2 - y1 * x2;
+
+ return (vx*vx + vy*vy + vz*vz) == 0.f;
+}
/**
* Emit a post-clip polygon to the next pipeline stage. The polygon
@@ -223,6 +246,8 @@ static void emit_poly( struct draw_stage *stage,
struct prim_header header;
unsigned i;
ushort edge_first, edge_middle, edge_last;
+ boolean last_tri_was_null = FALSE;
+ boolean tri_was_not_null = FALSE;
if (stage->draw->rasterizer->flatshade_first) {
edge_first = DRAW_PIPE_EDGE_FLAG_0;
@@ -244,6 +269,7 @@ static void emit_poly( struct draw_stage *stage,
header.pad = 0;
for (i = 2; i < n; i++, header.flags = edge_middle) {
+ boolean tri_null;
/* order the triangle verts to respect the provoking vertex mode */
if (stage->draw->rasterizer->flatshade_first) {
header.v[0] = inlist[0]; /* the provoking vertex */
@@ -256,6 +282,19 @@ static void emit_poly( struct draw_stage *stage,
header.v[2] = inlist[0]; /* the provoking vertex */
}
+ tri_null = is_tri_null(stage->draw, &header);
+ /* If we generated a triangle with an area, aka. non-null triangle,
+ * or if the previous triangle was also null then skip all subsequent
+ * null triangles */
+ if ((tri_was_not_null && tri_null) || (last_tri_was_null && tri_null)) {
+ last_tri_was_null = tri_null;
+ continue;
+ }
+ last_tri_was_null = tri_null;
+ if (!tri_null) {
+ tri_was_not_null = TRUE;
+ }
+
if (!edgeflags[i-1]) {
header.flags &= ~edge_middle;
}