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"
36 #include "arbprogparse.h"
37 #include "program_instruction.h"
41 /***********************************************************************
44 static struct brw_wm_ref
*get_ref( struct brw_wm_compile
*c
)
46 assert(c
->nr_refs
< BRW_WM_MAX_REF
);
47 return &c
->refs
[c
->nr_refs
++];
50 static struct brw_wm_value
*get_value( struct brw_wm_compile
*c
)
52 assert(c
->nr_refs
< BRW_WM_MAX_VREG
);
53 return &c
->vreg
[c
->nr_vreg
++];
56 static struct brw_wm_instruction
*get_instruction( struct brw_wm_compile
*c
)
58 assert(c
->nr_insns
< BRW_WM_MAX_INSN
);
59 return &c
->instruction
[c
->nr_insns
++];
62 /***********************************************************************
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 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 static void pass0_set_fpreg_ref( struct brw_wm_compile
*c
,
92 const struct brw_wm_ref
*src_ref
)
94 c
->pass0_fp_reg
[file
][idx
][component
] = src_ref
;
97 static const struct brw_wm_ref
*get_param_ref( struct brw_wm_compile
*c
,
98 const GLfloat
*param_ptr
)
100 GLuint i
= c
->prog_data
.nr_params
++;
102 if (i
>= BRW_WM_MAX_PARAM
) {
103 _mesa_printf("%s: out of params\n", __FUNCTION__
);
104 c
->prog_data
.error
= 1;
108 struct brw_wm_ref
*ref
= get_ref(c
);
110 c
->prog_data
.param
[i
] = param_ptr
;
111 c
->nr_creg
= (i
+16)/16;
113 /* Push the offsets into hw_reg. These will be added to the
114 * real register numbers once one is allocated in pass2.
116 ref
->hw_reg
= brw_vec1_grf((i
&8)?1:0, i
%8);
117 ref
->value
= &c
->creg
[i
/16];
126 static const struct brw_wm_ref
*get_const_ref( struct brw_wm_compile
*c
,
127 const GLfloat
*constval
)
131 /* Search for an existing const value matching the request:
133 for (i
= 0; i
< c
->nr_constrefs
; i
++) {
134 if (c
->constref
[i
].constval
== *constval
)
135 return c
->constref
[i
].ref
;
138 /* Else try to add a new one:
140 if (c
->nr_constrefs
< BRW_WM_MAX_CONST
) {
141 GLuint i
= c
->nr_constrefs
++;
143 /* A constant is a special type of parameter:
145 c
->constref
[i
].constval
= *constval
;
146 c
->constref
[i
].ref
= get_param_ref(c
, constval
);
148 return c
->constref
[i
].ref
;
151 _mesa_printf("%s: out of constrefs\n", __FUNCTION__
);
152 c
->prog_data
.error
= 1;
158 /* Lookup our internal registers
160 static const struct brw_wm_ref
*pass0_get_reg( struct brw_wm_compile
*c
,
165 const struct brw_wm_ref
*ref
= c
->pass0_fp_reg
[file
][idx
][component
];
170 case PROGRAM_PAYLOAD
:
171 case PROGRAM_TEMPORARY
:
175 case PROGRAM_LOCAL_PARAM
:
176 ref
= get_param_ref(c
, &c
->fp
->program
.Base
.LocalParams
[idx
][component
]);
179 case PROGRAM_ENV_PARAM
:
180 ref
= get_param_ref(c
, &c
->env_param
[idx
][component
]);
183 case PROGRAM_STATE_VAR
:
184 case PROGRAM_NAMED_PARAM
: {
185 struct gl_program_parameter_list
*plist
= c
->fp
->program
.Base
.Parameters
;
187 /* There's something really hokey about parameters parsed in
188 * arb programs - they all end up in here, whether they be
189 * state values, paramters or constants. This duplicates the
190 * structure above & also seems to subvert the limits set for
191 * each type of constant/param.
193 switch (plist
->Parameters
[idx
].Type
) {
194 case PROGRAM_NAMED_PARAM
:
195 case PROGRAM_CONSTANT
:
196 /* These are invarient:
198 ref
= get_const_ref(c
, &plist
->ParameterValues
[idx
][component
]);
201 case PROGRAM_STATE_VAR
:
202 /* These may change from run to run:
204 ref
= get_param_ref(c
, &plist
->ParameterValues
[idx
][component
] );
219 c
->pass0_fp_reg
[file
][idx
][component
] = ref
;
231 /***********************************************************************
232 * Straight translation to internal instruction format
235 static void pass0_set_dst( struct brw_wm_compile
*c
,
236 struct brw_wm_instruction
*out
,
237 const struct prog_instruction
*inst
,
240 const struct prog_dst_register
*dst
= &inst
->DstReg
;
243 for (i
= 0; i
< 4; i
++) {
244 if (writemask
& (1<<i
)) {
245 out
->dst
[i
] = get_value(c
);
247 pass0_set_fpreg_value(c
, dst
->File
, dst
->Index
, i
, out
->dst
[i
]);
251 out
->writemask
= writemask
;
255 static void pass0_set_dst_scalar( struct brw_wm_compile
*c
,
256 struct brw_wm_instruction
*out
,
257 const struct prog_instruction
*inst
,
261 const struct prog_dst_register
*dst
= &inst
->DstReg
;
264 /* Compute only the first (X) value:
266 out
->writemask
= WRITEMASK_X
;
267 out
->dst
[0] = get_value(c
);
269 /* Update our tracking register file for all the components in
272 for (i
= 0; i
< 4; i
++) {
273 if (writemask
& (1<<i
)) {
274 pass0_set_fpreg_value(c
, dst
->File
, dst
->Index
, i
, out
->dst
[0]);
284 static const struct brw_wm_ref
*get_fp_src_reg_ref( struct brw_wm_compile
*c
,
285 struct prog_src_register src
,
288 GLuint component
= GET_SWZ(src
.Swizzle
,i
);
289 const struct brw_wm_ref
*src_ref
;
290 static const GLfloat const_zero
= 0.0;
291 static const GLfloat const_one
= 1.0;
294 if (component
== SWIZZLE_ZERO
)
295 src_ref
= get_const_ref(c
, &const_zero
);
296 else if (component
== SWIZZLE_ONE
)
297 src_ref
= get_const_ref(c
, &const_one
);
299 src_ref
= pass0_get_reg(c
, src
.File
, src
.Index
, component
);
305 static struct brw_wm_ref
*get_new_ref( struct brw_wm_compile
*c
,
306 struct prog_src_register src
,
308 struct brw_wm_instruction
*insn
)
310 const struct brw_wm_ref
*ref
= get_fp_src_reg_ref(c
, src
, i
);
311 struct brw_wm_ref
*newref
= get_ref(c
);
313 newref
->value
= ref
->value
;
314 newref
->hw_reg
= ref
->hw_reg
;
317 newref
->insn
= insn
- c
->instruction
;
318 newref
->prevuse
= newref
->value
->lastuse
;
319 newref
->value
->lastuse
= newref
;
322 if (src
.NegateBase
& (1<<i
))
323 newref
->hw_reg
.negate
^= 1;
326 newref
->hw_reg
.negate
= 0;
327 newref
->hw_reg
.abs
= 1;
335 static struct brw_wm_instruction
*translate_insn( struct brw_wm_compile
*c
,
336 const struct prog_instruction
*inst
)
338 struct brw_wm_instruction
*out
= get_instruction(c
);
339 GLuint writemask
= inst
->DstReg
.WriteMask
;
340 GLuint nr_args
= brw_wm_nr_args(inst
->Opcode
);
343 /* Copy some data out of the instruction
345 out
->opcode
= inst
->Opcode
;
346 out
->saturate
= (inst
->SaturateMode
!= SATURATE_OFF
);
347 out
->tex_unit
= inst
->TexSrcUnit
;
348 out
->tex_idx
= inst
->TexSrcTarget
;
352 for (i
= 0; i
< nr_args
; i
++) {
353 for (j
= 0; j
< 4; j
++) {
354 out
->src
[i
][j
] = get_new_ref(c
, inst
->SrcReg
[i
], j
, out
);
360 if (brw_wm_is_scalar_result(out
->opcode
))
361 pass0_set_dst_scalar(c
, out
, inst
, writemask
);
363 pass0_set_dst(c
, out
, inst
, writemask
);
370 /***********************************************************************
371 * Optimize moves and swizzles away:
373 static void pass0_precalc_mov( struct brw_wm_compile
*c
,
374 const struct prog_instruction
*inst
)
376 const struct prog_dst_register
*dst
= &inst
->DstReg
;
377 GLuint writemask
= inst
->DstReg
.WriteMask
;
380 /* Get the effect of a MOV by manipulating our register table:
382 for (i
= 0; i
< 4; i
++) {
383 if (writemask
& (1<<i
)) {
384 pass0_set_fpreg_ref( c
, dst
->File
, dst
->Index
, i
,
385 get_new_ref(c
, inst
->SrcReg
[0], i
, NULL
));
391 /* Initialize payload "registers".
393 static void pass0_init_payload( struct brw_wm_compile
*c
)
397 for (i
= 0; i
< 4; i
++) {
398 GLuint j
= i
>= c
->key
.nr_depth_regs
? 0 : i
;
399 pass0_set_fpreg_value( c
, PROGRAM_PAYLOAD
, PAYLOAD_DEPTH
, i
,
400 &c
->payload
.depth
[j
] );
404 /* This seems to be an alternative to the INTERP_WPOS stuff I do
407 if (c
->key
.source_depth_reg
)
408 pass0_set_fpreg_value(c
, PROGRAM_INPUT
, FRAG_ATTRIB_WPOS
, 2,
409 &c
->payload
.depth
[c
->key
.source_depth_reg
/2]);
412 for (i
= 0; i
< FRAG_ATTRIB_MAX
; i
++)
413 pass0_set_fpreg_value( c
, PROGRAM_PAYLOAD
, i
, 0,
414 &c
->payload
.input_interp
[i
] );
417 /***********************************************************************
420 * Work forwards to give each calculated value a unique number. Where
421 * an instruction produces duplicate values (eg DP3), all are given
424 * Translate away swizzling and eliminate non-saturating moves.
426 void brw_wm_pass0( struct brw_wm_compile
*c
)
434 pass0_init_payload(c
);
436 for (insn
= 0; insn
< c
->nr_fp_insns
; insn
++) {
437 const struct prog_instruction
*inst
= &c
->prog_instructions
[insn
];
440 /* Optimize away moves, otherwise emit translated instruction:
442 switch (inst
->Opcode
) {
445 if (!inst
->SaturateMode
) {
446 pass0_precalc_mov(c
, inst
);
449 translate_insn(c
, inst
);
455 translate_insn(c
, inst
);
460 if (INTEL_DEBUG
& DEBUG_WM
) {
461 brw_wm_print_program(c
, "pass0");