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>
36 #include "shader/program.h"
37 #include "intel_batchbuffer.h"
39 #include "brw_defines.h"
40 #include "brw_context.h"
47 /* This is performed against the original triangles, so no indirection
51 static void compute_tri_direction( struct brw_clip_compile
*c
)
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
]);
61 /* Calculate the vectors of two edges of the triangle:
63 brw_ADD(p
, e
, v0
, negate(v2
));
64 brw_ADD(p
, f
, v1
, negate(v2
));
66 /* Take their crossproduct:
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
);
73 brw_MUL(p
, c
->reg
.dir
, c
->reg
.dir
, vec4(e
));
77 static void cull_direction( struct brw_clip_compile
*c
)
79 struct brw_compile
*p
= &c
->func
;
80 struct brw_instruction
*ccw
;
83 assert (!(c
->key
.fill_ccw
== CLIP_CULL
&&
84 c
->key
.fill_cw
== CLIP_CULL
));
86 if (c
->key
.fill_ccw
== CLIP_CULL
)
87 conditional
= BRW_CONDITIONAL_GE
;
89 conditional
= BRW_CONDITIONAL_L
;
94 get_element(c
->reg
.dir
, 2),
97 ccw
= brw_IF(p
, BRW_EXECUTE_1
);
99 brw_clip_kill_thread(c
);
106 static void copy_bfc( struct brw_clip_compile
*c
)
108 struct brw_compile
*p
= &c
->func
;
109 struct brw_instruction
*ccw
;
112 /* Do we have any colors to copy?
114 if (!(c
->offset
[VERT_RESULT_COL0
] && c
->offset
[VERT_RESULT_BFC0
]) &&
115 !(c
->offset
[VERT_RESULT_COL1
] && c
->offset
[VERT_RESULT_BFC1
]))
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.
122 if (c
->key
.copy_bfc_ccw
)
123 conditional
= BRW_CONDITIONAL_GE
;
125 conditional
= BRW_CONDITIONAL_L
;
128 vec1(brw_null_reg()),
130 get_element(c
->reg
.dir
, 2),
133 ccw
= brw_IF(p
, BRW_EXECUTE_1
);
137 for (i
= 0; i
< 3; i
++) {
138 if (c
->offset
[VERT_RESULT_COL0
] && c
->offset
[VERT_RESULT_BFC0
])
140 byte_offset(c
->reg
.vertex
[i
], c
->offset
[VERT_RESULT_COL0
]),
141 byte_offset(c
->reg
.vertex
[i
], c
->offset
[VERT_RESULT_BFC0
]));
143 if (c
->offset
[VERT_RESULT_COL1
] && c
->offset
[VERT_RESULT_BFC1
])
145 byte_offset(c
->reg
.vertex
[i
], c
->offset
[VERT_RESULT_COL1
]),
146 byte_offset(c
->reg
.vertex
[i
], c
->offset
[VERT_RESULT_BFC1
]));
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;
163 static void compute_offset( struct brw_clip_compile
*c
)
165 struct brw_compile
*p
= &c
->func
;
166 struct brw_reg off
= c
->reg
.offset
;
167 struct brw_reg dir
= c
->reg
.dir
;
169 brw_math_invert(p
, get_element(off
, 2), get_element(dir
, 2));
170 brw_MUL(p
, vec2(off
), dir
, get_element(off
, 2));
173 vec1(brw_null_reg()),
175 brw_abs(get_element(off
, 0)),
176 brw_abs(get_element(off
, 1)));
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
);
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
));
186 static void merge_edgeflags( struct brw_clip_compile
*c
)
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);
192 brw_AND(p
, tmp0
, get_element_ud(c
->reg
.R0
, 2), brw_imm_ud(PRIM_MASK
));
194 vec1(brw_null_reg()),
197 brw_imm_ud(_3DPRIM_POLYGON
));
199 /* Get away with using reg.vertex because we know that this is not
200 * a _3DPRIM_TRISTRIP_REVERSE:
202 is_poly
= brw_IF(p
, BRW_EXECUTE_1
);
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
);
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
);
214 brw_ENDIF(p
, is_poly
);
219 static void apply_one_offset( struct brw_clip_compile
*c
,
220 struct brw_indirect vert
)
222 struct brw_compile
*p
= &c
->func
;
223 struct brw_reg pos
= deref_4f(vert
, c
->offset
[VERT_RESULT_HPOS
]);
224 struct brw_reg z
= get_element(pos
, 2);
226 brw_ADD(p
, z
, z
, vec1(c
->reg
.offset
));
231 /***********************************************************************
232 * Output clipped polygon as an unfilled primitive:
234 static void emit_lines(struct brw_clip_compile
*c
,
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);
245 /* Need a seperate loop for 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
));
251 loop
= brw_DO(p
, BRW_EXECUTE_1
);
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));
256 apply_one_offset(c
, v0
);
258 brw_set_conditionalmod(p
, BRW_CONDITIONAL_G
);
259 brw_ADD(p
, c
->reg
.loopcount
, c
->reg
.loopcount
, brw_imm_d(-1));
264 /* v1ptr = &inlist[nr_verts]
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));
273 loop
= brw_DO(p
, BRW_EXECUTE_1
);
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));
279 /* draw edge if edgeflag != 0 */
281 vec1(brw_null_reg()), BRW_CONDITIONAL_NZ
,
282 deref_1f(v0
, c
->offset
[VERT_RESULT_EDGE
]),
284 draw_edge
= brw_IF(p
, BRW_EXECUTE_1
);
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
);
289 brw_ENDIF(p
, draw_edge
);
291 brw_set_conditionalmod(p
, BRW_CONDITIONAL_NZ
);
292 brw_ADD(p
, c
->reg
.loopcount
, c
->reg
.loopcount
, brw_imm_d(-1));
299 static void emit_points(struct brw_clip_compile
*c
,
300 GLboolean do_offset
)
302 struct brw_compile
*p
= &c
->func
;
303 struct brw_instruction
*loop
;
304 struct brw_instruction
*draw_point
;
306 struct brw_indirect v0
= brw_indirect(0, 0);
307 struct brw_indirect v0ptr
= brw_indirect(2, 0);
309 brw_MOV(p
, c
->reg
.loopcount
, c
->reg
.nr_verts
);
310 brw_MOV(p
, get_addr_reg(v0ptr
), brw_address(c
->reg
.inlist
));
312 loop
= brw_DO(p
, BRW_EXECUTE_1
);
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));
317 /* draw if edgeflag != 0
320 vec1(brw_null_reg()), BRW_CONDITIONAL_NZ
,
321 deref_1f(v0
, c
->offset
[VERT_RESULT_EDGE
]),
323 draw_point
= brw_IF(p
, BRW_EXECUTE_1
);
326 apply_one_offset(c
, v0
);
328 brw_clip_emit_vue(c
, v0
, 1, 0, (_3DPRIM_POINTLIST
<< 2) | R02_PRIM_START
| R02_PRIM_END
);
330 brw_ENDIF(p
, draw_point
);
332 brw_set_conditionalmod(p
, BRW_CONDITIONAL_NZ
);
333 brw_ADD(p
, c
->reg
.loopcount
, c
->reg
.loopcount
, brw_imm_d(-1));
344 static void emit_primitives( struct brw_clip_compile
*c
,
346 GLboolean do_offset
)
350 brw_clip_tri_emit_polygon(c
);
354 emit_lines(c
, do_offset
);
358 emit_points(c
, do_offset
);
369 static void emit_unfilled_primitives( struct brw_clip_compile
*c
)
371 struct brw_compile
*p
= &c
->func
;
372 struct brw_instruction
*ccw
;
374 /* Direction culling has already been done.
376 if (c
->key
.fill_ccw
!= c
->key
.fill_cw
&&
377 c
->key
.fill_ccw
!= CLIP_CULL
&&
378 c
->key
.fill_cw
!= CLIP_CULL
)
381 vec1(brw_null_reg()),
383 get_element(c
->reg
.dir
, 2),
386 ccw
= brw_IF(p
, BRW_EXECUTE_1
);
388 emit_primitives(c
, c
->key
.fill_ccw
, c
->key
.offset_ccw
);
390 ccw
= brw_ELSE(p
, ccw
);
392 emit_primitives(c
, c
->key
.fill_cw
, c
->key
.offset_cw
);
396 else if (c
->key
.fill_cw
!= CLIP_CULL
) {
397 emit_primitives(c
, c
->key
.fill_cw
, c
->key
.offset_cw
);
399 else if (c
->key
.fill_ccw
!= CLIP_CULL
) {
400 emit_primitives(c
, c
->key
.fill_ccw
, c
->key
.offset_ccw
);
407 static void check_nr_verts( struct brw_clip_compile
*c
)
409 struct brw_compile
*p
= &c
->func
;
410 struct brw_instruction
*if_insn
;
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
);
415 brw_clip_kill_thread(c
);
417 brw_ENDIF(p
, if_insn
);
421 void brw_emit_unfilled_clip( struct brw_clip_compile
*c
)
423 struct brw_compile
*p
= &c
->func
;
424 struct brw_instruction
*do_clip
;
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
);
434 brw_clip_tri_alloc_regs(c
, 3 + c
->key
.nr_userclip
+ 6);
435 brw_clip_tri_init_vertices(c
);
437 assert(c
->offset
[VERT_RESULT_EDGE
]);
439 if (c
->key
.fill_ccw
== CLIP_CULL
&&
440 c
->key
.fill_cw
== CLIP_CULL
) {
441 brw_clip_kill_thread(c
);
447 /* Need to use the inlist indirection here:
449 if (c
->need_direction
)
450 compute_tri_direction(c
);
452 if (c
->key
.fill_ccw
== CLIP_CULL
||
453 c
->key
.fill_cw
== CLIP_CULL
)
456 if (c
->key
.offset_ccw
||
460 if (c
->key
.copy_bfc_ccw
||
464 /* Need to do this whether we clip or not:
466 if (c
->key
.do_flat_shading
)
467 brw_clip_tri_flat_shade(c
);
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
);
473 brw_clip_init_planes(c
);
477 brw_ENDIF(p
, do_clip
);
479 emit_unfilled_primitives(c
);
480 brw_clip_kill_thread(c
);