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