2 Copyright (C) Intel Corp. 2006. All Rights Reserved.
3 Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to
4 develop this 3D driver.
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:
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.
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.
26 **********************************************************************/
29 * Keith Whitwell <keith@tungstengraphics.com>
32 #include "brw_defines.h"
33 #include "brw_context.h"
40 /* This is performed against the original triangles, so no indirection
44 static void compute_tri_direction( struct brw_clip_compile
*c
)
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
]);
54 /* Calculate the vectors of two edges of the triangle:
56 brw_ADD(p
, e
, v0
, negate(v2
));
57 brw_ADD(p
, f
, v1
, negate(v2
));
59 /* Take their crossproduct:
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
);
66 brw_MUL(p
, c
->reg
.dir
, c
->reg
.dir
, vec4(e
));
70 static void cull_direction( struct brw_clip_compile
*c
)
72 struct brw_compile
*p
= &c
->func
;
73 struct brw_instruction
*ccw
;
76 assert (!(c
->key
.fill_ccw
== CLIP_CULL
&&
77 c
->key
.fill_cw
== CLIP_CULL
));
79 if (c
->key
.fill_ccw
== CLIP_CULL
)
80 conditional
= BRW_CONDITIONAL_GE
;
82 conditional
= BRW_CONDITIONAL_L
;
87 get_element(c
->reg
.dir
, 2),
90 ccw
= brw_IF(p
, BRW_EXECUTE_1
);
92 brw_clip_kill_thread(c
);
99 static void copy_bfc( struct brw_clip_compile
*c
)
101 struct brw_compile
*p
= &c
->func
;
102 struct brw_instruction
*ccw
;
103 unsigned conditional
;
105 /* Do we have any colors to copy?
107 if (!(c
->offset
[VERT_RESULT_COL0
] && c
->offset
[VERT_RESULT_BFC0
]) &&
108 !(c
->offset
[VERT_RESULT_COL1
] && c
->offset
[VERT_RESULT_BFC1
]))
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.
115 if (c
->key
.copy_bfc_ccw
)
116 conditional
= BRW_CONDITIONAL_GE
;
118 conditional
= BRW_CONDITIONAL_L
;
121 vec1(brw_null_reg()),
123 get_element(c
->reg
.dir
, 2),
126 ccw
= brw_IF(p
, BRW_EXECUTE_1
);
130 for (i
= 0; i
< 3; i
++) {
131 if (c
->offset
[VERT_RESULT_COL0
] && c
->offset
[VERT_RESULT_BFC0
])
133 byte_offset(c
->reg
.vertex
[i
], c
->offset
[VERT_RESULT_COL0
]),
134 byte_offset(c
->reg
.vertex
[i
], c
->offset
[VERT_RESULT_BFC0
]));
136 if (c
->offset
[VERT_RESULT_COL1
] && c
->offset
[VERT_RESULT_BFC1
])
138 byte_offset(c
->reg
.vertex
[i
], c
->offset
[VERT_RESULT_COL1
]),
139 byte_offset(c
->reg
.vertex
[i
], c
->offset
[VERT_RESULT_BFC1
]));
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;
156 static void compute_offset( struct brw_clip_compile
*c
)
158 struct brw_compile
*p
= &c
->func
;
159 struct brw_reg off
= c
->reg
.offset
;
160 struct brw_reg dir
= c
->reg
.dir
;
162 brw_math_invert(p
, get_element(off
, 2), get_element(dir
, 2));
163 brw_MUL(p
, vec2(off
), dir
, get_element(off
, 2));
166 vec1(brw_null_reg()),
168 brw_abs(get_element(off
, 0)),
169 brw_abs(get_element(off
, 1)));
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
);
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
));
179 static void merge_edgeflags( struct brw_clip_compile
*c
)
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);
185 brw_AND(p
, tmp0
, get_element_ud(c
->reg
.R0
, 2), brw_imm_ud(PRIM_MASK
));
187 vec1(brw_null_reg()),
190 brw_imm_ud(_3DPRIM_POLYGON
));
192 /* Get away with using reg.vertex because we know that this is not
193 * a _3DPRIM_TRISTRIP_REVERSE:
195 is_poly
= brw_IF(p
, BRW_EXECUTE_1
);
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
);
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
);
207 brw_ENDIF(p
, is_poly
);
212 static void apply_one_offset( struct brw_clip_compile
*c
,
213 struct brw_indirect vert
)
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);
219 brw_ADD(p
, z
, z
, vec1(c
->reg
.offset
));
224 /***********************************************************************
225 * Output clipped polygon as an unfilled primitive:
227 static void emit_lines(struct brw_clip_compile
*c
,
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);
238 /* Need a seperate loop for 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
));
244 loop
= brw_DO(p
, BRW_EXECUTE_1
);
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));
249 apply_one_offset(c
, v0
);
251 brw_set_conditionalmod(p
, BRW_CONDITIONAL_G
);
252 brw_ADD(p
, c
->reg
.loopcount
, c
->reg
.loopcount
, brw_imm_d(-1));
257 /* v1ptr = &inlist[nr_verts]
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));
266 loop
= brw_DO(p
, BRW_EXECUTE_1
);
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));
272 /* draw edge if edgeflag != 0 */
274 vec1(brw_null_reg()), BRW_CONDITIONAL_NZ
,
275 deref_1f(v0
, c
->offset
[VERT_RESULT_EDGE
]),
277 draw_edge
= brw_IF(p
, BRW_EXECUTE_1
);
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
);
282 brw_ENDIF(p
, draw_edge
);
284 brw_set_conditionalmod(p
, BRW_CONDITIONAL_NZ
);
285 brw_ADD(p
, c
->reg
.loopcount
, c
->reg
.loopcount
, brw_imm_d(-1));
292 static void emit_points(struct brw_clip_compile
*c
,
295 struct brw_compile
*p
= &c
->func
;
296 struct brw_instruction
*loop
;
297 struct brw_instruction
*draw_point
;
299 struct brw_indirect v0
= brw_indirect(0, 0);
300 struct brw_indirect v0ptr
= brw_indirect(2, 0);
302 brw_MOV(p
, c
->reg
.loopcount
, c
->reg
.nr_verts
);
303 brw_MOV(p
, get_addr_reg(v0ptr
), brw_address(c
->reg
.inlist
));
305 loop
= brw_DO(p
, BRW_EXECUTE_1
);
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));
310 /* draw if edgeflag != 0
313 vec1(brw_null_reg()), BRW_CONDITIONAL_NZ
,
314 deref_1f(v0
, c
->offset
[VERT_RESULT_EDGE
]),
316 draw_point
= brw_IF(p
, BRW_EXECUTE_1
);
319 apply_one_offset(c
, v0
);
321 brw_clip_emit_vue(c
, v0
, 1, 0, (_3DPRIM_POINTLIST
<< 2) | R02_PRIM_START
| R02_PRIM_END
);
323 brw_ENDIF(p
, draw_point
);
325 brw_set_conditionalmod(p
, BRW_CONDITIONAL_NZ
);
326 brw_ADD(p
, c
->reg
.loopcount
, c
->reg
.loopcount
, brw_imm_d(-1));
337 static void emit_primitives( struct brw_clip_compile
*c
,
343 brw_clip_tri_emit_polygon(c
);
347 emit_lines(c
, do_offset
);
351 emit_points(c
, do_offset
);
362 static void emit_unfilled_primitives( struct brw_clip_compile
*c
)
364 struct brw_compile
*p
= &c
->func
;
365 struct brw_instruction
*ccw
;
367 /* Direction culling has already been done.
369 if (c
->key
.fill_ccw
!= c
->key
.fill_cw
&&
370 c
->key
.fill_ccw
!= CLIP_CULL
&&
371 c
->key
.fill_cw
!= CLIP_CULL
)
374 vec1(brw_null_reg()),
376 get_element(c
->reg
.dir
, 2),
379 ccw
= brw_IF(p
, BRW_EXECUTE_1
);
381 emit_primitives(c
, c
->key
.fill_ccw
, c
->key
.offset_ccw
);
383 ccw
= brw_ELSE(p
, ccw
);
385 emit_primitives(c
, c
->key
.fill_cw
, c
->key
.offset_cw
);
389 else if (c
->key
.fill_cw
!= CLIP_CULL
) {
390 emit_primitives(c
, c
->key
.fill_cw
, c
->key
.offset_cw
);
392 else if (c
->key
.fill_ccw
!= CLIP_CULL
) {
393 emit_primitives(c
, c
->key
.fill_ccw
, c
->key
.offset_ccw
);
400 static void check_nr_verts( struct brw_clip_compile
*c
)
402 struct brw_compile
*p
= &c
->func
;
403 struct brw_instruction
*if_insn
;
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
);
408 brw_clip_kill_thread(c
);
410 brw_ENDIF(p
, if_insn
);
414 void brw_emit_unfilled_clip( struct brw_clip_compile
*c
)
416 struct brw_compile
*p
= &c
->func
;
417 struct brw_instruction
*do_clip
;
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
);
427 brw_clip_tri_alloc_regs(c
, 3 + c
->key
.nr_userclip
+ 6);
428 brw_clip_tri_init_vertices(c
);
430 assert(c
->offset
[VERT_RESULT_EDGE
]);
432 if (c
->key
.fill_ccw
== CLIP_CULL
&&
433 c
->key
.fill_cw
== CLIP_CULL
) {
434 brw_clip_kill_thread(c
);
440 /* Need to use the inlist indirection here:
442 if (c
->need_direction
)
443 compute_tri_direction(c
);
445 if (c
->key
.fill_ccw
== CLIP_CULL
||
446 c
->key
.fill_cw
== CLIP_CULL
)
449 if (c
->key
.offset_ccw
||
453 if (c
->key
.copy_bfc_ccw
||
457 /* Need to do this whether we clip or not:
459 if (c
->key
.do_flat_shading
)
460 brw_clip_tri_flat_shade(c
);
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
);
466 brw_clip_init_planes(c
);
470 brw_ENDIF(p
, do_clip
);
472 emit_unfilled_primitives(c
);
473 brw_clip_kill_thread(c
);