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