1 /* 2 Copyright (C) Intel Corp. 2006. All Rights Reserved. 3 Intel funded Tungsten Graphics to 4 develop this 3D driver. 5 6 Permission is hereby granted, free of charge, to any person obtaining 7 a 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, sublicense, 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 16 portions of the Software. 17 18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 21 IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE 22 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 24 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 26 **********************************************************************/ 27 /* 28 * Authors: 29 * Keith Whitwell <keithw (at) vmware.com> 30 */ 31 32 #include "main/macros.h" 33 #include "main/enums.h" 34 #include "program/program.h" 35 36 #include "brw_clip.h" 37 38 39 /* This is performed against the original triangles, so no indirection 40 * required: 41 BZZZT! 42 */ 43 static void compute_tri_direction( struct brw_clip_compile *c ) 44 { 45 struct brw_codegen *p = &c->func; 46 struct brw_reg e = c->reg.tmp0; 47 struct brw_reg f = c->reg.tmp1; 48 GLuint hpos_offset = brw_varying_to_offset(&c->vue_map, VARYING_SLOT_POS); 49 struct brw_reg v0 = byte_offset(c->reg.vertex[0], hpos_offset); 50 struct brw_reg v1 = byte_offset(c->reg.vertex[1], hpos_offset); 51 struct brw_reg v2 = byte_offset(c->reg.vertex[2], hpos_offset); 52 53 54 struct brw_reg v0n = get_tmp(c); 55 struct brw_reg v1n = get_tmp(c); 56 struct brw_reg v2n = get_tmp(c); 57 58 /* Convert to NDC. 59 * NOTE: We can't modify the original vertex coordinates, 60 * as it may impact further operations. 61 * So, we have to keep normalized coordinates in temp registers. 62 * 63 * TBD-KC 64 * Try to optimize unnecessary MOV's. 65 */ 66 brw_MOV(p, v0n, v0); 67 brw_MOV(p, v1n, v1); 68 brw_MOV(p, v2n, v2); 69 70 brw_clip_project_position(c, v0n); 71 brw_clip_project_position(c, v1n); 72 brw_clip_project_position(c, v2n); 73 74 /* Calculate the vectors of two edges of the triangle: 75 */ 76 brw_ADD(p, e, v0n, negate(v2n)); 77 brw_ADD(p, f, v1n, negate(v2n)); 78 79 /* Take their crossproduct: 80 */ 81 brw_set_default_access_mode(p, BRW_ALIGN_16); 82 brw_MUL(p, vec4(brw_null_reg()), brw_swizzle(e, BRW_SWIZZLE_YZXW), 83 brw_swizzle(f, BRW_SWIZZLE_ZXYW)); 84 brw_MAC(p, vec4(e), negate(brw_swizzle(e, BRW_SWIZZLE_ZXYW)), 85 brw_swizzle(f, BRW_SWIZZLE_YZXW)); 86 brw_set_default_access_mode(p, BRW_ALIGN_1); 87 88 brw_MUL(p, c->reg.dir, c->reg.dir, vec4(e)); 89 } 90 91 92 static void cull_direction( struct brw_clip_compile *c ) 93 { 94 struct brw_codegen *p = &c->func; 95 GLuint conditional; 96 97 assert (!(c->key.fill_ccw == BRW_CLIP_FILL_MODE_CULL && 98 c->key.fill_cw == BRW_CLIP_FILL_MODE_CULL)); 99 100 if (c->key.fill_ccw == BRW_CLIP_FILL_MODE_CULL) 101 conditional = BRW_CONDITIONAL_GE; 102 else 103 conditional = BRW_CONDITIONAL_L; 104 105 brw_CMP(p, 106 vec1(brw_null_reg()), 107 conditional, 108 get_element(c->reg.dir, 2), 109 brw_imm_f(0)); 110 111 brw_IF(p, BRW_EXECUTE_1); 112 { 113 brw_clip_kill_thread(c); 114 } 115 brw_ENDIF(p); 116 } 117 118 119 120 static void copy_bfc( struct brw_clip_compile *c ) 121 { 122 struct brw_codegen *p = &c->func; 123 GLuint conditional; 124 125 /* Do we have any colors to copy? 126 */ 127 if (!(brw_clip_have_varying(c, VARYING_SLOT_COL0) && 128 brw_clip_have_varying(c, VARYING_SLOT_BFC0)) && 129 !(brw_clip_have_varying(c, VARYING_SLOT_COL1) && 130 brw_clip_have_varying(c, VARYING_SLOT_BFC1))) 131 return; 132 133 /* In some weird degenerate cases we can end up testing the 134 * direction twice, once for culling and once for bfc copying. Oh 135 * well, that's what you get for setting weird GL state. 136 */ 137 if (c->key.copy_bfc_ccw) 138 conditional = BRW_CONDITIONAL_GE; 139 else 140 conditional = BRW_CONDITIONAL_L; 141 142 brw_CMP(p, 143 vec1(brw_null_reg()), 144 conditional, 145 get_element(c->reg.dir, 2), 146 brw_imm_f(0)); 147 148 brw_IF(p, BRW_EXECUTE_1); 149 { 150 GLuint i; 151 152 for (i = 0; i < 3; i++) { 153 if (brw_clip_have_varying(c, VARYING_SLOT_COL0) && 154 brw_clip_have_varying(c, VARYING_SLOT_BFC0)) 155 brw_MOV(p, 156 byte_offset(c->reg.vertex[i], 157 brw_varying_to_offset(&c->vue_map, 158 VARYING_SLOT_COL0)), 159 byte_offset(c->reg.vertex[i], 160 brw_varying_to_offset(&c->vue_map, 161 VARYING_SLOT_BFC0))); 162 163 if (brw_clip_have_varying(c, VARYING_SLOT_COL1) && 164 brw_clip_have_varying(c, VARYING_SLOT_BFC1)) 165 brw_MOV(p, 166 byte_offset(c->reg.vertex[i], 167 brw_varying_to_offset(&c->vue_map, 168 VARYING_SLOT_COL1)), 169 byte_offset(c->reg.vertex[i], 170 brw_varying_to_offset(&c->vue_map, 171 VARYING_SLOT_BFC1))); 172 } 173 } 174 brw_ENDIF(p); 175 } 176 177 178 179 180 /* 181 GLfloat iz = 1.0 / dir.z; 182 GLfloat ac = dir.x * iz; 183 GLfloat bc = dir.y * iz; 184 offset = ctx->Polygon.OffsetUnits * DEPTH_SCALE; 185 offset += MAX2( abs(ac), abs(bc) ) * ctx->Polygon.OffsetFactor; 186 if (ctx->Polygon.OffsetClamp && isfinite(ctx->Polygon.OffsetClamp)) { 187 if (ctx->Polygon.OffsetClamp < 0) 188 offset = MAX2( offset, ctx->Polygon.OffsetClamp ); 189 else 190 offset = MIN2( offset, ctx->Polygon.OffsetClamp ); 191 } 192 offset *= MRD; 193 */ 194 static void compute_offset( struct brw_clip_compile *c ) 195 { 196 struct brw_codegen *p = &c->func; 197 struct brw_reg off = c->reg.offset; 198 struct brw_reg dir = c->reg.dir; 199 200 brw_math_invert(p, get_element(off, 2), get_element(dir, 2)); 201 brw_MUL(p, vec2(off), vec2(dir), get_element(off, 2)); 202 203 brw_CMP(p, 204 vec1(brw_null_reg()), 205 BRW_CONDITIONAL_GE, 206 brw_abs(get_element(off, 0)), 207 brw_abs(get_element(off, 1))); 208 209 brw_SEL(p, vec1(off), 210 brw_abs(get_element(off, 0)), brw_abs(get_element(off, 1))); 211 brw_inst_set_pred_control(p->devinfo, brw_last_inst, BRW_PREDICATE_NORMAL); 212 213 brw_MUL(p, vec1(off), vec1(off), brw_imm_f(c->key.offset_factor)); 214 brw_ADD(p, vec1(off), vec1(off), brw_imm_f(c->key.offset_units)); 215 if (c->key.offset_clamp && isfinite(c->key.offset_clamp)) { 216 brw_CMP(p, 217 vec1(brw_null_reg()), 218 c->key.offset_clamp < 0 ? BRW_CONDITIONAL_GE : BRW_CONDITIONAL_L, 219 vec1(off), 220 brw_imm_f(c->key.offset_clamp)); 221 brw_SEL(p, vec1(off), vec1(off), brw_imm_f(c->key.offset_clamp)); 222 } 223 } 224 225 226 static void merge_edgeflags( struct brw_clip_compile *c ) 227 { 228 struct brw_codegen *p = &c->func; 229 struct brw_reg tmp0 = get_element_ud(c->reg.tmp0, 0); 230 231 brw_AND(p, tmp0, get_element_ud(c->reg.R0, 2), brw_imm_ud(PRIM_MASK)); 232 brw_CMP(p, 233 vec1(brw_null_reg()), 234 BRW_CONDITIONAL_EQ, 235 tmp0, 236 brw_imm_ud(_3DPRIM_POLYGON)); 237 238 /* Get away with using reg.vertex because we know that this is not 239 * a _3DPRIM_TRISTRIP_REVERSE: 240 */ 241 brw_IF(p, BRW_EXECUTE_1); 242 { 243 brw_AND(p, vec1(brw_null_reg()), get_element_ud(c->reg.R0, 2), brw_imm_ud(1<<8)); 244 brw_inst_set_cond_modifier(p->devinfo, brw_last_inst, BRW_CONDITIONAL_EQ); 245 brw_MOV(p, byte_offset(c->reg.vertex[0], 246 brw_varying_to_offset(&c->vue_map, 247 VARYING_SLOT_EDGE)), 248 brw_imm_f(0)); 249 brw_inst_set_pred_control(p->devinfo, brw_last_inst, BRW_PREDICATE_NORMAL); 250 251 brw_AND(p, vec1(brw_null_reg()), get_element_ud(c->reg.R0, 2), brw_imm_ud(1<<9)); 252 brw_inst_set_cond_modifier(p->devinfo, brw_last_inst, BRW_CONDITIONAL_EQ); 253 brw_MOV(p, byte_offset(c->reg.vertex[2], 254 brw_varying_to_offset(&c->vue_map, 255 VARYING_SLOT_EDGE)), 256 brw_imm_f(0)); 257 brw_inst_set_pred_control(p->devinfo, brw_last_inst, BRW_PREDICATE_NORMAL); 258 } 259 brw_ENDIF(p); 260 } 261 262 263 264 static void apply_one_offset( struct brw_clip_compile *c, 265 struct brw_indirect vert ) 266 { 267 struct brw_codegen *p = &c->func; 268 GLuint ndc_offset = brw_varying_to_offset(&c->vue_map, 269 BRW_VARYING_SLOT_NDC); 270 struct brw_reg z = deref_1f(vert, ndc_offset + 271 2 * type_sz(BRW_REGISTER_TYPE_F)); 272 273 brw_ADD(p, z, z, vec1(c->reg.offset)); 274 } 275 276 277 278 /*********************************************************************** 279 * Output clipped polygon as an unfilled primitive: 280 */ 281 static void emit_lines(struct brw_clip_compile *c, 282 bool do_offset) 283 { 284 struct brw_codegen *p = &c->func; 285 struct brw_indirect v0 = brw_indirect(0, 0); 286 struct brw_indirect v1 = brw_indirect(1, 0); 287 struct brw_indirect v0ptr = brw_indirect(2, 0); 288 struct brw_indirect v1ptr = brw_indirect(3, 0); 289 290 /* Need a separate loop for offset: 291 */ 292 if (do_offset) { 293 brw_MOV(p, c->reg.loopcount, c->reg.nr_verts); 294 brw_MOV(p, get_addr_reg(v0ptr), brw_address(c->reg.inlist)); 295 296 brw_DO(p, BRW_EXECUTE_1); 297 { 298 brw_MOV(p, get_addr_reg(v0), deref_1uw(v0ptr, 0)); 299 brw_ADD(p, get_addr_reg(v0ptr), get_addr_reg(v0ptr), brw_imm_uw(2)); 300 301 apply_one_offset(c, v0); 302 303 brw_ADD(p, c->reg.loopcount, c->reg.loopcount, brw_imm_d(-1)); 304 brw_inst_set_cond_modifier(p->devinfo, brw_last_inst, BRW_CONDITIONAL_G); 305 } 306 brw_WHILE(p); 307 brw_inst_set_pred_control(p->devinfo, brw_last_inst, BRW_PREDICATE_NORMAL); 308 } 309 310 /* v1ptr = &inlist[nr_verts] 311 * *v1ptr = v0 312 */ 313 brw_MOV(p, c->reg.loopcount, c->reg.nr_verts); 314 brw_MOV(p, get_addr_reg(v0ptr), brw_address(c->reg.inlist)); 315 brw_ADD(p, get_addr_reg(v1ptr), get_addr_reg(v0ptr), retype(c->reg.nr_verts, BRW_REGISTER_TYPE_UW)); 316 brw_ADD(p, get_addr_reg(v1ptr), get_addr_reg(v1ptr), retype(c->reg.nr_verts, BRW_REGISTER_TYPE_UW)); 317 brw_MOV(p, deref_1uw(v1ptr, 0), deref_1uw(v0ptr, 0)); 318 319 brw_DO(p, BRW_EXECUTE_1); 320 { 321 brw_MOV(p, get_addr_reg(v0), deref_1uw(v0ptr, 0)); 322 brw_MOV(p, get_addr_reg(v1), deref_1uw(v0ptr, 2)); 323 brw_ADD(p, get_addr_reg(v0ptr), get_addr_reg(v0ptr), brw_imm_uw(2)); 324 325 /* draw edge if edgeflag != 0 */ 326 brw_CMP(p, 327 vec1(brw_null_reg()), BRW_CONDITIONAL_NZ, 328 deref_1f(v0, brw_varying_to_offset(&c->vue_map, 329 VARYING_SLOT_EDGE)), 330 brw_imm_f(0)); 331 brw_IF(p, BRW_EXECUTE_1); 332 { 333 brw_clip_emit_vue(c, v0, BRW_URB_WRITE_ALLOCATE_COMPLETE, 334 (_3DPRIM_LINESTRIP << URB_WRITE_PRIM_TYPE_SHIFT) 335 | URB_WRITE_PRIM_START); 336 brw_clip_emit_vue(c, v1, BRW_URB_WRITE_ALLOCATE_COMPLETE, 337 (_3DPRIM_LINESTRIP << URB_WRITE_PRIM_TYPE_SHIFT) 338 | URB_WRITE_PRIM_END); 339 } 340 brw_ENDIF(p); 341 342 brw_ADD(p, c->reg.loopcount, c->reg.loopcount, brw_imm_d(-1)); 343 brw_inst_set_cond_modifier(p->devinfo, brw_last_inst, BRW_CONDITIONAL_NZ); 344 } 345 brw_WHILE(p); 346 brw_inst_set_pred_control(p->devinfo, brw_last_inst, BRW_PREDICATE_NORMAL); 347 } 348 349 350 351 static void emit_points(struct brw_clip_compile *c, 352 bool do_offset ) 353 { 354 struct brw_codegen *p = &c->func; 355 356 struct brw_indirect v0 = brw_indirect(0, 0); 357 struct brw_indirect v0ptr = brw_indirect(2, 0); 358 359 brw_MOV(p, c->reg.loopcount, c->reg.nr_verts); 360 brw_MOV(p, get_addr_reg(v0ptr), brw_address(c->reg.inlist)); 361 362 brw_DO(p, BRW_EXECUTE_1); 363 { 364 brw_MOV(p, get_addr_reg(v0), deref_1uw(v0ptr, 0)); 365 brw_ADD(p, get_addr_reg(v0ptr), get_addr_reg(v0ptr), brw_imm_uw(2)); 366 367 /* draw if edgeflag != 0 368 */ 369 brw_CMP(p, 370 vec1(brw_null_reg()), BRW_CONDITIONAL_NZ, 371 deref_1f(v0, brw_varying_to_offset(&c->vue_map, 372 VARYING_SLOT_EDGE)), 373 brw_imm_f(0)); 374 brw_IF(p, BRW_EXECUTE_1); 375 { 376 if (do_offset) 377 apply_one_offset(c, v0); 378 379 brw_clip_emit_vue(c, v0, BRW_URB_WRITE_ALLOCATE_COMPLETE, 380 (_3DPRIM_POINTLIST << URB_WRITE_PRIM_TYPE_SHIFT) 381 | URB_WRITE_PRIM_START | URB_WRITE_PRIM_END); 382 } 383 brw_ENDIF(p); 384 385 brw_ADD(p, c->reg.loopcount, c->reg.loopcount, brw_imm_d(-1)); 386 brw_inst_set_cond_modifier(p->devinfo, brw_last_inst, BRW_CONDITIONAL_NZ); 387 } 388 brw_WHILE(p); 389 brw_inst_set_pred_control(p->devinfo, brw_last_inst, BRW_PREDICATE_NORMAL); 390 } 391 392 393 394 395 396 397 398 static void emit_primitives( struct brw_clip_compile *c, 399 GLuint mode, 400 bool do_offset ) 401 { 402 switch (mode) { 403 case BRW_CLIP_FILL_MODE_FILL: 404 brw_clip_tri_emit_polygon(c); 405 break; 406 407 case BRW_CLIP_FILL_MODE_LINE: 408 emit_lines(c, do_offset); 409 break; 410 411 case BRW_CLIP_FILL_MODE_POINT: 412 emit_points(c, do_offset); 413 break; 414 415 case BRW_CLIP_FILL_MODE_CULL: 416 unreachable("not reached"); 417 } 418 } 419 420 421 422 static void emit_unfilled_primitives( struct brw_clip_compile *c ) 423 { 424 struct brw_codegen *p = &c->func; 425 426 /* Direction culling has already been done. 427 */ 428 if (c->key.fill_ccw != c->key.fill_cw && 429 c->key.fill_ccw != BRW_CLIP_FILL_MODE_CULL && 430 c->key.fill_cw != BRW_CLIP_FILL_MODE_CULL) 431 { 432 brw_CMP(p, 433 vec1(brw_null_reg()), 434 BRW_CONDITIONAL_GE, 435 get_element(c->reg.dir, 2), 436 brw_imm_f(0)); 437 438 brw_IF(p, BRW_EXECUTE_1); 439 { 440 emit_primitives(c, c->key.fill_ccw, c->key.offset_ccw); 441 } 442 brw_ELSE(p); 443 { 444 emit_primitives(c, c->key.fill_cw, c->key.offset_cw); 445 } 446 brw_ENDIF(p); 447 } 448 else if (c->key.fill_cw != BRW_CLIP_FILL_MODE_CULL) { 449 emit_primitives(c, c->key.fill_cw, c->key.offset_cw); 450 } 451 else if (c->key.fill_ccw != BRW_CLIP_FILL_MODE_CULL) { 452 emit_primitives(c, c->key.fill_ccw, c->key.offset_ccw); 453 } 454 } 455 456 457 458 459 static void check_nr_verts( struct brw_clip_compile *c ) 460 { 461 struct brw_codegen *p = &c->func; 462 463 brw_CMP(p, vec1(brw_null_reg()), BRW_CONDITIONAL_L, c->reg.nr_verts, brw_imm_d(3)); 464 brw_IF(p, BRW_EXECUTE_1); 465 { 466 brw_clip_kill_thread(c); 467 } 468 brw_ENDIF(p); 469 } 470 471 472 void brw_emit_unfilled_clip( struct brw_clip_compile *c ) 473 { 474 struct brw_codegen *p = &c->func; 475 476 c->need_direction = ((c->key.offset_ccw || c->key.offset_cw) || 477 (c->key.fill_ccw != c->key.fill_cw) || 478 c->key.fill_ccw == BRW_CLIP_FILL_MODE_CULL || 479 c->key.fill_cw == BRW_CLIP_FILL_MODE_CULL || 480 c->key.copy_bfc_cw || 481 c->key.copy_bfc_ccw); 482 483 brw_clip_tri_alloc_regs(c, 3 + c->key.nr_userclip + 6); 484 brw_clip_tri_init_vertices(c); 485 brw_clip_init_ff_sync(c); 486 487 assert(brw_clip_have_varying(c, VARYING_SLOT_EDGE)); 488 489 if (c->key.fill_ccw == BRW_CLIP_FILL_MODE_CULL && 490 c->key.fill_cw == BRW_CLIP_FILL_MODE_CULL) { 491 brw_clip_kill_thread(c); 492 return; 493 } 494 495 merge_edgeflags(c); 496 497 /* Need to use the inlist indirection here: 498 */ 499 if (c->need_direction) 500 compute_tri_direction(c); 501 502 if (c->key.fill_ccw == BRW_CLIP_FILL_MODE_CULL || 503 c->key.fill_cw == BRW_CLIP_FILL_MODE_CULL) 504 cull_direction(c); 505 506 if (c->key.offset_ccw || 507 c->key.offset_cw) 508 compute_offset(c); 509 510 if (c->key.copy_bfc_ccw || 511 c->key.copy_bfc_cw) 512 copy_bfc(c); 513 514 /* Need to do this whether we clip or not: 515 */ 516 if (c->key.contains_flat_varying) 517 brw_clip_tri_flat_shade(c); 518 519 brw_clip_init_clipmask(c); 520 brw_CMP(p, vec1(brw_null_reg()), BRW_CONDITIONAL_NZ, c->reg.planemask, brw_imm_ud(0)); 521 brw_IF(p, BRW_EXECUTE_1); 522 { 523 brw_clip_init_planes(c); 524 brw_clip_tri(c); 525 check_nr_verts(c); 526 } 527 brw_ENDIF(p); 528 529 emit_unfilled_primitives(c); 530 brw_clip_kill_thread(c); 531 } 532