Tizen 2.0 Release
[profile/ivi/osmesa.git] / src / mesa / drivers / dri / i965 / brw_wm_pass2.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
36
37 /* Use these to force spilling so that that functionality can be
38  * tested with known-good examples rather than having to construct new
39  * tests.
40  */
41 #define TEST_PAYLOAD_SPILLS 0
42 #define TEST_DST_SPILLS 0
43
44 static void spill_value(struct brw_wm_compile *c,
45                         struct brw_wm_value *value);
46
47 static void prealloc_reg(struct brw_wm_compile *c,
48                          struct brw_wm_value *value,
49                          GLuint reg)
50 {
51    if (value->lastuse) {
52       /* Set nextuse to zero, it will be corrected by
53        * update_register_usage().
54        */
55       c->pass2_grf[reg].value = value;
56       c->pass2_grf[reg].nextuse = 0;
57
58       value->resident = &c->pass2_grf[reg];
59       value->hw_reg = brw_vec8_grf(reg*2, 0);
60
61       if (TEST_PAYLOAD_SPILLS)
62          spill_value(c, value);
63    }
64 }
65
66
67 /* Initialize all the register values.  Do the initial setup
68  * calculations for interpolants.
69  */
70 static void init_registers( struct brw_wm_compile *c )
71 {
72    struct brw_context *brw = c->func.brw;
73    struct intel_context *intel = &brw->intel;
74    GLuint nr_interp_regs = 0;
75    GLuint i = 0;
76    GLuint j;
77
78    for (j = 0; j < c->grf_limit; j++) 
79       c->pass2_grf[j].nextuse = BRW_WM_MAX_INSN;
80
81    for (j = 0; j < (c->nr_payload_regs + 1) / 2; j++)
82       prealloc_reg(c, &c->payload.depth[j], i++);
83
84    for (j = 0; j < c->nr_creg; j++) 
85       prealloc_reg(c, &c->creg[j], i++);
86
87    if (intel->gen >= 6) {
88       for (unsigned int j = 0; j < FRAG_ATTRIB_MAX; j++) {
89          if (brw->fragment_program->Base.InputsRead & BITFIELD64_BIT(j)) {
90             nr_interp_regs++;
91             prealloc_reg(c, &c->payload.input_interp[j], i++);
92          }
93       }
94    } else {
95       for (j = 0; j < VERT_RESULT_MAX; j++) {
96          if (c->key.vp_outputs_written & BITFIELD64_BIT(j)) {
97             int fp_index;
98
99             if (j >= VERT_RESULT_VAR0)
100                fp_index = j - (VERT_RESULT_VAR0 - FRAG_ATTRIB_VAR0);
101             else if (j <= VERT_RESULT_TEX7)
102                fp_index = j;
103             else
104                fp_index = -1;
105
106             nr_interp_regs++;
107             if (fp_index >= 0)
108                prealloc_reg(c, &c->payload.input_interp[fp_index], i++);
109          }
110       }
111       assert(nr_interp_regs >= 1);
112    }
113
114
115    c->prog_data.first_curbe_grf = ALIGN(c->nr_payload_regs, 2);
116    c->prog_data.urb_read_length = nr_interp_regs * 2;
117    c->prog_data.curb_read_length = c->nr_creg * 2;
118
119    c->max_wm_grf = i * 2;
120 }
121
122
123 /* Update the nextuse value for each register in our file.
124  */
125 static void update_register_usage(struct brw_wm_compile *c,
126                                   GLuint thisinsn)
127 {
128    GLuint i;
129
130    for (i = 1; i < c->grf_limit; i++) {
131       struct brw_wm_grf *grf = &c->pass2_grf[i];
132
133       /* Only search those which can change:
134        */
135       if (grf->nextuse < thisinsn) {
136          const struct brw_wm_ref *ref = grf->value->lastuse;
137
138          /* Has last use of value been passed?
139           */
140          if (ref->insn < thisinsn) {
141             grf->value->resident = 0;
142             grf->value = 0;
143             grf->nextuse = BRW_WM_MAX_INSN;
144          }
145          else {
146             /* Else loop through chain to update:
147              */
148             while (ref->prevuse && ref->prevuse->insn >= thisinsn)
149                ref = ref->prevuse;
150
151             grf->nextuse = ref->insn;
152          }
153       }
154    }
155 }
156
157
158 static void spill_value(struct brw_wm_compile *c,
159                         struct brw_wm_value *value)
160 {       
161    /* Allocate a spill slot.  Note that allocations start from 0x40 -
162     * the first slot is reserved to mean "undef" in brw_wm_emit.c
163     */
164    if (!value->spill_slot) {
165       c->last_scratch += 0x40;  
166       value->spill_slot = c->last_scratch;
167    }
168
169    /* The spill will be done in brw_wm_emit.c immediately after the
170     * value is calculated, so we can just take this reg without any
171     * further work.
172     */
173    value->resident->value = NULL;
174    value->resident->nextuse = BRW_WM_MAX_INSN;
175    value->resident = NULL;
176 }
177
178
179
180 /* Search for contiguous region with the most distant nearest
181  * member.  Free regs count as very distant.
182  *
183  * TODO: implement spill-to-reg so that we can rearrange discontigous
184  * free regs and then spill the oldest non-free regs in sequence.
185  * This would mean inserting instructions in this pass.
186  */
187 static GLuint search_contiguous_regs(struct brw_wm_compile *c,
188                                      GLuint nr,
189                                      GLuint thisinsn)
190 {
191    struct brw_wm_grf *grf = c->pass2_grf;
192    GLuint furthest = 0;
193    GLuint reg = 0;
194    GLuint i, j;
195
196    /* Start search at 1: r0 is special and can't be used or spilled.
197     */
198    for (i = 1; i < c->grf_limit && furthest < BRW_WM_MAX_INSN; i++) {
199       GLuint group_nextuse = BRW_WM_MAX_INSN;
200
201       for (j = 0; j < nr; j++) {
202          if (grf[i+j].nextuse < group_nextuse)
203             group_nextuse = grf[i+j].nextuse;
204       }
205
206       if (group_nextuse > furthest) {
207          furthest = group_nextuse;
208          reg = i;
209       }
210    }
211
212    assert(furthest != thisinsn);
213
214    /* Any non-empty regs will need to be spilled:
215     */
216    for (j = 0; j < nr; j++) 
217       if (grf[reg+j].value)
218          spill_value(c, grf[reg+j].value);
219
220    return reg;
221 }
222
223
224 static void alloc_contiguous_dest(struct brw_wm_compile *c, 
225                                   struct brw_wm_value *dst[],
226                                   GLuint nr,
227                                   GLuint thisinsn)
228 {
229    GLuint reg = search_contiguous_regs(c, nr, thisinsn);
230    GLuint i;
231
232    for (i = 0; i < nr; i++) {
233       if (!dst[i]) {
234          /* Need to grab a dummy value in TEX case.  Don't introduce
235           * it into the tracking scheme.
236           */
237          dst[i] = &c->vreg[c->nr_vreg++];
238       }
239       else {
240          assert(!dst[i]->resident);
241          assert(c->pass2_grf[reg+i].nextuse != thisinsn);
242
243          c->pass2_grf[reg+i].value = dst[i];
244          c->pass2_grf[reg+i].nextuse = thisinsn;
245
246          dst[i]->resident = &c->pass2_grf[reg+i];
247       }
248
249       dst[i]->hw_reg = brw_vec8_grf((reg+i)*2, 0);
250    }
251
252    if ((reg+nr)*2 > c->max_wm_grf)
253       c->max_wm_grf = (reg+nr) * 2;
254 }
255
256
257 static void load_args(struct brw_wm_compile *c, 
258                       struct brw_wm_instruction *inst)
259 {
260    GLuint thisinsn = inst - c->instruction;
261    GLuint i,j;
262
263    for (i = 0; i < 3; i++) {
264       for (j = 0; j < 4; j++) {
265          struct brw_wm_ref *ref = inst->src[i][j];
266
267          if (ref) {
268             if (!ref->value->resident) {
269                /* Need to bring the value in from scratch space.  The code for
270                 * this will be done in brw_wm_emit.c, here we just do the
271                 * register allocation and mark the ref as requiring a fill.
272                 */
273                GLuint reg = search_contiguous_regs(c, 1, thisinsn);
274
275                c->pass2_grf[reg].value = ref->value;
276                c->pass2_grf[reg].nextuse = thisinsn;
277
278                ref->value->resident = &c->pass2_grf[reg];
279
280                /* Note that a fill is required:
281                 */
282                ref->unspill_reg = reg*2;
283             }
284
285             /* Adjust the hw_reg to point at the value's current location:
286              */
287             assert(ref->value == ref->value->resident->value);
288             ref->hw_reg.nr += (ref->value->resident - c->pass2_grf) * 2;
289          }
290       }
291    }
292 }
293
294
295
296 /* Step 3: Work forwards once again.  Perform register allocations,
297  * taking into account instructions like TEX which require contiguous
298  * result registers.  Where necessary spill registers to scratch space
299  * and reload later.
300  */
301 void brw_wm_pass2( struct brw_wm_compile *c )
302 {
303    GLuint insn;
304    GLuint i;
305
306    init_registers(c);
307
308    for (insn = 0; insn < c->nr_insns; insn++) {
309       struct brw_wm_instruction *inst = &c->instruction[insn];
310
311       /* Update registers' nextuse values:
312        */
313       update_register_usage(c, insn);
314
315       /* May need to unspill some args.
316        */
317       load_args(c, inst);
318
319       /* Allocate registers to hold results:
320        */
321       switch (inst->opcode) {
322       case OPCODE_TEX:
323       case OPCODE_TXB:
324       case OPCODE_TXP:
325          alloc_contiguous_dest(c, inst->dst, 4, insn);
326          break;
327
328       default:
329          for (i = 0; i < 4; i++) {
330             if (inst->writemask & (1<<i)) {
331                assert(inst->dst[i]);
332                alloc_contiguous_dest(c, &inst->dst[i], 1, insn);
333             }
334          }
335          break;
336       }
337
338       if (TEST_DST_SPILLS && inst->opcode != WM_PIXELXY) {
339          for (i = 0; i < 4; i++)        
340             if (inst->dst[i])
341                spill_value(c, inst->dst[i]);
342       }
343    }
344
345    if (unlikely(INTEL_DEBUG & DEBUG_WM)) {
346       brw_wm_print_program(c, "pass2");
347    }
348
349    c->state = PASS2_DONE;
350
351    if (unlikely(INTEL_DEBUG & DEBUG_WM)) {
352        brw_wm_print_program(c, "pass2/done");
353    }
354 }