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
39static void release_tmps( struct brw_clip_compile *c )
40{
41   c->last_tmp = c->first_tmp;
42}
43
44
45void brw_clip_tri_alloc_regs( struct brw_clip_compile *c,
46			      GLuint nr_verts )
47{
48   const struct intel_device_info *devinfo = c->func.devinfo;
49   GLuint i = 0,j;
50
51   /* Register usage is static, precompute here:
52    */
53   c->reg.R0 = retype(brw_vec8_grf(i, 0), BRW_REGISTER_TYPE_UD); i++;
54
55   if (c->key.nr_userclip) {
56      c->reg.fixed_planes = brw_vec4_grf(i, 0);
57      i += (6 + c->key.nr_userclip + 1) / 2;
58
59      c->prog_data.curb_read_length = (6 + c->key.nr_userclip + 1) / 2;
60   }
61   else
62      c->prog_data.curb_read_length = 0;
63
64
65   /* Payload vertices plus space for more generated vertices:
66    */
67   for (j = 0; j < nr_verts; j++) {
68      c->reg.vertex[j] = brw_vec4_grf(i, 0);
69      i += c->nr_regs;
70   }
71
72   if (c->vue_map.num_slots % 2 && nr_verts > 0) {
73      /* The VUE has an odd number of slots so the last register is only half
74       * used.  Fill the second half with zero.
75       */
76      for (j = 0; j < 3; j++) {
77	 GLuint delta = brw_vue_slot_to_offset(c->vue_map.num_slots);
78
79	 brw_MOV(&c->func, byte_offset(c->reg.vertex[j], delta), brw_imm_f(0));
80      }
81   }
82
83   c->reg.t          = brw_vec1_grf(i, 0);
84   c->reg.loopcount  = retype(brw_vec1_grf(i, 1), BRW_REGISTER_TYPE_D);
85   c->reg.nr_verts   = retype(brw_vec1_grf(i, 2), BRW_REGISTER_TYPE_UD);
86   c->reg.planemask  = retype(brw_vec1_grf(i, 3), BRW_REGISTER_TYPE_UD);
87   c->reg.plane_equation = brw_vec4_grf(i, 4);
88   i++;
89
90   c->reg.dpPrev     = brw_vec1_grf(i, 0); /* fixme - dp4 will clobber r.1,2,3 */
91   c->reg.dp         = brw_vec1_grf(i, 4);
92   i++;
93
94   c->reg.inlist     = brw_uw16_reg(BRW_GENERAL_REGISTER_FILE, i, 0);
95   i++;
96
97   c->reg.outlist    = brw_uw16_reg(BRW_GENERAL_REGISTER_FILE, i, 0);
98   i++;
99
100   c->reg.freelist   = brw_uw16_reg(BRW_GENERAL_REGISTER_FILE, i, 0);
101   i++;
102
103   if (!c->key.nr_userclip) {
104      c->reg.fixed_planes = brw_vec8_grf(i, 0);
105      i++;
106   }
107
108   if (c->key.do_unfilled) {
109      c->reg.dir     = brw_vec4_grf(i, 0);
110      c->reg.offset  = brw_vec4_grf(i, 4);
111      i++;
112      c->reg.tmp0    = brw_vec4_grf(i, 0);
113      c->reg.tmp1    = brw_vec4_grf(i, 4);
114      i++;
115   }
116
117   c->reg.vertex_src_mask = retype(brw_vec1_grf(i, 0), BRW_REGISTER_TYPE_UD);
118   c->reg.clipdistance_offset = retype(brw_vec1_grf(i, 1), BRW_REGISTER_TYPE_W);
119   i++;
120
121   if (devinfo->ver == 5) {
122      c->reg.ff_sync = retype(brw_vec1_grf(i, 0), BRW_REGISTER_TYPE_UD);
123      i++;
124   }
125
126   c->first_tmp = i;
127   c->last_tmp = i;
128
129   c->prog_data.urb_read_length = c->nr_regs; /* ? */
130   c->prog_data.total_grf = i;
131}
132
133
134
135void brw_clip_tri_init_vertices( struct brw_clip_compile *c )
136{
137   struct brw_codegen *p = &c->func;
138   struct brw_reg tmp0 = c->reg.loopcount; /* handy temporary */
139
140   /* Initial list of indices for incoming vertices:
141    */
142   brw_AND(p, tmp0, get_element_ud(c->reg.R0, 2), brw_imm_ud(PRIM_MASK));
143   brw_CMP(p,
144	   vec1(brw_null_reg()),
145	   BRW_CONDITIONAL_EQ,
146	   tmp0,
147	   brw_imm_ud(_3DPRIM_TRISTRIP_REVERSE));
148
149   /* XXX: Is there an easier way to do this?  Need to reverse every
150    * second tristrip element:  Can ignore sometimes?
151    */
152   brw_IF(p, BRW_EXECUTE_1);
153   {
154      brw_MOV(p, get_element(c->reg.inlist, 0),  brw_address(c->reg.vertex[1]) );
155      brw_MOV(p, get_element(c->reg.inlist, 1),  brw_address(c->reg.vertex[0]) );
156      if (c->need_direction)
157	 brw_MOV(p, c->reg.dir, brw_imm_f(-1));
158   }
159   brw_ELSE(p);
160   {
161      brw_MOV(p, get_element(c->reg.inlist, 0),  brw_address(c->reg.vertex[0]) );
162      brw_MOV(p, get_element(c->reg.inlist, 1),  brw_address(c->reg.vertex[1]) );
163      if (c->need_direction)
164	 brw_MOV(p, c->reg.dir, brw_imm_f(1));
165   }
166   brw_ENDIF(p);
167
168   brw_MOV(p, get_element(c->reg.inlist, 2),  brw_address(c->reg.vertex[2]) );
169   brw_MOV(p, brw_vec8_grf(c->reg.outlist.nr, 0), brw_imm_f(0));
170   brw_MOV(p, c->reg.nr_verts, brw_imm_ud(3));
171}
172
173
174
175void brw_clip_tri_flat_shade( struct brw_clip_compile *c )
176{
177   struct brw_codegen *p = &c->func;
178   struct brw_reg tmp0 = c->reg.loopcount; /* handy temporary */
179
180   brw_AND(p, tmp0, get_element_ud(c->reg.R0, 2), brw_imm_ud(PRIM_MASK));
181   brw_CMP(p,
182	   vec1(brw_null_reg()),
183	   BRW_CONDITIONAL_EQ,
184	   tmp0,
185	   brw_imm_ud(_3DPRIM_POLYGON));
186
187   brw_IF(p, BRW_EXECUTE_1);
188   {
189      brw_clip_copy_flatshaded_attributes(c, 1, 0);
190      brw_clip_copy_flatshaded_attributes(c, 2, 0);
191   }
192   brw_ELSE(p);
193   {
194      if (c->key.pv_first) {
195	 brw_CMP(p,
196		 vec1(brw_null_reg()),
197		 BRW_CONDITIONAL_EQ,
198		 tmp0,
199		 brw_imm_ud(_3DPRIM_TRIFAN));
200	 brw_IF(p, BRW_EXECUTE_1);
201	 {
202	    brw_clip_copy_flatshaded_attributes(c, 0, 1);
203	    brw_clip_copy_flatshaded_attributes(c, 2, 1);
204	 }
205	 brw_ELSE(p);
206	 {
207	    brw_clip_copy_flatshaded_attributes(c, 1, 0);
208	    brw_clip_copy_flatshaded_attributes(c, 2, 0);
209	 }
210	 brw_ENDIF(p);
211      }
212      else {
213         brw_clip_copy_flatshaded_attributes(c, 0, 2);
214         brw_clip_copy_flatshaded_attributes(c, 1, 2);
215      }
216   }
217   brw_ENDIF(p);
218}
219
220
221/**
222 * Loads the clip distance for a vertex into `dst`, and ends with
223 * a comparison of it to zero with the condition `cond`.
224 *
225 * - If using a fixed plane, the distance is dot(hpos, plane).
226 * - If using a user clip plane, the distance is directly available in the vertex.
227 */
228static inline void
229load_clip_distance(struct brw_clip_compile *c, struct brw_indirect vtx,
230                struct brw_reg dst, GLuint hpos_offset, int cond)
231{
232   struct brw_codegen *p = &c->func;
233
234   dst = vec4(dst);
235   brw_AND(p, vec1(brw_null_reg()), c->reg.vertex_src_mask, brw_imm_ud(1));
236   brw_inst_set_cond_modifier(p->devinfo, brw_last_inst, BRW_CONDITIONAL_NZ);
237   brw_IF(p, BRW_EXECUTE_1);
238   {
239      struct brw_indirect temp_ptr = brw_indirect(7, 0);
240      brw_ADD(p, get_addr_reg(temp_ptr), get_addr_reg(vtx), c->reg.clipdistance_offset);
241      brw_MOV(p, vec1(dst), deref_1f(temp_ptr, 0));
242   }
243   brw_ELSE(p);
244   {
245      brw_MOV(p, dst, deref_4f(vtx, hpos_offset));
246      brw_DP4(p, dst, dst, c->reg.plane_equation);
247   }
248   brw_ENDIF(p);
249
250   brw_CMP(p, brw_null_reg(), cond, vec1(dst), brw_imm_f(0.0f));
251}
252
253
254/* Use mesa's clipping algorithms, translated to GFX4 assembly.
255 */
256void brw_clip_tri( struct brw_clip_compile *c )
257{
258   struct brw_codegen *p = &c->func;
259   struct brw_indirect vtx = brw_indirect(0, 0);
260   struct brw_indirect vtxPrev = brw_indirect(1, 0);
261   struct brw_indirect vtxOut = brw_indirect(2, 0);
262   struct brw_indirect plane_ptr = brw_indirect(3, 0);
263   struct brw_indirect inlist_ptr = brw_indirect(4, 0);
264   struct brw_indirect outlist_ptr = brw_indirect(5, 0);
265   struct brw_indirect freelist_ptr = brw_indirect(6, 0);
266   GLuint hpos_offset = brw_varying_to_offset(&c->vue_map, VARYING_SLOT_POS);
267   GLint clipdist0_offset = c->key.nr_userclip
268      ? brw_varying_to_offset(&c->vue_map, VARYING_SLOT_CLIP_DIST0)
269      : 0;
270
271   brw_MOV(p, get_addr_reg(vtxPrev),     brw_address(c->reg.vertex[2]) );
272   brw_MOV(p, get_addr_reg(plane_ptr),   brw_clip_plane0_address(c));
273   brw_MOV(p, get_addr_reg(inlist_ptr),  brw_address(c->reg.inlist));
274   brw_MOV(p, get_addr_reg(outlist_ptr), brw_address(c->reg.outlist));
275
276   brw_MOV(p, get_addr_reg(freelist_ptr), brw_address(c->reg.vertex[3]) );
277
278   /* Set the initial vertex source mask: The first 6 planes are the bounds
279    * of the view volume; the next 8 planes are the user clipping planes.
280    */
281   brw_MOV(p, c->reg.vertex_src_mask, brw_imm_ud(0x3fc0));
282
283   /* Set the initial clipdistance offset to be 6 floats before gl_ClipDistance[0].
284    * We'll increment 6 times before we start hitting actual user clipping. */
285   brw_MOV(p, c->reg.clipdistance_offset, brw_imm_d(clipdist0_offset - 6*sizeof(float)));
286
287   brw_DO(p, BRW_EXECUTE_1);
288   {
289      /* if (planemask & 1)
290       */
291      brw_AND(p, vec1(brw_null_reg()), c->reg.planemask, brw_imm_ud(1));
292      brw_inst_set_cond_modifier(p->devinfo, brw_last_inst, BRW_CONDITIONAL_NZ);
293
294      brw_IF(p, BRW_EXECUTE_1);
295      {
296	 /* vtxOut = freelist_ptr++
297	  */
298	 brw_MOV(p, get_addr_reg(vtxOut),       get_addr_reg(freelist_ptr) );
299	 brw_ADD(p, get_addr_reg(freelist_ptr), get_addr_reg(freelist_ptr), brw_imm_uw(c->nr_regs * REG_SIZE));
300
301	 if (c->key.nr_userclip)
302	    brw_MOV(p, c->reg.plane_equation, deref_4f(plane_ptr, 0));
303	 else
304	    brw_MOV(p, c->reg.plane_equation, deref_4b(plane_ptr, 0));
305
306	 brw_MOV(p, c->reg.loopcount, c->reg.nr_verts);
307	 brw_MOV(p, c->reg.nr_verts, brw_imm_ud(0));
308
309	 brw_DO(p, BRW_EXECUTE_1);
310	 {
311	    /* vtx = *input_ptr;
312	     */
313	    brw_MOV(p, get_addr_reg(vtx), deref_1uw(inlist_ptr, 0));
314
315            load_clip_distance(c, vtxPrev, c->reg.dpPrev, hpos_offset, BRW_CONDITIONAL_L);
316	    /* (prev < 0.0f) */
317	    brw_IF(p, BRW_EXECUTE_1);
318	    {
319               load_clip_distance(c, vtx, c->reg.dp, hpos_offset, BRW_CONDITIONAL_GE);
320	       /* IS_POSITIVE(next)
321		*/
322	       brw_IF(p, BRW_EXECUTE_1);
323	       {
324
325		  /* Coming back in.
326		   */
327		  brw_ADD(p, c->reg.t, c->reg.dpPrev, negate(c->reg.dp));
328		  brw_math_invert(p, c->reg.t, c->reg.t);
329		  brw_MUL(p, c->reg.t, c->reg.t, c->reg.dpPrev);
330
331		  /* If (vtxOut == 0) vtxOut = vtxPrev
332		   */
333		  brw_CMP(p, vec1(brw_null_reg()), BRW_CONDITIONAL_EQ, get_addr_reg(vtxOut), brw_imm_uw(0) );
334                  brw_MOV(p, get_addr_reg(vtxOut), get_addr_reg(vtxPrev));
335                  brw_inst_set_pred_control(p->devinfo, brw_last_inst,
336                                            BRW_PREDICATE_NORMAL);
337
338		  brw_clip_interp_vertex(c, vtxOut, vtxPrev, vtx, c->reg.t, false);
339
340		  /* *outlist_ptr++ = vtxOut;
341		   * nr_verts++;
342		   * vtxOut = 0;
343		   */
344		  brw_MOV(p, deref_1uw(outlist_ptr, 0), get_addr_reg(vtxOut));
345		  brw_ADD(p, get_addr_reg(outlist_ptr), get_addr_reg(outlist_ptr), brw_imm_uw(sizeof(short)));
346		  brw_ADD(p, c->reg.nr_verts, c->reg.nr_verts, brw_imm_ud(1));
347		  brw_MOV(p, get_addr_reg(vtxOut), brw_imm_uw(0) );
348	       }
349	       brw_ENDIF(p);
350
351	    }
352	    brw_ELSE(p);
353	    {
354	       /* *outlist_ptr++ = vtxPrev;
355		* nr_verts++;
356		*/
357	       brw_MOV(p, deref_1uw(outlist_ptr, 0), get_addr_reg(vtxPrev));
358	       brw_ADD(p, get_addr_reg(outlist_ptr), get_addr_reg(outlist_ptr), brw_imm_uw(sizeof(short)));
359	       brw_ADD(p, c->reg.nr_verts, c->reg.nr_verts, brw_imm_ud(1));
360
361               load_clip_distance(c, vtx, c->reg.dp, hpos_offset, BRW_CONDITIONAL_L);
362	       /* (next < 0.0f)
363		*/
364	       brw_IF(p, BRW_EXECUTE_1);
365	       {
366		  /* Going out of bounds.  Avoid division by zero as we
367		   * know dp != dpPrev from DIFFERENT_SIGNS, above.
368		   */
369		  brw_ADD(p, c->reg.t, c->reg.dp, negate(c->reg.dpPrev));
370		  brw_math_invert(p, c->reg.t, c->reg.t);
371		  brw_MUL(p, c->reg.t, c->reg.t, c->reg.dp);
372
373		  /* If (vtxOut == 0) vtxOut = vtx
374		   */
375		  brw_CMP(p, vec1(brw_null_reg()), BRW_CONDITIONAL_EQ, get_addr_reg(vtxOut), brw_imm_uw(0) );
376                  brw_MOV(p, get_addr_reg(vtxOut), get_addr_reg(vtx));
377                  brw_inst_set_pred_control(p->devinfo, brw_last_inst,
378                                            BRW_PREDICATE_NORMAL);
379
380		  brw_clip_interp_vertex(c, vtxOut, vtx, vtxPrev, c->reg.t, true);
381
382		  /* *outlist_ptr++ = vtxOut;
383		   * nr_verts++;
384		   * vtxOut = 0;
385		   */
386		  brw_MOV(p, deref_1uw(outlist_ptr, 0), get_addr_reg(vtxOut));
387		  brw_ADD(p, get_addr_reg(outlist_ptr), get_addr_reg(outlist_ptr), brw_imm_uw(sizeof(short)));
388		  brw_ADD(p, c->reg.nr_verts, c->reg.nr_verts, brw_imm_ud(1));
389		  brw_MOV(p, get_addr_reg(vtxOut), brw_imm_uw(0) );
390	       }
391	       brw_ENDIF(p);
392	    }
393	    brw_ENDIF(p);
394
395	    /* vtxPrev = vtx;
396	     * inlist_ptr++;
397	     */
398	    brw_MOV(p, get_addr_reg(vtxPrev), get_addr_reg(vtx));
399	    brw_ADD(p, get_addr_reg(inlist_ptr), get_addr_reg(inlist_ptr), brw_imm_uw(sizeof(short)));
400
401	    /* while (--loopcount != 0)
402	     */
403	    brw_ADD(p, c->reg.loopcount, c->reg.loopcount, brw_imm_d(-1));
404            brw_inst_set_cond_modifier(p->devinfo, brw_last_inst, BRW_CONDITIONAL_NZ);
405	 }
406	 brw_WHILE(p);
407         brw_inst_set_pred_control(p->devinfo, brw_last_inst, BRW_PREDICATE_NORMAL);
408
409	 /* vtxPrev = *(outlist_ptr-1)  OR: outlist[nr_verts-1]
410	  * inlist = outlist
411	  * inlist_ptr = &inlist[0]
412	  * outlist_ptr = &outlist[0]
413	  */
414	 brw_ADD(p, get_addr_reg(outlist_ptr), get_addr_reg(outlist_ptr), brw_imm_w(-2));
415	 brw_MOV(p, get_addr_reg(vtxPrev), deref_1uw(outlist_ptr, 0));
416	 brw_MOV(p, brw_vec8_grf(c->reg.inlist.nr, 0), brw_vec8_grf(c->reg.outlist.nr, 0));
417	 brw_MOV(p, get_addr_reg(inlist_ptr), brw_address(c->reg.inlist));
418	 brw_MOV(p, get_addr_reg(outlist_ptr), brw_address(c->reg.outlist));
419      }
420      brw_ENDIF(p);
421
422      /* plane_ptr++;
423       */
424      brw_ADD(p, get_addr_reg(plane_ptr), get_addr_reg(plane_ptr), brw_clip_plane_stride(c));
425
426      /* nr_verts >= 3
427       */
428      brw_CMP(p,
429	      vec1(brw_null_reg()),
430	      BRW_CONDITIONAL_GE,
431	      c->reg.nr_verts,
432	      brw_imm_ud(3));
433      brw_set_default_predicate_control(p, BRW_PREDICATE_NORMAL);
434
435      /* && (planemask>>=1) != 0
436       */
437      brw_SHR(p, c->reg.planemask, c->reg.planemask, brw_imm_ud(1));
438      brw_inst_set_cond_modifier(p->devinfo, brw_last_inst, BRW_CONDITIONAL_NZ);
439      brw_SHR(p, c->reg.vertex_src_mask, c->reg.vertex_src_mask, brw_imm_ud(1));
440      brw_ADD(p, c->reg.clipdistance_offset, c->reg.clipdistance_offset, brw_imm_w(sizeof(float)));
441   }
442   brw_WHILE(p);
443   brw_set_default_predicate_control(p, BRW_PREDICATE_NONE);
444}
445
446
447
448void brw_clip_tri_emit_polygon(struct brw_clip_compile *c)
449{
450   struct brw_codegen *p = &c->func;
451
452   /* for (loopcount = nr_verts-2; loopcount > 0; loopcount--)
453    */
454   brw_ADD(p,
455	   c->reg.loopcount,
456	   c->reg.nr_verts,
457	   brw_imm_d(-2));
458   brw_inst_set_cond_modifier(p->devinfo, brw_last_inst, BRW_CONDITIONAL_G);
459
460   brw_IF(p, BRW_EXECUTE_1);
461   {
462      struct brw_indirect v0 = brw_indirect(0, 0);
463      struct brw_indirect vptr = brw_indirect(1, 0);
464
465      brw_MOV(p, get_addr_reg(vptr), brw_address(c->reg.inlist));
466      brw_MOV(p, get_addr_reg(v0), deref_1uw(vptr, 0));
467
468      brw_clip_emit_vue(c, v0, BRW_URB_WRITE_ALLOCATE_COMPLETE,
469                        ((_3DPRIM_TRIFAN << URB_WRITE_PRIM_TYPE_SHIFT)
470                         | URB_WRITE_PRIM_START));
471
472      brw_ADD(p, get_addr_reg(vptr), get_addr_reg(vptr), brw_imm_uw(2));
473      brw_MOV(p, get_addr_reg(v0), deref_1uw(vptr, 0));
474
475      brw_DO(p, BRW_EXECUTE_1);
476      {
477	 brw_clip_emit_vue(c, v0, BRW_URB_WRITE_ALLOCATE_COMPLETE,
478                           (_3DPRIM_TRIFAN << URB_WRITE_PRIM_TYPE_SHIFT));
479
480	 brw_ADD(p, get_addr_reg(vptr), get_addr_reg(vptr), brw_imm_uw(2));
481	 brw_MOV(p, get_addr_reg(v0), deref_1uw(vptr, 0));
482
483	 brw_ADD(p, c->reg.loopcount, c->reg.loopcount, brw_imm_d(-1));
484         brw_inst_set_cond_modifier(p->devinfo, brw_last_inst, BRW_CONDITIONAL_NZ);
485      }
486      brw_WHILE(p);
487      brw_inst_set_pred_control(p->devinfo, brw_last_inst, BRW_PREDICATE_NORMAL);
488
489      brw_clip_emit_vue(c, v0, BRW_URB_WRITE_EOT_COMPLETE,
490                        ((_3DPRIM_TRIFAN << URB_WRITE_PRIM_TYPE_SHIFT)
491                         | URB_WRITE_PRIM_END));
492   }
493   brw_ENDIF(p);
494}
495
496static void do_clip_tri( struct brw_clip_compile *c )
497{
498   brw_clip_init_planes(c);
499
500   brw_clip_tri(c);
501}
502
503
504static void maybe_do_clip_tri( struct brw_clip_compile *c )
505{
506   struct brw_codegen *p = &c->func;
507
508   brw_CMP(p, vec1(brw_null_reg()), BRW_CONDITIONAL_NZ, c->reg.planemask, brw_imm_ud(0));
509   brw_IF(p, BRW_EXECUTE_1);
510   {
511      do_clip_tri(c);
512   }
513   brw_ENDIF(p);
514}
515
516static void brw_clip_test( struct brw_clip_compile *c )
517{
518    struct brw_reg t = retype(get_tmp(c), BRW_REGISTER_TYPE_UD);
519    struct brw_reg t1 = retype(get_tmp(c), BRW_REGISTER_TYPE_UD);
520    struct brw_reg t2 = retype(get_tmp(c), BRW_REGISTER_TYPE_UD);
521    struct brw_reg t3 = retype(get_tmp(c), BRW_REGISTER_TYPE_UD);
522
523    struct brw_reg v0 = get_tmp(c);
524    struct brw_reg v1 = get_tmp(c);
525    struct brw_reg v2 = get_tmp(c);
526
527    struct brw_indirect vt0 = brw_indirect(0, 0);
528    struct brw_indirect vt1 = brw_indirect(1, 0);
529    struct brw_indirect vt2 = brw_indirect(2, 0);
530
531    struct brw_codegen *p = &c->func;
532    struct brw_reg tmp0 = c->reg.loopcount; /* handy temporary */
533
534    GLuint hpos_offset = brw_varying_to_offset(&c->vue_map,
535                                                   VARYING_SLOT_POS);
536
537    brw_MOV(p, get_addr_reg(vt0), brw_address(c->reg.vertex[0]));
538    brw_MOV(p, get_addr_reg(vt1), brw_address(c->reg.vertex[1]));
539    brw_MOV(p, get_addr_reg(vt2), brw_address(c->reg.vertex[2]));
540    brw_MOV(p, v0, deref_4f(vt0, hpos_offset));
541    brw_MOV(p, v1, deref_4f(vt1, hpos_offset));
542    brw_MOV(p, v2, deref_4f(vt2, hpos_offset));
543    brw_AND(p, c->reg.planemask, c->reg.planemask, brw_imm_ud(~0x3f));
544
545    /* test nearz, xmin, ymin plane */
546    /* clip.xyz < -clip.w */
547    brw_CMP(p, t1, BRW_CONDITIONAL_L, v0, negate(get_element(v0, 3)));
548    brw_CMP(p, t2, BRW_CONDITIONAL_L, v1, negate(get_element(v1, 3)));
549    brw_CMP(p, t3, BRW_CONDITIONAL_L, v2, negate(get_element(v2, 3)));
550
551    /* All vertices are outside of a plane, rejected */
552    brw_AND(p, t, t1, t2);
553    brw_AND(p, t, t, t3);
554    brw_OR(p, tmp0, get_element(t, 0), get_element(t, 1));
555    brw_OR(p, tmp0, tmp0, get_element(t, 2));
556    brw_AND(p, brw_null_reg(), tmp0, brw_imm_ud(0x1));
557    brw_inst_set_cond_modifier(p->devinfo, brw_last_inst, BRW_CONDITIONAL_NZ);
558    brw_IF(p, BRW_EXECUTE_1);
559    {
560        brw_clip_kill_thread(c);
561    }
562    brw_ENDIF(p);
563    brw_set_default_predicate_control(p, BRW_PREDICATE_NONE);
564
565    /* some vertices are inside a plane, some are outside,need to clip */
566    brw_XOR(p, t, t1, t2);
567    brw_XOR(p, t1, t2, t3);
568    brw_OR(p, t, t, t1);
569    brw_AND(p, t, t, brw_imm_ud(0x1));
570    brw_CMP(p, brw_null_reg(), BRW_CONDITIONAL_NZ,
571            get_element(t, 0), brw_imm_ud(0));
572    brw_OR(p, c->reg.planemask, c->reg.planemask, brw_imm_ud((1<<5)));
573    brw_inst_set_pred_control(p->devinfo, brw_last_inst, BRW_PREDICATE_NORMAL);
574    brw_CMP(p, brw_null_reg(), BRW_CONDITIONAL_NZ,
575            get_element(t, 1), brw_imm_ud(0));
576    brw_OR(p, c->reg.planemask, c->reg.planemask, brw_imm_ud((1<<3)));
577    brw_inst_set_pred_control(p->devinfo, brw_last_inst, BRW_PREDICATE_NORMAL);
578    brw_CMP(p, brw_null_reg(), BRW_CONDITIONAL_NZ,
579            get_element(t, 2), brw_imm_ud(0));
580    brw_OR(p, c->reg.planemask, c->reg.planemask, brw_imm_ud((1<<1)));
581    brw_inst_set_pred_control(p->devinfo, brw_last_inst, BRW_PREDICATE_NORMAL);
582
583    /* test farz, xmax, ymax plane */
584    /* clip.xyz > clip.w */
585    brw_CMP(p, t1, BRW_CONDITIONAL_G, v0, get_element(v0, 3));
586    brw_CMP(p, t2, BRW_CONDITIONAL_G, v1, get_element(v1, 3));
587    brw_CMP(p, t3, BRW_CONDITIONAL_G, v2, get_element(v2, 3));
588
589    /* All vertices are outside of a plane, rejected */
590    brw_AND(p, t, t1, t2);
591    brw_AND(p, t, t, t3);
592    brw_OR(p, tmp0, get_element(t, 0), get_element(t, 1));
593    brw_OR(p, tmp0, tmp0, get_element(t, 2));
594    brw_AND(p, brw_null_reg(), tmp0, brw_imm_ud(0x1));
595    brw_inst_set_cond_modifier(p->devinfo, brw_last_inst, BRW_CONDITIONAL_NZ);
596    brw_IF(p, BRW_EXECUTE_1);
597    {
598        brw_clip_kill_thread(c);
599    }
600    brw_ENDIF(p);
601    brw_set_default_predicate_control(p, BRW_PREDICATE_NONE);
602
603    /* some vertices are inside a plane, some are outside,need to clip */
604    brw_XOR(p, t, t1, t2);
605    brw_XOR(p, t1, t2, t3);
606    brw_OR(p, t, t, t1);
607    brw_AND(p, t, t, brw_imm_ud(0x1));
608    brw_CMP(p, brw_null_reg(), BRW_CONDITIONAL_NZ,
609            get_element(t, 0), brw_imm_ud(0));
610    brw_OR(p, c->reg.planemask, c->reg.planemask, brw_imm_ud((1<<4)));
611    brw_inst_set_pred_control(p->devinfo, brw_last_inst, BRW_PREDICATE_NORMAL);
612    brw_CMP(p, brw_null_reg(), BRW_CONDITIONAL_NZ,
613            get_element(t, 1), brw_imm_ud(0));
614    brw_OR(p, c->reg.planemask, c->reg.planemask, brw_imm_ud((1<<2)));
615    brw_inst_set_pred_control(p->devinfo, brw_last_inst, BRW_PREDICATE_NORMAL);
616    brw_CMP(p, brw_null_reg(), BRW_CONDITIONAL_NZ,
617            get_element(t, 2), brw_imm_ud(0));
618    brw_OR(p, c->reg.planemask, c->reg.planemask, brw_imm_ud((1<<0)));
619    brw_inst_set_pred_control(p->devinfo, brw_last_inst, BRW_PREDICATE_NORMAL);
620
621    release_tmps(c);
622}
623
624
625void brw_emit_tri_clip( struct brw_clip_compile *c )
626{
627   struct brw_codegen *p = &c->func;
628   brw_clip_tri_alloc_regs(c, 3 + c->key.nr_userclip + 6);
629   brw_clip_tri_init_vertices(c);
630   brw_clip_init_clipmask(c);
631   brw_clip_init_ff_sync(c);
632
633   /* if -ve rhw workaround bit is set,
634      do cliptest */
635   if (p->devinfo->has_negative_rhw_bug) {
636      brw_AND(p, brw_null_reg(), get_element_ud(c->reg.R0, 2),
637              brw_imm_ud(1<<20));
638      brw_inst_set_cond_modifier(p->devinfo, brw_last_inst, BRW_CONDITIONAL_NZ);
639      brw_IF(p, BRW_EXECUTE_1);
640      {
641         brw_clip_test(c);
642      }
643      brw_ENDIF(p);
644   }
645   /* Can't push into do_clip_tri because with polygon (or quad)
646    * flatshading, need to apply the flatshade here because we don't
647    * respect the PV when converting to trifan for emit:
648    */
649   if (c->key.contains_flat_varying)
650      brw_clip_tri_flat_shade(c);
651
652   if ((c->key.clip_mode == BRW_CLIP_MODE_NORMAL) ||
653       (c->key.clip_mode == BRW_CLIP_MODE_KERNEL_CLIP))
654      do_clip_tri(c);
655   else
656      maybe_do_clip_tri(c);
657
658   brw_clip_tri_emit_polygon(c);
659
660   /* Send an empty message to kill the thread:
661    */
662   brw_clip_kill_thread(c);
663}
664