101e04c3fSmrg/*
201e04c3fSmrg Copyright (C) Intel Corp.  2006.  All Rights Reserved.
301e04c3fSmrg Intel funded Tungsten Graphics to
401e04c3fSmrg develop this 3D driver.
501e04c3fSmrg
601e04c3fSmrg Permission is hereby granted, free of charge, to any person obtaining
701e04c3fSmrg a copy of this software and associated documentation files (the
801e04c3fSmrg "Software"), to deal in the Software without restriction, including
901e04c3fSmrg without limitation the rights to use, copy, modify, merge, publish,
1001e04c3fSmrg distribute, sublicense, and/or sell copies of the Software, and to
1101e04c3fSmrg permit persons to whom the Software is furnished to do so, subject to
1201e04c3fSmrg the following conditions:
1301e04c3fSmrg
1401e04c3fSmrg The above copyright notice and this permission notice (including the
1501e04c3fSmrg next paragraph) shall be included in all copies or substantial
1601e04c3fSmrg portions of the Software.
1701e04c3fSmrg
1801e04c3fSmrg THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
1901e04c3fSmrg EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2001e04c3fSmrg MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
2101e04c3fSmrg IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
2201e04c3fSmrg LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
2301e04c3fSmrg OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
2401e04c3fSmrg WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2501e04c3fSmrg
2601e04c3fSmrg **********************************************************************/
2701e04c3fSmrg /*
2801e04c3fSmrg  * Authors:
2901e04c3fSmrg  *   Keith Whitwell <keithw@vmware.com>
3001e04c3fSmrg  */
3101e04c3fSmrg
3201e04c3fSmrg#include "main/macros.h"
3301e04c3fSmrg#include "main/enums.h"
3401e04c3fSmrg#include "program/program.h"
3501e04c3fSmrg
3601e04c3fSmrg#include "brw_clip.h"
3701e04c3fSmrg
3801e04c3fSmrgstatic void release_tmps( struct brw_clip_compile *c )
3901e04c3fSmrg{
4001e04c3fSmrg   c->last_tmp = c->first_tmp;
4101e04c3fSmrg}
4201e04c3fSmrg
4301e04c3fSmrg
4401e04c3fSmrgvoid brw_clip_tri_alloc_regs( struct brw_clip_compile *c,
4501e04c3fSmrg			      GLuint nr_verts )
4601e04c3fSmrg{
477ec681f3Smrg   const struct intel_device_info *devinfo = c->func.devinfo;
4801e04c3fSmrg   GLuint i = 0,j;
4901e04c3fSmrg
5001e04c3fSmrg   /* Register usage is static, precompute here:
5101e04c3fSmrg    */
5201e04c3fSmrg   c->reg.R0 = retype(brw_vec8_grf(i, 0), BRW_REGISTER_TYPE_UD); i++;
5301e04c3fSmrg
5401e04c3fSmrg   if (c->key.nr_userclip) {
5501e04c3fSmrg      c->reg.fixed_planes = brw_vec4_grf(i, 0);
5601e04c3fSmrg      i += (6 + c->key.nr_userclip + 1) / 2;
5701e04c3fSmrg
5801e04c3fSmrg      c->prog_data.curb_read_length = (6 + c->key.nr_userclip + 1) / 2;
5901e04c3fSmrg   }
6001e04c3fSmrg   else
6101e04c3fSmrg      c->prog_data.curb_read_length = 0;
6201e04c3fSmrg
6301e04c3fSmrg
6401e04c3fSmrg   /* Payload vertices plus space for more generated vertices:
6501e04c3fSmrg    */
6601e04c3fSmrg   for (j = 0; j < nr_verts; j++) {
6701e04c3fSmrg      c->reg.vertex[j] = brw_vec4_grf(i, 0);
6801e04c3fSmrg      i += c->nr_regs;
6901e04c3fSmrg   }
7001e04c3fSmrg
7101e04c3fSmrg   if (c->vue_map.num_slots % 2 && nr_verts > 0) {
7201e04c3fSmrg      /* The VUE has an odd number of slots so the last register is only half
7301e04c3fSmrg       * used.  Fill the second half with zero.
7401e04c3fSmrg       */
7501e04c3fSmrg      for (j = 0; j < 3; j++) {
7601e04c3fSmrg	 GLuint delta = brw_vue_slot_to_offset(c->vue_map.num_slots);
7701e04c3fSmrg
7801e04c3fSmrg	 brw_MOV(&c->func, byte_offset(c->reg.vertex[j], delta), brw_imm_f(0));
7901e04c3fSmrg      }
8001e04c3fSmrg   }
8101e04c3fSmrg
8201e04c3fSmrg   c->reg.t          = brw_vec1_grf(i, 0);
8301e04c3fSmrg   c->reg.loopcount  = retype(brw_vec1_grf(i, 1), BRW_REGISTER_TYPE_D);
8401e04c3fSmrg   c->reg.nr_verts   = retype(brw_vec1_grf(i, 2), BRW_REGISTER_TYPE_UD);
8501e04c3fSmrg   c->reg.planemask  = retype(brw_vec1_grf(i, 3), BRW_REGISTER_TYPE_UD);
8601e04c3fSmrg   c->reg.plane_equation = brw_vec4_grf(i, 4);
8701e04c3fSmrg   i++;
8801e04c3fSmrg
8901e04c3fSmrg   c->reg.dpPrev     = brw_vec1_grf(i, 0); /* fixme - dp4 will clobber r.1,2,3 */
9001e04c3fSmrg   c->reg.dp         = brw_vec1_grf(i, 4);
9101e04c3fSmrg   i++;
9201e04c3fSmrg
9301e04c3fSmrg   c->reg.inlist     = brw_uw16_reg(BRW_GENERAL_REGISTER_FILE, i, 0);
9401e04c3fSmrg   i++;
9501e04c3fSmrg
9601e04c3fSmrg   c->reg.outlist    = brw_uw16_reg(BRW_GENERAL_REGISTER_FILE, i, 0);
9701e04c3fSmrg   i++;
9801e04c3fSmrg
9901e04c3fSmrg   c->reg.freelist   = brw_uw16_reg(BRW_GENERAL_REGISTER_FILE, i, 0);
10001e04c3fSmrg   i++;
10101e04c3fSmrg
10201e04c3fSmrg   if (!c->key.nr_userclip) {
10301e04c3fSmrg      c->reg.fixed_planes = brw_vec8_grf(i, 0);
10401e04c3fSmrg      i++;
10501e04c3fSmrg   }
10601e04c3fSmrg
10701e04c3fSmrg   if (c->key.do_unfilled) {
10801e04c3fSmrg      c->reg.dir     = brw_vec4_grf(i, 0);
10901e04c3fSmrg      c->reg.offset  = brw_vec4_grf(i, 4);
11001e04c3fSmrg      i++;
11101e04c3fSmrg      c->reg.tmp0    = brw_vec4_grf(i, 0);
11201e04c3fSmrg      c->reg.tmp1    = brw_vec4_grf(i, 4);
11301e04c3fSmrg      i++;
11401e04c3fSmrg   }
11501e04c3fSmrg
11601e04c3fSmrg   c->reg.vertex_src_mask = retype(brw_vec1_grf(i, 0), BRW_REGISTER_TYPE_UD);
11701e04c3fSmrg   c->reg.clipdistance_offset = retype(brw_vec1_grf(i, 1), BRW_REGISTER_TYPE_W);
11801e04c3fSmrg   i++;
11901e04c3fSmrg
1207ec681f3Smrg   if (devinfo->ver == 5) {
12101e04c3fSmrg      c->reg.ff_sync = retype(brw_vec1_grf(i, 0), BRW_REGISTER_TYPE_UD);
12201e04c3fSmrg      i++;
12301e04c3fSmrg   }
12401e04c3fSmrg
12501e04c3fSmrg   c->first_tmp = i;
12601e04c3fSmrg   c->last_tmp = i;
12701e04c3fSmrg
12801e04c3fSmrg   c->prog_data.urb_read_length = c->nr_regs; /* ? */
12901e04c3fSmrg   c->prog_data.total_grf = i;
13001e04c3fSmrg}
13101e04c3fSmrg
13201e04c3fSmrg
13301e04c3fSmrg
13401e04c3fSmrgvoid brw_clip_tri_init_vertices( struct brw_clip_compile *c )
13501e04c3fSmrg{
13601e04c3fSmrg   struct brw_codegen *p = &c->func;
13701e04c3fSmrg   struct brw_reg tmp0 = c->reg.loopcount; /* handy temporary */
13801e04c3fSmrg
13901e04c3fSmrg   /* Initial list of indices for incoming vertexes:
14001e04c3fSmrg    */
14101e04c3fSmrg   brw_AND(p, tmp0, get_element_ud(c->reg.R0, 2), brw_imm_ud(PRIM_MASK));
14201e04c3fSmrg   brw_CMP(p,
14301e04c3fSmrg	   vec1(brw_null_reg()),
14401e04c3fSmrg	   BRW_CONDITIONAL_EQ,
14501e04c3fSmrg	   tmp0,
14601e04c3fSmrg	   brw_imm_ud(_3DPRIM_TRISTRIP_REVERSE));
14701e04c3fSmrg
14801e04c3fSmrg   /* XXX: Is there an easier way to do this?  Need to reverse every
14901e04c3fSmrg    * second tristrip element:  Can ignore sometimes?
15001e04c3fSmrg    */
15101e04c3fSmrg   brw_IF(p, BRW_EXECUTE_1);
15201e04c3fSmrg   {
15301e04c3fSmrg      brw_MOV(p, get_element(c->reg.inlist, 0),  brw_address(c->reg.vertex[1]) );
15401e04c3fSmrg      brw_MOV(p, get_element(c->reg.inlist, 1),  brw_address(c->reg.vertex[0]) );
15501e04c3fSmrg      if (c->need_direction)
15601e04c3fSmrg	 brw_MOV(p, c->reg.dir, brw_imm_f(-1));
15701e04c3fSmrg   }
15801e04c3fSmrg   brw_ELSE(p);
15901e04c3fSmrg   {
16001e04c3fSmrg      brw_MOV(p, get_element(c->reg.inlist, 0),  brw_address(c->reg.vertex[0]) );
16101e04c3fSmrg      brw_MOV(p, get_element(c->reg.inlist, 1),  brw_address(c->reg.vertex[1]) );
16201e04c3fSmrg      if (c->need_direction)
16301e04c3fSmrg	 brw_MOV(p, c->reg.dir, brw_imm_f(1));
16401e04c3fSmrg   }
16501e04c3fSmrg   brw_ENDIF(p);
16601e04c3fSmrg
16701e04c3fSmrg   brw_MOV(p, get_element(c->reg.inlist, 2),  brw_address(c->reg.vertex[2]) );
16801e04c3fSmrg   brw_MOV(p, brw_vec8_grf(c->reg.outlist.nr, 0), brw_imm_f(0));
16901e04c3fSmrg   brw_MOV(p, c->reg.nr_verts, brw_imm_ud(3));
17001e04c3fSmrg}
17101e04c3fSmrg
17201e04c3fSmrg
17301e04c3fSmrg
17401e04c3fSmrgvoid brw_clip_tri_flat_shade( struct brw_clip_compile *c )
17501e04c3fSmrg{
17601e04c3fSmrg   struct brw_codegen *p = &c->func;
17701e04c3fSmrg   struct brw_reg tmp0 = c->reg.loopcount; /* handy temporary */
17801e04c3fSmrg
17901e04c3fSmrg   brw_AND(p, tmp0, get_element_ud(c->reg.R0, 2), brw_imm_ud(PRIM_MASK));
18001e04c3fSmrg   brw_CMP(p,
18101e04c3fSmrg	   vec1(brw_null_reg()),
18201e04c3fSmrg	   BRW_CONDITIONAL_EQ,
18301e04c3fSmrg	   tmp0,
18401e04c3fSmrg	   brw_imm_ud(_3DPRIM_POLYGON));
18501e04c3fSmrg
18601e04c3fSmrg   brw_IF(p, BRW_EXECUTE_1);
18701e04c3fSmrg   {
18801e04c3fSmrg      brw_clip_copy_flatshaded_attributes(c, 1, 0);
18901e04c3fSmrg      brw_clip_copy_flatshaded_attributes(c, 2, 0);
19001e04c3fSmrg   }
19101e04c3fSmrg   brw_ELSE(p);
19201e04c3fSmrg   {
19301e04c3fSmrg      if (c->key.pv_first) {
19401e04c3fSmrg	 brw_CMP(p,
19501e04c3fSmrg		 vec1(brw_null_reg()),
19601e04c3fSmrg		 BRW_CONDITIONAL_EQ,
19701e04c3fSmrg		 tmp0,
19801e04c3fSmrg		 brw_imm_ud(_3DPRIM_TRIFAN));
19901e04c3fSmrg	 brw_IF(p, BRW_EXECUTE_1);
20001e04c3fSmrg	 {
20101e04c3fSmrg	    brw_clip_copy_flatshaded_attributes(c, 0, 1);
20201e04c3fSmrg	    brw_clip_copy_flatshaded_attributes(c, 2, 1);
20301e04c3fSmrg	 }
20401e04c3fSmrg	 brw_ELSE(p);
20501e04c3fSmrg	 {
20601e04c3fSmrg	    brw_clip_copy_flatshaded_attributes(c, 1, 0);
20701e04c3fSmrg	    brw_clip_copy_flatshaded_attributes(c, 2, 0);
20801e04c3fSmrg	 }
20901e04c3fSmrg	 brw_ENDIF(p);
21001e04c3fSmrg      }
21101e04c3fSmrg      else {
21201e04c3fSmrg         brw_clip_copy_flatshaded_attributes(c, 0, 2);
21301e04c3fSmrg         brw_clip_copy_flatshaded_attributes(c, 1, 2);
21401e04c3fSmrg      }
21501e04c3fSmrg   }
21601e04c3fSmrg   brw_ENDIF(p);
21701e04c3fSmrg}
21801e04c3fSmrg
21901e04c3fSmrg
22001e04c3fSmrg/**
22101e04c3fSmrg * Loads the clip distance for a vertex into `dst`, and ends with
22201e04c3fSmrg * a comparison of it to zero with the condition `cond`.
22301e04c3fSmrg *
22401e04c3fSmrg * - If using a fixed plane, the distance is dot(hpos, plane).
22501e04c3fSmrg * - If using a user clip plane, the distance is directly available in the vertex.
22601e04c3fSmrg */
22701e04c3fSmrgstatic inline void
22801e04c3fSmrgload_clip_distance(struct brw_clip_compile *c, struct brw_indirect vtx,
22901e04c3fSmrg                struct brw_reg dst, GLuint hpos_offset, int cond)
23001e04c3fSmrg{
23101e04c3fSmrg   struct brw_codegen *p = &c->func;
23201e04c3fSmrg
23301e04c3fSmrg   dst = vec4(dst);
23401e04c3fSmrg   brw_AND(p, vec1(brw_null_reg()), c->reg.vertex_src_mask, brw_imm_ud(1));
23501e04c3fSmrg   brw_inst_set_cond_modifier(p->devinfo, brw_last_inst, BRW_CONDITIONAL_NZ);
23601e04c3fSmrg   brw_IF(p, BRW_EXECUTE_1);
23701e04c3fSmrg   {
23801e04c3fSmrg      struct brw_indirect temp_ptr = brw_indirect(7, 0);
23901e04c3fSmrg      brw_ADD(p, get_addr_reg(temp_ptr), get_addr_reg(vtx), c->reg.clipdistance_offset);
24001e04c3fSmrg      brw_MOV(p, vec1(dst), deref_1f(temp_ptr, 0));
24101e04c3fSmrg   }
24201e04c3fSmrg   brw_ELSE(p);
24301e04c3fSmrg   {
24401e04c3fSmrg      brw_MOV(p, dst, deref_4f(vtx, hpos_offset));
24501e04c3fSmrg      brw_DP4(p, dst, dst, c->reg.plane_equation);
24601e04c3fSmrg   }
24701e04c3fSmrg   brw_ENDIF(p);
24801e04c3fSmrg
24901e04c3fSmrg   brw_CMP(p, brw_null_reg(), cond, vec1(dst), brw_imm_f(0.0f));
25001e04c3fSmrg}
25101e04c3fSmrg
25201e04c3fSmrg
2537ec681f3Smrg/* Use mesa's clipping algorithms, translated to GFX4 assembly.
25401e04c3fSmrg */
25501e04c3fSmrgvoid brw_clip_tri( struct brw_clip_compile *c )
25601e04c3fSmrg{
25701e04c3fSmrg   struct brw_codegen *p = &c->func;
25801e04c3fSmrg   struct brw_indirect vtx = brw_indirect(0, 0);
25901e04c3fSmrg   struct brw_indirect vtxPrev = brw_indirect(1, 0);
26001e04c3fSmrg   struct brw_indirect vtxOut = brw_indirect(2, 0);
26101e04c3fSmrg   struct brw_indirect plane_ptr = brw_indirect(3, 0);
26201e04c3fSmrg   struct brw_indirect inlist_ptr = brw_indirect(4, 0);
26301e04c3fSmrg   struct brw_indirect outlist_ptr = brw_indirect(5, 0);
26401e04c3fSmrg   struct brw_indirect freelist_ptr = brw_indirect(6, 0);
26501e04c3fSmrg   GLuint hpos_offset = brw_varying_to_offset(&c->vue_map, VARYING_SLOT_POS);
26601e04c3fSmrg   GLint clipdist0_offset = c->key.nr_userclip
26701e04c3fSmrg      ? brw_varying_to_offset(&c->vue_map, VARYING_SLOT_CLIP_DIST0)
26801e04c3fSmrg      : 0;
26901e04c3fSmrg
27001e04c3fSmrg   brw_MOV(p, get_addr_reg(vtxPrev),     brw_address(c->reg.vertex[2]) );
27101e04c3fSmrg   brw_MOV(p, get_addr_reg(plane_ptr),   brw_clip_plane0_address(c));
27201e04c3fSmrg   brw_MOV(p, get_addr_reg(inlist_ptr),  brw_address(c->reg.inlist));
27301e04c3fSmrg   brw_MOV(p, get_addr_reg(outlist_ptr), brw_address(c->reg.outlist));
27401e04c3fSmrg
27501e04c3fSmrg   brw_MOV(p, get_addr_reg(freelist_ptr), brw_address(c->reg.vertex[3]) );
27601e04c3fSmrg
27701e04c3fSmrg   /* Set the initial vertex source mask: The first 6 planes are the bounds
27801e04c3fSmrg    * of the view volume; the next 8 planes are the user clipping planes.
27901e04c3fSmrg    */
28001e04c3fSmrg   brw_MOV(p, c->reg.vertex_src_mask, brw_imm_ud(0x3fc0));
28101e04c3fSmrg
28201e04c3fSmrg   /* Set the initial clipdistance offset to be 6 floats before gl_ClipDistance[0].
28301e04c3fSmrg    * We'll increment 6 times before we start hitting actual user clipping. */
28401e04c3fSmrg   brw_MOV(p, c->reg.clipdistance_offset, brw_imm_d(clipdist0_offset - 6*sizeof(float)));
28501e04c3fSmrg
28601e04c3fSmrg   brw_DO(p, BRW_EXECUTE_1);
28701e04c3fSmrg   {
28801e04c3fSmrg      /* if (planemask & 1)
28901e04c3fSmrg       */
29001e04c3fSmrg      brw_AND(p, vec1(brw_null_reg()), c->reg.planemask, brw_imm_ud(1));
29101e04c3fSmrg      brw_inst_set_cond_modifier(p->devinfo, brw_last_inst, BRW_CONDITIONAL_NZ);
29201e04c3fSmrg
29301e04c3fSmrg      brw_IF(p, BRW_EXECUTE_1);
29401e04c3fSmrg      {
29501e04c3fSmrg	 /* vtxOut = freelist_ptr++
29601e04c3fSmrg	  */
29701e04c3fSmrg	 brw_MOV(p, get_addr_reg(vtxOut),       get_addr_reg(freelist_ptr) );
29801e04c3fSmrg	 brw_ADD(p, get_addr_reg(freelist_ptr), get_addr_reg(freelist_ptr), brw_imm_uw(c->nr_regs * REG_SIZE));
29901e04c3fSmrg
30001e04c3fSmrg	 if (c->key.nr_userclip)
30101e04c3fSmrg	    brw_MOV(p, c->reg.plane_equation, deref_4f(plane_ptr, 0));
30201e04c3fSmrg	 else
30301e04c3fSmrg	    brw_MOV(p, c->reg.plane_equation, deref_4b(plane_ptr, 0));
30401e04c3fSmrg
30501e04c3fSmrg	 brw_MOV(p, c->reg.loopcount, c->reg.nr_verts);
30601e04c3fSmrg	 brw_MOV(p, c->reg.nr_verts, brw_imm_ud(0));
30701e04c3fSmrg
30801e04c3fSmrg	 brw_DO(p, BRW_EXECUTE_1);
30901e04c3fSmrg	 {
31001e04c3fSmrg	    /* vtx = *input_ptr;
31101e04c3fSmrg	     */
31201e04c3fSmrg	    brw_MOV(p, get_addr_reg(vtx), deref_1uw(inlist_ptr, 0));
31301e04c3fSmrg
31401e04c3fSmrg            load_clip_distance(c, vtxPrev, c->reg.dpPrev, hpos_offset, BRW_CONDITIONAL_L);
31501e04c3fSmrg	    /* (prev < 0.0f) */
31601e04c3fSmrg	    brw_IF(p, BRW_EXECUTE_1);
31701e04c3fSmrg	    {
31801e04c3fSmrg               load_clip_distance(c, vtx, c->reg.dp, hpos_offset, BRW_CONDITIONAL_GE);
31901e04c3fSmrg	       /* IS_POSITIVE(next)
32001e04c3fSmrg		*/
32101e04c3fSmrg	       brw_IF(p, BRW_EXECUTE_1);
32201e04c3fSmrg	       {
32301e04c3fSmrg
32401e04c3fSmrg		  /* Coming back in.
32501e04c3fSmrg		   */
32601e04c3fSmrg		  brw_ADD(p, c->reg.t, c->reg.dpPrev, negate(c->reg.dp));
32701e04c3fSmrg		  brw_math_invert(p, c->reg.t, c->reg.t);
32801e04c3fSmrg		  brw_MUL(p, c->reg.t, c->reg.t, c->reg.dpPrev);
32901e04c3fSmrg
33001e04c3fSmrg		  /* If (vtxOut == 0) vtxOut = vtxPrev
33101e04c3fSmrg		   */
33201e04c3fSmrg		  brw_CMP(p, vec1(brw_null_reg()), BRW_CONDITIONAL_EQ, get_addr_reg(vtxOut), brw_imm_uw(0) );
33301e04c3fSmrg                  brw_MOV(p, get_addr_reg(vtxOut), get_addr_reg(vtxPrev));
33401e04c3fSmrg                  brw_inst_set_pred_control(p->devinfo, brw_last_inst,
33501e04c3fSmrg                                            BRW_PREDICATE_NORMAL);
33601e04c3fSmrg
33701e04c3fSmrg		  brw_clip_interp_vertex(c, vtxOut, vtxPrev, vtx, c->reg.t, false);
33801e04c3fSmrg
33901e04c3fSmrg		  /* *outlist_ptr++ = vtxOut;
34001e04c3fSmrg		   * nr_verts++;
34101e04c3fSmrg		   * vtxOut = 0;
34201e04c3fSmrg		   */
34301e04c3fSmrg		  brw_MOV(p, deref_1uw(outlist_ptr, 0), get_addr_reg(vtxOut));
34401e04c3fSmrg		  brw_ADD(p, get_addr_reg(outlist_ptr), get_addr_reg(outlist_ptr), brw_imm_uw(sizeof(short)));
34501e04c3fSmrg		  brw_ADD(p, c->reg.nr_verts, c->reg.nr_verts, brw_imm_ud(1));
34601e04c3fSmrg		  brw_MOV(p, get_addr_reg(vtxOut), brw_imm_uw(0) );
34701e04c3fSmrg	       }
34801e04c3fSmrg	       brw_ENDIF(p);
34901e04c3fSmrg
35001e04c3fSmrg	    }
35101e04c3fSmrg	    brw_ELSE(p);
35201e04c3fSmrg	    {
35301e04c3fSmrg	       /* *outlist_ptr++ = vtxPrev;
35401e04c3fSmrg		* nr_verts++;
35501e04c3fSmrg		*/
35601e04c3fSmrg	       brw_MOV(p, deref_1uw(outlist_ptr, 0), get_addr_reg(vtxPrev));
35701e04c3fSmrg	       brw_ADD(p, get_addr_reg(outlist_ptr), get_addr_reg(outlist_ptr), brw_imm_uw(sizeof(short)));
35801e04c3fSmrg	       brw_ADD(p, c->reg.nr_verts, c->reg.nr_verts, brw_imm_ud(1));
35901e04c3fSmrg
36001e04c3fSmrg               load_clip_distance(c, vtx, c->reg.dp, hpos_offset, BRW_CONDITIONAL_L);
36101e04c3fSmrg	       /* (next < 0.0f)
36201e04c3fSmrg		*/
36301e04c3fSmrg	       brw_IF(p, BRW_EXECUTE_1);
36401e04c3fSmrg	       {
36501e04c3fSmrg		  /* Going out of bounds.  Avoid division by zero as we
36601e04c3fSmrg		   * know dp != dpPrev from DIFFERENT_SIGNS, above.
36701e04c3fSmrg		   */
36801e04c3fSmrg		  brw_ADD(p, c->reg.t, c->reg.dp, negate(c->reg.dpPrev));
36901e04c3fSmrg		  brw_math_invert(p, c->reg.t, c->reg.t);
37001e04c3fSmrg		  brw_MUL(p, c->reg.t, c->reg.t, c->reg.dp);
37101e04c3fSmrg
37201e04c3fSmrg		  /* If (vtxOut == 0) vtxOut = vtx
37301e04c3fSmrg		   */
37401e04c3fSmrg		  brw_CMP(p, vec1(brw_null_reg()), BRW_CONDITIONAL_EQ, get_addr_reg(vtxOut), brw_imm_uw(0) );
37501e04c3fSmrg                  brw_MOV(p, get_addr_reg(vtxOut), get_addr_reg(vtx));
37601e04c3fSmrg                  brw_inst_set_pred_control(p->devinfo, brw_last_inst,
37701e04c3fSmrg                                            BRW_PREDICATE_NORMAL);
37801e04c3fSmrg
37901e04c3fSmrg		  brw_clip_interp_vertex(c, vtxOut, vtx, vtxPrev, c->reg.t, true);
38001e04c3fSmrg
38101e04c3fSmrg		  /* *outlist_ptr++ = vtxOut;
38201e04c3fSmrg		   * nr_verts++;
38301e04c3fSmrg		   * vtxOut = 0;
38401e04c3fSmrg		   */
38501e04c3fSmrg		  brw_MOV(p, deref_1uw(outlist_ptr, 0), get_addr_reg(vtxOut));
38601e04c3fSmrg		  brw_ADD(p, get_addr_reg(outlist_ptr), get_addr_reg(outlist_ptr), brw_imm_uw(sizeof(short)));
38701e04c3fSmrg		  brw_ADD(p, c->reg.nr_verts, c->reg.nr_verts, brw_imm_ud(1));
38801e04c3fSmrg		  brw_MOV(p, get_addr_reg(vtxOut), brw_imm_uw(0) );
38901e04c3fSmrg	       }
39001e04c3fSmrg	       brw_ENDIF(p);
39101e04c3fSmrg	    }
39201e04c3fSmrg	    brw_ENDIF(p);
39301e04c3fSmrg
39401e04c3fSmrg	    /* vtxPrev = vtx;
39501e04c3fSmrg	     * inlist_ptr++;
39601e04c3fSmrg	     */
39701e04c3fSmrg	    brw_MOV(p, get_addr_reg(vtxPrev), get_addr_reg(vtx));
39801e04c3fSmrg	    brw_ADD(p, get_addr_reg(inlist_ptr), get_addr_reg(inlist_ptr), brw_imm_uw(sizeof(short)));
39901e04c3fSmrg
40001e04c3fSmrg	    /* while (--loopcount != 0)
40101e04c3fSmrg	     */
40201e04c3fSmrg	    brw_ADD(p, c->reg.loopcount, c->reg.loopcount, brw_imm_d(-1));
40301e04c3fSmrg            brw_inst_set_cond_modifier(p->devinfo, brw_last_inst, BRW_CONDITIONAL_NZ);
40401e04c3fSmrg	 }
40501e04c3fSmrg	 brw_WHILE(p);
40601e04c3fSmrg         brw_inst_set_pred_control(p->devinfo, brw_last_inst, BRW_PREDICATE_NORMAL);
40701e04c3fSmrg
40801e04c3fSmrg	 /* vtxPrev = *(outlist_ptr-1)  OR: outlist[nr_verts-1]
40901e04c3fSmrg	  * inlist = outlist
41001e04c3fSmrg	  * inlist_ptr = &inlist[0]
41101e04c3fSmrg	  * outlist_ptr = &outlist[0]
41201e04c3fSmrg	  */
41301e04c3fSmrg	 brw_ADD(p, get_addr_reg(outlist_ptr), get_addr_reg(outlist_ptr), brw_imm_w(-2));
41401e04c3fSmrg	 brw_MOV(p, get_addr_reg(vtxPrev), deref_1uw(outlist_ptr, 0));
41501e04c3fSmrg	 brw_MOV(p, brw_vec8_grf(c->reg.inlist.nr, 0), brw_vec8_grf(c->reg.outlist.nr, 0));
41601e04c3fSmrg	 brw_MOV(p, get_addr_reg(inlist_ptr), brw_address(c->reg.inlist));
41701e04c3fSmrg	 brw_MOV(p, get_addr_reg(outlist_ptr), brw_address(c->reg.outlist));
41801e04c3fSmrg      }
41901e04c3fSmrg      brw_ENDIF(p);
42001e04c3fSmrg
42101e04c3fSmrg      /* plane_ptr++;
42201e04c3fSmrg       */
42301e04c3fSmrg      brw_ADD(p, get_addr_reg(plane_ptr), get_addr_reg(plane_ptr), brw_clip_plane_stride(c));
42401e04c3fSmrg
42501e04c3fSmrg      /* nr_verts >= 3
42601e04c3fSmrg       */
42701e04c3fSmrg      brw_CMP(p,
42801e04c3fSmrg	      vec1(brw_null_reg()),
42901e04c3fSmrg	      BRW_CONDITIONAL_GE,
43001e04c3fSmrg	      c->reg.nr_verts,
43101e04c3fSmrg	      brw_imm_ud(3));
43201e04c3fSmrg      brw_set_default_predicate_control(p, BRW_PREDICATE_NORMAL);
43301e04c3fSmrg
43401e04c3fSmrg      /* && (planemask>>=1) != 0
43501e04c3fSmrg       */
43601e04c3fSmrg      brw_SHR(p, c->reg.planemask, c->reg.planemask, brw_imm_ud(1));
43701e04c3fSmrg      brw_inst_set_cond_modifier(p->devinfo, brw_last_inst, BRW_CONDITIONAL_NZ);
43801e04c3fSmrg      brw_SHR(p, c->reg.vertex_src_mask, c->reg.vertex_src_mask, brw_imm_ud(1));
43901e04c3fSmrg      brw_ADD(p, c->reg.clipdistance_offset, c->reg.clipdistance_offset, brw_imm_w(sizeof(float)));
44001e04c3fSmrg   }
44101e04c3fSmrg   brw_WHILE(p);
44201e04c3fSmrg   brw_set_default_predicate_control(p, BRW_PREDICATE_NONE);
44301e04c3fSmrg}
44401e04c3fSmrg
44501e04c3fSmrg
44601e04c3fSmrg
44701e04c3fSmrgvoid brw_clip_tri_emit_polygon(struct brw_clip_compile *c)
44801e04c3fSmrg{
44901e04c3fSmrg   struct brw_codegen *p = &c->func;
45001e04c3fSmrg
45101e04c3fSmrg   /* for (loopcount = nr_verts-2; loopcount > 0; loopcount--)
45201e04c3fSmrg    */
45301e04c3fSmrg   brw_ADD(p,
45401e04c3fSmrg	   c->reg.loopcount,
45501e04c3fSmrg	   c->reg.nr_verts,
45601e04c3fSmrg	   brw_imm_d(-2));
45701e04c3fSmrg   brw_inst_set_cond_modifier(p->devinfo, brw_last_inst, BRW_CONDITIONAL_G);
45801e04c3fSmrg
45901e04c3fSmrg   brw_IF(p, BRW_EXECUTE_1);
46001e04c3fSmrg   {
46101e04c3fSmrg      struct brw_indirect v0 = brw_indirect(0, 0);
46201e04c3fSmrg      struct brw_indirect vptr = brw_indirect(1, 0);
46301e04c3fSmrg
46401e04c3fSmrg      brw_MOV(p, get_addr_reg(vptr), brw_address(c->reg.inlist));
46501e04c3fSmrg      brw_MOV(p, get_addr_reg(v0), deref_1uw(vptr, 0));
46601e04c3fSmrg
46701e04c3fSmrg      brw_clip_emit_vue(c, v0, BRW_URB_WRITE_ALLOCATE_COMPLETE,
46801e04c3fSmrg                        ((_3DPRIM_TRIFAN << URB_WRITE_PRIM_TYPE_SHIFT)
46901e04c3fSmrg                         | URB_WRITE_PRIM_START));
47001e04c3fSmrg
47101e04c3fSmrg      brw_ADD(p, get_addr_reg(vptr), get_addr_reg(vptr), brw_imm_uw(2));
47201e04c3fSmrg      brw_MOV(p, get_addr_reg(v0), deref_1uw(vptr, 0));
47301e04c3fSmrg
47401e04c3fSmrg      brw_DO(p, BRW_EXECUTE_1);
47501e04c3fSmrg      {
47601e04c3fSmrg	 brw_clip_emit_vue(c, v0, BRW_URB_WRITE_ALLOCATE_COMPLETE,
47701e04c3fSmrg                           (_3DPRIM_TRIFAN << URB_WRITE_PRIM_TYPE_SHIFT));
47801e04c3fSmrg
47901e04c3fSmrg	 brw_ADD(p, get_addr_reg(vptr), get_addr_reg(vptr), brw_imm_uw(2));
48001e04c3fSmrg	 brw_MOV(p, get_addr_reg(v0), deref_1uw(vptr, 0));
48101e04c3fSmrg
48201e04c3fSmrg	 brw_ADD(p, c->reg.loopcount, c->reg.loopcount, brw_imm_d(-1));
48301e04c3fSmrg         brw_inst_set_cond_modifier(p->devinfo, brw_last_inst, BRW_CONDITIONAL_NZ);
48401e04c3fSmrg      }
48501e04c3fSmrg      brw_WHILE(p);
48601e04c3fSmrg      brw_inst_set_pred_control(p->devinfo, brw_last_inst, BRW_PREDICATE_NORMAL);
48701e04c3fSmrg
48801e04c3fSmrg      brw_clip_emit_vue(c, v0, BRW_URB_WRITE_EOT_COMPLETE,
48901e04c3fSmrg                        ((_3DPRIM_TRIFAN << URB_WRITE_PRIM_TYPE_SHIFT)
49001e04c3fSmrg                         | URB_WRITE_PRIM_END));
49101e04c3fSmrg   }
49201e04c3fSmrg   brw_ENDIF(p);
49301e04c3fSmrg}
49401e04c3fSmrg
49501e04c3fSmrgstatic void do_clip_tri( struct brw_clip_compile *c )
49601e04c3fSmrg{
49701e04c3fSmrg   brw_clip_init_planes(c);
49801e04c3fSmrg
49901e04c3fSmrg   brw_clip_tri(c);
50001e04c3fSmrg}
50101e04c3fSmrg
50201e04c3fSmrg
50301e04c3fSmrgstatic void maybe_do_clip_tri( struct brw_clip_compile *c )
50401e04c3fSmrg{
50501e04c3fSmrg   struct brw_codegen *p = &c->func;
50601e04c3fSmrg
50701e04c3fSmrg   brw_CMP(p, vec1(brw_null_reg()), BRW_CONDITIONAL_NZ, c->reg.planemask, brw_imm_ud(0));
50801e04c3fSmrg   brw_IF(p, BRW_EXECUTE_1);
50901e04c3fSmrg   {
51001e04c3fSmrg      do_clip_tri(c);
51101e04c3fSmrg   }
51201e04c3fSmrg   brw_ENDIF(p);
51301e04c3fSmrg}
51401e04c3fSmrg
51501e04c3fSmrgstatic void brw_clip_test( struct brw_clip_compile *c )
51601e04c3fSmrg{
51701e04c3fSmrg    struct brw_reg t = retype(get_tmp(c), BRW_REGISTER_TYPE_UD);
51801e04c3fSmrg    struct brw_reg t1 = retype(get_tmp(c), BRW_REGISTER_TYPE_UD);
51901e04c3fSmrg    struct brw_reg t2 = retype(get_tmp(c), BRW_REGISTER_TYPE_UD);
52001e04c3fSmrg    struct brw_reg t3 = retype(get_tmp(c), BRW_REGISTER_TYPE_UD);
52101e04c3fSmrg
52201e04c3fSmrg    struct brw_reg v0 = get_tmp(c);
52301e04c3fSmrg    struct brw_reg v1 = get_tmp(c);
52401e04c3fSmrg    struct brw_reg v2 = get_tmp(c);
52501e04c3fSmrg
52601e04c3fSmrg    struct brw_indirect vt0 = brw_indirect(0, 0);
52701e04c3fSmrg    struct brw_indirect vt1 = brw_indirect(1, 0);
52801e04c3fSmrg    struct brw_indirect vt2 = brw_indirect(2, 0);
52901e04c3fSmrg
53001e04c3fSmrg    struct brw_codegen *p = &c->func;
53101e04c3fSmrg    struct brw_reg tmp0 = c->reg.loopcount; /* handy temporary */
53201e04c3fSmrg
53301e04c3fSmrg    GLuint hpos_offset = brw_varying_to_offset(&c->vue_map,
53401e04c3fSmrg                                                   VARYING_SLOT_POS);
53501e04c3fSmrg
53601e04c3fSmrg    brw_MOV(p, get_addr_reg(vt0), brw_address(c->reg.vertex[0]));
53701e04c3fSmrg    brw_MOV(p, get_addr_reg(vt1), brw_address(c->reg.vertex[1]));
53801e04c3fSmrg    brw_MOV(p, get_addr_reg(vt2), brw_address(c->reg.vertex[2]));
53901e04c3fSmrg    brw_MOV(p, v0, deref_4f(vt0, hpos_offset));
54001e04c3fSmrg    brw_MOV(p, v1, deref_4f(vt1, hpos_offset));
54101e04c3fSmrg    brw_MOV(p, v2, deref_4f(vt2, hpos_offset));
54201e04c3fSmrg    brw_AND(p, c->reg.planemask, c->reg.planemask, brw_imm_ud(~0x3f));
54301e04c3fSmrg
54401e04c3fSmrg    /* test nearz, xmin, ymin plane */
54501e04c3fSmrg    /* clip.xyz < -clip.w */
54601e04c3fSmrg    brw_CMP(p, t1, BRW_CONDITIONAL_L, v0, negate(get_element(v0, 3)));
54701e04c3fSmrg    brw_CMP(p, t2, BRW_CONDITIONAL_L, v1, negate(get_element(v1, 3)));
54801e04c3fSmrg    brw_CMP(p, t3, BRW_CONDITIONAL_L, v2, negate(get_element(v2, 3)));
54901e04c3fSmrg
55001e04c3fSmrg    /* All vertices are outside of a plane, rejected */
55101e04c3fSmrg    brw_AND(p, t, t1, t2);
55201e04c3fSmrg    brw_AND(p, t, t, t3);
55301e04c3fSmrg    brw_OR(p, tmp0, get_element(t, 0), get_element(t, 1));
55401e04c3fSmrg    brw_OR(p, tmp0, tmp0, get_element(t, 2));
55501e04c3fSmrg    brw_AND(p, brw_null_reg(), tmp0, brw_imm_ud(0x1));
55601e04c3fSmrg    brw_inst_set_cond_modifier(p->devinfo, brw_last_inst, BRW_CONDITIONAL_NZ);
55701e04c3fSmrg    brw_IF(p, BRW_EXECUTE_1);
55801e04c3fSmrg    {
55901e04c3fSmrg        brw_clip_kill_thread(c);
56001e04c3fSmrg    }
56101e04c3fSmrg    brw_ENDIF(p);
56201e04c3fSmrg    brw_set_default_predicate_control(p, BRW_PREDICATE_NONE);
56301e04c3fSmrg
56401e04c3fSmrg    /* some vertices are inside a plane, some are outside,need to clip */
56501e04c3fSmrg    brw_XOR(p, t, t1, t2);
56601e04c3fSmrg    brw_XOR(p, t1, t2, t3);
56701e04c3fSmrg    brw_OR(p, t, t, t1);
56801e04c3fSmrg    brw_AND(p, t, t, brw_imm_ud(0x1));
56901e04c3fSmrg    brw_CMP(p, brw_null_reg(), BRW_CONDITIONAL_NZ,
57001e04c3fSmrg            get_element(t, 0), brw_imm_ud(0));
57101e04c3fSmrg    brw_OR(p, c->reg.planemask, c->reg.planemask, brw_imm_ud((1<<5)));
57201e04c3fSmrg    brw_inst_set_pred_control(p->devinfo, brw_last_inst, BRW_PREDICATE_NORMAL);
57301e04c3fSmrg    brw_CMP(p, brw_null_reg(), BRW_CONDITIONAL_NZ,
57401e04c3fSmrg            get_element(t, 1), brw_imm_ud(0));
57501e04c3fSmrg    brw_OR(p, c->reg.planemask, c->reg.planemask, brw_imm_ud((1<<3)));
57601e04c3fSmrg    brw_inst_set_pred_control(p->devinfo, brw_last_inst, BRW_PREDICATE_NORMAL);
57701e04c3fSmrg    brw_CMP(p, brw_null_reg(), BRW_CONDITIONAL_NZ,
57801e04c3fSmrg            get_element(t, 2), brw_imm_ud(0));
57901e04c3fSmrg    brw_OR(p, c->reg.planemask, c->reg.planemask, brw_imm_ud((1<<1)));
58001e04c3fSmrg    brw_inst_set_pred_control(p->devinfo, brw_last_inst, BRW_PREDICATE_NORMAL);
58101e04c3fSmrg
58201e04c3fSmrg    /* test farz, xmax, ymax plane */
58301e04c3fSmrg    /* clip.xyz > clip.w */
58401e04c3fSmrg    brw_CMP(p, t1, BRW_CONDITIONAL_G, v0, get_element(v0, 3));
58501e04c3fSmrg    brw_CMP(p, t2, BRW_CONDITIONAL_G, v1, get_element(v1, 3));
58601e04c3fSmrg    brw_CMP(p, t3, BRW_CONDITIONAL_G, v2, get_element(v2, 3));
58701e04c3fSmrg
58801e04c3fSmrg    /* All vertices are outside of a plane, rejected */
58901e04c3fSmrg    brw_AND(p, t, t1, t2);
59001e04c3fSmrg    brw_AND(p, t, t, t3);
59101e04c3fSmrg    brw_OR(p, tmp0, get_element(t, 0), get_element(t, 1));
59201e04c3fSmrg    brw_OR(p, tmp0, tmp0, get_element(t, 2));
59301e04c3fSmrg    brw_AND(p, brw_null_reg(), tmp0, brw_imm_ud(0x1));
59401e04c3fSmrg    brw_inst_set_cond_modifier(p->devinfo, brw_last_inst, BRW_CONDITIONAL_NZ);
59501e04c3fSmrg    brw_IF(p, BRW_EXECUTE_1);
59601e04c3fSmrg    {
59701e04c3fSmrg        brw_clip_kill_thread(c);
59801e04c3fSmrg    }
59901e04c3fSmrg    brw_ENDIF(p);
60001e04c3fSmrg    brw_set_default_predicate_control(p, BRW_PREDICATE_NONE);
60101e04c3fSmrg
60201e04c3fSmrg    /* some vertices are inside a plane, some are outside,need to clip */
60301e04c3fSmrg    brw_XOR(p, t, t1, t2);
60401e04c3fSmrg    brw_XOR(p, t1, t2, t3);
60501e04c3fSmrg    brw_OR(p, t, t, t1);
60601e04c3fSmrg    brw_AND(p, t, t, brw_imm_ud(0x1));
60701e04c3fSmrg    brw_CMP(p, brw_null_reg(), BRW_CONDITIONAL_NZ,
60801e04c3fSmrg            get_element(t, 0), brw_imm_ud(0));
60901e04c3fSmrg    brw_OR(p, c->reg.planemask, c->reg.planemask, brw_imm_ud((1<<4)));
61001e04c3fSmrg    brw_inst_set_pred_control(p->devinfo, brw_last_inst, BRW_PREDICATE_NORMAL);
61101e04c3fSmrg    brw_CMP(p, brw_null_reg(), BRW_CONDITIONAL_NZ,
61201e04c3fSmrg            get_element(t, 1), brw_imm_ud(0));
61301e04c3fSmrg    brw_OR(p, c->reg.planemask, c->reg.planemask, brw_imm_ud((1<<2)));
61401e04c3fSmrg    brw_inst_set_pred_control(p->devinfo, brw_last_inst, BRW_PREDICATE_NORMAL);
61501e04c3fSmrg    brw_CMP(p, brw_null_reg(), BRW_CONDITIONAL_NZ,
61601e04c3fSmrg            get_element(t, 2), brw_imm_ud(0));
61701e04c3fSmrg    brw_OR(p, c->reg.planemask, c->reg.planemask, brw_imm_ud((1<<0)));
61801e04c3fSmrg    brw_inst_set_pred_control(p->devinfo, brw_last_inst, BRW_PREDICATE_NORMAL);
61901e04c3fSmrg
62001e04c3fSmrg    release_tmps(c);
62101e04c3fSmrg}
62201e04c3fSmrg
62301e04c3fSmrg
62401e04c3fSmrgvoid brw_emit_tri_clip( struct brw_clip_compile *c )
62501e04c3fSmrg{
62601e04c3fSmrg   struct brw_codegen *p = &c->func;
62701e04c3fSmrg   brw_clip_tri_alloc_regs(c, 3 + c->key.nr_userclip + 6);
62801e04c3fSmrg   brw_clip_tri_init_vertices(c);
62901e04c3fSmrg   brw_clip_init_clipmask(c);
63001e04c3fSmrg   brw_clip_init_ff_sync(c);
63101e04c3fSmrg
63201e04c3fSmrg   /* if -ve rhw workaround bit is set,
63301e04c3fSmrg      do cliptest */
63401e04c3fSmrg   if (p->devinfo->has_negative_rhw_bug) {
63501e04c3fSmrg      brw_AND(p, brw_null_reg(), get_element_ud(c->reg.R0, 2),
63601e04c3fSmrg              brw_imm_ud(1<<20));
63701e04c3fSmrg      brw_inst_set_cond_modifier(p->devinfo, brw_last_inst, BRW_CONDITIONAL_NZ);
63801e04c3fSmrg      brw_IF(p, BRW_EXECUTE_1);
63901e04c3fSmrg      {
64001e04c3fSmrg         brw_clip_test(c);
64101e04c3fSmrg      }
64201e04c3fSmrg      brw_ENDIF(p);
64301e04c3fSmrg   }
64401e04c3fSmrg   /* Can't push into do_clip_tri because with polygon (or quad)
64501e04c3fSmrg    * flatshading, need to apply the flatshade here because we don't
64601e04c3fSmrg    * respect the PV when converting to trifan for emit:
64701e04c3fSmrg    */
64801e04c3fSmrg   if (c->key.contains_flat_varying)
64901e04c3fSmrg      brw_clip_tri_flat_shade(c);
65001e04c3fSmrg
65101e04c3fSmrg   if ((c->key.clip_mode == BRW_CLIP_MODE_NORMAL) ||
65201e04c3fSmrg       (c->key.clip_mode == BRW_CLIP_MODE_KERNEL_CLIP))
65301e04c3fSmrg      do_clip_tri(c);
65401e04c3fSmrg   else
65501e04c3fSmrg      maybe_do_clip_tri(c);
65601e04c3fSmrg
65701e04c3fSmrg   brw_clip_tri_emit_polygon(c);
65801e04c3fSmrg
65901e04c3fSmrg   /* Send an empty message to kill the thread:
66001e04c3fSmrg    */
66101e04c3fSmrg   brw_clip_kill_thread(c);
66201e04c3fSmrg}
663