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 <[email protected]>
30 */
31
32 #include "elk_clip.h"
33 #include "elk_prim.h"
34
elk_clip_line_alloc_regs(struct elk_clip_compile * c)35 static void elk_clip_line_alloc_regs( struct elk_clip_compile *c )
36 {
37 const struct intel_device_info *devinfo = c->func.devinfo;
38 GLuint i = 0,j;
39
40 /* Register usage is static, precompute here:
41 */
42 c->reg.R0 = retype(elk_vec8_grf(i, 0), ELK_REGISTER_TYPE_UD); i++;
43
44 if (c->key.nr_userclip) {
45 c->reg.fixed_planes = elk_vec4_grf(i, 0);
46 i += (6 + c->key.nr_userclip + 1) / 2;
47
48 c->prog_data.curb_read_length = (6 + c->key.nr_userclip + 1) / 2;
49 }
50 else
51 c->prog_data.curb_read_length = 0;
52
53
54 /* Payload vertices plus space for more generated vertices:
55 */
56 for (j = 0; j < 4; j++) {
57 c->reg.vertex[j] = elk_vec4_grf(i, 0);
58 i += c->nr_regs;
59 }
60
61 c->reg.t = elk_vec1_grf(i, 0);
62 c->reg.t0 = elk_vec1_grf(i, 1);
63 c->reg.t1 = elk_vec1_grf(i, 2);
64 c->reg.planemask = retype(elk_vec1_grf(i, 3), ELK_REGISTER_TYPE_UD);
65 c->reg.plane_equation = elk_vec4_grf(i, 4);
66 i++;
67
68 c->reg.dp0 = elk_vec1_grf(i, 0); /* fixme - dp4 will clobber r.1,2,3 */
69 c->reg.dp1 = elk_vec1_grf(i, 4);
70 i++;
71
72 if (!c->key.nr_userclip) {
73 c->reg.fixed_planes = elk_vec8_grf(i, 0);
74 i++;
75 }
76
77 c->reg.vertex_src_mask = retype(elk_vec1_grf(i, 0), ELK_REGISTER_TYPE_UD);
78 c->reg.clipdistance_offset = retype(elk_vec1_grf(i, 1), ELK_REGISTER_TYPE_W);
79 i++;
80
81 if (devinfo->ver == 5) {
82 c->reg.ff_sync = retype(elk_vec1_grf(i, 0), ELK_REGISTER_TYPE_UD);
83 i++;
84 }
85
86 c->first_tmp = i;
87 c->last_tmp = i;
88
89 c->prog_data.urb_read_length = c->nr_regs; /* ? */
90 c->prog_data.total_grf = i;
91 }
92
93
94 /* Line clipping, more or less following the following algorithm:
95 *
96 * for (p=0;p<MAX_PLANES;p++) {
97 * if (clipmask & (1 << p)) {
98 * GLfloat dp0 = DOTPROD( vtx0, plane[p] );
99 * GLfloat dp1 = DOTPROD( vtx1, plane[p] );
100 *
101 * if (dp1 < 0.0f) {
102 * GLfloat t = dp1 / (dp1 - dp0);
103 * if (t > t1) t1 = t;
104 * } else {
105 * GLfloat t = dp0 / (dp0 - dp1);
106 * if (t > t0) t0 = t;
107 * }
108 *
109 * if (t0 + t1 >= 1.0)
110 * return;
111 * }
112 * }
113 *
114 * interp( ctx, newvtx0, vtx0, vtx1, t0 );
115 * interp( ctx, newvtx1, vtx1, vtx0, t1 );
116 *
117 */
clip_and_emit_line(struct elk_clip_compile * c)118 static void clip_and_emit_line( struct elk_clip_compile *c )
119 {
120 struct elk_codegen *p = &c->func;
121 struct elk_indirect vtx0 = elk_indirect(0, 0);
122 struct elk_indirect vtx1 = elk_indirect(1, 0);
123 struct elk_indirect newvtx0 = elk_indirect(2, 0);
124 struct elk_indirect newvtx1 = elk_indirect(3, 0);
125 struct elk_indirect plane_ptr = elk_indirect(4, 0);
126 struct elk_reg v1_null_ud = retype(vec1(elk_null_reg()), ELK_REGISTER_TYPE_UD);
127 GLuint hpos_offset = elk_varying_to_offset(&c->vue_map, VARYING_SLOT_POS);
128 GLint clipdist0_offset = c->key.nr_userclip
129 ? elk_varying_to_offset(&c->vue_map, VARYING_SLOT_CLIP_DIST0)
130 : 0;
131
132 elk_MOV(p, get_addr_reg(vtx0), elk_address(c->reg.vertex[0]));
133 elk_MOV(p, get_addr_reg(vtx1), elk_address(c->reg.vertex[1]));
134 elk_MOV(p, get_addr_reg(newvtx0), elk_address(c->reg.vertex[2]));
135 elk_MOV(p, get_addr_reg(newvtx1), elk_address(c->reg.vertex[3]));
136 elk_MOV(p, get_addr_reg(plane_ptr), elk_clip_plane0_address(c));
137
138 /* Note: init t0, t1 together:
139 */
140 elk_MOV(p, vec2(c->reg.t0), elk_imm_f(0));
141
142 elk_clip_init_planes(c);
143 elk_clip_init_clipmask(c);
144
145 /* -ve rhw workaround */
146 if (p->devinfo->has_negative_rhw_bug) {
147 elk_AND(p, elk_null_reg(), get_element_ud(c->reg.R0, 2),
148 elk_imm_ud(1<<20));
149 elk_inst_set_cond_modifier(p->devinfo, elk_last_inst, ELK_CONDITIONAL_NZ);
150 elk_OR(p, c->reg.planemask, c->reg.planemask, elk_imm_ud(0x3f));
151 elk_inst_set_pred_control(p->devinfo, elk_last_inst, ELK_PREDICATE_NORMAL);
152 }
153
154 /* Set the initial vertex source mask: The first 6 planes are the bounds
155 * of the view volume; the next 8 planes are the user clipping planes.
156 */
157 elk_MOV(p, c->reg.vertex_src_mask, elk_imm_ud(0x3fc0));
158
159 /* Set the initial clipdistance offset to be 6 floats before gl_ClipDistance[0].
160 * We'll increment 6 times before we start hitting actual user clipping. */
161 elk_MOV(p, c->reg.clipdistance_offset, elk_imm_d(clipdist0_offset - 6*sizeof(float)));
162
163 elk_DO(p, ELK_EXECUTE_1);
164 {
165 /* if (planemask & 1)
166 */
167 elk_AND(p, v1_null_ud, c->reg.planemask, elk_imm_ud(1));
168 elk_inst_set_cond_modifier(p->devinfo, elk_last_inst, ELK_CONDITIONAL_NZ);
169
170 elk_IF(p, ELK_EXECUTE_1);
171 {
172 elk_AND(p, v1_null_ud, c->reg.vertex_src_mask, elk_imm_ud(1));
173 elk_inst_set_cond_modifier(p->devinfo, elk_last_inst, ELK_CONDITIONAL_NZ);
174 elk_IF(p, ELK_EXECUTE_1);
175 {
176 /* user clip distance: just fetch the correct float from each vertex */
177 struct elk_indirect temp_ptr = elk_indirect(7, 0);
178 elk_ADD(p, get_addr_reg(temp_ptr), get_addr_reg(vtx0), c->reg.clipdistance_offset);
179 elk_MOV(p, c->reg.dp0, deref_1f(temp_ptr, 0));
180 elk_ADD(p, get_addr_reg(temp_ptr), get_addr_reg(vtx1), c->reg.clipdistance_offset);
181 elk_MOV(p, c->reg.dp1, deref_1f(temp_ptr, 0));
182 }
183 elk_ELSE(p);
184 {
185 /* fixed plane: fetch the hpos, dp4 against the plane. */
186 if (c->key.nr_userclip)
187 elk_MOV(p, c->reg.plane_equation, deref_4f(plane_ptr, 0));
188 else
189 elk_MOV(p, c->reg.plane_equation, deref_4b(plane_ptr, 0));
190
191 elk_DP4(p, vec4(c->reg.dp0), deref_4f(vtx0, hpos_offset), c->reg.plane_equation);
192 elk_DP4(p, vec4(c->reg.dp1), deref_4f(vtx1, hpos_offset), c->reg.plane_equation);
193 }
194 elk_ENDIF(p);
195
196 elk_CMP(p, elk_null_reg(), ELK_CONDITIONAL_L, vec1(c->reg.dp1), elk_imm_f(0.0f));
197
198 elk_IF(p, ELK_EXECUTE_1);
199 {
200 /*
201 * Both can be negative on GM965/G965 due to RHW workaround
202 * if so, this object should be rejected.
203 */
204 if (p->devinfo->has_negative_rhw_bug) {
205 elk_CMP(p, vec1(elk_null_reg()), ELK_CONDITIONAL_LE, c->reg.dp0, elk_imm_f(0.0));
206 elk_IF(p, ELK_EXECUTE_1);
207 {
208 elk_clip_kill_thread(c);
209 }
210 elk_ENDIF(p);
211 }
212
213 elk_ADD(p, c->reg.t, c->reg.dp1, negate(c->reg.dp0));
214 elk_math_invert(p, c->reg.t, c->reg.t);
215 elk_MUL(p, c->reg.t, c->reg.t, c->reg.dp1);
216
217 elk_CMP(p, vec1(elk_null_reg()), ELK_CONDITIONAL_G, c->reg.t, c->reg.t1 );
218 elk_MOV(p, c->reg.t1, c->reg.t);
219 elk_inst_set_pred_control(p->devinfo, elk_last_inst,
220 ELK_PREDICATE_NORMAL);
221 }
222 elk_ELSE(p);
223 {
224 /* Coming back in. We know that both cannot be negative
225 * because the line would have been culled in that case.
226 */
227
228 /* If both are positive, do nothing */
229 /* Only on GM965/G965 */
230 if (p->devinfo->has_negative_rhw_bug) {
231 elk_CMP(p, vec1(elk_null_reg()), ELK_CONDITIONAL_L, c->reg.dp0, elk_imm_f(0.0));
232 elk_IF(p, ELK_EXECUTE_1);
233 }
234
235 {
236 elk_ADD(p, c->reg.t, c->reg.dp0, negate(c->reg.dp1));
237 elk_math_invert(p, c->reg.t, c->reg.t);
238 elk_MUL(p, c->reg.t, c->reg.t, c->reg.dp0);
239
240 elk_CMP(p, vec1(elk_null_reg()), ELK_CONDITIONAL_G, c->reg.t, c->reg.t0 );
241 elk_MOV(p, c->reg.t0, c->reg.t);
242 elk_inst_set_pred_control(p->devinfo, elk_last_inst,
243 ELK_PREDICATE_NORMAL);
244 }
245
246 if (p->devinfo->has_negative_rhw_bug) {
247 elk_ENDIF(p);
248 }
249 }
250 elk_ENDIF(p);
251 }
252 elk_ENDIF(p);
253
254 /* plane_ptr++;
255 */
256 elk_ADD(p, get_addr_reg(plane_ptr), get_addr_reg(plane_ptr), elk_clip_plane_stride(c));
257
258 /* while (planemask>>=1) != 0
259 */
260 elk_SHR(p, c->reg.planemask, c->reg.planemask, elk_imm_ud(1));
261 elk_inst_set_cond_modifier(p->devinfo, elk_last_inst, ELK_CONDITIONAL_NZ);
262 elk_SHR(p, c->reg.vertex_src_mask, c->reg.vertex_src_mask, elk_imm_ud(1));
263 elk_inst_set_pred_control(p->devinfo, elk_last_inst, ELK_PREDICATE_NORMAL);
264 elk_ADD(p, c->reg.clipdistance_offset, c->reg.clipdistance_offset, elk_imm_w(sizeof(float)));
265 elk_inst_set_pred_control(p->devinfo, elk_last_inst, ELK_PREDICATE_NORMAL);
266 }
267 elk_WHILE(p);
268 elk_inst_set_pred_control(p->devinfo, elk_last_inst, ELK_PREDICATE_NORMAL);
269
270 elk_ADD(p, c->reg.t, c->reg.t0, c->reg.t1);
271 elk_CMP(p, vec1(elk_null_reg()), ELK_CONDITIONAL_L, c->reg.t, elk_imm_f(1.0));
272 elk_IF(p, ELK_EXECUTE_1);
273 {
274 elk_clip_interp_vertex(c, newvtx0, vtx0, vtx1, c->reg.t0, false);
275 elk_clip_interp_vertex(c, newvtx1, vtx1, vtx0, c->reg.t1, false);
276
277 elk_clip_emit_vue(c, newvtx0, ELK_URB_WRITE_ALLOCATE_COMPLETE,
278 (_3DPRIM_LINESTRIP << URB_WRITE_PRIM_TYPE_SHIFT)
279 | URB_WRITE_PRIM_START);
280 elk_clip_emit_vue(c, newvtx1, ELK_URB_WRITE_EOT_COMPLETE,
281 (_3DPRIM_LINESTRIP << URB_WRITE_PRIM_TYPE_SHIFT)
282 | URB_WRITE_PRIM_END);
283 }
284 elk_ENDIF(p);
285 elk_clip_kill_thread(c);
286 }
287
288
289
elk_emit_line_clip(struct elk_clip_compile * c)290 void elk_emit_line_clip( struct elk_clip_compile *c )
291 {
292 elk_clip_line_alloc_regs(c);
293 elk_clip_init_ff_sync(c);
294
295 if (c->key.contains_flat_varying) {
296 if (c->key.pv_first)
297 elk_clip_copy_flatshaded_attributes(c, 1, 0);
298 else
299 elk_clip_copy_flatshaded_attributes(c, 0, 1);
300 }
301
302 clip_and_emit_line(c);
303 }
304