i965: Make the old VS backend record pull constant references in pull_params[].
[mesa.git] / src / mesa / drivers / dri / i965 / brw_wm_pass0.c
1 /*
2 Copyright (C) Intel Corp. 2006. All Rights Reserved.
3 Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to
4 develop this 3D driver.
5
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:
13
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.
17
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.
25
26 **********************************************************************/
27 /*
28 * Authors:
29 * Keith Whitwell <keith@tungstengraphics.com>
30 */
31
32
33 #include "brw_context.h"
34 #include "brw_wm.h"
35 #include "program/prog_parameter.h"
36
37
38
39 /***********************************************************************
40 */
41
42 static struct brw_wm_ref *get_ref( struct brw_wm_compile *c )
43 {
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++];
47 }
48
49 static struct brw_wm_value *get_value( struct brw_wm_compile *c)
50 {
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++];
54 }
55
56 /** return pointer to a newly allocated instruction */
57 static struct brw_wm_instruction *get_instruction( struct brw_wm_compile *c )
58 {
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++];
62 }
63
64 /***********************************************************************
65 */
66
67 /** Init the "undef" register */
68 static void pass0_init_undef( struct brw_wm_compile *c)
69 {
70 struct brw_wm_ref *ref = &c->undef_ref;
71 ref->value = &c->undef_value;
72 ref->hw_reg = brw_vec8_grf(0, 0);
73 ref->insn = 0;
74 ref->prevuse = NULL;
75 }
76
77 /** Set a FP register to a value */
78 static void pass0_set_fpreg_value( struct brw_wm_compile *c,
79 GLuint file,
80 GLuint idx,
81 GLuint component,
82 struct brw_wm_value *value )
83 {
84 struct brw_wm_ref *ref = get_ref(c);
85 ref->value = value;
86 ref->hw_reg = brw_vec8_grf(0, 0);
87 ref->insn = 0;
88 ref->prevuse = NULL;
89 c->pass0_fp_reg[file][idx][component] = ref;
90 }
91
92 /** Set a FP register to a ref */
93 static void pass0_set_fpreg_ref( struct brw_wm_compile *c,
94 GLuint file,
95 GLuint idx,
96 GLuint component,
97 const struct brw_wm_ref *src_ref )
98 {
99 c->pass0_fp_reg[file][idx][component] = src_ref;
100 }
101
102 static const struct brw_wm_ref *get_param_ref( struct brw_wm_compile *c,
103 const GLfloat *param_ptr )
104 {
105 GLuint i = c->prog_data.nr_params++;
106
107 if (i >= BRW_WM_MAX_PARAM) {
108 printf("%s: out of params\n", __FUNCTION__);
109 c->prog_data.error = 1;
110 return NULL;
111 }
112 else {
113 struct brw_wm_ref *ref = get_ref(c);
114
115 c->prog_data.param[i] = param_ptr;
116 c->prog_data.param_convert[i] = PARAM_NO_CONVERT;
117 c->nr_creg = (i+16)/16;
118
119 /* Push the offsets into hw_reg. These will be added to the
120 * real register numbers once one is allocated in pass2.
121 */
122 ref->hw_reg = brw_vec1_grf((i&8)?1:0, i%8);
123 ref->value = &c->creg[i/16];
124 ref->insn = 0;
125 ref->prevuse = NULL;
126
127 return ref;
128 }
129 }
130
131
132 /** Return a ref to a constant/literal value */
133 static const struct brw_wm_ref *get_const_ref( struct brw_wm_compile *c,
134 const GLfloat *constval )
135 {
136 GLuint i;
137
138 /* Search for an existing const value matching the request:
139 */
140 for (i = 0; i < c->nr_constrefs; i++) {
141 if (c->constref[i].constval == *constval)
142 return c->constref[i].ref;
143 }
144
145 /* Else try to add a new one:
146 */
147 if (c->nr_constrefs < BRW_WM_MAX_CONST) {
148 GLuint i = c->nr_constrefs++;
149
150 /* A constant is a special type of parameter:
151 */
152 c->constref[i].constval = *constval;
153 c->constref[i].ref = get_param_ref(c, constval);
154
155 return c->constref[i].ref;
156 }
157 else {
158 printf("%s: out of constrefs\n", __FUNCTION__);
159 c->prog_data.error = 1;
160 return NULL;
161 }
162 }
163
164
165 /* Lookup our internal registers
166 */
167 static const struct brw_wm_ref *pass0_get_reg( struct brw_wm_compile *c,
168 GLuint file,
169 GLuint idx,
170 GLuint component )
171 {
172 const struct brw_wm_ref *ref = c->pass0_fp_reg[file][idx][component];
173
174 if (!ref) {
175 switch (file) {
176 case PROGRAM_INPUT:
177 case PROGRAM_PAYLOAD:
178 case PROGRAM_TEMPORARY:
179 case PROGRAM_OUTPUT:
180 case PROGRAM_VARYING:
181 break;
182
183 case PROGRAM_LOCAL_PARAM:
184 ref = get_param_ref(c, &c->fp->program.Base.LocalParams[idx][component]);
185 break;
186
187 case PROGRAM_ENV_PARAM:
188 ref = get_param_ref(c, &c->env_param[idx][component]);
189 break;
190
191 case PROGRAM_STATE_VAR:
192 case PROGRAM_UNIFORM:
193 case PROGRAM_CONSTANT:
194 case PROGRAM_NAMED_PARAM: {
195 struct gl_program_parameter_list *plist = c->fp->program.Base.Parameters;
196
197 /* There's something really hokey about parameters parsed in
198 * arb programs - they all end up in here, whether they be
199 * state values, parameters or constants. This duplicates the
200 * structure above & also seems to subvert the limits set for
201 * each type of constant/param.
202 */
203 switch (plist->Parameters[idx].Type) {
204 case PROGRAM_NAMED_PARAM:
205 case PROGRAM_CONSTANT:
206 /* These are invarient:
207 */
208 ref = get_const_ref(c, &plist->ParameterValues[idx][component].f);
209 break;
210
211 case PROGRAM_STATE_VAR:
212 case PROGRAM_UNIFORM:
213 /* These may change from run to run:
214 */
215 ref = get_param_ref(c, &plist->ParameterValues[idx][component].f );
216 break;
217
218 default:
219 assert(0);
220 break;
221 }
222 break;
223 }
224
225 default:
226 assert(0);
227 break;
228 }
229
230 c->pass0_fp_reg[file][idx][component] = ref;
231 }
232
233 if (!ref)
234 ref = &c->undef_ref;
235
236 return ref;
237 }
238
239
240
241 /***********************************************************************
242 * Straight translation to internal instruction format
243 */
244
245 static void pass0_set_dst( struct brw_wm_compile *c,
246 struct brw_wm_instruction *out,
247 const struct prog_instruction *inst,
248 GLuint writemask )
249 {
250 const struct prog_dst_register *dst = &inst->DstReg;
251 GLuint i;
252
253 for (i = 0; i < 4; i++) {
254 if (writemask & (1<<i)) {
255 out->dst[i] = get_value(c);
256 pass0_set_fpreg_value(c, dst->File, dst->Index, i, out->dst[i]);
257 }
258 }
259
260 out->writemask = writemask;
261 }
262
263
264 static const struct brw_wm_ref *get_fp_src_reg_ref( struct brw_wm_compile *c,
265 struct prog_src_register src,
266 GLuint i )
267 {
268 GLuint component = GET_SWZ(src.Swizzle,i);
269 const struct brw_wm_ref *src_ref;
270 static const GLfloat const_zero = 0.0;
271 static const GLfloat const_one = 1.0;
272
273 if (component == SWIZZLE_ZERO)
274 src_ref = get_const_ref(c, &const_zero);
275 else if (component == SWIZZLE_ONE)
276 src_ref = get_const_ref(c, &const_one);
277 else
278 src_ref = pass0_get_reg(c, src.File, src.Index, component);
279
280 return src_ref;
281 }
282
283
284 static struct brw_wm_ref *get_new_ref( struct brw_wm_compile *c,
285 struct prog_src_register src,
286 GLuint i,
287 struct brw_wm_instruction *insn)
288 {
289 const struct brw_wm_ref *ref = get_fp_src_reg_ref(c, src, i);
290 struct brw_wm_ref *newref = get_ref(c);
291
292 newref->value = ref->value;
293 newref->hw_reg = ref->hw_reg;
294
295 if (insn) {
296 newref->insn = insn - c->instruction;
297 newref->prevuse = newref->value->lastuse;
298 newref->value->lastuse = newref;
299 }
300
301 if (src.Negate & (1 << i))
302 newref->hw_reg.negate ^= 1;
303
304 if (src.Abs) {
305 newref->hw_reg.negate = 0;
306 newref->hw_reg.abs = 1;
307 }
308
309 return newref;
310 }
311
312
313 static void
314 translate_insn(struct brw_wm_compile *c,
315 const struct prog_instruction *inst)
316 {
317 struct brw_wm_instruction *out = get_instruction(c);
318 GLuint writemask = inst->DstReg.WriteMask;
319 GLuint nr_args = brw_wm_nr_args(inst->Opcode);
320 GLuint i, j;
321
322 /* Copy some data out of the instruction
323 */
324 out->opcode = inst->Opcode;
325 out->saturate = (inst->SaturateMode != SATURATE_OFF);
326 out->tex_unit = inst->TexSrcUnit;
327 out->tex_idx = inst->TexSrcTarget;
328 out->tex_shadow = inst->TexShadow;
329 out->eot = inst->Aux & INST_AUX_EOT;
330 out->target = INST_AUX_GET_TARGET(inst->Aux);
331
332 /* Args:
333 */
334 for (i = 0; i < nr_args; i++) {
335 for (j = 0; j < 4; j++) {
336 out->src[i][j] = get_new_ref(c, inst->SrcReg[i], j, out);
337 }
338 }
339
340 /* Dst:
341 */
342 pass0_set_dst(c, out, inst, writemask);
343 }
344
345
346
347 /***********************************************************************
348 * Optimize moves and swizzles away:
349 */
350 static void pass0_precalc_mov( struct brw_wm_compile *c,
351 const struct prog_instruction *inst )
352 {
353 const struct prog_dst_register *dst = &inst->DstReg;
354 GLuint writemask = inst->DstReg.WriteMask;
355 struct brw_wm_ref *refs[4];
356 GLuint i;
357
358 /* Get the effect of a MOV by manipulating our register table:
359 * First get all refs, then assign refs. This ensures that "in-place"
360 * swizzles such as:
361 * MOV t, t.xxyx
362 * are handled correctly. Previously, these two steps were done in
363 * one loop and the above case was incorrectly handled.
364 */
365 for (i = 0; i < 4; i++) {
366 refs[i] = get_new_ref(c, inst->SrcReg[0], i, NULL);
367 }
368 for (i = 0; i < 4; i++) {
369 if (writemask & (1 << i)) {
370 pass0_set_fpreg_ref( c, dst->File, dst->Index, i, refs[i]);
371 }
372 }
373 }
374
375
376 /* Initialize payload "registers".
377 */
378 static void pass0_init_payload( struct brw_wm_compile *c )
379 {
380 GLuint i;
381
382 for (i = 0; i < 4; i++) {
383 GLuint j = i >= (c->nr_payload_regs + 1) / 2 ? 0 : i;
384 pass0_set_fpreg_value( c, PROGRAM_PAYLOAD, PAYLOAD_DEPTH, i,
385 &c->payload.depth[j] );
386 }
387
388 #if 0
389 /* This seems to be an alternative to the INTERP_WPOS stuff I do
390 * elsewhere:
391 */
392 if (c->key.source_depth_reg)
393 pass0_set_fpreg_value(c, PROGRAM_INPUT, FRAG_ATTRIB_WPOS, 2,
394 &c->payload.depth[c->key.source_depth_reg/2]);
395 #endif
396
397 for (i = 0; i < FRAG_ATTRIB_MAX; i++)
398 pass0_set_fpreg_value( c, PROGRAM_PAYLOAD, i, 0,
399 &c->payload.input_interp[i] );
400 }
401
402
403 /***********************************************************************
404 * PASS 0
405 *
406 * Work forwards to give each calculated value a unique number. Where
407 * an instruction produces duplicate values (eg DP3), all are given
408 * the same number.
409 *
410 * Translate away swizzling and eliminate non-saturating moves.
411 */
412 void brw_wm_pass0( struct brw_wm_compile *c )
413 {
414 GLuint insn;
415
416 c->nr_vreg = 0;
417 c->nr_insns = 0;
418
419 pass0_init_undef(c);
420 pass0_init_payload(c);
421
422 for (insn = 0; insn < c->nr_fp_insns; insn++) {
423 const struct prog_instruction *inst = &c->prog_instructions[insn];
424
425 /* Optimize away moves, otherwise emit translated instruction:
426 */
427 switch (inst->Opcode) {
428 case OPCODE_MOV:
429 case OPCODE_SWZ:
430 if (!inst->SaturateMode) {
431 pass0_precalc_mov(c, inst);
432 }
433 else {
434 translate_insn(c, inst);
435 }
436 break;
437 default:
438 translate_insn(c, inst);
439 break;
440 }
441 }
442
443 if (unlikely(INTEL_DEBUG & DEBUG_WM)) {
444 brw_wm_print_program(c, "pass0");
445 }
446 }