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