Minor r200 vertex program cleanups. Remove disabled leftovers from r300 vertex progra...
[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.h"
36 #include "arbprogparse.h"
37 #include "program_instruction.h"
38
39
40
41 /***********************************************************************
42 */
43
44 static struct brw_wm_ref *get_ref( struct brw_wm_compile *c )
45 {
46 assert(c->nr_refs < BRW_WM_MAX_REF);
47 return &c->refs[c->nr_refs++];
48 }
49
50 static struct brw_wm_value *get_value( struct brw_wm_compile *c)
51 {
52 assert(c->nr_refs < BRW_WM_MAX_VREG);
53 return &c->vreg[c->nr_vreg++];
54 }
55
56 static struct brw_wm_instruction *get_instruction( struct brw_wm_compile *c )
57 {
58 assert(c->nr_insns < BRW_WM_MAX_INSN);
59 return &c->instruction[c->nr_insns++];
60 }
61
62 /***********************************************************************
63 */
64
65 static void pass0_init_undef( struct brw_wm_compile *c)
66 {
67 struct brw_wm_ref *ref = &c->undef_ref;
68 ref->value = &c->undef_value;
69 ref->hw_reg = brw_vec8_grf(0, 0);
70 ref->insn = 0;
71 ref->prevuse = NULL;
72 }
73
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 static void pass0_set_fpreg_ref( struct brw_wm_compile *c,
89 GLuint file,
90 GLuint idx,
91 GLuint component,
92 const struct brw_wm_ref *src_ref )
93 {
94 c->pass0_fp_reg[file][idx][component] = src_ref;
95 }
96
97 static const struct brw_wm_ref *get_param_ref( struct brw_wm_compile *c,
98 const GLfloat *param_ptr )
99 {
100 GLuint i = c->prog_data.nr_params++;
101
102 if (i >= BRW_WM_MAX_PARAM) {
103 _mesa_printf("%s: out of params\n", __FUNCTION__);
104 c->prog_data.error = 1;
105 return NULL;
106 }
107 else {
108 struct brw_wm_ref *ref = get_ref(c);
109
110 c->prog_data.param[i] = param_ptr;
111 c->nr_creg = (i+16)/16;
112
113 /* Push the offsets into hw_reg. These will be added to the
114 * real register numbers once one is allocated in pass2.
115 */
116 ref->hw_reg = brw_vec1_grf((i&8)?1:0, i%8);
117 ref->value = &c->creg[i/16];
118 ref->insn = 0;
119 ref->prevuse = NULL;
120
121 return ref;
122 }
123 }
124
125
126 static const struct brw_wm_ref *get_const_ref( struct brw_wm_compile *c,
127 const GLfloat *constval )
128 {
129 GLuint i;
130
131 /* Search for an existing const value matching the request:
132 */
133 for (i = 0; i < c->nr_constrefs; i++) {
134 if (c->constref[i].constval == *constval)
135 return c->constref[i].ref;
136 }
137
138 /* Else try to add a new one:
139 */
140 if (c->nr_constrefs < BRW_WM_MAX_CONST) {
141 GLuint i = c->nr_constrefs++;
142
143 /* A constant is a special type of parameter:
144 */
145 c->constref[i].constval = *constval;
146 c->constref[i].ref = get_param_ref(c, constval);
147
148 return c->constref[i].ref;
149 }
150 else {
151 _mesa_printf("%s: out of constrefs\n", __FUNCTION__);
152 c->prog_data.error = 1;
153 return NULL;
154 }
155 }
156
157
158 /* Lookup our internal registers
159 */
160 static const struct brw_wm_ref *pass0_get_reg( struct brw_wm_compile *c,
161 GLuint file,
162 GLuint idx,
163 GLuint component )
164 {
165 const struct brw_wm_ref *ref = c->pass0_fp_reg[file][idx][component];
166
167 if (!ref) {
168 switch (file) {
169 case PROGRAM_INPUT:
170 case PROGRAM_PAYLOAD:
171 case PROGRAM_TEMPORARY:
172 case PROGRAM_OUTPUT:
173 break;
174
175 case PROGRAM_LOCAL_PARAM:
176 ref = get_param_ref(c, &c->fp->program.Base.LocalParams[idx][component]);
177 break;
178
179 case PROGRAM_ENV_PARAM:
180 ref = get_param_ref(c, &c->env_param[idx][component]);
181 break;
182
183 case PROGRAM_STATE_VAR:
184 case PROGRAM_NAMED_PARAM: {
185 struct gl_program_parameter_list *plist = c->fp->program.Base.Parameters;
186
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.
192 */
193 switch (plist->Parameters[idx].Type) {
194 case PROGRAM_NAMED_PARAM:
195 case PROGRAM_CONSTANT:
196 /* These are invarient:
197 */
198 ref = get_const_ref(c, &plist->ParameterValues[idx][component]);
199 break;
200
201 case PROGRAM_STATE_VAR:
202 /* These may change from run to run:
203 */
204 ref = get_param_ref(c, &plist->ParameterValues[idx][component] );
205 break;
206
207 default:
208 assert(0);
209 break;
210 }
211 break;
212 }
213
214 default:
215 assert(0);
216 break;
217 }
218
219 c->pass0_fp_reg[file][idx][component] = ref;
220 }
221
222 if (!ref)
223 ref = &c->undef_ref;
224
225 return ref;
226 }
227
228
229
230
231 /***********************************************************************
232 * Straight translation to internal instruction format
233 */
234
235 static void pass0_set_dst( struct brw_wm_compile *c,
236 struct brw_wm_instruction *out,
237 const struct prog_instruction *inst,
238 GLuint writemask )
239 {
240 const struct prog_dst_register *dst = &inst->DstReg;
241 GLuint i;
242
243 for (i = 0; i < 4; i++) {
244 if (writemask & (1<<i)) {
245 out->dst[i] = get_value(c);
246
247 pass0_set_fpreg_value(c, dst->File, dst->Index, i, out->dst[i]);
248 }
249 }
250
251 out->writemask = writemask;
252 }
253
254
255 static void pass0_set_dst_scalar( struct brw_wm_compile *c,
256 struct brw_wm_instruction *out,
257 const struct prog_instruction *inst,
258 GLuint writemask )
259 {
260 if (writemask) {
261 const struct prog_dst_register *dst = &inst->DstReg;
262 GLuint i;
263
264 /* Compute only the first (X) value:
265 */
266 out->writemask = WRITEMASK_X;
267 out->dst[0] = get_value(c);
268
269 /* Update our tracking register file for all the components in
270 * writemask:
271 */
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]);
275 }
276 }
277 }
278 else
279 out->writemask = 0;
280 }
281
282
283
284 static const struct brw_wm_ref *get_fp_src_reg_ref( struct brw_wm_compile *c,
285 struct prog_src_register src,
286 GLuint i )
287 {
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;
292
293
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);
298 else
299 src_ref = pass0_get_reg(c, src.File, src.Index, component);
300
301 return src_ref;
302 }
303
304
305 static struct brw_wm_ref *get_new_ref( struct brw_wm_compile *c,
306 struct prog_src_register src,
307 GLuint i,
308 struct brw_wm_instruction *insn)
309 {
310 const struct brw_wm_ref *ref = get_fp_src_reg_ref(c, src, i);
311 struct brw_wm_ref *newref = get_ref(c);
312
313 newref->value = ref->value;
314 newref->hw_reg = ref->hw_reg;
315
316 if (insn) {
317 newref->insn = insn - c->instruction;
318 newref->prevuse = newref->value->lastuse;
319 newref->value->lastuse = newref;
320 }
321
322 if (src.NegateBase & (1<<i))
323 newref->hw_reg.negate ^= 1;
324
325 if (src.Abs) {
326 newref->hw_reg.negate = 0;
327 newref->hw_reg.abs = 1;
328 }
329
330 return newref;
331 }
332
333
334
335 static struct brw_wm_instruction *translate_insn( struct brw_wm_compile *c,
336 const struct prog_instruction *inst )
337 {
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);
341 GLuint i, j;
342
343 /* Copy some data out of the instruction
344 */
345 out->opcode = inst->Opcode;
346 out->saturate = (inst->SaturateMode != SATURATE_OFF);
347 out->tex_unit = inst->TexSrcUnit;
348 out->tex_idx = inst->TexSrcTarget;
349
350 /* Args:
351 */
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);
355 }
356 }
357
358 /* Dst:
359 */
360 if (brw_wm_is_scalar_result(out->opcode))
361 pass0_set_dst_scalar(c, out, inst, writemask);
362 else
363 pass0_set_dst(c, out, inst, writemask);
364
365 return out;
366 }
367
368
369
370 /***********************************************************************
371 * Optimize moves and swizzles away:
372 */
373 static void pass0_precalc_mov( struct brw_wm_compile *c,
374 const struct prog_instruction *inst )
375 {
376 const struct prog_dst_register *dst = &inst->DstReg;
377 GLuint writemask = inst->DstReg.WriteMask;
378 GLuint i;
379
380 /* Get the effect of a MOV by manipulating our register table:
381 */
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));
386 }
387 }
388 }
389
390
391 /* Initialize payload "registers".
392 */
393 static void pass0_init_payload( struct brw_wm_compile *c )
394 {
395 GLuint i;
396
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] );
401 }
402
403 #if 0
404 /* This seems to be an alternative to the INTERP_WPOS stuff I do
405 * elsewhere:
406 */
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]);
410 #endif
411
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] );
415 }
416
417 /***********************************************************************
418 * PASS 0
419 *
420 * Work forwards to give each calculated value a unique number. Where
421 * an instruction produces duplicate values (eg DP3), all are given
422 * the same number.
423 *
424 * Translate away swizzling and eliminate non-saturating moves.
425 */
426 void brw_wm_pass0( struct brw_wm_compile *c )
427 {
428 GLuint insn;
429
430 c->nr_vreg = 0;
431 c->nr_insns = 0;
432
433 pass0_init_undef(c);
434 pass0_init_payload(c);
435
436 for (insn = 0; insn < c->nr_fp_insns; insn++) {
437 const struct prog_instruction *inst = &c->prog_instructions[insn];
438
439
440 /* Optimize away moves, otherwise emit translated instruction:
441 */
442 switch (inst->Opcode) {
443 case OPCODE_MOV:
444 case OPCODE_SWZ:
445 if (!inst->SaturateMode) {
446 pass0_precalc_mov(c, inst);
447 }
448 else {
449 translate_insn(c, inst);
450 }
451 break;
452
453
454 default:
455 translate_insn(c, inst);
456 break;
457 }
458 }
459
460 if (INTEL_DEBUG & DEBUG_WM) {
461 brw_wm_print_program(c, "pass0");
462 }
463 }
464