1 /*
2  Copyright (C) Intel Corp.  2006.  All Rights Reserved.
3  Intel funded Tungsten Graphics (http://www.tungstengraphics.com) 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 <keith@tungstengraphics.com>
30   */
31 
32 #include "main/glheader.h"
33 #include "main/macros.h"
34 #include "main/enums.h"
35 #include "program/program.h"
36 
37 #include "intel_batchbuffer.h"
38 
39 #include "brw_defines.h"
40 #include "brw_context.h"
41 #include "brw_eu.h"
42 #include "brw_clip.h"
43 
44 
45 
46 /* This is performed against the original triangles, so no indirection
47  * required:
48 BZZZT!
49  */
compute_tri_direction(struct brw_clip_compile * c)50 static void compute_tri_direction( struct brw_clip_compile *c )
51 {
52    struct brw_compile *p = &c->func;
53    struct brw_reg e = c->reg.tmp0;
54    struct brw_reg f = c->reg.tmp1;
55    GLuint hpos_offset = brw_vert_result_to_offset(&c->vue_map,
56                                                   VERT_RESULT_HPOS);
57    struct brw_reg v0 = byte_offset(c->reg.vertex[0], hpos_offset);
58    struct brw_reg v1 = byte_offset(c->reg.vertex[1], hpos_offset);
59    struct brw_reg v2 = byte_offset(c->reg.vertex[2], hpos_offset);
60 
61 
62    struct brw_reg v0n = get_tmp(c);
63    struct brw_reg v1n = get_tmp(c);
64    struct brw_reg v2n = get_tmp(c);
65 
66    /* Convert to NDC.
67     * NOTE: We can't modify the original vertex coordinates,
68     * as it may impact further operations.
69     * So, we have to keep normalized coordinates in temp registers.
70     *
71     * TBD-KC
72     * Try to optimize unnecessary MOV's.
73     */
74    brw_MOV(p, v0n, v0);
75    brw_MOV(p, v1n, v1);
76    brw_MOV(p, v2n, v2);
77 
78    brw_clip_project_position(c, v0n);
79    brw_clip_project_position(c, v1n);
80    brw_clip_project_position(c, v2n);
81 
82    /* Calculate the vectors of two edges of the triangle:
83     */
84    brw_ADD(p, e, v0n, negate(v2n));
85    brw_ADD(p, f, v1n, negate(v2n));
86 
87    /* Take their crossproduct:
88     */
89    brw_set_access_mode(p, BRW_ALIGN_16);
90    brw_MUL(p, vec4(brw_null_reg()), brw_swizzle(e, 1,2,0,3),  brw_swizzle(f,2,0,1,3));
91    brw_MAC(p, vec4(e),  negate(brw_swizzle(e, 2,0,1,3)), brw_swizzle(f,1,2,0,3));
92    brw_set_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_compile *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_compile *p = &c->func;
129    GLuint conditional;
130 
131    /* Do we have any colors to copy?
132     */
133    if (!(brw_clip_have_vert_result(c, VERT_RESULT_COL0) &&
134          brw_clip_have_vert_result(c, VERT_RESULT_BFC0)) &&
135        !(brw_clip_have_vert_result(c, VERT_RESULT_COL1) &&
136          brw_clip_have_vert_result(c, VERT_RESULT_BFC1)))
137       return;
138 
139    /* In some wierd degnerate 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 wierd 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_vert_result(c, VERT_RESULT_COL0) &&
160              brw_clip_have_vert_result(c, VERT_RESULT_BFC0))
161 	    brw_MOV(p,
162 		    byte_offset(c->reg.vertex[i],
163                                 brw_vert_result_to_offset(&c->vue_map,
164                                                           VERT_RESULT_COL0)),
165 		    byte_offset(c->reg.vertex[i],
166                                 brw_vert_result_to_offset(&c->vue_map,
167                                                           VERT_RESULT_BFC0)));
168 
169 	 if (brw_clip_have_vert_result(c, VERT_RESULT_COL1) &&
170              brw_clip_have_vert_result(c, VERT_RESULT_BFC1))
171 	    brw_MOV(p,
172 		    byte_offset(c->reg.vertex[i],
173                                 brw_vert_result_to_offset(&c->vue_map,
174                                                           VERT_RESULT_COL1)),
175 		    byte_offset(c->reg.vertex[i],
176                                 brw_vert_result_to_offset(&c->vue_map,
177                                                           VERT_RESULT_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   offset *= MRD;
193 */
compute_offset(struct brw_clip_compile * c)194 static void compute_offset( struct brw_clip_compile *c )
195 {
196    struct brw_compile *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), 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), brw_abs(get_element(off, 0)), brw_abs(get_element(off, 1)));
210    brw_set_predicate_control(p, BRW_PREDICATE_NONE);
211 
212    brw_MUL(p, vec1(off), off, brw_imm_f(c->key.offset_factor));
213    brw_ADD(p, vec1(off), off, brw_imm_f(c->key.offset_units));
214 }
215 
216 
merge_edgeflags(struct brw_clip_compile * c)217 static void merge_edgeflags( struct brw_clip_compile *c )
218 {
219    struct brw_compile *p = &c->func;
220    struct brw_reg tmp0 = get_element_ud(c->reg.tmp0, 0);
221 
222    brw_AND(p, tmp0, get_element_ud(c->reg.R0, 2), brw_imm_ud(PRIM_MASK));
223    brw_CMP(p,
224 	   vec1(brw_null_reg()),
225 	   BRW_CONDITIONAL_EQ,
226 	   tmp0,
227 	   brw_imm_ud(_3DPRIM_POLYGON));
228 
229    /* Get away with using reg.vertex because we know that this is not
230     * a _3DPRIM_TRISTRIP_REVERSE:
231     */
232    brw_IF(p, BRW_EXECUTE_1);
233    {
234       brw_set_conditionalmod(p, BRW_CONDITIONAL_EQ);
235       brw_AND(p, vec1(brw_null_reg()), get_element_ud(c->reg.R0, 2), brw_imm_ud(1<<8));
236       brw_MOV(p, byte_offset(c->reg.vertex[0],
237                              brw_vert_result_to_offset(&c->vue_map,
238                                                        VERT_RESULT_EDGE)),
239               brw_imm_f(0));
240       brw_set_predicate_control(p, BRW_PREDICATE_NONE);
241 
242       brw_set_conditionalmod(p, BRW_CONDITIONAL_EQ);
243       brw_AND(p, vec1(brw_null_reg()), get_element_ud(c->reg.R0, 2), brw_imm_ud(1<<9));
244       brw_MOV(p, byte_offset(c->reg.vertex[2],
245                              brw_vert_result_to_offset(&c->vue_map,
246                                                        VERT_RESULT_EDGE)),
247               brw_imm_f(0));
248       brw_set_predicate_control(p, BRW_PREDICATE_NONE);
249    }
250    brw_ENDIF(p);
251 }
252 
253 
254 
apply_one_offset(struct brw_clip_compile * c,struct brw_indirect vert)255 static void apply_one_offset( struct brw_clip_compile *c,
256 			  struct brw_indirect vert )
257 {
258    struct brw_compile *p = &c->func;
259    GLuint ndc_offset = brw_vert_result_to_offset(&c->vue_map,
260                                                  BRW_VERT_RESULT_NDC);
261    struct brw_reg z = deref_1f(vert, ndc_offset +
262 			       2 * type_sz(BRW_REGISTER_TYPE_F));
263 
264    brw_ADD(p, z, z, vec1(c->reg.offset));
265 }
266 
267 
268 
269 /***********************************************************************
270  * Output clipped polygon as an unfilled primitive:
271  */
emit_lines(struct brw_clip_compile * c,bool do_offset)272 static void emit_lines(struct brw_clip_compile *c,
273 		       bool do_offset)
274 {
275    struct brw_compile *p = &c->func;
276    struct brw_indirect v0 = brw_indirect(0, 0);
277    struct brw_indirect v1 = brw_indirect(1, 0);
278    struct brw_indirect v0ptr = brw_indirect(2, 0);
279    struct brw_indirect v1ptr = brw_indirect(3, 0);
280 
281    /* Need a seperate loop for offset:
282     */
283    if (do_offset) {
284       brw_MOV(p, c->reg.loopcount, c->reg.nr_verts);
285       brw_MOV(p, get_addr_reg(v0ptr), brw_address(c->reg.inlist));
286 
287       brw_DO(p, BRW_EXECUTE_1);
288       {
289 	 brw_MOV(p, get_addr_reg(v0), deref_1uw(v0ptr, 0));
290 	 brw_ADD(p, get_addr_reg(v0ptr), get_addr_reg(v0ptr), brw_imm_uw(2));
291 
292 	 apply_one_offset(c, v0);
293 
294 	 brw_set_conditionalmod(p, BRW_CONDITIONAL_G);
295 	 brw_ADD(p, c->reg.loopcount, c->reg.loopcount, brw_imm_d(-1));
296       }
297       brw_WHILE(p);
298    }
299 
300    /* v1ptr = &inlist[nr_verts]
301     * *v1ptr = v0
302     */
303    brw_MOV(p, c->reg.loopcount, c->reg.nr_verts);
304    brw_MOV(p, get_addr_reg(v0ptr), brw_address(c->reg.inlist));
305    brw_ADD(p, get_addr_reg(v1ptr), get_addr_reg(v0ptr), retype(c->reg.nr_verts, BRW_REGISTER_TYPE_UW));
306    brw_ADD(p, get_addr_reg(v1ptr), get_addr_reg(v1ptr), retype(c->reg.nr_verts, BRW_REGISTER_TYPE_UW));
307    brw_MOV(p, deref_1uw(v1ptr, 0), deref_1uw(v0ptr, 0));
308 
309    brw_DO(p, BRW_EXECUTE_1);
310    {
311       brw_MOV(p, get_addr_reg(v0), deref_1uw(v0ptr, 0));
312       brw_MOV(p, get_addr_reg(v1), deref_1uw(v0ptr, 2));
313       brw_ADD(p, get_addr_reg(v0ptr), get_addr_reg(v0ptr), brw_imm_uw(2));
314 
315       /* draw edge if edgeflag != 0 */
316       brw_CMP(p,
317 	      vec1(brw_null_reg()), BRW_CONDITIONAL_NZ,
318 	      deref_1f(v0, brw_vert_result_to_offset(&c->vue_map,
319                                                      VERT_RESULT_EDGE)),
320 	      brw_imm_f(0));
321       brw_IF(p, BRW_EXECUTE_1);
322       {
323 	 brw_clip_emit_vue(c, v0, 1, 0,
324                            (_3DPRIM_LINESTRIP << URB_WRITE_PRIM_TYPE_SHIFT)
325                            | URB_WRITE_PRIM_START);
326 	 brw_clip_emit_vue(c, v1, 1, 0,
327                            (_3DPRIM_LINESTRIP << URB_WRITE_PRIM_TYPE_SHIFT)
328                            | URB_WRITE_PRIM_END);
329       }
330       brw_ENDIF(p);
331 
332       brw_set_conditionalmod(p, BRW_CONDITIONAL_NZ);
333       brw_ADD(p, c->reg.loopcount, c->reg.loopcount, brw_imm_d(-1));
334    }
335    brw_WHILE(p);
336 }
337 
338 
339 
emit_points(struct brw_clip_compile * c,bool do_offset)340 static void emit_points(struct brw_clip_compile *c,
341 			bool do_offset )
342 {
343    struct brw_compile *p = &c->func;
344 
345    struct brw_indirect v0 = brw_indirect(0, 0);
346    struct brw_indirect v0ptr = brw_indirect(2, 0);
347 
348    brw_MOV(p, c->reg.loopcount, c->reg.nr_verts);
349    brw_MOV(p, get_addr_reg(v0ptr), brw_address(c->reg.inlist));
350 
351    brw_DO(p, BRW_EXECUTE_1);
352    {
353       brw_MOV(p, get_addr_reg(v0), deref_1uw(v0ptr, 0));
354       brw_ADD(p, get_addr_reg(v0ptr), get_addr_reg(v0ptr), brw_imm_uw(2));
355 
356       /* draw if edgeflag != 0
357        */
358       brw_CMP(p,
359 	      vec1(brw_null_reg()), BRW_CONDITIONAL_NZ,
360 	      deref_1f(v0, brw_vert_result_to_offset(&c->vue_map,
361                                                      VERT_RESULT_EDGE)),
362 	      brw_imm_f(0));
363       brw_IF(p, BRW_EXECUTE_1);
364       {
365 	 if (do_offset)
366 	    apply_one_offset(c, v0);
367 
368 	 brw_clip_emit_vue(c, v0, 1, 0,
369                            (_3DPRIM_POINTLIST << URB_WRITE_PRIM_TYPE_SHIFT)
370                            | URB_WRITE_PRIM_START | URB_WRITE_PRIM_END);
371       }
372       brw_ENDIF(p);
373 
374       brw_set_conditionalmod(p, BRW_CONDITIONAL_NZ);
375       brw_ADD(p, c->reg.loopcount, c->reg.loopcount, brw_imm_d(-1));
376    }
377    brw_WHILE(p);
378 }
379 
380 
381 
382 
383 
384 
385 
emit_primitives(struct brw_clip_compile * c,GLuint mode,bool do_offset)386 static void emit_primitives( struct brw_clip_compile *c,
387 			     GLuint mode,
388 			     bool do_offset )
389 {
390    switch (mode) {
391    case CLIP_FILL:
392       brw_clip_tri_emit_polygon(c);
393       break;
394 
395    case CLIP_LINE:
396       emit_lines(c, do_offset);
397       break;
398 
399    case CLIP_POINT:
400       emit_points(c, do_offset);
401       break;
402 
403    case CLIP_CULL:
404       assert(0);
405       break;
406    }
407 }
408 
409 
410 
emit_unfilled_primitives(struct brw_clip_compile * c)411 static void emit_unfilled_primitives( struct brw_clip_compile *c )
412 {
413    struct brw_compile *p = &c->func;
414 
415    /* Direction culling has already been done.
416     */
417    if (c->key.fill_ccw != c->key.fill_cw &&
418        c->key.fill_ccw != CLIP_CULL &&
419        c->key.fill_cw != CLIP_CULL)
420    {
421       brw_CMP(p,
422 	      vec1(brw_null_reg()),
423 	      BRW_CONDITIONAL_GE,
424 	      get_element(c->reg.dir, 2),
425 	      brw_imm_f(0));
426 
427       brw_IF(p, BRW_EXECUTE_1);
428       {
429 	 emit_primitives(c, c->key.fill_ccw, c->key.offset_ccw);
430       }
431       brw_ELSE(p);
432       {
433 	 emit_primitives(c, c->key.fill_cw, c->key.offset_cw);
434       }
435       brw_ENDIF(p);
436    }
437    else if (c->key.fill_cw != CLIP_CULL) {
438       emit_primitives(c, c->key.fill_cw, c->key.offset_cw);
439    }
440    else if (c->key.fill_ccw != CLIP_CULL) {
441       emit_primitives(c, c->key.fill_ccw, c->key.offset_ccw);
442    }
443 }
444 
445 
446 
447 
check_nr_verts(struct brw_clip_compile * c)448 static void check_nr_verts( struct brw_clip_compile *c )
449 {
450    struct brw_compile *p = &c->func;
451 
452    brw_CMP(p, vec1(brw_null_reg()), BRW_CONDITIONAL_L, c->reg.nr_verts, brw_imm_d(3));
453    brw_IF(p, BRW_EXECUTE_1);
454    {
455       brw_clip_kill_thread(c);
456    }
457    brw_ENDIF(p);
458 }
459 
460 
brw_emit_unfilled_clip(struct brw_clip_compile * c)461 void brw_emit_unfilled_clip( struct brw_clip_compile *c )
462 {
463    struct brw_compile *p = &c->func;
464 
465    c->need_direction = ((c->key.offset_ccw || c->key.offset_cw) ||
466 			(c->key.fill_ccw != c->key.fill_cw) ||
467 			c->key.fill_ccw == CLIP_CULL ||
468 			c->key.fill_cw == CLIP_CULL ||
469 			c->key.copy_bfc_cw ||
470 			c->key.copy_bfc_ccw);
471 
472    brw_clip_tri_alloc_regs(c, 3 + c->key.nr_userclip + 6);
473    brw_clip_tri_init_vertices(c);
474    brw_clip_init_ff_sync(c);
475 
476    assert(brw_clip_have_vert_result(c, VERT_RESULT_EDGE));
477 
478    if (c->key.fill_ccw == CLIP_CULL &&
479        c->key.fill_cw == CLIP_CULL) {
480       brw_clip_kill_thread(c);
481       return;
482    }
483 
484    merge_edgeflags(c);
485 
486    /* Need to use the inlist indirection here:
487     */
488    if (c->need_direction)
489       compute_tri_direction(c);
490 
491    if (c->key.fill_ccw == CLIP_CULL ||
492        c->key.fill_cw == CLIP_CULL)
493       cull_direction(c);
494 
495    if (c->key.offset_ccw ||
496        c->key.offset_cw)
497       compute_offset(c);
498 
499    if (c->key.copy_bfc_ccw ||
500        c->key.copy_bfc_cw)
501       copy_bfc(c);
502 
503    /* Need to do this whether we clip or not:
504     */
505    if (c->key.do_flat_shading)
506       brw_clip_tri_flat_shade(c);
507 
508    brw_clip_init_clipmask(c);
509    brw_CMP(p, vec1(brw_null_reg()), BRW_CONDITIONAL_NZ, c->reg.planemask, brw_imm_ud(0));
510    brw_IF(p, BRW_EXECUTE_1);
511    {
512       brw_clip_init_planes(c);
513       brw_clip_tri(c);
514       check_nr_verts(c);
515    }
516    brw_ENDIF(p);
517 
518    emit_unfilled_primitives(c);
519    brw_clip_kill_thread(c);
520 }
521 
522 
523 
524