i965g: still working on compilation
[mesa.git] / src / gallium / drivers / 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
36
37
38 /***********************************************************************
39 */
40
41 static struct brw_wm_ref *get_ref( struct brw_wm_compile *c )
42 {
43 assert(c->nr_refs < BRW_WM_MAX_REF);
44 return &c->refs[c->nr_refs++];
45 }
46
47 static struct brw_wm_value *get_value( struct brw_wm_compile *c)
48 {
49 assert(c->nr_refs < BRW_WM_MAX_VREG);
50 return &c->vreg[c->nr_vreg++];
51 }
52
53 /** return pointer to a newly allocated instruction */
54 static struct brw_wm_instruction *get_instruction( struct brw_wm_compile *c )
55 {
56 assert(c->nr_insns < BRW_WM_MAX_INSN);
57 return &c->instruction[c->nr_insns++];
58 }
59
60 /***********************************************************************
61 */
62
63 /** Init the "undef" register */
64 static void pass0_init_undef( struct brw_wm_compile *c)
65 {
66 struct brw_wm_ref *ref = &c->undef_ref;
67 ref->value = &c->undef_value;
68 ref->hw_reg = brw_vec8_grf(0, 0);
69 ref->insn = 0;
70 ref->prevuse = NULL;
71 }
72
73 /** Set a FP register to a value */
74 static void pass0_set_fpreg_value( struct brw_wm_compile *c,
75 GLuint file,
76 GLuint idx,
77 GLuint component,
78 struct brw_wm_value *value )
79 {
80 struct brw_wm_ref *ref = get_ref(c);
81 ref->value = value;
82 ref->hw_reg = brw_vec8_grf(0, 0);
83 ref->insn = 0;
84 ref->prevuse = NULL;
85 c->pass0_fp_reg[file][idx][component] = ref;
86 }
87
88 /** Set a FP register to a ref */
89 static void pass0_set_fpreg_ref( struct brw_wm_compile *c,
90 GLuint file,
91 GLuint idx,
92 GLuint component,
93 const struct brw_wm_ref *src_ref )
94 {
95 c->pass0_fp_reg[file][idx][component] = src_ref;
96 }
97
98 static const struct brw_wm_ref *get_param_ref( struct brw_wm_compile *c,
99 const GLfloat *param_ptr )
100 {
101 GLuint i = c->prog_data.nr_params++;
102
103 if (i >= BRW_WM_MAX_PARAM) {
104 debug_printf("%s: out of params\n", __FUNCTION__);
105 c->prog_data.error = 1;
106 return NULL;
107 }
108 else {
109 struct brw_wm_ref *ref = get_ref(c);
110
111 c->prog_data.param[i] = param_ptr;
112 c->nr_creg = (i+16)/16;
113
114 /* Push the offsets into hw_reg. These will be added to the
115 * real register numbers once one is allocated in pass2.
116 */
117 ref->hw_reg = brw_vec1_grf((i&8)?1:0, i%8);
118 ref->value = &c->creg[i/16];
119 ref->insn = 0;
120 ref->prevuse = NULL;
121
122 return ref;
123 }
124 }
125
126
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 )
130 {
131 GLuint i;
132
133 /* Search for an existing const value matching the request:
134 */
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;
138 }
139
140 /* Else try to add a new one:
141 */
142 if (c->nr_imm_refs < BRW_WM_MAX_IMM) {
143 GLuint i = c->nr_imm_refs++;
144
145 /* An immediate is a special type of parameter:
146 */
147 c->imm_ref[i].imm_val = *imm_val;
148 c->imm_ref[i].ref = get_param_ref(c, imm_val);
149
150 return c->imm_ref[i].ref;
151 }
152 else {
153 debug_printf("%s: out of imm_refs\n", __FUNCTION__);
154 c->prog_data.error = 1;
155 return NULL;
156 }
157 }
158
159
160 /* Lookup our internal registers
161 */
162 static const struct brw_wm_ref *pass0_get_reg( struct brw_wm_compile *c,
163 GLuint file,
164 GLuint idx,
165 GLuint component )
166 {
167 const struct brw_wm_ref *ref = c->pass0_fp_reg[file][idx][component];
168
169 if (!ref) {
170 switch (file) {
171 case PROGRAM_INPUT:
172 case PROGRAM_PAYLOAD:
173 case PROGRAM_TEMPORARY:
174 case PROGRAM_OUTPUT:
175 case PROGRAM_VARYING:
176 break;
177
178 case PROGRAM_LOCAL_PARAM:
179 ref = get_param_ref(c, &c->fp->program.Base.LocalParams[idx][component]);
180 break;
181
182 case PROGRAM_ENV_PARAM:
183 ref = get_param_ref(c, &c->env_param[idx][component]);
184 break;
185
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;
191
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.
197 */
198 switch (plist->Parameters[idx].Type) {
199 case PROGRAM_NAMED_PARAM:
200 case PROGRAM_CONSTANT:
201 /* These are invarient:
202 */
203 ref = get_imm_ref(c, &plist->ParameterValues[idx][component]);
204 break;
205
206 case PROGRAM_STATE_VAR:
207 case PROGRAM_UNIFORM:
208 /* These may change from run to run:
209 */
210 ref = get_param_ref(c, &plist->ParameterValues[idx][component] );
211 break;
212
213 default:
214 assert(0);
215 break;
216 }
217 break;
218 }
219
220 default:
221 assert(0);
222 break;
223 }
224
225 c->pass0_fp_reg[file][idx][component] = ref;
226 }
227
228 if (!ref)
229 ref = &c->undef_ref;
230
231 return ref;
232 }
233
234
235
236 /***********************************************************************
237 * Straight translation to internal instruction format
238 */
239
240 static void pass0_set_dst( struct brw_wm_compile *c,
241 struct brw_wm_instruction *out,
242 const struct prog_instruction *inst,
243 GLuint writemask )
244 {
245 const struct prog_dst_register *dst = &inst->DstReg;
246 GLuint i;
247
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]);
252 }
253 }
254
255 out->writemask = writemask;
256 }
257
258
259 static const struct brw_wm_ref *get_fp_src_reg_ref( struct brw_wm_compile *c,
260 struct prog_src_register src,
261 GLuint i )
262 {
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;
267
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);
272 else
273 src_ref = pass0_get_reg(c, src.File, src.Index, component);
274
275 return src_ref;
276 }
277
278
279 static struct brw_wm_ref *get_new_ref( struct brw_wm_compile *c,
280 struct prog_src_register src,
281 GLuint i,
282 struct brw_wm_instruction *insn)
283 {
284 const struct brw_wm_ref *ref = get_fp_src_reg_ref(c, src, i);
285 struct brw_wm_ref *newref = get_ref(c);
286
287 newref->value = ref->value;
288 newref->hw_reg = ref->hw_reg;
289
290 if (insn) {
291 newref->insn = insn - c->instruction;
292 newref->prevuse = newref->value->lastuse;
293 newref->value->lastuse = newref;
294 }
295
296 if (src.Negate & (1 << i))
297 newref->hw_reg.negate ^= 1;
298
299 if (src.Abs) {
300 newref->hw_reg.negate = 0;
301 newref->hw_reg.abs = 1;
302 }
303
304 return newref;
305 }
306
307
308 static void
309 translate_insn(struct brw_wm_compile *c,
310 const struct prog_instruction *inst)
311 {
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);
315 GLuint i, j;
316
317 /* Copy some data out of the instruction
318 */
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;
326
327 /* Args:
328 */
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);
332 }
333 }
334
335 /* Dst:
336 */
337 pass0_set_dst(c, out, inst, writemask);
338 }
339
340
341
342 /***********************************************************************
343 * Optimize moves and swizzles away:
344 */
345 static void pass0_precalc_mov( struct brw_wm_compile *c,
346 const struct prog_instruction *inst )
347 {
348 const struct prog_dst_register *dst = &inst->DstReg;
349 GLuint writemask = inst->DstReg.WriteMask;
350 struct brw_wm_ref *refs[4];
351 GLuint i;
352
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"
355 * swizzles such as:
356 * MOV t, t.xxyx
357 * are handled correctly. Previously, these two steps were done in
358 * one loop and the above case was incorrectly handled.
359 */
360 for (i = 0; i < 4; i++) {
361 refs[i] = get_new_ref(c, inst->SrcReg[0], i, NULL);
362 }
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]);
366 }
367 }
368 }
369
370
371 /* Initialize payload "registers".
372 */
373 static void pass0_init_payload( struct brw_wm_compile *c )
374 {
375 GLuint i;
376
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] );
381 }
382
383 #if 0
384 /* This seems to be an alternative to the INTERP_WPOS stuff I do
385 * elsewhere:
386 */
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]);
390 #endif
391
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] );
395 }
396
397
398 /***********************************************************************
399 * PASS 0
400 *
401 * Work forwards to give each calculated value a unique number. Where
402 * an instruction produces duplicate values (eg DP3), all are given
403 * the same number.
404 *
405 * Translate away swizzling and eliminate non-saturating moves.
406 */
407 void brw_wm_pass0( struct brw_wm_compile *c )
408 {
409 GLuint insn;
410
411 c->nr_vreg = 0;
412 c->nr_insns = 0;
413
414 pass0_init_undef(c);
415 pass0_init_payload(c);
416
417 for (insn = 0; insn < c->nr_fp_insns; insn++) {
418 const struct prog_instruction *inst = &c->prog_instructions[insn];
419
420 /* Optimize away moves, otherwise emit translated instruction:
421 */
422 switch (inst->Opcode) {
423 case OPCODE_MOV:
424 if (!inst->SaturateMode) {
425 pass0_precalc_mov(c, inst);
426 }
427 else {
428 translate_insn(c, inst);
429 }
430 break;
431 default:
432 translate_insn(c, inst);
433 break;
434 }
435 }
436
437 if (BRW_DEBUG & DEBUG_WM) {
438 brw_wm_print_program(c, "pass0");
439 }
440 }