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 
38 
39 /* This is performed against the original triangles, so no indirection
40  * required:
41 BZZZT!
42  */
compute_tri_direction(struct brw_clip_compile * c)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 
cull_direction(struct brw_clip_compile * c)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 
copy_bfc(struct brw_clip_compile * c)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 */
compute_offset(struct brw_clip_compile * c)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 
merge_edgeflags(struct brw_clip_compile * c)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 
apply_one_offset(struct brw_clip_compile * c,struct brw_indirect vert)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  */
emit_lines(struct brw_clip_compile * c,bool do_offset)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 
emit_points(struct brw_clip_compile * c,bool do_offset)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 
emit_primitives(struct brw_clip_compile * c,GLuint mode,bool do_offset)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 
emit_unfilled_primitives(struct brw_clip_compile * c)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 
check_nr_verts(struct brw_clip_compile * c)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 
brw_emit_unfilled_clip(struct brw_clip_compile * c)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