• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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