Mesa (master): Store clipping distance for user clip planes as part of vertex processing

Ian Romanick idr at kemper.freedesktop.org
Tue Oct 13 22:19:54 UTC 2009


Module: Mesa
Branch: master
Commit: f058b25881e08c9d89a33345e5c84e1357396932
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=f058b25881e08c9d89a33345e5c84e1357396932

Author: Ian Romanick <ian.d.romanick at intel.com>
Date:   Thu Oct  8 17:28:02 2009 -0700

Store clipping distance for user clip planes as part of vertex processing

Once the clipping distance is calculated and stored per vertex, the
distances can be re-used when clipping is actually performed.  This
doesn't have any immediate benefit, but it paves the way for
implementing gl_ClipDistance in vertex shaders and result.clip[] in
vertex programs.

This has not produces any oglconform regressions on my G31 system
which uses software TNL.

Signed-off-by: Ian Romanick <ian.d.romanick at intel.com>
Reviewed-by: Brian Paul <brianp at vmware.com>

---

 src/mesa/tnl/t_context.h    |    1 +
 src/mesa/tnl/t_vb_cliptmp.h |  103 ++++++++++++++++++++++++++++++++++++------
 src/mesa/tnl/t_vb_program.c |   15 ++++++
 src/mesa/tnl/t_vb_vertex.c  |   31 ++++++++++++-
 4 files changed, 132 insertions(+), 18 deletions(-)

diff --git a/src/mesa/tnl/t_context.h b/src/mesa/tnl/t_context.h
index 6137c2d..ca4edcf 100644
--- a/src/mesa/tnl/t_context.h
+++ b/src/mesa/tnl/t_context.h
@@ -207,6 +207,7 @@ struct vertex_buffer
    GLvector4f  *EyePtr;		                /* _TNL_BIT_POS */
    GLvector4f  *ClipPtr;	                /* _TNL_BIT_POS */
    GLvector4f  *NdcPtr;                         /* _TNL_BIT_POS */
+   GLfloat     *ClipDistancePtr[MAX_CLIP_PLANES]; /* _TNL_BIT_POS */
    GLubyte     ClipOrMask;	                /* _TNL_BIT_POS */
    GLubyte     ClipAndMask;	                /* _TNL_BIT_POS */
    GLubyte     *ClipMask;		        /* _TNL_BIT_POS */
diff --git a/src/mesa/tnl/t_vb_cliptmp.h b/src/mesa/tnl/t_vb_cliptmp.h
index 618b8b3..0d2183a 100644
--- a/src/mesa/tnl/t_vb_cliptmp.h
+++ b/src/mesa/tnl/t_vb_cliptmp.h
@@ -80,6 +80,58 @@ do {									\
 } while (0)
 
 
