Store clipping distance for user clip planes as part of vertex processing
authorIan Romanick <ian.d.romanick@intel.com>
Fri, 9 Oct 2009 00:28:02 +0000 (17:28 -0700)
committerIan Romanick <ian.d.romanick@intel.com>
Tue, 13 Oct 2009 22:15:20 +0000 (15:15 -0700)
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@intel.com>
Reviewed-by: Brian Paul <brianp@vmware.com>
src/mesa/tnl/t_context.h
src/mesa/tnl/t_vb_cliptmp.h
src/mesa/tnl/t_vb_program.c
src/mesa/tnl/t_vb_vertex.c

index 6137c2d..ca4edcf 100644 (file)
@@ -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 */
index 618b8b3..0d2183a 100644 (file)
@@ -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
index c10a276..5fb83c2 100644 (file)
@@ -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;
    }
index 4734754..2a61ff1 100644 (file)
@@ -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;