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 gen_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->gen == 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