Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

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