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