1b8e80941Smrg/*
2b8e80941Smrg Copyright (C) Intel Corp.  2006.  All Rights Reserved.
3b8e80941Smrg Intel funded Tungsten Graphics to
4b8e80941Smrg develop this 3D driver.
5b8e80941Smrg
6b8e80941Smrg Permission is hereby granted, free of charge, to any person obtaining
7b8e80941Smrg a copy of this software and associated documentation files (the
8b8e80941Smrg "Software"), to deal in the Software without restriction, including
9b8e80941Smrg without limitation the rights to use, copy, modify, merge, publish,
10b8e80941Smrg distribute, sublicense, and/or sell copies of the Software, and to
11b8e80941Smrg permit persons to whom the Software is furnished to do so, subject to
12b8e80941Smrg the following conditions:
13b8e80941Smrg
14b8e80941Smrg The above copyright notice and this permission notice (including the
15b8e80941Smrg next paragraph) shall be included in all copies or substantial
16b8e80941Smrg portions of the Software.
17b8e80941Smrg
18b8e80941Smrg THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19b8e80941Smrg EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20b8e80941Smrg MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21b8e80941Smrg IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
22b8e80941Smrg LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23b8e80941Smrg OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24b8e80941Smrg WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25b8e80941Smrg
26b8e80941Smrg **********************************************************************/
27b8e80941Smrg /*
28b8e80941Smrg  * Authors:
29b8e80941Smrg  *   Keith Whitwell <keithw@vmware.com>
30b8e80941Smrg  */
31b8e80941Smrg
32b8e80941Smrg
33b8e80941Smrg#include "main/macros.h"
34b8e80941Smrg#include "main/enums.h"
35b8e80941Smrg#include "program/program.h"
36b8e80941Smrg
37b8e80941Smrg#include "brw_clip.h"
38b8e80941Smrg
39b8e80941Smrg
40b8e80941Smrgstruct brw_reg get_tmp( struct brw_clip_compile *c )
41b8e80941Smrg{
42b8e80941Smrg   struct brw_reg tmp = brw_vec4_grf(c->last_tmp, 0);
43b8e80941Smrg
44b8e80941Smrg   if (++c->last_tmp > c->prog_data.total_grf)
45b8e80941Smrg      c->prog_data.total_grf = c->last_tmp;
46b8e80941Smrg
47b8e80941Smrg   return tmp;
48b8e80941Smrg}
49b8e80941Smrg
50b8e80941Smrgstatic void release_tmp( struct brw_clip_compile *c, struct brw_reg tmp )
51b8e80941Smrg{
52b8e80941Smrg   if (tmp.nr == c->last_tmp-1)
53b8e80941Smrg      c->last_tmp--;
54b8e80941Smrg}
55b8e80941Smrg
56b8e80941Smrg
57b8e80941Smrgstatic struct brw_reg make_plane_ud(GLuint x, GLuint y, GLuint z, GLuint w)
58b8e80941Smrg{
59b8e80941Smrg   return brw_imm_ud((w<<24) | (z<<16) | (y<<8) | x);
60b8e80941Smrg}
61b8e80941Smrg
62b8e80941Smrg
63b8e80941Smrgvoid brw_clip_init_planes( struct brw_clip_compile *c )
64b8e80941Smrg{
65b8e80941Smrg   struct brw_codegen *p = &c->func;
66b8e80941Smrg
67b8e80941Smrg   if (!c->key.nr_userclip) {
68b8e80941Smrg      brw_MOV(p, get_element_ud(c->reg.fixed_planes, 0), make_plane_ud( 0,    0, 0xff, 1));
69b8e80941Smrg      brw_MOV(p, get_element_ud(c->reg.fixed_planes, 1), make_plane_ud( 0,    0,    1, 1));
70b8e80941Smrg      brw_MOV(p, get_element_ud(c->reg.fixed_planes, 2), make_plane_ud( 0, 0xff,    0, 1));
71b8e80941Smrg      brw_MOV(p, get_element_ud(c->reg.fixed_planes, 3), make_plane_ud( 0,    1,    0, 1));
72b8e80941Smrg      brw_MOV(p, get_element_ud(c->reg.fixed_planes, 4), make_plane_ud(0xff,  0,    0, 1));
73b8e80941Smrg      brw_MOV(p, get_element_ud(c->reg.fixed_planes, 5), make_plane_ud( 1,    0,    0, 1));
74b8e80941Smrg   }
75b8e80941Smrg}
76b8e80941Smrg
77b8e80941Smrg
78b8e80941Smrg
79b8e80941Smrg#define W 3
80b8e80941Smrg
81b8e80941Smrg/* Project 'pos' to screen space (or back again), overwrite with results:
82b8e80941Smrg */
83b8e80941Smrgvoid brw_clip_project_position(struct brw_clip_compile *c, struct brw_reg pos )
84b8e80941Smrg{
85b8e80941Smrg   struct brw_codegen *p = &c->func;
86b8e80941Smrg
87b8e80941Smrg   /* calc rhw
88b8e80941Smrg    */
89b8e80941Smrg   brw_math_invert(p, get_element(pos, W), get_element(pos, W));
90b8e80941Smrg
91b8e80941Smrg   /* value.xyz *= value.rhw
92b8e80941Smrg    */
93b8e80941Smrg   brw_set_default_access_mode(p, BRW_ALIGN_16);
94b8e80941Smrg   brw_MUL(p, brw_writemask(pos, WRITEMASK_XYZ), pos,
95b8e80941Smrg           brw_swizzle(pos, BRW_SWIZZLE_WWWW));
96b8e80941Smrg   brw_set_default_access_mode(p, BRW_ALIGN_1);
97b8e80941Smrg}
98b8e80941Smrg
99b8e80941Smrg
100b8e80941Smrgstatic void brw_clip_project_vertex( struct brw_clip_compile *c,
101b8e80941Smrg				     struct brw_indirect vert_addr )
102b8e80941Smrg{
103b8e80941Smrg   struct brw_codegen *p = &c->func;
104b8e80941Smrg   struct brw_reg tmp = get_tmp(c);
105b8e80941Smrg   GLuint hpos_offset = brw_varying_to_offset(&c->vue_map, VARYING_SLOT_POS);
106b8e80941Smrg   GLuint ndc_offset = brw_varying_to_offset(&c->vue_map,
107b8e80941Smrg                                             BRW_VARYING_SLOT_NDC);
108b8e80941Smrg
109b8e80941Smrg   /* Fixup position.  Extract from the original vertex and re-project
110b8e80941Smrg    * to screen space:
111b8e80941Smrg    */
112b8e80941Smrg   brw_MOV(p, tmp, deref_4f(vert_addr, hpos_offset));
113b8e80941Smrg   brw_clip_project_position(c, tmp);
114b8e80941Smrg   brw_MOV(p, deref_4f(vert_addr, ndc_offset), tmp);
115b8e80941Smrg
116b8e80941Smrg   release_tmp(c, tmp);
117b8e80941Smrg}
118b8e80941Smrg
119b8e80941Smrg
120b8e80941Smrg
121b8e80941Smrg
122b8e80941Smrg/* Interpolate between two vertices and put the result into a0.0.
123b8e80941Smrg * Increment a0.0 accordingly.
124b8e80941Smrg *
125b8e80941Smrg * Beware that dest_ptr can be equal to v0_ptr!
126b8e80941Smrg */
127b8e80941Smrgvoid brw_clip_interp_vertex( struct brw_clip_compile *c,
128b8e80941Smrg			     struct brw_indirect dest_ptr,
129b8e80941Smrg			     struct brw_indirect v0_ptr, /* from */
130b8e80941Smrg			     struct brw_indirect v1_ptr, /* to */
131b8e80941Smrg			     struct brw_reg t0,
132b8e80941Smrg			     bool force_edgeflag)
133b8e80941Smrg{
134b8e80941Smrg   struct brw_codegen *p = &c->func;
135b8e80941Smrg   struct brw_reg t_nopersp, v0_ndc_copy;
136b8e80941Smrg   GLuint slot;
137b8e80941Smrg
138b8e80941Smrg   /* Just copy the vertex header:
139b8e80941Smrg    */
140b8e80941Smrg   /*
141b8e80941Smrg    * After CLIP stage, only first 256 bits of the VUE are read
142b8e80941Smrg    * back on Ironlake, so needn't change it
143b8e80941Smrg    */
144b8e80941Smrg   brw_copy_indirect_to_indirect(p, dest_ptr, v0_ptr, 1);
145b8e80941Smrg
146b8e80941Smrg
147b8e80941Smrg   /* First handle the 3D and NDC interpolation, in case we
148b8e80941Smrg    * need noperspective interpolation. Doing it early has no
149b8e80941Smrg    * performance impact in any case.
150b8e80941Smrg    */
151b8e80941Smrg
152b8e80941Smrg   /* Take a copy of the v0 NDC coordinates, in case dest == v0. */
153b8e80941Smrg   if (c->key.contains_noperspective_varying) {
154b8e80941Smrg      GLuint offset = brw_varying_to_offset(&c->vue_map,
155b8e80941Smrg                                                 BRW_VARYING_SLOT_NDC);
156b8e80941Smrg      v0_ndc_copy = get_tmp(c);
157b8e80941Smrg      brw_MOV(p, v0_ndc_copy, deref_4f(v0_ptr, offset));
158b8e80941Smrg   }
159b8e80941Smrg
160b8e80941Smrg   /* Compute the new 3D position
161b8e80941Smrg    *
162b8e80941Smrg    * dest_hpos = v0_hpos * (1 - t0) + v1_hpos * t0
163b8e80941Smrg    */
164b8e80941Smrg   {
165b8e80941Smrg      GLuint delta = brw_varying_to_offset(&c->vue_map, VARYING_SLOT_POS);
166b8e80941Smrg      struct brw_reg tmp = get_tmp(c);
167b8e80941Smrg      brw_MUL(p, vec4(brw_null_reg()), deref_4f(v1_ptr, delta), t0);
168b8e80941Smrg      brw_MAC(p, tmp, negate(deref_4f(v0_ptr, delta)), t0);
169b8e80941Smrg      brw_ADD(p, deref_4f(dest_ptr, delta), deref_4f(v0_ptr, delta), tmp);
170b8e80941Smrg      release_tmp(c, tmp);
171b8e80941Smrg   }
172b8e80941Smrg
173b8e80941Smrg   /* Recreate the projected (NDC) coordinate in the new vertex header */
174b8e80941Smrg   brw_clip_project_vertex(c, dest_ptr);
175b8e80941Smrg
176b8e80941Smrg   /* If we have noperspective attributes,
177b8e80941Smrg    * we need to compute the screen-space t
178b8e80941Smrg    */
179b8e80941Smrg   if (c->key.contains_noperspective_varying) {
180b8e80941Smrg      GLuint delta = brw_varying_to_offset(&c->vue_map,
181b8e80941Smrg                                                BRW_VARYING_SLOT_NDC);
182b8e80941Smrg      struct brw_reg tmp = get_tmp(c);
183b8e80941Smrg      t_nopersp = get_tmp(c);
184b8e80941Smrg
185b8e80941Smrg      /* t_nopersp = vec4(v1.xy, dest.xy) */
186b8e80941Smrg      brw_MOV(p, t_nopersp, deref_4f(v1_ptr, delta));
187b8e80941Smrg      brw_MOV(p, tmp, deref_4f(dest_ptr, delta));
188b8e80941Smrg      brw_set_default_access_mode(p, BRW_ALIGN_16);
189b8e80941Smrg      brw_MOV(p,
190b8e80941Smrg              brw_writemask(t_nopersp, WRITEMASK_ZW),
191b8e80941Smrg              brw_swizzle(tmp, BRW_SWIZZLE_XYXY));
192b8e80941Smrg
193b8e80941Smrg      /* t_nopersp = vec4(v1.xy, dest.xy) - v0.xyxy */
194b8e80941Smrg      brw_ADD(p, t_nopersp, t_nopersp,
195b8e80941Smrg              negate(brw_swizzle(v0_ndc_copy, BRW_SWIZZLE_XYXY)));
196b8e80941Smrg
197b8e80941Smrg      /* Add the absolute values of the X and Y deltas so that if
198b8e80941Smrg       * the points aren't in the same place on the screen we get
199b8e80941Smrg       * nonzero values to divide.
200b8e80941Smrg       *
201b8e80941Smrg       * After that, we have vert1 - vert0 in t_nopersp.x and
202b8e80941Smrg       * vertnew - vert0 in t_nopersp.y
203b8e80941Smrg       *
204b8e80941Smrg       * t_nopersp = vec2(|v1.x  -v0.x| + |v1.y  -v0.y|,
205b8e80941Smrg       *                  |dest.x-v0.x| + |dest.y-v0.y|)
206b8e80941Smrg       */
207b8e80941Smrg      brw_ADD(p,
208b8e80941Smrg              brw_writemask(t_nopersp, WRITEMASK_XY),
209b8e80941Smrg              brw_abs(brw_swizzle(t_nopersp, BRW_SWIZZLE_XZXZ)),
210b8e80941Smrg              brw_abs(brw_swizzle(t_nopersp, BRW_SWIZZLE_YWYW)));
211b8e80941Smrg      brw_set_default_access_mode(p, BRW_ALIGN_1);
212b8e80941Smrg
213b8e80941Smrg      /* If the points are in the same place, just substitute a
214b8e80941Smrg       * value to avoid divide-by-zero
215b8e80941Smrg       */
216b8e80941Smrg      brw_CMP(p, vec1(brw_null_reg()), BRW_CONDITIONAL_EQ,
217b8e80941Smrg              vec1(t_nopersp),
218b8e80941Smrg              brw_imm_f(0));
219b8e80941Smrg      brw_IF(p, BRW_EXECUTE_1);
220b8e80941Smrg      brw_MOV(p, t_nopersp, brw_imm_vf4(brw_float_to_vf(1.0),
221b8e80941Smrg                                        brw_float_to_vf(0.0),
222b8e80941Smrg                                        brw_float_to_vf(0.0),
223b8e80941Smrg                                        brw_float_to_vf(0.0)));
224b8e80941Smrg      brw_ENDIF(p);
225b8e80941Smrg
226b8e80941Smrg      /* Now compute t_nopersp = t_nopersp.y/t_nopersp.x and broadcast it. */
227b8e80941Smrg      brw_math_invert(p, get_element(t_nopersp, 0), get_element(t_nopersp, 0));
228b8e80941Smrg      brw_MUL(p, vec1(t_nopersp), vec1(t_nopersp),
229b8e80941Smrg            vec1(suboffset(t_nopersp, 1)));
230b8e80941Smrg      brw_set_default_access_mode(p, BRW_ALIGN_16);
231b8e80941Smrg      brw_MOV(p, t_nopersp, brw_swizzle(t_nopersp, BRW_SWIZZLE_XXXX));
232b8e80941Smrg      brw_set_default_access_mode(p, BRW_ALIGN_1);
233b8e80941Smrg
234b8e80941Smrg      release_tmp(c, tmp);
235b8e80941Smrg      release_tmp(c, v0_ndc_copy);
236b8e80941Smrg   }
237b8e80941Smrg
238b8e80941Smrg   /* Now we can iterate over each attribute
239b8e80941Smrg    * (could be done in pairs?)
240b8e80941Smrg    */
241b8e80941Smrg   for (slot = 0; slot < c->vue_map.num_slots; slot++) {
242b8e80941Smrg      int varying = c->vue_map.slot_to_varying[slot];
243b8e80941Smrg      GLuint delta = brw_vue_slot_to_offset(slot);
244b8e80941Smrg
245b8e80941Smrg      /* HPOS, NDC already handled above */
246b8e80941Smrg      if (varying == VARYING_SLOT_POS || varying == BRW_VARYING_SLOT_NDC)
247b8e80941Smrg         continue;
248b8e80941Smrg
249b8e80941Smrg
250b8e80941Smrg      if (varying == VARYING_SLOT_EDGE) {
251b8e80941Smrg	 if (force_edgeflag)
252b8e80941Smrg	    brw_MOV(p, deref_4f(dest_ptr, delta), brw_imm_f(1));
253b8e80941Smrg	 else
254b8e80941Smrg	    brw_MOV(p, deref_4f(dest_ptr, delta), deref_4f(v0_ptr, delta));
255b8e80941Smrg      } else if (varying == VARYING_SLOT_PSIZ) {
256b8e80941Smrg         /* PSIZ doesn't need interpolation because it isn't used by the
257b8e80941Smrg          * fragment shader.
258b8e80941Smrg          */
259b8e80941Smrg      } else if (varying < VARYING_SLOT_MAX) {
260b8e80941Smrg	 /* This is a true vertex result (and not a special value for the VUE
261b8e80941Smrg	  * header), so interpolate:
262b8e80941Smrg	  *
263b8e80941Smrg	  *        New = attr0 + t*attr1 - t*attr0
264b8e80941Smrg          *
265b8e80941Smrg          * Unless the attribute is flat shaded -- in which case just copy
266b8e80941Smrg          * from one of the sources (doesn't matter which; already copied from pv)
267b8e80941Smrg	  */
268b8e80941Smrg         GLuint interp = c->key.interp_mode[slot];
269b8e80941Smrg
270b8e80941Smrg         if (interp != INTERP_MODE_FLAT) {
271b8e80941Smrg            struct brw_reg tmp = get_tmp(c);
272b8e80941Smrg            struct brw_reg t =
273b8e80941Smrg               interp == INTERP_MODE_NOPERSPECTIVE ? t_nopersp : t0;
274b8e80941Smrg
275b8e80941Smrg            brw_MUL(p,
276b8e80941Smrg                  vec4(brw_null_reg()),
277b8e80941Smrg                  deref_4f(v1_ptr, delta),
278b8e80941Smrg                  t);
279b8e80941Smrg
280b8e80941Smrg            brw_MAC(p,
281b8e80941Smrg                  tmp,
282b8e80941Smrg                  negate(deref_4f(v0_ptr, delta)),
283b8e80941Smrg                  t);
284b8e80941Smrg
285b8e80941Smrg            brw_ADD(p,
286b8e80941Smrg                  deref_4f(dest_ptr, delta),
287b8e80941Smrg                  deref_4f(v0_ptr, delta),
288b8e80941Smrg                  tmp);
289b8e80941Smrg
290b8e80941Smrg            release_tmp(c, tmp);
291b8e80941Smrg         }
292b8e80941Smrg         else {
293b8e80941Smrg            brw_MOV(p,
294b8e80941Smrg                  deref_4f(dest_ptr, delta),
295b8e80941Smrg                  deref_4f(v0_ptr, delta));
296b8e80941Smrg         }
297b8e80941Smrg      }
298b8e80941Smrg   }
299b8e80941Smrg
300b8e80941Smrg   if (c->vue_map.num_slots % 2) {
301b8e80941Smrg      GLuint delta = brw_vue_slot_to_offset(c->vue_map.num_slots);
302b8e80941Smrg
303b8e80941Smrg      brw_MOV(p, deref_4f(dest_ptr, delta), brw_imm_f(0));
304b8e80941Smrg   }
305b8e80941Smrg
306b8e80941Smrg   if (c->key.contains_noperspective_varying)
307b8e80941Smrg      release_tmp(c, t_nopersp);
308b8e80941Smrg}
309b8e80941Smrg
310b8e80941Smrgvoid brw_clip_emit_vue(struct brw_clip_compile *c,
311b8e80941Smrg		       struct brw_indirect vert,
312b8e80941Smrg                       enum brw_urb_write_flags flags,
313b8e80941Smrg		       GLuint header)
314b8e80941Smrg{
315b8e80941Smrg   struct brw_codegen *p = &c->func;
316b8e80941Smrg   bool allocate = flags & BRW_URB_WRITE_ALLOCATE;
317b8e80941Smrg
318b8e80941Smrg   brw_clip_ff_sync(c);
319b8e80941Smrg
320b8e80941Smrg   /* Any URB entry that is allocated must subsequently be used or discarded,
321b8e80941Smrg    * so it doesn't make sense to mark EOT and ALLOCATE at the same time.
322b8e80941Smrg    */
323b8e80941Smrg   assert(!(allocate && (flags & BRW_URB_WRITE_EOT)));
324b8e80941Smrg
325b8e80941Smrg   /* Copy the vertex from vertn into m1..mN+1:
326b8e80941Smrg    */
327b8e80941Smrg   brw_copy_from_indirect(p, brw_message_reg(1), vert, c->nr_regs);
328b8e80941Smrg
329b8e80941Smrg   /* Overwrite PrimType and PrimStart in the message header, for
330b8e80941Smrg    * each vertex in turn:
331b8e80941Smrg    */
332b8e80941Smrg   brw_MOV(p, get_element_ud(c->reg.R0, 2), brw_imm_ud(header));
333b8e80941Smrg
334b8e80941Smrg
335b8e80941Smrg   /* Send each vertex as a separate write to the urb.  This
336b8e80941Smrg    * is different to the concept in brw_sf_emit.c, where
337b8e80941Smrg    * subsequent writes are used to build up a single urb
338b8e80941Smrg    * entry.  Each of these writes instantiates a separate
339b8e80941Smrg    * urb entry - (I think... what about 'allocate'?)
340b8e80941Smrg    */
341b8e80941Smrg   brw_urb_WRITE(p,
342b8e80941Smrg		 allocate ? c->reg.R0 : retype(brw_null_reg(), BRW_REGISTER_TYPE_UD),
343b8e80941Smrg		 0,
344b8e80941Smrg		 c->reg.R0,
345b8e80941Smrg                 flags,
346b8e80941Smrg		 c->nr_regs + 1, /* msg length */
347b8e80941Smrg		 allocate ? 1 : 0, /* response_length */
348b8e80941Smrg		 0,		/* urb offset */
349b8e80941Smrg		 BRW_URB_SWIZZLE_NONE);
350b8e80941Smrg}
351b8e80941Smrg
352b8e80941Smrg
353b8e80941Smrg
354b8e80941Smrgvoid brw_clip_kill_thread(struct brw_clip_compile *c)
355b8e80941Smrg{
356b8e80941Smrg   struct brw_codegen *p = &c->func;
357b8e80941Smrg
358b8e80941Smrg   brw_clip_ff_sync(c);
359b8e80941Smrg   /* Send an empty message to kill the thread and release any
360b8e80941Smrg    * allocated urb entry:
361b8e80941Smrg    */
362b8e80941Smrg   brw_urb_WRITE(p,
363b8e80941Smrg		 retype(brw_null_reg(), BRW_REGISTER_TYPE_UD),
364b8e80941Smrg		 0,
365b8e80941Smrg		 c->reg.R0,
366b8e80941Smrg                 BRW_URB_WRITE_UNUSED | BRW_URB_WRITE_EOT_COMPLETE,
367b8e80941Smrg		 1, 		/* msg len */
368b8e80941Smrg		 0, 		/* response len */
369b8e80941Smrg		 0,
370b8e80941Smrg		 BRW_URB_SWIZZLE_NONE);
371b8e80941Smrg}
372b8e80941Smrg
373b8e80941Smrg
374b8e80941Smrg
375b8e80941Smrg
376b8e80941Smrgstruct brw_reg brw_clip_plane0_address( struct brw_clip_compile *c )
377b8e80941Smrg{
378b8e80941Smrg   return brw_address(c->reg.fixed_planes);
379b8e80941Smrg}
380b8e80941Smrg
381b8e80941Smrg
382b8e80941Smrgstruct brw_reg brw_clip_plane_stride( struct brw_clip_compile *c )
383b8e80941Smrg{
384b8e80941Smrg   if (c->key.nr_userclip) {
385b8e80941Smrg      return brw_imm_uw(16);
386b8e80941Smrg   }
387b8e80941Smrg   else {
388b8e80941Smrg      return brw_imm_uw(4);
389b8e80941Smrg   }
390b8e80941Smrg}
391b8e80941Smrg
392b8e80941Smrg
393b8e80941Smrg/* Distribute flatshaded attributes from provoking vertex prior to
394b8e80941Smrg * clipping.
395b8e80941Smrg */
396b8e80941Smrgvoid brw_clip_copy_flatshaded_attributes( struct brw_clip_compile *c,
397b8e80941Smrg			   GLuint to, GLuint from )
398b8e80941Smrg{
399b8e80941Smrg   struct brw_codegen *p = &c->func;
400b8e80941Smrg
401b8e80941Smrg   for (int i = 0; i < c->vue_map.num_slots; i++) {
402b8e80941Smrg      if (c->key.interp_mode[i] == INTERP_MODE_FLAT) {
403b8e80941Smrg         brw_MOV(p,
404b8e80941Smrg                 byte_offset(c->reg.vertex[to], brw_vue_slot_to_offset(i)),
405b8e80941Smrg                 byte_offset(c->reg.vertex[from], brw_vue_slot_to_offset(i)));
406b8e80941Smrg      }
407b8e80941Smrg   }
408b8e80941Smrg}
409b8e80941Smrg
410b8e80941Smrg
411b8e80941Smrg
412b8e80941Smrgvoid brw_clip_init_clipmask( struct brw_clip_compile *c )
413b8e80941Smrg{
414b8e80941Smrg   struct brw_codegen *p = &c->func;
415b8e80941Smrg   struct brw_reg incoming = get_element_ud(c->reg.R0, 2);
416b8e80941Smrg
417b8e80941Smrg   /* Shift so that lowest outcode bit is rightmost:
418b8e80941Smrg    */
419b8e80941Smrg   brw_SHR(p, c->reg.planemask, incoming, brw_imm_ud(26));
420b8e80941Smrg
421b8e80941Smrg   if (c->key.nr_userclip) {
422b8e80941Smrg      struct brw_reg tmp = retype(vec1(get_tmp(c)), BRW_REGISTER_TYPE_UD);
423b8e80941Smrg
424b8e80941Smrg      /* Rearrange userclip outcodes so that they come directly after
425b8e80941Smrg       * the fixed plane bits.
426b8e80941Smrg       */
427b8e80941Smrg      if (p->devinfo->gen == 5 || p->devinfo->is_g4x)
428b8e80941Smrg         brw_AND(p, tmp, incoming, brw_imm_ud(0xff<<14));
429b8e80941Smrg      else
430b8e80941Smrg         brw_AND(p, tmp, incoming, brw_imm_ud(0x3f<<14));
431b8e80941Smrg
432b8e80941Smrg      brw_SHR(p, tmp, tmp, brw_imm_ud(8));
433b8e80941Smrg      brw_OR(p, c->reg.planemask, c->reg.planemask, tmp);
434b8e80941Smrg
435b8e80941Smrg      release_tmp(c, tmp);
436b8e80941Smrg   }
437b8e80941Smrg}
438b8e80941Smrg
439b8e80941Smrgvoid brw_clip_ff_sync(struct brw_clip_compile *c)
440b8e80941Smrg{
441b8e80941Smrg    struct brw_codegen *p = &c->func;
442b8e80941Smrg
443b8e80941Smrg    if (p->devinfo->gen == 5) {
444b8e80941Smrg        brw_AND(p, brw_null_reg(), c->reg.ff_sync, brw_imm_ud(0x1));
445b8e80941Smrg        brw_inst_set_cond_modifier(p->devinfo, brw_last_inst, BRW_CONDITIONAL_Z);
446b8e80941Smrg        brw_IF(p, BRW_EXECUTE_1);
447b8e80941Smrg        {
448b8e80941Smrg            brw_OR(p, c->reg.ff_sync, c->reg.ff_sync, brw_imm_ud(0x1));
449b8e80941Smrg            brw_ff_sync(p,
450b8e80941Smrg			c->reg.R0,
451b8e80941Smrg			0,
452b8e80941Smrg			c->reg.R0,
453b8e80941Smrg			1, /* allocate */
454b8e80941Smrg			1, /* response length */
455b8e80941Smrg			0 /* eot */);
456b8e80941Smrg        }
457b8e80941Smrg        brw_ENDIF(p);
458b8e80941Smrg        brw_set_default_predicate_control(p, BRW_PREDICATE_NONE);
459b8e80941Smrg    }
460b8e80941Smrg}
461b8e80941Smrg
462b8e80941Smrgvoid brw_clip_init_ff_sync(struct brw_clip_compile *c)
463b8e80941Smrg{
464b8e80941Smrg    struct brw_codegen *p = &c->func;
465b8e80941Smrg
466b8e80941Smrg    if (p->devinfo->gen == 5) {
467b8e80941Smrg        brw_MOV(p, c->reg.ff_sync, brw_imm_ud(0));
468b8e80941Smrg    }
469b8e80941Smrg}
470