draw: clipdistance support (v2)
authorDave Airlie <airlied@redhat.com>
Fri, 6 Jan 2012 12:23:00 +0000 (12:23 +0000)
committerDave Airlie <airlied@redhat.com>
Wed, 11 Jan 2012 08:20:11 +0000 (08:20 +0000)
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 <airlied@redhat.com>
src/gallium/auxiliary/draw/draw_cliptest_tmp.h
src/gallium/auxiliary/draw/draw_context.c
src/gallium/auxiliary/draw/draw_pipe_clip.c
src/gallium/auxiliary/draw/draw_private.h
src/gallium/auxiliary/draw/draw_pt_post_vs.c
src/gallium/auxiliary/draw/draw_vs.c
src/gallium/auxiliary/draw/draw_vs.h

index 7dba49b28706d4a35acb8e6d15de35e07fafc0a3..bff266b8f98de6f61c34827938decd269f3ff528 100644 (file)
@@ -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;
                }
             }
          }
index 6d7075e545246ac661a81d2b779232b28cb546a4..7e554dcbb00380ff03afb2c92fd7afcebd7231dc 100644 (file)
@@ -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.
index fbc8f6751298fabad8a6bca6b9b1b9f0592bf3b6..f7019725fdf3f59414c71013daf8003be139ec32 100644 (file)
@@ -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<<plane_idx);
 
       assert(n < MAX_CLIPPED_VERTICES);
@@ -299,7 +326,7 @@ do_clip_tri( struct draw_stage *stage,
         struct vertex_header *vert = inlist[i];
          boolean *edge = &inEdges[i];
 
-        float dp = dot4( vert->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);
index aa9b602a353125dd34ac88823a60a50e4ffeae54..31beb4b98e3a5b6e3d8a53299c1a00c4e4afff50 100644 (file)
@@ -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);
index a8d65fd5d7b60df2cf87f6ff080bfd14ba870604..a83bb59a748433bf15bc5a8634e1933b2b5e4d00 100644 (file)
@@ -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;
 }
 
index 150653c669ac049446a31c8fca49ccf7ede6c02a..56c4f882cae329037b9bd6cd44aa60821d915801 100644 (file)
@@ -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 {
index a3b90faa24b505b06cab6bd5f7758790328b1075..8a440911af7155e78b7e7be907d1b05328fa7fc5 100644 (file)
@@ -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];