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 brw_clip_line_alloc_regs( struct brw_clip_compile *c )
3901e04c3fSmrg{
407ec681f3Smrg   const struct intel_device_info *devinfo = c->func.devinfo;
4101e04c3fSmrg   GLuint i = 0,j;
4201e04c3fSmrg
4301e04c3fSmrg   /* Register usage is static, precompute here:
4401e04c3fSmrg    */
4501e04c3fSmrg   c->reg.R0 = retype(brw_vec8_grf(i, 0), BRW_REGISTER_TYPE_UD); i++;
4601e04c3fSmrg
4701e04c3fSmrg   if (c->key.nr_userclip) {
4801e04c3fSmrg      c->reg.fixed_planes = brw_vec4_grf(i, 0);
4901e04c3fSmrg      i += (6 + c->key.nr_userclip + 1) / 2;
5001e04c3fSmrg
5101e04c3fSmrg      c->prog_data.curb_read_length = (6 + c->key.nr_userclip + 1) / 2;
5201e04c3fSmrg   }
5301e04c3fSmrg   else
5401e04c3fSmrg      c->prog_data.curb_read_length = 0;
5501e04c3fSmrg
5601e04c3fSmrg
5701e04c3fSmrg   /* Payload vertices plus space for more generated vertices:
5801e04c3fSmrg    */
5901e04c3fSmrg   for (j = 0; j < 4; j++) {
6001e04c3fSmrg      c->reg.vertex[j] = brw_vec4_grf(i, 0);
6101e04c3fSmrg      i += c->nr_regs;
6201e04c3fSmrg   }
6301e04c3fSmrg
6401e04c3fSmrg   c->reg.t           = brw_vec1_grf(i, 0);
6501e04c3fSmrg   c->reg.t0          = brw_vec1_grf(i, 1);
6601e04c3fSmrg   c->reg.t1          = brw_vec1_grf(i, 2);
6701e04c3fSmrg   c->reg.planemask   = retype(brw_vec1_grf(i, 3), BRW_REGISTER_TYPE_UD);
6801e04c3fSmrg   c->reg.plane_equation = brw_vec4_grf(i, 4);
6901e04c3fSmrg   i++;
7001e04c3fSmrg
7101e04c3fSmrg   c->reg.dp0         = brw_vec1_grf(i, 0); /* fixme - dp4 will clobber r.1,2,3 */
7201e04c3fSmrg   c->reg.dp1         = brw_vec1_grf(i, 4);
7301e04c3fSmrg   i++;
7401e04c3fSmrg
7501e04c3fSmrg   if (!c->key.nr_userclip) {
7601e04c3fSmrg      c->reg.fixed_planes = brw_vec8_grf(i, 0);
7701e04c3fSmrg      i++;
7801e04c3fSmrg   }
7901e04c3fSmrg
8001e04c3fSmrg   c->reg.vertex_src_mask = retype(brw_vec1_grf(i, 0), BRW_REGISTER_TYPE_UD);
8101e04c3fSmrg   c->reg.clipdistance_offset = retype(brw_vec1_grf(i, 1), BRW_REGISTER_TYPE_W);
8201e04c3fSmrg   i++;
8301e04c3fSmrg
847ec681f3Smrg   if (devinfo->ver == 5) {
8501e04c3fSmrg      c->reg.ff_sync = retype(brw_vec1_grf(i, 0), BRW_REGISTER_TYPE_UD);
8601e04c3fSmrg      i++;
8701e04c3fSmrg   }
8801e04c3fSmrg
8901e04c3fSmrg   c->first_tmp = i;
9001e04c3fSmrg   c->last_tmp = i;
9101e04c3fSmrg
9201e04c3fSmrg   c->prog_data.urb_read_length = c->nr_regs; /* ? */
9301e04c3fSmrg   c->prog_data.total_grf = i;
9401e04c3fSmrg}
9501e04c3fSmrg
9601e04c3fSmrg
9701e04c3fSmrg/* Line clipping, more or less following the following algorithm:
9801e04c3fSmrg *
9901e04c3fSmrg *  for (p=0;p<MAX_PLANES;p++) {
10001e04c3fSmrg *     if (clipmask & (1 << p)) {
10101e04c3fSmrg *        GLfloat dp0 = DOTPROD( vtx0, plane[p] );
10201e04c3fSmrg *        GLfloat dp1 = DOTPROD( vtx1, plane[p] );
10301e04c3fSmrg *
10401e04c3fSmrg *        if (dp1 < 0.0f) {
10501e04c3fSmrg *           GLfloat t = dp1 / (dp1 - dp0);
10601e04c3fSmrg *           if (t > t1) t1 = t;
10701e04c3fSmrg *        } else {
10801e04c3fSmrg *           GLfloat t = dp0 / (dp0 - dp1);
10901e04c3fSmrg *           if (t > t0) t0 = t;
11001e04c3fSmrg *        }
11101e04c3fSmrg *
11201e04c3fSmrg *        if (t0 + t1 >= 1.0)
11301e04c3fSmrg *           return;
11401e04c3fSmrg *     }
11501e04c3fSmrg *  }
11601e04c3fSmrg *
11701e04c3fSmrg *  interp( ctx, newvtx0, vtx0, vtx1, t0 );
11801e04c3fSmrg *  interp( ctx, newvtx1, vtx1, vtx0, t1 );
11901e04c3fSmrg *
12001e04c3fSmrg */
12101e04c3fSmrgstatic void clip_and_emit_line( struct brw_clip_compile *c )
12201e04c3fSmrg{
12301e04c3fSmrg   struct brw_codegen *p = &c->func;
12401e04c3fSmrg   struct brw_indirect vtx0     = brw_indirect(0, 0);
12501e04c3fSmrg   struct brw_indirect vtx1      = brw_indirect(1, 0);
12601e04c3fSmrg   struct brw_indirect newvtx0   = brw_indirect(2, 0);
12701e04c3fSmrg   struct brw_indirect newvtx1   = brw_indirect(3, 0);
12801e04c3fSmrg   struct brw_indirect plane_ptr = brw_indirect(4, 0);
12901e04c3fSmrg   struct brw_reg v1_null_ud = retype(vec1(brw_null_reg()), BRW_REGISTER_TYPE_UD);
13001e04c3fSmrg   GLuint hpos_offset = brw_varying_to_offset(&c->vue_map, VARYING_SLOT_POS);
13101e04c3fSmrg   GLint clipdist0_offset = c->key.nr_userclip
13201e04c3fSmrg      ? brw_varying_to_offset(&c->vue_map, VARYING_SLOT_CLIP_DIST0)
13301e04c3fSmrg      : 0;
13401e04c3fSmrg
13501e04c3fSmrg   brw_MOV(p, get_addr_reg(vtx0),      brw_address(c->reg.vertex[0]));
13601e04c3fSmrg   brw_MOV(p, get_addr_reg(vtx1),      brw_address(c->reg.vertex[1]));
13701e04c3fSmrg   brw_MOV(p, get_addr_reg(newvtx0),   brw_address(c->reg.vertex[2]));
13801e04c3fSmrg   brw_MOV(p, get_addr_reg(newvtx1),   brw_address(c->reg.vertex[3]));
13901e04c3fSmrg   brw_MOV(p, get_addr_reg(plane_ptr), brw_clip_plane0_address(c));
14001e04c3fSmrg
14101e04c3fSmrg   /* Note: init t0, t1 together:
14201e04c3fSmrg    */
14301e04c3fSmrg   brw_MOV(p, vec2(c->reg.t0), brw_imm_f(0));
14401e04c3fSmrg
14501e04c3fSmrg   brw_clip_init_planes(c);
14601e04c3fSmrg   brw_clip_init_clipmask(c);
14701e04c3fSmrg
14801e04c3fSmrg   /* -ve rhw workaround */
14901e04c3fSmrg   if (p->devinfo->has_negative_rhw_bug) {
15001e04c3fSmrg      brw_AND(p, brw_null_reg(), get_element_ud(c->reg.R0, 2),
15101e04c3fSmrg              brw_imm_ud(1<<20));
15201e04c3fSmrg      brw_inst_set_cond_modifier(p->devinfo, brw_last_inst, BRW_CONDITIONAL_NZ);
15301e04c3fSmrg      brw_OR(p, c->reg.planemask, c->reg.planemask, brw_imm_ud(0x3f));
15401e04c3fSmrg      brw_inst_set_pred_control(p->devinfo, brw_last_inst, BRW_PREDICATE_NORMAL);
15501e04c3fSmrg   }
15601e04c3fSmrg
15701e04c3fSmrg   /* Set the initial vertex source mask: The first 6 planes are the bounds
15801e04c3fSmrg    * of the view volume; the next 8 planes are the user clipping planes.
15901e04c3fSmrg    */
16001e04c3fSmrg   brw_MOV(p, c->reg.vertex_src_mask, brw_imm_ud(0x3fc0));
16101e04c3fSmrg
16201e04c3fSmrg   /* Set the initial clipdistance offset to be 6 floats before gl_ClipDistance[0].
16301e04c3fSmrg    * We'll increment 6 times before we start hitting actual user clipping. */
16401e04c3fSmrg   brw_MOV(p, c->reg.clipdistance_offset, brw_imm_d(clipdist0_offset - 6*sizeof(float)));
16501e04c3fSmrg
16601e04c3fSmrg   brw_DO(p, BRW_EXECUTE_1);
16701e04c3fSmrg   {
16801e04c3fSmrg      /* if (planemask & 1)
16901e04c3fSmrg       */
17001e04c3fSmrg      brw_AND(p, v1_null_ud, c->reg.planemask, brw_imm_ud(1));
17101e04c3fSmrg      brw_inst_set_cond_modifier(p->devinfo, brw_last_inst, BRW_CONDITIONAL_NZ);
17201e04c3fSmrg
17301e04c3fSmrg      brw_IF(p, BRW_EXECUTE_1);
17401e04c3fSmrg      {
17501e04c3fSmrg         brw_AND(p, v1_null_ud, c->reg.vertex_src_mask, brw_imm_ud(1));
17601e04c3fSmrg         brw_inst_set_cond_modifier(p->devinfo, brw_last_inst, BRW_CONDITIONAL_NZ);
17701e04c3fSmrg         brw_IF(p, BRW_EXECUTE_1);
17801e04c3fSmrg         {
17901e04c3fSmrg            /* user clip distance: just fetch the correct float from each vertex */
18001e04c3fSmrg            struct brw_indirect temp_ptr = brw_indirect(7, 0);
18101e04c3fSmrg            brw_ADD(p, get_addr_reg(temp_ptr), get_addr_reg(vtx0), c->reg.clipdistance_offset);
18201e04c3fSmrg            brw_MOV(p, c->reg.dp0, deref_1f(temp_ptr, 0));
18301e04c3fSmrg            brw_ADD(p, get_addr_reg(temp_ptr), get_addr_reg(vtx1), c->reg.clipdistance_offset);
18401e04c3fSmrg            brw_MOV(p, c->reg.dp1, deref_1f(temp_ptr, 0));
18501e04c3fSmrg         }
18601e04c3fSmrg         brw_ELSE(p);
18701e04c3fSmrg         {
18801e04c3fSmrg            /* fixed plane: fetch the hpos, dp4 against the plane. */
18901e04c3fSmrg            if (c->key.nr_userclip)
19001e04c3fSmrg               brw_MOV(p, c->reg.plane_equation, deref_4f(plane_ptr, 0));
19101e04c3fSmrg            else
19201e04c3fSmrg               brw_MOV(p, c->reg.plane_equation, deref_4b(plane_ptr, 0));
19301e04c3fSmrg
19401e04c3fSmrg            brw_DP4(p, vec4(c->reg.dp0), deref_4f(vtx0, hpos_offset), c->reg.plane_equation);
19501e04c3fSmrg            brw_DP4(p, vec4(c->reg.dp1), deref_4f(vtx1, hpos_offset), c->reg.plane_equation);
19601e04c3fSmrg         }
19701e04c3fSmrg         brw_ENDIF(p);
19801e04c3fSmrg
19901e04c3fSmrg         brw_CMP(p, brw_null_reg(), BRW_CONDITIONAL_L, vec1(c->reg.dp1), brw_imm_f(0.0f));
20001e04c3fSmrg
20101e04c3fSmrg         brw_IF(p, BRW_EXECUTE_1);
20201e04c3fSmrg         {
20301e04c3fSmrg             /*
20401e04c3fSmrg              * Both can be negative on GM965/G965 due to RHW workaround
20501e04c3fSmrg              * if so, this object should be rejected.
20601e04c3fSmrg              */
20701e04c3fSmrg             if (p->devinfo->has_negative_rhw_bug) {
20801e04c3fSmrg                 brw_CMP(p, vec1(brw_null_reg()), BRW_CONDITIONAL_LE, c->reg.dp0, brw_imm_f(0.0));
20901e04c3fSmrg                 brw_IF(p, BRW_EXECUTE_1);
21001e04c3fSmrg                 {
21101e04c3fSmrg                     brw_clip_kill_thread(c);
21201e04c3fSmrg                 }
21301e04c3fSmrg                 brw_ENDIF(p);
21401e04c3fSmrg             }
21501e04c3fSmrg
21601e04c3fSmrg             brw_ADD(p, c->reg.t, c->reg.dp1, negate(c->reg.dp0));
21701e04c3fSmrg             brw_math_invert(p, c->reg.t, c->reg.t);
21801e04c3fSmrg             brw_MUL(p, c->reg.t, c->reg.t, c->reg.dp1);
21901e04c3fSmrg
22001e04c3fSmrg             brw_CMP(p, vec1(brw_null_reg()), BRW_CONDITIONAL_G, c->reg.t, c->reg.t1 );
22101e04c3fSmrg             brw_MOV(p, c->reg.t1, c->reg.t);
22201e04c3fSmrg             brw_inst_set_pred_control(p->devinfo, brw_last_inst,
22301e04c3fSmrg                                       BRW_PREDICATE_NORMAL);
22401e04c3fSmrg	 }
22501e04c3fSmrg	 brw_ELSE(p);
22601e04c3fSmrg	 {
22701e04c3fSmrg             /* Coming back in.  We know that both cannot be negative
22801e04c3fSmrg              * because the line would have been culled in that case.
22901e04c3fSmrg              */
23001e04c3fSmrg
23101e04c3fSmrg             /* If both are positive, do nothing */
23201e04c3fSmrg             /* Only on GM965/G965 */
23301e04c3fSmrg             if (p->devinfo->has_negative_rhw_bug) {
23401e04c3fSmrg                 brw_CMP(p, vec1(brw_null_reg()), BRW_CONDITIONAL_L, c->reg.dp0, brw_imm_f(0.0));
23501e04c3fSmrg                 brw_IF(p, BRW_EXECUTE_1);
23601e04c3fSmrg             }
23701e04c3fSmrg
23801e04c3fSmrg             {
23901e04c3fSmrg                 brw_ADD(p, c->reg.t, c->reg.dp0, negate(c->reg.dp1));
24001e04c3fSmrg                 brw_math_invert(p, c->reg.t, c->reg.t);
24101e04c3fSmrg                 brw_MUL(p, c->reg.t, c->reg.t, c->reg.dp0);
24201e04c3fSmrg
24301e04c3fSmrg                 brw_CMP(p, vec1(brw_null_reg()), BRW_CONDITIONAL_G, c->reg.t, c->reg.t0 );
24401e04c3fSmrg                 brw_MOV(p, c->reg.t0, c->reg.t);
24501e04c3fSmrg                 brw_inst_set_pred_control(p->devinfo, brw_last_inst,
24601e04c3fSmrg                                           BRW_PREDICATE_NORMAL);
24701e04c3fSmrg             }
24801e04c3fSmrg
24901e04c3fSmrg             if (p->devinfo->has_negative_rhw_bug) {
25001e04c3fSmrg                 brw_ENDIF(p);
25101e04c3fSmrg             }
25201e04c3fSmrg         }
25301e04c3fSmrg	 brw_ENDIF(p);
25401e04c3fSmrg      }
25501e04c3fSmrg      brw_ENDIF(p);
25601e04c3fSmrg
25701e04c3fSmrg      /* plane_ptr++;
25801e04c3fSmrg       */
25901e04c3fSmrg      brw_ADD(p, get_addr_reg(plane_ptr), get_addr_reg(plane_ptr), brw_clip_plane_stride(c));
26001e04c3fSmrg
26101e04c3fSmrg      /* while (planemask>>=1) != 0
26201e04c3fSmrg       */
26301e04c3fSmrg      brw_SHR(p, c->reg.planemask, c->reg.planemask, brw_imm_ud(1));
26401e04c3fSmrg      brw_inst_set_cond_modifier(p->devinfo, brw_last_inst, BRW_CONDITIONAL_NZ);
26501e04c3fSmrg      brw_SHR(p, c->reg.vertex_src_mask, c->reg.vertex_src_mask, brw_imm_ud(1));
26601e04c3fSmrg      brw_inst_set_pred_control(p->devinfo, brw_last_inst, BRW_PREDICATE_NORMAL);
26701e04c3fSmrg      brw_ADD(p, c->reg.clipdistance_offset, c->reg.clipdistance_offset, brw_imm_w(sizeof(float)));
26801e04c3fSmrg      brw_inst_set_pred_control(p->devinfo, brw_last_inst, BRW_PREDICATE_NORMAL);
26901e04c3fSmrg   }
27001e04c3fSmrg   brw_WHILE(p);
27101e04c3fSmrg   brw_inst_set_pred_control(p->devinfo, brw_last_inst, BRW_PREDICATE_NORMAL);
27201e04c3fSmrg
27301e04c3fSmrg   brw_ADD(p, c->reg.t, c->reg.t0, c->reg.t1);
27401e04c3fSmrg   brw_CMP(p, vec1(brw_null_reg()), BRW_CONDITIONAL_L, c->reg.t, brw_imm_f(1.0));
27501e04c3fSmrg   brw_IF(p, BRW_EXECUTE_1);
27601e04c3fSmrg   {
27701e04c3fSmrg      brw_clip_interp_vertex(c, newvtx0, vtx0, vtx1, c->reg.t0, false);
27801e04c3fSmrg      brw_clip_interp_vertex(c, newvtx1, vtx1, vtx0, c->reg.t1, false);
27901e04c3fSmrg
28001e04c3fSmrg      brw_clip_emit_vue(c, newvtx0, BRW_URB_WRITE_ALLOCATE_COMPLETE,
28101e04c3fSmrg                        (_3DPRIM_LINESTRIP << URB_WRITE_PRIM_TYPE_SHIFT)
28201e04c3fSmrg                        | URB_WRITE_PRIM_START);
28301e04c3fSmrg      brw_clip_emit_vue(c, newvtx1, BRW_URB_WRITE_EOT_COMPLETE,
28401e04c3fSmrg                        (_3DPRIM_LINESTRIP << URB_WRITE_PRIM_TYPE_SHIFT)
28501e04c3fSmrg                        | URB_WRITE_PRIM_END);
28601e04c3fSmrg   }
28701e04c3fSmrg   brw_ENDIF(p);
28801e04c3fSmrg   brw_clip_kill_thread(c);
28901e04c3fSmrg}
29001e04c3fSmrg
29101e04c3fSmrg
29201e04c3fSmrg
29301e04c3fSmrgvoid brw_emit_line_clip( struct brw_clip_compile *c )
29401e04c3fSmrg{
29501e04c3fSmrg   brw_clip_line_alloc_regs(c);
29601e04c3fSmrg   brw_clip_init_ff_sync(c);
29701e04c3fSmrg
29801e04c3fSmrg   if (c->key.contains_flat_varying) {
29901e04c3fSmrg      if (c->key.pv_first)
30001e04c3fSmrg         brw_clip_copy_flatshaded_attributes(c, 1, 0);
30101e04c3fSmrg      else
30201e04c3fSmrg         brw_clip_copy_flatshaded_attributes(c, 0, 1);
30301e04c3fSmrg   }
30401e04c3fSmrg
30501e04c3fSmrg   clip_and_emit_line(c);
30601e04c3fSmrg}
307