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>
33 #include "brw_context.h"
35 #include "shader/prog_parameter.h"
39 /***********************************************************************
42 static struct brw_wm_ref
*get_ref( struct brw_wm_compile
*c
)
44 assert(c
->nr_refs
< BRW_WM_MAX_REF
);
45 return &c
->refs
[c
->nr_refs
++];
48 static struct brw_wm_value
*get_value( struct brw_wm_compile
*c
)
50 assert(c
->nr_refs
< BRW_WM_MAX_VREG
);
51 return &c
->vreg
[c
->nr_vreg
++];
54 static struct brw_wm_instruction
*get_instruction( struct brw_wm_compile
*c
)
56 assert(c
->nr_insns
< BRW_WM_MAX_INSN
);
57 return &c
->instruction
[c
->nr_insns
++];
60 /***********************************************************************
63 static void pass0_init_undef( struct brw_wm_compile
*c
)
65 struct brw_wm_ref
*ref
= &c
->undef_ref
;
66 ref
->value
= &c
->undef_value
;
67 ref
->hw_reg
= brw_vec8_grf(0, 0);
72 static void pass0_set_fpreg_value( struct brw_wm_compile
*c
,
76 struct brw_wm_value
*value
)
78 struct brw_wm_ref
*ref
= get_ref(c
);
80 ref
->hw_reg
= brw_vec8_grf(0, 0);
83 c
->pass0_fp_reg
[file
][idx
][component
] = ref
;
86 static void pass0_set_fpreg_ref( struct brw_wm_compile
*c
,
90 const struct brw_wm_ref
*src_ref
)
92 c
->pass0_fp_reg
[file
][idx
][component
] = src_ref
;
95 static const struct brw_wm_ref
*get_param_ref( struct brw_wm_compile
*c
,
96 const GLfloat
*param_ptr
)
98 GLuint i
= c
->prog_data
.nr_params
++;
100 if (i
>= BRW_WM_MAX_PARAM
) {
101 _mesa_printf("%s: out of params\n", __FUNCTION__
);
102 c
->prog_data
.error
= 1;
106 struct brw_wm_ref
*ref
= get_ref(c
);
108 c
->prog_data
.param
[i
] = param_ptr
;
109 c
->nr_creg
= (i
+16)/16;
111 /* Push the offsets into hw_reg. These will be added to the
112 * real register numbers once one is allocated in pass2.
114 ref
->hw_reg
= brw_vec1_grf((i
&8)?1:0, i
%8);
115 ref
->value
= &c
->creg
[i
/16];
124 static const struct brw_wm_ref
*get_const_ref( struct brw_wm_compile
*c
,
125 const GLfloat
*constval
)
129 /* Search for an existing const value matching the request:
131 for (i
= 0; i
< c
->nr_constrefs
; i
++) {
132 if (c
->constref
[i
].constval
== *constval
)
133 return c
->constref
[i
].ref
;
136 /* Else try to add a new one:
138 if (c
->nr_constrefs
< BRW_WM_MAX_CONST
) {
139 GLuint i
= c
->nr_constrefs
++;
141 /* A constant is a special type of parameter:
143 c
->constref
[i
].constval
= *constval
;
144 c
->constref
[i
].ref
= get_param_ref(c
, constval
);
146 return c
->constref
[i
].ref
;
149 _mesa_printf("%s: out of constrefs\n", __FUNCTION__
);
150 c
->prog_data
.error
= 1;
156 /* Lookup our internal registers
158 static const struct brw_wm_ref
*pass0_get_reg( struct brw_wm_compile
*c
,
163 const struct brw_wm_ref
*ref
= c
->pass0_fp_reg
[file
][idx
][component
];
168 case PROGRAM_PAYLOAD
:
169 case PROGRAM_TEMPORARY
:
171 case PROGRAM_VARYING
:
174 case PROGRAM_LOCAL_PARAM
:
175 ref
= get_param_ref(c
, &c
->fp
->program
.Base
.LocalParams
[idx
][component
]);
178 case PROGRAM_ENV_PARAM
:
179 ref
= get_param_ref(c
, &c
->env_param
[idx
][component
]);
182 case PROGRAM_STATE_VAR
:
183 case PROGRAM_UNIFORM
:
184 case PROGRAM_CONSTANT
:
185 case PROGRAM_NAMED_PARAM
: {
186 struct gl_program_parameter_list
*plist
= c
->fp
->program
.Base
.Parameters
;
188 /* There's something really hokey about parameters parsed in
189 * arb programs - they all end up in here, whether they be
190 * state values, paramters or constants. This duplicates the
191 * structure above & also seems to subvert the limits set for
192 * each type of constant/param.
194 switch (plist
->Parameters
[idx
].Type
) {
195 case PROGRAM_NAMED_PARAM
:
196 case PROGRAM_CONSTANT
:
197 /* These are invarient:
199 ref
= get_const_ref(c
, &plist
->ParameterValues
[idx
][component
]);
202 case PROGRAM_STATE_VAR
:
203 case PROGRAM_UNIFORM
:
204 /* These may change from run to run:
206 ref
= get_param_ref(c
, &plist
->ParameterValues
[idx
][component
] );
221 c
->pass0_fp_reg
[file
][idx
][component
] = ref
;
233 /***********************************************************************
234 * Straight translation to internal instruction format
237 static void pass0_set_dst( struct brw_wm_compile
*c
,
238 struct brw_wm_instruction
*out
,
239 const struct prog_instruction
*inst
,
242 const struct prog_dst_register
*dst
= &inst
->DstReg
;
245 for (i
= 0; i
< 4; i
++) {
246 if (writemask
& (1<<i
)) {
247 out
->dst
[i
] = get_value(c
);
249 pass0_set_fpreg_value(c
, dst
->File
, dst
->Index
, i
, out
->dst
[i
]);
253 out
->writemask
= writemask
;
257 static void pass0_set_dst_scalar( struct brw_wm_compile
*c
,
258 struct brw_wm_instruction
*out
,
259 const struct prog_instruction
*inst
,
263 const struct prog_dst_register
*dst
= &inst
->DstReg
;
266 /* Compute only the first (X) value:
268 out
->writemask
= WRITEMASK_X
;
269 out
->dst
[0] = get_value(c
);
271 /* Update our tracking register file for all the components in
274 for (i
= 0; i
< 4; i
++) {
275 if (writemask
& (1<<i
)) {
276 pass0_set_fpreg_value(c
, dst
->File
, dst
->Index
, i
, out
->dst
[0]);
286 static const struct brw_wm_ref
*get_fp_src_reg_ref( struct brw_wm_compile
*c
,
287 struct prog_src_register src
,
290 GLuint component
= GET_SWZ(src
.Swizzle
,i
);
291 const struct brw_wm_ref
*src_ref
;
292 static const GLfloat const_zero
= 0.0;
293 static const GLfloat const_one
= 1.0;
296 if (component
== SWIZZLE_ZERO
)
297 src_ref
= get_const_ref(c
, &const_zero
);
298 else if (component
== SWIZZLE_ONE
)
299 src_ref
= get_const_ref(c
, &const_one
);
301 src_ref
= pass0_get_reg(c
, src
.File
, src
.Index
, component
);
307 static struct brw_wm_ref
*get_new_ref( struct brw_wm_compile
*c
,
308 struct prog_src_register src
,
310 struct brw_wm_instruction
*insn
)
312 const struct brw_wm_ref
*ref
= get_fp_src_reg_ref(c
, src
, i
);
313 struct brw_wm_ref
*newref
= get_ref(c
);
315 newref
->value
= ref
->value
;
316 newref
->hw_reg
= ref
->hw_reg
;
319 newref
->insn
= insn
- c
->instruction
;
320 newref
->prevuse
= newref
->value
->lastuse
;
321 newref
->value
->lastuse
= newref
;
324 if (src
.NegateBase
& (1<<i
))
325 newref
->hw_reg
.negate
^= 1;
328 newref
->hw_reg
.negate
= 0;
329 newref
->hw_reg
.abs
= 1;
337 static struct brw_wm_instruction
*translate_insn( struct brw_wm_compile
*c
,
338 const struct prog_instruction
*inst
)
340 struct brw_wm_instruction
*out
= get_instruction(c
);
341 GLuint writemask
= inst
->DstReg
.WriteMask
;
342 GLuint nr_args
= brw_wm_nr_args(inst
->Opcode
);
345 /* Copy some data out of the instruction
347 out
->opcode
= inst
->Opcode
;
348 out
->saturate
= (inst
->SaturateMode
!= SATURATE_OFF
);
349 out
->tex_unit
= inst
->TexSrcUnit
;
350 out
->tex_idx
= inst
->TexSrcTarget
;
351 out
->eot
= inst
->Sampler
& 1;
352 out
->target
= inst
->Sampler
>>1;
356 for (i
= 0; i
< nr_args
; i
++) {
357 for (j
= 0; j
< 4; j
++) {
358 out
->src
[i
][j
] = get_new_ref(c
, inst
->SrcReg
[i
], j
, out
);
364 if (brw_wm_is_scalar_result(out
->opcode
))
365 pass0_set_dst_scalar(c
, out
, inst
, writemask
);
367 pass0_set_dst(c
, out
, inst
, writemask
);
374 /***********************************************************************
375 * Optimize moves and swizzles away:
377 static void pass0_precalc_mov( struct brw_wm_compile
*c
,
378 const struct prog_instruction
*inst
)
380 const struct prog_dst_register
*dst
= &inst
->DstReg
;
381 GLuint writemask
= inst
->DstReg
.WriteMask
;
384 /* Get the effect of a MOV by manipulating our register table:
386 for (i
= 0; i
< 4; i
++) {
387 if (writemask
& (1<<i
)) {
388 pass0_set_fpreg_ref( c
, dst
->File
, dst
->Index
, i
,
389 get_new_ref(c
, inst
->SrcReg
[0], i
, NULL
));
395 /* Initialize payload "registers".
397 static void pass0_init_payload( struct brw_wm_compile
*c
)
401 for (i
= 0; i
< 4; i
++) {
402 GLuint j
= i
>= c
->key
.nr_depth_regs
? 0 : i
;
403 pass0_set_fpreg_value( c
, PROGRAM_PAYLOAD
, PAYLOAD_DEPTH
, i
,
404 &c
->payload
.depth
[j
] );
408 /* This seems to be an alternative to the INTERP_WPOS stuff I do
411 if (c
->key
.source_depth_reg
)
412 pass0_set_fpreg_value(c
, PROGRAM_INPUT
, FRAG_ATTRIB_WPOS
, 2,
413 &c
->payload
.depth
[c
->key
.source_depth_reg
/2]);
416 for (i
= 0; i
< FRAG_ATTRIB_MAX
; i
++)
417 pass0_set_fpreg_value( c
, PROGRAM_PAYLOAD
, i
, 0,
418 &c
->payload
.input_interp
[i
] );
421 /***********************************************************************
424 * Work forwards to give each calculated value a unique number. Where
425 * an instruction produces duplicate values (eg DP3), all are given
428 * Translate away swizzling and eliminate non-saturating moves.
430 void brw_wm_pass0( struct brw_wm_compile
*c
)
438 pass0_init_payload(c
);
440 for (insn
= 0; insn
< c
->nr_fp_insns
; insn
++) {
441 const struct prog_instruction
*inst
= &c
->prog_instructions
[insn
];
444 /* Optimize away moves, otherwise emit translated instruction:
446 switch (inst
->Opcode
) {
449 if (!inst
->SaturateMode
) {
450 pass0_precalc_mov(c
, inst
);
453 translate_insn(c
, inst
);
459 translate_insn(c
, inst
);
464 if (INTEL_DEBUG
& DEBUG_WM
) {
465 brw_wm_print_program(c
, "pass0");