Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

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