From f058b25881e08c9d89a33345e5c84e1357396932 Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Thu, 8 Oct 2009 17:28:02 -0700 Subject: [PATCH] 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 Reviewed-by: Brian Paul --- 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 6137c2d2fe5..ca4edcfcb9b 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 618b8b31304..0d2183a9e67 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 c10a27614ff..5fb83c2b01b 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 4734754ea40..2a61ff11779 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; -- 2.30.2