+#define POLY_USERCLIP(PLANE)						\
+do {									\
+   if (mask & CLIP_USER_BIT) {						\
+      GLuint idxPrev = inlist[0];					\
+      GLfloat dpPrev = VB->ClipDistancePtr[PLANE][idxPrev];		\
+      GLuint outcount = 0;						\
+      GLuint i;								\
+									\
+      inlist[n] = inlist[0]; /* prevent rotation of vertices */		\
+      for (i = 1; i <= n; i++) {					\
+	 GLuint idx = inlist[i];					\
+	 GLfloat dp = VB->ClipDistancePtr[PLANE][idx];			\
+									\
+	 if (!IS_NEGATIVE(dpPrev)) {					\
+	    outlist[outcount++] = idxPrev;				\
+	 }								\
+									\
+	 if (DIFFERENT_SIGNS(dp, dpPrev)) {				\
+	    if (IS_NEGATIVE(dp)) {					\
+	       /* Going out of bounds.  Avoid division by zero as we	\
+		* know dp != dpPrev from DIFFERENT_SIGNS, above.	\
+		*/							\
+	       GLfloat t = dp / (dp - dpPrev);				\
+               INTERP_4F( t, coord[newvert], coord[idx], coord[idxPrev]); \
+	       interp( ctx, t, newvert, idx, idxPrev, GL_TRUE );	\
+	    } else {							\
+	       /* Coming back in.					\
+		*/							\
+	       GLfloat t = dpPrev / (dpPrev - dp);			\
+               INTERP_4F( t, coord[newvert], coord[idxPrev], coord[idx]); \
+	       interp( ctx, t, newvert, idxPrev, idx, GL_FALSE );	\
+	    }								\
+            outlist[outcount++] = newvert++;				\
+	 }								\
+									\
+	 idxPrev = idx;							\
+	 dpPrev = dp;							\
+      }									\
+									\
+      if (outcount < 3)							\
+	 return;							\
+									\
+      {									\
+	 GLuint *tmp = inlist;						\
+	 inlist = outlist;						\
+	 outlist = tmp;							\
+	 n = outcount;							\
+      }									\
+   }									\
+} while (0)
+
+
 #define LINE_CLIP(PLANE_BIT, A, B, C, D )				\
 do {									\
    if (mask & PLANE_BIT) {						\
@@ -111,6 +163,37 @@ do {									\
 } while (0)
 
 
+#define LINE_USERCLIP(PLANE)						\
+do {									\
+   if (mask & CLIP_USER_BIT) {						\
+      const GLfloat dp0 = VB->ClipDistancePtr[PLANE][v0];		\
+      const GLfloat dp1 = VB->ClipDistancePtr[PLANE][v1];		\
+      const GLboolean neg_dp0 = IS_NEGATIVE(dp0);			\
+      const GLboolean neg_dp1 = IS_NEGATIVE(dp1);			\
+									\
+      /* For regular clipping, we know from the clipmask that one	\
+       * (or both) of these must be negative (otherwise we wouldn't	\
+       * be here).							\
+       * For userclip, there is only a single bit for all active	\
+       * planes, so we can end up here when there is nothing to do,	\
+       * hence the second IS_NEGATIVE() test:				\
+       */								\
+      if (neg_dp0 && neg_dp1)						\
+         return; /* both vertices outside clip plane: discard */	\
+									\
+      if (neg_dp1) {							\
+	 GLfloat t = dp1 / (dp1 - dp0);					\
+	 if (t > t1) t1 = t;						\
+      } else if (neg_dp0) {						\
+	 GLfloat t = dp0 / (dp0 - dp1);					\
+	 if (t > t0) t0 = t;						\
+      }									\
+      if (t0 + t1 >= 1.0)						\
+	 return; /* discard */						\
+   }									\
+} while (0)
+
+
 
 /* Clip a line against the viewport and user clip planes.
  */
@@ -139,11 +222,7 @@ TAG(clip_line)( GLcontext *ctx, GLuint v0, GLuint v1, GLubyte mask )
    if (mask & CLIP_USER_BIT) {
       for (p = 0; p < ctx->Const.MaxClipPlanes; p++) {
 	 if (ctx->Transform.ClipPlanesEnabled & (1 << p)) {
-            const GLfloat a = ctx->Transform._ClipUserPlane[p][0];
-            const GLfloat b = ctx->Transform._ClipUserPlane[p][1];
-            const GLfloat c = ctx->Transform._ClipUserPlane[p][2];
-            const GLfloat d = ctx->Transform._ClipUserPlane[p][3];
-	    LINE_CLIP( CLIP_USER_BIT, a, b, c, d );
+	    LINE_USERCLIP(p);
 	 }
       }
    }
@@ -228,11 +307,7 @@ TAG(clip_tri)( GLcontext *ctx, GLuint v0, GLuint v1, GLuint v2, GLubyte mask )
    if (mask & CLIP_USER_BIT) {
       for (p = 0; p < ctx->Const.MaxClipPlanes; p++) {
          if (ctx->Transform.ClipPlanesEnabled & (1 << p)) {
-            const GLfloat a = ctx->Transform._ClipUserPlane[p][0];
-            const GLfloat b = ctx->Transform._ClipUserPlane[p][1];
-            const GLfloat c = ctx->Transform._ClipUserPlane[p][2];
-            const GLfloat d = ctx->Transform._ClipUserPlane[p][3];
-            POLY_CLIP( CLIP_USER_BIT, a, b, c, d );
+            POLY_USERCLIP(p);
          }
       }
    }
@@ -291,11 +366,7 @@ TAG(clip_quad)( GLcontext *ctx, GLuint v0, GLuint v1, GLuint v2, GLuint v3,
    if (mask & CLIP_USER_BIT) {
       for (p = 0; p < ctx->Const.MaxClipPlanes; p++) {
 	 if (ctx->Transform.ClipPlanesEnabled & (1 << p)) {
-            const GLfloat a = ctx->Transform._ClipUserPlane[p][0];
-            const GLfloat b = ctx->Transform._ClipUserPlane[p][1];
-            const GLfloat c = ctx->Transform._ClipUserPlane[p][2];
-            const GLfloat d = ctx->Transform._ClipUserPlane[p][3];
-	    POLY_CLIP( CLIP_USER_BIT, a, b, c, d );
+	    POLY_USERCLIP(p);
 	 }
       }
    }
@@ -317,4 +388,6 @@ TAG(clip_quad)( GLcontext *ctx, GLuint v0, GLuint v1, GLuint v2, GLuint v3,
 #undef SIZE
 #undef TAG
 #undef POLY_CLIP
+#undef POLY_USERCLIP
 #undef LINE_CLIP
+#undef LINE_USERCLIP
diff --git a/src/mesa/tnl/t_vb_program.c b/src/mesa/tnl/t_vb_program.c
index c10a276..5fb83c2 100644
--- a/src/mesa/tnl/t_vb_program.c
+++ b/src/mesa/tnl/t_vb_program.c
@@ -66,6 +66,7 @@ struct vp_stage_data {
    GLvector4f results[VERT_RESULT_MAX];
 
    GLvector4f ndcCoords;              /**< normalized device coords */
+   GLfloat *clipdistance[MAX_CLIP_PLANES];
    GLubyte *clipmask;                 /**< clip flags */
    GLubyte ormask, andmask;           /**< for clipping */
 };
@@ -77,6 +78,7 @@ struct vp_stage_data {
 static void
 userclip( GLcontext *ctx,
           GLvector4f *clip,
+          GLfloat *clipdistance[MAX_CLIP_PLANES],
           GLubyte *clipmask,
           GLubyte *clipormask,
           GLubyte *clipandmask )
@@ -105,6 +107,8 @@ userclip( GLcontext *ctx,
 	       clipmask[i] |= CLIP_USER_BIT;
 	    }
 
+	    clipdistance[p][i] = dp;
+
 	    STRIDE_F(coord, stride);
 	 }
 
@@ -164,6 +168,7 @@ do_ndc_cliptest(GLcontext *ctx, struct vp_stage_data *store)
       ctx->VertexProgram.Current->IsPositionInvariant)) {
       userclip( ctx,
 		VB->ClipPtr,
+		store->clipdistance,
 		store->clipmask,
 		&store->ormask,
 		&store->andmask );
@@ -171,6 +176,9 @@ do_ndc_cliptest(GLcontext *ctx, struct vp_stage_data *store)
       if (store->andmask) {
 	 return GL_FALSE;
       }
+
+      memcpy(VB->ClipDistancePtr, store->clipdistance,
+	     sizeof(store->clipdistance));
    }
 
    VB->ClipAndMask = store->andmask;
@@ -514,6 +522,10 @@ init_vp(GLcontext *ctx, struct tnl_pipeline_stage *stage)
    _mesa_vector4f_alloc( &store->ndcCoords, 0, size, 32 );
    store->clipmask = (GLubyte *) ALIGN_MALLOC(sizeof(GLubyte)*size, 32 );
 
+   for (i = 0; i < MAX_CLIP_PLANES; i++)
+      store->clipdistance[i] =
+	 (GLfloat *) ALIGN_MALLOC(sizeof(GLfloat) * size, 32);
+
    return GL_TRUE;
 }
 
@@ -537,6 +549,9 @@ dtr(struct tnl_pipeline_stage *stage)
       _mesa_vector4f_free( &store->ndcCoords );
       ALIGN_FREE( store->clipmask );
 
+      for (i = 0; i < MAX_CLIP_PLANES; i++)
+	 ALIGN_FREE(store->clipdistance[i]);
+
       FREE( store );
       stage->privatePtr = NULL;
    }
