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