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