Add Intel i965G/Q DRI driver.
[mesa.git] / src / mesa / drivers / dri / i965 / brw_clip_tri.c
1 /*
2 Copyright (C) Intel Corp. 2006. All Rights Reserved.
3 Intel funded Tungsten Graphics (http://www.tungstengraphics.com) 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 <keith@tungstengraphics.com>
30 */
31
32 #include "glheader.h"
33 #include "macros.h"
34 #include "enums.h"
35
36 #include "shader/program.h"
37 #include "intel_batchbuffer.h"
38
39 #include "brw_defines.h"
40 #include "brw_context.h"
41 #include "brw_eu.h"
42 #include "brw_util.h"
43 #include "brw_clip.h"
44
45
46
47 void brw_clip_tri_alloc_regs( struct brw_clip_compile *c,
48 GLuint nr_verts )
49 {
50 GLuint i = 0,j;
51
52 /* Register usage is static, precompute here:
53 */
54 c->reg.R0 = retype(brw_vec8_grf(i, 0), BRW_REGISTER_TYPE_UD); i++;
55
56 if (c->key.nr_userclip) {
57 c->reg.fixed_planes = brw_vec4_grf(i, 0);
58 i += (6 + c->key.nr_userclip + 1) / 2;
59
60 c->prog_data.curb_read_length = (6 + c->key.nr_userclip + 1) / 2;
61 }
62 else
63 c->prog_data.curb_read_length = 0;
64
65
66 /* Payload vertices plus space for more generated vertices:
67 */
68 for (j = 0; j < nr_verts; j++) {
69 c->reg.vertex[j] = brw_vec4_grf(i, 0);
70 i += c->nr_regs;
71 }
72
73 if (c->nr_attrs & 1) {
74 for (j = 0; j < 3; j++) {
75 GLuint delta = c->nr_attrs*16 + 32;
76 brw_MOV(&c->func, byte_offset(c->reg.vertex[j], delta), brw_imm_f(0));
77 }
78 }
79
80 c->reg.t = brw_vec1_grf(i, 0);
81 c->reg.loopcount = retype(brw_vec1_grf(i, 1), BRW_REGISTER_TYPE_UD);
82 c->reg.nr_verts = retype(brw_vec1_grf(i, 2), BRW_REGISTER_TYPE_UD);
83 c->reg.planemask = retype(brw_vec1_grf(i, 3), BRW_REGISTER_TYPE_UD);
84 c->reg.plane_equation = brw_vec4_grf(i, 4);
85 i++;
86
87 c->reg.dpPrev = brw_vec1_grf(i, 0); /* fixme - dp4 will clobber r.1,2,3 */
88 c->reg.dp = brw_vec1_grf(i, 4);
89 i++;
90
91 c->reg.inlist = brw_uw16_reg(BRW_GENERAL_REGISTER_FILE, i, 0);
92 i++;
93
94 c->reg.outlist = brw_uw16_reg(BRW_GENERAL_REGISTER_FILE, i, 0);
95 i++;
96
97 c->reg.freelist = brw_uw16_reg(BRW_GENERAL_REGISTER_FILE, i, 0);
98 i++;
99
100 if (!c->key.nr_userclip) {
101 c->reg.fixed_planes = brw_vec8_grf(i, 0);
102 i++;
103 }
104
105 if (c->key.do_unfilled) {
106 c->reg.dir = brw_vec4_grf(i, 0);
107 c->reg.offset = brw_vec4_grf(i, 4);
108 i++;
109 c->reg.tmp0 = brw_vec4_grf(i, 0);
110 c->reg.tmp1 = brw_vec4_grf(i, 4);
111 i++;
112 }
113
114 c->first_tmp = i;
115 c->last_tmp = i;
116
117 c->prog_data.urb_read_length = c->nr_regs; /* ? */
118 c->prog_data.total_grf = i;
119 }
120
121
122
123 void brw_clip_tri_init_vertices( struct brw_clip_compile *c )
124 {
125 struct brw_compile *p = &c->func;
126 struct brw_reg tmp0 = c->reg.loopcount; /* handy temporary */
127 struct brw_instruction *is_rev;
128
129 /* Initial list of indices for incoming vertexes:
130 */
131 brw_AND(p, tmp0, get_element_ud(c->reg.R0, 2), brw_imm_ud(PRIM_MASK));
132 brw_CMP(p,
133 vec1(brw_null_reg()),
134 BRW_CONDITIONAL_EQ,
135 tmp0,
136 brw_imm_ud(_3DPRIM_TRISTRIP_REVERSE));
137
138 /* XXX: Is there an easier way to do this? Need to reverse every
139 * second tristrip element: Can ignore sometimes?
140 */
141 is_rev = brw_IF(p, BRW_EXECUTE_1);
142 {
143 brw_MOV(p, get_element(c->reg.inlist, 0), brw_address(c->reg.vertex[1]) );
144 brw_MOV(p, get_element(c->reg.inlist, 1), brw_address(c->reg.vertex[0]) );
145 if (c->need_direction)
146 brw_MOV(p, c->reg.dir, brw_imm_f(-1));
147 }
148 is_rev = brw_ELSE(p, is_rev);
149 {
150 brw_MOV(p, get_element(c->reg.inlist, 0), brw_address(c->reg.vertex[0]) );
151 brw_MOV(p, get_element(c->reg.inlist, 1), brw_address(c->reg.vertex[1]) );
152 if (c->need_direction)
153 brw_MOV(p, c->reg.dir, brw_imm_f(1));
154 }
155 brw_ENDIF(p, is_rev);
156
157 brw_MOV(p, get_element(c->reg.inlist, 2), brw_address(c->reg.vertex[2]) );
158 brw_MOV(p, brw_vec8_grf(c->reg.outlist.nr, 0), brw_imm_f(0));
159 brw_MOV(p, c->reg.nr_verts, brw_imm_ud(3));
160 }
161
162
163
164 void brw_clip_tri_flat_shade( struct brw_clip_compile *c )
165 {
166 struct brw_compile *p = &c->func;
167 struct brw_instruction *is_poly;
168 struct brw_reg tmp0 = c->reg.loopcount; /* handy temporary */
169
170 brw_AND(p, tmp0, get_element_ud(c->reg.R0, 2), brw_imm_ud(PRIM_MASK));
171 brw_CMP(p,
172 vec1(brw_null_reg()),
173 BRW_CONDITIONAL_EQ,
174 tmp0,
175 brw_imm_ud(_3DPRIM_POLYGON));
176
177 is_poly = brw_IF(p, BRW_EXECUTE_1);
178 {
179 brw_clip_copy_colors(c, 1, 0);
180 brw_clip_copy_colors(c, 2, 0);
181 }
182 is_poly = brw_ELSE(p, is_poly);
183 {
184 brw_clip_copy_colors(c, 0, 2);
185 brw_clip_copy_colors(c, 1, 2);
186 }
187 brw_ENDIF(p, is_poly);
188 }
189
190
191
192 /* Use mesa's clipping algorithms, translated to GEN4 assembly.
193 */
194 void brw_clip_tri( struct brw_clip_compile *c )
195 {
196 struct brw_compile *p = &c->func;
197 struct brw_indirect vtx = brw_indirect(0, 0);
198 struct brw_indirect vtxPrev = brw_indirect(1, 0);
199 struct brw_indirect vtxOut = brw_indirect(2, 0);
200 struct brw_indirect plane_ptr = brw_indirect(3, 0);
201 struct brw_indirect inlist_ptr = brw_indirect(4, 0);
202 struct brw_indirect outlist_ptr = brw_indirect(5, 0);
203 struct brw_indirect freelist_ptr = brw_indirect(6, 0);
204 struct brw_instruction *plane_loop;
205 struct brw_instruction *plane_active;
206 struct brw_instruction *vertex_loop;
207 struct brw_instruction *next_test;
208 struct brw_instruction *prev_test;
209
210 brw_MOV(p, get_addr_reg(vtxPrev), brw_address(c->reg.vertex[2]) );
211 brw_MOV(p, get_addr_reg(plane_ptr), brw_clip_plane0_address(c));
212 brw_MOV(p, get_addr_reg(inlist_ptr), brw_address(c->reg.inlist));
213 brw_MOV(p, get_addr_reg(outlist_ptr), brw_address(c->reg.outlist));
214
215 brw_MOV(p, get_addr_reg(freelist_ptr), brw_address(c->reg.vertex[3]) );
216
217 plane_loop = brw_DO(p, BRW_EXECUTE_1);
218 {
219 /* if (planemask & 1)
220 */
221 brw_set_conditionalmod(p, BRW_CONDITIONAL_NZ);
222 brw_AND(p, vec1(brw_null_reg()), c->reg.planemask, brw_imm_ud(1));
223
224 plane_active = brw_IF(p, BRW_EXECUTE_1);
225 {
226 /* vtxOut = freelist_ptr++
227 */
228 brw_MOV(p, get_addr_reg(vtxOut), get_addr_reg(freelist_ptr) );
229 brw_ADD(p, get_addr_reg(freelist_ptr), get_addr_reg(freelist_ptr), brw_imm_uw(c->nr_regs * REG_SIZE));
230
231 if (c->key.nr_userclip)
232 brw_MOV(p, c->reg.plane_equation, deref_4f(plane_ptr, 0));
233 else
234 brw_MOV(p, c->reg.plane_equation, deref_4b(plane_ptr, 0));
235
236 brw_MOV(p, c->reg.loopcount, c->reg.nr_verts);
237 brw_MOV(p, c->reg.nr_verts, brw_imm_ud(0));
238
239 vertex_loop = brw_DO(p, BRW_EXECUTE_1);
240 {
241 /* vtx = *input_ptr;
242 */
243 brw_MOV(p, get_addr_reg(vtx), deref_1uw(inlist_ptr, 0));
244
245 /* IS_NEGATIVE(prev) */
246 brw_set_conditionalmod(p, BRW_CONDITIONAL_L);
247 brw_DP4(p, vec4(c->reg.dpPrev), deref_4f(vtxPrev, c->offset[VERT_RESULT_HPOS]), c->reg.plane_equation);
248 prev_test = brw_IF(p, BRW_EXECUTE_1);
249 {
250 /* IS_POSITIVE(next)
251 */
252 brw_set_conditionalmod(p, BRW_CONDITIONAL_GE);
253 brw_DP4(p, vec4(c->reg.dp), deref_4f(vtx, c->offset[VERT_RESULT_HPOS]), c->reg.plane_equation);
254 next_test = brw_IF(p, BRW_EXECUTE_1);
255 {
256
257 /* Coming back in.
258 */
259 brw_ADD(p, c->reg.t, c->reg.dpPrev, negate(c->reg.dp));
260 brw_math_invert(p, c->reg.t, c->reg.t);
261 brw_MUL(p, c->reg.t, c->reg.t, c->reg.dpPrev);
262
263 /* If (vtxOut == 0) vtxOut = vtxPrev
264 */
265 brw_CMP(p, vec1(brw_null_reg()), BRW_CONDITIONAL_EQ, get_addr_reg(vtxOut), brw_imm_uw(0) );
266 brw_MOV(p, get_addr_reg(vtxOut), get_addr_reg(vtxPrev) );
267 brw_set_predicate_control(p, BRW_PREDICATE_NONE);
268
269 brw_clip_interp_vertex(c, vtxOut, vtxPrev, vtx, c->reg.t, GL_FALSE);
270
271 /* *outlist_ptr++ = vtxOut;
272 * nr_verts++;
273 * vtxOut = 0;
274 */
275 brw_MOV(p, deref_1uw(outlist_ptr, 0), get_addr_reg(vtxOut));
276 brw_ADD(p, get_addr_reg(outlist_ptr), get_addr_reg(outlist_ptr), brw_imm_uw(sizeof(short)));
277 brw_ADD(p, c->reg.nr_verts, c->reg.nr_verts, brw_imm_ud(1));
278 brw_MOV(p, get_addr_reg(vtxOut), brw_imm_uw(0) );
279 }
280 brw_ENDIF(p, next_test);
281
282 }
283 prev_test = brw_ELSE(p, prev_test);
284 {
285 /* *outlist_ptr++ = vtxPrev;
286 * nr_verts++;
287 */
288 brw_MOV(p, deref_1uw(outlist_ptr, 0), get_addr_reg(vtxPrev));
289 brw_ADD(p, get_addr_reg(outlist_ptr), get_addr_reg(outlist_ptr), brw_imm_uw(sizeof(short)));
290 brw_ADD(p, c->reg.nr_verts, c->reg.nr_verts, brw_imm_ud(1));
291
292 /* IS_NEGATIVE(next)
293 */
294 brw_set_conditionalmod(p, BRW_CONDITIONAL_L);
295 brw_DP4(p, vec4(c->reg.dp), deref_4f(vtx, c->offset[VERT_RESULT_HPOS]), c->reg.plane_equation);
296 next_test = brw_IF(p, BRW_EXECUTE_1);
297 {
298 /* Going out of bounds. Avoid division by zero as we
299 * know dp != dpPrev from DIFFERENT_SIGNS, above.
300 */
301 brw_ADD(p, c->reg.t, c->reg.dp, negate(c->reg.dpPrev));
302 brw_math_invert(p, c->reg.t, c->reg.t);
303 brw_MUL(p, c->reg.t, c->reg.t, c->reg.dp);
304
305 /* If (vtxOut == 0) vtxOut = vtx
306 */
307 brw_CMP(p, vec1(brw_null_reg()), BRW_CONDITIONAL_EQ, get_addr_reg(vtxOut), brw_imm_uw(0) );
308 brw_MOV(p, get_addr_reg(vtxOut), get_addr_reg(vtx) );
309 brw_set_predicate_control(p, BRW_PREDICATE_NONE);
310
311 brw_clip_interp_vertex(c, vtxOut, vtx, vtxPrev, c->reg.t, GL_TRUE);
312
313 /* *outlist_ptr++ = vtxOut;
314 * nr_verts++;
315 * vtxOut = 0;
316 */
317 brw_MOV(p, deref_1uw(outlist_ptr, 0), get_addr_reg(vtxOut));
318 brw_ADD(p, get_addr_reg(outlist_ptr), get_addr_reg(outlist_ptr), brw_imm_uw(sizeof(short)));
319 brw_ADD(p, c->reg.nr_verts, c->reg.nr_verts, brw_imm_ud(1));
320 brw_MOV(p, get_addr_reg(vtxOut), brw_imm_uw(0) );
321 }
322 brw_ENDIF(p, next_test);
323 }
324 brw_ENDIF(p, prev_test);
325
326 /* vtxPrev = vtx;
327 * inlist_ptr++;
328 */
329 brw_MOV(p, get_addr_reg(vtxPrev), get_addr_reg(vtx));
330 brw_ADD(p, get_addr_reg(inlist_ptr), get_addr_reg(inlist_ptr), brw_imm_uw(sizeof(short)));
331
332 /* while (--loopcount != 0)
333 */
334 brw_set_conditionalmod(p, BRW_CONDITIONAL_NZ);
335 brw_ADD(p, c->reg.loopcount, c->reg.loopcount, brw_imm_d(-1));
336 }
337 brw_WHILE(p, vertex_loop);
338
339 /* vtxPrev = *(outlist_ptr-1) OR: outlist[nr_verts-1]
340 * inlist = outlist
341 * inlist_ptr = &inlist[0]
342 * outlist_ptr = &outlist[0]
343 */
344 brw_ADD(p, get_addr_reg(outlist_ptr), get_addr_reg(outlist_ptr), brw_imm_w(-2));
345 brw_MOV(p, get_addr_reg(vtxPrev), deref_1uw(outlist_ptr, 0));
346 brw_MOV(p, brw_vec8_grf(c->reg.inlist.nr, 0), brw_vec8_grf(c->reg.outlist.nr, 0));
347 brw_MOV(p, get_addr_reg(inlist_ptr), brw_address(c->reg.inlist));
348 brw_MOV(p, get_addr_reg(outlist_ptr), brw_address(c->reg.outlist));
349 }
350 brw_ENDIF(p, plane_active);
351
352 /* plane_ptr++;
353 */
354 brw_ADD(p, get_addr_reg(plane_ptr), get_addr_reg(plane_ptr), brw_clip_plane_stride(c));
355
356 /* nr_verts >= 3
357 */
358 brw_CMP(p,
359 vec1(brw_null_reg()),
360 BRW_CONDITIONAL_GE,
361 c->reg.nr_verts,
362 brw_imm_ud(3));
363
364 /* && (planemask>>=1) != 0
365 */
366 brw_set_conditionalmod(p, BRW_CONDITIONAL_NZ);
367 brw_SHR(p, c->reg.planemask, c->reg.planemask, brw_imm_ud(1));
368 }
369 brw_WHILE(p, plane_loop);
370 }
371
372
373
374 void brw_clip_tri_emit_polygon(struct brw_clip_compile *c)
375 {
376 struct brw_compile *p = &c->func;
377 struct brw_instruction *loop, *if_insn;
378
379 /* for (loopcount = nr_verts-2; loopcount > 0; loopcount--)
380 */
381 brw_set_conditionalmod(p, BRW_CONDITIONAL_G);
382 brw_ADD(p,
383 c->reg.loopcount,
384 c->reg.nr_verts,
385 brw_imm_d(-2));
386
387 if_insn = brw_IF(p, BRW_EXECUTE_1);
388 {
389 struct brw_indirect v0 = brw_indirect(0, 0);
390 struct brw_indirect vptr = brw_indirect(1, 0);
391
392 brw_MOV(p, get_addr_reg(vptr), brw_address(c->reg.inlist));
393 brw_MOV(p, get_addr_reg(v0), deref_1uw(vptr, 0));
394
395 brw_clip_emit_vue(c, v0, 1, 0, ((_3DPRIM_TRIFAN << 2) | R02_PRIM_START));
396
397 brw_ADD(p, get_addr_reg(vptr), get_addr_reg(vptr), brw_imm_uw(2));
398 brw_MOV(p, get_addr_reg(v0), deref_1uw(vptr, 0));
399
400 loop = brw_DO(p, BRW_EXECUTE_1);
401 {
402 brw_clip_emit_vue(c, v0, 1, 0, (_3DPRIM_TRIFAN << 2));
403
404 brw_ADD(p, get_addr_reg(vptr), get_addr_reg(vptr), brw_imm_uw(2));
405 brw_MOV(p, get_addr_reg(v0), deref_1uw(vptr, 0));
406
407 brw_set_conditionalmod(p, BRW_CONDITIONAL_NZ);
408 brw_ADD(p, c->reg.loopcount, c->reg.loopcount, brw_imm_d(-1));
409 }
410 brw_WHILE(p, loop);
411
412 brw_clip_emit_vue(c, v0, 0, 1, ((_3DPRIM_TRIFAN << 2) | R02_PRIM_END));
413 }
414 brw_ENDIF(p, if_insn);
415 }
416
417 static void do_clip_tri( struct brw_clip_compile *c )
418 {
419 brw_clip_init_planes(c);
420
421 brw_clip_tri(c);
422 }
423
424
425 static void maybe_do_clip_tri( struct brw_clip_compile *c )
426 {
427 struct brw_compile *p = &c->func;
428 struct brw_instruction *do_clip;
429
430 brw_CMP(p, vec1(brw_null_reg()), BRW_CONDITIONAL_NZ, c->reg.planemask, brw_imm_ud(0));
431 do_clip = brw_IF(p, BRW_EXECUTE_1);
432 {
433 do_clip_tri(c);
434 }
435 brw_ENDIF(p, do_clip);
436 }
437
438
439
440
441 void brw_emit_tri_clip( struct brw_clip_compile *c )
442 {
443 brw_clip_tri_alloc_regs(c, 3 + c->key.nr_userclip + 6);
444 brw_clip_tri_init_vertices(c);
445 brw_clip_init_clipmask(c);
446
447 /* Can't push into do_clip_tri because with polygon (or quad)
448 * flatshading, need to apply the flatshade here because we don't
449 * respect the PV when converting to trifan for emit:
450 */
451 if (c->key.do_flat_shading)
452 brw_clip_tri_flat_shade(c);
453
454 if (c->key.clip_mode == BRW_CLIPMODE_NORMAL)
455 do_clip_tri(c);
456 else
457 maybe_do_clip_tri(c);
458
459 brw_clip_tri_emit_polygon(c);
460
461 /* Send an empty message to kill the thread:
462 */
463 brw_clip_kill_thread(c);
464 }
465
466
467