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