From 1865f341d8f45b389061fc08d2da90b7aa8a6099 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 6 Jan 2012 12:23:00 +0000 Subject: [PATCH] draw: clipdistance support (v2) Add support for using the clipdistance instead of clip plane. Passes all piglit clipdistance tests. v2: fixup some comments from Brian in review. Signed-off-by: Dave Airlie --- src/gallium/auxiliary/draw/draw_cliptest_tmp.h | 30 ++++++++++++++++-- src/gallium/auxiliary/draw/draw_context.c | 6 ++++ src/gallium/auxiliary/draw/draw_pipe_clip.c | 42 ++++++++++++++++++++------ src/gallium/auxiliary/draw/draw_private.h | 5 +-- src/gallium/auxiliary/draw/draw_pt_post_vs.c | 4 +-- src/gallium/auxiliary/draw/draw_vs.c | 7 +++++ src/gallium/auxiliary/draw/draw_vs.h | 2 +- 7 files changed, 79 insertions(+), 17 deletions(-) diff --git a/src/gallium/auxiliary/draw/draw_cliptest_tmp.h b/src/gallium/auxiliary/draw/draw_cliptest_tmp.h index 7dba49b2870..bff266b8f98 100644 --- a/src/gallium/auxiliary/draw/draw_cliptest_tmp.h +++ b/src/gallium/auxiliary/draw/draw_cliptest_tmp.h @@ -36,12 +36,19 @@ static boolean TAG(do_cliptest)( struct pt_post_vs *pvs, /* const */ float (*plane)[4] = pvs->draw->plane; const unsigned pos = draw_current_shader_position_output(pvs->draw); const unsigned cv = draw_current_shader_clipvertex_output(pvs->draw); + unsigned cd[2]; const unsigned ef = pvs->draw->vs.edgeflag_output; const unsigned ucp_enable = pvs->draw->rasterizer->clip_plane_enable; const unsigned flags = (FLAGS); unsigned need_pipeline = 0; unsigned j; unsigned i; + bool have_cd = false; + cd[0] = draw_current_shader_clipdistance_output(pvs->draw, 0); + cd[1] = draw_current_shader_clipdistance_output(pvs->draw, 1); + + if (cd[0] != pos || cd[1] != pos) + have_cd = true; for (j = 0; j < info->count; j++) { float *position = out->data[pos]; @@ -89,14 +96,31 @@ static boolean TAG(do_cliptest)( struct pt_post_vs *pvs, if (flags & DO_CLIP_USER) { unsigned ucp_mask = ucp_enable; - + int num_written_clipdistance = pvs->draw->vs.vertex_shader->info.num_written_clipdistance; while (ucp_mask) { unsigned plane_idx = ffs(ucp_mask)-1; ucp_mask &= ~(1 << plane_idx); plane_idx += 6; - if (dot4(clipvertex, plane[plane_idx]) < 0) { - mask |= 1 << plane_idx; + /* + * for user clipping check if we have a clip distance output + * and the shader has written to it, otherwise use clipvertex + * to decide when the plane is clipping. + */ + if (have_cd && num_written_clipdistance) { + float clipdist; + i = plane_idx - 6; + out->have_clipdist = 1; + /* first four clip distance in first vector etc. */ + if (i < 4) + clipdist = out->data[cd[0]][i]; + else + clipdist = out->data[cd[1]][i-4]; + if (clipdist < 0) + mask |= 1 << plane_idx; + } else { + if (dot4(clipvertex, plane[plane_idx]) < 0) + mask |= 1 << plane_idx; } } } diff --git a/src/gallium/auxiliary/draw/draw_context.c b/src/gallium/auxiliary/draw/draw_context.c index 6d7075e5452..7e554dcbb00 100644 --- a/src/gallium/auxiliary/draw/draw_context.c +++ b/src/gallium/auxiliary/draw/draw_context.c @@ -701,6 +701,12 @@ draw_current_shader_clipvertex_output(const struct draw_context *draw) return draw->vs.clipvertex_output; } +uint +draw_current_shader_clipdistance_output(const struct draw_context *draw, int index) +{ + return draw->vs.clipdistance_output[index]; +} + /** * Return a pointer/handle for a driver/CSO rasterizer object which * disabled culling, stippling, unfilled tris, etc. diff --git a/src/gallium/auxiliary/draw/draw_pipe_clip.c b/src/gallium/auxiliary/draw/draw_pipe_clip.c index fbc8f675129..f7019725fdf 100644 --- a/src/gallium/auxiliary/draw/draw_pipe_clip.c +++ b/src/gallium/auxiliary/draw/draw_pipe_clip.c @@ -119,13 +119,17 @@ static void interp( const struct clip_stage *clip, const unsigned nr_attrs = draw_current_shader_outputs(clip->stage.draw); 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 clip_dist[2]; unsigned j; + clip_dist[0] = draw_current_shader_clipdistance_output(clip->stage.draw, 0); + clip_dist[1] = draw_current_shader_clipdistance_output(clip->stage.draw, 1); + /* Vertex header. */ dst->clipmask = 0; dst->edgeflag = 0; /* will get overwritten later */ - dst->pad = 0; + dst->have_clipdist = in->have_clipdist; dst->vertex_id = UNDEFINED_VERTEX_ID; /* Interpolate the clip-space coords. @@ -241,6 +245,29 @@ dot4(const float *a, const float *b) a[3] * b[3]); } +/* + * this function extracts the clip distance for the current plane, + * it first checks if the shader provided a clip distance, otherwise + * it works out the value using the clipvertex + */ +static INLINE float getclipdist(const struct clip_stage *clipper, + struct vertex_header *vert, + int plane_idx) +{ + const float *plane; + float dp; + if (vert->have_clipdist && plane_idx >= 6) { + /* pick the correct clipdistance element from the output vectors */ + int _idx = plane_idx - 6; + int cdi = _idx >= 4; + int vidx = cdi ? _idx - 4 : _idx; + dp = vert->data[draw_current_shader_clipdistance_output(clipper->stage.draw, cdi)][vidx]; + } else { + plane = clipper->plane[plane_idx]; + dp = dot4(vert->clip, plane); + } + return dp; +} /* Clip a triangle against the viewport and user clip planes. */ @@ -281,12 +308,12 @@ do_clip_tri( struct draw_stage *stage, while (clipmask && n >= 3) { const unsigned plane_idx = ffs(clipmask)-1; const boolean is_user_clip_plane = plane_idx >= 6; - const float *plane = clipper->plane[plane_idx]; struct vertex_header *vert_prev = inlist[0]; boolean *edge_prev = &inEdges[0]; - float dp_prev = dot4( vert_prev->clip, plane ); + float dp_prev; unsigned outcount = 0; + dp_prev = getclipdist(clipper, vert_prev, plane_idx); clipmask &= ~(1<clip, plane ); + float dp = getclipdist(clipper, vert, plane_idx); if (!IS_NEGATIVE(dp_prev)) { assert(outcount < MAX_CLIPPED_VERTICES); @@ -421,17 +448,14 @@ do_clip_line( struct draw_stage *stage, const struct clip_stage *clipper = clip_stage( stage ); struct vertex_header *v0 = header->v[0]; struct vertex_header *v1 = header->v[1]; - const float *pos0 = v0->clip; - const float *pos1 = v1->clip; float t0 = 0.0F; float t1 = 0.0F; struct prim_header newprim; while (clipmask) { const unsigned plane_idx = ffs(clipmask)-1; - const float *plane = clipper->plane[plane_idx]; - const float dp0 = dot4( pos0, plane ); - const float dp1 = dot4( pos1, plane ); + const float dp0 = getclipdist(clipper, v0, plane_idx); + const float dp1 = getclipdist(clipper, v1, plane_idx); if (dp1 < 0.0F) { float t = dp1 / (dp1 - dp0); diff --git a/src/gallium/auxiliary/draw/draw_private.h b/src/gallium/auxiliary/draw/draw_private.h index aa9b602a353..31beb4b98e3 100644 --- a/src/gallium/auxiliary/draw/draw_private.h +++ b/src/gallium/auxiliary/draw/draw_private.h @@ -72,7 +72,7 @@ struct tgsi_sampler; struct vertex_header { unsigned clipmask:DRAW_TOTAL_CLIP_PLANES; unsigned edgeflag:1; - unsigned pad:1; + unsigned have_clipdist:1; unsigned vertex_id:16; float clip[4]; @@ -232,7 +232,7 @@ struct draw_context uint position_output; uint edgeflag_output; uint clipvertex_output; - + uint clipdistance_output[2]; /** TGSI program interpreter runtime state */ struct tgsi_exec_machine *machine; @@ -381,6 +381,7 @@ void draw_gs_destroy( struct draw_context *draw ); uint draw_current_shader_outputs(const struct draw_context *draw); uint draw_current_shader_position_output(const struct draw_context *draw); uint draw_current_shader_clipvertex_output(const struct draw_context *draw); +uint draw_current_shader_clipdistance_output(const struct draw_context *draw, int index); int draw_alloc_extra_vertex_attrib(struct draw_context *draw, uint semantic_name, uint semantic_index); void draw_remove_extra_vertex_attribs(struct draw_context *draw); diff --git a/src/gallium/auxiliary/draw/draw_pt_post_vs.c b/src/gallium/auxiliary/draw/draw_pt_post_vs.c index a8d65fd5d7b..a83bb59a748 100644 --- a/src/gallium/auxiliary/draw/draw_pt_post_vs.c +++ b/src/gallium/auxiliary/draw/draw_pt_post_vs.c @@ -31,7 +31,7 @@ #include "draw/draw_context.h" #include "draw/draw_private.h" #include "draw/draw_pt.h" - +#include "draw/draw_vs.h" #define DO_CLIP_XY 0x1 #define DO_CLIP_FULL_Z 0x2 @@ -56,7 +56,7 @@ initialize_vertex_header(struct vertex_header *header) { header->clipmask = 0; header->edgeflag = 1; - header->pad = 0; + header->have_clipdist = 0; header->vertex_id = UNDEFINED_VERTEX_ID; } diff --git a/src/gallium/auxiliary/draw/draw_vs.c b/src/gallium/auxiliary/draw/draw_vs.c index 150653c669a..56c4f882cae 100644 --- a/src/gallium/auxiliary/draw/draw_vs.c +++ b/src/gallium/auxiliary/draw/draw_vs.c @@ -132,6 +132,11 @@ draw_create_vertex_shader(struct draw_context *draw, vs->info.output_semantic_index[i] == 0) { found_clipvertex = TRUE; vs->clipvertex_output = i; + } else if (vs->info.output_semantic_name[i] == TGSI_SEMANTIC_CLIPDIST) { + if (vs->info.output_semantic_index[i] == 0) + vs->clipdistance_output[0] = i; + else + vs->clipdistance_output[1] = i; } } if (!found_clipvertex) @@ -156,6 +161,8 @@ draw_bind_vertex_shader(struct draw_context *draw, draw->vs.position_output = dvs->position_output; draw->vs.edgeflag_output = dvs->edgeflag_output; draw->vs.clipvertex_output = dvs->clipvertex_output; + draw->vs.clipdistance_output[0] = dvs->clipdistance_output[0]; + draw->vs.clipdistance_output[1] = dvs->clipdistance_output[1]; dvs->prepare( dvs, draw ); } else { diff --git a/src/gallium/auxiliary/draw/draw_vs.h b/src/gallium/auxiliary/draw/draw_vs.h index a3b90faa24b..8a440911af7 100644 --- a/src/gallium/auxiliary/draw/draw_vs.h +++ b/src/gallium/auxiliary/draw/draw_vs.h @@ -112,7 +112,7 @@ struct draw_vertex_shader { unsigned position_output; unsigned edgeflag_output; unsigned clipvertex_output; - + unsigned clipdistance_output[2]; /* Extracted from shader: */ const float (*immediates)[4]; -- 2.11.0