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"
38 /***********************************************************************
41 static struct brw_wm_ref
*get_ref( struct brw_wm_compile
*c
)
43 assert(c
->nr_refs
< BRW_WM_MAX_REF
);
44 return &c
->refs
[c
->nr_refs
++];
47 static struct brw_wm_value
*get_value( struct brw_wm_compile
*c
)
49 assert(c
->nr_refs
< BRW_WM_MAX_VREG
);
50 return &c
->vreg
[c
->nr_vreg
++];
53 /** return pointer to a newly allocated instruction */
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 /** Init the "undef" register */
64 static void pass0_init_undef( struct brw_wm_compile
*c
)
66 struct brw_wm_ref
*ref
= &c
->undef_ref
;
67 ref
->value
= &c
->undef_value
;
68 ref
->hw_reg
= brw_vec8_grf(0, 0);
73 /** Set a FP register to a value */
74 static void pass0_set_fpreg_value( struct brw_wm_compile
*c
,
78 struct brw_wm_value
*value
)
80 struct brw_wm_ref
*ref
= get_ref(c
);
82 ref
->hw_reg
= brw_vec8_grf(0, 0);
85 c
->pass0_fp_reg
[file
][idx
][component
] = ref
;
88 /** Set a FP register to a ref */
89 static void pass0_set_fpreg_ref( struct brw_wm_compile
*c
,
93 const struct brw_wm_ref
*src_ref
)
95 c
->pass0_fp_reg
[file
][idx
][component
] = src_ref
;
98 static const struct brw_wm_ref
*get_param_ref( struct brw_wm_compile
*c
,
99 const GLfloat
*param_ptr
)
101 GLuint i
= c
->prog_data
.nr_params
++;
103 if (i
>= BRW_WM_MAX_PARAM
) {
104 debug_printf("%s: out of params\n", __FUNCTION__
);
105 c
->prog_data
.error
= 1;
109 struct brw_wm_ref
*ref
= get_ref(c
);
111 c
->prog_data
.param
[i
] = param_ptr
;
112 c
->nr_creg
= (i
+16)/16;
114 /* Push the offsets into hw_reg. These will be added to the
115 * real register numbers once one is allocated in pass2.
117 ref
->hw_reg
= brw_vec1_grf((i
&8)?1:0, i
%8);
118 ref
->value
= &c
->creg
[i
/16];
127 /** Return a ref to an immediate value */
128 static const struct brw_wm_ref
*get_imm_ref( struct brw_wm_compile
*c
,
129 const GLfloat
*imm1f
)
133 /* Search for an existing const value matching the request:
135 for (i
= 0; i
< c
->nr_imm_refs
; i
++) {
136 if (c
->imm_ref
[i
].imm_val
== *imm1f
)
137 return c
->imm_ref
[i
].ref
;
140 /* Else try to add a new one:
142 if (c
->nr_imm_refs
< BRW_WM_MAX_IMM
) {
143 GLuint i
= c
->nr_imm_refs
++;
145 /* An immediate is a special type of parameter:
147 c
->imm_ref
[i
].imm_val
= *imm_val
;
148 c
->imm_ref
[i
].ref
= get_param_ref(c
, imm_val
);
150 return c
->imm_ref
[i
].ref
;
153 debug_printf("%s: out of imm_refs\n", __FUNCTION__
);
154 c
->prog_data
.error
= 1;
160 /* Lookup our internal registers
162 static const struct brw_wm_ref
*pass0_get_reg( struct brw_wm_compile
*c
,
167 const struct brw_wm_ref
*ref
= c
->pass0_fp_reg
[file
][idx
][component
];
172 case PROGRAM_PAYLOAD
:
173 case PROGRAM_TEMPORARY
:
175 case PROGRAM_VARYING
:
178 case PROGRAM_LOCAL_PARAM
:
179 ref
= get_param_ref(c
, &c
->fp
->program
.Base
.LocalParams
[idx
][component
]);
182 case PROGRAM_ENV_PARAM
:
183 ref
= get_param_ref(c
, &c
->env_param
[idx
][component
]);
186 case PROGRAM_STATE_VAR
:
187 case PROGRAM_UNIFORM
:
188 case PROGRAM_CONSTANT
:
189 case PROGRAM_NAMED_PARAM
: {
190 struct gl_program_parameter_list
*plist
= c
->fp
->program
.Base
.Parameters
;
192 /* There's something really hokey about parameters parsed in
193 * arb programs - they all end up in here, whether they be
194 * state values, parameters or constants. This duplicates the
195 * structure above & also seems to subvert the limits set for
196 * each type of constant/param.
198 switch (plist
->Parameters
[idx
].Type
) {
199 case PROGRAM_NAMED_PARAM
:
200 case PROGRAM_CONSTANT
:
201 /* These are invarient:
203 ref
= get_imm_ref(c
, &plist
->ParameterValues
[idx
][component
]);
206 case PROGRAM_STATE_VAR
:
207 case PROGRAM_UNIFORM
:
208 /* These may change from run to run:
210 ref
= get_param_ref(c
, &plist
->ParameterValues
[idx
][component
] );
225 c
->pass0_fp_reg
[file
][idx
][component
] = ref
;
236 /***********************************************************************
237 * Straight translation to internal instruction format
240 static void pass0_set_dst( struct brw_wm_compile
*c
,
241 struct brw_wm_instruction
*out
,
242 const struct prog_instruction
*inst
,
245 const struct prog_dst_register
*dst
= &inst
->DstReg
;
248 for (i
= 0; i
< 4; i
++) {
249 if (writemask
& (1<<i
)) {
250 out
->dst
[i
] = get_value(c
);
251 pass0_set_fpreg_value(c
, dst
->File
, dst
->Index
, i
, out
->dst
[i
]);
255 out
->writemask
= writemask
;
259 static const struct brw_wm_ref
*get_fp_src_reg_ref( struct brw_wm_compile
*c
,
260 struct prog_src_register src
,
263 GLuint component
= GET_SWZ(src
.Swizzle
,i
);
264 const struct brw_wm_ref
*src_ref
;
265 static const GLfloat const_zero
= 0.0;
266 static const GLfloat const_one
= 1.0;
268 if (component
== SWIZZLE_ZERO
)
269 src_ref
= get_imm_ref(c
, &const_zero
);
270 else if (component
== SWIZZLE_ONE
)
271 src_ref
= get_imm_ref(c
, &const_one
);
273 src_ref
= pass0_get_reg(c
, src
.File
, src
.Index
, component
);
279 static struct brw_wm_ref
*get_new_ref( struct brw_wm_compile
*c
,
280 struct prog_src_register src
,
282 struct brw_wm_instruction
*insn
)
284 const struct brw_wm_ref
*ref
= get_fp_src_reg_ref(c
, src
, i
);
285 struct brw_wm_ref
*newref
= get_ref(c
);
287 newref
->value
= ref
->value
;
288 newref
->hw_reg
= ref
->hw_reg
;
291 newref
->insn
= insn
- c
->instruction
;
292 newref
->prevuse
= newref
->value
->lastuse
;
293 newref
->value
->lastuse
= newref
;
296 if (src
.Negate
& (1 << i
))
297 newref
->hw_reg
.negate
^= 1;
300 newref
->hw_reg
.negate
= 0;
301 newref
->hw_reg
.abs
= 1;
309 translate_insn(struct brw_wm_compile
*c
,
310 const struct prog_instruction
*inst
)
312 struct brw_wm_instruction
*out
= get_instruction(c
);
313 GLuint writemask
= inst
->DstReg
.WriteMask
;
314 GLuint nr_args
= brw_wm_nr_args(inst
->Opcode
);
317 /* Copy some data out of the instruction
319 out
->opcode
= inst
->Opcode
;
320 out
->saturate
= (inst
->SaturateMode
!= SATURATE_OFF
);
321 out
->tex_unit
= inst
->TexSrcUnit
;
322 out
->tex_idx
= inst
->TexSrcTarget
;
323 out
->tex_shadow
= inst
->TexShadow
;
324 out
->eot
= inst
->Aux
& 1;
325 out
->target
= inst
->Aux
>> 1;
329 for (i
= 0; i
< nr_args
; i
++) {
330 for (j
= 0; j
< 4; j
++) {
331 out
->src
[i
][j
] = get_new_ref(c
, inst
->SrcReg
[i
], j
, out
);
337 pass0_set_dst(c
, out
, inst
, writemask
);
342 /***********************************************************************
343 * Optimize moves and swizzles away:
345 static void pass0_precalc_mov( struct brw_wm_compile
*c
,
346 const struct prog_instruction
*inst
)
348 const struct prog_dst_register
*dst
= &inst
->DstReg
;
349 GLuint writemask
= inst
->DstReg
.WriteMask
;
350 struct brw_wm_ref
*refs
[4];
353 /* Get the effect of a MOV by manipulating our register table:
354 * First get all refs, then assign refs. This ensures that "in-place"
357 * are handled correctly. Previously, these two steps were done in
358 * one loop and the above case was incorrectly handled.
360 for (i
= 0; i
< 4; i
++) {
361 refs
[i
] = get_new_ref(c
, inst
->SrcReg
[0], i
, NULL
);
363 for (i
= 0; i
< 4; i
++) {
364 if (writemask
& (1 << i
)) {
365 pass0_set_fpreg_ref( c
, dst
->File
, dst
->Index
, i
, refs
[i
]);
371 /* Initialize payload "registers".
373 static void pass0_init_payload( struct brw_wm_compile
*c
)
377 for (i
= 0; i
< 4; i
++) {
378 GLuint j
= i
>= c
->key
.nr_depth_regs
? 0 : i
;
379 pass0_set_fpreg_value( c
, PROGRAM_PAYLOAD
, PAYLOAD_DEPTH
, i
,
380 &c
->payload
.depth
[j
] );
384 /* This seems to be an alternative to the INTERP_WPOS stuff I do
387 if (c
->key
.source_depth_reg
)
388 pass0_set_fpreg_value(c
, PROGRAM_INPUT
, FRAG_ATTRIB_WPOS
, 2,
389 &c
->payload
.depth
[c
->key
.source_depth_reg
/2]);
392 for (i
= 0; i
< FRAG_ATTRIB_MAX
; i
++)
393 pass0_set_fpreg_value( c
, PROGRAM_PAYLOAD
, i
, 0,
394 &c
->payload
.input_interp
[i
] );
398 /***********************************************************************
401 * Work forwards to give each calculated value a unique number. Where
402 * an instruction produces duplicate values (eg DP3), all are given
405 * Translate away swizzling and eliminate non-saturating moves.
407 void brw_wm_pass0( struct brw_wm_compile
*c
)
415 pass0_init_payload(c
);
417 for (insn
= 0; insn
< c
->nr_fp_insns
; insn
++) {
418 const struct prog_instruction
*inst
= &c
->prog_instructions
[insn
];
420 /* Optimize away moves, otherwise emit translated instruction:
422 switch (inst
->Opcode
) {
424 if (!inst
->SaturateMode
) {
425 pass0_precalc_mov(c
, inst
);
428 translate_insn(c
, inst
);
432 translate_insn(c
, inst
);
437 if (BRW_DEBUG
& DEBUG_WM
) {
438 brw_wm_print_program(c
, "pass0");