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>
33 #include "main/macros.h"
34 #include "main/enums.h"
35 #include "program/program.h"
40 struct brw_reg
get_tmp( struct brw_clip_compile
*c
)
42 struct brw_reg tmp
= brw_vec4_grf(c
->last_tmp
, 0);
44 if (++c
->last_tmp
> c
->prog_data
.total_grf
)
45 c
->prog_data
.total_grf
= c
->last_tmp
;
50 static void release_tmp( struct brw_clip_compile
*c
, struct brw_reg tmp
)
52 if (tmp
.nr
== c
->last_tmp
-1)
57 static struct brw_reg
make_plane_ud(GLuint x
, GLuint y
, GLuint z
, GLuint w
)
59 return brw_imm_ud((w
<<24) | (z
<<16) | (y
<<8) | x
);
63 void brw_clip_init_planes( struct brw_clip_compile
*c
)
65 struct brw_codegen
*p
= &c
->func
;
67 if (!c
->key
.nr_userclip
) {
68 brw_MOV(p
, get_element_ud(c
->reg
.fixed_planes
, 0), make_plane_ud( 0, 0, 0xff, 1));
69 brw_MOV(p
, get_element_ud(c
->reg
.fixed_planes
, 1), make_plane_ud( 0, 0, 1, 1));
70 brw_MOV(p
, get_element_ud(c
->reg
.fixed_planes
, 2), make_plane_ud( 0, 0xff, 0, 1));
71 brw_MOV(p
, get_element_ud(c
->reg
.fixed_planes
, 3), make_plane_ud( 0, 1, 0, 1));
72 brw_MOV(p
, get_element_ud(c
->reg
.fixed_planes
, 4), make_plane_ud(0xff, 0, 0, 1));
73 brw_MOV(p
, get_element_ud(c
->reg
.fixed_planes
, 5), make_plane_ud( 1, 0, 0, 1));
81 /* Project 'pos' to screen space (or back again), overwrite with results:
83 void brw_clip_project_position(struct brw_clip_compile
*c
, struct brw_reg pos
)
85 struct brw_codegen
*p
= &c
->func
;
89 brw_math_invert(p
, get_element(pos
, W
), get_element(pos
, W
));
91 /* value.xyz *= value.rhw
93 brw_set_default_access_mode(p
, BRW_ALIGN_16
);
94 brw_MUL(p
, brw_writemask(pos
, WRITEMASK_XYZ
), pos
,
95 brw_swizzle(pos
, BRW_SWIZZLE_WWWW
));
96 brw_set_default_access_mode(p
, BRW_ALIGN_1
);
100 static void brw_clip_project_vertex( struct brw_clip_compile
*c
,
101 struct brw_indirect vert_addr
)
103 struct brw_codegen
*p
= &c
->func
;
104 struct brw_reg tmp
= get_tmp(c
);
105 GLuint hpos_offset
= brw_varying_to_offset(&c
->vue_map
, VARYING_SLOT_POS
);
106 GLuint ndc_offset
= brw_varying_to_offset(&c
->vue_map
,
107 BRW_VARYING_SLOT_NDC
);
109 /* Fixup position. Extract from the original vertex and re-project
112 brw_MOV(p
, tmp
, deref_4f(vert_addr
, hpos_offset
));
113 brw_clip_project_position(c
, tmp
);
114 brw_MOV(p
, deref_4f(vert_addr
, ndc_offset
), tmp
);
122 /* Interpolate between two vertices and put the result into a0.0.
123 * Increment a0.0 accordingly.
125 * Beware that dest_ptr can be equal to v0_ptr!
127 void brw_clip_interp_vertex( struct brw_clip_compile
*c
,
128 struct brw_indirect dest_ptr
,
129 struct brw_indirect v0_ptr
, /* from */
130 struct brw_indirect v1_ptr
, /* to */
134 struct brw_codegen
*p
= &c
->func
;
135 struct brw_reg t_nopersp
, v0_ndc_copy
;
138 /* Just copy the vertex header:
141 * After CLIP stage, only first 256 bits of the VUE are read
142 * back on Ironlake, so needn't change it
144 brw_copy_indirect_to_indirect(p
, dest_ptr
, v0_ptr
, 1);
147 /* First handle the 3D and NDC interpolation, in case we
148 * need noperspective interpolation. Doing it early has no
149 * performance impact in any case.
152 /* Take a copy of the v0 NDC coordinates, in case dest == v0. */
153 if (c
->key
.contains_noperspective_varying
) {
154 GLuint offset
= brw_varying_to_offset(&c
->vue_map
,
155 BRW_VARYING_SLOT_NDC
);
156 v0_ndc_copy
= get_tmp(c
);
157 brw_MOV(p
, v0_ndc_copy
, deref_4f(v0_ptr
, offset
));
160 /* Compute the new 3D position
162 * dest_hpos = v0_hpos * (1 - t0) + v1_hpos * t0
165 GLuint delta
= brw_varying_to_offset(&c
->vue_map
, VARYING_SLOT_POS
);
166 struct brw_reg tmp
= get_tmp(c
);
167 brw_MUL(p
, vec4(brw_null_reg()), deref_4f(v1_ptr
, delta
), t0
);
168 brw_MAC(p
, tmp
, negate(deref_4f(v0_ptr
, delta
)), t0
);
169 brw_ADD(p
, deref_4f(dest_ptr
, delta
), deref_4f(v0_ptr
, delta
), tmp
);
173 /* Recreate the projected (NDC) coordinate in the new vertex header */
174 brw_clip_project_vertex(c
, dest_ptr
);
176 /* If we have noperspective attributes,
177 * we need to compute the screen-space t
179 if (c
->key
.contains_noperspective_varying
) {
180 GLuint delta
= brw_varying_to_offset(&c
->vue_map
,
181 BRW_VARYING_SLOT_NDC
);
182 struct brw_reg tmp
= get_tmp(c
);
183 t_nopersp
= get_tmp(c
);
185 /* t_nopersp = vec4(v1.xy, dest.xy) */
186 brw_MOV(p
, t_nopersp
, deref_4f(v1_ptr
, delta
));
187 brw_MOV(p
, tmp
, deref_4f(dest_ptr
, delta
));
188 brw_set_default_access_mode(p
, BRW_ALIGN_16
);
190 brw_writemask(t_nopersp
, WRITEMASK_ZW
),
191 brw_swizzle(tmp
, BRW_SWIZZLE_XYXY
));
193 /* t_nopersp = vec4(v1.xy, dest.xy) - v0.xyxy */
194 brw_ADD(p
, t_nopersp
, t_nopersp
,
195 negate(brw_swizzle(v0_ndc_copy
, BRW_SWIZZLE_XYXY
)));
197 /* Add the absolute values of the X and Y deltas so that if
198 * the points aren't in the same place on the screen we get
199 * nonzero values to divide.
201 * After that, we have vert1 - vert0 in t_nopersp.x and
202 * vertnew - vert0 in t_nopersp.y
204 * t_nopersp = vec2(|v1.x -v0.x| + |v1.y -v0.y|,
205 * |dest.x-v0.x| + |dest.y-v0.y|)
208 brw_writemask(t_nopersp
, WRITEMASK_XY
),
209 brw_abs(brw_swizzle(t_nopersp
, BRW_SWIZZLE_XZXZ
)),
210 brw_abs(brw_swizzle(t_nopersp
, BRW_SWIZZLE_YWYW
)));
211 brw_set_default_access_mode(p
, BRW_ALIGN_1
);
213 /* If the points are in the same place, just substitute a
214 * value to avoid divide-by-zero
216 brw_CMP(p
, vec1(brw_null_reg()), BRW_CONDITIONAL_EQ
,
219 brw_IF(p
, BRW_EXECUTE_1
);
220 brw_MOV(p
, t_nopersp
, brw_imm_vf4(brw_float_to_vf(1.0),
221 brw_float_to_vf(0.0),
222 brw_float_to_vf(0.0),
223 brw_float_to_vf(0.0)));
226 /* Now compute t_nopersp = t_nopersp.y/t_nopersp.x and broadcast it. */
227 brw_math_invert(p
, get_element(t_nopersp
, 0), get_element(t_nopersp
, 0));
228 brw_MUL(p
, vec1(t_nopersp
), vec1(t_nopersp
),
229 vec1(suboffset(t_nopersp
, 1)));
230 brw_set_default_access_mode(p
, BRW_ALIGN_16
);
231 brw_MOV(p
, t_nopersp
, brw_swizzle(t_nopersp
, BRW_SWIZZLE_XXXX
));
232 brw_set_default_access_mode(p
, BRW_ALIGN_1
);
235 release_tmp(c
, v0_ndc_copy
);
238 /* Now we can iterate over each attribute
239 * (could be done in pairs?)
241 for (slot
= 0; slot
< c
->vue_map
.num_slots
; slot
++) {
242 int varying
= c
->vue_map
.slot_to_varying
[slot
];
243 GLuint delta
= brw_vue_slot_to_offset(slot
);
245 /* HPOS, NDC already handled above */
246 if (varying
== VARYING_SLOT_POS
|| varying
== BRW_VARYING_SLOT_NDC
)
250 if (varying
== VARYING_SLOT_EDGE
) {
252 brw_MOV(p
, deref_4f(dest_ptr
, delta
), brw_imm_f(1));
254 brw_MOV(p
, deref_4f(dest_ptr
, delta
), deref_4f(v0_ptr
, delta
));
255 } else if (varying
== VARYING_SLOT_PSIZ
) {
256 /* PSIZ doesn't need interpolation because it isn't used by the
259 } else if (varying
< VARYING_SLOT_MAX
) {
260 /* This is a true vertex result (and not a special value for the VUE
261 * header), so interpolate:
263 * New = attr0 + t*attr1 - t*attr0
265 * Unless the attribute is flat shaded -- in which case just copy
266 * from one of the sources (doesn't matter which; already copied from pv)
268 GLuint interp
= c
->key
.interp_mode
[slot
];
270 if (interp
!= INTERP_MODE_FLAT
) {
271 struct brw_reg tmp
= get_tmp(c
);
273 interp
== INTERP_MODE_NOPERSPECTIVE
? t_nopersp
: t0
;
276 vec4(brw_null_reg()),
277 deref_4f(v1_ptr
, delta
),
282 negate(deref_4f(v0_ptr
, delta
)),
286 deref_4f(dest_ptr
, delta
),
287 deref_4f(v0_ptr
, delta
),
294 deref_4f(dest_ptr
, delta
),
295 deref_4f(v0_ptr
, delta
));
300 if (c
->vue_map
.num_slots
% 2) {
301 GLuint delta
= brw_vue_slot_to_offset(c
->vue_map
.num_slots
);
303 brw_MOV(p
, deref_4f(dest_ptr
, delta
), brw_imm_f(0));
306 if (c
->key
.contains_noperspective_varying
)
307 release_tmp(c
, t_nopersp
);
310 void brw_clip_emit_vue(struct brw_clip_compile
*c
,
311 struct brw_indirect vert
,
312 enum brw_urb_write_flags flags
,
315 struct brw_codegen
*p
= &c
->func
;
316 bool allocate
= flags
& BRW_URB_WRITE_ALLOCATE
;
320 /* Any URB entry that is allocated must subsequently be used or discarded,
321 * so it doesn't make sense to mark EOT and ALLOCATE at the same time.
323 assert(!(allocate
&& (flags
& BRW_URB_WRITE_EOT
)));
325 /* Copy the vertex from vertn into m1..mN+1:
327 brw_copy_from_indirect(p
, brw_message_reg(1), vert
, c
->nr_regs
);
329 /* Overwrite PrimType and PrimStart in the message header, for
330 * each vertex in turn:
332 brw_MOV(p
, get_element_ud(c
->reg
.R0
, 2), brw_imm_ud(header
));
335 /* Send each vertex as a separate write to the urb. This
336 * is different to the concept in brw_sf_emit.c, where
337 * subsequent writes are used to build up a single urb
338 * entry. Each of these writes instantiates a separate
339 * urb entry - (I think... what about 'allocate'?)
342 allocate
? c
->reg
.R0
: retype(brw_null_reg(), BRW_REGISTER_TYPE_UD
),
346 c
->nr_regs
+ 1, /* msg length */
347 allocate
? 1 : 0, /* response_length */
349 BRW_URB_SWIZZLE_NONE
);
354 void brw_clip_kill_thread(struct brw_clip_compile
*c
)
356 struct brw_codegen
*p
= &c
->func
;
359 /* Send an empty message to kill the thread and release any
360 * allocated urb entry:
363 retype(brw_null_reg(), BRW_REGISTER_TYPE_UD
),
366 BRW_URB_WRITE_UNUSED
| BRW_URB_WRITE_EOT_COMPLETE
,
368 0, /* response len */
370 BRW_URB_SWIZZLE_NONE
);
376 struct brw_reg
brw_clip_plane0_address( struct brw_clip_compile
*c
)
378 return brw_address(c
->reg
.fixed_planes
);
382 struct brw_reg
brw_clip_plane_stride( struct brw_clip_compile
*c
)
384 if (c
->key
.nr_userclip
) {
385 return brw_imm_uw(16);
388 return brw_imm_uw(4);
393 /* Distribute flatshaded attributes from provoking vertex prior to
396 void brw_clip_copy_flatshaded_attributes( struct brw_clip_compile
*c
,
397 GLuint to
, GLuint from
)
399 struct brw_codegen
*p
= &c
->func
;
401 for (int i
= 0; i
< c
->vue_map
.num_slots
; i
++) {
402 if (c
->key
.interp_mode
[i
] == INTERP_MODE_FLAT
) {
404 byte_offset(c
->reg
.vertex
[to
], brw_vue_slot_to_offset(i
)),
405 byte_offset(c
->reg
.vertex
[from
], brw_vue_slot_to_offset(i
)));
412 void brw_clip_init_clipmask( struct brw_clip_compile
*c
)
414 struct brw_codegen
*p
= &c
->func
;
415 struct brw_reg incoming
= get_element_ud(c
->reg
.R0
, 2);
417 /* Shift so that lowest outcode bit is rightmost:
419 brw_SHR(p
, c
->reg
.planemask
, incoming
, brw_imm_ud(26));
421 if (c
->key
.nr_userclip
) {
422 struct brw_reg tmp
= retype(vec1(get_tmp(c
)), BRW_REGISTER_TYPE_UD
);
424 /* Rearrange userclip outcodes so that they come directly after
425 * the fixed plane bits.
427 if (p
->devinfo
->gen
== 5 || p
->devinfo
->is_g4x
)
428 brw_AND(p
, tmp
, incoming
, brw_imm_ud(0xff<<14));
430 brw_AND(p
, tmp
, incoming
, brw_imm_ud(0x3f<<14));
432 brw_SHR(p
, tmp
, tmp
, brw_imm_ud(8));
433 brw_OR(p
, c
->reg
.planemask
, c
->reg
.planemask
, tmp
);
439 void brw_clip_ff_sync(struct brw_clip_compile
*c
)
441 struct brw_codegen
*p
= &c
->func
;
443 if (p
->devinfo
->gen
== 5) {
444 brw_AND(p
, brw_null_reg(), c
->reg
.ff_sync
, brw_imm_ud(0x1));
445 brw_inst_set_cond_modifier(p
->devinfo
, brw_last_inst
, BRW_CONDITIONAL_Z
);
446 brw_IF(p
, BRW_EXECUTE_1
);
448 brw_OR(p
, c
->reg
.ff_sync
, c
->reg
.ff_sync
, brw_imm_ud(0x1));
454 1, /* response length */
458 brw_set_default_predicate_control(p
, BRW_PREDICATE_NONE
);
462 void brw_clip_init_ff_sync(struct brw_clip_compile
*c
)
464 struct brw_codegen
*p
= &c
->func
;
466 if (p
->devinfo
->gen
== 5) {
467 brw_MOV(p
, c
->reg
.ff_sync
, brw_imm_ud(0));