Merge branch 'mesa_7_7_branch'
[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 #include "util/u_memory.h"
33 #include "util/u_math.h"
34
35 #include "brw_debug.h"
36 #include "brw_wm.h"
37
38
39
40 /***********************************************************************
41 */
42
43 static struct brw_wm_ref *get_ref( struct brw_wm_compile *c )
44 {
45 assert(c->nr_refs < BRW_WM_MAX_REF);
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 return &c->vreg[c->nr_vreg++];
53 }
54
55 /** return pointer to a newly allocated instruction */
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 /** Init the "undef" register */
66 static void pass0_init_undef( struct brw_wm_compile *c)
67 {
68 struct brw_wm_ref *ref = &c->undef_ref;
69 ref->value = &c->undef_value;
70 ref->hw_reg = brw_vec8_grf(0, 0);
71 ref->insn = 0;
72 ref->prevuse = NULL;
73 }
74
75 /** Set a FP register to a value */
76 static void pass0_set_fpreg_value( struct brw_wm_compile *c,
77 GLuint file,
78 GLuint idx,
79 GLuint component,
80 struct brw_wm_value *value )
81 {
82 struct brw_wm_ref *ref = get_ref(c);
83 ref->value = value;
84 ref->hw_reg = brw_vec8_grf(0, 0);
85 ref->insn = 0;
86 ref->prevuse = NULL;
87 c->pass0_fp_reg[file][idx][component] = ref;
88 }
89
90 /** Set a FP register to a ref */
91 static void pass0_set_fpreg_ref( struct brw_wm_compile *c,
92 GLuint file,
93 GLuint idx,
94 GLuint component,
95 const struct brw_wm_ref *src_ref )
96 {
97 c->pass0_fp_reg[file][idx][component] = src_ref;
98 }
99
100 static const struct brw_wm_ref *get_param_ref( struct brw_wm_compile *c,
101 unsigned idx,
102 unsigned component)
103 {
104 GLuint i = idx * 4 + component;
105
106 if (i >= BRW_WM_MAX_PARAM) {
107 debug_printf("%s: out of params\n", __FUNCTION__);
108 c->prog_data.error = 1;
109 return NULL;
110 }
111 else {
112 struct brw_wm_ref *ref = get_ref(c);
113
114 c->nr_creg = MAX2(c->nr_creg, (i+16)/16);
115
116 /* Push the offsets into hw_reg. These will be added to the
117 * real register numbers once one is allocated in pass2.
118 */
119 ref->hw_reg = brw_vec1_grf((i&8)?1:0, i%8);
120 ref->value = &c->creg[i/16];
121 ref->insn = 0;
122 ref->prevuse = NULL;
123
124 return ref;
125 }
126 }
127
128
129
130
131 /* Lookup our internal registers
132 */
133 static const struct brw_wm_ref *pass0_get_reg( struct brw_wm_compile *c,
134 GLuint file,
135 GLuint idx,
136 GLuint component )
137 {
138 const struct brw_wm_ref *ref = c->pass0_fp_reg[file][idx][component];
139
140 if (!ref) {
141 switch (file) {
142 case TGSI_FILE_INPUT:
143 case TGSI_FILE_TEMPORARY:
144 case TGSI_FILE_OUTPUT:
145 case BRW_FILE_PAYLOAD:
146 /* should already be done?? */
147 break;
148
149 case TGSI_FILE_CONSTANT:
150 ref = get_param_ref(c,
151 c->fp->info.immediate_count + idx,
152 component);
153 break;
154
155 case TGSI_FILE_IMMEDIATE:
156 ref = get_param_ref(c,
157 idx,
158 component);
159 break;
160
161 default:
162 assert(0);
163 break;
164 }
165
166 c->pass0_fp_reg[file][idx][component] = ref;
167 }
168
169 if (!ref)
170 ref = &c->undef_ref;
171
172 return ref;
173 }
174
175
176
177 /***********************************************************************
178 * Straight translation to internal instruction format
179 */
180
181 static void pass0_set_dst( struct brw_wm_compile *c,
182 struct brw_wm_instruction *out,
183 const struct brw_fp_instruction *inst,
184 GLuint writemask )
185 {
186 const struct brw_fp_dst dst = inst->dst;
187 GLuint i;
188
189 for (i = 0; i < 4; i++) {
190 if (writemask & (1<<i)) {
191 out->dst[i] = get_value(c);
192 pass0_set_fpreg_value(c, dst.file, dst.index, i, out->dst[i]);
193 }
194 }
195
196 out->writemask = writemask;
197 }
198
199
200 static const struct brw_wm_ref *get_fp_src_reg_ref( struct brw_wm_compile *c,
201 struct brw_fp_src src,
202 GLuint i )
203 {
204 return pass0_get_reg(c, src.file, src.index, BRW_GET_SWZ(src.swizzle,i));
205 }
206
207
208 static struct brw_wm_ref *get_new_ref( struct brw_wm_compile *c,
209 struct brw_fp_src src,
210 GLuint i,
211 struct brw_wm_instruction *insn)
212 {
213 const struct brw_wm_ref *ref = get_fp_src_reg_ref(c, src, i);
214 struct brw_wm_ref *newref = get_ref(c);
215
216 newref->value = ref->value;
217 newref->hw_reg = ref->hw_reg;
218
219 if (insn) {
220 newref->insn = insn - c->instruction;
221 newref->prevuse = newref->value->lastuse;
222 newref->value->lastuse = newref;
223 }
224
225 if (src.negate)
226 newref->hw_reg.negate ^= 1;
227
228 if (src.abs) {
229 newref->hw_reg.negate = 0;
230 newref->hw_reg.abs = 1;
231 }
232
233 return newref;
234 }
235
236
237 static void
238 translate_insn(struct brw_wm_compile *c,
239 const struct brw_fp_instruction *inst)
240 {
241 struct brw_wm_instruction *out = get_instruction(c);
242 GLuint writemask = inst->dst.writemask;
243 GLuint nr_args = brw_wm_nr_args(inst->opcode);
244 GLuint i, j;
245
246 /* Copy some data out of the instruction
247 */
248 out->opcode = inst->opcode;
249 out->saturate = inst->dst.saturate;
250 out->tex_unit = inst->tex_unit;
251 out->target = inst->target;
252
253 /* Nasty hack:
254 */
255 out->eot = (inst->opcode == WM_FB_WRITE &&
256 inst->tex_unit != 0);
257
258
259 /* Args:
260 */
261 for (i = 0; i < nr_args; i++) {
262 for (j = 0; j < 4; j++) {
263 out->src[i][j] = get_new_ref(c, inst->src[i], j, out);
264 }
265 }
266
267 /* Dst:
268 */
269 pass0_set_dst(c, out, inst, writemask);
270 }
271
272
273
274 /***********************************************************************
275 * Optimize moves and swizzles away:
276 */
277 static void pass0_precalc_mov( struct brw_wm_compile *c,
278 const struct brw_fp_instruction *inst )
279 {
280 const struct brw_fp_dst dst = inst->dst;
281 GLuint writemask = dst.writemask;
282 struct brw_wm_ref *refs[4];
283 GLuint i;
284
285 /* Get the effect of a MOV by manipulating our register table:
286 * First get all refs, then assign refs. This ensures that "in-place"
287 * swizzles such as:
288 * MOV t, t.xxyx
289 * are handled correctly. Previously, these two steps were done in
290 * one loop and the above case was incorrectly handled.
291 */
292 for (i = 0; i < 4; i++) {
293 refs[i] = get_new_ref(c, inst->src[0], i, NULL);
294 }
295 for (i = 0; i < 4; i++) {
296 if (writemask & (1 << i)) {
297 pass0_set_fpreg_ref( c, dst.file, dst.index, i, refs[i]);
298 }
299 }
300 }
301
302
303 /* Initialize payload "registers".
304 */
305 static void pass0_init_payload( struct brw_wm_compile *c )
306 {
307 GLuint i;
308
309 for (i = 0; i < 4; i++) {
310 GLuint j = i >= c->key.nr_depth_regs ? 0 : i;
311 pass0_set_fpreg_value( c, BRW_FILE_PAYLOAD, PAYLOAD_DEPTH, i,
312 &c->payload.depth[j] );
313 }
314
315 for (i = 0; i < c->key.nr_inputs; i++)
316 pass0_set_fpreg_value( c, BRW_FILE_PAYLOAD, i, 0,
317 &c->payload.input_interp[i] );
318 }
319
320
321 /***********************************************************************
322 * PASS 0
323 *
324 * Work forwards to give each calculated value a unique number. Where
325 * an instruction produces duplicate values (eg DP3), all are given
326 * the same number.
327 *
328 * Translate away swizzling and eliminate non-saturating moves.
329 *
330 * Translate instructions from our fp_instruction structs to our
331 * internal brw_wm_instruction representation.
332 */
333 void brw_wm_pass0( struct brw_wm_compile *c )
334 {
335 GLuint insn;
336
337 c->nr_vreg = 0;
338 c->nr_insns = 0;
339
340 pass0_init_undef(c);
341 pass0_init_payload(c);
342
343 for (insn = 0; insn < c->nr_fp_insns; insn++) {
344 const struct brw_fp_instruction *inst = &c->fp_instructions[insn];
345
346 /* Optimize away moves, otherwise emit translated instruction:
347 */
348 switch (inst->opcode) {
349 case TGSI_OPCODE_MOV:
350 if (!inst->dst.saturate) {
351 pass0_precalc_mov(c, inst);
352 }
353 else {
354 translate_insn(c, inst);
355 }
356 break;
357 default:
358 translate_insn(c, inst);
359 break;
360 }
361 }
362
363 if (BRW_DEBUG & DEBUG_WM) {
364 brw_wm_print_program(c, "pass0");
365 }
366 }