Home | History | Annotate | Download | only in draw
      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 (at) 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 */
     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  */
     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  */
     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  */
    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  */
    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
    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  */
    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
    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
    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
    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
    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
    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
    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 
    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 
    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 
    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 
    686 static void clip_reset_stipple_counter( struct draw_stage *stage )
    687 {
    688    stage->next->reset_stipple_counter( stage->next );
    689 }
    690 
    691 
    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  */
    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