OSDN Git Service

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