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