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
3301e04c3fSmrg#include "main/macros.h"
3401e04c3fSmrg#include "main/enums.h"
3501e04c3fSmrg#include "program/program.h"
3601e04c3fSmrg
3701e04c3fSmrg#include "brw_clip.h"
3801e04c3fSmrg
3901e04c3fSmrg
4001e04c3fSmrgstruct brw_reg get_tmp( struct brw_clip_compile *c )
4101e04c3fSmrg{
4201e04c3fSmrg   struct brw_reg tmp = brw_vec4_grf(c->last_tmp, 0);
4301e04c3fSmrg
4401e04c3fSmrg   if (++c->last_tmp > c->prog_data.total_grf)
4501e04c3fSmrg      c->prog_data.total_grf = c->last_tmp;
4601e04c3fSmrg
4701e04c3fSmrg   return tmp;
4801e04c3fSmrg}
4901e04c3fSmrg
5001e04c3fSmrgstatic void release_tmp( struct brw_clip_compile *c, struct brw_reg tmp )
5101e04c3fSmrg{
5201e04c3fSmrg   if (tmp.nr == c->last_tmp-1)
5301e04c3fSmrg      c->last_tmp--;
5401e04c3fSmrg}
5501e04c3fSmrg
5601e04c3fSmrg
5701e04c3fSmrgstatic struct brw_reg make_plane_ud(GLuint x, GLuint y, GLuint z, GLuint w)
5801e04c3fSmrg{
5901e04c3fSmrg   return brw_imm_ud((w<<24) | (z<<16) | (y<<8) | x);
6001e04c3fSmrg}
6101e04c3fSmrg
6201e04c3fSmrg
6301e04c3fSmrgvoid brw_clip_init_planes( struct brw_clip_compile *c )
6401e04c3fSmrg{
6501e04c3fSmrg   struct brw_codegen *p = &c->func;
6601e04c3fSmrg
6701e04c3fSmrg   if (!c->key.nr_userclip) {
6801e04c3fSmrg      brw_MOV(p, get_element_ud(c->reg.fixed_planes, 0), make_plane_ud( 0,    0, 0xff, 1));
6901e04c3fSmrg      brw_MOV(p, get_element_ud(c->reg.fixed_planes, 1), make_plane_ud( 0,    0,    1, 1));
7001e04c3fSmrg      brw_MOV(p, get_element_ud(c->reg.fixed_planes, 2), make_plane_ud( 0, 0xff,    0, 1));
7101e04c3fSmrg      brw_MOV(p, get_element_ud(c->reg.fixed_planes, 3), make_plane_ud( 0,    1,    0, 1));
7201e04c3fSmrg      brw_MOV(p, get_element_ud(c->reg.fixed_planes, 4), make_plane_ud(0xff,  0,    0, 1));
7301e04c3fSmrg      brw_MOV(p, get_element_ud(c->reg.fixed_planes, 5), make_plane_ud( 1,    0,    0, 1));
7401e04c3fSmrg   }
7501e04c3fSmrg}
7601e04c3fSmrg
7701e04c3fSmrg
7801e04c3fSmrg
7901e04c3fSmrg#define W 3
8001e04c3fSmrg
8101e04c3fSmrg/* Project 'pos' to screen space (or back again), overwrite with results:
8201e04c3fSmrg */
8301e04c3fSmrgvoid brw_clip_project_position(struct brw_clip_compile *c, struct brw_reg pos )
8401e04c3fSmrg{
8501e04c3fSmrg   struct brw_codegen *p = &c->func;
8601e04c3fSmrg
8701e04c3fSmrg   /* calc rhw
8801e04c3fSmrg    */
8901e04c3fSmrg   brw_math_invert(p, get_element(pos, W), get_element(pos, W));
9001e04c3fSmrg
9101e04c3fSmrg   /* value.xyz *= value.rhw
9201e04c3fSmrg    */
9301e04c3fSmrg   brw_set_default_access_mode(p, BRW_ALIGN_16);
9401e04c3fSmrg   brw_MUL(p, brw_writemask(pos, WRITEMASK_XYZ), pos,
9501e04c3fSmrg           brw_swizzle(pos, BRW_SWIZZLE_WWWW));
9601e04c3fSmrg   brw_set_default_access_mode(p, BRW_ALIGN_1);
9701e04c3fSmrg}
9801e04c3fSmrg
9901e04c3fSmrg
10001e04c3fSmrgstatic void brw_clip_project_vertex( struct brw_clip_compile *c,
10101e04c3fSmrg				     struct brw_indirect vert_addr )
10201e04c3fSmrg{
10301e04c3fSmrg   struct brw_codegen *p = &c->func;
10401e04c3fSmrg   struct brw_reg tmp = get_tmp(c);
10501e04c3fSmrg   GLuint hpos_offset = brw_varying_to_offset(&c->vue_map, VARYING_SLOT_POS);
10601e04c3fSmrg   GLuint ndc_offset = brw_varying_to_offset(&c->vue_map,
10701e04c3fSmrg                                             BRW_VARYING_SLOT_NDC);
10801e04c3fSmrg
10901e04c3fSmrg   /* Fixup position.  Extract from the original vertex and re-project
11001e04c3fSmrg    * to screen space:
11101e04c3fSmrg    */
11201e04c3fSmrg   brw_MOV(p, tmp, deref_4f(vert_addr, hpos_offset));
11301e04c3fSmrg   brw_clip_project_position(c, tmp);
11401e04c3fSmrg   brw_MOV(p, deref_4f(vert_addr, ndc_offset), tmp);
11501e04c3fSmrg
11601e04c3fSmrg   release_tmp(c, tmp);
11701e04c3fSmrg}
11801e04c3fSmrg
11901e04c3fSmrg
12001e04c3fSmrg
12101e04c3fSmrg
12201e04c3fSmrg/* Interpolate between two vertices and put the result into a0.0.
12301e04c3fSmrg * Increment a0.0 accordingly.
12401e04c3fSmrg *
12501e04c3fSmrg * Beware that dest_ptr can be equal to v0_ptr!
12601e04c3fSmrg */
12701e04c3fSmrgvoid brw_clip_interp_vertex( struct brw_clip_compile *c,
12801e04c3fSmrg			     struct brw_indirect dest_ptr,
12901e04c3fSmrg			     struct brw_indirect v0_ptr, /* from */
13001e04c3fSmrg			     struct brw_indirect v1_ptr, /* to */
13101e04c3fSmrg			     struct brw_reg t0,
13201e04c3fSmrg			     bool force_edgeflag)
13301e04c3fSmrg{
13401e04c3fSmrg   struct brw_codegen *p = &c->func;
13501e04c3fSmrg   struct brw_reg t_nopersp, v0_ndc_copy;
13601e04c3fSmrg   GLuint slot;
13701e04c3fSmrg
13801e04c3fSmrg   /* Just copy the vertex header:
13901e04c3fSmrg    */
14001e04c3fSmrg   /*
14101e04c3fSmrg    * After CLIP stage, only first 256 bits of the VUE are read
14201e04c3fSmrg    * back on Ironlake, so needn't change it
14301e04c3fSmrg    */
14401e04c3fSmrg   brw_copy_indirect_to_indirect(p, dest_ptr, v0_ptr, 1);
14501e04c3fSmrg
14601e04c3fSmrg
14701e04c3fSmrg   /* First handle the 3D and NDC interpolation, in case we
14801e04c3fSmrg    * need noperspective interpolation. Doing it early has no
14901e04c3fSmrg    * performance impact in any case.
15001e04c3fSmrg    */
15101e04c3fSmrg
15201e04c3fSmrg   /* Take a copy of the v0 NDC coordinates, in case dest == v0. */
15301e04c3fSmrg   if (c->key.contains_noperspective_varying) {
15401e04c3fSmrg      GLuint offset = brw_varying_to_offset(&c->vue_map,
15501e04c3fSmrg                                                 BRW_VARYING_SLOT_NDC);
15601e04c3fSmrg      v0_ndc_copy = get_tmp(c);
15701e04c3fSmrg      brw_MOV(p, v0_ndc_copy, deref_4f(v0_ptr, offset));
15801e04c3fSmrg   }
15901e04c3fSmrg
16001e04c3fSmrg   /* Compute the new 3D position
16101e04c3fSmrg    *
16201e04c3fSmrg    * dest_hpos = v0_hpos * (1 - t0) + v1_hpos * t0
16301e04c3fSmrg    */
16401e04c3fSmrg   {
16501e04c3fSmrg      GLuint delta = brw_varying_to_offset(&c->vue_map, VARYING_SLOT_POS);
16601e04c3fSmrg      struct brw_reg tmp = get_tmp(c);
16701e04c3fSmrg      brw_MUL(p, vec4(brw_null_reg()), deref_4f(v1_ptr, delta), t0);
16801e04c3fSmrg      brw_MAC(p, tmp, negate(deref_4f(v0_ptr, delta)), t0);
16901e04c3fSmrg      brw_ADD(p, deref_4f(dest_ptr, delta), deref_4f(v0_ptr, delta), tmp);
17001e04c3fSmrg      release_tmp(c, tmp);
17101e04c3fSmrg   }
17201e04c3fSmrg
17301e04c3fSmrg   /* Recreate the projected (NDC) coordinate in the new vertex header */
17401e04c3fSmrg   brw_clip_project_vertex(c, dest_ptr);
17501e04c3fSmrg
17601e04c3fSmrg   /* If we have noperspective attributes,
17701e04c3fSmrg    * we need to compute the screen-space t
17801e04c3fSmrg    */
17901e04c3fSmrg   if (c->key.contains_noperspective_varying) {
18001e04c3fSmrg      GLuint delta = brw_varying_to_offset(&c->vue_map,
18101e04c3fSmrg                                                BRW_VARYING_SLOT_NDC);
18201e04c3fSmrg      struct brw_reg tmp = get_tmp(c);
18301e04c3fSmrg      t_nopersp = get_tmp(c);
18401e04c3fSmrg
18501e04c3fSmrg      /* t_nopersp = vec4(v1.xy, dest.xy) */
18601e04c3fSmrg      brw_MOV(p, t_nopersp, deref_4f(v1_ptr, delta));
18701e04c3fSmrg      brw_MOV(p, tmp, deref_4f(dest_ptr, delta));
18801e04c3fSmrg      brw_set_default_access_mode(p, BRW_ALIGN_16);
18901e04c3fSmrg      brw_MOV(p,
19001e04c3fSmrg              brw_writemask(t_nopersp, WRITEMASK_ZW),
19101e04c3fSmrg              brw_swizzle(tmp, BRW_SWIZZLE_XYXY));
19201e04c3fSmrg
19301e04c3fSmrg      /* t_nopersp = vec4(v1.xy, dest.xy) - v0.xyxy */
19401e04c3fSmrg      brw_ADD(p, t_nopersp, t_nopersp,
19501e04c3fSmrg              negate(brw_swizzle(v0_ndc_copy, BRW_SWIZZLE_XYXY)));
19601e04c3fSmrg
19701e04c3fSmrg      /* Add the absolute values of the X and Y deltas so that if
19801e04c3fSmrg       * the points aren't in the same place on the screen we get
19901e04c3fSmrg       * nonzero values to divide.
20001e04c3fSmrg       *
20101e04c3fSmrg       * After that, we have vert1 - vert0 in t_nopersp.x and
20201e04c3fSmrg       * vertnew - vert0 in t_nopersp.y
20301e04c3fSmrg       *
20401e04c3fSmrg       * t_nopersp = vec2(|v1.x  -v0.x| + |v1.y  -v0.y|,
20501e04c3fSmrg       *                  |dest.x-v0.x| + |dest.y-v0.y|)
20601e04c3fSmrg       */
20701e04c3fSmrg      brw_ADD(p,
20801e04c3fSmrg              brw_writemask(t_nopersp, WRITEMASK_XY),
20901e04c3fSmrg              brw_abs(brw_swizzle(t_nopersp, BRW_SWIZZLE_XZXZ)),
21001e04c3fSmrg              brw_abs(brw_swizzle(t_nopersp, BRW_SWIZZLE_YWYW)));
21101e04c3fSmrg      brw_set_default_access_mode(p, BRW_ALIGN_1);
21201e04c3fSmrg
21301e04c3fSmrg      /* If the points are in the same place, just substitute a
21401e04c3fSmrg       * value to avoid divide-by-zero
21501e04c3fSmrg       */
21601e04c3fSmrg      brw_CMP(p, vec1(brw_null_reg()), BRW_CONDITIONAL_EQ,
21701e04c3fSmrg              vec1(t_nopersp),
21801e04c3fSmrg              brw_imm_f(0));
21901e04c3fSmrg      brw_IF(p, BRW_EXECUTE_1);
22001e04c3fSmrg      brw_MOV(p, t_nopersp, brw_imm_vf4(brw_float_to_vf(1.0),
22101e04c3fSmrg                                        brw_float_to_vf(0.0),
22201e04c3fSmrg                                        brw_float_to_vf(0.0),
22301e04c3fSmrg                                        brw_float_to_vf(0.0)));
22401e04c3fSmrg      brw_ENDIF(p);
22501e04c3fSmrg
22601e04c3fSmrg      /* Now compute t_nopersp = t_nopersp.y/t_nopersp.x and broadcast it. */
22701e04c3fSmrg      brw_math_invert(p, get_element(t_nopersp, 0), get_element(t_nopersp, 0));
22801e04c3fSmrg      brw_MUL(p, vec1(t_nopersp), vec1(t_nopersp),
22901e04c3fSmrg            vec1(suboffset(t_nopersp, 1)));
23001e04c3fSmrg      brw_set_default_access_mode(p, BRW_ALIGN_16);
23101e04c3fSmrg      brw_MOV(p, t_nopersp, brw_swizzle(t_nopersp, BRW_SWIZZLE_XXXX));
23201e04c3fSmrg      brw_set_default_access_mode(p, BRW_ALIGN_1);
23301e04c3fSmrg
23401e04c3fSmrg      release_tmp(c, tmp);
23501e04c3fSmrg      release_tmp(c, v0_ndc_copy);
23601e04c3fSmrg   }
23701e04c3fSmrg
23801e04c3fSmrg   /* Now we can iterate over each attribute
23901e04c3fSmrg    * (could be done in pairs?)
24001e04c3fSmrg    */
24101e04c3fSmrg   for (slot = 0; slot < c->vue_map.num_slots; slot++) {
24201e04c3fSmrg      int varying = c->vue_map.slot_to_varying[slot];
24301e04c3fSmrg      GLuint delta = brw_vue_slot_to_offset(slot);
24401e04c3fSmrg
24501e04c3fSmrg      /* HPOS, NDC already handled above */
24601e04c3fSmrg      if (varying == VARYING_SLOT_POS || varying == BRW_VARYING_SLOT_NDC)
24701e04c3fSmrg         continue;
24801e04c3fSmrg
24901e04c3fSmrg
25001e04c3fSmrg      if (varying == VARYING_SLOT_EDGE) {
25101e04c3fSmrg	 if (force_edgeflag)
25201e04c3fSmrg	    brw_MOV(p, deref_4f(dest_ptr, delta), brw_imm_f(1));
25301e04c3fSmrg	 else
25401e04c3fSmrg	    brw_MOV(p, deref_4f(dest_ptr, delta), deref_4f(v0_ptr, delta));
25501e04c3fSmrg      } else if (varying == VARYING_SLOT_PSIZ) {
25601e04c3fSmrg         /* PSIZ doesn't need interpolation because it isn't used by the
25701e04c3fSmrg          * fragment shader.
25801e04c3fSmrg          */
25901e04c3fSmrg      } else if (varying < VARYING_SLOT_MAX) {
26001e04c3fSmrg	 /* This is a true vertex result (and not a special value for the VUE
26101e04c3fSmrg	  * header), so interpolate:
26201e04c3fSmrg	  *
26301e04c3fSmrg	  *        New = attr0 + t*attr1 - t*attr0
26401e04c3fSmrg          *
26501e04c3fSmrg          * Unless the attribute is flat shaded -- in which case just copy
26601e04c3fSmrg          * from one of the sources (doesn't matter which; already copied from pv)
26701e04c3fSmrg	  */
26801e04c3fSmrg         GLuint interp = c->key.interp_mode[slot];
26901e04c3fSmrg
27001e04c3fSmrg         if (interp != INTERP_MODE_FLAT) {
27101e04c3fSmrg            struct brw_reg tmp = get_tmp(c);
27201e04c3fSmrg            struct brw_reg t =
27301e04c3fSmrg               interp == INTERP_MODE_NOPERSPECTIVE ? t_nopersp : t0;
27401e04c3fSmrg
27501e04c3fSmrg            brw_MUL(p,
27601e04c3fSmrg                  vec4(brw_null_reg()),
27701e04c3fSmrg                  deref_4f(v1_ptr, delta),
27801e04c3fSmrg                  t);
27901e04c3fSmrg
28001e04c3fSmrg            brw_MAC(p,
28101e04c3fSmrg                  tmp,
28201e04c3fSmrg                  negate(deref_4f(v0_ptr, delta)),
28301e04c3fSmrg                  t);
28401e04c3fSmrg
28501e04c3fSmrg            brw_ADD(p,
28601e04c3fSmrg                  deref_4f(dest_ptr, delta),
28701e04c3fSmrg                  deref_4f(v0_ptr, delta),
28801e04c3fSmrg                  tmp);
28901e04c3fSmrg
29001e04c3fSmrg            release_tmp(c, tmp);
29101e04c3fSmrg         }
29201e04c3fSmrg         else {
29301e04c3fSmrg            brw_MOV(p,
29401e04c3fSmrg                  deref_4f(dest_ptr, delta),
29501e04c3fSmrg                  deref_4f(v0_ptr, delta));
29601e04c3fSmrg         }
29701e04c3fSmrg      }
29801e04c3fSmrg   }
29901e04c3fSmrg
30001e04c3fSmrg   if (c->vue_map.num_slots % 2) {
30101e04c3fSmrg      GLuint delta = brw_vue_slot_to_offset(c->vue_map.num_slots);
30201e04c3fSmrg
30301e04c3fSmrg      brw_MOV(p, deref_4f(dest_ptr, delta), brw_imm_f(0));
30401e04c3fSmrg   }
30501e04c3fSmrg
30601e04c3fSmrg   if (c->key.contains_noperspective_varying)
30701e04c3fSmrg      release_tmp(c, t_nopersp);
30801e04c3fSmrg}
30901e04c3fSmrg
31001e04c3fSmrgvoid brw_clip_emit_vue(struct brw_clip_compile *c,
31101e04c3fSmrg		       struct brw_indirect vert,
31201e04c3fSmrg                       enum brw_urb_write_flags flags,
31301e04c3fSmrg		       GLuint header)
31401e04c3fSmrg{
31501e04c3fSmrg   struct brw_codegen *p = &c->func;
31601e04c3fSmrg   bool allocate = flags & BRW_URB_WRITE_ALLOCATE;
31701e04c3fSmrg
31801e04c3fSmrg   brw_clip_ff_sync(c);
31901e04c3fSmrg
32001e04c3fSmrg   /* Any URB entry that is allocated must subsequently be used or discarded,
32101e04c3fSmrg    * so it doesn't make sense to mark EOT and ALLOCATE at the same time.
32201e04c3fSmrg    */
32301e04c3fSmrg   assert(!(allocate && (flags & BRW_URB_WRITE_EOT)));
32401e04c3fSmrg
32501e04c3fSmrg   /* Copy the vertex from vertn into m1..mN+1:
32601e04c3fSmrg    */
32701e04c3fSmrg   brw_copy_from_indirect(p, brw_message_reg(1), vert, c->nr_regs);
32801e04c3fSmrg
32901e04c3fSmrg   /* Overwrite PrimType and PrimStart in the message header, for
33001e04c3fSmrg    * each vertex in turn:
33101e04c3fSmrg    */
33201e04c3fSmrg   brw_MOV(p, get_element_ud(c->reg.R0, 2), brw_imm_ud(header));
33301e04c3fSmrg
33401e04c3fSmrg
33501e04c3fSmrg   /* Send each vertex as a separate write to the urb.  This
33601e04c3fSmrg    * is different to the concept in brw_sf_emit.c, where
33701e04c3fSmrg    * subsequent writes are used to build up a single urb
33801e04c3fSmrg    * entry.  Each of these writes instantiates a separate
33901e04c3fSmrg    * urb entry - (I think... what about 'allocate'?)
34001e04c3fSmrg    */
34101e04c3fSmrg   brw_urb_WRITE(p,
34201e04c3fSmrg		 allocate ? c->reg.R0 : retype(brw_null_reg(), BRW_REGISTER_TYPE_UD),
34301e04c3fSmrg		 0,
34401e04c3fSmrg		 c->reg.R0,
34501e04c3fSmrg                 flags,
34601e04c3fSmrg		 c->nr_regs + 1, /* msg length */
34701e04c3fSmrg		 allocate ? 1 : 0, /* response_length */
34801e04c3fSmrg		 0,		/* urb offset */
34901e04c3fSmrg		 BRW_URB_SWIZZLE_NONE);
35001e04c3fSmrg}
35101e04c3fSmrg
35201e04c3fSmrg
35301e04c3fSmrg
35401e04c3fSmrgvoid brw_clip_kill_thread(struct brw_clip_compile *c)
35501e04c3fSmrg{
35601e04c3fSmrg   struct brw_codegen *p = &c->func;
35701e04c3fSmrg
35801e04c3fSmrg   brw_clip_ff_sync(c);
35901e04c3fSmrg   /* Send an empty message to kill the thread and release any
36001e04c3fSmrg    * allocated urb entry:
36101e04c3fSmrg    */
36201e04c3fSmrg   brw_urb_WRITE(p,
36301e04c3fSmrg		 retype(brw_null_reg(), BRW_REGISTER_TYPE_UD),
36401e04c3fSmrg		 0,
36501e04c3fSmrg		 c->reg.R0,
36601e04c3fSmrg                 BRW_URB_WRITE_UNUSED | BRW_URB_WRITE_EOT_COMPLETE,
36701e04c3fSmrg		 1, 		/* msg len */
36801e04c3fSmrg		 0, 		/* response len */
36901e04c3fSmrg		 0,
37001e04c3fSmrg		 BRW_URB_SWIZZLE_NONE);
37101e04c3fSmrg}
37201e04c3fSmrg
37301e04c3fSmrg
37401e04c3fSmrg
37501e04c3fSmrg
37601e04c3fSmrgstruct brw_reg brw_clip_plane0_address( struct brw_clip_compile *c )
37701e04c3fSmrg{
37801e04c3fSmrg   return brw_address(c->reg.fixed_planes);
37901e04c3fSmrg}
38001e04c3fSmrg
38101e04c3fSmrg
38201e04c3fSmrgstruct brw_reg brw_clip_plane_stride( struct brw_clip_compile *c )
38301e04c3fSmrg{
38401e04c3fSmrg   if (c->key.nr_userclip) {
38501e04c3fSmrg      return brw_imm_uw(16);
38601e04c3fSmrg   }
38701e04c3fSmrg   else {
38801e04c3fSmrg      return brw_imm_uw(4);
38901e04c3fSmrg   }
39001e04c3fSmrg}
39101e04c3fSmrg
39201e04c3fSmrg
39301e04c3fSmrg/* Distribute flatshaded attributes from provoking vertex prior to
39401e04c3fSmrg * clipping.
39501e04c3fSmrg */
39601e04c3fSmrgvoid brw_clip_copy_flatshaded_attributes( struct brw_clip_compile *c,
39701e04c3fSmrg			   GLuint to, GLuint from )
39801e04c3fSmrg{
39901e04c3fSmrg   struct brw_codegen *p = &c->func;
40001e04c3fSmrg
40101e04c3fSmrg   for (int i = 0; i < c->vue_map.num_slots; i++) {
40201e04c3fSmrg      if (c->key.interp_mode[i] == INTERP_MODE_FLAT) {
40301e04c3fSmrg         brw_MOV(p,
40401e04c3fSmrg                 byte_offset(c->reg.vertex[to], brw_vue_slot_to_offset(i)),
40501e04c3fSmrg                 byte_offset(c->reg.vertex[from], brw_vue_slot_to_offset(i)));
40601e04c3fSmrg      }
40701e04c3fSmrg   }
40801e04c3fSmrg}
40901e04c3fSmrg
41001e04c3fSmrg
41101e04c3fSmrg
41201e04c3fSmrgvoid brw_clip_init_clipmask( struct brw_clip_compile *c )
41301e04c3fSmrg{
41401e04c3fSmrg   struct brw_codegen *p = &c->func;
41501e04c3fSmrg   struct brw_reg incoming = get_element_ud(c->reg.R0, 2);
41601e04c3fSmrg
41701e04c3fSmrg   /* Shift so that lowest outcode bit is rightmost:
41801e04c3fSmrg    */
41901e04c3fSmrg   brw_SHR(p, c->reg.planemask, incoming, brw_imm_ud(26));
42001e04c3fSmrg
42101e04c3fSmrg   if (c->key.nr_userclip) {
42201e04c3fSmrg      struct brw_reg tmp = retype(vec1(get_tmp(c)), BRW_REGISTER_TYPE_UD);
42301e04c3fSmrg
42401e04c3fSmrg      /* Rearrange userclip outcodes so that they come directly after
42501e04c3fSmrg       * the fixed plane bits.
42601e04c3fSmrg       */
4277ec681f3Smrg      if (p->devinfo->ver == 5 || p->devinfo->is_g4x)
42801e04c3fSmrg         brw_AND(p, tmp, incoming, brw_imm_ud(0xff<<14));
42901e04c3fSmrg      else
43001e04c3fSmrg         brw_AND(p, tmp, incoming, brw_imm_ud(0x3f<<14));
43101e04c3fSmrg
43201e04c3fSmrg      brw_SHR(p, tmp, tmp, brw_imm_ud(8));
43301e04c3fSmrg      brw_OR(p, c->reg.planemask, c->reg.planemask, tmp);
43401e04c3fSmrg
43501e04c3fSmrg      release_tmp(c, tmp);
43601e04c3fSmrg   }
43701e04c3fSmrg}
43801e04c3fSmrg
43901e04c3fSmrgvoid brw_clip_ff_sync(struct brw_clip_compile *c)
44001e04c3fSmrg{
44101e04c3fSmrg    struct brw_codegen *p = &c->func;
44201e04c3fSmrg
4437ec681f3Smrg    if (p->devinfo->ver == 5) {
44401e04c3fSmrg        brw_AND(p, brw_null_reg(), c->reg.ff_sync, brw_imm_ud(0x1));
44501e04c3fSmrg        brw_inst_set_cond_modifier(p->devinfo, brw_last_inst, BRW_CONDITIONAL_Z);
44601e04c3fSmrg        brw_IF(p, BRW_EXECUTE_1);
44701e04c3fSmrg        {
44801e04c3fSmrg            brw_OR(p, c->reg.ff_sync, c->reg.ff_sync, brw_imm_ud(0x1));
44901e04c3fSmrg            brw_ff_sync(p,
45001e04c3fSmrg			c->reg.R0,
45101e04c3fSmrg			0,
45201e04c3fSmrg			c->reg.R0,
45301e04c3fSmrg			1, /* allocate */
45401e04c3fSmrg			1, /* response length */
45501e04c3fSmrg			0 /* eot */);
45601e04c3fSmrg        }
45701e04c3fSmrg        brw_ENDIF(p);
45801e04c3fSmrg        brw_set_default_predicate_control(p, BRW_PREDICATE_NONE);
45901e04c3fSmrg    }
46001e04c3fSmrg}
46101e04c3fSmrg
46201e04c3fSmrgvoid brw_clip_init_ff_sync(struct brw_clip_compile *c)
46301e04c3fSmrg{
46401e04c3fSmrg    struct brw_codegen *p = &c->func;
46501e04c3fSmrg
4667ec681f3Smrg    if (p->devinfo->ver == 5) {
46701e04c3fSmrg        brw_MOV(p, c->reg.ff_sync, brw_imm_ud(0));
46801e04c3fSmrg    }
46901e04c3fSmrg}
470