Tizen 2.0 Release
[profile/ivi/osmesa.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 }