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 memset(&c
->refs
[c
->nr_refs
], 0, sizeof(*c
->refs
));
46 return &c
->refs
[c
->nr_refs
++];
49 static struct brw_wm_value
*get_value( struct brw_wm_compile
*c
)
51 assert(c
->nr_refs
< BRW_WM_MAX_VREG
);
52 memset(&c
->vreg
[c
->nr_vreg
], 0, sizeof(*c
->vreg
));
53 return &c
->vreg
[c
->nr_vreg
++];
56 /** return pointer to a newly allocated instruction */
57 static struct brw_wm_instruction
*get_instruction( struct brw_wm_compile
*c
)
59 assert(c
->nr_insns
< BRW_WM_MAX_INSN
);
60 memset(&c
->instruction
[c
->nr_insns
], 0, sizeof(*c
->instruction
));
61 return &c
->instruction
[c
->nr_insns
++];
64 /***********************************************************************
67 /** Init the "undef" register */
68 static void pass0_init_undef( struct brw_wm_compile
*c
)
70 struct brw_wm_ref
*ref
= &c
->undef_ref
;
71 ref
->value
= &c
->undef_value
;
72 ref
->hw_reg
= brw_vec8_grf(0, 0);
77 /** Set a FP register to a value */
78 static void pass0_set_fpreg_value( struct brw_wm_compile
*c
,
82 struct brw_wm_value
*value
)
84 struct brw_wm_ref
*ref
= get_ref(c
);
86 ref
->hw_reg
= brw_vec8_grf(0, 0);
89 c
->pass0_fp_reg
[file
][idx
][component
] = ref
;
92 /** Set a FP register to a ref */
93 static void pass0_set_fpreg_ref( struct brw_wm_compile
*c
,
97 const struct brw_wm_ref
*src_ref
)
99 c
->pass0_fp_reg
[file
][idx
][component
] = src_ref
;
102 static const struct brw_wm_ref
*get_param_ref( struct brw_wm_compile
*c
,
103 const GLfloat
*param_ptr
)
105 GLuint i
= c
->prog_data
.nr_params
++;
107 if (i
>= BRW_WM_MAX_PARAM
) {
108 printf("%s: out of params\n", __FUNCTION__
);
109 c
->prog_data
.error
= 1;
113 struct brw_wm_ref
*ref
= get_ref(c
);
115 c
->prog_data
.param
[i
] = param_ptr
;
116 c
->nr_creg
= (i
+16)/16;
118 /* Push the offsets into hw_reg. These will be added to the
119 * real register numbers once one is allocated in pass2.
121 ref
->hw_reg
= brw_vec1_grf((i
&8)?1:0, i
%8);
122 ref
->value
= &c
->creg
[i
/16];
131 /** Return a ref to a constant/literal value */
132 static const struct brw_wm_ref
*get_const_ref( struct brw_wm_compile
*c
,
133 const GLfloat
*constval
)
137 /* Search for an existing const value matching the request:
139 for (i
= 0; i
< c
->nr_constrefs
; i
++) {
140 if (c
->constref
[i
].constval
== *constval
)
141 return c
->constref
[i
].ref
;
144 /* Else try to add a new one:
146 if (c
->nr_constrefs
< BRW_WM_MAX_CONST
) {
147 GLuint i
= c
->nr_constrefs
++;
149 /* A constant is a special type of parameter:
151 c
->constref
[i
].constval
= *constval
;
152 c
->constref
[i
].ref
= get_param_ref(c
, constval
);
154 return c
->constref
[i
].ref
;
157 printf("%s: out of constrefs\n", __FUNCTION__
);
158 c
->prog_data
.error
= 1;
164 /* Lookup our internal registers
166 static const struct brw_wm_ref
*pass0_get_reg( struct brw_wm_compile
*c
,
171 const struct brw_wm_ref
*ref
= c
->pass0_fp_reg
[file
][idx
][component
];
176 case PROGRAM_PAYLOAD
:
177 case PROGRAM_TEMPORARY
:
179 case PROGRAM_VARYING
:
182 case PROGRAM_LOCAL_PARAM
:
183 ref
= get_param_ref(c
, &c
->fp
->program
.Base
.LocalParams
[idx
][component
]);
186 case PROGRAM_ENV_PARAM
:
187 ref
= get_param_ref(c
, &c
->env_param
[idx
][component
]);
190 case PROGRAM_STATE_VAR
:
191 case PROGRAM_UNIFORM
:
192 case PROGRAM_CONSTANT
:
193 case PROGRAM_NAMED_PARAM
: {
194 struct gl_program_parameter_list
*plist
= c
->fp
->program
.Base
.Parameters
;
196 /* There's something really hokey about parameters parsed in
197 * arb programs - they all end up in here, whether they be
198 * state values, parameters or constants. This duplicates the
199 * structure above & also seems to subvert the limits set for
200 * each type of constant/param.
202 switch (plist
->Parameters
[idx
].Type
) {
203 case PROGRAM_NAMED_PARAM
:
204 case PROGRAM_CONSTANT
:
205 /* These are invarient:
207 ref
= get_const_ref(c
, &plist
->ParameterValues
[idx
][component
]);
210 case PROGRAM_STATE_VAR
:
211 case PROGRAM_UNIFORM
:
212 /* These may change from run to run:
214 ref
= get_param_ref(c
, &plist
->ParameterValues
[idx
][component
] );
229 c
->pass0_fp_reg
[file
][idx
][component
] = ref
;
240 /***********************************************************************
241 * Straight translation to internal instruction format
244 static void pass0_set_dst( struct brw_wm_compile
*c
,
245 struct brw_wm_instruction
*out
,
246 const struct prog_instruction
*inst
,
249 const struct prog_dst_register
*dst
= &inst
->DstReg
;
252 for (i
= 0; i
< 4; i
++) {
253 if (writemask
& (1<<i
)) {
254 out
->dst
[i
] = get_value(c
);
255 pass0_set_fpreg_value(c
, dst
->File
, dst
->Index
, i
, out
->dst
[i
]);
259 out
->writemask
= writemask
;
263 static const struct brw_wm_ref
*get_fp_src_reg_ref( struct brw_wm_compile
*c
,
264 struct prog_src_register src
,
267 GLuint component
= GET_SWZ(src
.Swizzle
,i
);
268 const struct brw_wm_ref
*src_ref
;
269 static const GLfloat const_zero
= 0.0;
270 static const GLfloat const_one
= 1.0;
272 if (component
== SWIZZLE_ZERO
)
273 src_ref
= get_const_ref(c
, &const_zero
);
274 else if (component
== SWIZZLE_ONE
)
275 src_ref
= get_const_ref(c
, &const_one
);
277 src_ref
= pass0_get_reg(c
, src
.File
, src
.Index
, component
);
283 static struct brw_wm_ref
*get_new_ref( struct brw_wm_compile
*c
,
284 struct prog_src_register src
,
286 struct brw_wm_instruction
*insn
)
288 const struct brw_wm_ref
*ref
= get_fp_src_reg_ref(c
, src
, i
);
289 struct brw_wm_ref
*newref
= get_ref(c
);
291 newref
->value
= ref
->value
;
292 newref
->hw_reg
= ref
->hw_reg
;
295 newref
->insn
= insn
- c
->instruction
;
296 newref
->prevuse
= newref
->value
->lastuse
;
297 newref
->value
->lastuse
= newref
;
300 if (src
.Negate
& (1 << i
))
301 newref
->hw_reg
.negate
^= 1;
304 newref
->hw_reg
.negate
= 0;
305 newref
->hw_reg
.abs
= 1;
313 translate_insn(struct brw_wm_compile
*c
,
314 const struct prog_instruction
*inst
)
316 struct brw_wm_instruction
*out
= get_instruction(c
);
317 GLuint writemask
= inst
->DstReg
.WriteMask
;
318 GLuint nr_args
= brw_wm_nr_args(inst
->Opcode
);
321 /* Copy some data out of the instruction
323 out
->opcode
= inst
->Opcode
;
324 out
->saturate
= (inst
->SaturateMode
!= SATURATE_OFF
);
325 out
->tex_unit
= inst
->TexSrcUnit
;
326 out
->tex_idx
= inst
->TexSrcTarget
;
327 out
->tex_shadow
= inst
->TexShadow
;
328 out
->eot
= inst
->Aux
& INST_AUX_EOT
;
329 out
->target
= INST_AUX_GET_TARGET(inst
->Aux
);
333 for (i
= 0; i
< nr_args
; i
++) {
334 for (j
= 0; j
< 4; j
++) {
335 out
->src
[i
][j
] = get_new_ref(c
, inst
->SrcReg
[i
], j
, out
);
341 pass0_set_dst(c
, out
, inst
, writemask
);
346 /***********************************************************************
347 * Optimize moves and swizzles away:
349 static void pass0_precalc_mov( struct brw_wm_compile
*c
,
350 const struct prog_instruction
*inst
)
352 const struct prog_dst_register
*dst
= &inst
->DstReg
;
353 GLuint writemask
= inst
->DstReg
.WriteMask
;
354 struct brw_wm_ref
*refs
[4];
357 /* Get the effect of a MOV by manipulating our register table:
358 * First get all refs, then assign refs. This ensures that "in-place"
361 * are handled correctly. Previously, these two steps were done in
362 * one loop and the above case was incorrectly handled.
364 for (i
= 0; i
< 4; i
++) {
365 refs
[i
] = get_new_ref(c
, inst
->SrcReg
[0], i
, NULL
);
367 for (i
= 0; i
< 4; i
++) {
368 if (writemask
& (1 << i
)) {
369 pass0_set_fpreg_ref( c
, dst
->File
, dst
->Index
, i
, refs
[i
]);
375 /* Initialize payload "registers".
377 static void pass0_init_payload( struct brw_wm_compile
*c
)
381 for (i
= 0; i
< 4; i
++) {
382 GLuint j
= i
>= c
->key
.nr_depth_regs
? 0 : i
;
383 pass0_set_fpreg_value( c
, PROGRAM_PAYLOAD
, PAYLOAD_DEPTH
, i
,
384 &c
->payload
.depth
[j
] );
388 /* This seems to be an alternative to the INTERP_WPOS stuff I do
391 if (c
->key
.source_depth_reg
)
392 pass0_set_fpreg_value(c
, PROGRAM_INPUT
, FRAG_ATTRIB_WPOS
, 2,
393 &c
->payload
.depth
[c
->key
.source_depth_reg
/2]);
396 for (i
= 0; i
< FRAG_ATTRIB_MAX
; i
++)
397 pass0_set_fpreg_value( c
, PROGRAM_PAYLOAD
, i
, 0,
398 &c
->payload
.input_interp
[i
] );
402 /***********************************************************************
405 * Work forwards to give each calculated value a unique number. Where
406 * an instruction produces duplicate values (eg DP3), all are given
409 * Translate away swizzling and eliminate non-saturating moves.
411 void brw_wm_pass0( struct brw_wm_compile
*c
)
419 pass0_init_payload(c
);
421 for (insn
= 0; insn
< c
->nr_fp_insns
; insn
++) {
422 const struct prog_instruction
*inst
= &c
->prog_instructions
[insn
];
424 /* Optimize away moves, otherwise emit translated instruction:
426 switch (inst
->Opcode
) {
429 if (!inst
->SaturateMode
) {
430 pass0_precalc_mov(c
, inst
);
433 translate_insn(c
, inst
);
437 translate_insn(c
, inst
);
442 if (INTEL_DEBUG
& DEBUG_WM
) {
443 brw_wm_print_program(c
, "pass0");