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