• Home
  • 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