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
3801e04c3fSmrg
3901e04c3fSmrg/* This is performed against the original triangles, so no indirection
4001e04c3fSmrg * required:
4101e04c3fSmrgBZZZT!
4201e04c3fSmrg */
4301e04c3fSmrgstatic void compute_tri_direction( struct brw_clip_compile *c )
4401e04c3fSmrg{
4501e04c3fSmrg   struct brw_codegen *p = &c->func;
4601e04c3fSmrg   struct brw_reg e = c->reg.tmp0;
4701e04c3fSmrg   struct brw_reg f = c->reg.tmp1;
4801e04c3fSmrg   GLuint hpos_offset = brw_varying_to_offset(&c->vue_map, VARYING_SLOT_POS);
4901e04c3fSmrg   struct brw_reg v0 = byte_offset(c->reg.vertex[0], hpos_offset);
5001e04c3fSmrg   struct brw_reg v1 = byte_offset(c->reg.vertex[1], hpos_offset);
5101e04c3fSmrg   struct brw_reg v2 = byte_offset(c->reg.vertex[2], hpos_offset);
5201e04c3fSmrg
5301e04c3fSmrg
5401e04c3fSmrg   struct brw_reg v0n = get_tmp(c);
5501e04c3fSmrg   struct brw_reg v1n = get_tmp(c);
5601e04c3fSmrg   struct brw_reg v2n = get_tmp(c);
5701e04c3fSmrg
5801e04c3fSmrg   /* Convert to NDC.
5901e04c3fSmrg    * NOTE: We can't modify the original vertex coordinates,
6001e04c3fSmrg    * as it may impact further operations.
6101e04c3fSmrg    * So, we have to keep normalized coordinates in temp registers.
6201e04c3fSmrg    *
6301e04c3fSmrg    * TBD-KC
6401e04c3fSmrg    * Try to optimize unnecessary MOV's.
6501e04c3fSmrg    */
6601e04c3fSmrg   brw_MOV(p, v0n, v0);
6701e04c3fSmrg   brw_MOV(p, v1n, v1);
6801e04c3fSmrg   brw_MOV(p, v2n, v2);
6901e04c3fSmrg
7001e04c3fSmrg   brw_clip_project_position(c, v0n);
7101e04c3fSmrg   brw_clip_project_position(c, v1n);
7201e04c3fSmrg   brw_clip_project_position(c, v2n);
7301e04c3fSmrg
7401e04c3fSmrg   /* Calculate the vectors of two edges of the triangle:
7501e04c3fSmrg    */
7601e04c3fSmrg   brw_ADD(p, e, v0n, negate(v2n));
7701e04c3fSmrg   brw_ADD(p, f, v1n, negate(v2n));
7801e04c3fSmrg
7901e04c3fSmrg   /* Take their crossproduct:
8001e04c3fSmrg    */
8101e04c3fSmrg   brw_set_default_access_mode(p, BRW_ALIGN_16);
8201e04c3fSmrg   brw_MUL(p, vec4(brw_null_reg()), brw_swizzle(e, BRW_SWIZZLE_YZXW),
8301e04c3fSmrg           brw_swizzle(f, BRW_SWIZZLE_ZXYW));
8401e04c3fSmrg   brw_MAC(p, vec4(e),  negate(brw_swizzle(e, BRW_SWIZZLE_ZXYW)),
8501e04c3fSmrg           brw_swizzle(f, BRW_SWIZZLE_YZXW));
8601e04c3fSmrg   brw_set_default_access_mode(p, BRW_ALIGN_1);
8701e04c3fSmrg
8801e04c3fSmrg   brw_MUL(p, c->reg.dir, c->reg.dir, vec4(e));
8901e04c3fSmrg}
9001e04c3fSmrg
9101e04c3fSmrg
9201e04c3fSmrgstatic void cull_direction( struct brw_clip_compile *c )
9301e04c3fSmrg{
9401e04c3fSmrg   struct brw_codegen *p = &c->func;
9501e04c3fSmrg   GLuint conditional;
9601e04c3fSmrg
9701e04c3fSmrg   assert (!(c->key.fill_ccw == BRW_CLIP_FILL_MODE_CULL &&
9801e04c3fSmrg	     c->key.fill_cw == BRW_CLIP_FILL_MODE_CULL));
9901e04c3fSmrg
10001e04c3fSmrg   if (c->key.fill_ccw == BRW_CLIP_FILL_MODE_CULL)
10101e04c3fSmrg      conditional = BRW_CONDITIONAL_GE;
10201e04c3fSmrg   else
10301e04c3fSmrg      conditional = BRW_CONDITIONAL_L;
10401e04c3fSmrg
10501e04c3fSmrg   brw_CMP(p,
10601e04c3fSmrg	   vec1(brw_null_reg()),
10701e04c3fSmrg	   conditional,
10801e04c3fSmrg	   get_element(c->reg.dir, 2),
10901e04c3fSmrg	   brw_imm_f(0));
11001e04c3fSmrg
11101e04c3fSmrg   brw_IF(p, BRW_EXECUTE_1);
11201e04c3fSmrg   {
11301e04c3fSmrg      brw_clip_kill_thread(c);
11401e04c3fSmrg   }
11501e04c3fSmrg   brw_ENDIF(p);
11601e04c3fSmrg}
11701e04c3fSmrg
11801e04c3fSmrg
11901e04c3fSmrg
12001e04c3fSmrgstatic void copy_bfc( struct brw_clip_compile *c )
12101e04c3fSmrg{
12201e04c3fSmrg   struct brw_codegen *p = &c->func;
12301e04c3fSmrg   GLuint conditional;
12401e04c3fSmrg
12501e04c3fSmrg   /* Do we have any colors to copy?
12601e04c3fSmrg    */
12701e04c3fSmrg   if (!(brw_clip_have_varying(c, VARYING_SLOT_COL0) &&
12801e04c3fSmrg         brw_clip_have_varying(c, VARYING_SLOT_BFC0)) &&
12901e04c3fSmrg       !(brw_clip_have_varying(c, VARYING_SLOT_COL1) &&
13001e04c3fSmrg         brw_clip_have_varying(c, VARYING_SLOT_BFC1)))
13101e04c3fSmrg      return;
13201e04c3fSmrg
13301e04c3fSmrg   /* In some weird degenerate cases we can end up testing the
13401e04c3fSmrg    * direction twice, once for culling and once for bfc copying.  Oh
13501e04c3fSmrg    * well, that's what you get for setting weird GL state.
13601e04c3fSmrg    */
13701e04c3fSmrg   if (c->key.copy_bfc_ccw)
13801e04c3fSmrg      conditional = BRW_CONDITIONAL_GE;
13901e04c3fSmrg   else
14001e04c3fSmrg      conditional = BRW_CONDITIONAL_L;
14101e04c3fSmrg
14201e04c3fSmrg   brw_CMP(p,
14301e04c3fSmrg	   vec1(brw_null_reg()),
14401e04c3fSmrg	   conditional,
14501e04c3fSmrg	   get_element(c->reg.dir, 2),
14601e04c3fSmrg	   brw_imm_f(0));
14701e04c3fSmrg
14801e04c3fSmrg   brw_IF(p, BRW_EXECUTE_1);
14901e04c3fSmrg   {
15001e04c3fSmrg      GLuint i;
15101e04c3fSmrg
15201e04c3fSmrg      for (i = 0; i < 3; i++) {
15301e04c3fSmrg	 if (brw_clip_have_varying(c, VARYING_SLOT_COL0) &&
15401e04c3fSmrg             brw_clip_have_varying(c, VARYING_SLOT_BFC0))
15501e04c3fSmrg	    brw_MOV(p,
15601e04c3fSmrg		    byte_offset(c->reg.vertex[i],
15701e04c3fSmrg                                brw_varying_to_offset(&c->vue_map,
15801e04c3fSmrg                                                      VARYING_SLOT_COL0)),
15901e04c3fSmrg		    byte_offset(c->reg.vertex[i],
16001e04c3fSmrg                                brw_varying_to_offset(&c->vue_map,
16101e04c3fSmrg                                                      VARYING_SLOT_BFC0)));
16201e04c3fSmrg
16301e04c3fSmrg	 if (brw_clip_have_varying(c, VARYING_SLOT_COL1) &&
16401e04c3fSmrg             brw_clip_have_varying(c, VARYING_SLOT_BFC1))
16501e04c3fSmrg	    brw_MOV(p,
16601e04c3fSmrg		    byte_offset(c->reg.vertex[i],
16701e04c3fSmrg                                brw_varying_to_offset(&c->vue_map,
16801e04c3fSmrg                                                      VARYING_SLOT_COL1)),
16901e04c3fSmrg		    byte_offset(c->reg.vertex[i],
17001e04c3fSmrg                                brw_varying_to_offset(&c->vue_map,
17101e04c3fSmrg                                                      VARYING_SLOT_BFC1)));
17201e04c3fSmrg      }
17301e04c3fSmrg   }
17401e04c3fSmrg   brw_ENDIF(p);
17501e04c3fSmrg}
17601e04c3fSmrg
17701e04c3fSmrg
17801e04c3fSmrg
17901e04c3fSmrg
18001e04c3fSmrg/*
18101e04c3fSmrg  GLfloat iz	= 1.0 / dir.z;
18201e04c3fSmrg  GLfloat ac	= dir.x * iz;
18301e04c3fSmrg  GLfloat bc	= dir.y * iz;
18401e04c3fSmrg  offset = ctx->Polygon.OffsetUnits * DEPTH_SCALE;
18501e04c3fSmrg  offset += MAX2( abs(ac), abs(bc) ) * ctx->Polygon.OffsetFactor;
18601e04c3fSmrg  if (ctx->Polygon.OffsetClamp && isfinite(ctx->Polygon.OffsetClamp)) {
18701e04c3fSmrg    if (ctx->Polygon.OffsetClamp < 0)
18801e04c3fSmrg      offset = MAX2( offset, ctx->Polygon.OffsetClamp );
18901e04c3fSmrg    else
19001e04c3fSmrg      offset = MIN2( offset, ctx->Polygon.OffsetClamp );
19101e04c3fSmrg  }
19201e04c3fSmrg  offset *= MRD;
19301e04c3fSmrg*/
19401e04c3fSmrgstatic void compute_offset( struct brw_clip_compile *c )
19501e04c3fSmrg{
19601e04c3fSmrg   struct brw_codegen *p = &c->func;
19701e04c3fSmrg   struct brw_reg off = c->reg.offset;
19801e04c3fSmrg   struct brw_reg dir = c->reg.dir;
19901e04c3fSmrg
20001e04c3fSmrg   brw_math_invert(p, get_element(off, 2), get_element(dir, 2));
20101e04c3fSmrg   brw_MUL(p, vec2(off), vec2(dir), get_element(off, 2));
20201e04c3fSmrg
20301e04c3fSmrg   brw_CMP(p,
20401e04c3fSmrg	   vec1(brw_null_reg()),
20501e04c3fSmrg	   BRW_CONDITIONAL_GE,
20601e04c3fSmrg	   brw_abs(get_element(off, 0)),
20701e04c3fSmrg	   brw_abs(get_element(off, 1)));
20801e04c3fSmrg
20901e04c3fSmrg   brw_SEL(p, vec1(off),
21001e04c3fSmrg           brw_abs(get_element(off, 0)), brw_abs(get_element(off, 1)));
21101e04c3fSmrg   brw_inst_set_pred_control(p->devinfo, brw_last_inst, BRW_PREDICATE_NORMAL);
21201e04c3fSmrg
21301e04c3fSmrg   brw_MUL(p, vec1(off), vec1(off), brw_imm_f(c->key.offset_factor));
21401e04c3fSmrg   brw_ADD(p, vec1(off), vec1(off), brw_imm_f(c->key.offset_units));
21501e04c3fSmrg   if (c->key.offset_clamp && isfinite(c->key.offset_clamp)) {
21601e04c3fSmrg      brw_CMP(p,
21701e04c3fSmrg              vec1(brw_null_reg()),
21801e04c3fSmrg              c->key.offset_clamp < 0 ? BRW_CONDITIONAL_GE : BRW_CONDITIONAL_L,
21901e04c3fSmrg              vec1(off),
22001e04c3fSmrg              brw_imm_f(c->key.offset_clamp));
22101e04c3fSmrg      brw_SEL(p, vec1(off), vec1(off), brw_imm_f(c->key.offset_clamp));
22201e04c3fSmrg   }
22301e04c3fSmrg}
22401e04c3fSmrg
22501e04c3fSmrg
22601e04c3fSmrgstatic void merge_edgeflags( struct brw_clip_compile *c )
22701e04c3fSmrg{
22801e04c3fSmrg   struct brw_codegen *p = &c->func;
22901e04c3fSmrg   struct brw_reg tmp0 = get_element_ud(c->reg.tmp0, 0);
23001e04c3fSmrg
23101e04c3fSmrg   brw_AND(p, tmp0, get_element_ud(c->reg.R0, 2), brw_imm_ud(PRIM_MASK));
23201e04c3fSmrg   brw_CMP(p,
23301e04c3fSmrg	   vec1(brw_null_reg()),
23401e04c3fSmrg	   BRW_CONDITIONAL_EQ,
23501e04c3fSmrg	   tmp0,
23601e04c3fSmrg	   brw_imm_ud(_3DPRIM_POLYGON));
23701e04c3fSmrg
23801e04c3fSmrg   /* Get away with using reg.vertex because we know that this is not
23901e04c3fSmrg    * a _3DPRIM_TRISTRIP_REVERSE:
24001e04c3fSmrg    */
24101e04c3fSmrg   brw_IF(p, BRW_EXECUTE_1);
24201e04c3fSmrg   {
24301e04c3fSmrg      brw_AND(p, vec1(brw_null_reg()), get_element_ud(c->reg.R0, 2), brw_imm_ud(1<<8));
24401e04c3fSmrg      brw_inst_set_cond_modifier(p->devinfo, brw_last_inst, BRW_CONDITIONAL_EQ);
24501e04c3fSmrg      brw_MOV(p, byte_offset(c->reg.vertex[0],
24601e04c3fSmrg                             brw_varying_to_offset(&c->vue_map,
24701e04c3fSmrg                                                   VARYING_SLOT_EDGE)),
24801e04c3fSmrg              brw_imm_f(0));
24901e04c3fSmrg      brw_inst_set_pred_control(p->devinfo, brw_last_inst, BRW_PREDICATE_NORMAL);
25001e04c3fSmrg
25101e04c3fSmrg      brw_AND(p, vec1(brw_null_reg()), get_element_ud(c->reg.R0, 2), brw_imm_ud(1<<9));
25201e04c3fSmrg      brw_inst_set_cond_modifier(p->devinfo, brw_last_inst, BRW_CONDITIONAL_EQ);
25301e04c3fSmrg      brw_MOV(p, byte_offset(c->reg.vertex[2],
25401e04c3fSmrg                             brw_varying_to_offset(&c->vue_map,
25501e04c3fSmrg                                                   VARYING_SLOT_EDGE)),
25601e04c3fSmrg              brw_imm_f(0));
25701e04c3fSmrg      brw_inst_set_pred_control(p->devinfo, brw_last_inst, BRW_PREDICATE_NORMAL);
25801e04c3fSmrg   }
25901e04c3fSmrg   brw_ENDIF(p);
26001e04c3fSmrg}
26101e04c3fSmrg
26201e04c3fSmrg
26301e04c3fSmrg
26401e04c3fSmrgstatic void apply_one_offset( struct brw_clip_compile *c,
26501e04c3fSmrg			  struct brw_indirect vert )
26601e04c3fSmrg{
26701e04c3fSmrg   struct brw_codegen *p = &c->func;
26801e04c3fSmrg   GLuint ndc_offset = brw_varying_to_offset(&c->vue_map,
26901e04c3fSmrg                                             BRW_VARYING_SLOT_NDC);
27001e04c3fSmrg   struct brw_reg z = deref_1f(vert, ndc_offset +
27101e04c3fSmrg			       2 * type_sz(BRW_REGISTER_TYPE_F));
27201e04c3fSmrg
27301e04c3fSmrg   brw_ADD(p, z, z, vec1(c->reg.offset));
27401e04c3fSmrg}
27501e04c3fSmrg
27601e04c3fSmrg
27701e04c3fSmrg
27801e04c3fSmrg/***********************************************************************
27901e04c3fSmrg * Output clipped polygon as an unfilled primitive:
28001e04c3fSmrg */
28101e04c3fSmrgstatic void emit_lines(struct brw_clip_compile *c,
28201e04c3fSmrg		       bool do_offset)
28301e04c3fSmrg{
28401e04c3fSmrg   struct brw_codegen *p = &c->func;
28501e04c3fSmrg   struct brw_indirect v0 = brw_indirect(0, 0);
28601e04c3fSmrg   struct brw_indirect v1 = brw_indirect(1, 0);
28701e04c3fSmrg   struct brw_indirect v0ptr = brw_indirect(2, 0);
28801e04c3fSmrg   struct brw_indirect v1ptr = brw_indirect(3, 0);
28901e04c3fSmrg
29001e04c3fSmrg   /* Need a separate loop for offset:
29101e04c3fSmrg    */
29201e04c3fSmrg   if (do_offset) {
29301e04c3fSmrg      brw_MOV(p, c->reg.loopcount, c->reg.nr_verts);
29401e04c3fSmrg      brw_MOV(p, get_addr_reg(v0ptr), brw_address(c->reg.inlist));
29501e04c3fSmrg
29601e04c3fSmrg      brw_DO(p, BRW_EXECUTE_1);
29701e04c3fSmrg      {
29801e04c3fSmrg	 brw_MOV(p, get_addr_reg(v0), deref_1uw(v0ptr, 0));
29901e04c3fSmrg	 brw_ADD(p, get_addr_reg(v0ptr), get_addr_reg(v0ptr), brw_imm_uw(2));
30001e04c3fSmrg
30101e04c3fSmrg	 apply_one_offset(c, v0);
30201e04c3fSmrg
30301e04c3fSmrg	 brw_ADD(p, c->reg.loopcount, c->reg.loopcount, brw_imm_d(-1));
30401e04c3fSmrg         brw_inst_set_cond_modifier(p->devinfo, brw_last_inst, BRW_CONDITIONAL_G);
30501e04c3fSmrg      }
30601e04c3fSmrg      brw_WHILE(p);
30701e04c3fSmrg      brw_inst_set_pred_control(p->devinfo, brw_last_inst, BRW_PREDICATE_NORMAL);
30801e04c3fSmrg   }
30901e04c3fSmrg
31001e04c3fSmrg   /* v1ptr = &inlist[nr_verts]
31101e04c3fSmrg    * *v1ptr = v0
31201e04c3fSmrg    */
31301e04c3fSmrg   brw_MOV(p, c->reg.loopcount, c->reg.nr_verts);
31401e04c3fSmrg   brw_MOV(p, get_addr_reg(v0ptr), brw_address(c->reg.inlist));
31501e04c3fSmrg   brw_ADD(p, get_addr_reg(v1ptr), get_addr_reg(v0ptr), retype(c->reg.nr_verts, BRW_REGISTER_TYPE_UW));
31601e04c3fSmrg   brw_ADD(p, get_addr_reg(v1ptr), get_addr_reg(v1ptr), retype(c->reg.nr_verts, BRW_REGISTER_TYPE_UW));
31701e04c3fSmrg   brw_MOV(p, deref_1uw(v1ptr, 0), deref_1uw(v0ptr, 0));
31801e04c3fSmrg
31901e04c3fSmrg   brw_DO(p, BRW_EXECUTE_1);
32001e04c3fSmrg   {
32101e04c3fSmrg      brw_MOV(p, get_addr_reg(v0), deref_1uw(v0ptr, 0));
32201e04c3fSmrg      brw_MOV(p, get_addr_reg(v1), deref_1uw(v0ptr, 2));
32301e04c3fSmrg      brw_ADD(p, get_addr_reg(v0ptr), get_addr_reg(v0ptr), brw_imm_uw(2));
32401e04c3fSmrg
32501e04c3fSmrg      /* draw edge if edgeflag != 0 */
32601e04c3fSmrg      brw_CMP(p,
32701e04c3fSmrg	      vec1(brw_null_reg()), BRW_CONDITIONAL_NZ,
32801e04c3fSmrg	      deref_1f(v0, brw_varying_to_offset(&c->vue_map,
32901e04c3fSmrg                                                 VARYING_SLOT_EDGE)),
33001e04c3fSmrg	      brw_imm_f(0));
33101e04c3fSmrg      brw_IF(p, BRW_EXECUTE_1);
33201e04c3fSmrg      {
33301e04c3fSmrg	 brw_clip_emit_vue(c, v0, BRW_URB_WRITE_ALLOCATE_COMPLETE,
33401e04c3fSmrg                           (_3DPRIM_LINESTRIP << URB_WRITE_PRIM_TYPE_SHIFT)
33501e04c3fSmrg                           | URB_WRITE_PRIM_START);
33601e04c3fSmrg	 brw_clip_emit_vue(c, v1, BRW_URB_WRITE_ALLOCATE_COMPLETE,
33701e04c3fSmrg                           (_3DPRIM_LINESTRIP << URB_WRITE_PRIM_TYPE_SHIFT)
33801e04c3fSmrg                           | URB_WRITE_PRIM_END);
33901e04c3fSmrg      }
34001e04c3fSmrg      brw_ENDIF(p);
34101e04c3fSmrg
34201e04c3fSmrg      brw_ADD(p, c->reg.loopcount, c->reg.loopcount, brw_imm_d(-1));
34301e04c3fSmrg      brw_inst_set_cond_modifier(p->devinfo, brw_last_inst, BRW_CONDITIONAL_NZ);
34401e04c3fSmrg   }
34501e04c3fSmrg   brw_WHILE(p);
34601e04c3fSmrg   brw_inst_set_pred_control(p->devinfo, brw_last_inst, BRW_PREDICATE_NORMAL);
34701e04c3fSmrg}
34801e04c3fSmrg
34901e04c3fSmrg
35001e04c3fSmrg
35101e04c3fSmrgstatic void emit_points(struct brw_clip_compile *c,
35201e04c3fSmrg			bool do_offset )
35301e04c3fSmrg{
35401e04c3fSmrg   struct brw_codegen *p = &c->func;
35501e04c3fSmrg
35601e04c3fSmrg   struct brw_indirect v0 = brw_indirect(0, 0);
35701e04c3fSmrg   struct brw_indirect v0ptr = brw_indirect(2, 0);
35801e04c3fSmrg
35901e04c3fSmrg   brw_MOV(p, c->reg.loopcount, c->reg.nr_verts);
36001e04c3fSmrg   brw_MOV(p, get_addr_reg(v0ptr), brw_address(c->reg.inlist));
36101e04c3fSmrg
36201e04c3fSmrg   brw_DO(p, BRW_EXECUTE_1);
36301e04c3fSmrg   {
36401e04c3fSmrg      brw_MOV(p, get_addr_reg(v0), deref_1uw(v0ptr, 0));
36501e04c3fSmrg      brw_ADD(p, get_addr_reg(v0ptr), get_addr_reg(v0ptr), brw_imm_uw(2));
36601e04c3fSmrg
36701e04c3fSmrg      /* draw if edgeflag != 0
36801e04c3fSmrg       */
36901e04c3fSmrg      brw_CMP(p,
37001e04c3fSmrg	      vec1(brw_null_reg()), BRW_CONDITIONAL_NZ,
37101e04c3fSmrg	      deref_1f(v0, brw_varying_to_offset(&c->vue_map,
37201e04c3fSmrg                                                 VARYING_SLOT_EDGE)),
37301e04c3fSmrg	      brw_imm_f(0));
37401e04c3fSmrg      brw_IF(p, BRW_EXECUTE_1);
37501e04c3fSmrg      {
37601e04c3fSmrg	 if (do_offset)
37701e04c3fSmrg	    apply_one_offset(c, v0);
37801e04c3fSmrg
37901e04c3fSmrg	 brw_clip_emit_vue(c, v0, BRW_URB_WRITE_ALLOCATE_COMPLETE,
38001e04c3fSmrg                           (_3DPRIM_POINTLIST << URB_WRITE_PRIM_TYPE_SHIFT)
38101e04c3fSmrg                           | URB_WRITE_PRIM_START | URB_WRITE_PRIM_END);
38201e04c3fSmrg      }
38301e04c3fSmrg      brw_ENDIF(p);
38401e04c3fSmrg
38501e04c3fSmrg      brw_ADD(p, c->reg.loopcount, c->reg.loopcount, brw_imm_d(-1));
38601e04c3fSmrg      brw_inst_set_cond_modifier(p->devinfo, brw_last_inst, BRW_CONDITIONAL_NZ);
38701e04c3fSmrg   }
38801e04c3fSmrg   brw_WHILE(p);
38901e04c3fSmrg   brw_inst_set_pred_control(p->devinfo, brw_last_inst, BRW_PREDICATE_NORMAL);
39001e04c3fSmrg}
39101e04c3fSmrg
39201e04c3fSmrg
39301e04c3fSmrg
39401e04c3fSmrg
39501e04c3fSmrg
39601e04c3fSmrg
39701e04c3fSmrg
39801e04c3fSmrgstatic void emit_primitives( struct brw_clip_compile *c,
39901e04c3fSmrg			     GLuint mode,
40001e04c3fSmrg			     bool do_offset )
40101e04c3fSmrg{
40201e04c3fSmrg   switch (mode) {
40301e04c3fSmrg   case BRW_CLIP_FILL_MODE_FILL:
40401e04c3fSmrg      brw_clip_tri_emit_polygon(c);
40501e04c3fSmrg      break;
40601e04c3fSmrg
40701e04c3fSmrg   case BRW_CLIP_FILL_MODE_LINE:
40801e04c3fSmrg      emit_lines(c, do_offset);
40901e04c3fSmrg      break;
41001e04c3fSmrg
41101e04c3fSmrg   case BRW_CLIP_FILL_MODE_POINT:
41201e04c3fSmrg      emit_points(c, do_offset);
41301e04c3fSmrg      break;
41401e04c3fSmrg
41501e04c3fSmrg   case BRW_CLIP_FILL_MODE_CULL:
41601e04c3fSmrg      unreachable("not reached");
41701e04c3fSmrg   }
41801e04c3fSmrg}
41901e04c3fSmrg
42001e04c3fSmrg
42101e04c3fSmrg
42201e04c3fSmrgstatic void emit_unfilled_primitives( struct brw_clip_compile *c )
42301e04c3fSmrg{
42401e04c3fSmrg   struct brw_codegen *p = &c->func;
42501e04c3fSmrg
42601e04c3fSmrg   /* Direction culling has already been done.
42701e04c3fSmrg    */
42801e04c3fSmrg   if (c->key.fill_ccw != c->key.fill_cw &&
42901e04c3fSmrg       c->key.fill_ccw != BRW_CLIP_FILL_MODE_CULL &&
43001e04c3fSmrg       c->key.fill_cw != BRW_CLIP_FILL_MODE_CULL)
43101e04c3fSmrg   {
43201e04c3fSmrg      brw_CMP(p,
43301e04c3fSmrg	      vec1(brw_null_reg()),
43401e04c3fSmrg	      BRW_CONDITIONAL_GE,
43501e04c3fSmrg	      get_element(c->reg.dir, 2),
43601e04c3fSmrg	      brw_imm_f(0));
43701e04c3fSmrg
43801e04c3fSmrg      brw_IF(p, BRW_EXECUTE_1);
43901e04c3fSmrg      {
44001e04c3fSmrg	 emit_primitives(c, c->key.fill_ccw, c->key.offset_ccw);
44101e04c3fSmrg      }
44201e04c3fSmrg      brw_ELSE(p);
44301e04c3fSmrg      {
44401e04c3fSmrg	 emit_primitives(c, c->key.fill_cw, c->key.offset_cw);
44501e04c3fSmrg      }
44601e04c3fSmrg      brw_ENDIF(p);
44701e04c3fSmrg   }
44801e04c3fSmrg   else if (c->key.fill_cw != BRW_CLIP_FILL_MODE_CULL) {
44901e04c3fSmrg      emit_primitives(c, c->key.fill_cw, c->key.offset_cw);
45001e04c3fSmrg   }
45101e04c3fSmrg   else if (c->key.fill_ccw != BRW_CLIP_FILL_MODE_CULL) {
45201e04c3fSmrg      emit_primitives(c, c->key.fill_ccw, c->key.offset_ccw);
45301e04c3fSmrg   }
45401e04c3fSmrg}
45501e04c3fSmrg
45601e04c3fSmrg
45701e04c3fSmrg
45801e04c3fSmrg
45901e04c3fSmrgstatic void check_nr_verts( struct brw_clip_compile *c )
46001e04c3fSmrg{
46101e04c3fSmrg   struct brw_codegen *p = &c->func;
46201e04c3fSmrg
46301e04c3fSmrg   brw_CMP(p, vec1(brw_null_reg()), BRW_CONDITIONAL_L, c->reg.nr_verts, brw_imm_d(3));
46401e04c3fSmrg   brw_IF(p, BRW_EXECUTE_1);
46501e04c3fSmrg   {
46601e04c3fSmrg      brw_clip_kill_thread(c);
46701e04c3fSmrg   }
46801e04c3fSmrg   brw_ENDIF(p);
46901e04c3fSmrg}
47001e04c3fSmrg
47101e04c3fSmrg
47201e04c3fSmrgvoid brw_emit_unfilled_clip( struct brw_clip_compile *c )
47301e04c3fSmrg{
47401e04c3fSmrg   struct brw_codegen *p = &c->func;
47501e04c3fSmrg
47601e04c3fSmrg   c->need_direction = ((c->key.offset_ccw || c->key.offset_cw) ||
47701e04c3fSmrg			(c->key.fill_ccw != c->key.fill_cw) ||
47801e04c3fSmrg			c->key.fill_ccw == BRW_CLIP_FILL_MODE_CULL ||
47901e04c3fSmrg			c->key.fill_cw == BRW_CLIP_FILL_MODE_CULL ||
48001e04c3fSmrg			c->key.copy_bfc_cw ||
48101e04c3fSmrg			c->key.copy_bfc_ccw);
48201e04c3fSmrg
48301e04c3fSmrg   brw_clip_tri_alloc_regs(c, 3 + c->key.nr_userclip + 6);
48401e04c3fSmrg   brw_clip_tri_init_vertices(c);
48501e04c3fSmrg   brw_clip_init_ff_sync(c);
48601e04c3fSmrg
48701e04c3fSmrg   assert(brw_clip_have_varying(c, VARYING_SLOT_EDGE));
48801e04c3fSmrg
48901e04c3fSmrg   if (c->key.fill_ccw == BRW_CLIP_FILL_MODE_CULL &&
49001e04c3fSmrg       c->key.fill_cw == BRW_CLIP_FILL_MODE_CULL) {
49101e04c3fSmrg      brw_clip_kill_thread(c);
49201e04c3fSmrg      return;
49301e04c3fSmrg   }
49401e04c3fSmrg
49501e04c3fSmrg   merge_edgeflags(c);
49601e04c3fSmrg
49701e04c3fSmrg   /* Need to use the inlist indirection here:
49801e04c3fSmrg    */
49901e04c3fSmrg   if (c->need_direction)
50001e04c3fSmrg      compute_tri_direction(c);
50101e04c3fSmrg
50201e04c3fSmrg   if (c->key.fill_ccw == BRW_CLIP_FILL_MODE_CULL ||
50301e04c3fSmrg       c->key.fill_cw == BRW_CLIP_FILL_MODE_CULL)
50401e04c3fSmrg      cull_direction(c);
50501e04c3fSmrg
50601e04c3fSmrg   if (c->key.offset_ccw ||
50701e04c3fSmrg       c->key.offset_cw)
50801e04c3fSmrg      compute_offset(c);
50901e04c3fSmrg
51001e04c3fSmrg   if (c->key.copy_bfc_ccw ||
51101e04c3fSmrg       c->key.copy_bfc_cw)
51201e04c3fSmrg      copy_bfc(c);
51301e04c3fSmrg
51401e04c3fSmrg   /* Need to do this whether we clip or not:
51501e04c3fSmrg    */
51601e04c3fSmrg   if (c->key.contains_flat_varying)
51701e04c3fSmrg      brw_clip_tri_flat_shade(c);
51801e04c3fSmrg
51901e04c3fSmrg   brw_clip_init_clipmask(c);
52001e04c3fSmrg   brw_CMP(p, vec1(brw_null_reg()), BRW_CONDITIONAL_NZ, c->reg.planemask, brw_imm_ud(0));
52101e04c3fSmrg   brw_IF(p, BRW_EXECUTE_1);
52201e04c3fSmrg   {
52301e04c3fSmrg      brw_clip_init_planes(c);
52401e04c3fSmrg      brw_clip_tri(c);
52501e04c3fSmrg      check_nr_verts(c);
52601e04c3fSmrg   }
52701e04c3fSmrg   brw_ENDIF(p);
52801e04c3fSmrg
52901e04c3fSmrg   emit_unfilled_primitives(c);
53001e04c3fSmrg   brw_clip_kill_thread(c);
53101e04c3fSmrg}
532