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