1 /*
2  Copyright (C) Intel Corp.  2006.  All Rights Reserved.
3  Intel funded Tungsten Graphics to
4  develop this 3D driver.
5 
6  Permission is hereby granted, free of charge, to any person obtaining
7  a copy of this software and associated documentation files (the
8  "Software"), to deal in the Software without restriction, including
9  without limitation the rights to use, copy, modify, merge, publish,
10  distribute, sublicense, and/or sell copies of the Software, and to
11  permit persons to whom the Software is furnished to do so, subject to
12  the following conditions:
13 
14  The above copyright notice and this permission notice (including the
15  next paragraph) shall be included in all copies or substantial
16  portions of the Software.
17 
18  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21  IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
22  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 
26  **********************************************************************/
27  /*
28   * Authors:
29   *   Keith Whitwell <keithw@vmware.com>
30   */
31 
32 #include "main/macros.h"
33 #include "main/enums.h"
34 #include "program/program.h"
35 
36 #include "brw_clip.h"
37 
brw_clip_line_alloc_regs(struct brw_clip_compile * c)38 static void brw_clip_line_alloc_regs( struct brw_clip_compile *c )
39 {
40    const struct intel_device_info *devinfo = c->func.devinfo;
41    GLuint i = 0,j;
42 
43    /* Register usage is static, precompute here:
44     */
45    c->reg.R0 = retype(brw_vec8_grf(i, 0), BRW_REGISTER_TYPE_UD); i++;
46 
47    if (c->key.nr_userclip) {
48       c->reg.fixed_planes = brw_vec4_grf(i, 0);
49       i += (6 + c->key.nr_userclip + 1) / 2;
50 
51       c->prog_data.curb_read_length = (6 + c->key.nr_userclip + 1) / 2;
52    }
53    else
54       c->prog_data.curb_read_length = 0;
55 
56 
57    /* Payload vertices plus space for more generated vertices:
58     */
59    for (j = 0; j < 4; j++) {
60       c->reg.vertex[j] = brw_vec4_grf(i, 0);
61       i += c->nr_regs;
62    }
63 
64    c->reg.t           = brw_vec1_grf(i, 0);
65    c->reg.t0          = brw_vec1_grf(i, 1);
66    c->reg.t1          = brw_vec1_grf(i, 2);
67    c->reg.planemask   = retype(brw_vec1_grf(i, 3), BRW_REGISTER_TYPE_UD);
68    c->reg.plane_equation = brw_vec4_grf(i, 4);
69    i++;
70 
71    c->reg.dp0         = brw_vec1_grf(i, 0); /* fixme - dp4 will clobber r.1,2,3 */
72    c->reg.dp1         = brw_vec1_grf(i, 4);
73    i++;
74 
75    if (!c->key.nr_userclip) {
76       c->reg.fixed_planes = brw_vec8_grf(i, 0);
77       i++;
78    }
79 
80    c->reg.vertex_src_mask = retype(brw_vec1_grf(i, 0), BRW_REGISTER_TYPE_UD);
81    c->reg.clipdistance_offset = retype(brw_vec1_grf(i, 1), BRW_REGISTER_TYPE_W);
82    i++;
83 
84    if (devinfo->ver == 5) {
85       c->reg.ff_sync = retype(brw_vec1_grf(i, 0), BRW_REGISTER_TYPE_UD);
86       i++;
87    }
88 
89    c->first_tmp = i;
90    c->last_tmp = i;
91 
92    c->prog_data.urb_read_length = c->nr_regs; /* ? */
93    c->prog_data.total_grf = i;
94 }
95 
96 
97 /* Line clipping, more or less following the following algorithm:
98  *
99  *  for (p=0;p<MAX_PLANES;p++) {
100  *     if (clipmask & (1 << p)) {
101  *        GLfloat dp0 = DOTPROD( vtx0, plane[p] );
102  *        GLfloat dp1 = DOTPROD( vtx1, plane[p] );
103  *
104  *        if (dp1 < 0.0f) {
105  *           GLfloat t = dp1 / (dp1 - dp0);
106  *           if (t > t1) t1 = t;
107  *        } else {
108  *           GLfloat t = dp0 / (dp0 - dp1);
109  *           if (t > t0) t0 = t;
110  *        }
111  *
112  *        if (t0 + t1 >= 1.0)
113  *           return;
114  *     }
115  *  }
116  *
117  *  interp( ctx, newvtx0, vtx0, vtx1, t0 );
118  *  interp( ctx, newvtx1, vtx1, vtx0, t1 );
119  *
120  */
clip_and_emit_line(struct brw_clip_compile * c)121 static void clip_and_emit_line( struct brw_clip_compile *c )
122 {
123    struct brw_codegen *p = &c->func;
124    struct brw_indirect vtx0     = brw_indirect(0, 0);
125    struct brw_indirect vtx1      = brw_indirect(1, 0);
126    struct brw_indirect newvtx0   = brw_indirect(2, 0);
127    struct brw_indirect newvtx1   = brw_indirect(3, 0);
128    struct brw_indirect plane_ptr = brw_indirect(4, 0);
129    struct brw_reg v1_null_ud = retype(vec1(brw_null_reg()), BRW_REGISTER_TYPE_UD);
130    GLuint hpos_offset = brw_varying_to_offset(&c->vue_map, VARYING_SLOT_POS);
131    GLint clipdist0_offset = c->key.nr_userclip
132       ? brw_varying_to_offset(&c->vue_map, VARYING_SLOT_CLIP_DIST0)
133       : 0;
134 
135    brw_MOV(p, get_addr_reg(vtx0),      brw_address(c->reg.vertex[0]));
136    brw_MOV(p, get_addr_reg(vtx1),      brw_address(c->reg.vertex[1]));
137    brw_MOV(p, get_addr_reg(newvtx0),   brw_address(c->reg.vertex[2]));
138    brw_MOV(p, get_addr_reg(newvtx1),   brw_address(c->reg.vertex[3]));
139    brw_MOV(p, get_addr_reg(plane_ptr), brw_clip_plane0_address(c));
140 
141    /* Note: init t0, t1 together:
142     */
143    brw_MOV(p, vec2(c->reg.t0), brw_imm_f(0));
144 
145    brw_clip_init_planes(c);
146    brw_clip_init_clipmask(c);
147 
148    /* -ve rhw workaround */
149    if (p->devinfo->has_negative_rhw_bug) {
150       brw_AND(p, brw_null_reg(), get_element_ud(c->reg.R0, 2),
151               brw_imm_ud(1<<20));
152       brw_inst_set_cond_modifier(p->devinfo, brw_last_inst, BRW_CONDITIONAL_NZ);
153       brw_OR(p, c->reg.planemask, c->reg.planemask, brw_imm_ud(0x3f));
154       brw_inst_set_pred_control(p->devinfo, brw_last_inst, BRW_PREDICATE_NORMAL);
155    }
156 
157    /* Set the initial vertex source mask: The first 6 planes are the bounds
158     * of the view volume; the next 8 planes are the user clipping planes.
159     */
160    brw_MOV(p, c->reg.vertex_src_mask, brw_imm_ud(0x3fc0));
161 
162    /* Set the initial clipdistance offset to be 6 floats before gl_ClipDistance[0].
163     * We'll increment 6 times before we start hitting actual user clipping. */
164    brw_MOV(p, c->reg.clipdistance_offset, brw_imm_d(clipdist0_offset - 6*sizeof(float)));
165 
166    brw_DO(p, BRW_EXECUTE_1);
167    {
168       /* if (planemask & 1)
169        */
170       brw_AND(p, v1_null_ud, c->reg.planemask, brw_imm_ud(1));
171       brw_inst_set_cond_modifier(p->devinfo, brw_last_inst, BRW_CONDITIONAL_NZ);
172 
173       brw_IF(p, BRW_EXECUTE_1);
174       {
175          brw_AND(p, v1_null_ud, c->reg.vertex_src_mask, brw_imm_ud(1));
176          brw_inst_set_cond_modifier(p->devinfo, brw_last_inst, BRW_CONDITIONAL_NZ);
177          brw_IF(p, BRW_EXECUTE_1);
178          {
179             /* user clip distance: just fetch the correct float from each vertex */
180             struct brw_indirect temp_ptr = brw_indirect(7, 0);
181             brw_ADD(p, get_addr_reg(temp_ptr), get_addr_reg(vtx0), c->reg.clipdistance_offset);
182             brw_MOV(p, c->reg.dp0, deref_1f(temp_ptr, 0));
183             brw_ADD(p, get_addr_reg(temp_ptr), get_addr_reg(vtx1), c->reg.clipdistance_offset);
184             brw_MOV(p, c->reg.dp1, deref_1f(temp_ptr, 0));
185          }
186          brw_ELSE(p);
187          {
188             /* fixed plane: fetch the hpos, dp4 against the plane. */
189             if (c->key.nr_userclip)
190                brw_MOV(p, c->reg.plane_equation, deref_4f(plane_ptr, 0));
191             else
192                brw_MOV(p, c->reg.plane_equation, deref_4b(plane_ptr, 0));
193 
194             brw_DP4(p, vec4(c->reg.dp0), deref_4f(vtx0, hpos_offset), c->reg.plane_equation);
195             brw_DP4(p, vec4(c->reg.dp1), deref_4f(vtx1, hpos_offset), c->reg.plane_equation);
196          }
197          brw_ENDIF(p);
198 
199          brw_CMP(p, brw_null_reg(), BRW_CONDITIONAL_L, vec1(c->reg.dp1), brw_imm_f(0.0f));
200 
201          brw_IF(p, BRW_EXECUTE_1);
202          {
203              /*
204               * Both can be negative on GM965/G965 due to RHW workaround
205               * if so, this object should be rejected.
206               */
207              if (p->devinfo->has_negative_rhw_bug) {
208                  brw_CMP(p, vec1(brw_null_reg()), BRW_CONDITIONAL_LE, c->reg.dp0, brw_imm_f(0.0));
209                  brw_IF(p, BRW_EXECUTE_1);
210                  {
211                      brw_clip_kill_thread(c);
212                  }
213                  brw_ENDIF(p);
214              }
215 
216              brw_ADD(p, c->reg.t, c->reg.dp1, negate(c->reg.dp0));
217              brw_math_invert(p, c->reg.t, c->reg.t);
218              brw_MUL(p, c->reg.t, c->reg.t, c->reg.dp1);
219 
220              brw_CMP(p, vec1(brw_null_reg()), BRW_CONDITIONAL_G, c->reg.t, c->reg.t1 );
221              brw_MOV(p, c->reg.t1, c->reg.t);
222              brw_inst_set_pred_control(p->devinfo, brw_last_inst,
223                                        BRW_PREDICATE_NORMAL);
224 	 }
225 	 brw_ELSE(p);
226 	 {
227              /* Coming back in.  We know that both cannot be negative
228               * because the line would have been culled in that case.
229               */
230 
231              /* If both are positive, do nothing */
232              /* Only on GM965/G965 */
233              if (p->devinfo->has_negative_rhw_bug) {
234                  brw_CMP(p, vec1(brw_null_reg()), BRW_CONDITIONAL_L, c->reg.dp0, brw_imm_f(0.0));
235                  brw_IF(p, BRW_EXECUTE_1);
236              }
237 
238              {
239                  brw_ADD(p, c->reg.t, c->reg.dp0, negate(c->reg.dp1));
240                  brw_math_invert(p, c->reg.t, c->reg.t);
241                  brw_MUL(p, c->reg.t, c->reg.t, c->reg.dp0);
242 
243                  brw_CMP(p, vec1(brw_null_reg()), BRW_CONDITIONAL_G, c->reg.t, c->reg.t0 );
244                  brw_MOV(p, c->reg.t0, c->reg.t);
245                  brw_inst_set_pred_control(p->devinfo, brw_last_inst,
246                                            BRW_PREDICATE_NORMAL);
247              }
248 
249              if (p->devinfo->has_negative_rhw_bug) {
250                  brw_ENDIF(p);
251              }
252          }
253 	 brw_ENDIF(p);
254       }
255       brw_ENDIF(p);
256 
257       /* plane_ptr++;
258        */
259       brw_ADD(p, get_addr_reg(plane_ptr), get_addr_reg(plane_ptr), brw_clip_plane_stride(c));
260 
261       /* while (planemask>>=1) != 0
262        */
263       brw_SHR(p, c->reg.planemask, c->reg.planemask, brw_imm_ud(1));
264       brw_inst_set_cond_modifier(p->devinfo, brw_last_inst, BRW_CONDITIONAL_NZ);
265       brw_SHR(p, c->reg.vertex_src_mask, c->reg.vertex_src_mask, brw_imm_ud(1));
266       brw_inst_set_pred_control(p->devinfo, brw_last_inst, BRW_PREDICATE_NORMAL);
267       brw_ADD(p, c->reg.clipdistance_offset, c->reg.clipdistance_offset, brw_imm_w(sizeof(float)));
268       brw_inst_set_pred_control(p->devinfo, brw_last_inst, BRW_PREDICATE_NORMAL);
269    }
270    brw_WHILE(p);
271    brw_inst_set_pred_control(p->devinfo, brw_last_inst, BRW_PREDICATE_NORMAL);
272 
273    brw_ADD(p, c->reg.t, c->reg.t0, c->reg.t1);
274    brw_CMP(p, vec1(brw_null_reg()), BRW_CONDITIONAL_L, c->reg.t, brw_imm_f(1.0));
275    brw_IF(p, BRW_EXECUTE_1);
276    {
277       brw_clip_interp_vertex(c, newvtx0, vtx0, vtx1, c->reg.t0, false);
278       brw_clip_interp_vertex(c, newvtx1, vtx1, vtx0, c->reg.t1, false);
279 
280       brw_clip_emit_vue(c, newvtx0, BRW_URB_WRITE_ALLOCATE_COMPLETE,
281                         (_3DPRIM_LINESTRIP << URB_WRITE_PRIM_TYPE_SHIFT)
282                         | URB_WRITE_PRIM_START);
283       brw_clip_emit_vue(c, newvtx1, BRW_URB_WRITE_EOT_COMPLETE,
284                         (_3DPRIM_LINESTRIP << URB_WRITE_PRIM_TYPE_SHIFT)
285                         | URB_WRITE_PRIM_END);
286    }
287    brw_ENDIF(p);
288    brw_clip_kill_thread(c);
289 }
290 
291 
292 
brw_emit_line_clip(struct brw_clip_compile * c)293 void brw_emit_line_clip( struct brw_clip_compile *c )
294 {
295    brw_clip_line_alloc_regs(c);
296    brw_clip_init_ff_sync(c);
297 
298    if (c->key.contains_flat_varying) {
299       if (c->key.pv_first)
300          brw_clip_copy_flatshaded_attributes(c, 1, 0);
301       else
302          brw_clip_copy_flatshaded_attributes(c, 0, 1);
303    }
304 
305    clip_and_emit_line(c);
306 }
307