Merge branch 'master' into r500test
[mesa.git] / src / mesa / drivers / dri / i965 / brw_clip_unfilled.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 /* This is performed against the original triangles, so no indirection
48 * required:
49 BZZZT!
50 */
51 static void compute_tri_direction( struct brw_clip_compile *c )
52 {
53 struct brw_compile *p = &c->func;
54 struct brw_reg e = c->reg.tmp0;
55 struct brw_reg f = c->reg.tmp1;
56 struct brw_reg v0 = byte_offset(c->reg.vertex[0], c->offset[VERT_RESULT_HPOS]);
57 struct brw_reg v1 = byte_offset(c->reg.vertex[1], c->offset[VERT_RESULT_HPOS]);
58 struct brw_reg v2 = byte_offset(c->reg.vertex[2], c->offset[VERT_RESULT_HPOS]);
59
60
61 /* Calculate the vectors of two edges of the triangle:
62 */
63 brw_ADD(p, e, v0, negate(v2));
64 brw_ADD(p, f, v1, negate(v2));
65
66 /* Take their crossproduct:
67 */
68 brw_set_access_mode(p, BRW_ALIGN_16);
69 brw_MUL(p, vec4(brw_null_reg()), brw_swizzle(e, 1,2,0,3), brw_swizzle(f,2,0,1,3));
70 brw_MAC(p, vec4(e), negate(brw_swizzle(e, 2,0,1,3)), brw_swizzle(f,1,2,0,3));
71 brw_set_access_mode(p, BRW_ALIGN_1);
72
73 brw_MUL(p, c->reg.dir, c->reg.dir, vec4(e));
74 }
75
76
77 static void cull_direction( struct brw_clip_compile *c )
78 {
79 struct brw_compile *p = &c->func;
80 struct brw_instruction *ccw;
81 GLuint conditional;
82
83 assert (!(c->key.fill_ccw == CLIP_CULL &&
84 c->key.fill_cw == CLIP_CULL));
85
86 if (c->key.fill_ccw == CLIP_CULL)
87 conditional = BRW_CONDITIONAL_GE;
88 else
89 conditional = BRW_CONDITIONAL_L;
90
91 brw_CMP(p,
92 vec1(brw_null_reg()),
93 conditional,
94 get_element(c->reg.dir, 2),
95 brw_imm_f(0));
96
97 ccw = brw_IF(p, BRW_EXECUTE_1);
98 {
99 brw_clip_kill_thread(c);
100 }
101 brw_ENDIF(p, ccw);
102 }
103
104
105
106 static void copy_bfc( struct brw_clip_compile *c )
107 {
108 struct brw_compile *p = &c->func;
109 struct brw_instruction *ccw;
110 GLuint conditional;
111
112 /* Do we have any colors to copy?
113 */
114 if (!(c->offset[VERT_RESULT_COL0] && c->offset[VERT_RESULT_BFC0]) &&
115 !(c->offset[VERT_RESULT_COL1] && c->offset[VERT_RESULT_BFC1]))
116 return;
117
118 /* In some wierd degnerate cases we can end up testing the
119 * direction twice, once for culling and once for bfc copying. Oh
120 * well, that's what you get for setting wierd GL state.
121 */
122 if (c->key.copy_bfc_ccw)
123 conditional = BRW_CONDITIONAL_GE;
124 else
125 conditional = BRW_CONDITIONAL_L;
126
127 brw_CMP(p,
128 vec1(brw_null_reg()),
129 conditional,
130 get_element(c->reg.dir, 2),
131 brw_imm_f(0));
132
133 ccw = brw_IF(p, BRW_EXECUTE_1);
134 {
135 GLuint i;
136
137 for (i = 0; i < 3; i++) {
138 if (c->offset[VERT_RESULT_COL0] && c->offset[VERT_RESULT_BFC0])
139 brw_MOV(p,
140 byte_offset(c->reg.vertex[i], c->offset[VERT_RESULT_COL0]),
141 byte_offset(c->reg.vertex[i], c->offset[VERT_RESULT_BFC0]));
142
143 if (c->offset[VERT_RESULT_COL1] && c->offset[VERT_RESULT_BFC1])
144 brw_MOV(p,
145 byte_offset(c->reg.vertex[i], c->offset[VERT_RESULT_COL1]),
146 byte_offset(c->reg.vertex[i], c->offset[VERT_RESULT_BFC1]));
147 }
148 }
149 brw_ENDIF(p, ccw);
150 }
151
152
153
154
155 /*
156 GLfloat iz = 1.0 / dir.z;
157 GLfloat ac = dir.x * iz;
158 GLfloat bc = dir.y * iz;
159 offset = ctx->Polygon.OffsetUnits * DEPTH_SCALE;
160 offset += MAX2( abs(ac), abs(bc) ) * ctx->Polygon.OffsetFactor;
161 offset *= MRD;
162 */
163 static void compute_offset( struct brw_clip_compile *c )
164 {
165 struct brw_compile *p = &c->func;
166 struct brw_reg off = c->reg.offset;
167 struct brw_reg dir = c->reg.dir;
168
169 brw_math_invert(p, get_element(off, 2), get_element(dir, 2));
170 brw_MUL(p, vec2(off), dir, get_element(off, 2));
171
172 brw_CMP(p,
173 vec1(brw_null_reg()),
174 BRW_CONDITIONAL_GE,
175 brw_abs(get_element(off, 0)),
176 brw_abs(get_element(off, 1)));
177
178 brw_SEL(p, vec1(off), brw_abs(get_element(off, 0)), brw_abs(get_element(off, 1)));
179 brw_set_predicate_control(p, BRW_PREDICATE_NONE);
180
181 brw_MUL(p, vec1(off), off, brw_imm_f(c->key.offset_factor));
182 brw_ADD(p, vec1(off), off, brw_imm_f(c->key.offset_units));
183 }
184
185
186 static void merge_edgeflags( struct brw_clip_compile *c )
187 {
188 struct brw_compile *p = &c->func;
189 struct brw_instruction *is_poly;
190 struct brw_reg tmp0 = get_element_ud(c->reg.tmp0, 0);
191
192 brw_AND(p, tmp0, get_element_ud(c->reg.R0, 2), brw_imm_ud(PRIM_MASK));
193 brw_CMP(p,
194 vec1(brw_null_reg()),
195 BRW_CONDITIONAL_EQ,
196 tmp0,
197 brw_imm_ud(_3DPRIM_POLYGON));
198
199 /* Get away with using reg.vertex because we know that this is not
200 * a _3DPRIM_TRISTRIP_REVERSE:
201 */
202 is_poly = brw_IF(p, BRW_EXECUTE_1);
203 {
204 brw_set_conditionalmod(p, BRW_CONDITIONAL_EQ);
205 brw_AND(p, vec1(brw_null_reg()), get_element_ud(c->reg.R0, 2), brw_imm_ud(1<<8));
206 brw_MOV(p, byte_offset(c->reg.vertex[0], c->offset[VERT_RESULT_EDGE]), brw_imm_f(0));
207 brw_set_predicate_control(p, BRW_PREDICATE_NONE);
208
209 brw_set_conditionalmod(p, BRW_CONDITIONAL_EQ);
210 brw_AND(p, vec1(brw_null_reg()), get_element_ud(c->reg.R0, 2), brw_imm_ud(1<<9));
211 brw_MOV(p, byte_offset(c->reg.vertex[2], c->offset[VERT_RESULT_EDGE]), brw_imm_f(0));
212 brw_set_predicate_control(p, BRW_PREDICATE_NONE);
213 }
214 brw_ENDIF(p, is_poly);
215 }
216
217
218
219 static void apply_one_offset( struct brw_clip_compile *c,
220 struct brw_indirect vert )
221 {
222 struct brw_compile *p = &c->func;
223 struct brw_reg z = deref_1f(vert, c->header_position_offset +
224 2 * type_sz(BRW_REGISTER_TYPE_F));
225
226 brw_ADD(p, z, z, vec1(c->reg.offset));
227 }
228
229
230
231 /***********************************************************************
232 * Output clipped polygon as an unfilled primitive:
233 */
234 static void emit_lines(struct brw_clip_compile *c,
235 GLboolean do_offset)
236 {
237 struct brw_compile *p = &c->func;
238 struct brw_instruction *loop;
239 struct brw_instruction *draw_edge;
240 struct brw_indirect v0 = brw_indirect(0, 0);
241 struct brw_indirect v1 = brw_indirect(1, 0);
242 struct brw_indirect v0ptr = brw_indirect(2, 0);
243 struct brw_indirect v1ptr = brw_indirect(3, 0);
244
245 /* Need a seperate loop for offset:
246 */
247 if (do_offset) {
248 brw_MOV(p, c->reg.loopcount, c->reg.nr_verts);
249 brw_MOV(p, get_addr_reg(v0ptr), brw_address(c->reg.inlist));
250
251 loop = brw_DO(p, BRW_EXECUTE_1);
252 {
253 brw_MOV(p, get_addr_reg(v0), deref_1uw(v0ptr, 0));
254 brw_ADD(p, get_addr_reg(v0ptr), get_addr_reg(v0ptr), brw_imm_uw(2));
255
256 apply_one_offset(c, v0);
257
258 brw_set_conditionalmod(p, BRW_CONDITIONAL_G);
259 brw_ADD(p, c->reg.loopcount, c->reg.loopcount, brw_imm_d(-1));
260 }
261 brw_WHILE(p, loop);
262 }
263
264 /* v1ptr = &inlist[nr_verts]
265 * *v1ptr = v0
266 */
267 brw_MOV(p, c->reg.loopcount, c->reg.nr_verts);
268 brw_MOV(p, get_addr_reg(v0ptr), brw_address(c->reg.inlist));
269 brw_ADD(p, get_addr_reg(v1ptr), get_addr_reg(v0ptr), retype(c->reg.nr_verts, BRW_REGISTER_TYPE_UW));
270 brw_ADD(p, get_addr_reg(v1ptr), get_addr_reg(v1ptr), retype(c->reg.nr_verts, BRW_REGISTER_TYPE_UW));
271 brw_MOV(p, deref_1uw(v1ptr, 0), deref_1uw(v0ptr, 0));
272
273 loop = brw_DO(p, BRW_EXECUTE_1);
274 {
275 brw_MOV(p, get_addr_reg(v0), deref_1uw(v0ptr, 0));
276 brw_MOV(p, get_addr_reg(v1), deref_1uw(v0ptr, 2));
277 brw_ADD(p, get_addr_reg(v0ptr), get_addr_reg(v0ptr), brw_imm_uw(2));
278
279 /* draw edge if edgeflag != 0 */
280 brw_CMP(p,
281 vec1(brw_null_reg()), BRW_CONDITIONAL_NZ,
282 deref_1f(v0, c->offset[VERT_RESULT_EDGE]),
283 brw_imm_f(0));
284 draw_edge = brw_IF(p, BRW_EXECUTE_1);
285 {
286 brw_clip_emit_vue(c, v0, 1, 0, (_3DPRIM_LINESTRIP << 2) | R02_PRIM_START);
287 brw_clip_emit_vue(c, v1, 1, 0, (_3DPRIM_LINESTRIP << 2) | R02_PRIM_END);
288 }
289 brw_ENDIF(p, draw_edge);
290
291 brw_set_conditionalmod(p, BRW_CONDITIONAL_NZ);
292 brw_ADD(p, c->reg.loopcount, c->reg.loopcount, brw_imm_d(-1));
293 }
294 brw_WHILE(p, loop);
295 }
296
297
298
299 static void emit_points(struct brw_clip_compile *c,
300 GLboolean do_offset )
301 {
302 struct brw_compile *p = &c->func;
303 struct brw_instruction *loop;
304 struct brw_instruction *draw_point;
305
306 struct brw_indirect v0 = brw_indirect(0, 0);
307 struct brw_indirect v0ptr = brw_indirect(2, 0);
308
309 brw_MOV(p, c->reg.loopcount, c->reg.nr_verts);
310 brw_MOV(p, get_addr_reg(v0ptr), brw_address(c->reg.inlist));
311
312 loop = brw_DO(p, BRW_EXECUTE_1);
313 {
314 brw_MOV(p, get_addr_reg(v0), deref_1uw(v0ptr, 0));
315 brw_ADD(p, get_addr_reg(v0ptr), get_addr_reg(v0ptr), brw_imm_uw(2));
316
317 /* draw if edgeflag != 0
318 */
319 brw_CMP(p,
320 vec1(brw_null_reg()), BRW_CONDITIONAL_NZ,
321 deref_1f(v0, c->offset[VERT_RESULT_EDGE]),
322 brw_imm_f(0));
323 draw_point = brw_IF(p, BRW_EXECUTE_1);
324 {
325 if (do_offset)
326 apply_one_offset(c, v0);
327
328 brw_clip_emit_vue(c, v0, 1, 0, (_3DPRIM_POINTLIST << 2) | R02_PRIM_START | R02_PRIM_END);
329 }
330 brw_ENDIF(p, draw_point);
331
332 brw_set_conditionalmod(p, BRW_CONDITIONAL_NZ);
333 brw_ADD(p, c->reg.loopcount, c->reg.loopcount, brw_imm_d(-1));
334 }
335 brw_WHILE(p, loop);
336 }
337
338
339
340
341
342
343
344 static void emit_primitives( struct brw_clip_compile *c,
345 GLuint mode,
346 GLboolean do_offset )
347 {
348 switch (mode) {
349 case CLIP_FILL:
350 brw_clip_tri_emit_polygon(c);
351 break;
352
353 case CLIP_LINE:
354 emit_lines(c, do_offset);
355 break;
356
357 case CLIP_POINT:
358 emit_points(c, do_offset);
359 break;
360
361 case CLIP_CULL:
362 assert(0);
363 break;
364 }
365 }
366
367
368
369 static void emit_unfilled_primitives( struct brw_clip_compile *c )
370 {
371 struct brw_compile *p = &c->func;
372 struct brw_instruction *ccw;
373
374 /* Direction culling has already been done.
375 */
376 if (c->key.fill_ccw != c->key.fill_cw &&
377 c->key.fill_ccw != CLIP_CULL &&
378 c->key.fill_cw != CLIP_CULL)
379 {
380 brw_CMP(p,
381 vec1(brw_null_reg()),
382 BRW_CONDITIONAL_GE,
383 get_element(c->reg.dir, 2),
384 brw_imm_f(0));
385
386 ccw = brw_IF(p, BRW_EXECUTE_1);
387 {
388 emit_primitives(c, c->key.fill_ccw, c->key.offset_ccw);
389 }
390 ccw = brw_ELSE(p, ccw);
391 {
392 emit_primitives(c, c->key.fill_cw, c->key.offset_cw);
393 }
394 brw_ENDIF(p, ccw);
395 }
396 else if (c->key.fill_cw != CLIP_CULL) {
397 emit_primitives(c, c->key.fill_cw, c->key.offset_cw);
398 }
399 else if (c->key.fill_ccw != CLIP_CULL) {
400 emit_primitives(c, c->key.fill_ccw, c->key.offset_ccw);
401 }
402 }
403
404
405
406
407 static void check_nr_verts( struct brw_clip_compile *c )
408 {
409 struct brw_compile *p = &c->func;
410 struct brw_instruction *if_insn;
411
412 brw_CMP(p, vec1(brw_null_reg()), BRW_CONDITIONAL_L, c->reg.nr_verts, brw_imm_d(3));
413 if_insn = brw_IF(p, BRW_EXECUTE_1);
414 {
415 brw_clip_kill_thread(c);
416 }
417 brw_ENDIF(p, if_insn);
418 }
419
420
421 void brw_emit_unfilled_clip( struct brw_clip_compile *c )
422 {
423 struct brw_compile *p = &c->func;
424 struct brw_instruction *do_clip;
425
426
427 c->need_direction = ((c->key.offset_ccw || c->key.offset_cw) ||
428 (c->key.fill_ccw != c->key.fill_cw) ||
429 c->key.fill_ccw == CLIP_CULL ||
430 c->key.fill_cw == CLIP_CULL ||
431 c->key.copy_bfc_cw ||
432 c->key.copy_bfc_ccw);
433
434 brw_clip_tri_alloc_regs(c, 3 + c->key.nr_userclip + 6);
435 brw_clip_tri_init_vertices(c);
436
437 assert(c->offset[VERT_RESULT_EDGE]);
438
439 if (c->key.fill_ccw == CLIP_CULL &&
440 c->key.fill_cw == CLIP_CULL) {
441 brw_clip_kill_thread(c);
442 return;
443 }
444
445 merge_edgeflags(c);
446
447 /* Need to use the inlist indirection here:
448 */
449 if (c->need_direction)
450 compute_tri_direction(c);
451
452 if (c->key.fill_ccw == CLIP_CULL ||
453 c->key.fill_cw == CLIP_CULL)
454 cull_direction(c);
455
456 if (c->key.offset_ccw ||
457 c->key.offset_cw)
458 compute_offset(c);
459
460 if (c->key.copy_bfc_ccw ||
461 c->key.copy_bfc_cw)
462 copy_bfc(c);
463
464 /* Need to do this whether we clip or not:
465 */
466 if (c->key.do_flat_shading)
467 brw_clip_tri_flat_shade(c);
468
469 brw_clip_init_clipmask(c);
470 brw_CMP(p, vec1(brw_null_reg()), BRW_CONDITIONAL_NZ, c->reg.planemask, brw_imm_ud(0));
471 do_clip = brw_IF(p, BRW_EXECUTE_1);
472 {
473 brw_clip_init_planes(c);
474 brw_clip_tri(c);
475 check_nr_verts(c);
476 }
477 brw_ENDIF(p, do_clip);
478
479 emit_unfilled_primitives(c);
480 brw_clip_kill_thread(c);
481 }
482
483
484