2 Copyright (C) Intel Corp. 2006. All Rights Reserved.
3 Intel funded Tungsten Graphics 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 <keithw@vmware.com>
32 #include "main/macros.h"
33 #include "main/enums.h"
34 #include "program/program.h"
39 /* This is performed against the original triangles, so no indirection
43 static void compute_tri_direction( struct brw_clip_compile
*c
)
45 struct brw_codegen
*p
= &c
->func
;
46 struct brw_reg e
= c
->reg
.tmp0
;
47 struct brw_reg f
= c
->reg
.tmp1
;
48 GLuint hpos_offset
= brw_varying_to_offset(&c
->vue_map
, VARYING_SLOT_POS
);
49 struct brw_reg v0
= byte_offset(c
->reg
.vertex
[0], hpos_offset
);
50 struct brw_reg v1
= byte_offset(c
->reg
.vertex
[1], hpos_offset
);
51 struct brw_reg v2
= byte_offset(c
->reg
.vertex
[2], hpos_offset
);
54 struct brw_reg v0n
= get_tmp(c
);
55 struct brw_reg v1n
= get_tmp(c
);
56 struct brw_reg v2n
= get_tmp(c
);
59 * NOTE: We can't modify the original vertex coordinates,
60 * as it may impact further operations.
61 * So, we have to keep normalized coordinates in temp registers.
64 * Try to optimize unnecessary MOV's.
70 brw_clip_project_position(c
, v0n
);
71 brw_clip_project_position(c
, v1n
);
72 brw_clip_project_position(c
, v2n
);
74 /* Calculate the vectors of two edges of the triangle:
76 brw_ADD(p
, e
, v0n
, negate(v2n
));
77 brw_ADD(p
, f
, v1n
, negate(v2n
));
79 /* Take their crossproduct:
81 brw_set_default_access_mode(p
, BRW_ALIGN_16
);
82 brw_MUL(p
, vec4(brw_null_reg()), brw_swizzle(e
, BRW_SWIZZLE_YZXW
),
83 brw_swizzle(f
, BRW_SWIZZLE_ZXYW
));
84 brw_MAC(p
, vec4(e
), negate(brw_swizzle(e
, BRW_SWIZZLE_ZXYW
)),
85 brw_swizzle(f
, BRW_SWIZZLE_YZXW
));
86 brw_set_default_access_mode(p
, BRW_ALIGN_1
);
88 brw_MUL(p
, c
->reg
.dir
, c
->reg
.dir
, vec4(e
));
92 static void cull_direction( struct brw_clip_compile
*c
)
94 struct brw_codegen
*p
= &c
->func
;
97 assert (!(c
->key
.fill_ccw
== BRW_CLIP_FILL_MODE_CULL
&&
98 c
->key
.fill_cw
== BRW_CLIP_FILL_MODE_CULL
));
100 if (c
->key
.fill_ccw
== BRW_CLIP_FILL_MODE_CULL
)
101 conditional
= BRW_CONDITIONAL_GE
;
103 conditional
= BRW_CONDITIONAL_L
;
106 vec1(brw_null_reg()),
108 get_element(c
->reg
.dir
, 2),
111 brw_IF(p
, BRW_EXECUTE_1
);
113 brw_clip_kill_thread(c
);
120 static void copy_bfc( struct brw_clip_compile
*c
)
122 struct brw_codegen
*p
= &c
->func
;
125 /* Do we have any colors to copy?
127 if (!(brw_clip_have_varying(c
, VARYING_SLOT_COL0
) &&
128 brw_clip_have_varying(c
, VARYING_SLOT_BFC0
)) &&
129 !(brw_clip_have_varying(c
, VARYING_SLOT_COL1
) &&
130 brw_clip_have_varying(c
, VARYING_SLOT_BFC1
)))
133 /* In some weird degenerate cases we can end up testing the
134 * direction twice, once for culling and once for bfc copying. Oh
135 * well, that's what you get for setting weird GL state.
137 if (c
->key
.copy_bfc_ccw
)
138 conditional
= BRW_CONDITIONAL_GE
;
140 conditional
= BRW_CONDITIONAL_L
;
143 vec1(brw_null_reg()),
145 get_element(c
->reg
.dir
, 2),
148 brw_IF(p
, BRW_EXECUTE_1
);
152 for (i
= 0; i
< 3; i
++) {
153 if (brw_clip_have_varying(c
, VARYING_SLOT_COL0
) &&
154 brw_clip_have_varying(c
, VARYING_SLOT_BFC0
))
156 byte_offset(c
->reg
.vertex
[i
],
157 brw_varying_to_offset(&c
->vue_map
,
159 byte_offset(c
->reg
.vertex
[i
],
160 brw_varying_to_offset(&c
->vue_map
,
161 VARYING_SLOT_BFC0
)));
163 if (brw_clip_have_varying(c
, VARYING_SLOT_COL1
) &&
164 brw_clip_have_varying(c
, VARYING_SLOT_BFC1
))
166 byte_offset(c
->reg
.vertex
[i
],
167 brw_varying_to_offset(&c
->vue_map
,
169 byte_offset(c
->reg
.vertex
[i
],
170 brw_varying_to_offset(&c
->vue_map
,
171 VARYING_SLOT_BFC1
)));
181 GLfloat iz = 1.0 / dir.z;
182 GLfloat ac = dir.x * iz;
183 GLfloat bc = dir.y * iz;
184 offset = ctx->Polygon.OffsetUnits * DEPTH_SCALE;
185 offset += MAX2( abs(ac), abs(bc) ) * ctx->Polygon.OffsetFactor;
186 if (ctx->Polygon.OffsetClamp && isfinite(ctx->Polygon.OffsetClamp)) {
187 if (ctx->Polygon.OffsetClamp < 0)
188 offset = MAX2( offset, ctx->Polygon.OffsetClamp );
190 offset = MIN2( offset, ctx->Polygon.OffsetClamp );
194 static void compute_offset( struct brw_clip_compile
*c
)
196 struct brw_codegen
*p
= &c
->func
;
197 struct brw_reg off
= c
->reg
.offset
;
198 struct brw_reg dir
= c
->reg
.dir
;
200 brw_math_invert(p
, get_element(off
, 2), get_element(dir
, 2));
201 brw_MUL(p
, vec2(off
), vec2(dir
), get_element(off
, 2));
204 vec1(brw_null_reg()),
206 brw_abs(get_element(off
, 0)),
207 brw_abs(get_element(off
, 1)));
209 brw_SEL(p
, vec1(off
),
210 brw_abs(get_element(off
, 0)), brw_abs(get_element(off
, 1)));
211 brw_inst_set_pred_control(p
->devinfo
, brw_last_inst
, BRW_PREDICATE_NORMAL
);
213 brw_MUL(p
, vec1(off
), vec1(off
), brw_imm_f(c
->key
.offset_factor
));
214 brw_ADD(p
, vec1(off
), vec1(off
), brw_imm_f(c
->key
.offset_units
));
215 if (c
->key
.offset_clamp
&& isfinite(c
->key
.offset_clamp
)) {
217 vec1(brw_null_reg()),
218 c
->key
.offset_clamp
< 0 ? BRW_CONDITIONAL_GE
: BRW_CONDITIONAL_L
,
220 brw_imm_f(c
->key
.offset_clamp
));
221 brw_SEL(p
, vec1(off
), vec1(off
), brw_imm_f(c
->key
.offset_clamp
));
226 static void merge_edgeflags( struct brw_clip_compile
*c
)
228 struct brw_codegen
*p
= &c
->func
;
229 struct brw_reg tmp0
= get_element_ud(c
->reg
.tmp0
, 0);
231 brw_AND(p
, tmp0
, get_element_ud(c
->reg
.R0
, 2), brw_imm_ud(PRIM_MASK
));
233 vec1(brw_null_reg()),
236 brw_imm_ud(_3DPRIM_POLYGON
));
238 /* Get away with using reg.vertex because we know that this is not
239 * a _3DPRIM_TRISTRIP_REVERSE:
241 brw_IF(p
, BRW_EXECUTE_1
);
243 brw_AND(p
, vec1(brw_null_reg()), get_element_ud(c
->reg
.R0
, 2), brw_imm_ud(1<<8));
244 brw_inst_set_cond_modifier(p
->devinfo
, brw_last_inst
, BRW_CONDITIONAL_EQ
);
245 brw_MOV(p
, byte_offset(c
->reg
.vertex
[0],
246 brw_varying_to_offset(&c
->vue_map
,
249 brw_inst_set_pred_control(p
->devinfo
, brw_last_inst
, BRW_PREDICATE_NORMAL
);
251 brw_AND(p
, vec1(brw_null_reg()), get_element_ud(c
->reg
.R0
, 2), brw_imm_ud(1<<9));
252 brw_inst_set_cond_modifier(p
->devinfo
, brw_last_inst
, BRW_CONDITIONAL_EQ
);
253 brw_MOV(p
, byte_offset(c
->reg
.vertex
[2],
254 brw_varying_to_offset(&c
->vue_map
,
257 brw_inst_set_pred_control(p
->devinfo
, brw_last_inst
, BRW_PREDICATE_NORMAL
);
264 static void apply_one_offset( struct brw_clip_compile
*c
,
265 struct brw_indirect vert
)
267 struct brw_codegen
*p
= &c
->func
;
268 GLuint ndc_offset
= brw_varying_to_offset(&c
->vue_map
,
269 BRW_VARYING_SLOT_NDC
);
270 struct brw_reg z
= deref_1f(vert
, ndc_offset
+
271 2 * type_sz(BRW_REGISTER_TYPE_F
));
273 brw_ADD(p
, z
, z
, vec1(c
->reg
.offset
));
278 /***********************************************************************
279 * Output clipped polygon as an unfilled primitive:
281 static void emit_lines(struct brw_clip_compile
*c
,
284 struct brw_codegen
*p
= &c
->func
;
285 struct brw_indirect v0
= brw_indirect(0, 0);
286 struct brw_indirect v1
= brw_indirect(1, 0);
287 struct brw_indirect v0ptr
= brw_indirect(2, 0);
288 struct brw_indirect v1ptr
= brw_indirect(3, 0);
290 /* Need a separate loop for offset:
293 brw_MOV(p
, c
->reg
.loopcount
, c
->reg
.nr_verts
);
294 brw_MOV(p
, get_addr_reg(v0ptr
), brw_address(c
->reg
.inlist
));
296 brw_DO(p
, BRW_EXECUTE_1
);
298 brw_MOV(p
, get_addr_reg(v0
), deref_1uw(v0ptr
, 0));
299 brw_ADD(p
, get_addr_reg(v0ptr
), get_addr_reg(v0ptr
), brw_imm_uw(2));
301 apply_one_offset(c
, v0
);
303 brw_ADD(p
, c
->reg
.loopcount
, c
->reg
.loopcount
, brw_imm_d(-1));
304 brw_inst_set_cond_modifier(p
->devinfo
, brw_last_inst
, BRW_CONDITIONAL_G
);
307 brw_inst_set_pred_control(p
->devinfo
, brw_last_inst
, BRW_PREDICATE_NORMAL
);
310 /* v1ptr = &inlist[nr_verts]
313 brw_MOV(p
, c
->reg
.loopcount
, c
->reg
.nr_verts
);
314 brw_MOV(p
, get_addr_reg(v0ptr
), brw_address(c
->reg
.inlist
));
315 brw_ADD(p
, get_addr_reg(v1ptr
), get_addr_reg(v0ptr
), retype(c
->reg
.nr_verts
, BRW_REGISTER_TYPE_UW
));
316 brw_ADD(p
, get_addr_reg(v1ptr
), get_addr_reg(v1ptr
), retype(c
->reg
.nr_verts
, BRW_REGISTER_TYPE_UW
));
317 brw_MOV(p
, deref_1uw(v1ptr
, 0), deref_1uw(v0ptr
, 0));
319 brw_DO(p
, BRW_EXECUTE_1
);
321 brw_MOV(p
, get_addr_reg(v0
), deref_1uw(v0ptr
, 0));
322 brw_MOV(p
, get_addr_reg(v1
), deref_1uw(v0ptr
, 2));
323 brw_ADD(p
, get_addr_reg(v0ptr
), get_addr_reg(v0ptr
), brw_imm_uw(2));
325 /* draw edge if edgeflag != 0 */
327 vec1(brw_null_reg()), BRW_CONDITIONAL_NZ
,
328 deref_1f(v0
, brw_varying_to_offset(&c
->vue_map
,
331 brw_IF(p
, BRW_EXECUTE_1
);
333 brw_clip_emit_vue(c
, v0
, BRW_URB_WRITE_ALLOCATE_COMPLETE
,
334 (_3DPRIM_LINESTRIP
<< URB_WRITE_PRIM_TYPE_SHIFT
)
335 | URB_WRITE_PRIM_START
);
336 brw_clip_emit_vue(c
, v1
, BRW_URB_WRITE_ALLOCATE_COMPLETE
,
337 (_3DPRIM_LINESTRIP
<< URB_WRITE_PRIM_TYPE_SHIFT
)
338 | URB_WRITE_PRIM_END
);
342 brw_ADD(p
, c
->reg
.loopcount
, c
->reg
.loopcount
, brw_imm_d(-1));
343 brw_inst_set_cond_modifier(p
->devinfo
, brw_last_inst
, BRW_CONDITIONAL_NZ
);
346 brw_inst_set_pred_control(p
->devinfo
, brw_last_inst
, BRW_PREDICATE_NORMAL
);
351 static void emit_points(struct brw_clip_compile
*c
,
354 struct brw_codegen
*p
= &c
->func
;
356 struct brw_indirect v0
= brw_indirect(0, 0);
357 struct brw_indirect v0ptr
= brw_indirect(2, 0);
359 brw_MOV(p
, c
->reg
.loopcount
, c
->reg
.nr_verts
);
360 brw_MOV(p
, get_addr_reg(v0ptr
), brw_address(c
->reg
.inlist
));
362 brw_DO(p
, BRW_EXECUTE_1
);
364 brw_MOV(p
, get_addr_reg(v0
), deref_1uw(v0ptr
, 0));
365 brw_ADD(p
, get_addr_reg(v0ptr
), get_addr_reg(v0ptr
), brw_imm_uw(2));
367 /* draw if edgeflag != 0
370 vec1(brw_null_reg()), BRW_CONDITIONAL_NZ
,
371 deref_1f(v0
, brw_varying_to_offset(&c
->vue_map
,
374 brw_IF(p
, BRW_EXECUTE_1
);
377 apply_one_offset(c
, v0
);
379 brw_clip_emit_vue(c
, v0
, BRW_URB_WRITE_ALLOCATE_COMPLETE
,
380 (_3DPRIM_POINTLIST
<< URB_WRITE_PRIM_TYPE_SHIFT
)
381 | URB_WRITE_PRIM_START
| URB_WRITE_PRIM_END
);
385 brw_ADD(p
, c
->reg
.loopcount
, c
->reg
.loopcount
, brw_imm_d(-1));
386 brw_inst_set_cond_modifier(p
->devinfo
, brw_last_inst
, BRW_CONDITIONAL_NZ
);
389 brw_inst_set_pred_control(p
->devinfo
, brw_last_inst
, BRW_PREDICATE_NORMAL
);
398 static void emit_primitives( struct brw_clip_compile
*c
,
403 case BRW_CLIP_FILL_MODE_FILL
:
404 brw_clip_tri_emit_polygon(c
);
407 case BRW_CLIP_FILL_MODE_LINE
:
408 emit_lines(c
, do_offset
);
411 case BRW_CLIP_FILL_MODE_POINT
:
412 emit_points(c
, do_offset
);
415 case BRW_CLIP_FILL_MODE_CULL
:
416 unreachable("not reached");
422 static void emit_unfilled_primitives( struct brw_clip_compile
*c
)
424 struct brw_codegen
*p
= &c
->func
;
426 /* Direction culling has already been done.
428 if (c
->key
.fill_ccw
!= c
->key
.fill_cw
&&
429 c
->key
.fill_ccw
!= BRW_CLIP_FILL_MODE_CULL
&&
430 c
->key
.fill_cw
!= BRW_CLIP_FILL_MODE_CULL
)
433 vec1(brw_null_reg()),
435 get_element(c
->reg
.dir
, 2),
438 brw_IF(p
, BRW_EXECUTE_1
);
440 emit_primitives(c
, c
->key
.fill_ccw
, c
->key
.offset_ccw
);
444 emit_primitives(c
, c
->key
.fill_cw
, c
->key
.offset_cw
);
448 else if (c
->key
.fill_cw
!= BRW_CLIP_FILL_MODE_CULL
) {
449 emit_primitives(c
, c
->key
.fill_cw
, c
->key
.offset_cw
);
451 else if (c
->key
.fill_ccw
!= BRW_CLIP_FILL_MODE_CULL
) {
452 emit_primitives(c
, c
->key
.fill_ccw
, c
->key
.offset_ccw
);
459 static void check_nr_verts( struct brw_clip_compile
*c
)
461 struct brw_codegen
*p
= &c
->func
;
463 brw_CMP(p
, vec1(brw_null_reg()), BRW_CONDITIONAL_L
, c
->reg
.nr_verts
, brw_imm_d(3));
464 brw_IF(p
, BRW_EXECUTE_1
);
466 brw_clip_kill_thread(c
);
472 void brw_emit_unfilled_clip( struct brw_clip_compile
*c
)
474 struct brw_codegen
*p
= &c
->func
;
476 c
->need_direction
= ((c
->key
.offset_ccw
|| c
->key
.offset_cw
) ||
477 (c
->key
.fill_ccw
!= c
->key
.fill_cw
) ||
478 c
->key
.fill_ccw
== BRW_CLIP_FILL_MODE_CULL
||
479 c
->key
.fill_cw
== BRW_CLIP_FILL_MODE_CULL
||
480 c
->key
.copy_bfc_cw
||
481 c
->key
.copy_bfc_ccw
);
483 brw_clip_tri_alloc_regs(c
, 3 + c
->key
.nr_userclip
+ 6);
484 brw_clip_tri_init_vertices(c
);
485 brw_clip_init_ff_sync(c
);
487 assert(brw_clip_have_varying(c
, VARYING_SLOT_EDGE
));
489 if (c
->key
.fill_ccw
== BRW_CLIP_FILL_MODE_CULL
&&
490 c
->key
.fill_cw
== BRW_CLIP_FILL_MODE_CULL
) {
491 brw_clip_kill_thread(c
);
497 /* Need to use the inlist indirection here:
499 if (c
->need_direction
)
500 compute_tri_direction(c
);
502 if (c
->key
.fill_ccw
== BRW_CLIP_FILL_MODE_CULL
||
503 c
->key
.fill_cw
== BRW_CLIP_FILL_MODE_CULL
)
506 if (c
->key
.offset_ccw
||
510 if (c
->key
.copy_bfc_ccw
||
514 /* Need to do this whether we clip or not:
516 if (c
->key
.contains_flat_varying
)
517 brw_clip_tri_flat_shade(c
);
519 brw_clip_init_clipmask(c
);
520 brw_CMP(p
, vec1(brw_null_reg()), BRW_CONDITIONAL_NZ
, c
->reg
.planemask
, brw_imm_ud(0));
521 brw_IF(p
, BRW_EXECUTE_1
);
523 brw_clip_init_planes(c
);
529 emit_unfilled_primitives(c
);
530 brw_clip_kill_thread(c
);