diff --git a/src/mesa/tnl/t_vb_vertex.c b/src/mesa/tnl/t_vb_vertex.c
index 4734754..2a61ff1 100644
--- a/src/mesa/tnl/t_vb_vertex.c
+++ b/src/mesa/tnl/t_vb_vertex.c
@@ -44,6 +44,7 @@ struct vertex_stage_data {
    GLvector4f eye;
    GLvector4f clip;
    GLvector4f proj;
+   GLfloat *clipdistance[MAX_CLIP_PLANES];
    GLubyte *clipmask;
    GLubyte ormask;
    GLubyte andmask;
@@ -56,11 +57,12 @@ struct vertex_stage_data {
 
 /* This function implements cliptesting for user-defined clip planes.
  * The clipping of primitives to these planes is implemented in
- * t_render_clip.h.
+ * t_vp_cliptmp.h.
  */
 #define USER_CLIPTEST(NAME, SZ)					\
 static void NAME( GLcontext *ctx,				\
 		  GLvector4f *clip,				\
+		  GLfloat *clipdistances[MAX_CLIP_PLANES],	\
 		  GLubyte *clipmask,				\
 		  GLubyte *clipormask,				\
 		  GLubyte *clipandmask )			\
@@ -88,6 +90,8 @@ static void NAME( GLcontext *ctx,				\
 	       clipmask[i] |= CLIP_USER_BIT;			\
 	    }							\
 								\
+	    clipdistances[p][i] = dp;				\
+								\
 	    STRIDE_F(coord, stride);				\
 	 }							\
 								\
@@ -107,8 +111,9 @@ USER_CLIPTEST(userclip3, 3)
 USER_CLIPTEST(userclip4, 4)
 
 static void (*(usercliptab[5]))( GLcontext *,
-				 GLvector4f *, GLubyte *,
-				 GLubyte *, GLubyte * ) =
+				 GLvector4f *,
+				 GLfloat *[MAX_CLIP_PLANES],
+				 GLubyte *, GLubyte *, GLubyte * ) =
 {
    NULL,
    NULL,
@@ -214,12 +219,16 @@ static GLboolean run_vertex_stage( GLcontext *ctx,
    if (ctx->Transform.ClipPlanesEnabled) {
       usercliptab[VB->ClipPtr->size]( ctx,
 				      VB->ClipPtr,
+				      store->clipdistance,
 				      store->clipmask,
 				      &store->ormask,
 				      &store->andmask );
 
       if (store->andmask)
 	 return GL_FALSE;
+
+      memcpy(VB->ClipDistancePtr, store->clipdistance,
+	     sizeof(store->clipdistance));
    }
 
    VB->ClipAndMask = store->andmask;
@@ -236,6 +245,7 @@ static GLboolean init_vertex_stage( GLcontext *ctx,
    struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
    struct vertex_stage_data *store;
    GLuint size = VB->Size;
+   unsigned i;
 
    stage->privatePtr = CALLOC(sizeof(*store));
    store = VERTEX_STAGE_DATA(stage);
@@ -247,8 +257,17 @@ static GLboolean init_vertex_stage( GLcontext *ctx,
    _mesa_vector4f_alloc( &store->proj, 0, size, 32 );
 
    store->clipmask = (GLubyte *) ALIGN_MALLOC(sizeof(GLubyte)*size, 32 );
+   for (i = 0; i < MAX_CLIP_PLANES; i++)
+      store->clipdistance[i] =
+	 (GLfloat *) ALIGN_MALLOC(sizeof(GLfloat) * size, 32);
 
    if (!store->clipmask ||
+       !store->clipdistance[0] ||
+       !store->clipdistance[1] ||
+       !store->clipdistance[2] ||
+       !store->clipdistance[3] ||
+       !store->clipdistance[4] ||
+       !store->clipdistance[5] ||
        !store->eye.data ||
        !store->clip.data ||
        !store->proj.data)
@@ -262,10 +281,16 @@ static void dtr( struct tnl_pipeline_stage *stage )
    struct vertex_stage_data *store = VERTEX_STAGE_DATA(stage);
 
    if (store) {
+      unsigned i;
+
       _mesa_vector4f_free( &store->eye );
       _mesa_vector4f_free( &store->clip );
       _mesa_vector4f_free( &store->proj );
       ALIGN_FREE( store->clipmask );
+
+      for (i = 0; i < MAX_CLIP_PLANES; i++)
+	 ALIGN_FREE(store->clipdistance[i]);
+
       FREE(store);
       stage->privatePtr = NULL;
       stage->run = init_vertex_stage;




More information about the mesa-commit mailing list