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 /** return pointer to a newly allocated instruction */
55 static struct brw_wm_instruction
*get_instruction( struct brw_wm_compile
*c
)
57 assert(c
->nr_insns
< BRW_WM_MAX_INSN
);
58 return &c
->instruction
[c
->nr_insns
++];
61 /***********************************************************************
64 /** Init the "undef" register */
65 static void pass0_init_undef( struct brw_wm_compile
*c
)
67 struct brw_wm_ref
*ref
= &c
->undef_ref
;
68 ref
->value
= &c
->undef_value
;
69 ref
->hw_reg
= brw_vec8_grf(0, 0);
74 /** Set a FP register to a value */
75 static void pass0_set_fpreg_value( struct brw_wm_compile
*c
,
79 struct brw_wm_value
*value
)
81 struct brw_wm_ref
*ref
= get_ref(c
);
83 ref
->hw_reg
= brw_vec8_grf(0, 0);
86 c
->pass0_fp_reg
[file
][idx
][component
] = ref
;
89 /** Set a FP register to a ref */
90 static void pass0_set_fpreg_ref( struct brw_wm_compile
*c
,
94 const struct brw_wm_ref
*src_ref
)
96 c
->pass0_fp_reg
[file
][idx
][component
] = src_ref
;
99 static const struct brw_wm_ref
*get_param_ref( struct brw_wm_compile
*c
,
100 const GLfloat
*param_ptr
)
102 GLuint i
= c
->prog_data
.nr_params
++;
104 if (i
>= BRW_WM_MAX_PARAM
) {
105 _mesa_printf("%s: out of params\n", __FUNCTION__
);
106 c
->prog_data
.error
= 1;
110 struct brw_wm_ref
*ref
= get_ref(c
);
112 c
->prog_data
.param
[i
] = param_ptr
;
113 c
->nr_creg
= (i
+16)/16;
115 /* Push the offsets into hw_reg. These will be added to the
116 * real register numbers once one is allocated in pass2.
118 ref
->hw_reg
= brw_vec1_grf((i
&8)?1:0, i
%8);
119 ref
->value
= &c
->creg
[i
/16];
128 /** Return a ref to a constant/literal value */
129 static const struct brw_wm_ref
*get_const_ref( struct brw_wm_compile
*c
,
130 const GLfloat
*constval
)
134 /* Search for an existing const value matching the request:
136 for (i
= 0; i
< c
->nr_constrefs
; i
++) {
137 if (c
->constref
[i
].constval
== *constval
)
138 return c
->constref
[i
].ref
;
141 /* Else try to add a new one:
143 if (c
->nr_constrefs
< BRW_WM_MAX_CONST
) {
144 GLuint i
= c
->nr_constrefs
++;
146 /* A constant is a special type of parameter:
148 c
->constref
[i
].constval
= *constval
;
149 c
->constref
[i
].ref
= get_param_ref(c
, constval
);
151 return c
->constref
[i
].ref
;
154 _mesa_printf("%s: out of constrefs\n", __FUNCTION__
);
155 c
->prog_data
.error
= 1;
161 /* Lookup our internal registers
163 static const struct brw_wm_ref
*pass0_get_reg( struct brw_wm_compile
*c
,
168 const struct brw_wm_ref
*ref
= c
->pass0_fp_reg
[file
][idx
][component
];
173 case PROGRAM_PAYLOAD
:
174 case PROGRAM_TEMPORARY
:
176 case PROGRAM_VARYING
:
179 case PROGRAM_LOCAL_PARAM
:
180 ref
= get_param_ref(c
, &c
->fp
->program
.Base
.LocalParams
[idx
][component
]);
183 case PROGRAM_ENV_PARAM
:
184 ref
= get_param_ref(c
, &c
->env_param
[idx
][component
]);
187 case PROGRAM_STATE_VAR
:
188 case PROGRAM_UNIFORM
:
189 case PROGRAM_CONSTANT
:
190 case PROGRAM_NAMED_PARAM
: {
191 struct gl_program_parameter_list
*plist
= c
->fp
->program
.Base
.Parameters
;
193 /* There's something really hokey about parameters parsed in
194 * arb programs - they all end up in here, whether they be
195 * state values, parameters or constants. This duplicates the
196 * structure above & also seems to subvert the limits set for
197 * each type of constant/param.
199 switch (plist
->Parameters
[idx
].Type
) {
200 case PROGRAM_NAMED_PARAM
:
201 case PROGRAM_CONSTANT
:
202 /* These are invarient:
204 ref
= get_const_ref(c
, &plist
->ParameterValues
[idx
][component
]);
207 case PROGRAM_STATE_VAR
:
208 case PROGRAM_UNIFORM
:
209 /* These may change from run to run:
211 ref
= get_param_ref(c
, &plist
->ParameterValues
[idx
][component
] );
226 c
->pass0_fp_reg
[file
][idx
][component
] = ref
;
237 /***********************************************************************
238 * Straight translation to internal instruction format
241 static void pass0_set_dst( struct brw_wm_compile
*c
,
242 struct brw_wm_instruction
*out
,
243 const struct prog_instruction
*inst
,
246 const struct prog_dst_register
*dst
= &inst
->DstReg
;
249 for (i
= 0; i
< 4; i
++) {
250 if (writemask
& (1<<i
)) {
251 out
->dst
[i
] = get_value(c
);
252 pass0_set_fpreg_value(c
, dst
->File
, dst
->Index
, i
, out
->dst
[i
]);
256 out
->writemask
= writemask
;
260 static const struct brw_wm_ref
*get_fp_src_reg_ref( struct brw_wm_compile
*c
,
261 struct prog_src_register src
,
264 GLuint component
= GET_SWZ(src
.Swizzle
,i
);
265 const struct brw_wm_ref
*src_ref
;
266 static const GLfloat const_zero
= 0.0;
267 static const GLfloat const_one
= 1.0;
269 if (component
== SWIZZLE_ZERO
)
270 src_ref
= get_const_ref(c
, &const_zero
);
271 else if (component
== SWIZZLE_ONE
)
272 src_ref
= get_const_ref(c
, &const_one
);
274 src_ref
= pass0_get_reg(c
, src
.File
, src
.Index
, component
);
280 static struct brw_wm_ref
*get_new_ref( struct brw_wm_compile
*c
,
281 struct prog_src_register src
,
283 struct brw_wm_instruction
*insn
)
285 const struct brw_wm_ref
*ref
= get_fp_src_reg_ref(c
, src
, i
);
286 struct brw_wm_ref
*newref
= get_ref(c
);
288 newref
->value
= ref
->value
;
289 newref
->hw_reg
= ref
->hw_reg
;
292 newref
->insn
= insn
- c
->instruction
;
293 newref
->prevuse
= newref
->value
->lastuse
;
294 newref
->value
->lastuse
= newref
;
297 if (src
.Negate
& (1 << i
))
298 newref
->hw_reg
.negate
^= 1;
301 newref
->hw_reg
.negate
= 0;
302 newref
->hw_reg
.abs
= 1;
310 translate_insn(struct brw_wm_compile
*c
,
311 const struct prog_instruction
*inst
)
313 struct brw_wm_instruction
*out
= get_instruction(c
);
314 GLuint writemask
= inst
->DstReg
.WriteMask
;
315 GLuint nr_args
= brw_wm_nr_args(inst
->Opcode
);
318 /* Copy some data out of the instruction
320 out
->opcode
= inst
->Opcode
;
321 out
->saturate
= (inst
->SaturateMode
!= SATURATE_OFF
);
322 out
->tex_unit
= inst
->TexSrcUnit
;
323 out
->tex_idx
= inst
->TexSrcTarget
;
324 out
->tex_shadow
= inst
->TexShadow
;
325 out
->eot
= inst
->Aux
& 1;
326 out
->target
= inst
->Aux
>> 1;
330 for (i
= 0; i
< nr_args
; i
++) {
331 for (j
= 0; j
< 4; j
++) {
332 out
->src
[i
][j
] = get_new_ref(c
, inst
->SrcReg
[i
], j
, out
);
338 pass0_set_dst(c
, out
, inst
, writemask
);
343 /***********************************************************************
344 * Optimize moves and swizzles away:
346 static void pass0_precalc_mov( struct brw_wm_compile
*c
,
347 const struct prog_instruction
*inst
)
349 const struct prog_dst_register
*dst
= &inst
->DstReg
;
350 GLuint writemask
= inst
->DstReg
.WriteMask
;
351 struct brw_wm_ref
*refs
[4];
354 /* Get the effect of a MOV by manipulating our register table:
355 * First get all refs, then assign refs. This ensures that "in-place"
358 * are handled correctly. Previously, these two steps were done in
359 * one loop and the above case was incorrectly handled.
361 for (i
= 0; i
< 4; i
++) {
362 refs
[i
] = get_new_ref(c
, inst
->SrcReg
[0], i
, NULL
);
364 for (i
= 0; i
< 4; i
++) {
365 if (writemask
& (1 << i
)) {
366 pass0_set_fpreg_ref( c
, dst
->File
, dst
->Index
, i
, refs
[i
]);
372 /* Initialize payload "registers".
374 static void pass0_init_payload( struct brw_wm_compile
*c
)
378 for (i
= 0; i
< 4; i
++) {
379 GLuint j
= i
>= c
->key
.nr_depth_regs
? 0 : i
;
380 pass0_set_fpreg_value( c
, PROGRAM_PAYLOAD
, PAYLOAD_DEPTH
, i
,
381 &c
->payload
.depth
[j
] );
385 /* This seems to be an alternative to the INTERP_WPOS stuff I do
388 if (c
->key
.source_depth_reg
)
389 pass0_set_fpreg_value(c
, PROGRAM_INPUT
, FRAG_ATTRIB_WPOS
, 2,
390 &c
->payload
.depth
[c
->key
.source_depth_reg
/2]);
393 for (i
= 0; i
< FRAG_ATTRIB_MAX
; i
++)
394 pass0_set_fpreg_value( c
, PROGRAM_PAYLOAD
, i
, 0,
395 &c
->payload
.input_interp
[i
] );
399 /***********************************************************************
402 * Work forwards to give each calculated value a unique number. Where
403 * an instruction produces duplicate values (eg DP3), all are given
406 * Translate away swizzling and eliminate non-saturating moves.
408 void brw_wm_pass0( struct brw_wm_compile
*c
)
416 pass0_init_payload(c
);
418 for (insn
= 0; insn
< c
->nr_fp_insns
; insn
++) {
419 const struct prog_instruction
*inst
= &c
->prog_instructions
[insn
];
421 /* Optimize away moves, otherwise emit translated instruction:
423 switch (inst
->Opcode
) {
426 if (!inst
->SaturateMode
) {
427 pass0_precalc_mov(c
, inst
);
430 translate_insn(c
, inst
);
434 translate_insn(c
, inst
);
439 if (INTEL_DEBUG
& DEBUG_WM
) {
440 brw_wm_print_program(c
, "pass0");