• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /**************************************************************************
2   *
3   * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
4   * All Rights Reserved.
5   *
6   * Permission is hereby granted, free of charge, to any person obtaining a
7   * copy of this software and associated documentation files (the
8   * "Software"), to deal in the Software without restriction, including
9   * without limitation the rights to use, copy, modify, merge, publish,
10   * distribute, sub license, and/or sell copies of the Software, and to
11   * permit persons to whom the Software is furnished to do so, subject to
12   * the following conditions:
13   *
14   * The above copyright notice and this permission notice (including the
15   * next paragraph) shall be included in all copies or substantial portions
16   * of the Software.
17   *
18   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19   * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20   * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21   * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22   * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23   * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24   * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25   *
26   **************************************************************************/
27  
28  /**
29   * \brief  Clipping stage
30   *
31   * \author  Keith Whitwell <keith@tungstengraphics.com>
32   */
33  
34  
35  #include "util/u_memory.h"
36  #include "util/u_math.h"
37  
38  #include "pipe/p_shader_tokens.h"
39  
40  #include "draw_vs.h"
41  #include "draw_pipe.h"
42  #include "draw_fs.h"
43  
44  
45  #ifndef IS_NEGATIVE
46  #define IS_NEGATIVE(X) ((X) < 0.0)
47  #endif
48  
49  #ifndef DIFFERENT_SIGNS
50  #define DIFFERENT_SIGNS(x, y) ((x) * (y) <= 0.0F && (x) - (y) != 0.0F)
51  #endif
52  
53  #define MAX_CLIPPED_VERTICES ((2 * (6 + PIPE_MAX_CLIP_PLANES))+1)
54  
55  
56  
57  struct clip_stage {
58     struct draw_stage stage;      /**< base class */
59  
60     /* List of the attributes to be flatshaded. */
61     uint num_flat_attribs;
62     uint flat_attribs[PIPE_MAX_SHADER_OUTPUTS];
63  
64     /* Mask of attributes in noperspective mode */
65     boolean noperspective_attribs[PIPE_MAX_SHADER_OUTPUTS];
66  
67     float (*plane)[4];
68  };
69  
70  
71  /** Cast wrapper */
clip_stage(struct draw_stage * stage)72  static INLINE struct clip_stage *clip_stage( struct draw_stage *stage )
73  {
74     return (struct clip_stage *)stage;
75  }
76  
77  
78  #define LINTERP(T, OUT, IN) ((OUT) + (T) * ((IN) - (OUT)))
79  
80  
81  /* All attributes are float[4], so this is easy:
82   */
interp_attr(float dst[4],float t,const float in[4],const float out[4])83  static void interp_attr( float dst[4],
84  			 float t,
85  			 const float in[4],
86  			 const float out[4] )
87  {
88     dst[0] = LINTERP( t, out[0], in[0] );
89     dst[1] = LINTERP( t, out[1], in[1] );
90     dst[2] = LINTERP( t, out[2], in[2] );
91     dst[3] = LINTERP( t, out[3], in[3] );
92  }
93  
94  
95  /**
96   * Copy flat shaded attributes src vertex to dst vertex.
97   */
copy_flat(struct draw_stage * stage,struct vertex_header * dst,const struct vertex_header * src)98  static void copy_flat( struct draw_stage *stage,
99                         struct vertex_header *dst,
100                         const struct vertex_header *src )
101  {
102     const struct clip_stage *clipper = clip_stage(stage);
103     uint i;
104     for (i = 0; i < clipper->num_flat_attribs; i++) {
105        const uint attr = clipper->flat_attribs[i];
106        COPY_4FV(dst->data[attr], src->data[attr]);
107     }
108  }
109  
110  
111  
112  /* Interpolate between two vertices to produce a third.
113   */
interp(const struct clip_stage * clip,struct vertex_header * dst,float t,const struct vertex_header * out,const struct vertex_header * in)114  static void interp( const struct clip_stage *clip,
115  		    struct vertex_header *dst,
116  		    float t,
117  		    const struct vertex_header *out,
118  		    const struct vertex_header *in )
119  {
120     const unsigned nr_attrs = draw_current_shader_outputs(clip->stage.draw);
121     const unsigned pos_attr = draw_current_shader_position_output(clip->stage.draw);
122     const unsigned clip_attr = draw_current_shader_clipvertex_output(clip->stage.draw);
123     unsigned j;
124     float t_nopersp;
125  
126     /* Vertex header.
127      */
128     dst->clipmask = 0;
129     dst->edgeflag = 0;        /* will get overwritten later */
130     dst->have_clipdist = in->have_clipdist;
131     dst->vertex_id = UNDEFINED_VERTEX_ID;
132  
133     /* Interpolate the clip-space coords.
134      */
135     interp_attr(dst->clip, t, in->clip, out->clip);
136     /* interpolate the clip-space position */
137     interp_attr(dst->pre_clip_pos, t, in->pre_clip_pos, out->pre_clip_pos);
138  
139     /* Do the projective divide and viewport transformation to get
140      * new window coordinates:
141      */
142     {
143        const float *pos = dst->pre_clip_pos;
144        const float *scale = clip->stage.draw->viewport.scale;
145        const float *trans = clip->stage.draw->viewport.translate;
146        const float oow = 1.0f / pos[3];
147  
148        dst->data[pos_attr][0] = pos[0] * oow * scale[0] + trans[0];
149        dst->data[pos_attr][1] = pos[1] * oow * scale[1] + trans[1];
150        dst->data[pos_attr][2] = pos[2] * oow * scale[2] + trans[2];
151        dst->data[pos_attr][3] = oow;
152     }
153  
154     /**
155      * Compute the t in screen-space instead of 3d space to use
156      * for noperspective interpolation.
157      *
158      * The points can be aligned with the X axis, so in that case try
159      * the Y.  When both points are at the same screen position, we can
160      * pick whatever value (the interpolated point won't be in front
161      * anyway), so just use the 3d t.
162      */
163     {
164        int k;
165        t_nopersp = t;
166        for (k = 0; k < 2; k++)
167           if (in->data[pos_attr][k] != out->data[pos_attr][k]) {
168              t_nopersp = (dst->data[pos_attr][k] - out->data[pos_attr][k]) /
169                 (in->data[pos_attr][k] - out->data[pos_attr][k]);
170              break;
171           }
172     }
173  
174     /* Other attributes
175      */
176     for (j = 0; j < nr_attrs; j++) {
177        if (j != pos_attr && j != clip_attr) {
178           if (clip->noperspective_attribs[j])
179              interp_attr(dst->data[j], t_nopersp, in->data[j], out->data[j]);
180           else
181              interp_attr(dst->data[j], t, in->data[j], out->data[j]);
182        }
183     }
184  }
185  
186  
187  /**
188   * Emit a post-clip polygon to the next pipeline stage.  The polygon
189   * will be convex and the provoking vertex will always be vertex[0].
190   */
emit_poly(struct draw_stage * stage,struct vertex_header ** inlist,const boolean * edgeflags,unsigned n,const struct prim_header * origPrim)191  static void emit_poly( struct draw_stage *stage,
192  		       struct vertex_header **inlist,
193                         const boolean *edgeflags,
194  		       unsigned n,
195  		       const struct prim_header *origPrim)
196  {
197     struct prim_header header;
198     unsigned i;
199     ushort edge_first, edge_middle, edge_last;
200  
201     if (stage->draw->rasterizer->flatshade_first) {
202        edge_first  = DRAW_PIPE_EDGE_FLAG_0;
203        edge_middle = DRAW_PIPE_EDGE_FLAG_1;
204        edge_last   = DRAW_PIPE_EDGE_FLAG_2;
205     }
206     else {
207        edge_first  = DRAW_PIPE_EDGE_FLAG_2;
208        edge_middle = DRAW_PIPE_EDGE_FLAG_0;
209        edge_last   = DRAW_PIPE_EDGE_FLAG_1;
210     }
211  
212     if (!edgeflags[0])
213        edge_first = 0;
214  
215     /* later stages may need the determinant, but only the sign matters */
216     header.det = origPrim->det;
217     header.flags = DRAW_PIPE_RESET_STIPPLE | edge_first | edge_middle;
218     header.pad = 0;
219  
220     for (i = 2; i < n; i++, header.flags = edge_middle) {
221        /* order the triangle verts to respect the provoking vertex mode */
222        if (stage->draw->rasterizer->flatshade_first) {
223           header.v[0] = inlist[0];  /* the provoking vertex */
224           header.v[1] = inlist[i-1];
225           header.v[2] = inlist[i];
226        }
227        else {
228           header.v[0] = inlist[i-1];
229           header.v[1] = inlist[i];
230           header.v[2] = inlist[0];  /* the provoking vertex */
231        }
232  
233        if (!edgeflags[i-1]) {
234           header.flags &= ~edge_middle;
235        }
236  
237        if (i == n - 1 && edgeflags[i])
238           header.flags |= edge_last;
239  
240        if (0) {
241           const struct draw_vertex_shader *vs = stage->draw->vs.vertex_shader;
242           uint j, k;
243           debug_printf("Clipped tri: (flat-shade-first = %d)\n",
244                        stage->draw->rasterizer->flatshade_first);
245           for (j = 0; j < 3; j++) {
246              for (k = 0; k < vs->info.num_outputs; k++) {
247                 debug_printf("  Vert %d: Attr %d:  %f %f %f %f\n", j, k,
248                              header.v[j]->data[k][0],
249                              header.v[j]->data[k][1],
250                              header.v[j]->data[k][2],
251                              header.v[j]->data[k][3]);
252              }
253           }
254        }
255  
256        stage->next->tri( stage->next, &header );
257     }
258  }
259  
260  
261  static INLINE float
dot4(const float * a,const float * b)262  dot4(const float *a, const float *b)
263  {
264     return (a[0] * b[0] +
265             a[1] * b[1] +
266             a[2] * b[2] +
267             a[3] * b[3]);
268  }
269  
270  /*
271   * this function extracts the clip distance for the current plane,
272   * it first checks if the shader provided a clip distance, otherwise
273   * it works out the value using the clipvertex
274   */
getclipdist(const struct clip_stage * clipper,struct vertex_header * vert,int plane_idx)275  static INLINE float getclipdist(const struct clip_stage *clipper,
276                                  struct vertex_header *vert,
277                                  int plane_idx)
278  {
279     const float *plane;
280     float dp;
281     if (vert->have_clipdist && plane_idx >= 6) {
282        /* pick the correct clipdistance element from the output vectors */
283        int _idx = plane_idx - 6;
284        int cdi = _idx >= 4;
285        int vidx = cdi ? _idx - 4 : _idx;
286        dp = vert->data[draw_current_shader_clipdistance_output(clipper->stage.draw, cdi)][vidx];
287     } else {
288        plane = clipper->plane[plane_idx];
289        dp = dot4(vert->clip, plane);
290     }
291     return dp;
292  }
293  
294  /* Clip a triangle against the viewport and user clip planes.
295   */
296  static void
do_clip_tri(struct draw_stage * stage,struct prim_header * header,unsigned clipmask)297  do_clip_tri( struct draw_stage *stage,
298  	     struct prim_header *header,
299  	     unsigned clipmask )
300  {
301     struct clip_stage *clipper = clip_stage( stage );
302     struct vertex_header *a[MAX_CLIPPED_VERTICES];
303     struct vertex_header *b[MAX_CLIPPED_VERTICES];
304     struct vertex_header **inlist = a;
305     struct vertex_header **outlist = b;
306     unsigned tmpnr = 0;
307     unsigned n = 3;
308     unsigned i;
309     boolean aEdges[MAX_CLIPPED_VERTICES];
310     boolean bEdges[MAX_CLIPPED_VERTICES];
311     boolean *inEdges = aEdges;
312     boolean *outEdges = bEdges;
313  
314     inlist[0] = header->v[0];
315     inlist[1] = header->v[1];
316     inlist[2] = header->v[2];
317  
318     /*
319      * Note: at this point we can't just use the per-vertex edge flags.
320      * We have to observe the edge flag bits set in header->flags which
321      * were set during primitive decomposition.  Put those flags into
322      * an edge flags array which parallels the vertex array.
323      * Later, in the 'unfilled' pipeline stage we'll draw the edge if both
324      * the header.flags bit is set AND the per-vertex edgeflag field is set.
325      */
326     inEdges[0] = !!(header->flags & DRAW_PIPE_EDGE_FLAG_0);
327     inEdges[1] = !!(header->flags & DRAW_PIPE_EDGE_FLAG_1);
328     inEdges[2] = !!(header->flags & DRAW_PIPE_EDGE_FLAG_2);
329  
330     while (clipmask && n >= 3) {
331        const unsigned plane_idx = ffs(clipmask)-1;
332        const boolean is_user_clip_plane = plane_idx >= 6;
333        struct vertex_header *vert_prev = inlist[0];
334        boolean *edge_prev = &inEdges[0];
335        float dp_prev;
336        unsigned outcount = 0;
337  
338        dp_prev = getclipdist(clipper, vert_prev, plane_idx);
339        clipmask &= ~(1<<plane_idx);
340  
341        assert(n < MAX_CLIPPED_VERTICES);
342        if (n >= MAX_CLIPPED_VERTICES)
343           return;
344        inlist[n] = inlist[0]; /* prevent rotation of vertices */
345        inEdges[n] = inEdges[0];
346  
347        for (i = 1; i <= n; i++) {
348  	 struct vertex_header *vert = inlist[i];
349           boolean *edge = &inEdges[i];
350  
351           float dp = getclipdist(clipper, vert, plane_idx);
352  
353  	 if (!IS_NEGATIVE(dp_prev)) {
354              assert(outcount < MAX_CLIPPED_VERTICES);
355              if (outcount >= MAX_CLIPPED_VERTICES)
356                 return;
357              outEdges[outcount] = *edge_prev;
358  	    outlist[outcount++] = vert_prev;
359  	 }
360  
361  	 if (DIFFERENT_SIGNS(dp, dp_prev)) {
362  	    struct vertex_header *new_vert;
363              boolean *new_edge;
364  
365              assert(tmpnr < MAX_CLIPPED_VERTICES + 1);
366              if (tmpnr >= MAX_CLIPPED_VERTICES + 1)
367                 return;
368              new_vert = clipper->stage.tmp[tmpnr++];
369  
370              assert(outcount < MAX_CLIPPED_VERTICES);
371              if (outcount >= MAX_CLIPPED_VERTICES)
372                 return;
373  
374              new_edge = &outEdges[outcount];
375  	    outlist[outcount++] = new_vert;
376  
377  	    if (IS_NEGATIVE(dp)) {
378  	       /* Going out of bounds.  Avoid division by zero as we
379  		* know dp != dp_prev from DIFFERENT_SIGNS, above.
380  		*/
381  	       float t = dp / (dp - dp_prev);
382  	       interp( clipper, new_vert, t, vert, vert_prev );
383  
384  	       /* Whether or not to set edge flag for the new vert depends
385                  * on whether it's a user-defined clipping plane.  We're
386                  * copying NVIDIA's behaviour here.
387  		*/
388                 if (is_user_clip_plane) {
389                    /* we want to see an edge along the clip plane */
390                    *new_edge = TRUE;
391                    new_vert->edgeflag = TRUE;
392                 }
393                 else {
394                    /* we don't want to see an edge along the frustum clip plane */
395                    *new_edge = *edge_prev;
396                    new_vert->edgeflag = FALSE;
397                 }
398  	    }
399              else {
400  	       /* Coming back in.
401  		*/
402  	       float t = dp_prev / (dp_prev - dp);
403  	       interp( clipper, new_vert, t, vert_prev, vert );
404  
405  	       /* Copy starting vert's edgeflag:
406  		*/
407  	       new_vert->edgeflag = vert_prev->edgeflag;
408                 *new_edge = *edge_prev;
409  	    }
410  	 }
411  
412  	 vert_prev = vert;
413           edge_prev = edge;
414  	 dp_prev = dp;
415        }
416  
417        /* swap in/out lists */
418        {
419  	 struct vertex_header **tmp = inlist;
420  	 inlist = outlist;
421  	 outlist = tmp;
422  	 n = outcount;
423        }
424        {
425           boolean *tmp = inEdges;
426           inEdges = outEdges;
427           outEdges = tmp;
428        }
429  
430     }
431  
432     /* If flat-shading, copy provoking vertex color to polygon vertex[0]
433      */
434     if (n >= 3) {
435        if (clipper->num_flat_attribs) {
436           if (stage->draw->rasterizer->flatshade_first) {
437              if (inlist[0] != header->v[0]) {
438                 assert(tmpnr < MAX_CLIPPED_VERTICES + 1);
439                 if (tmpnr >= MAX_CLIPPED_VERTICES + 1)
440                    return;
441                 inlist[0] = dup_vert(stage, inlist[0], tmpnr++);
442                 copy_flat(stage, inlist[0], header->v[0]);
443              }
444           }
445           else {
446              if (inlist[0] != header->v[2]) {
447                 assert(tmpnr < MAX_CLIPPED_VERTICES + 1);
448                 if (tmpnr >= MAX_CLIPPED_VERTICES + 1)
449                    return;
450                 inlist[0] = dup_vert(stage, inlist[0], tmpnr++);
451                 copy_flat(stage, inlist[0], header->v[2]);
452              }
453           }
454        }
455  
456        /* Emit the polygon as triangles to the setup stage:
457         */
458        emit_poly( stage, inlist, inEdges, n, header );
459     }
460  }
461  
462  
463  /* Clip a line against the viewport and user clip planes.
464   */
465  static void
do_clip_line(struct draw_stage * stage,struct prim_header * header,unsigned clipmask)466  do_clip_line( struct draw_stage *stage,
467  	      struct prim_header *header,
468  	      unsigned clipmask )
469  {
470     const struct clip_stage *clipper = clip_stage( stage );
471     struct vertex_header *v0 = header->v[0];
472     struct vertex_header *v1 = header->v[1];
473     float t0 = 0.0F;
474     float t1 = 0.0F;
475     struct prim_header newprim;
476  
477     while (clipmask) {
478        const unsigned plane_idx = ffs(clipmask)-1;
479        const float dp0 = getclipdist(clipper, v0, plane_idx);
480        const float dp1 = getclipdist(clipper, v1, plane_idx);
481  
482        if (dp1 < 0.0F) {
483  	 float t = dp1 / (dp1 - dp0);
484           t1 = MAX2(t1, t);
485        }
486  
487        if (dp0 < 0.0F) {
488  	 float t = dp0 / (dp0 - dp1);
489           t0 = MAX2(t0, t);
490        }
491  
492        if (t0 + t1 >= 1.0F)
493  	 return; /* discard */
494  
495        clipmask &= ~(1 << plane_idx);  /* turn off this plane's bit */
496     }
497  
498     if (v0->clipmask) {
499        interp( clipper, stage->tmp[0], t0, v0, v1 );
500        copy_flat(stage, stage->tmp[0], v0);
501        newprim.v[0] = stage->tmp[0];
502     }
503     else {
504        newprim.v[0] = v0;
505     }
506  
507     if (v1->clipmask) {
508        interp( clipper, stage->tmp[1], t1, v1, v0 );
509        newprim.v[1] = stage->tmp[1];
510     }
511     else {
512        newprim.v[1] = v1;
513     }
514  
515     stage->next->line( stage->next, &newprim );
516  }
517  
518  
519  static void
clip_point(struct draw_stage * stage,struct prim_header * header)520  clip_point( struct draw_stage *stage,
521  	    struct prim_header *header )
522  {
523     if (header->v[0]->clipmask == 0)
524        stage->next->point( stage->next, header );
525  }
526  
527  
528  static void
clip_line(struct draw_stage * stage,struct prim_header * header)529  clip_line( struct draw_stage *stage,
530  	   struct prim_header *header )
531  {
532     unsigned clipmask = (header->v[0]->clipmask |
533                          header->v[1]->clipmask);
534  
535     if (clipmask == 0) {
536        /* no clipping needed */
537        stage->next->line( stage->next, header );
538     }
539     else if ((header->v[0]->clipmask &
540               header->v[1]->clipmask) == 0) {
541        do_clip_line(stage, header, clipmask);
542     }
543     /* else, totally clipped */
544  }
545  
546  
547  static void
clip_tri(struct draw_stage * stage,struct prim_header * header)548  clip_tri( struct draw_stage *stage,
549  	  struct prim_header *header )
550  {
551     unsigned clipmask = (header->v[0]->clipmask |
552                          header->v[1]->clipmask |
553                          header->v[2]->clipmask);
554  
555     if (clipmask == 0) {
556        /* no clipping needed */
557        stage->next->tri( stage->next, header );
558     }
559     else if ((header->v[0]->clipmask &
560               header->v[1]->clipmask &
561               header->v[2]->clipmask) == 0) {
562        do_clip_tri(stage, header, clipmask);
563     }
564  }
565  
566  
567  /* Update state.  Could further delay this until we hit the first
568   * primitive that really requires clipping.
569   */
570  static void
clip_init_state(struct draw_stage * stage)571  clip_init_state( struct draw_stage *stage )
572  {
573     struct clip_stage *clipper = clip_stage( stage );
574     const struct draw_vertex_shader *vs = stage->draw->vs.vertex_shader;
575     const struct draw_fragment_shader *fs = stage->draw->fs.fragment_shader;
576     uint i;
577  
578     /* We need to know for each attribute what kind of interpolation is
579      * done on it (flat, smooth or noperspective).  But the information
580      * is not directly accessible for outputs, only for inputs.  So we
581      * have to match semantic name and index between the VS (or GS/ES)
582      * outputs and the FS inputs to get to the interpolation mode.
583      *
584      * The only hitch is with gl_FrontColor/gl_BackColor which map to
585      * gl_Color, and their Secondary versions.  First there are (up to)
586      * two outputs for one input, so we tuck the information in a
587      * specific array.  Second if they don't have qualifiers, the
588      * default value has to be picked from the global shade mode.
589      *
590      * Of course, if we don't have a fragment shader in the first
591      * place, defaults should be used.
592      */
593  
594     /* First pick up the interpolation mode for
595      * gl_Color/gl_SecondaryColor, with the correct default.
596      */
597     int indexed_interp[2];
598     indexed_interp[0] = indexed_interp[1] = stage->draw->rasterizer->flatshade ?
599        TGSI_INTERPOLATE_CONSTANT : TGSI_INTERPOLATE_PERSPECTIVE;
600  
601     if (fs) {
602        for (i = 0; i < fs->info.num_inputs; i++) {
603           if (fs->info.input_semantic_name[i] == TGSI_SEMANTIC_COLOR) {
604              if (fs->info.input_interpolate[i] != TGSI_INTERPOLATE_COLOR)
605                 indexed_interp[fs->info.input_semantic_index[i]] = fs->info.input_interpolate[i];
606           }
607        }
608     }
609  
610     /* Then resolve the interpolation mode for every output attribute.
611      *
612      * Given how the rest of the code, the most efficient way is to
613      * have a vector of flat-mode attributes, and a mask for
614      * noperspective attributes.
615      */
616  
617     clipper->num_flat_attribs = 0;
618     memset(clipper->noperspective_attribs, 0, sizeof(clipper->noperspective_attribs));
619     for (i = 0; i < vs->info.num_outputs; i++) {
620        /* Find the interpolation mode for a specific attribute
621         */
622        int interp;
623  
624        /* If it's gl_{Front,Back}{,Secondary}Color, pick up the mode
625         * from the array we've filled before. */
626        if (vs->info.output_semantic_name[i] == TGSI_SEMANTIC_COLOR ||
627            vs->info.output_semantic_name[i] == TGSI_SEMANTIC_BCOLOR) {
628           interp = indexed_interp[vs->info.output_semantic_index[i]];
629        } else {
630           /* Otherwise, search in the FS inputs, with a decent default
631            * if we don't find it.
632            */
633           uint j;
634           interp = TGSI_INTERPOLATE_PERSPECTIVE;
635           if (fs) {
636              for (j = 0; j < fs->info.num_inputs; j++) {
637                 if (vs->info.output_semantic_name[i] == fs->info.input_semantic_name[j] &&
638                     vs->info.output_semantic_index[i] == fs->info.input_semantic_index[j]) {
639                    interp = fs->info.input_interpolate[j];
640                    break;
641                 }
642              }
643           }
644        }
645  
646        /* If it's flat, add it to the flat vector.  Otherwise update
647         * the noperspective mask.
648         */
649        if (interp == TGSI_INTERPOLATE_CONSTANT) {
650           clipper->flat_attribs[clipper->num_flat_attribs] = i;
651           clipper->num_flat_attribs++;
652        } else
653           clipper->noperspective_attribs[i] = interp == TGSI_INTERPOLATE_LINEAR;
654     }
655  
656     stage->tri = clip_tri;
657     stage->line = clip_line;
658  }
659  
660  
661  
clip_first_tri(struct draw_stage * stage,struct prim_header * header)662  static void clip_first_tri( struct draw_stage *stage,
663  			    struct prim_header *header )
664  {
665     clip_init_state( stage );
666     stage->tri( stage, header );
667  }
668  
clip_first_line(struct draw_stage * stage,struct prim_header * header)669  static void clip_first_line( struct draw_stage *stage,
670  			     struct prim_header *header )
671  {
672     clip_init_state( stage );
673     stage->line( stage, header );
674  }
675  
676  
clip_flush(struct draw_stage * stage,unsigned flags)677  static void clip_flush( struct draw_stage *stage,
678  			     unsigned flags )
679  {
680     stage->tri = clip_first_tri;
681     stage->line = clip_first_line;
682     stage->next->flush( stage->next, flags );
683  }
684  
685  
clip_reset_stipple_counter(struct draw_stage * stage)686  static void clip_reset_stipple_counter( struct draw_stage *stage )
687  {
688     stage->next->reset_stipple_counter( stage->next );
689  }
690  
691  
clip_destroy(struct draw_stage * stage)692  static void clip_destroy( struct draw_stage *stage )
693  {
694     draw_free_temp_verts( stage );
695     FREE( stage );
696  }
697  
698  
699  /**
700   * Allocate a new clipper stage.
701   * \return pointer to new stage object
702   */
draw_clip_stage(struct draw_context * draw)703  struct draw_stage *draw_clip_stage( struct draw_context *draw )
704  {
705     struct clip_stage *clipper = CALLOC_STRUCT(clip_stage);
706     if (clipper == NULL)
707        goto fail;
708  
709     clipper->stage.draw = draw;
710     clipper->stage.name = "clipper";
711     clipper->stage.point = clip_point;
712     clipper->stage.line = clip_first_line;
713     clipper->stage.tri = clip_first_tri;
714     clipper->stage.flush = clip_flush;
715     clipper->stage.reset_stipple_counter = clip_reset_stipple_counter;
716     clipper->stage.destroy = clip_destroy;
717  
718     clipper->plane = draw->plane;
719  
720     if (!draw_alloc_temp_verts( &clipper->stage, MAX_CLIPPED_VERTICES+1 ))
721        goto fail;
722  
723     return &clipper->stage;
724  
725   fail:
726     if (clipper)
727        clipper->stage.destroy( &clipper->stage );
728  
729     return NULL;
730  }
731