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->ver == 5 || p->devinfo->verx10 == 45)
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->ver == 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->ver == 5) {
467
brw_MOV(p, c->reg.ff_sync, brw_imm_ud(0));