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 54struct 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 */ 76static inline struct clip_stage *clip_stage(struct draw_stage *stage) 77{ 78 return (struct clip_stage *)stage; 79} 80 81static inline unsigned 82draw_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 */ 102static 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 */ 117static 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 */ 131static 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 */ 216static 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 297static inline float 298dot4(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 */ 311static 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 */ 345static void 346do_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 */ 571static void 572do_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 651static void 652clip_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 */ 665static void 666clip_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 692static void 693clip_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 700static void 701clip_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 718static void 719clip_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 737static int 738find_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 */ 782static void 783clip_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 901static 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 908static 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 916static 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 924static void clip_reset_stipple_counter(struct draw_stage *stage) 925{ 926 stage->next->reset_stipple_counter( stage->next ); 927} 928 929 930static 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 */ 941struct 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